#include "reg_helper.h"
#include "core_types.h"
#include "dcn35/dcn35_dccg.h"
#include "dcn42_dccg.h"
#include "dcn20/dcn20_dccg.h"
#define TO_DCN_DCCG(dccg)\
container_of(dccg, struct dcn_dccg, base)
#define REG(reg) \
(dccg_dcn->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
#define CTX \
dccg_dcn->base.ctx
#define DC_LOGGER \
dccg->ctx->logger
void dccg42_otg_add_pixel(struct dccg *dccg,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (otg_inst) {
case 0:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG0_ADD_PIXEL, 1);
break;
case 1:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG1_ADD_PIXEL, 1);
break;
case 2:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG2_ADD_PIXEL, 1);
break;
case 3:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG3_ADD_PIXEL, 1);
break;
default:
ASSERT(0);
}
}
void dccg42_otg_drop_pixel(struct dccg *dccg,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (otg_inst) {
case 0:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG0_DROP_PIXEL, 1);
break;
case 1:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG1_DROP_PIXEL, 1);
break;
case 2:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG2_DROP_PIXEL, 1);
break;
case 3:
REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL,
OTG3_DROP_PIXEL, 1);
break;
default:
ASSERT(0);
}
}
void dccg42_enable_global_fgcg(struct dccg *dccg, bool value)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.disable_clock_gate)
value = false;
REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value);
}
void dccg42_set_physymclk(
struct dccg *dccg,
int phy_inst,
enum physymclk_clock_source clk_src,
bool force_enable)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (phy_inst) {
case 0:
if (force_enable) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYASYMCLK_ROOT_GATE_DISABLE, 1);
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_EN, 1,
PHYASYMCLK_SRC_SEL, clk_src);
} else {
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_EN, 0,
PHYASYMCLK_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYASYMCLK_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
}
break;
case 1:
if (force_enable) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYBSYMCLK_ROOT_GATE_DISABLE, 1);
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_EN, 1,
PHYBSYMCLK_SRC_SEL, clk_src);
} else {
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_EN, 0,
PHYBSYMCLK_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYBSYMCLK_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
}
break;
case 2:
if (force_enable) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYCSYMCLK_ROOT_GATE_DISABLE, 1);
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_EN, 1,
PHYCSYMCLK_SRC_SEL, clk_src);
} else {
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_EN, 0,
PHYCSYMCLK_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYCSYMCLK_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
}
break;
case 3:
if (force_enable) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYDSYMCLK_ROOT_GATE_DISABLE, 1);
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_EN, 1,
PHYDSYMCLK_SRC_SEL, clk_src);
} else {
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_EN, 0,
PHYDSYMCLK_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYDSYMCLK_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
}
break;
case 4:
if (force_enable) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYESYMCLK_ROOT_GATE_DISABLE, 1);
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_EN, 1,
PHYESYMCLK_SRC_SEL, clk_src);
} else {
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_EN, 0,
PHYESYMCLK_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
PHYESYMCLK_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1);
}
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg42_disable_hdmistreamclk(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0,
HDMISTREAMCLK0_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL6,
HDMISTREAMCLK0_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream ? 0 : 1);
}
static void dccg42_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar ? 0 : 1);
}
void dccg42_set_pixel_rate_div(
struct dccg *dccg,
uint32_t otg_inst,
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused)
{
(void)unused;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
uint32_t dp_dto_int;
uint32_t reg_val;
if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
return;
}
dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
if (tmds_div == cur_tmds_div)
return;
reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
switch (otg_inst) {
case 0:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 1:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 2:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 3:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
void dccg42_trigger_dio_fifo_resync(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 1);
REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 0);
REG_WAIT(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, 1, 50, 2000);
}
static void dccg42_init(struct dccg *dccg)
{
int otg_inst;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
for (otg_inst = 0; otg_inst < 4; otg_inst++)
dccg35_disable_symclk32_se(dccg, otg_inst);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) {
dccg401_disable_symclk32_le(dccg, 0);
dccg401_disable_symclk32_le(dccg, 1);
dccg401_disable_symclk32_le(dccg, 2);
dccg401_disable_symclk32_le(dccg, 3);
}
if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) {
dccg401_disable_dpstreamclk(dccg, 0);
dccg401_disable_dpstreamclk(dccg, 1);
dccg401_disable_dpstreamclk(dccg, 2);
dccg401_disable_dpstreamclk(dccg, 3);
}
if (!dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) {
REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2,
PHYASYMCLK_ROOT_GATE_DISABLE, 1,
PHYBSYMCLK_ROOT_GATE_DISABLE, 1,
PHYCSYMCLK_ROOT_GATE_DISABLE, 1,
PHYDSYMCLK_ROOT_GATE_DISABLE, 1,
PHYESYMCLK_ROOT_GATE_DISABLE, 1);
}
dccg42_disable_hdmistreamclk(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
dccg42_disable_hdmicharclk(dccg, 0);
}
static const struct dccg_funcs dccg42_funcs = {
.enable_hdmicharclk = dccg401_enable_hdmicharclk,
.disable_hdmicharclk = dccg42_disable_hdmicharclk,
.set_hdmistreamclk = dccg401_set_hdmistreamclk,
.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
.update_dpp_dto = dccg35_update_dpp_dto,
.dpp_root_clock_control = dccg35_dpp_root_clock_control,
.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
.dccg_init = dccg42_init,
.set_dpstreamclk = dccg401_set_dpstreamclk,
.enable_symclk32_se = dccg31_enable_symclk32_se,
.disable_symclk32_se = dccg35_disable_symclk32_se,
.enable_symclk32_le = dccg401_enable_symclk32_le,
.disable_symclk32_le = dccg401_disable_symclk32_le,
.set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating,
.set_physymclk = dccg42_set_physymclk,
.set_dtbclk_dto = NULL,
.set_dto_dscclk = dccg401_set_dto_dscclk,
.set_ref_dscclk = dccg401_set_ref_dscclk,
.set_valid_pixel_rate = NULL,
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
.set_audio_dtbclk_dto = NULL,
.otg_add_pixel = dccg42_otg_add_pixel,
.otg_drop_pixel = dccg42_otg_drop_pixel,
.disable_dsc = dccg35_disable_dscclk,
.enable_dsc = dccg35_enable_dscclk,
.set_pixel_rate_div = dccg42_set_pixel_rate_div,
.get_pixel_rate_div = dccg401_get_pixel_rate_div,
.trigger_dio_fifo_resync = dccg42_trigger_dio_fifo_resync,
.set_dp_dto = dccg401_set_dp_dto,
.enable_symclk_se = dccg35_enable_symclk_se,
.disable_symclk_se = dccg35_disable_symclk_se,
.set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
.dccg_root_gate_disable_control = dccg35_root_gate_disable_control,
.dccg_read_reg_state = dccg31_read_reg_state,
.dccg_enable_global_fgcg = dccg42_enable_global_fgcg,
.allow_clock_gating = dccg2_allow_clock_gating
};
struct dccg *dccg42_create(
struct dc_context *ctx,
const struct dccg_registers *regs,
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask)
{
struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
struct dccg *base;
if (dccg_dcn == NULL) {
BREAK_TO_DEBUGGER();
return NULL;
}
base = &dccg_dcn->base;
base->ctx = ctx;
base->funcs = &dccg42_funcs;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
return &dccg_dcn->base;
}