]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Migrate DIO registers access from hwseq to dio component.
authorBhuvanachandra Pinninti <bpinnint@amd.com>
Thu, 8 Jan 2026 13:07:57 +0000 (18:37 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 3 Feb 2026 21:43:03 +0000 (16:43 -0500)
[why]
Direct DIO registers access in hwseq layer was creating register conflicts.

[how]
Migrated DIO registers from hwseq to dio component.

Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Signed-off-by: Bhuvanachandra Pinninti <bpinnint@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
13 files changed:
drivers/gpu/drm/amd/display/dc/dio/Makefile
drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/hw/dio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c

index 0dfd480976f774ed169063cd6072ce67c74ecce1..02eec03dc2041264b97bccdc26d8b699ca5e61d2 100644 (file)
@@ -27,7 +27,7 @@ ifdef CONFIG_DRM_AMD_DC_FP
 ###############################################################################
 # DCN10
 ###############################################################################
-DIO_DCN10 = dcn10_link_encoder.o dcn10_stream_encoder.o
+DIO_DCN10 = dcn10_link_encoder.o dcn10_stream_encoder.o dcn10_dio.o
 
 AMD_DAL_DIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/dio/dcn10/,$(DIO_DCN10))
 
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c
new file mode 100644 (file)
index 0000000..edcf4e6
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#include "dc_hw_types.h"
+#include "dm_services.h"
+#include "reg_helper.h"
+#include "dcn10_dio.h"
+
+#define CTX \
+       dio10->base.ctx
+#define REG(reg)\
+       dio10->regs->reg
+
+#undef FN
+#define FN(reg_name, field_name) \
+       dio10->shifts->field_name, dio10->masks->field_name
+
+static void dcn10_dio_mem_pwr_ctrl(struct dio *dio, bool enable_i2c_light_sleep)
+{
+       struct dcn10_dio *dio10 = TO_DCN10_DIO(dio);
+
+       /* power AFMT HDMI memory */
+       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+
+       if (enable_i2c_light_sleep)
+               REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1);
+}
+
+static const struct dio_funcs dcn10_dio_funcs = {
+       .mem_pwr_ctrl = dcn10_dio_mem_pwr_ctrl,
+};
+
+void dcn10_dio_construct(
+       struct dcn10_dio *dio10,
+       struct dc_context *ctx,
+       const struct dcn_dio_registers *regs,
+       const struct dcn_dio_shift *shifts,
+       const struct dcn_dio_mask *masks)
+{
+       dio10->base.ctx = ctx;
+       dio10->base.funcs = &dcn10_dio_funcs;
+
+       dio10->regs = regs;
+       dio10->shifts = shifts;
+       dio10->masks = masks;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h
new file mode 100644 (file)
index 0000000..369c599
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef __DCN10_DIO_H__
+#define __DCN10_DIO_H__
+
+#include "dio.h"
+
+#define TO_DCN10_DIO(dio_base) \
+       container_of(dio_base, struct dcn10_dio, base)
+
+#define DIO_REG_LIST_DCN10()\
+       SR(DIO_MEM_PWR_CTRL)
+
+struct dcn_dio_registers {
+       uint32_t DIO_MEM_PWR_CTRL;
+};
+
+struct dcn_dio_shift {
+       uint8_t I2C_LIGHT_SLEEP_FORCE;
+};
+
+struct dcn_dio_mask {
+       uint32_t I2C_LIGHT_SLEEP_FORCE;
+};
+
+struct dcn10_dio {
+       struct dio base;
+       const struct dcn_dio_registers *regs;
+       const struct dcn_dio_shift *shifts;
+       const struct dcn_dio_mask *masks;
+};
+
+void dcn10_dio_construct(
+       struct dcn10_dio *dio10,
+       struct dc_context *ctx,
+       const struct dcn_dio_registers *regs,
+       const struct dcn_dio_shift *shifts,
+       const struct dcn_dio_mask *masks);
+
+#endif /* __DCN10_DIO_H__ */
index f89b2f5a9bbd37635a53e70e168d56fe8ce4e798..5243177c1faadcb4647b4429a2807c7971ef1870 100644 (file)
@@ -50,6 +50,7 @@
 #include "link_hwss.h"
 #include "dpcd_defs.h"
 #include "dsc.h"
+#include "dio/dcn10/dcn10_dio.h"
 #include "dce/dmub_psr.h"
 #include "dc_dmub_srv.h"
 #include "dce/dmub_hw_lock_mgr.h"
@@ -1881,7 +1882,8 @@ void dcn10_init_hw(struct dc *dc)
 
        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
        if (!is_optimized_init_done)
-               REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+               if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+                       dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
 
        if (!dc->debug.disable_clock_gate) {
                /* enable all DCN clock gating */
index 7cd225a6cf6cbcefef4f7b92f61f0a8ba458d9b7..ce18d75fd99185ba0e78dd2565242e82e3b211f0 100644 (file)
@@ -40,6 +40,8 @@
 #include "clk_mgr.h"
 #include "reg_helper.h"
 #include "dcn10/dcn10_hubbub.h"
+#include "dio/dcn10/dcn10_dio.h"
+
 
 #define CTX \
        hws->ctx
@@ -360,7 +362,8 @@ void dcn201_init_hw(struct dc *dc)
        }
 
        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
 
        if (!dc->debug.disable_clock_gate) {
                /* enable all DCN clock gating */
index 3ff15ec9dc17f96c7e3341e4f70dfdbcdb99a639..d58f2cf2615c0701c42ade5ee97a69cc2cd7f8d0 100644 (file)
@@ -53,6 +53,7 @@
 #include "dcn30/dcn30_resource.h"
 #include "link_service.h"
 #include "dc_state_priv.h"
+#include "dio/dcn10/dcn10_dio.h"
 
 #define TO_DCN_DCCG(dccg)\
        container_of(dccg, struct dcn_dccg, base)
@@ -794,7 +795,8 @@ void dcn30_init_hw(struct dc *dc)
        }
 
        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
 
        if (!dc->debug.disable_clock_gate) {
                /* enable all DCN clock gating */
index 91a672a46289ff33af659b11768ead13c7b7c7f5..db2f7cbb12ff5ba9643b8f34760bd9ea3af8240f 100644 (file)
@@ -53,6 +53,7 @@
 #include "dcn30/dcn30_vpg.h"
 #include "dce/dce_i2c_hw.h"
 #include "dce/dmub_abm_lcd.h"
+#include "dio/dcn10/dcn10_dio.h"
 
 #define DC_LOGGER_INIT(logger)
 
@@ -237,12 +238,9 @@ void dcn31_init_hw(struct dc *dc)
                        abms[i]->funcs->abm_init(abms[i], backlight, user_level);
        }
 
-       /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
-
-       // Set i2c to light sleep until engine is setup
-       if (dc->debug.enable_mem_low_power.bits.i2c)
-               REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1);
+       /* Power on DIO memory (AFMT HDMI) and set I2C to light sleep */
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, dc->debug.enable_mem_low_power.bits.i2c);
 
        if (hws->funcs.setup_hpo_hw_control)
                hws->funcs.setup_hpo_hw_control(hws, false);
