]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
gpu: ipu-v3: pre: add dynamic buffer layout reconfiguration
authorLucas Stach <l.stach@pengutronix.de>
Fri, 17 May 2024 10:45:48 +0000 (12:45 +0200)
committerPhilipp Zabel <p.zabel@pengutronix.de>
Wed, 26 Jun 2024 15:43:54 +0000 (17:43 +0200)
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@pengutronix.de>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://lore.kernel.org/r/20240517104549.3648939-2-l.stach@pengutronix.de
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20240517104549.3648939-2-l.stach@pengutronix.de
drivers/gpu/ipu-v3/ipu-pre.c
drivers/gpu/ipu-v3/ipu-prg.c
drivers/gpu/ipu-v3/ipu-prv.h

index fe34433027fb3e3c38adb5aa9a91f8c5a417f409..0ec16282e3b439cad95c4beefba2f6dc04e91ad1 100644 (file)
@@ -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;
 };
 
@@ -162,6 +166,40 @@ void ipu_pre_put(struct ipu_pre *pre)
        pre->cur.in_use = false;
 }
 
+static inline void
+ipu_pre_update_safe_window(struct ipu_pre *pre)
+{
+       if (pre->cur.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;
+}
+
+static void
+ipu_pre_configure_modifier(struct ipu_pre *pre, uint64_t modifier)
+{
+       u32 val;
+
+       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;
+
+       pre->cur.modifier = modifier;
+}
+
 void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
                       unsigned int height, unsigned int stride, u32 format,
                       uint64_t modifier, unsigned int bufaddr)
@@ -170,15 +208,16 @@ 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.cpp = info->cpp[0];
+       pre->cur.ctrl = readl(pre->regs + IPU_PRE_CTRL);
+
        /* calculate safe window for ctrl register updates */
-       if (modifier == DRM_FORMAT_MOD_LINEAR)
-               pre->cur.safe_window_end = height - 2;
-       else
-               pre->cur.safe_window_end = DIV_ROUND_UP(height, 4) - 1;
+       ipu_pre_update_safe_window(pre);
 
        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) |
@@ -208,40 +247,29 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
 
        writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
 
-       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 (info->cpp[0] == 2)
-                       val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
-       }
-       writel(val, pre->regs + IPU_PRE_TPR_CTRL);
+       ipu_pre_configure_modifier(pre, modifier);
 
-       val = readl(pre->regs + IPU_PRE_CTRL);
-       val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
-              IPU_PRE_CTRL_SDW_UPDATE;
-       if (modifier == DRM_FORMAT_MOD_LINEAR)
-               val &= ~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_EN_REPEAT | IPU_PRE_CTRL_ENABLE;
+       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;
        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)
+               ipu_pre_configure_modifier(pre, modifier);
+
        do {
                if (time_after(jiffies, timeout)) {
                        dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
@@ -252,9 +280,14 @@ void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
                current_yblock =
                        (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
                        IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
-       } while (current_yblock == 0 || current_yblock >= pre->cur.safe_window_end);
+       } while (current_yblock == 0 ||
+                current_yblock >= pre->cur.safe_window_end);
+
+       writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE,
+              pre->regs + IPU_PRE_CTRL);
 
-       writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
+       /* calculate safe window for the next update with the new modifier */
+       ipu_pre_update_safe_window(pre);
 }
 
 bool ipu_pre_update_pending(struct ipu_pre *pre)
index 72960570995590cdb5ed4aff4120f30d4d339109..661dedf6617a10c6e4f4a948a0a73adbfba9cec2 100644 (file)
@@ -287,7 +287,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
        chan = &prg->chan[prg_chan];
 
        if (chan->enabled) {
-               ipu_pre_update(prg->pres[chan->used_pre], *eba);
+               ipu_pre_update(prg->pres[chan->used_pre], modifier, *eba);
                return 0;
        }
 
index d4621b1ea7f1232f187e6bbab7e590890a15344d..3884acb7995ab04a20a1a0e12c512cfcc6cd08bd 100644 (file)
@@ -263,7 +263,7 @@ u32 ipu_pre_get_baddr(struct ipu_pre *pre);
 void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
                       unsigned int height, unsigned int stride, u32 format,
                       uint64_t modifier, unsigned int bufaddr);
-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);
 bool ipu_pre_update_pending(struct ipu_pre *pre);
 
 struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,