diff mbox series

[6/6] drm/msm/dpu: Update dev core dump to dump registers of sub blocks

Message ID 20230622-devcoredump_patch-v1-6-3b2cdcc6a576@quicinc.com
State New
Headers show
Series Add support to print sub block registers in dpu hw catalog | expand

Commit Message

Ryan McCann June 22, 2023, 11:48 p.m. UTC
Currently, the device core dump mechanism does not dump registers of sub
blocks within the DSPP, SSPP, DSC, and PINGPONG blocks. Add wrapper
function to dump hardware blocks that contain sub blocks.

Signed-off-by: Ryan McCann <quic_rmccann@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 194 +++++++++++++++++++++++++++-----
 1 file changed, 168 insertions(+), 26 deletions(-)

Comments

Abhinav Kumar June 29, 2023, 11:29 p.m. UTC | #1
On 6/24/2023 7:44 PM, Abhinav Kumar wrote:
> 
> 
> On 6/24/2023 8:03 AM, Dmitry Baryshkov wrote:
>> On 24/06/2023 17:17, Abhinav Kumar wrote:
>>>
>>>
>>> On 6/24/2023 5:07 AM, Dmitry Baryshkov wrote:
>>>> On 24/06/2023 03:09, Abhinav Kumar wrote:
>>>>>
>>>>>
>>>>> On 6/22/2023 5:13 PM, Dmitry Baryshkov wrote:
>>>>>> On 23/06/2023 02:48, Ryan McCann wrote:
>>>>>>> Currently, the device core dump mechanism does not dump registers 
>>>>>>> of sub
>>>>>>> blocks within the DSPP, SSPP, DSC, and PINGPONG blocks. Add wrapper
>>>>>>> function to dump hardware blocks that contain sub blocks.
>>>>>>>
>>>>>>> Signed-off-by: Ryan McCann <quic_rmccann@quicinc.com>
>>>>>>> ---
>>>>>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 194 
>>>>>>> +++++++++++++++++++++++++++-----
>>>>>>>   1 file changed, 168 insertions(+), 26 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>> index aa8499de1b9f..9b1b1c382269 100644
>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>> @@ -885,6 +885,154 @@ static int dpu_irq_postinstall(struct 
>>>>>>> msm_kms *kms)
>>>>>>>       return 0;
>>>>>>>   }
>>>>>>> +static void dpu_kms_mdp_snapshot_add_block(struct msm_disp_state 
>>>>>>> *disp_state,
>>>>>>> +                       void __iomem *mmio, void *blk,
>>>>>>> +                       enum dpu_hw_blk_type blk_type)
>>>>>>
>>>>>> No. Such multiplexers add no value to the code. Please inline it.
>>>>>>
>>>>>> Not to mention that this patch is hard to review. You both move 
>>>>>> existing code and add new features. If it were to go, it should 
>>>>>> have been split into two patches: one introducing the multiplexer 
>>>>>> and another one adding subblocks.
>>>>>>
>>>>>
>>>>> Ok. we can split this into:
>>>>>
>>>>> 1) adding the multiplexer
>>>>> 2) adding sub-blk parsing support inside the multiplexer
>>>>
>>>> I'd say, drop the multiplexer completely. It adds no value here. It 
>>>> is only used from dpu_kms_mdp_snapshot(). If the code there was 
>>>> complex enough, it would have made sense to _split_ the function. 
>>>> But even in such case there would be no point in having multiplexer. 
>>>> We do not enumerate block by type.
>>>>
>>>
>>> Can you pls elaborate what you mean by enumerate blk by type?
>>>
>>> We do have DPU_HW_BLK_***
>>>
>>> Did you mean sub-blk?
>>>
>>>>>
>>>>>>> +{
>>>>>>> +    u32 base;
>>>>>>> +
>>>>>>> +    switch (blk_type) {
>>>>>>> +    case DPU_HW_BLK_TOP:
>>>>>>> +    {
>>>>>>> +        struct dpu_mdp_cfg *top = (struct dpu_mdp_cfg *)blk;
>>>>>>> +
>>>>>>> +        if (top->features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {
>>>>>>> +            msm_disp_snapshot_add_block(disp_state, 
>>>>>>> MDP_PERIPH_TOP0,
>>>>>>> +                            mmio + top->base, "top");
>>>>>>> +            msm_disp_snapshot_add_block(disp_state, top->len - 
>>>>>>> MDP_PERIPH_TOP0_END,
>>>>>>> +                            mmio + top->base + MDP_PERIPH_TOP0_END,
>>>>>>> +                            "top_2");
>>>>>>> +        } else {
>>>>>>> +            msm_disp_snapshot_add_block(disp_state, top->len, 
>>>>>>> mmio + top->base, "top");
>>>>>>> +        }
>>>>>>> +        break;
>>>>>>> +    }
>>>>>>> +    case DPU_HW_BLK_LM:
>>>>>>> +    {
>>>>>>> +        struct dpu_lm_cfg *mixer = (struct dpu_lm_cfg *)blk;
>>>>>>> +
>>>>>>> +        msm_disp_snapshot_add_block(disp_state, mixer->len, mmio 
>>>>>>> + mixer->base, "%s",
>>>>>>> +                        mixer->name);
>>>>>>> +        break;
>>>>>>> +    }
>>>>>>> +    case DPU_HW_BLK_CTL:
>>>>>>> +    {
>>>>>>> +        struct dpu_ctl_cfg *ctl = (struct dpu_ctl_cfg *)blk;
>>>>>>> +
>>>>>>> +        msm_disp_snapshot_add_block(disp_state, ctl->len, mmio + 
>>>>>>> ctl->base, "%s",
>>>>>>> +                        ctl->name);
>>>>>>> +        break;
>>>>>>> +    }
>>>>>>> +    case DPU_HW_BLK_INTF:
>>>>>>> +    {
>>>>>>> +        struct dpu_intf_cfg *intf = (struct dpu_intf_cfg *)blk;
>>>>>>> +
>>>>>>> +        msm_disp_snapshot_add_block(disp_state, intf->len, mmio 
>>>>>>> + intf->base, "%s",
>>>>>>> +                        intf->name);
>>>>>>> +        break;
>>>>>>> +    }
>>>>>>> +    case DPU_HW_BLK_WB:
>>>>>>> +    {
>>>>>>> +        struct dpu_wb_cfg *wb = (struct dpu_wb_cfg *)blk;
>>>>>>> +
>>>>>>> +        msm_disp_snapshot_add_block(disp_state, wb->len, mmio + 
>>>>>>> wb->base, "%s",
>>>>>>> +                        wb->name);
>>>>>>> +        break;
>>>>>>> +    }
>>>>>>> +    case DPU_HW_BLK_SSPP:
>>>>>>> +    {
>>>>>>> +        struct dpu_sspp_cfg *sspp_block = (struct dpu_sspp_cfg 
>>>>>>> *)blk;
>>>>>>> +        const struct dpu_sspp_sub_blks *sblk = sspp_block->sblk;
>>>>>>> +
>>>>>>> +        base = sspp_block->base;
>>>>>>> +
>>>>>>> +        msm_disp_snapshot_add_block(disp_state, sspp_block->len, 
>>>>>>> mmio + base, "%s",
>>>>>>> +                        sspp_block->name);
>>>>>>> +
>>>>>>> +        if (sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED3) ||
>>>>>>> +            sspp_block->features & 
>>>>>>> BIT(DPU_SSPP_SCALER_QSEED3LITE) ||
>>>>>>> +            sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED4))
>>>>>>> +            msm_disp_snapshot_add_block(disp_state, 
>>>>>>> sblk->scaler_blk.len,
>>>>>>> +                            mmio + base + sblk->scaler_blk.base, 
>>>>>>> "%s_%s",
>>>>>>> +                            sspp_block->name, 
>>>>>>> sblk->scaler_blk.name);
>>>>>>
>>>>>> Actually, it would be better to:
>>>>>> - drop name from all sblk instances (and use known string instead 
>>>>>> of the sblk name here)
>>>>>> - Use sblk->foo_blk.len to check if it should be printed or not.
>>>>>>
>>>>>
>>>>> No, I dont agree. If we drop the names from the sub_blk in the 
>>>>> catalog, we will end up using "sub_blk_name" string here in the 
>>>>> code to indicate which blk that is in the dump.
>>>>>
>>>>> If we add more sub_blks in the catalog in the future we need to 
>>>>> keep changing the code over here. Thats not how it should be.
>>>>>
>>>>> Leaving the names in the catalog ensures that this code wont change 
>>>>> and only catalog changes when we add a new sub_blk either for an 
>>>>> existing or new chipset.
>>>>>
>>>>> catalog is indicating the new blk, and dumping code just prints it.
>>>>>
>>>>> with your approach, dumping code will or can keep changing with 
>>>>> chipsets or sub_blks. Thats not how it should be.
>>>>
>>>> Well, we do not enumerate sub-blocks in any way, they are not 
>>>> indexed. So even with sblk->blk.name in place, adding new sub-block 
>>>> would require adding new code here. That's why I wrote that the 
>>>> calling code knows which sub-block it refers to.
>>>>
>>>
>>> Today, unfortunately each sub_blk type is different so we have to do 
>>> this case by case.
>>>
>>> Ideally, this should have just been
>>>
>>> -> print main blk
>>> -> print all sub-blks of the main blk
>>>
>>> Without having to handle each main blk's sub-blks separately.
>>>
>>> That way the dumping code would have remained generic without having 
>>> to do even the multiplexer in the first place.
>>>
>>> Need to explore if somehow we can come up with a generic sub-blk 
>>> struct and make this possible. Then this code will become much easier 
>>> and what I am saying will make total sense.
>>
>> In such case, yes. However I'd warn about having a generic array of 
>> subblocks. Having named subblock entries might complicate 
>> snapshotting, but it makes the rest of the DPU driver smaller.
>>
> 
> Need to explore this. But not immediately.
> 
>>>
>>> Even without that, conceptually these sub-blk names are reflecting 
>>> whats in our software document. So its not a random name but reflects 
>>> the actual sub-blk name from the hardware.
>>
>> Yes
>>
>>> So this belongs in the catalog.
>>
>> But the sub-block field already has a correct name: scaler_blk, 
>> csc_blk, etc. Having both sub-block field name and the .name inside 
>> results in kind of duplication, which seems unnecessary to me.
>>
> 
> No, there is a difference and not duplicated. One is the name of the 
> struct so it can really be anything and doesnt need to match the hw doc 
> name. But the other is the string name which we can give exactly to 
> match software interface doc and makes parsing such a dump much much 
> easier.
> 
> One point I dont see you have considered is the block index of the sub_blk.
> 
> Today, yes I see only a "pcc" or a "dither" etc
> 
> What if there are two PCCs or two dithers.
> 
> Then their names can just be "pcc_0" and "pcc_1" or "dither_0" and 
> "dither_1".
> 
> Having name gives us the ability to easily incorporate even unsequential 
> indices.
> 
> For example, every sspp's name today is not sequential. it can be 
> "sspp_3" then "sspp_8" etc
> 
> By having names reflect the correct indices, dumping code becomes less 
> complex as the catalog will still have the right names as dumping code 
> will just use that.
> 

The QC team is in agreement that we would like to go ahead with the 
names from the catalog and not drop them.

Hence we will post the next revision with the name still from the 
catalog and drop the multiplexer completely.

Since the intern has a short period of time to finish development on 
this task, we would like to go ahead with this approach and post the 
next rev.
Dmitry Baryshkov June 30, 2023, 12:10 a.m. UTC | #2
On 30/06/2023 02:29, Abhinav Kumar wrote:
> 
> 
> On 6/24/2023 7:44 PM, Abhinav Kumar wrote:
>>
>>
>> On 6/24/2023 8:03 AM, Dmitry Baryshkov wrote:
>>> On 24/06/2023 17:17, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 6/24/2023 5:07 AM, Dmitry Baryshkov wrote:
>>>>> On 24/06/2023 03:09, Abhinav Kumar wrote:
>>>>>>
>>>>>>
>>>>>> On 6/22/2023 5:13 PM, Dmitry Baryshkov wrote:
>>>>>>> On 23/06/2023 02:48, Ryan McCann wrote:
>>>>>>>> Currently, the device core dump mechanism does not dump 
>>>>>>>> registers of sub
>>>>>>>> blocks within the DSPP, SSPP, DSC, and PINGPONG blocks. Add wrapper
>>>>>>>> function to dump hardware blocks that contain sub blocks.
>>>>>>>>
>>>>>>>> Signed-off-by: Ryan McCann <quic_rmccann@quicinc.com>
>>>>>>>> ---
>>>>>>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 194 
>>>>>>>> +++++++++++++++++++++++++++-----
>>>>>>>>   1 file changed, 168 insertions(+), 26 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
>>>>>>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>>> index aa8499de1b9f..9b1b1c382269 100644
>>>>>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>>>>>> @@ -885,6 +885,154 @@ static int dpu_irq_postinstall(struct 
>>>>>>>> msm_kms *kms)
>>>>>>>>       return 0;
>>>>>>>>   }
>>>>>>>> +static void dpu_kms_mdp_snapshot_add_block(struct 
>>>>>>>> msm_disp_state *disp_state,
>>>>>>>> +                       void __iomem *mmio, void *blk,
>>>>>>>> +                       enum dpu_hw_blk_type blk_type)
>>>>>>>
>>>>>>> No. Such multiplexers add no value to the code. Please inline it.
>>>>>>>
>>>>>>> Not to mention that this patch is hard to review. You both move 
>>>>>>> existing code and add new features. If it were to go, it should 
>>>>>>> have been split into two patches: one introducing the multiplexer 
>>>>>>> and another one adding subblocks.
>>>>>>>
>>>>>>
>>>>>> Ok. we can split this into:
>>>>>>
>>>>>> 1) adding the multiplexer
>>>>>> 2) adding sub-blk parsing support inside the multiplexer
>>>>>
>>>>> I'd say, drop the multiplexer completely. It adds no value here. It 
>>>>> is only used from dpu_kms_mdp_snapshot(). If the code there was 
>>>>> complex enough, it would have made sense to _split_ the function. 
>>>>> But even in such case there would be no point in having 
>>>>> multiplexer. We do not enumerate block by type.
>>>>>
>>>>
>>>> Can you pls elaborate what you mean by enumerate blk by type?
>>>>
>>>> We do have DPU_HW_BLK_***
>>>>
>>>> Did you mean sub-blk?
>>>>
>>>>>>
>>>>>>>> +{
>>>>>>>> +    u32 base;
>>>>>>>> +
>>>>>>>> +    switch (blk_type) {
>>>>>>>> +    case DPU_HW_BLK_TOP:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_mdp_cfg *top = (struct dpu_mdp_cfg *)blk;
>>>>>>>> +
>>>>>>>> +        if (top->features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {
>>>>>>>> +            msm_disp_snapshot_add_block(disp_state, 
>>>>>>>> MDP_PERIPH_TOP0,
>>>>>>>> +                            mmio + top->base, "top");
>>>>>>>> +            msm_disp_snapshot_add_block(disp_state, top->len - 
>>>>>>>> MDP_PERIPH_TOP0_END,
>>>>>>>> +                            mmio + top->base + 
>>>>>>>> MDP_PERIPH_TOP0_END,
>>>>>>>> +                            "top_2");
>>>>>>>> +        } else {
>>>>>>>> +            msm_disp_snapshot_add_block(disp_state, top->len, 
>>>>>>>> mmio + top->base, "top");
>>>>>>>> +        }
>>>>>>>> +        break;
>>>>>>>> +    }
>>>>>>>> +    case DPU_HW_BLK_LM:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_lm_cfg *mixer = (struct dpu_lm_cfg *)blk;
>>>>>>>> +
>>>>>>>> +        msm_disp_snapshot_add_block(disp_state, mixer->len, 
>>>>>>>> mmio + mixer->base, "%s",
>>>>>>>> +                        mixer->name);
>>>>>>>> +        break;
>>>>>>>> +    }
>>>>>>>> +    case DPU_HW_BLK_CTL:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_ctl_cfg *ctl = (struct dpu_ctl_cfg *)blk;
>>>>>>>> +
>>>>>>>> +        msm_disp_snapshot_add_block(disp_state, ctl->len, mmio 
>>>>>>>> + ctl->base, "%s",
>>>>>>>> +                        ctl->name);
>>>>>>>> +        break;
>>>>>>>> +    }
>>>>>>>> +    case DPU_HW_BLK_INTF:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_intf_cfg *intf = (struct dpu_intf_cfg *)blk;
>>>>>>>> +
>>>>>>>> +        msm_disp_snapshot_add_block(disp_state, intf->len, mmio 
>>>>>>>> + intf->base, "%s",
>>>>>>>> +                        intf->name);
>>>>>>>> +        break;
>>>>>>>> +    }
>>>>>>>> +    case DPU_HW_BLK_WB:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_wb_cfg *wb = (struct dpu_wb_cfg *)blk;
>>>>>>>> +
>>>>>>>> +        msm_disp_snapshot_add_block(disp_state, wb->len, mmio + 
>>>>>>>> wb->base, "%s",
>>>>>>>> +                        wb->name);
>>>>>>>> +        break;
>>>>>>>> +    }
>>>>>>>> +    case DPU_HW_BLK_SSPP:
>>>>>>>> +    {
>>>>>>>> +        struct dpu_sspp_cfg *sspp_block = (struct dpu_sspp_cfg 
>>>>>>>> *)blk;
>>>>>>>> +        const struct dpu_sspp_sub_blks *sblk = sspp_block->sblk;
>>>>>>>> +
>>>>>>>> +        base = sspp_block->base;
>>>>>>>> +
>>>>>>>> +        msm_disp_snapshot_add_block(disp_state, 
>>>>>>>> sspp_block->len, mmio + base, "%s",
>>>>>>>> +                        sspp_block->name);
>>>>>>>> +
>>>>>>>> +        if (sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED3) ||
>>>>>>>> +            sspp_block->features & 
>>>>>>>> BIT(DPU_SSPP_SCALER_QSEED3LITE) ||
>>>>>>>> +            sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED4))
>>>>>>>> +            msm_disp_snapshot_add_block(disp_state, 
>>>>>>>> sblk->scaler_blk.len,
>>>>>>>> +                            mmio + base + 
>>>>>>>> sblk->scaler_blk.base, "%s_%s",
>>>>>>>> +                            sspp_block->name, 
>>>>>>>> sblk->scaler_blk.name);
>>>>>>>
>>>>>>> Actually, it would be better to:
>>>>>>> - drop name from all sblk instances (and use known string instead 
>>>>>>> of the sblk name here)
>>>>>>> - Use sblk->foo_blk.len to check if it should be printed or not.
>>>>>>>
>>>>>>
>>>>>> No, I dont agree. If we drop the names from the sub_blk in the 
>>>>>> catalog, we will end up using "sub_blk_name" string here in the 
>>>>>> code to indicate which blk that is in the dump.
>>>>>>
>>>>>> If we add more sub_blks in the catalog in the future we need to 
>>>>>> keep changing the code over here. Thats not how it should be.
>>>>>>
>>>>>> Leaving the names in the catalog ensures that this code wont 
>>>>>> change and only catalog changes when we add a new sub_blk either 
>>>>>> for an existing or new chipset.
>>>>>>
>>>>>> catalog is indicating the new blk, and dumping code just prints it.
>>>>>>
>>>>>> with your approach, dumping code will or can keep changing with 
>>>>>> chipsets or sub_blks. Thats not how it should be.
>>>>>
>>>>> Well, we do not enumerate sub-blocks in any way, they are not 
>>>>> indexed. So even with sblk->blk.name in place, adding new sub-block 
>>>>> would require adding new code here. That's why I wrote that the 
>>>>> calling code knows which sub-block it refers to.
>>>>>
>>>>
>>>> Today, unfortunately each sub_blk type is different so we have to do 
>>>> this case by case.
>>>>
>>>> Ideally, this should have just been
>>>>
>>>> -> print main blk
>>>> -> print all sub-blks of the main blk
>>>>
>>>> Without having to handle each main blk's sub-blks separately.
>>>>
>>>> That way the dumping code would have remained generic without having 
>>>> to do even the multiplexer in the first place.
>>>>
>>>> Need to explore if somehow we can come up with a generic sub-blk 
>>>> struct and make this possible. Then this code will become much 
>>>> easier and what I am saying will make total sense.
>>>
>>> In such case, yes. However I'd warn about having a generic array of 
>>> subblocks. Having named subblock entries might complicate 
>>> snapshotting, but it makes the rest of the DPU driver smaller.
>>>
>>
>> Need to explore this. But not immediately.
>>
>>>>
>>>> Even without that, conceptually these sub-blk names are reflecting 
>>>> whats in our software document. So its not a random name but 
>>>> reflects the actual sub-blk name from the hardware.
>>>
>>> Yes
>>>
>>>> So this belongs in the catalog.
>>>
>>> But the sub-block field already has a correct name: scaler_blk, 
>>> csc_blk, etc. Having both sub-block field name and the .name inside 
>>> results in kind of duplication, which seems unnecessary to me.
>>>
>>
>> No, there is a difference and not duplicated. One is the name of the 
>> struct so it can really be anything and doesnt need to match the hw 
>> doc name. But the other is the string name which we can give exactly 
>> to match software interface doc and makes parsing such a dump much 
>> much easier.
>>
>> One point I dont see you have considered is the block index of the 
>> sub_blk.
>>
>> Today, yes I see only a "pcc" or a "dither" etc
>>
>> What if there are two PCCs or two dithers.
>>
>> Then their names can just be "pcc_0" and "pcc_1" or "dither_0" and 
>> "dither_1".
>>
>> Having name gives us the ability to easily incorporate even 
>> unsequential indices.
>>
>> For example, every sspp's name today is not sequential. it can be 
>> "sspp_3" then "sspp_8" etc
>>
>> By having names reflect the correct indices, dumping code becomes less 
>> complex as the catalog will still have the right names as dumping code 
>> will just use that.
>>
> 
> The QC team is in agreement that we would like to go ahead with the 
> names from the catalog and not drop them.
> 
> Hence we will post the next revision with the name still from the 
> catalog and drop the multiplexer completely.

