999 lines · c
1/*2 * Copyright 2023 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#include "reg_helper.h"27#include "core_types.h"28#include "dcn401_dccg.h"29#include "dcn31/dcn31_dccg.h"30 31/*32#include "dmub_common.h"33#include "dmcub_reg_access_helper.h"34 35#include "dmub401_common.h"36#include "dmub401_regs.h"37#include "dmub401_dccg.h"38*/39 40#define TO_DCN_DCCG(dccg)\41 container_of(dccg, struct dcn_dccg, base)42 43#define REG(reg) \44 (dccg_dcn->regs->reg)45 46#undef FN47#define FN(reg_name, field_name) \48 dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name49 50#define CTX \51 dccg_dcn->base.ctx52#define DC_LOGGER \53 dccg->ctx->logger54 55static void dcn401_set_dppclk_enable(struct dccg *dccg,56 uint32_t dpp_inst, uint32_t enable)57{58 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);59 60 switch (dpp_inst) {61 case 0:62 REG_UPDATE(DPPCLK_CTRL, DPPCLK0_EN, enable);63 break;64 case 1:65 REG_UPDATE(DPPCLK_CTRL, DPPCLK1_EN, enable);66 break;67 case 2:68 REG_UPDATE(DPPCLK_CTRL, DPPCLK2_EN, enable);69 break;70 case 3:71 REG_UPDATE(DPPCLK_CTRL, DPPCLK3_EN, enable);72 break;73 default:74 break;75 }76}77void dccg401_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)78{79 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);80 81 if (dccg->ref_dppclk && req_dppclk) {82 int ref_dppclk = dccg->ref_dppclk;83 int modulo, phase;84 85 // phase / modulo = dpp pipe clk / dpp global clk86 modulo = 0xff; // use FF at the end87 phase = ((modulo * req_dppclk) + ref_dppclk - 1) / ref_dppclk;88 89 if (phase > 0xff) {90 ASSERT(false);91 phase = 0xff;92 }93 94 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,95 DPPCLK0_DTO_PHASE, phase,96 DPPCLK0_DTO_MODULO, modulo);97 dcn401_set_dppclk_enable(dccg, dpp_inst, true);98 } else {99 dcn401_set_dppclk_enable(dccg, dpp_inst, false);100 }101 102 dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;103}104 105/* This function is a workaround for writing to OTG_PIXEL_RATE_DIV106 * without the probability of causing a DIG FIFO error.107 */108static void dccg401_wait_for_dentist_change_done(109 struct dccg *dccg)110{111 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);112 113 uint32_t dentist_dispclk_value = REG_READ(DENTIST_DISPCLK_CNTL);114 115 REG_WRITE(DENTIST_DISPCLK_CNTL, dentist_dispclk_value);116 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 2000);117}118 119static void dccg401_get_pixel_rate_div(120 struct dccg *dccg,121 uint32_t otg_inst,122 uint32_t *tmds_div,123 uint32_t *dp_dto_int)124{125 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);126 uint32_t val_tmds_div = PIXEL_RATE_DIV_NA;127 128 switch (otg_inst) {129 case 0:130 REG_GET_2(OTG_PIXEL_RATE_DIV,131 OTG0_TMDS_PIXEL_RATE_DIV, &val_tmds_div,132 DPDTO0_INT, dp_dto_int);133 break;134 case 1:135 REG_GET_2(OTG_PIXEL_RATE_DIV,136 OTG1_TMDS_PIXEL_RATE_DIV, &val_tmds_div,137 DPDTO1_INT, dp_dto_int);138 break;139 case 2:140 REG_GET_2(OTG_PIXEL_RATE_DIV,141 OTG2_TMDS_PIXEL_RATE_DIV, &val_tmds_div,142 DPDTO2_INT, dp_dto_int);143 break;144 case 3:145 REG_GET_2(OTG_PIXEL_RATE_DIV,146 OTG3_TMDS_PIXEL_RATE_DIV, &val_tmds_div,147 DPDTO3_INT, dp_dto_int);148 break;149 default:150 BREAK_TO_DEBUGGER();151 return;152 }153 154 *tmds_div = val_tmds_div == 0 ? PIXEL_RATE_DIV_BY_2 : PIXEL_RATE_DIV_BY_4;155}156 157static void dccg401_set_pixel_rate_div(158 struct dccg *dccg,159 uint32_t otg_inst,160 enum pixel_rate_div tmds_div,161 enum pixel_rate_div unused)162{163 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);164 uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;165 uint32_t dp_dto_int;166 uint32_t reg_val;167 168 // only 2 and 4 are valid on dcn401169 if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {170 return;171 }172 173 dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);174 if (tmds_div == cur_tmds_div)175 return;176 177 // encode enum to register value178 reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;179 180 switch (otg_inst) {181 case 0:182 REG_UPDATE(OTG_PIXEL_RATE_DIV,183 OTG0_TMDS_PIXEL_RATE_DIV, reg_val);184 185 dccg401_wait_for_dentist_change_done(dccg);186 break;187 case 1:188 REG_UPDATE(OTG_PIXEL_RATE_DIV,189 OTG1_TMDS_PIXEL_RATE_DIV, reg_val);190 191 dccg401_wait_for_dentist_change_done(dccg);192 break;193 case 2:194 REG_UPDATE(OTG_PIXEL_RATE_DIV,195 OTG2_TMDS_PIXEL_RATE_DIV, reg_val);196 197 dccg401_wait_for_dentist_change_done(dccg);198 break;199 case 3:200 REG_UPDATE(OTG_PIXEL_RATE_DIV,201 OTG3_TMDS_PIXEL_RATE_DIV, reg_val);202 203 dccg401_wait_for_dentist_change_done(dccg);204 break;205 default:206 BREAK_TO_DEBUGGER();207 return;208 }209}210 211 212static void dccg401_set_dtbclk_p_src(213 struct dccg *dccg,214 enum streamclk_source src,215 uint32_t otg_inst)216{217 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);218 219 uint32_t p_src_sel = 0; /* selects dprefclk */220 if (src == DTBCLK0)221 p_src_sel = 2; /* selects dtbclk0 */222 223 switch (otg_inst) {224 case 0:225 if (src == REFCLK)226 REG_UPDATE(DTBCLK_P_CNTL,227 DTBCLK_P0_EN, 0);228 else229 REG_UPDATE_2(DTBCLK_P_CNTL,230 DTBCLK_P0_SRC_SEL, p_src_sel,231 DTBCLK_P0_EN, 1);232 break;233 case 1:234 if (src == REFCLK)235 REG_UPDATE(DTBCLK_P_CNTL,236 DTBCLK_P1_EN, 0);237 else238 REG_UPDATE_2(DTBCLK_P_CNTL,239 DTBCLK_P1_SRC_SEL, p_src_sel,240 DTBCLK_P1_EN, 1);241 break;242 case 2:243 if (src == REFCLK)244 REG_UPDATE(DTBCLK_P_CNTL,245 DTBCLK_P2_EN, 0);246 else247 REG_UPDATE_2(DTBCLK_P_CNTL,248 DTBCLK_P2_SRC_SEL, p_src_sel,249 DTBCLK_P2_EN, 1);250 break;251 case 3:252 if (src == REFCLK)253 REG_UPDATE(DTBCLK_P_CNTL,254 DTBCLK_P3_EN, 0);255 else256 REG_UPDATE_2(DTBCLK_P_CNTL,257 DTBCLK_P3_SRC_SEL, p_src_sel,258 DTBCLK_P3_EN, 1);259 break;260 default:261 BREAK_TO_DEBUGGER();262 return;263 }264 265}266 267void dccg401_set_physymclk(268 struct dccg *dccg,269 int phy_inst,270 enum physymclk_clock_source clk_src,271 bool force_enable)272{273 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);274 275 /* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */276 switch (phy_inst) {277 case 0:278 if (force_enable) {279 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,280 PHYASYMCLK_EN, 1,281 PHYASYMCLK_SRC_SEL, clk_src);282 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)283 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,284 PHYASYMCLK_ROOT_GATE_DISABLE, 1);285 } else {286 REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,287 PHYASYMCLK_EN, 0,288 PHYASYMCLK_SRC_SEL, 0);289 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)290 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,291 PHYASYMCLK_ROOT_GATE_DISABLE, 0);292 }293 break;294 case 1:295 if (force_enable) {296 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,297 PHYBSYMCLK_EN, 1,298 PHYBSYMCLK_SRC_SEL, clk_src);299 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)300 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,301 PHYBSYMCLK_ROOT_GATE_DISABLE, 1);302 } else {303 REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,304 PHYBSYMCLK_EN, 0,305 PHYBSYMCLK_SRC_SEL, 0);306 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)307 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,308 PHYBSYMCLK_ROOT_GATE_DISABLE, 0);309 }310 break;311 case 2:312 if (force_enable) {313 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,314 PHYCSYMCLK_EN, 1,315 PHYCSYMCLK_SRC_SEL, clk_src);316 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)317 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,318 PHYCSYMCLK_ROOT_GATE_DISABLE, 1);319 } else {320 REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,321 PHYCSYMCLK_EN, 0,322 PHYCSYMCLK_SRC_SEL, 0);323 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)324 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,325 PHYCSYMCLK_ROOT_GATE_DISABLE, 0);326 }327 break;328 case 3:329 if (force_enable) {330 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,331 PHYDSYMCLK_EN, 1,332 PHYDSYMCLK_SRC_SEL, clk_src);333 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)334 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,335 PHYDSYMCLK_ROOT_GATE_DISABLE, 1);336 } else {337 REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,338 PHYDSYMCLK_EN, 0,339 PHYDSYMCLK_SRC_SEL, 0);340 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)341 REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,342 PHYDSYMCLK_ROOT_GATE_DISABLE, 0);343 }344 break;345 default:346 BREAK_TO_DEBUGGER();347 return;348 }349}350 351static void dccg401_get_dccg_ref_freq(struct dccg *dccg,352 unsigned int xtalin_freq_inKhz,353 unsigned int *dccg_ref_freq_inKhz)354{355 /*356 * Assume refclk is sourced from xtalin357 * expect 100MHz358 */359 *dccg_ref_freq_inKhz = xtalin_freq_inKhz;360 return;361}362 363static void dccg401_otg_add_pixel(struct dccg *dccg,364 uint32_t otg_inst)365{366 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);367 368 REG_UPDATE(OTG_PIXEL_RATE_CNTL[otg_inst],369 OTG_ADD_PIXEL[otg_inst], 1);370}371 372static void dccg401_otg_drop_pixel(struct dccg *dccg,373 uint32_t otg_inst)374{375 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);376 377 REG_UPDATE(OTG_PIXEL_RATE_CNTL[otg_inst],378 OTG_DROP_PIXEL[otg_inst], 1);379}380 381static void dccg401_enable_symclk32_le(382 struct dccg *dccg,383 int hpo_le_inst,384 enum phyd32clk_clock_source phyd32clk)385{386 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);387 388 /* select one of the PHYD32CLKs as the source for symclk32_le */389 switch (hpo_le_inst) {390 case 0:391 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)392 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,393 SYMCLK32_LE0_GATE_DISABLE, 1,394 SYMCLK32_ROOT_LE0_GATE_DISABLE, 1);395 REG_UPDATE_2(SYMCLK32_LE_CNTL,396 SYMCLK32_LE0_SRC_SEL, phyd32clk,397 SYMCLK32_LE0_EN, 1);398 break;399 case 1:400 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)401 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,402 SYMCLK32_LE1_GATE_DISABLE, 1,403 SYMCLK32_ROOT_LE1_GATE_DISABLE, 1);404 REG_UPDATE_2(SYMCLK32_LE_CNTL,405 SYMCLK32_LE1_SRC_SEL, phyd32clk,406 SYMCLK32_LE1_EN, 1);407 break;408 case 2:409 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)410 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,411 SYMCLK32_LE2_GATE_DISABLE, 1,412 SYMCLK32_ROOT_LE2_GATE_DISABLE, 1);413 REG_UPDATE_2(SYMCLK32_LE_CNTL,414 SYMCLK32_LE2_SRC_SEL, phyd32clk,415 SYMCLK32_LE2_EN, 1);416 break;417 case 3:418 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)419 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,420 SYMCLK32_LE3_GATE_DISABLE, 1,421 SYMCLK32_ROOT_LE3_GATE_DISABLE, 1);422 REG_UPDATE_2(SYMCLK32_LE_CNTL,423 SYMCLK32_LE3_SRC_SEL, phyd32clk,424 SYMCLK32_LE3_EN, 1);425 break;426 default:427 BREAK_TO_DEBUGGER();428 return;429 }430}431 432static void dccg401_disable_symclk32_le(433 struct dccg *dccg,434 int hpo_le_inst)435{436 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);437 438 /* set refclk as the source for symclk32_le */439 switch (hpo_le_inst) {440 case 0:441 REG_UPDATE_2(SYMCLK32_LE_CNTL,442 SYMCLK32_LE0_SRC_SEL, 0,443 SYMCLK32_LE0_EN, 0);444 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)445 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,446 SYMCLK32_LE0_GATE_DISABLE, 0,447 SYMCLK32_ROOT_LE0_GATE_DISABLE, 0);448 break;449 case 1:450 REG_UPDATE_2(SYMCLK32_LE_CNTL,451 SYMCLK32_LE1_SRC_SEL, 0,452 SYMCLK32_LE1_EN, 0);453 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)454 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,455 SYMCLK32_LE1_GATE_DISABLE, 0,456 SYMCLK32_ROOT_LE1_GATE_DISABLE, 0);457 break;458 case 2:459 REG_UPDATE_2(SYMCLK32_LE_CNTL,460 SYMCLK32_LE2_SRC_SEL, 0,461 SYMCLK32_LE2_EN, 0);462 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)463 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,464 SYMCLK32_LE2_GATE_DISABLE, 0,465 SYMCLK32_ROOT_LE2_GATE_DISABLE, 0);466 break;467 case 3:468 REG_UPDATE_2(SYMCLK32_LE_CNTL,469 SYMCLK32_LE3_SRC_SEL, 0,470 SYMCLK32_LE3_EN, 0);471 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)472 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,473 SYMCLK32_LE3_GATE_DISABLE, 0,474 SYMCLK32_ROOT_LE3_GATE_DISABLE, 0);475 break;476 default:477 BREAK_TO_DEBUGGER();478 return;479 }480}481 482static void dccg401_enable_dpstreamclk(struct dccg *dccg, int otg_inst, int dp_hpo_inst)483{484 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);485 486 /* enabled to select one of the DTBCLKs for pipe */487 switch (dp_hpo_inst) {488 case 0:489 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)490 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,491 DPSTREAMCLK0_ROOT_GATE_DISABLE, 1,492 DPSTREAMCLK0_GATE_DISABLE, 1);493 REG_UPDATE_2(DPSTREAMCLK_CNTL,494 DPSTREAMCLK0_SRC_SEL, otg_inst,495 DPSTREAMCLK0_EN, 1);496 break;497 case 1:498 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)499 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,500 DPSTREAMCLK1_ROOT_GATE_DISABLE, 1,501 DPSTREAMCLK1_GATE_DISABLE, 1);502 REG_UPDATE_2(DPSTREAMCLK_CNTL,503 DPSTREAMCLK1_SRC_SEL, otg_inst,504 DPSTREAMCLK1_EN, 1);505 break;506 case 2:507 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)508 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,509 DPSTREAMCLK2_ROOT_GATE_DISABLE, 1,510 DPSTREAMCLK2_GATE_DISABLE, 1);511 REG_UPDATE_2(DPSTREAMCLK_CNTL,512 DPSTREAMCLK2_SRC_SEL, otg_inst,513 DPSTREAMCLK2_EN, 1);514 break;515 case 3:516 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)517 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,518 DPSTREAMCLK3_ROOT_GATE_DISABLE, 1,519 DPSTREAMCLK3_GATE_DISABLE, 1);520 REG_UPDATE_2(DPSTREAMCLK_CNTL,521 DPSTREAMCLK3_SRC_SEL, otg_inst,522 DPSTREAMCLK3_EN, 1);523 break;524 default:525 BREAK_TO_DEBUGGER();526 return;527 }528 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)529 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,530 DPSTREAMCLK_GATE_DISABLE, 1,531 DPSTREAMCLK_ROOT_GATE_DISABLE, 1);532}533 534static void dccg401_disable_dpstreamclk(struct dccg *dccg, int dp_hpo_inst)535{536 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);537 538 switch (dp_hpo_inst) {539 case 0:540 REG_UPDATE(DPSTREAMCLK_CNTL,541 DPSTREAMCLK0_EN, 0);542 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)543 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,544 DPSTREAMCLK0_ROOT_GATE_DISABLE, 0,545 DPSTREAMCLK0_GATE_DISABLE, 0);546 break;547 case 1:548 REG_UPDATE(DPSTREAMCLK_CNTL,549 DPSTREAMCLK1_EN, 0);550 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)551 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,552 DPSTREAMCLK1_ROOT_GATE_DISABLE, 0,553 DPSTREAMCLK1_GATE_DISABLE, 0);554 break;555 case 2:556 REG_UPDATE(DPSTREAMCLK_CNTL,557 DPSTREAMCLK2_EN, 0);558 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)559 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,560 DPSTREAMCLK2_ROOT_GATE_DISABLE, 0,561 DPSTREAMCLK2_GATE_DISABLE, 0);562 break;563 case 3:564 REG_UPDATE(DPSTREAMCLK_CNTL,565 DPSTREAMCLK3_EN, 0);566 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)567 REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL5,568 DPSTREAMCLK3_ROOT_GATE_DISABLE, 0,569 DPSTREAMCLK3_GATE_DISABLE, 0);570 break;571 default:572 BREAK_TO_DEBUGGER();573 return;574 }575}576 577static void dccg401_set_dpstreamclk(578 struct dccg *dccg,579 enum streamclk_source src,580 int otg_inst,581 int dp_hpo_inst)582{583 /* set the dtbclk_p source */584 dccg401_set_dtbclk_p_src(dccg, src, otg_inst);585 586 /* enabled to select one of the DTBCLKs for pipe */587 if (src == REFCLK)588 dccg401_disable_dpstreamclk(dccg, dp_hpo_inst);589 else590 dccg401_enable_dpstreamclk(dccg, otg_inst, dp_hpo_inst);591}592 593static void dccg401_set_dp_dto(594 struct dccg *dccg,595 const struct dp_dto_params *params)596{597 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);598 599 bool enable = false;600 601 if (params->otg_inst > 3) {602 /* dcn401 only has 4 instances */603 BREAK_TO_DEBUGGER();604 return;605 }606 if (!params->refclk_hz) {607 BREAK_TO_DEBUGGER();608 return;609 }610 611 if (!dc_is_tmds_signal(params->signal)) {612 uint64_t dto_integer;613 uint64_t dto_phase_hz;614 uint64_t dto_modulo_hz = params->refclk_hz;615 616 enable = true;617 618 /* Set DTO values:619 * int = target_pix_rate / reference_clock620 * phase = target_pix_rate - int * reference_clock,621 * modulo = reference_clock */622 dto_integer = div_u64(params->pixclk_hz, dto_modulo_hz);623 dto_phase_hz = params->pixclk_hz - dto_integer * dto_modulo_hz;624 625 if (dto_phase_hz <= 0) {626 /* negative pixel rate should never happen */627 BREAK_TO_DEBUGGER();628 return;629 }630 631 switch (params->otg_inst) {632 case 0:633 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 1);634 REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL3,635 SYMCLK32_SE0_GATE_DISABLE, 1,636 SYMCLK32_ROOT_SE0_GATE_DISABLE, 1,637 SYMCLK32_LE0_GATE_DISABLE, 1,638 SYMCLK32_ROOT_LE0_GATE_DISABLE, 1);639 break;640 case 1:641 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 1);642 REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL3,643 SYMCLK32_SE1_GATE_DISABLE, 1,644 SYMCLK32_ROOT_SE1_GATE_DISABLE, 1,645 SYMCLK32_LE1_GATE_DISABLE, 1,646 SYMCLK32_ROOT_LE1_GATE_DISABLE, 1);647 break;648 case 2:649 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 1);650 REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL3,651 SYMCLK32_SE2_GATE_DISABLE, 1,652 SYMCLK32_ROOT_SE2_GATE_DISABLE, 1,653 SYMCLK32_LE2_GATE_DISABLE, 1,654 SYMCLK32_ROOT_LE2_GATE_DISABLE, 1);655 break;656 case 3:657 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 1);658 REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL3,659 SYMCLK32_SE3_GATE_DISABLE, 1,660 SYMCLK32_ROOT_SE3_GATE_DISABLE, 1,661 SYMCLK32_LE3_GATE_DISABLE, 1,662 SYMCLK32_ROOT_LE3_GATE_DISABLE, 1);663 break;664 }665 666 dccg401_set_dtbclk_p_src(dccg, params->clk_src, params->otg_inst);667 668 REG_WRITE(DP_DTO_PHASE[params->otg_inst], dto_phase_hz);669 REG_WRITE(DP_DTO_MODULO[params->otg_inst], dto_modulo_hz);670 671 switch (params->otg_inst) {672 case 0:673 REG_UPDATE(OTG_PIXEL_RATE_DIV,674 DPDTO0_INT, dto_integer);675 break;676 case 1:677 REG_UPDATE(OTG_PIXEL_RATE_DIV,678 DPDTO1_INT, dto_integer);679 break;680 case 2:681 REG_UPDATE(OTG_PIXEL_RATE_DIV,682 DPDTO2_INT, dto_integer);683 break;684 case 3:685 REG_UPDATE(OTG_PIXEL_RATE_DIV,686 DPDTO3_INT, dto_integer);687 break;688 default:689 BREAK_TO_DEBUGGER();690 return;691 }692 }693 694 /* Toggle DTO */695 REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst],696 DP_DTO_ENABLE[params->otg_inst], enable,697 PIPE_DTO_SRC_SEL[params->otg_inst], enable);698}699 700void dccg401_init(struct dccg *dccg)701{702 /* Set HPO stream encoder to use refclk to avoid case where PHY is703 * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which704 * will cause DCN to hang.705 */706 dccg31_disable_symclk32_se(dccg, 0);707 dccg31_disable_symclk32_se(dccg, 1);708 dccg31_disable_symclk32_se(dccg, 2);709 dccg31_disable_symclk32_se(dccg, 3);710 711 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) {712 dccg401_disable_symclk32_le(dccg, 0);713 dccg401_disable_symclk32_le(dccg, 1);714 dccg401_disable_symclk32_le(dccg, 2);715 dccg401_disable_symclk32_le(dccg, 3);716 }717 718 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) {719 dccg401_disable_dpstreamclk(dccg, 0);720 dccg401_disable_dpstreamclk(dccg, 1);721 dccg401_disable_dpstreamclk(dccg, 2);722 dccg401_disable_dpstreamclk(dccg, 3);723 }724 725 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) {726 dccg401_set_physymclk(dccg, 0, PHYSYMCLK_FORCE_SRC_SYMCLK, false);727 dccg401_set_physymclk(dccg, 1, PHYSYMCLK_FORCE_SRC_SYMCLK, false);728 dccg401_set_physymclk(dccg, 2, PHYSYMCLK_FORCE_SRC_SYMCLK, false);729 dccg401_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);730 }731}732 733static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst)734{735 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);736 737 switch (inst) {738 case 0:739 REG_UPDATE_2(DSCCLK0_DTO_PARAM,740 DSCCLK0_DTO_PHASE, 1,741 DSCCLK0_DTO_MODULO, 1);742 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);743 744 break;745 case 1:746 REG_UPDATE_2(DSCCLK1_DTO_PARAM,747 DSCCLK1_DTO_PHASE, 1,748 DSCCLK1_DTO_MODULO, 1);749 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);750 break;751 case 2:752 REG_UPDATE_2(DSCCLK2_DTO_PARAM,753 DSCCLK2_DTO_PHASE, 1,754 DSCCLK2_DTO_MODULO, 1);755 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);756 break;757 case 3:758 REG_UPDATE_2(DSCCLK3_DTO_PARAM,759 DSCCLK3_DTO_PHASE, 1,760 DSCCLK3_DTO_MODULO, 1);761 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);762 break;763 default:764 BREAK_TO_DEBUGGER();765 return;766 }767}768 769static void dccg401_set_ref_dscclk(struct dccg *dccg,770 uint32_t dsc_inst)771{772 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);773 774 switch (dsc_inst) {775 case 0:776 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 0);777 REG_UPDATE_2(DSCCLK0_DTO_PARAM,778 DSCCLK0_DTO_PHASE, 0,779 DSCCLK0_DTO_MODULO, 0);780 break;781 case 1:782 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0);783 REG_UPDATE_2(DSCCLK1_DTO_PARAM,784 DSCCLK1_DTO_PHASE, 0,785 DSCCLK1_DTO_MODULO, 0);786 break;787 case 2:788 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0);789 REG_UPDATE_2(DSCCLK2_DTO_PARAM,790 DSCCLK2_DTO_PHASE, 0,791 DSCCLK2_DTO_MODULO, 0);792 break;793 case 3:794 REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0);795 REG_UPDATE_2(DSCCLK3_DTO_PARAM,796 DSCCLK3_DTO_PHASE, 0,797 DSCCLK3_DTO_MODULO, 0);798 break;799 default:800 return;801 }802}803 804static void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)805{806 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);807 808 switch (link_enc_inst) {809 case 0:810 REG_UPDATE(SYMCLKA_CLOCK_ENABLE,811 SYMCLKA_CLOCK_ENABLE, 1);812 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)813 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, 1);814 break;815 case 1:816 REG_UPDATE(SYMCLKB_CLOCK_ENABLE,817 SYMCLKB_CLOCK_ENABLE, 1);818 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)819 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, 1);820 break;821 case 2:822 REG_UPDATE(SYMCLKC_CLOCK_ENABLE,823 SYMCLKC_CLOCK_ENABLE, 1);824 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)825 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, 1);826 break;827 case 3:828 REG_UPDATE(SYMCLKD_CLOCK_ENABLE,829 SYMCLKD_CLOCK_ENABLE, 1);830 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)831 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, 1);832 break;833 }834 835 switch (stream_enc_inst) {836 case 0:837 REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE,838 SYMCLKA_FE_EN, 1,839 SYMCLKA_FE_SRC_SEL, link_enc_inst);840 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)841 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, 1);842 break;843 case 1:844 REG_UPDATE_2(SYMCLKB_CLOCK_ENABLE,845 SYMCLKB_FE_EN, 1,846 SYMCLKB_FE_SRC_SEL, link_enc_inst);847 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)848 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, 1);849 break;850 case 2:851 REG_UPDATE_2(SYMCLKC_CLOCK_ENABLE,852 SYMCLKC_FE_EN, 1,853 SYMCLKC_FE_SRC_SEL, link_enc_inst);854 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)855 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, 1);856 break;857 case 3:858 REG_UPDATE_2(SYMCLKD_CLOCK_ENABLE,859 SYMCLKD_FE_EN, 1,860 SYMCLKD_FE_SRC_SEL, link_enc_inst);861 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)862 REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, 1);863 break;864 }865}866 867/*get other front end connected to this backend*/868static uint8_t dccg401_get_number_enabled_symclk_fe_connected_to_be(struct dccg *dccg, uint32_t link_enc_inst)869{870 uint8_t num_enabled_symclk_fe = 0;871 uint32_t fe_clk_en[4] = {0}, be_clk_sel[4] = {0};872 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);873 uint8_t i;874 875 REG_GET_2(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, &fe_clk_en[0],876 SYMCLKA_FE_SRC_SEL, &be_clk_sel[0]);877 878 REG_GET_2(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, &fe_clk_en[1],879 SYMCLKB_FE_SRC_SEL, &be_clk_sel[1]);880 881 REG_GET_2(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, &fe_clk_en[2],882 SYMCLKC_FE_SRC_SEL, &be_clk_sel[2]);883 884 REG_GET_2(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, &fe_clk_en[3],885 SYMCLKD_FE_SRC_SEL, &be_clk_sel[3]);886 887 for (i = 0; i < ARRAY_SIZE(fe_clk_en); i++) {888 if (fe_clk_en[i] && be_clk_sel[i] == link_enc_inst)889 num_enabled_symclk_fe++;890 }891 892 return num_enabled_symclk_fe;893}894 895static void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)896{897 uint8_t num_enabled_symclk_fe = 0;898 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);899 900 switch (stream_enc_inst) {901 case 0:902 REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE,903 SYMCLKA_FE_EN, 0,904 SYMCLKA_FE_SRC_SEL, 0);905 break;906 case 1:907 REG_UPDATE_2(SYMCLKB_CLOCK_ENABLE,908 SYMCLKB_FE_EN, 0,909 SYMCLKB_FE_SRC_SEL, 0);910 break;911 case 2:912 REG_UPDATE_2(SYMCLKC_CLOCK_ENABLE,913 SYMCLKC_FE_EN, 0,914 SYMCLKC_FE_SRC_SEL, 0);915 break;916 case 3:917 REG_UPDATE_2(SYMCLKD_CLOCK_ENABLE,918 SYMCLKD_FE_EN, 0,919 SYMCLKD_FE_SRC_SEL, 0);920 break;921 }922 923 /*check other enabled symclk fe connected to this be */924 num_enabled_symclk_fe = dccg401_get_number_enabled_symclk_fe_connected_to_be(dccg, link_enc_inst);925 /*only turn off backend clk if other front ends attached to this backend are all off,926 for mst, only turn off the backend if this is the last front end*/927 if (num_enabled_symclk_fe == 0) {928 switch (link_enc_inst) {929 case 0:930 REG_UPDATE(SYMCLKA_CLOCK_ENABLE,931 SYMCLKA_CLOCK_ENABLE, 0);932 break;933 case 1:934 REG_UPDATE(SYMCLKB_CLOCK_ENABLE,935 SYMCLKB_CLOCK_ENABLE, 0);936 break;937 case 2:938 REG_UPDATE(SYMCLKC_CLOCK_ENABLE,939 SYMCLKC_CLOCK_ENABLE, 0);940 break;941 case 3:942 REG_UPDATE(SYMCLKD_CLOCK_ENABLE,943 SYMCLKD_CLOCK_ENABLE, 0);944 break;945 }946 }947}948 949static const struct dccg_funcs dccg401_funcs = {950 .update_dpp_dto = dccg401_update_dpp_dto,951 .get_dccg_ref_freq = dccg401_get_dccg_ref_freq,952 .dccg_init = dccg401_init,953 .set_dpstreamclk = dccg401_set_dpstreamclk,954 .enable_symclk32_se = dccg31_enable_symclk32_se,955 .disable_symclk32_se = dccg31_disable_symclk32_se,956 .enable_symclk32_le = dccg401_enable_symclk32_le,957 .disable_symclk32_le = dccg401_disable_symclk32_le,958 .set_physymclk = dccg401_set_physymclk,959 .set_dtbclk_dto = NULL,960 .set_dto_dscclk = dccg401_set_dto_dscclk,961 .set_ref_dscclk = dccg401_set_ref_dscclk,962 .set_valid_pixel_rate = NULL,963 .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,964 .set_audio_dtbclk_dto = NULL,965 .otg_add_pixel = dccg401_otg_add_pixel,966 .otg_drop_pixel = dccg401_otg_drop_pixel,967 .set_pixel_rate_div = dccg401_set_pixel_rate_div,968 .get_pixel_rate_div = dccg401_get_pixel_rate_div,969 .set_dp_dto = dccg401_set_dp_dto,970 .enable_symclk_se = dccg401_enable_symclk_se,971 .disable_symclk_se = dccg401_disable_symclk_se,972 .set_dtbclk_p_src = dccg401_set_dtbclk_p_src,973};974 975struct dccg *dccg401_create(976 struct dc_context *ctx,977 const struct dccg_registers *regs,978 const struct dccg_shift *dccg_shift,979 const struct dccg_mask *dccg_mask)980{981 struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);982 struct dccg *base;983 984 if (dccg_dcn == NULL) {985 BREAK_TO_DEBUGGER();986 return NULL;987 }988 989 base = &dccg_dcn->base;990 base->ctx = ctx;991 base->funcs = &dccg401_funcs;992 993 dccg_dcn->regs = regs;994 dccg_dcn->dccg_shift = dccg_shift;995 dccg_dcn->dccg_mask = dccg_mask;996 997 return &dccg_dcn->base;998}999