All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lucas Stach <l.stach@pengutronix.de>
To: Philipp Zabel <p.zabel@pengutronix.de>
Cc: kernel@pengutronix.de, dri-devel@lists.freedesktop.org,
	patchwork-lst@pengutronix.de
Subject: [PATCH 2/2] gpu: ipu-v3: pre: add dynamic buffer layout reconfiguration
Date: Thu, 26 Jan 2023 19:47:44 +0100	[thread overview]
Message-ID: <20230126184744.921758-2-l.stach@pengutronix.de> (raw)
In-Reply-To: <20230126184744.921758-1-l.stach@pengutronix.de>

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>
---
 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;
+
+		pre->cur.modifier = modifier;
+	}
+
 	do {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
@@ -255,9 +291,10 @@ 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 >= safe_window_end);
 
-	writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
+	writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE,
+	       pre->regs + IPU_PRE_CTRL);
 }
 
 bool ipu_pre_update_pending(struct ipu_pre *pre)
diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c
index 196797c1b4b3..eb8cfcd9f5b4 100644
--- a/drivers/gpu/ipu-v3/ipu-prg.c
+++ b/drivers/gpu/ipu-v3/ipu-prg.c
@@ -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;
 	}
 
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 291ac1bab66d..24f05ff3c047 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -262,7 +262,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,
-- 
2.30.2


  reply	other threads:[~2023-01-26 18:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-26 18:47 [PATCH 1/2] gpu: ipu-v3: pre: move state into struct Lucas Stach
2023-01-26 18:47 ` Lucas Stach [this message]
2023-01-27 10:20   ` [PATCH 2/2] gpu: ipu-v3: pre: add dynamic buffer layout reconfiguration Philipp Zabel
2023-01-27 10:20 ` [PATCH 1/2] gpu: ipu-v3: pre: move state into struct Philipp Zabel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230126184744.921758-2-l.stach@pengutronix.de \
    --to=l.stach@pengutronix.de \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=kernel@pengutronix.de \
    --cc=p.zabel@pengutronix.de \
    --cc=patchwork-lst@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.