[PATCH 11/34] drm/amd/display: Fix HostVM init and SOCBB VM config for DCN6
Tom Chung <[email protected]> Wed, 5 Aug 2026 14:36:23 +0800
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
From: Nicholas Kazlauskas <[email protected]> [Why] Underflow occurs in testing for DCHVM and RIOMMU interop tests when attempting to scan out surfaces in VM. [How] New registers have been added to DCN6 for HostVM to control which VFID to prefetch by default. These need to be programmed during the VM init sequence. The sequence validated from DCN42 is used (and xref'd with the design documentation with hardware) with the register placed in an ordering that appears correct. HostVM and GPUVM are also currently disabled and set an incorrect number of page table levels and min page size in the SOCBB for DCN6b. These are updated, but driver also needs to select the B variant when creating the SOC BB to ensure that they're piped into DML. Lastly, the init function for the vm context is branched out to skip initializing VMID 15 - this workaround should no longer be necessary on DCN6. Reviewed-by: Dillon Varone <[email protected]> Signed-off-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Tom Chung <[email protected]> --- .../display/dc/hubbub/dcn10/dcn10_hubbub.h | 4 +- .../display/dc/hubbub/dcn60/dcn60_hubbub.c | 89 ++++++++++++++++++- .../display/dc/hubbub/dcn60/dcn60_hubbub.h | 13 +++ .../dc/resource/dcn60/dcn60_resource.c | 6 ++ .../dc/resource/dcn60/dcn60_resource.h | 6 ++ .../dcn60/dcn60_soc_and_ip_translator.c | 6 +- .../gpu/drm/amd/display/include/dal_asic_id.h | 5 ++ 7 files changed, 126 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h index 5f065b4045ee..53fac324748d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h @@ -143,6 +143,7 @@ struct dcn_hubbub_registers { uint32_t DCHVM_CLK_CTRL; uint32_t DCHVM_RIOMMU_CTRL0; uint32_t DCHVM_RIOMMU_STAT0; + uint32_t DCHVM_PREFETCH_VFID; uint32_t DCHUBBUB_DET0_CTRL; uint32_t DCHUBBUB_DET1_CTRL; uint32_t DCHUBBUB_DET2_CTRL; @@ -398,7 +399,8 @@ struct dcn_hubbub_registers { type HOSTVM_PREFETCH_REQ; \ type HOSTVM_POWERSTATUS; \ type RIOMMU_ACTIVE; \ - type HOSTVM_PREFETCH_DONE + type HOSTVM_PREFETCH_DONE; \ + type HOSTVM_PREFETCH_VFID #define HUBBUB_RET_REG_FIELD_LIST(type) \ type DET_DEPTH;\ diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c index e2a457ab13bb..820b156474e1 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c @@ -18,6 +18,92 @@ #define FN(reg_name, field_name) \ hubbub2->shifts->field_name, hubbub2->masks->field_name +static void dcn60_control_dchvm_gating(const struct hubbub *hubbub, uint32_t disable_gating) +{ + const struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + if (disable_gating != 0) { + REG_UPDATE(DCHVM_MEM_CTRL, HVM_GPUVMRET_FORCE_REQ, 0); + } + + REG_UPDATE(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, disable_gating); + + REG_UPDATE_4(DCHVM_CLK_CTRL, + HVM_DISPCLK_R_GATE_DIS, disable_gating, + HVM_DISPCLK_G_GATE_DIS, disable_gating, + HVM_DCFCLK_R_GATE_DIS, disable_gating, + HVM_DCFCLK_G_GATE_DIS, disable_gating); + + udelay(1); +} + +static void dcn60_dchvm_init(struct hubbub *hubbub) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + uint32_t riommu_active = 0; + uint32_t prefetch_done = 0; + unsigned int i; + + /* If already prefetched return early. */ + REG_GET(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, &prefetch_done); + + if (prefetch_done) { + hubbub->riommu_active = true; + return; + } + + /* Init DCHVM block. */ + REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1); + + /* Poll until the rIOMMU and main IOMMU are active. */ + for (i = 0; i < 100u; i++) { + REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active); + if (riommu_active) + break; + + udelay(5); + } + + if (!riommu_active) { + DC_LOG_ERROR("Timed out waiting for DCHVM RIOMMU_ACTIVE\n"); + return; + } + + /* Disable gating and memory power requests. */ + dcn60_control_dchvm_gating(hubbub, 1); + + /* Select the physical function's host table for the initial prefetch. */ + REG_UPDATE(DCHVM_PREFETCH_VFID, HOSTVM_PREFETCH_VFID, 1U << 31); + + /* Reflect the power status of DCHUBBUB. */ + REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1); + + /* Wait for power status to propagate to rIOMMU before prefetch req.*/ + udelay(5); + + /* Start rIOMMU prefetching. */ + REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1); + + /* Poll for prefetch to be done. */ + REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100); + + /* Re-enable gating and memory power requests. */ + dcn60_control_dchvm_gating(hubbub, 0); + + hubbub->riommu_active = true; +} + +static int hubbub60_init_dchub_sys_ctx(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config) +{ + int num_vmids = hubbub3_init_dchub_sys_ctx(hubbub, pa_config); + + if (hubbub->funcs->dchvm_init) + hubbub->funcs->dchvm_init(hubbub); + + return num_vmids; +} + static void dcn60_init_crb(struct hubbub *hubbub) { struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); @@ -1752,7 +1838,7 @@ static void hubbub60_override_utm_client_qc_profile(struct hubbub *hubbub, uint8 static const struct hubbub_funcs hubbub60_funcs = { .update_dchub = hubbub2_update_dchub, - .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx, + .init_dchub_sys_ctx = hubbub60_init_dchub_sys_ctx, .init_vm_ctx = hubbub2_init_vm_ctx, .dcc_support_swizzle_addr3 = hubbub401_dcc_support_swizzle, .dcc_support_pixel_format_plane0_plane1 = @@ -1768,6 +1854,7 @@ static const struct hubbub_funcs hubbub60_funcs = { .force_pstate_change_control = hubbub3_force_pstate_change_control, .init_watermarks = hubbub60_init_watermarks, .init_crb = dcn60_init_crb, + .dchvm_init = dcn60_dchvm_init, .hubbub_read_state = hubbub2_read_state, .force_usr_retraining_allow = NULL, .set_request_limit = hubbub32_set_request_limit, diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.h index 03b5182d233c..ed47c462e8fe 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.h @@ -16,6 +16,19 @@ #define DCN6_0_CRB_SEGMENT_SIZE_KB 64 #define HUBBUB_MASK_SH_LIST_DCN6_0(mask_sh)\ + HUBBUB_SF(DCHVM_CTRL0, HOSTVM_INIT_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_FORCE_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_POWER_STATUS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_R_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_G_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_R_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_G_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, mask_sh), \ + HUBBUB_SF(DCHVM_PREFETCH_VFID, HOSTVM_PREFETCH_VFID, mask_sh), \ HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ HUBBUB_SF(DCHUBBUB_SOFT_RESET, DCHUBBUB_GLOBAL_SOFT_RESET, mask_sh), \ HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c index 1cbff128789d..2dac5f7486d9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c @@ -1962,6 +1962,8 @@ static bool dcn60_resource_construct( struct ddc_service_init_data ddc_init_data = {0}; uint32_t pipe_fuses = 0; uint32_t num_pipes = 4; + bool is_lite3 = + ASICREV_IS_DCN6_VARIANT_LITE3(ctx->asic_id.hw_internal_rev); #undef REG_STRUCT #define REG_STRUCT bios_regs @@ -2341,6 +2343,10 @@ static bool dcn60_resource_construct( dc->dml2_options.max_segments_per_hubp = 20; dc->dml2_options.det_segment_size = DCN6_0_CRB_SEGMENT_SIZE_KB; + if (is_lite3) { + dc->dml2_options.gpuvm_enable = true; + dc->dml2_options.hostvm_enable = true; + } /* SPL */ dc->caps.scl_caps.sharpener_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.h index 913f049deeb3..b1a802f9f4b4 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.h @@ -59,6 +59,12 @@ bool dcn50_program_mcache_pipe_config(struct dc_state *context, /* HUBBUB */ #define HUBBUB_REG_LIST_DCN60_RI(id) \ + SR(DCHVM_CTRL0), \ + SR(DCHVM_MEM_CTRL), \ + SR(DCHVM_CLK_CTRL), \ + SR(DCHVM_RIOMMU_CTRL0), \ + SR(DCHVM_RIOMMU_STAT0), \ + SR(DCHVM_PREFETCH_VFID), \ SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A), \ SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B), \ SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL), \ diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn60/dcn60_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn60/dcn60_soc_and_ip_translator.c index c26ad0903975..f1ee2225e9b8 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn60/dcn60_soc_and_ip_translator.c +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn60/dcn60_soc_and_ip_translator.c @@ -5,6 +5,7 @@ #include "dcn60_soc_and_ip_translator.h" #include "soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h" #include "bounding_boxes/dcn6_soc_bb.h" +#include "dal_asic_id.h" /* soc_and_ip_translator component used to get up-to-date values for bounding box. * Bounding box values are stored in several locations and locations can vary with DCN revision. @@ -94,7 +95,10 @@ static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc static void dcn60_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) { //get default soc_bb with static values - dcn6_test_initialize_soc_bb(soc_bb); + if (ASICREV_IS_DCN6_VARIANT_LITE3(dc->ctx->asic_id.hw_internal_rev)) + dcn6b_test_initialize_soc_bb(soc_bb); + else + dcn6_test_initialize_soc_bb(soc_bb); //get default soc_bb with static values apply_soc_bb_updates(soc_bb, dc, config); diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index 7ed785be8473..f4c6ddb6378e 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -275,6 +275,8 @@ enum { DCN6_VARIANT2_B0 = 0x11, DCN6_VARIANT3_A0 = 0x20, DCN6_VARIANT3_UPPER = 0x2F, + DCN6_VARIANT_LITE3_A0 = 0x50, + DCN6_VARIANT_LITE3_B0 = 0x51, DCN6_UNKNOWN = 0xFF }; @@ -284,6 +286,9 @@ enum { #define ASICREV_IS_DCN6_VARIANT2_A0(eChipRev) (eChipRev >= DCN6_VARIANT2_A0 && eChipRev < DCN6_VARIANT2_B0) #define ASICREV_IS_DCN6_VARIANT2_B0(eChipRev) (eChipRev >= DCN6_VARIANT2_B0 && eChipRev < DCN6_VARIANT3_A0) #define ASICREV_IS_DCN6_VARIANT3(eChipRev) (eChipRev >= DCN6_VARIANT3_A0 && eChipRev <= DCN6_VARIANT3_UPPER) +#define ASICREV_IS_DCN6_VARIANT_LITE3(eChipRev) (eChipRev >= DCN6_VARIANT_LITE3_A0 && eChipRev < DCN6_UNKNOWN) +#define ASICREV_IS_DCN6_VARIANT_LITE3_A0(eChipRev) (eChipRev >= DCN6_VARIANT_LITE3_A0 && eChipRev < DCN6_VARIANT_LITE3_B0) +#define ASICREV_IS_DCN6_VARIANT_LITE3_B0(eChipRev) (eChipRev >= DCN6_VARIANT_LITE3_B0 && eChipRev < DCN6_UNKNOWN) enum { GC_12_0_0_A0 = 0x50, -- 2.43.0