[PATCH 2/2] gpu: ipu-v3: pre: add dynamic buffer layout reconfiguration
Philipp Zabel
p.zabel at pengutronix.de
Fri Jan 27 10:20:05 UTC 2023
On Thu, Jan 26, 2023 at 07:47:44PM +0100, Lucas Stach wrote:
> imx-drm doesn't mandate a modeset when the framebuffer modifier changes,
> but currently the tile prefetch and resolve (TPR) configuration of the
> PRE is only set up on the initial modeset.
>
> As the TPR configuration is double buffered, same as all the other PRE
> states, we can support dynamic reconfiguration of the buffer layout from
> one frame to another. As switching between (super-)tiled and linear
> prefetch needs to touch the CTRL register make sure to do the
> reconfiguration inside the safe window.
>
> Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
> ---
> drivers/gpu/ipu-v3/ipu-pre.c | 59 +++++++++++++++++++++++++++++-------
> drivers/gpu/ipu-v3/ipu-prg.c | 2 +-
> drivers/gpu/ipu-v3/ipu-prv.h | 2 +-
> 3 files changed, 50 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c
> index befffc85a146..e8d9792827dd 100644
> --- a/drivers/gpu/ipu-v3/ipu-pre.c
> +++ b/drivers/gpu/ipu-v3/ipu-pre.c
> @@ -99,8 +99,12 @@ struct ipu_pre {
>
> struct {
> bool in_use;
> + uint64_t modifier;
> + unsigned int height;
> unsigned int safe_window_end;
> unsigned int bufaddr;
> + u32 ctrl;
> + u8 cpp;
> } cur;
> };
>
> @@ -173,6 +177,11 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
> u32 active_bpp = info->cpp[0] >> 1;
> u32 val;
>
> + pre->cur.bufaddr = bufaddr;
> + pre->cur.height = height;
> + pre->cur.modifier = modifier;
> + pre->cur.cpp = info->cpp[0];
> +
> /* calculate safe window for ctrl register updates */
> if (modifier == DRM_FORMAT_MOD_LINEAR)
> pre->cur.safe_window_end = height - 2;
> @@ -181,7 +190,6 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
>
> writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
> writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
> - pre->cur.bufaddr = bufaddr;
>
> val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
> IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
> @@ -223,28 +231,56 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
> }
> writel(val, pre->regs + IPU_PRE_TPR_CTRL);
>
> - val = readl(pre->regs + IPU_PRE_CTRL);
> - val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
> - IPU_PRE_CTRL_SDW_UPDATE;
> + pre->cur.ctrl = readl(pre->regs + IPU_PRE_CTRL);
> + pre->cur.ctrl |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE;
> if (modifier == DRM_FORMAT_MOD_LINEAR)
> - val &= ~IPU_PRE_CTRL_BLOCK_EN;
> + pre->cur.ctrl &= ~IPU_PRE_CTRL_BLOCK_EN;
> else
> - val |= IPU_PRE_CTRL_BLOCK_EN;
> - writel(val, pre->regs + IPU_PRE_CTRL);
> + pre->cur.ctrl |= IPU_PRE_CTRL_BLOCK_EN;
> + writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE,
> + pre->regs + IPU_PRE_CTRL);
> }
>
> -void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
> +void ipu_pre_update(struct ipu_pre *pre, uint64_t modifier, unsigned int bufaddr)
> {
> unsigned long timeout = jiffies + msecs_to_jiffies(5);
> unsigned short current_yblock;
> + unsigned int safe_window_end = pre->cur.safe_window_end;
> u32 val;
>
> - if (bufaddr == pre->cur.bufaddr)
> + if (bufaddr == pre->cur.bufaddr &&
> + modifier == pre->cur.modifier)
> return;
>
> writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
> pre->cur.bufaddr = bufaddr;
>
> + if (modifier != pre->cur.modifier) {
> + val = readl(pre->regs + IPU_PRE_TPR_CTRL);
> + val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
> + if (modifier != DRM_FORMAT_MOD_LINEAR) {
> + /* only support single buffer formats for now */
> + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
> + if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
> + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
> + if (pre->cur.cpp == 2)
> + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
> + }
> + writel(val, pre->regs + IPU_PRE_TPR_CTRL);
> +
> + if (modifier == DRM_FORMAT_MOD_LINEAR)
> + pre->cur.ctrl &= ~IPU_PRE_CTRL_BLOCK_EN;
> + else
> + pre->cur.ctrl |= IPU_PRE_CTRL_BLOCK_EN;
> +
> + if (modifier == DRM_FORMAT_MOD_LINEAR)
> + pre->cur.safe_window_end = pre->cur.height - 2;
> + else
> + pre->cur.safe_window_end = DIV_ROUND_UP(pre->cur.height, 4) - 1;
Could you extract the same code from ipu_pre_configure() into a separate
function, say ipu_pre_configure_modifier(), instead, and call that from
both places?
regards
Philipp
More information about the dri-devel
mailing list