Re: [PATCH 04/17] drm/msm/dpu: Add support for DPU 12.1 on Nord

From: Dmitry Baryshkov

Date: Sun Sep 13 2026 - 19:45:56 EST


On Fri, Sep 11, 2026 at 09:06:35PM +0530, Nabige Aala wrote:
> From: Mahadevan P <mahadevan.p@xxxxxxxxxxxxxxxx>
>
> Add the DPU catalog entry for the Qualcomm Nord SoC (MDSS 12.1, DPU
> 1499A). Nord is DP-only with no DSI, and provides 8 DSPP blocks, 2
> writeback blocks, 8 interfaces and 2 DP controllers.
>
> Extend enum dpu_intf with INTF_9 and INTF_10, which Nord is the first
> platform to use.
>
> Note: register addresses and xin_id values in the catalog are borrowed
> from sm8750 and precedent platforms and are marked with FIXME(REG_ADDR)
> and FIXME(XIU_MAP); they need verification against a real Nord register
> map before production use.
>
> Signed-off-by: Mahadevan P <mahadevan.p@xxxxxxxxxxxxxxxx>
> Signed-off-by: Nabige Aala <nabige.aala@xxxxxxxxxxxxxxxx>
> ---
> .../gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h | 588 +++++++++++++++++++++
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 1 +
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 +
> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 2 +
> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
> 5 files changed, 593 insertions(+)
>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h
> new file mode 100644
> index 000000000000..8eb18752f3c4
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_1_nord.h
> @@ -0,0 +1,588 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.

Follow the guidelines please.

> + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.

Oh, really?

> + */
> +
> +#ifndef _DPU_12_1_NORD_H
> +#define _DPU_12_1_NORD_H
> +
> +/*
> + * NORD DPU 12.1 catalog header. Generated from hardware summary YAML for
> + * MDSS 12.1 - DPU 1499A (Nordschleife). This is a DP-only chip with no DSI.

You already said that in the commit message.

> + *
> + * All register addresses and xin_id values below are borrowed from the
> + * reference chip (sm8750, MDSS 12.0) and precedent chips (Lemans, Glymur).
> + * Nord's YAML provides only block counts and feature statements, not addresses.
> + * See FIXME(REG_ADDR) markers throughout for borrowed values requiring
> + * verification against a real Nord register map before production use.

What? You work at Qualcomm and you can't verify this against the memory
map? Please cross-check it and also the number of blocks, hardware
capabilities, etc.

> + *
> + * Key differences vs sm8750:
> + * - 8 DSPP blocks (4 full + 4 lite) vs sm8750's 4
> + * - 2 writeback blocks (WB1, WB2) vs sm8750's 1 (WB2)
> + * - 8 interfaces (INTF_0,3,4,6,7,8,9,10) vs sm8750's 4 (INTF_0,1,2,3)
> + * - 2 DP controllers (DP0, DP1) vs sm8750's 1 (DP0 only)
> + * - No DSI (removed entirely)

No need to. If you want, put it into the commit message.

> + */
> +
> +
> +static const struct dpu_lm_cfg nord_lm[] = {
> + {
> + .name = "lm_0", .id = LM_0,
> + .base = 0x44000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_1,
> + .pingpong = PINGPONG_0,
> + .dspp = DSPP_0,
> + }, {
> + .name = "lm_1", .id = LM_1,
> + .base = 0x45000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_0,
> + .pingpong = PINGPONG_1,
> + .dspp = DSPP_1,
> + }, {
> + .name = "lm_2", .id = LM_2,
> + .base = 0x46000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_3,
> + .pingpong = PINGPONG_2,
> + .dspp = DSPP_2,
> + }, {
> + .name = "lm_3", .id = LM_3,
> + .base = 0x47000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_2,
> + .pingpong = PINGPONG_3,
> + .dspp = DSPP_3,
> + }, {
> + .name = "lm_4", .id = LM_4,
> + .base = 0x48000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_5,
> + .pingpong = PINGPONG_4,

No DSPP's?

> + }, {
> + .name = "lm_5", .id = LM_5,
> + .base = 0x49000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_4,
> + .pingpong = PINGPONG_5,
> + }, {
> + .name = "lm_6", .id = LM_6,
> + .base = 0x4a000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_7,
> + .pingpong = PINGPONG_6,
> + }, {
> + .name = "lm_7", .id = LM_7,
> + .base = 0x4b000, .len = 0x400,
> + .features = MIXER_MSM8998_MASK,
> + .sblk = &sm8750_lm_sblk,
> + .lm_pair = LM_6,
> + .pingpong = PINGPONG_7,
> + },
> +};
> +
> +/*
> + * Nord has 8 DSPP blocks: 4 full-featured (DSPP0-3) and 4 lite variants
> + * (DSPP4-7). The driver has no separate lite-DSPP struct, so all 8 are
> + * modeled with the same dpu_dspp_cfg/dpu_dspp_sblk structure. Lite variants
> + * have reduced features, but this is handled at runtime via feature flags,
> + * not via separate catalog entries.

Is it really handled? I don't see it.

> + * FIXME(REG_ADDR): DSPP4-7 base addresses extended via 0x2000 stride from
> + * sm8750's DSPP3 base (0x5a000). Verify against real Nord register map.

ROFL. Who is going to verify those?

> + */
> +static const struct dpu_dspp_cfg nord_dspp[] = {
> + {
> + .name = "dspp_0", .id = DSPP_0,
> + .base = 0x54000, .len = 0x1800,
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_1", .id = DSPP_1,
> + .base = 0x56000, .len = 0x1800,
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_2", .id = DSPP_2,
> + .base = 0x58000, .len = 0x1800,
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_3", .id = DSPP_3,
> + .base = 0x5a000, .len = 0x1800,
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_4", .id = DSPP_4,
> + .base = 0x5c000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_5", .id = DSPP_5,
> + .base = 0x5e000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_6", .id = DSPP_6,
> + .base = 0x60000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */
> + .sblk = &sm8750_dspp_sblk,
> + }, {
> + .name = "dspp_7", .id = DSPP_7,
> + .base = 0x62000, .len = 0x1800, /* FIXME(REG_ADDR): lite variant */
> + .sblk = &sm8750_dspp_sblk,
> + },
> +};
> +