index 3f76fba7dcccc3489b494ab58fa0bd9d01a35099..37300e12e64552d297e9ad11335545df0d8eb26c 100644 (file)
@@ -52,6 +52,7 @@
 #include "link_service.h"
 #include "../dcn20/dcn20_hwseq.h"
 #include "dc_state_priv.h"
+#include "dio/dcn10/dcn10_dio.h"
 
 #define DC_LOGGER_INIT(logger)
 
@@ -955,7 +956,8 @@ void dcn32_init_hw(struct dc *dc)
        }
 
        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
 
        if (!dc->debug.disable_clock_gate) {
                /* enable all DCN clock gating */
index 1c7263f9ef51d1a914fd5b83dbe75dab1b908a01..b5a4cefbd35f242faad63d8c3b1185b5217bec88 100644 (file)
@@ -53,6 +53,7 @@
 #include "dcn30/dcn30_vpg.h"
 #include "dce/dce_i2c_hw.h"
 #include "dsc.h"
+#include "dio/dcn10/dcn10_dio.h"
 #include "dcn20/dcn20_optc.h"
 #include "dcn30/dcn30_cm_common.h"
 #include "dcn31/dcn31_hwseq.h"
@@ -272,12 +273,9 @@ void dcn35_init_hw(struct dc *dc)
                }
        }
 
-       /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
-
-       // Set i2c to light sleep until engine is setup
-       if (dc->debug.enable_mem_low_power.bits.i2c)
-               REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0);
+       /* Power on DIO memory (AFMT HDMI) and optionally disable I2C light sleep */
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, !dc->debug.enable_mem_low_power.bits.i2c);
 
        if (hws->funcs.setup_hpo_hw_control)
                hws->funcs.setup_hpo_hw_control(hws, false);
