407 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright 2022 Advanced Micro Devices, Inc.4 *5 * Permission is hereby granted, free of charge, to any person obtaining a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: AMD24 *25 */26 27#include "reg_helper.h"28#include "core_types.h"29 30#include "dcn31/dcn31_dccg.h"31#include "dcn314_dccg.h"32 33#define TO_DCN_DCCG(dccg)\34 container_of(dccg, struct dcn_dccg, base)35 36#define REG(reg) \37 (dccg_dcn->regs->reg)38 39#undef FN40#define FN(reg_name, field_name) \41 dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name42 43#define CTX \44 dccg_dcn->base.ctx45#define DC_LOGGER \46 dccg->ctx->logger47 48static void dccg314_trigger_dio_fifo_resync(49 struct dccg *dccg)50{51 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);52 uint32_t dispclk_rdivider_value = 0;53 54 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_RDIVIDER, &dispclk_rdivider_value);55 REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, dispclk_rdivider_value);56}57 58static void dccg314_get_pixel_rate_div(59 struct dccg *dccg,60 uint32_t otg_inst,61 uint32_t *k1,62 uint32_t *k2)63{64 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);65 uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;66 67 *k1 = PIXEL_RATE_DIV_NA;68 *k2 = PIXEL_RATE_DIV_NA;69 70 switch (otg_inst) {71 case 0:72 REG_GET_2(OTG_PIXEL_RATE_DIV,73 OTG0_PIXEL_RATE_DIVK1, &val_k1,74 OTG0_PIXEL_RATE_DIVK2, &val_k2);75 break;76 case 1:77 REG_GET_2(OTG_PIXEL_RATE_DIV,78 OTG1_PIXEL_RATE_DIVK1, &val_k1,79 OTG1_PIXEL_RATE_DIVK2, &val_k2);80 break;81 case 2:82 REG_GET_2(OTG_PIXEL_RATE_DIV,83 OTG2_PIXEL_RATE_DIVK1, &val_k1,84 OTG2_PIXEL_RATE_DIVK2, &val_k2);85 break;86 case 3:87 REG_GET_2(OTG_PIXEL_RATE_DIV,88 OTG3_PIXEL_RATE_DIVK1, &val_k1,89 OTG3_PIXEL_RATE_DIVK2, &val_k2);90 break;91 default:92 BREAK_TO_DEBUGGER();93 return;94 }95 96 *k1 = val_k1;97 *k2 = val_k2;98}99 100static void dccg314_set_pixel_rate_div(101 struct dccg *dccg,102 uint32_t otg_inst,103 enum pixel_rate_div k1,104 enum pixel_rate_div k2)105{106 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);107 uint32_t cur_k1 = PIXEL_RATE_DIV_NA;108 uint32_t cur_k2 = PIXEL_RATE_DIV_NA;109 110 // Don't program 0xF into the register field. Not valid since111 // K1 / K2 field is only 1 / 2 bits wide112 if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA) {113 BREAK_TO_DEBUGGER();114 return;115 }116 117 dccg314_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2);118 if (k1 == cur_k1 && k2 == cur_k2)119 return;120 121 switch (otg_inst) {122 case 0:123 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,124 OTG0_PIXEL_RATE_DIVK1, k1,125 OTG0_PIXEL_RATE_DIVK2, k2);126 break;127 case 1:128 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,129 OTG1_PIXEL_RATE_DIVK1, k1,130 OTG1_PIXEL_RATE_DIVK2, k2);131 break;132 case 2:133 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,134 OTG2_PIXEL_RATE_DIVK1, k1,135 OTG2_PIXEL_RATE_DIVK2, k2);136 break;137 case 3:138 REG_UPDATE_2(OTG_PIXEL_RATE_DIV,139 OTG3_PIXEL_RATE_DIVK1, k1,140 OTG3_PIXEL_RATE_DIVK2, k2);141 break;142 default:143 BREAK_TO_DEBUGGER();144 return;145 }146}147 148static void dccg314_set_dtbclk_p_src(149 struct dccg *dccg,150 enum streamclk_source src,151 uint32_t otg_inst)152{153 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);154 155 uint32_t p_src_sel = 0; /* selects dprefclk */156 157 if (src == DTBCLK0)158 p_src_sel = 2; /* selects dtbclk0 */159 160 switch (otg_inst) {161 case 0:162 if (src == REFCLK)163 REG_UPDATE(DTBCLK_P_CNTL,164 DTBCLK_P0_EN, 0);165 else166 REG_UPDATE_2(DTBCLK_P_CNTL,167 DTBCLK_P0_SRC_SEL, p_src_sel,168 DTBCLK_P0_EN, 1);169 break;170 case 1:171 if (src == REFCLK)172 REG_UPDATE(DTBCLK_P_CNTL,173 DTBCLK_P1_EN, 0);174 else175 REG_UPDATE_2(DTBCLK_P_CNTL,176 DTBCLK_P1_SRC_SEL, p_src_sel,177 DTBCLK_P1_EN, 1);178 break;179 case 2:180 if (src == REFCLK)181 REG_UPDATE(DTBCLK_P_CNTL,182 DTBCLK_P2_EN, 0);183 else184 REG_UPDATE_2(DTBCLK_P_CNTL,185 DTBCLK_P2_SRC_SEL, p_src_sel,186 DTBCLK_P2_EN, 1);187 break;188 case 3:189 if (src == REFCLK)190 REG_UPDATE(DTBCLK_P_CNTL,191 DTBCLK_P3_EN, 0);192 else193 REG_UPDATE_2(DTBCLK_P_CNTL,194 DTBCLK_P3_SRC_SEL, p_src_sel,195 DTBCLK_P3_EN, 1);196 break;197 default:198 BREAK_TO_DEBUGGER();199 return;200 }201 202}203 204/* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */205static void dccg314_set_dtbclk_dto(206 struct dccg *dccg,207 const struct dtbclk_dto_params *params)208{209 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);210 /* DTO Output Rate / Pixel Rate = 1/4 */211 int req_dtbclk_khz = params->pixclk_khz / 4;212 213 if (params->ref_dtbclk_khz && req_dtbclk_khz) {214 uint32_t modulo, phase;215 216 // phase / modulo = dtbclk / dtbclk ref217 modulo = params->ref_dtbclk_khz * 1000;218 phase = req_dtbclk_khz * 1000;219 220 REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], modulo);221 REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], phase);222 223 REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],224 DTBCLK_DTO_ENABLE[params->otg_inst], 1);225 226 REG_WAIT(OTG_PIXEL_RATE_CNTL[params->otg_inst],227 DTBCLKDTO_ENABLE_STATUS[params->otg_inst], 1,228 1, 100);229 230 /* program OTG_PIXEL_RATE_DIV for DIVK1 and DIVK2 fields */231 dccg314_set_pixel_rate_div(dccg, params->otg_inst, PIXEL_RATE_DIV_BY_1, PIXEL_RATE_DIV_BY_1);232 233 /* The recommended programming sequence to enable DTBCLK DTO to generate234 * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should235 * be set only after DTO is enabled236 */237 REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],238 PIPE_DTO_SRC_SEL[params->otg_inst], 2);239 } else {240 REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst],241 DTBCLK_DTO_ENABLE[params->otg_inst], 0,242 PIPE_DTO_SRC_SEL[params->otg_inst], 1);243 244 REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0);245 REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0);246 }247}248 249void dccg314_set_dpstreamclk(250 struct dccg *dccg,251 enum streamclk_source src,252 int otg_inst,253 int dp_hpo_inst)254{255 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);256 257 /* set the dtbclk_p source */258 dccg314_set_dtbclk_p_src(dccg, src, otg_inst);259 260 /* enabled to select one of the DTBCLKs for pipe */261 switch (dp_hpo_inst) {262 case 0:263 REG_UPDATE_2(DPSTREAMCLK_CNTL,264 DPSTREAMCLK0_EN, (src == REFCLK) ? 0 : 1,265 DPSTREAMCLK0_SRC_SEL, otg_inst);266 break;267 case 1:268 REG_UPDATE_2(DPSTREAMCLK_CNTL,269 DPSTREAMCLK1_EN, (src == REFCLK) ? 0 : 1,270 DPSTREAMCLK1_SRC_SEL, otg_inst);271 break;272 case 2:273 REG_UPDATE_2(DPSTREAMCLK_CNTL,274 DPSTREAMCLK2_EN, (src == REFCLK) ? 0 : 1,275 DPSTREAMCLK2_SRC_SEL, otg_inst);276 break;277 case 3:278 REG_UPDATE_2(DPSTREAMCLK_CNTL,279 DPSTREAMCLK3_EN, (src == REFCLK) ? 0 : 1,280 DPSTREAMCLK3_SRC_SEL, otg_inst);281 break;282 default:283 BREAK_TO_DEBUGGER();284 return;285 }286}287 288static void dccg314_init(struct dccg *dccg)289{290 int otg_inst;291 292 /* Set HPO stream encoder to use refclk to avoid case where PHY is293 * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which294 * will cause DCN to hang.295 */296 for (otg_inst = 0; otg_inst < 4; otg_inst++)297 dccg31_disable_symclk32_se(dccg, otg_inst);298 299 if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)300 for (otg_inst = 0; otg_inst < 2; otg_inst++)301 dccg31_disable_symclk32_le(dccg, otg_inst);302 303 if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)304 for (otg_inst = 0; otg_inst < 4; otg_inst++)305 dccg314_set_dpstreamclk(dccg, REFCLK, otg_inst,306 otg_inst);307 308 if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)309 for (otg_inst = 0; otg_inst < 5; otg_inst++)310 dccg31_set_physymclk(dccg, otg_inst,311 PHYSYMCLK_FORCE_SRC_SYMCLK, false);312}313 314static void dccg314_set_valid_pixel_rate(315 struct dccg *dccg,316 int ref_dtbclk_khz,317 int otg_inst,318 int pixclk_khz)319{320 struct dtbclk_dto_params dto_params = {0};321 322 dto_params.ref_dtbclk_khz = ref_dtbclk_khz;323 dto_params.otg_inst = otg_inst;324 dto_params.pixclk_khz = pixclk_khz;325 326 dccg314_set_dtbclk_dto(dccg, &dto_params);327}328 329static void dccg314_dpp_root_clock_control(330 struct dccg *dccg,331 unsigned int dpp_inst,332 bool clock_on)333{334 struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);335 336 if (dccg->dpp_clock_gated[dpp_inst] != clock_on)337 return;338 339 if (clock_on) {340 /* turn off the DTO and leave phase/modulo at max */341 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 0);342 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,343 DPPCLK0_DTO_PHASE, 0xFF,344 DPPCLK0_DTO_MODULO, 0xFF);345 } else {346 /* turn on the DTO to generate a 0hz clock */347 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 1);348 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,349 DPPCLK0_DTO_PHASE, 0,350 DPPCLK0_DTO_MODULO, 1);351 }352 353 dccg->dpp_clock_gated[dpp_inst] = !clock_on;354}355 356static const struct dccg_funcs dccg314_funcs = {357 .update_dpp_dto = dccg31_update_dpp_dto,358 .dpp_root_clock_control = dccg314_dpp_root_clock_control,359 .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,360 .dccg_init = dccg314_init,361 .set_dpstreamclk = dccg314_set_dpstreamclk,362 .enable_symclk32_se = dccg31_enable_symclk32_se,363 .disable_symclk32_se = dccg31_disable_symclk32_se,364 .enable_symclk32_le = dccg31_enable_symclk32_le,365 .disable_symclk32_le = dccg31_disable_symclk32_le,366 .set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating,367 .set_physymclk = dccg31_set_physymclk,368 .set_dtbclk_dto = dccg314_set_dtbclk_dto,369 .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,370 .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,371 .otg_add_pixel = dccg31_otg_add_pixel,372 .otg_drop_pixel = dccg31_otg_drop_pixel,373 .set_dispclk_change_mode = dccg31_set_dispclk_change_mode,374 .disable_dsc = dccg31_disable_dscclk,375 .enable_dsc = dccg31_enable_dscclk,376 .set_pixel_rate_div = dccg314_set_pixel_rate_div,377 .get_pixel_rate_div = dccg314_get_pixel_rate_div,378 .trigger_dio_fifo_resync = dccg314_trigger_dio_fifo_resync,379 .set_valid_pixel_rate = dccg314_set_valid_pixel_rate,380 .set_dtbclk_p_src = dccg314_set_dtbclk_p_src381};382 383struct dccg *dccg314_create(384 struct dc_context *ctx,385 const struct dccg_registers *regs,386 const struct dccg_shift *dccg_shift,387 const struct dccg_mask *dccg_mask)388{389 struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);390 struct dccg *base;391 392 if (dccg_dcn == NULL) {393 BREAK_TO_DEBUGGER();394 return NULL;395 }396 397 base = &dccg_dcn->base;398 base->ctx = ctx;399 base->funcs = &dccg314_funcs;400 401 dccg_dcn->regs = regs;402 dccg_dcn->dccg_shift = dccg_shift;403 dccg_dcn->dccg_mask = dccg_mask;404 405 return &dccg_dcn->base;406}407