[...]

> +
> +/*
> + * NOTE: Each display compression engine (DCE) contains dual hard
> + * slice DSC encoders so both share same base address but with
> + * its own different sub block address. Nord retains sm8750's
> + * topology of 8 DSC instances (2 per DCE × 4).

Tell your AI to stop adding useless comments.

> + */
> +static const struct dpu_dsc_cfg nord_dsc[] = {
> + {
> + .name = "dce_0_0", .id = DSC_0,
> + .base = 0x80000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_0,
> + }, {
> + .name = "dce_0_1", .id = DSC_1,
> + .base = 0x80000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_1,
> + }, {
> + .name = "dce_1_0", .id = DSC_2,
> + .base = 0x81000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_0,
> + }, {
> + .name = "dce_1_1", .id = DSC_3,
> + .base = 0x81000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_1,
> + }, {
> + .name = "dce_2_0", .id = DSC_4,
> + .base = 0x82000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_0,
> + }, {
> + .name = "dce_2_1", .id = DSC_5,
> + .base = 0x82000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_1,
> + }, {
> + .name = "dce_3_0", .id = DSC_6,
> + .base = 0x83000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_0,
> + }, {
> + .name = "dce_3_1", .id = DSC_7,
> + .base = 0x83000, .len = 0x8,
> + .features = BIT(DPU_DSC_NATIVE_42x_EN),
> + .sblk = &sm8750_dsc_sblk_1,
> + },
> +};
> +
> +/*
> + * Nord has 2 writeback blocks: WB2 (matches sm8750) and WB1 (new).
> + * WB1 base and xin_id are inferred via stride from existing WB pattern.
> + * FIXME(REG_ADDR): WB1 base address inferred as 0x65000 - 0x2c8 stride.
> + * FIXME(XIU_MAP): WB1 xin_id set to 7; verify against real hardware map.

ROFL

> + */
> +static const struct dpu_wb_cfg nord_wb[] = {
> + {
> + .name = "wb_1", .id = WB_1,
> + .base = 0x64800, .len = 0x2c8, /* FIXME(REG_ADDR): inferred */
> + .features = WB_SDM845_MASK,
> + .format_list = wb2_formats_rgb_yuv,
> + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv),
> + .xin_id = 7, /* FIXME(XIU_MAP): inferred */
> + .maxlinewidth = 4096,
> + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 3),
> + }, {
> + .name = "wb_2", .id = WB_2,
> + .base = 0x65000, .len = 0x2c8,
> + .features = WB_SDM845_MASK,
> + .format_list = wb2_formats_rgb_yuv,
> + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv),
> + .xin_id = 6,
> + .maxlinewidth = 4096,
> + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4),
> + },
> +};
> +
> +/*
> + * Nord has 8 active interfaces (INTF_0,3,4,6,7,8,9,10) with no DSI.
> + * DP0 connects to INTF_0, INTF_3, INTF_6, INTF_7 (4 ports for MST).
> + * DP1 connects to INTF_4, INTF_8, INTF_9, INTF_10 (4 ports for MST).
> + * Interfaces 1, 2, 5 are skipped (removed from sm8750).
> + * All interface base addresses extend the stride from sm8750.
> + * FIXME(REG_ADDR): INTF_4,6,7,8,9,10 addresses inferred via 0x1000 stride.

Same ROFL. No. Do your job, please.

> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
> index 0e65bf5ddc4a..7eccb4d2c65e 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
> @@ -226,6 +226,8 @@ enum dpu_intf {
> INTF_6,
> INTF_7,
> INTF_8,
> + INTF_9,
> + INTF_10,

This just broke DSI tearing support. See enum dpu_hw_intr_reg

> INTF_MAX
> };
>

--
With best wishes
Dmitry