[PATCH v3 01/27] drm/msm/mdss: correct UBWC programming sequences

Dmitry Baryshkov
2026-03-12T13:29:35Z

The UBWC registers in the MDSS region are not dependent on the UBWC
version (it is an invalid assumption we inherited from the vendor SDE
driver). Instead they are dependent only on the MDSS core revision.

Rework UBWC programming to follow MDSS revision and to use required (aka
encoder) UBWC version instead of the ubwc_dec_version.

Fixes: d68db6069a8e ("drm/msm/mdss: convert UBWC setup to use match data")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_mdss.c | 115 +++++++++++++++--------------------------
1 file changed, 41 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
index 9047e8d9ee89..7cb8aeaa7ecf 100644
--- a/drivers/gpu/drm/msm/msm_mdss.c
+++ b/drivers/gpu/drm/msm/msm_mdss.c
@@ -166,22 +166,19 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss)
return 0;
}

-static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss)
+static void msm_mdss_4x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
- u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
+ u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle & 0x1) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);

- if (data->ubwc_bank_spread)
- value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
-
if (data->ubwc_enc_version == UBWC_1_0)
value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(1);

writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
}

-static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss)
+static void msm_mdss_5x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle & 0x1) |
@@ -199,11 +196,12 @@ static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss)
writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
}

-static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss)
+static void msm_mdss_6x_setup_ubwc(struct msm_mdss *msm_mdss)
{
const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
+ u32 ver, prediction_mode;

if (data->ubwc_bank_spread)
value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
@@ -211,45 +209,42 @@ static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss)
if (data->macrotile_mode)
value |= MDSS_UBWC_STATIC_MACROTILE_MODE;

- writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);
-
- if (data->ubwc_enc_version == UBWC_3_0) {
- writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
- writel_relaxed(0, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
- } else {
- if (data->ubwc_dec_version == UBWC_4_3)
- writel_relaxed(3, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
- else
- writel_relaxed(2, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
- writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
- }
-}
-
-static void msm_mdss_setup_ubwc_dec_50(struct msm_mdss *msm_mdss)
-{
- const struct qcom_ubwc_cfg_data *data = msm_mdss->mdss_data;
- u32 value = MDSS_UBWC_STATIC_UBWC_SWIZZLE(data->ubwc_swizzle) |
- MDSS_UBWC_STATIC_HIGHEST_BANK_BIT(data->highest_bank_bit - 13);
-
- if (data->ubwc_bank_spread)
- value |= MDSS_UBWC_STATIC_UBWC_BANK_SPREAD;
-
- if (data->macrotile_mode)
- value |= MDSS_UBWC_STATIC_MACROTILE_MODE;
+ if (data->ubwc_enc_version == UBWC_1_0)
+ value |= MDSS_UBWC_STATIC_UBWC_MIN_ACC_LEN(1);

writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC);

- if (data->ubwc_dec_version == UBWC_6_0)
- writel_relaxed(5, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
+ if (data->ubwc_enc_version < UBWC_4_0)
+ prediction_mode = 0;
else
- writel_relaxed(4, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
-
- writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
+ prediction_mode = 1;
+
+ if (data->ubwc_enc_version >= UBWC_6_0)
+ ver = 5;
+ else if (data->ubwc_enc_version >= UBWC_5_0)
+ ver = 4;
+ else if (data->ubwc_enc_version >= UBWC_4_3)
+ ver = 3;
+ else if (data->ubwc_enc_version >= UBWC_4_0)
+ ver = 2;
+ else if (data->ubwc_enc_version >= UBWC_3_0)
+ ver = 1;
+ else /* UBWC 1.0 and 2.0 */
+ ver = 0;
+
+ writel_relaxed(ver, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2);
+ writel_relaxed(prediction_mode, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE);
}

+#define MDSS_HW_VER(major, minor, step) \
+ ((((major) & 0xf) << 28) | \
+ (((minor) & 0xfff) << 16) | \
+ ((step) & 0xffff))
+
static int msm_mdss_enable(struct msm_mdss *msm_mdss)
{
int ret, i;
+ u32 hw_rev;

/*
* Several components have AXI clocks that can only be turned on if
@@ -275,43 +270,15 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
if (msm_mdss->is_mdp5 || !msm_mdss->mdss_data)
return 0;

- /*
- * ubwc config is part of the "mdss" region which is not accessible
- * from the rest of the driver. hardcode known configurations here
- *
- * Decoder version can be read from the UBWC_DEC_HW_VERSION reg,
- * UBWC_n and the rest of params comes from hw data.
- */
- switch (msm_mdss->mdss_data->ubwc_dec_version) {
- case 0: /* no UBWC */
- case UBWC_1_0:
- /* do nothing */
- break;
- case UBWC_2_0:
- msm_mdss_setup_ubwc_dec_20(msm_mdss);
- break;
- case UBWC_3_0:
- msm_mdss_setup_ubwc_dec_30(msm_mdss);
- break;
- case UBWC_4_0:
- case UBWC_4_3:
- msm_mdss_setup_ubwc_dec_40(msm_mdss);
- break;
- case UBWC_5_0:
- msm_mdss_setup_ubwc_dec_50(msm_mdss);
- break;
- case UBWC_6_0:
- msm_mdss_setup_ubwc_dec_50(msm_mdss);
- break;
- default:
- dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n",
- msm_mdss->mdss_data->ubwc_dec_version);
- dev_err(msm_mdss->dev, "HW_REV: 0x%x\n",
- readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_VERSION));
- dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n",
- readl_relaxed(msm_mdss->mmio + REG_MDSS_UBWC_DEC_HW_VERSION));
- break;
- }
+ hw_rev = readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_VERSION);
+
+ if (hw_rev >= MDSS_HW_VER(6, 0, 0))
+ msm_mdss_6x_setup_ubwc(msm_mdss);
+ else if (hw_rev >= MDSS_HW_VER(5, 0, 0))
+ msm_mdss_5x_setup_ubwc(msm_mdss);
+ else if (hw_rev >= MDSS_HW_VER(4, 0, 0))
+ msm_mdss_4x_setup_ubwc(msm_mdss);
+ /* else UBWC 1.0 or none, no params to program */

return ret;
}

--
2.47.3