Ack, let's see how it goes.

> 
> Since the intern has a short period of time to finish development on 
> this task, we would like to go ahead with this approach and post the 
> next rev.

This is a bad argument.
diff mbox series

Patch

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index aa8499de1b9f..9b1b1c382269 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -885,6 +885,154 @@  static int dpu_irq_postinstall(struct msm_kms *kms)
 	return 0;
 }
 
+static void dpu_kms_mdp_snapshot_add_block(struct msm_disp_state *disp_state,
+					   void __iomem *mmio, void *blk,
+					   enum dpu_hw_blk_type blk_type)
+{
+	u32 base;
+
+	switch (blk_type) {
+	case DPU_HW_BLK_TOP:
+	{
+		struct dpu_mdp_cfg *top = (struct dpu_mdp_cfg *)blk;
+
+		if (top->features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {
+			msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0,
+						    mmio + top->base, "top");
+			msm_disp_snapshot_add_block(disp_state, top->len - MDP_PERIPH_TOP0_END,
+						    mmio + top->base + MDP_PERIPH_TOP0_END,
+						    "top_2");
+		} else {
+			msm_disp_snapshot_add_block(disp_state, top->len, mmio + top->base, "top");
+		}
+		break;
+	}
+	case DPU_HW_BLK_LM:
+	{
+		struct dpu_lm_cfg *mixer = (struct dpu_lm_cfg *)blk;
+
+		msm_disp_snapshot_add_block(disp_state, mixer->len, mmio + mixer->base, "%s",
+					    mixer->name);
+		break;
+	}
+	case DPU_HW_BLK_CTL:
+	{
+		struct dpu_ctl_cfg *ctl = (struct dpu_ctl_cfg *)blk;
+
+		msm_disp_snapshot_add_block(disp_state, ctl->len, mmio + ctl->base, "%s",
+					    ctl->name);
+		break;
+	}
+	case DPU_HW_BLK_INTF:
+	{
+		struct dpu_intf_cfg *intf = (struct dpu_intf_cfg *)blk;
+
+		msm_disp_snapshot_add_block(disp_state, intf->len, mmio + intf->base, "%s",
+					    intf->name);
+		break;
+	}
+	case DPU_HW_BLK_WB:
+	{
+		struct dpu_wb_cfg *wb = (struct dpu_wb_cfg *)blk;
+
+		msm_disp_snapshot_add_block(disp_state, wb->len, mmio + wb->base, "%s",
+					    wb->name);
+		break;
+	}
+	case DPU_HW_BLK_SSPP:
+	{
+		struct dpu_sspp_cfg *sspp_block = (struct dpu_sspp_cfg *)blk;
+		const struct dpu_sspp_sub_blks *sblk = sspp_block->sblk;
+
+		base = sspp_block->base;
+
+		msm_disp_snapshot_add_block(disp_state, sspp_block->len, mmio + base, "%s",
+					    sspp_block->name);
+
+		if (sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED3) ||
+		    sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED3LITE) ||
+		    sspp_block->features & BIT(DPU_SSPP_SCALER_QSEED4))
+			msm_disp_snapshot_add_block(disp_state, sblk->scaler_blk.len,
+						    mmio + base + sblk->scaler_blk.base, "%s_%s",
+						    sspp_block->name, sblk->scaler_blk.name);
+
+		if (sspp_block->features & BIT(DPU_SSPP_CSC) || sspp_block->features
+					& BIT(DPU_SSPP_CSC_10BIT))
+			msm_disp_snapshot_add_block(disp_state, sblk->csc_blk.len,
+						    mmio + base + sblk->csc_blk.base, "%s_%s",
+						    sspp_block->name, sblk->csc_blk.name);
+		break;
+	}
+	case DPU_HW_BLK_DSPP:
+	{
+		struct dpu_dspp_cfg *dspp_block = (struct dpu_dspp_cfg *)blk;
+
+		base = dspp_block->base;
+
+		msm_disp_snapshot_add_block(disp_state, dspp_block->len, mmio + base, "%s",
+					    dspp_block->name);
+
+		if (dspp_block->features & BIT(DPU_DSPP_PCC))
+			msm_disp_snapshot_add_block(disp_state, dspp_block->sblk->pcc.len,
+						    mmio + base + dspp_block->sblk->pcc.base,
+						    "%s_%s", dspp_block->name,
+						    dspp_block->sblk->pcc.name);
+		break;
+	}
+	case DPU_HW_BLK_PINGPONG:
+	{
+		struct dpu_pingpong_cfg *pingpong_block = (struct dpu_pingpong_cfg *)blk;
+		const struct dpu_pingpong_sub_blks *sblk = pingpong_block->sblk;
+
+		base = pingpong_block->base;
+
+		msm_disp_snapshot_add_block(disp_state, pingpong_block->len, mmio + base, "%s",
+					    pingpong_block->name);
+
+		if (pingpong_block->features & BIT(DPU_PINGPONG_TE2))
+			msm_disp_snapshot_add_block(disp_state, sblk->te2.len,
+						    mmio + base + sblk->te2.base, "%s_%s",
+						    pingpong_block->name, sblk->te2.name);
+
+		if (pingpong_block->features & BIT(DPU_PINGPONG_DITHER))
+			msm_disp_snapshot_add_block(disp_state, sblk->dither.len,
+						    mmio + base + sblk->dither.base, "%s_%s",
+						    pingpong_block->name, sblk->dither.name);
+		break;
+	}
+	case DPU_HW_BLK_DSC:
+	{
+		struct dpu_dsc_cfg *dsc_block = (struct dpu_dsc_cfg *)blk;
+
+		base = dsc_block->base;
+
+		if (dsc_block->features & BIT(DPU_DSC_HW_REV_1_2)) {
+			struct dpu_dsc_blk enc = dsc_block->sblk->enc;
+			struct dpu_dsc_blk ctl = dsc_block->sblk->ctl;
+
+			/* For now, pass in a length of 0 because the DSC_BLK register space
+			 * overlaps with the sblks' register space.
+			 *
+			 * TODO: Pass in a length of 0 t0 DSC_BLK_1_2 in the HW catalog where
+			 * applicable.
+			 */
+			msm_disp_snapshot_add_block(disp_state, 0, mmio + base, "%s",
+						    dsc_block->name);
+			msm_disp_snapshot_add_block(disp_state, enc.len, mmio + base + enc.base,
+						    "%s_%s", dsc_block->name, enc.name);
+			msm_disp_snapshot_add_block(disp_state, ctl.len, mmio + base + ctl.base,
+						    "%s_%s", dsc_block->name, ctl.name);
+		} else {
+			msm_disp_snapshot_add_block(disp_state, dsc_block->len, mmio + base, "%s",
+						    dsc_block->name);
+		}
+		break;
+	}
+	default:
+		DPU_ERROR("Block type not supported.");
+	}
+}
+
 static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_kms *kms)
 {
 	int i;
@@ -899,53 +1047,47 @@  static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
 
 	/* dump CTL sub-blocks HW regs info */
 	for (i = 0; i < cat->ctl_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,
-				dpu_kms->mmio + cat->ctl[i].base, "ctl_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->ctl[i],
+					       DPU_HW_BLK_CTL);
 
 	/* dump DSPP sub-blocks HW regs info */
 	for (i = 0; i < cat->dspp_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->dspp[i].len,
-				dpu_kms->mmio + cat->dspp[i].base, "dspp_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->dspp[i],
+					       DPU_HW_BLK_DSPP);
 
 	/* dump INTF sub-blocks HW regs info */
 	for (i = 0; i < cat->intf_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->intf[i].len,
-				dpu_kms->mmio + cat->intf[i].base, "intf_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->intf[i],
+					       DPU_HW_BLK_INTF);
 
 	/* dump PP sub-blocks HW regs info */
 	for (i = 0; i < cat->pingpong_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->pingpong[i].len,
-				dpu_kms->mmio + cat->pingpong[i].base, "pingpong_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->pingpong[i],
+					       DPU_HW_BLK_PINGPONG);
 
 	/* dump SSPP sub-blocks HW regs info */
 	for (i = 0; i < cat->sspp_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->sspp[i].len,
-				dpu_kms->mmio + cat->sspp[i].base, "sspp_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->sspp[i],
+					       DPU_HW_BLK_SSPP);
 
 	/* dump LM sub-blocks HW regs info */
 	for (i = 0; i < cat->mixer_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len,
-				dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->mixer[i],
+					       DPU_HW_BLK_LM);
 
 	/* dump WB sub-blocks HW regs info */
 	for (i = 0; i < cat->wb_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
-				dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
-
-	if (cat->mdp[0].features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {
-		msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0,
-				dpu_kms->mmio + cat->mdp[0].base, "top");
-		msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len - MDP_PERIPH_TOP0_END,
-				dpu_kms->mmio + cat->mdp[0].base + MDP_PERIPH_TOP0_END, "top_2");
-	} else {
-		msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len,
-				dpu_kms->mmio + cat->mdp[0].base, "top");
-	}
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->wb[i],
+					       DPU_HW_BLK_WB);
+
+	/* dump top block */
+	dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->mdp[0],
+				       DPU_HW_BLK_TOP);
 
 	/* dump DSC sub-blocks HW regs info */
 	for (i = 0; i < cat->dsc_count; i++)
-		msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
-				dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
+		dpu_kms_mdp_snapshot_add_block(disp_state, dpu_kms->mmio, (void *)&cat->dsc[i],
+					       DPU_HW_BLK_DSC);
 
 	pm_runtime_put_sync(&dpu_kms->pdev->dev);
 }