1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2026 Advanced Micro Devices, Inc. 4 5 #include "reg_helper.h" 6 #include "core_types.h" 7 #include "dcn35/dcn35_dccg.h" 8 #include "dcn42_dccg.h" 9 10 #define TO_DCN_DCCG(dccg)\ 11 container_of(dccg, struct dcn_dccg, base) 12 13 #define REG(reg) \ 14 (dccg_dcn->regs->reg) 15 16 #undef FN 17 #define FN(reg_name, field_name) \ 18 dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name 19 20 #define CTX \ 21 dccg_dcn->base.ctx 22 #define DC_LOGGER \ 23 dccg->ctx->logger 24 25 void dccg42_otg_add_pixel(struct dccg *dccg, 26 uint32_t otg_inst) 27 { 28 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 29 30 switch (otg_inst) { 31 case 0: 32 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 33 OTG0_ADD_PIXEL, 1); 34 break; 35 case 1: 36 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 37 OTG1_ADD_PIXEL, 1); 38 break; 39 case 2: 40 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 41 OTG2_ADD_PIXEL, 1); 42 break; 43 case 3: 44 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 45 OTG3_ADD_PIXEL, 1); 46 break; 47 default: 48 ASSERT(0); 49 } 50 } 51 52 void dccg42_otg_drop_pixel(struct dccg *dccg, 53 uint32_t otg_inst) 54 { 55 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 56 57 switch (otg_inst) { 58 case 0: 59 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 60 OTG0_DROP_PIXEL, 1); 61 break; 62 case 1: 63 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 64 OTG1_DROP_PIXEL, 1); 65 break; 66 case 2: 67 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 68 OTG2_DROP_PIXEL, 1); 69 break; 70 case 3: 71 REG_UPDATE(OTG_ADD_DROP_PIXEL_CNTL, 72 OTG3_DROP_PIXEL, 1); 73 break; 74 default: 75 ASSERT(0); 76 } 77 } 78 79 void dccg42_enable_global_fgcg(struct dccg *dccg, bool value) 80 { 81 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 82 83 if (dccg->ctx->dc->debug.disable_clock_gate) 84 value = false; 85 REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value); 86 } 87 88 void dccg42_set_physymclk( 89 struct dccg *dccg, 90 int phy_inst, 91 enum physymclk_clock_source clk_src, 92 bool force_enable) 93 { 94 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 95 96 switch (phy_inst) { 97 case 0: 98 if (force_enable) { 99 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 100 PHYASYMCLK_ROOT_GATE_DISABLE, 1); 101 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL, 102 PHYASYMCLK_EN, 1, 103 PHYASYMCLK_SRC_SEL, clk_src); 104 } else { 105 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL, 106 PHYASYMCLK_EN, 0, 107 PHYASYMCLK_SRC_SEL, 0); 108 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 109 PHYASYMCLK_ROOT_GATE_DISABLE, 110 dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1); 111 } 112 break; 113 case 1: 114 if (force_enable) { 115 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 116 PHYBSYMCLK_ROOT_GATE_DISABLE, 1); 117 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL, 118 PHYBSYMCLK_EN, 1, 119 PHYBSYMCLK_SRC_SEL, clk_src); 120 } else { 121 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL, 122 PHYBSYMCLK_EN, 0, 123 PHYBSYMCLK_SRC_SEL, 0); 124 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 125 PHYBSYMCLK_ROOT_GATE_DISABLE, 126 dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1); 127 } 128 break; 129 case 2: 130 if (force_enable) { 131 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 132 PHYCSYMCLK_ROOT_GATE_DISABLE, 1); 133 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL, 134 PHYCSYMCLK_EN, 1, 135 PHYCSYMCLK_SRC_SEL, clk_src); 136 } else { 137 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL, 138 PHYCSYMCLK_EN, 0, 139 PHYCSYMCLK_SRC_SEL, 0); 140 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 141 PHYCSYMCLK_ROOT_GATE_DISABLE, 142 dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1); 143 } 144 break; 145 case 3: 146 if (force_enable) { 147 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 148 PHYDSYMCLK_ROOT_GATE_DISABLE, 1); 149 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL, 150 PHYDSYMCLK_EN, 1, 151 PHYDSYMCLK_SRC_SEL, clk_src); 152 } else { 153 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL, 154 PHYDSYMCLK_EN, 0, 155 PHYDSYMCLK_SRC_SEL, 0); 156 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 157 PHYDSYMCLK_ROOT_GATE_DISABLE, 158 dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1); 159 } 160 break; 161 case 4: 162 if (force_enable) { 163 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 164 PHYESYMCLK_ROOT_GATE_DISABLE, 1); 165 REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL, 166 PHYESYMCLK_EN, 1, 167 PHYESYMCLK_SRC_SEL, clk_src); 168 } else { 169 REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL, 170 PHYESYMCLK_EN, 0, 171 PHYESYMCLK_SRC_SEL, 0); 172 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, 173 PHYESYMCLK_ROOT_GATE_DISABLE, 174 dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk ? 0 : 1); 175 } 176 break; 177 default: 178 BREAK_TO_DEBUGGER(); 179 return; 180 } 181 } 182 183 void dccg42_set_pixel_rate_div( 184 struct dccg *dccg, 185 uint32_t otg_inst, 186 enum pixel_rate_div tmds_div, 187 enum pixel_rate_div unused) 188 { 189 (void)unused; 190 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 191 uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA; 192 uint32_t dp_dto_int; 193 uint32_t reg_val; 194 195 // only 2 and 4 are valid on dcn401 196 if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) { 197 return; 198 } 199 200 dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int); 201 if (tmds_div == cur_tmds_div) 202 return; 203 204 // encode enum to register value 205 reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0; 206 207 switch (otg_inst) { 208 case 0: 209 REG_UPDATE(OTG_PIXEL_RATE_DIV, 210 OTG0_TMDS_PIXEL_RATE_DIV, reg_val); 211 break; 212 case 1: 213 REG_UPDATE(OTG_PIXEL_RATE_DIV, 214 OTG1_TMDS_PIXEL_RATE_DIV, reg_val); 215 break; 216 case 2: 217 REG_UPDATE(OTG_PIXEL_RATE_DIV, 218 OTG2_TMDS_PIXEL_RATE_DIV, reg_val); 219 break; 220 case 3: 221 REG_UPDATE(OTG_PIXEL_RATE_DIV, 222 OTG3_TMDS_PIXEL_RATE_DIV, reg_val); 223 break; 224 default: 225 BREAK_TO_DEBUGGER(); 226 return; 227 } 228 } 229 230 void dccg42_trigger_dio_fifo_resync(struct dccg *dccg) 231 { 232 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 233 234 REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 1); 235 REG_UPDATE(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, 0); 236 REG_WAIT(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, 1, 50, 2000); 237 } 238 239 static void dccg42_init(struct dccg *dccg) 240 { 241 int otg_inst; 242 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); 243 244 /* Set HPO stream encoder to use refclk to avoid case where PHY is 245 * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which 246 * will cause DCN to hang. 247 */ 248 for (otg_inst = 0; otg_inst < 4; otg_inst++) 249 dccg35_disable_symclk32_se(dccg, otg_inst); 250 251 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) { 252 dccg401_disable_symclk32_le(dccg, 0); 253 dccg401_disable_symclk32_le(dccg, 1); 254 dccg401_disable_symclk32_le(dccg, 2); 255 dccg401_disable_symclk32_le(dccg, 3); 256 } 257 258 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) { 259 dccg401_disable_dpstreamclk(dccg, 0); 260 dccg401_disable_dpstreamclk(dccg, 1); 261 dccg401_disable_dpstreamclk(dccg, 2); 262 dccg401_disable_dpstreamclk(dccg, 3); 263 } 264 if (!dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) { 265 REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, 266 PHYASYMCLK_ROOT_GATE_DISABLE, 1, 267 PHYBSYMCLK_ROOT_GATE_DISABLE, 1, 268 PHYCSYMCLK_ROOT_GATE_DISABLE, 1, 269 PHYDSYMCLK_ROOT_GATE_DISABLE, 1, 270 PHYESYMCLK_ROOT_GATE_DISABLE, 1); 271 } 272 } 273 274 275 static const struct dccg_funcs dccg42_funcs = { 276 .update_dpp_dto = dccg35_update_dpp_dto, 277 .dpp_root_clock_control = dccg35_dpp_root_clock_control, 278 .get_dccg_ref_freq = dccg401_get_dccg_ref_freq, 279 .dccg_init = dccg42_init, 280 .set_dpstreamclk = dccg401_set_dpstreamclk, 281 /* Redundant with above^ */ 282 /* .set_dpstreamclk_root_clock_gating = dccg35_set_dpstreamclk_root_clock_gating, */ 283 .enable_symclk32_se = dccg31_enable_symclk32_se, 284 .disable_symclk32_se = dccg35_disable_symclk32_se, 285 .enable_symclk32_le = dccg401_enable_symclk32_le, 286 .disable_symclk32_le = dccg401_disable_symclk32_le, 287 .set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating, 288 .set_physymclk = dccg42_set_physymclk, 289 .set_dtbclk_dto = NULL, 290 .set_dto_dscclk = dccg401_set_dto_dscclk, 291 .set_ref_dscclk = dccg401_set_ref_dscclk, 292 .set_valid_pixel_rate = NULL, 293 .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, 294 .set_audio_dtbclk_dto = NULL, 295 .otg_add_pixel = dccg42_otg_add_pixel, 296 .otg_drop_pixel = dccg42_otg_drop_pixel, 297 .disable_dsc = dccg35_disable_dscclk, 298 .enable_dsc = dccg35_enable_dscclk, 299 .set_pixel_rate_div = dccg42_set_pixel_rate_div, 300 .get_pixel_rate_div = dccg401_get_pixel_rate_div, 301 .trigger_dio_fifo_resync = dccg42_trigger_dio_fifo_resync, 302 .set_dp_dto = dccg401_set_dp_dto, 303 .enable_symclk_se = dccg35_enable_symclk_se, 304 .disable_symclk_se = dccg35_disable_symclk_se, 305 .set_dtbclk_p_src = dccg401_set_dtbclk_p_src, 306 .dccg_root_gate_disable_control = dccg35_root_gate_disable_control, 307 .dccg_read_reg_state = dccg31_read_reg_state, 308 .dccg_enable_global_fgcg = dccg42_enable_global_fgcg, 309 }; 310 311 struct dccg *dccg42_create( 312 struct dc_context *ctx, 313 const struct dccg_registers *regs, 314 const struct dccg_shift *dccg_shift, 315 const struct dccg_mask *dccg_mask) 316 { 317 struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL); 318 struct dccg *base; 319 320 if (dccg_dcn == NULL) { 321 BREAK_TO_DEBUGGER(); 322 return NULL; 323 } 324 325 base = &dccg_dcn->base; 326 base->ctx = ctx; 327 base->funcs = &dccg42_funcs; 328 329 dccg_dcn->regs = regs; 330 dccg_dcn->dccg_shift = dccg_shift; 331 dccg_dcn->dccg_mask = dccg_mask; 332 333 return &dccg_dcn->base; 334 } 335