index 567ed207d7cd41c34feb2b0beacebd36eed0418f..9cda39d0ed95fe833b0b3c921a3a99dd5ad01374 100644 (file)
@@ -39,6 +39,7 @@
 #include "dc_state_priv.h"
 #include "link_enc_cfg.h"
 #include "../hw_sequencer.h"
+#include "dio/dcn10/dcn10_dio.h"
 
 #define DC_LOGGER_INIT(logger)
 
@@ -320,7 +321,8 @@ void dcn401_init_hw(struct dc *dc)
        }
 
        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
-       REG_WRITE(DIO_MEM_PWR_CTRL, 0);
+       if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
+               dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
 
        if (!dc->debug.disable_clock_gate) {
                /* enable all DCN clock gating */
index 61d8ef759aca9ff8bb15a410067f0a5569957331..43579b0e1482526c4a898e95a176a9cda5341272 100644 (file)
@@ -35,6 +35,7 @@
 #include "hubp.h"
 #include "mpc.h"
 #include "dwb.h"
+#include "hw/dio.h"
 #include "mcif_wb.h"
 #include "panel_cntl.h"
 #include "dmub/inc/dmub_cmd.h"
@@ -250,6 +251,7 @@ struct resource_pool {
        struct timing_generator *timing_generators[MAX_PIPES];
        struct stream_encoder *stream_enc[MAX_PIPES * 2];
        struct hubbub *hubbub;
+       struct dio *dio;
        struct mpc *mpc;
        struct pp_smu_funcs *pp_smu;
        struct dce_aux *engines[MAX_PIPES];
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h
new file mode 100644 (file)
index 0000000..532bf54
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef __DC_DIO_H__
+#define __DC_DIO_H__
+
+#include "dc_types.h"
+
+struct dc_context;
+struct dio;
+
+struct dio_funcs {
+       void (*mem_pwr_ctrl)(struct dio *dio, bool enable_i2c_light_sleep);
+};
+
+struct dio {
+       const struct dio_funcs *funcs;
+       struct dc_context *ctx;
+};
+
+#endif /* __DC_DIO_H__ */
index 1cdbb65da4a335d4299e07f267618462a3715da3..df3acf58958281e9df9f78bf6483e205a6cf49a9 100644 (file)
@@ -21,6 +21,7 @@
 #include "dcn401/dcn401_hubbub.h"
 #include "dcn401/dcn401_mpc.h"
 #include "dcn401/dcn401_hubp.h"
+#include "dio/dcn10/dcn10_dio.h"
 #include "irq/dcn401/irq_service_dcn401.h"
 #include "dcn401/dcn401_dpp.h"
 #include "dcn401/dcn401_optc.h"
@@ -634,6 +635,22 @@ static const struct dcn20_vmid_mask vmid_masks = {
                DCN20_VMID_MASK_SH_LIST(_MASK)
 };
 
+#define dio_regs_init() \
+               DIO_REG_LIST_DCN10()
+
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST_DCN401(mask_sh)\
+               HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+               DIO_MASK_SH_LIST_DCN401(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+               DIO_MASK_SH_LIST_DCN401(_MASK)
+};
+
 static const struct resource_caps res_cap_dcn4_01 = {
        .num_timing_generator = 4,
        .num_opp = 4,
@@ -881,6 +898,22 @@ static struct hubbub *dcn401_hubbub_create(struct dc_context *ctx)
        return &hubbub2->base;
 }
 
+static struct dio *dcn401_dio_create(struct dc_context *ctx)
+{
+       struct dcn10_dio *dio10 = kzalloc(sizeof(struct dcn10_dio), GFP_KERNEL);
+
+       if (!dio10)
+               return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+       dio_regs_init();
+
+       dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+       return &dio10->base;
+}
+
 static struct hubp *dcn401_hubp_create(
        struct dc_context *ctx,
        uint32_t inst)
@@ -2071,6 +2104,14 @@ static bool dcn401_resource_construct(
                goto create_fail;
        }
 
+       /* DIO */
+       pool->base.dio = dcn401_dio_create(ctx);
+       if (pool->base.dio == NULL) {
+               BREAK_TO_DEBUGGER();
+               dm_error("DC: failed to create dio!\n");
+               goto create_fail;
+       }
+
        /* HUBPs, DPPs, OPPs, TGs, ABMs */
        for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) {