drm/amd/display: Migrate DIO registers access from hwseq to dio component.

[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>
This commit is contained in:
Bhuvanachandra Pinninti 2026-01-08 18:37:57 +05:30 committed by Alex Deucher
parent c2d2ccc85f
commit b82f075934
13 changed files with 179 additions and 18 deletions

View 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))

View File

@ -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;
}

View File

@ -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__ */

View 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 */

View 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 */

View 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 */

View 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);

View 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 */

View 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);

View 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 */

View 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];

View File

@ -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__ */

View 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++) {