2873 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 "dm_services.h"28#include "dc.h"29 30#include "dcn32/dcn32_init.h"31 32#include "resource.h"33#include "include/irq_service_interface.h"34#include "dcn32_resource.h"35 36#include "dcn20/dcn20_resource.h"37#include "dcn30/dcn30_resource.h"38 39#include "dcn10/dcn10_ipp.h"40#include "dcn30/dcn30_hubbub.h"41#include "dcn31/dcn31_hubbub.h"42#include "dcn32/dcn32_hubbub.h"43#include "dcn32/dcn32_mpc.h"44#include "dcn32/dcn32_hubp.h"45#include "irq/dcn32/irq_service_dcn32.h"46#include "dcn32/dcn32_dpp.h"47#include "dcn32/dcn32_optc.h"48#include "dcn20/dcn20_hwseq.h"49#include "dcn30/dcn30_hwseq.h"50#include "dce110/dce110_hwseq.h"51#include "dcn30/dcn30_opp.h"52#include "dcn20/dcn20_dsc.h"53#include "dcn30/dcn30_vpg.h"54#include "dcn30/dcn30_afmt.h"55#include "dcn30/dcn30_dio_stream_encoder.h"56#include "dcn32/dcn32_dio_stream_encoder.h"57#include "dcn31/dcn31_hpo_dp_stream_encoder.h"58#include "dcn31/dcn31_hpo_dp_link_encoder.h"59#include "dcn32/dcn32_hpo_dp_link_encoder.h"60#include "dcn31/dcn31_apg.h"61#include "dcn31/dcn31_dio_link_encoder.h"62#include "dcn32/dcn32_dio_link_encoder.h"63#include "dce/dce_clock_source.h"64#include "dce/dce_audio.h"65#include "dce/dce_hwseq.h"66#include "clk_mgr.h"67#include "virtual/virtual_stream_encoder.h"68#include "dml/display_mode_vba.h"69#include "dcn32/dcn32_dccg.h"70#include "dcn10/dcn10_resource.h"71#include "link.h"72#include "dcn31/dcn31_panel_cntl.h"73 74#include "dcn30/dcn30_dwb.h"75#include "dcn32/dcn32_mmhubbub.h"76 77#include "dcn/dcn_3_2_0_offset.h"78#include "dcn/dcn_3_2_0_sh_mask.h"79#include "nbio/nbio_4_3_0_offset.h"80 81#include "reg_helper.h"82#include "dce/dmub_abm.h"83#include "dce/dmub_psr.h"84#include "dce/dce_aux.h"85#include "dce/dce_i2c.h"86 87#include "dml/dcn30/display_mode_vba_30.h"88#include "vm_helper.h"89#include "dcn20/dcn20_vmid.h"90#include "dml/dcn32/dcn32_fpu.h"91 92#include "dc_state_priv.h"93 94#include "dml2/dml2_wrapper.h"95 96#define DC_LOGGER_INIT(logger)97 98enum dcn32_clk_src_array_id {99 DCN32_CLK_SRC_PLL0,100 DCN32_CLK_SRC_PLL1,101 DCN32_CLK_SRC_PLL2,102 DCN32_CLK_SRC_PLL3,103 DCN32_CLK_SRC_PLL4,104 DCN32_CLK_SRC_TOTAL105};106 107/* begin *********************108 * macros to expend register list macro defined in HW object header file109 */110 111/* DCN */112#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]113 114#define BASE(seg) BASE_INNER(seg)115 116#define SR(reg_name)\117 REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \118 reg ## reg_name119#define SR_ARR(reg_name, id) \120 REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name121 122#define SR_ARR_INIT(reg_name, id, value) \123 REG_STRUCT[id].reg_name = value124 125#define SRI(reg_name, block, id)\126 REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \127 reg ## block ## id ## _ ## reg_name128 129#define SRI_ARR(reg_name, block, id)\130 REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \131 reg ## block ## id ## _ ## reg_name132 133#define SR_ARR_I2C(reg_name, id) \134 REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name135 136#define SRI_ARR_I2C(reg_name, block, id)\137 REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \138 reg ## block ## id ## _ ## reg_name139 140#define SRI_ARR_ALPHABET(reg_name, block, index, id)\141 REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \142 reg ## block ## id ## _ ## reg_name143 144#define SRI2(reg_name, block, id)\145 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \146 reg ## reg_name147#define SRI2_ARR(reg_name, block, id)\148 REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \149 reg ## reg_name150 151#define SRIR(var_name, reg_name, block, id)\152 .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \153 reg ## block ## id ## _ ## reg_name154 155#define SRII(reg_name, block, id)\156 REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \157 reg ## block ## id ## _ ## reg_name158 159#define SRII_ARR_2(reg_name, block, id, inst)\160 REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \161 reg ## block ## id ## _ ## reg_name162 163#define SRII_MPC_RMU(reg_name, block, id)\164 .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \165 reg ## block ## id ## _ ## reg_name166 167#define SRII_DWB(reg_name, temp_name, block, id)\168 REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \169 reg ## block ## id ## _ ## temp_name170 171#define SF_DWB2(reg_name, block, id, field_name, post_fix) \172 .field_name = reg_name ## __ ## field_name ## post_fix173 174#define DCCG_SRII(reg_name, block, id)\175 REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \176 reg ## block ## id ## _ ## reg_name177 178#define VUPDATE_SRII(reg_name, block, id)\179 REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \180 reg ## reg_name ## _ ## block ## id181 182/* NBIO */183#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg]184 185#define NBIO_BASE(seg) \186 NBIO_BASE_INNER(seg)187 188#define NBIO_SR(reg_name)\189 REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \190 regBIF_BX0_ ## reg_name191#define NBIO_SR_ARR(reg_name, id)\192 REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \193 regBIF_BX0_ ## reg_name194 195#undef CTX196#define CTX ctx197#define REG(reg_name) \198 (ctx->dcn_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)199 200static struct bios_registers bios_regs;201 202#define bios_regs_init() \203 ( \204 NBIO_SR(BIOS_SCRATCH_3),\205 NBIO_SR(BIOS_SCRATCH_6)\206 )207 208#define clk_src_regs_init(index, pllid)\209 CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid)210 211static struct dce110_clk_src_regs clk_src_regs[5];212 213static const struct dce110_clk_src_shift cs_shift = {214 CS_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT)215};216 217static const struct dce110_clk_src_mask cs_mask = {218 CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK)219};220 221#define abm_regs_init(id)\222 ABM_DCN32_REG_LIST_RI(id)223 224static struct dce_abm_registers abm_regs[4];225 226static const struct dce_abm_shift abm_shift = {227 ABM_MASK_SH_LIST_DCN32(__SHIFT)228};229 230static const struct dce_abm_mask abm_mask = {231 ABM_MASK_SH_LIST_DCN32(_MASK)232};233 234#define audio_regs_init(id)\235 AUD_COMMON_REG_LIST_RI(id)236 237static struct dce_audio_registers audio_regs[5];238 239#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\240 SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\241 SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\242 AUD_COMMON_MASK_SH_LIST_BASE(mask_sh)243 244static const struct dce_audio_shift audio_shift = {245 DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT)246};247 248static const struct dce_audio_mask audio_mask = {249 DCE120_AUD_COMMON_MASK_SH_LIST(_MASK)250};251 252#define vpg_regs_init(id)\253 VPG_DCN3_REG_LIST_RI(id)254 255static struct dcn30_vpg_registers vpg_regs[10];256 257static const struct dcn30_vpg_shift vpg_shift = {258 DCN3_VPG_MASK_SH_LIST(__SHIFT)259};260 261static const struct dcn30_vpg_mask vpg_mask = {262 DCN3_VPG_MASK_SH_LIST(_MASK)263};264 265#define afmt_regs_init(id)\266 AFMT_DCN3_REG_LIST_RI(id)267 268static struct dcn30_afmt_registers afmt_regs[6];269 270static const struct dcn30_afmt_shift afmt_shift = {271 DCN3_AFMT_MASK_SH_LIST(__SHIFT)272};273 274static const struct dcn30_afmt_mask afmt_mask = {275 DCN3_AFMT_MASK_SH_LIST(_MASK)276};277 278#define apg_regs_init(id)\279 APG_DCN31_REG_LIST_RI(id)280 281static struct dcn31_apg_registers apg_regs[4];282 283static const struct dcn31_apg_shift apg_shift = {284 DCN31_APG_MASK_SH_LIST(__SHIFT)285};286 287static const struct dcn31_apg_mask apg_mask = {288 DCN31_APG_MASK_SH_LIST(_MASK)289};290 291#define stream_enc_regs_init(id)\292 SE_DCN32_REG_LIST_RI(id)293 294static struct dcn10_stream_enc_registers stream_enc_regs[5];295 296static const struct dcn10_stream_encoder_shift se_shift = {297 SE_COMMON_MASK_SH_LIST_DCN32(__SHIFT)298};299 300static const struct dcn10_stream_encoder_mask se_mask = {301 SE_COMMON_MASK_SH_LIST_DCN32(_MASK)302};303 304 305#define aux_regs_init(id)\306 DCN2_AUX_REG_LIST_RI(id)307 308static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5];309 310#define hpd_regs_init(id)\311 HPD_REG_LIST_RI(id)312 313static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5];314 315#define link_regs_init(id, phyid)\316 ( \317 LE_DCN31_REG_LIST_RI(id), \318 UNIPHY_DCN2_REG_LIST_RI(id, phyid)\319 )320 /*DPCS_DCN31_REG_LIST(id),*/ \321 322static struct dcn10_link_enc_registers link_enc_regs[5];323 324static const struct dcn10_link_enc_shift le_shift = {325 LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \326 //DPCS_DCN31_MASK_SH_LIST(__SHIFT)327};328 329static const struct dcn10_link_enc_mask le_mask = {330 LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \331 //DPCS_DCN31_MASK_SH_LIST(_MASK)332};333 334#define hpo_dp_stream_encoder_reg_init(id)\335 DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id)336 337static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4];338 339static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {340 DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT)341};342 343static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {344 DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)345};346 347 348#define hpo_dp_link_encoder_reg_init(id)\349 DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id)350 /*DCN3_1_RDPCSTX_REG_LIST(0),*/351 /*DCN3_1_RDPCSTX_REG_LIST(1),*/352 /*DCN3_1_RDPCSTX_REG_LIST(2),*/353 /*DCN3_1_RDPCSTX_REG_LIST(3),*/354 355static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2];356 357static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = {358 DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT)359};360 361static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {362 DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)363};364 365#define dpp_regs_init(id)\366 DPP_REG_LIST_DCN30_COMMON_RI(id)367 368static struct dcn3_dpp_registers dpp_regs[4];369 370static const struct dcn3_dpp_shift tf_shift = {371 DPP_REG_LIST_SH_MASK_DCN30_COMMON(__SHIFT)372};373 374static const struct dcn3_dpp_mask tf_mask = {375 DPP_REG_LIST_SH_MASK_DCN30_COMMON(_MASK)376};377 378 379#define opp_regs_init(id)\380 OPP_REG_LIST_DCN30_RI(id)381 382static struct dcn20_opp_registers opp_regs[4];383 384static const struct dcn20_opp_shift opp_shift = {385 OPP_MASK_SH_LIST_DCN20(__SHIFT)386};387 388static const struct dcn20_opp_mask opp_mask = {389 OPP_MASK_SH_LIST_DCN20(_MASK)390};391 392#define aux_engine_regs_init(id)\393 ( \394 AUX_COMMON_REG_LIST0_RI(id), \395 SR_ARR_INIT(AUXN_IMPCAL, id, 0), \396 SR_ARR_INIT(AUXP_IMPCAL, id, 0), \397 SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \398 SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)\399 )400 401static struct dce110_aux_registers aux_engine_regs[5];402 403static const struct dce110_aux_registers_shift aux_shift = {404 DCN_AUX_MASK_SH_LIST(__SHIFT)405};406 407static const struct dce110_aux_registers_mask aux_mask = {408 DCN_AUX_MASK_SH_LIST(_MASK)409};410 411#define dwbc_regs_dcn3_init(id)\412 DWBC_COMMON_REG_LIST_DCN30_RI(id)413 414static struct dcn30_dwbc_registers dwbc30_regs[1];415 416static const struct dcn30_dwbc_shift dwbc30_shift = {417 DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)418};419 420static const struct dcn30_dwbc_mask dwbc30_mask = {421 DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK)422};423 424#define mcif_wb_regs_dcn3_init(id)\425 MCIF_WB_COMMON_REG_LIST_DCN32_RI(id)426 427static struct dcn30_mmhubbub_registers mcif_wb30_regs[1];428 429static const struct dcn30_mmhubbub_shift mcif_wb30_shift = {430 MCIF_WB_COMMON_MASK_SH_LIST_DCN32(__SHIFT)431};432 433static const struct dcn30_mmhubbub_mask mcif_wb30_mask = {434 MCIF_WB_COMMON_MASK_SH_LIST_DCN32(_MASK)435};436 437#define dsc_regsDCN20_init(id)\438 DSC_REG_LIST_DCN20_RI(id)439 440static struct dcn20_dsc_registers dsc_regs[4];441 442static const struct dcn20_dsc_shift dsc_shift = {443 DSC_REG_LIST_SH_MASK_DCN20(__SHIFT)444};445 446static const struct dcn20_dsc_mask dsc_mask = {447 DSC_REG_LIST_SH_MASK_DCN20(_MASK)448};449 450static struct dcn30_mpc_registers mpc_regs;451 452#define dcn_mpc_regs_init() \453 MPC_REG_LIST_DCN3_2_RI(0),\454 MPC_REG_LIST_DCN3_2_RI(1),\455 MPC_REG_LIST_DCN3_2_RI(2),\456 MPC_REG_LIST_DCN3_2_RI(3),\457 MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\458 MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\459 MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\460 MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\461 MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0)462 463static const struct dcn30_mpc_shift mpc_shift = {464 MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT)465};466 467static const struct dcn30_mpc_mask mpc_mask = {468 MPC_COMMON_MASK_SH_LIST_DCN32(_MASK)469};470 471#define optc_regs_init(id)\472 OPTC_COMMON_REG_LIST_DCN3_2_RI(id)473 474static struct dcn_optc_registers optc_regs[4];475 476static const struct dcn_optc_shift optc_shift = {477 OPTC_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT)478};479 480static const struct dcn_optc_mask optc_mask = {481 OPTC_COMMON_MASK_SH_LIST_DCN3_2(_MASK)482};483 484#define hubp_regs_init(id)\485 HUBP_REG_LIST_DCN32_RI(id)486 487static struct dcn_hubp2_registers hubp_regs[4];488 489 490static const struct dcn_hubp2_shift hubp_shift = {491 HUBP_MASK_SH_LIST_DCN32(__SHIFT)492};493 494static const struct dcn_hubp2_mask hubp_mask = {495 HUBP_MASK_SH_LIST_DCN32(_MASK)496};497 498static struct dcn_hubbub_registers hubbub_reg;499#define hubbub_reg_init()\500 HUBBUB_REG_LIST_DCN32_RI(0)501 502static const struct dcn_hubbub_shift hubbub_shift = {503 HUBBUB_MASK_SH_LIST_DCN32(__SHIFT)504};505 506static const struct dcn_hubbub_mask hubbub_mask = {507 HUBBUB_MASK_SH_LIST_DCN32(_MASK)508};509 510static struct dccg_registers dccg_regs;511 512#define dccg_regs_init()\513 DCCG_REG_LIST_DCN32_RI()514 515static const struct dccg_shift dccg_shift = {516 DCCG_MASK_SH_LIST_DCN32(__SHIFT)517};518 519static const struct dccg_mask dccg_mask = {520 DCCG_MASK_SH_LIST_DCN32(_MASK)521};522 523 524#define SRII2(reg_name_pre, reg_name_post, id)\525 .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \526 ## id ## _ ## reg_name_post ## _BASE_IDX) + \527 reg ## reg_name_pre ## id ## _ ## reg_name_post528 529 530#define HWSEQ_DCN32_REG_LIST()\531 SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \532 SR(DIO_MEM_PWR_CTRL), \533 SR(ODM_MEM_PWR_CTRL3), \534 SR(MMHUBBUB_MEM_PWR_CNTL), \535 SR(DCCG_GATE_DISABLE_CNTL), \536 SR(DCCG_GATE_DISABLE_CNTL2), \537 SR(DCFCLK_CNTL),\538 SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \539 SRII(PIXEL_RATE_CNTL, OTG, 0), \540 SRII(PIXEL_RATE_CNTL, OTG, 1),\541 SRII(PIXEL_RATE_CNTL, OTG, 2),\542 SRII(PIXEL_RATE_CNTL, OTG, 3),\543 SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\544 SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\545 SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\546 SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\547 SR(MICROSECOND_TIME_BASE_DIV), \548 SR(MILLISECOND_TIME_BASE_DIV), \549 SR(DISPCLK_FREQ_CHANGE_CNTL), \550 SR(RBBMIF_TIMEOUT_DIS), \551 SR(RBBMIF_TIMEOUT_DIS_2), \552 SR(DCHUBBUB_CRC_CTRL), \553 SR(DPP_TOP0_DPP_CRC_CTRL), \554 SR(DPP_TOP0_DPP_CRC_VAL_B_A), \555 SR(DPP_TOP0_DPP_CRC_VAL_R_G), \556 SR(MPC_CRC_CTRL), \557 SR(MPC_CRC_RESULT_GB), \558 SR(MPC_CRC_RESULT_C), \559 SR(MPC_CRC_RESULT_AR), \560 SR(DOMAIN0_PG_CONFIG), \561 SR(DOMAIN1_PG_CONFIG), \562 SR(DOMAIN2_PG_CONFIG), \563 SR(DOMAIN3_PG_CONFIG), \564 SR(DOMAIN16_PG_CONFIG), \565 SR(DOMAIN17_PG_CONFIG), \566 SR(DOMAIN18_PG_CONFIG), \567 SR(DOMAIN19_PG_CONFIG), \568 SR(DOMAIN0_PG_STATUS), \569 SR(DOMAIN1_PG_STATUS), \570 SR(DOMAIN2_PG_STATUS), \571 SR(DOMAIN3_PG_STATUS), \572 SR(DOMAIN16_PG_STATUS), \573 SR(DOMAIN17_PG_STATUS), \574 SR(DOMAIN18_PG_STATUS), \575 SR(DOMAIN19_PG_STATUS), \576 SR(D1VGA_CONTROL), \577 SR(D2VGA_CONTROL), \578 SR(D3VGA_CONTROL), \579 SR(D4VGA_CONTROL), \580 SR(D5VGA_CONTROL), \581 SR(D6VGA_CONTROL), \582 SR(DC_IP_REQUEST_CNTL), \583 SR(AZALIA_AUDIO_DTO), \584 SR(AZALIA_CONTROLLER_CLOCK_GATING)585 586static struct dce_hwseq_registers hwseq_reg;587 588#define hwseq_reg_init()\589 HWSEQ_DCN32_REG_LIST()590 591#define HWSEQ_DCN32_MASK_SH_LIST(mask_sh)\592 HWSEQ_DCN_MASK_SH_LIST(mask_sh), \593 HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \594 HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \595 HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \596 HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \597 HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \598 HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \599 HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \600 HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \601 HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \602 HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \603 HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \604 HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \605 HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \606 HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \607 HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \608 HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \609 HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \610 HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \611 HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \612 HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \613 HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \614 HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \615 HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \616 HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \617 HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \618 HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \619 HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \620 HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \621 HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \622 HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \623 HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh)624 625static const struct dce_hwseq_shift hwseq_shift = {626 HWSEQ_DCN32_MASK_SH_LIST(__SHIFT)627};628 629static const struct dce_hwseq_mask hwseq_mask = {630 HWSEQ_DCN32_MASK_SH_LIST(_MASK)631};632#define vmid_regs_init(id)\633 DCN20_VMID_REG_LIST_RI(id)634 635static struct dcn_vmid_registers vmid_regs[16];636 637static const struct dcn20_vmid_shift vmid_shifts = {638 DCN20_VMID_MASK_SH_LIST(__SHIFT)639};640 641static const struct dcn20_vmid_mask vmid_masks = {642 DCN20_VMID_MASK_SH_LIST(_MASK)643};644 645static const struct resource_caps res_cap_dcn32 = {646 .num_timing_generator = 4,647 .num_opp = 4,648 .num_video_plane = 4,649 .num_audio = 5,650 .num_stream_encoder = 5,651 .num_hpo_dp_stream_encoder = 4,652 .num_hpo_dp_link_encoder = 2,653 .num_pll = 5,654 .num_dwb = 1,655 .num_ddc = 5,656 .num_vmid = 16,657 .num_mpc_3dlut = 4,658 .num_dsc = 4,659};660 661static const struct dc_plane_cap plane_cap = {662 .type = DC_PLANE_TYPE_DCN_UNIVERSAL,663 .per_pixel_alpha = true,664 665 .pixel_format_support = {666 .argb8888 = true,667 .nv12 = true,668 .fp16 = true,669 .p010 = true,670 .ayuv = false,671 },672 673 .max_upscale_factor = {674 .argb8888 = 16000,675 .nv12 = 16000,676 .fp16 = 16000677 },678 679 // 6:1 downscaling ratio: 1000/6 = 166.666680 .max_downscale_factor = {681 .argb8888 = 167,682 .nv12 = 167,683 .fp16 = 167684 },685 64,686 64687};688 689static const struct dc_debug_options debug_defaults_drv = {690 .disable_dmcu = true,691 .force_abm_enable = false,692 .timing_trace = false,693 .clock_trace = true,694 .disable_pplib_clock_request = false,695 .pipe_split_policy = MPC_SPLIT_AVOID, // Due to CRB, no need to MPC split anymore696 .force_single_disp_pipe_split = false,697 .disable_dcc = DCC_ENABLE,698 .vsr_support = true,699 .performance_trace = false,700 .max_downscale_src_width = 7680,/*upto 8K*/701 .disable_pplib_wm_range = false,702 .scl_reset_length10 = true,703 .sanity_checks = false,704 .underflow_assert_delay_us = 0xFFFFFFFF,705 .dwb_fi_phase = -1, // -1 = disable,706 .dmub_command_table = true,707 .enable_mem_low_power = {708 .bits = {709 .vga = false,710 .i2c = false,711 .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled712 .dscl = false,713 .cm = false,714 .mpc = false,715 .optc = true,716 }717 },718 .use_max_lb = true,719 .force_disable_subvp = false,720 .exit_idle_opt_for_cursor_updates = true,721 .using_dml2 = false,722 .using_dml21 = false, // TODO : Temporary for N-1 validation. Remove after N-1 is done.723 .enable_single_display_2to1_odm_policy = true,724 725 /* Must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/726 .enable_double_buffered_dsc_pg_support = true,727 .enable_dp_dig_pixel_rate_div_policy = 1,728 .allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback"729 .alloc_extra_way_for_cursor = true,730 .min_prefetch_in_strobe_ns = 60000, // 60us731 .disable_unbounded_requesting = false,732 .override_dispclk_programming = true,733 .disable_fpo_optimizations = false,734 .fpo_vactive_margin_us = 2000, // 2000us735 .disable_fpo_vactive = false,736 .disable_boot_optimizations = false,737 .disable_subvp_high_refresh = false,738 .disable_dp_plus_plus_wa = true,739 .fpo_vactive_min_active_margin_us = 200,740 .fpo_vactive_max_blank_us = 1000,741 .enable_legacy_fast_update = false,742};743 744static struct dce_aux *dcn32_aux_engine_create(745 struct dc_context *ctx,746 uint32_t inst)747{748 struct aux_engine_dce110 *aux_engine =749 kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);750 751 if (!aux_engine)752 return NULL;753 754#undef REG_STRUCT755#define REG_STRUCT aux_engine_regs756 aux_engine_regs_init(0),757 aux_engine_regs_init(1),758 aux_engine_regs_init(2),759 aux_engine_regs_init(3),760 aux_engine_regs_init(4);761 762 dce110_aux_engine_construct(aux_engine, ctx, inst,763 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,764 &aux_engine_regs[inst],765 &aux_mask,766 &aux_shift,767 ctx->dc->caps.extended_aux_timeout_support);768 769 return &aux_engine->base;770}771#define i2c_inst_regs_init(id)\772 I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id)773 774static struct dce_i2c_registers i2c_hw_regs[5];775 776static const struct dce_i2c_shift i2c_shifts = {777 I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT)778};779 780static const struct dce_i2c_mask i2c_masks = {781 I2C_COMMON_MASK_SH_LIST_DCN30(_MASK)782};783 784static struct dce_i2c_hw *dcn32_i2c_hw_create(785 struct dc_context *ctx,786 uint32_t inst)787{788 struct dce_i2c_hw *dce_i2c_hw =789 kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL);790 791 if (!dce_i2c_hw)792 return NULL;793 794#undef REG_STRUCT795#define REG_STRUCT i2c_hw_regs796 i2c_inst_regs_init(1),797 i2c_inst_regs_init(2),798 i2c_inst_regs_init(3),799 i2c_inst_regs_init(4),800 i2c_inst_regs_init(5);801 802 dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst,803 &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks);804 805 return dce_i2c_hw;806}807 808static struct clock_source *dcn32_clock_source_create(809 struct dc_context *ctx,810 struct dc_bios *bios,811 enum clock_source_id id,812 const struct dce110_clk_src_regs *regs,813 bool dp_clk_src)814{815 struct dce110_clk_src *clk_src =816 kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL);817 818 if (!clk_src)819 return NULL;820 821 if (dcn31_clk_src_construct(clk_src, ctx, bios, id,822 regs, &cs_shift, &cs_mask)) {823 clk_src->base.dp_clk_src = dp_clk_src;824 return &clk_src->base;825 }826 827 kfree(clk_src);828 BREAK_TO_DEBUGGER();829 return NULL;830}831 832static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx)833{834 int i;835 836 struct dcn20_hubbub *hubbub2 = kzalloc(sizeof(struct dcn20_hubbub),837 GFP_KERNEL);838 839 if (!hubbub2)840 return NULL;841 842#undef REG_STRUCT843#define REG_STRUCT hubbub_reg844 hubbub_reg_init();845 846#undef REG_STRUCT847#define REG_STRUCT vmid_regs848 vmid_regs_init(0),849 vmid_regs_init(1),850 vmid_regs_init(2),851 vmid_regs_init(3),852 vmid_regs_init(4),853 vmid_regs_init(5),854 vmid_regs_init(6),855 vmid_regs_init(7),856 vmid_regs_init(8),857 vmid_regs_init(9),858 vmid_regs_init(10),859 vmid_regs_init(11),860 vmid_regs_init(12),861 vmid_regs_init(13),862 vmid_regs_init(14),863 vmid_regs_init(15);864 865 hubbub32_construct(hubbub2, ctx,866 &hubbub_reg,867 &hubbub_shift,868 &hubbub_mask,869 ctx->dc->dml.ip.det_buffer_size_kbytes,870 ctx->dc->dml.ip.pixel_chunk_size_kbytes,871 ctx->dc->dml.ip.config_return_buffer_size_in_kbytes);872 873 874 for (i = 0; i < res_cap_dcn32.num_vmid; i++) {875 struct dcn20_vmid *vmid = &hubbub2->vmid[i];876 877 vmid->ctx = ctx;878 879 vmid->regs = &vmid_regs[i];880 vmid->shifts = &vmid_shifts;881 vmid->masks = &vmid_masks;882 }883 884 return &hubbub2->base;885}886 887static struct hubp *dcn32_hubp_create(888 struct dc_context *ctx,889 uint32_t inst)890{891 struct dcn20_hubp *hubp2 =892 kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL);893 894 if (!hubp2)895 return NULL;896 897#undef REG_STRUCT898#define REG_STRUCT hubp_regs899 hubp_regs_init(0),900 hubp_regs_init(1),901 hubp_regs_init(2),902 hubp_regs_init(3);903 904 if (hubp32_construct(hubp2, ctx, inst,905 &hubp_regs[inst], &hubp_shift, &hubp_mask))906 return &hubp2->base;907 908 BREAK_TO_DEBUGGER();909 kfree(hubp2);910 return NULL;911}912 913static void dcn32_dpp_destroy(struct dpp **dpp)914{915 kfree(TO_DCN30_DPP(*dpp));916 *dpp = NULL;917}918 919static struct dpp *dcn32_dpp_create(920 struct dc_context *ctx,921 uint32_t inst)922{923 struct dcn3_dpp *dpp3 =924 kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL);925 926 if (!dpp3)927 return NULL;928 929#undef REG_STRUCT930#define REG_STRUCT dpp_regs931 dpp_regs_init(0),932 dpp_regs_init(1),933 dpp_regs_init(2),934 dpp_regs_init(3);935 936 if (dpp32_construct(dpp3, ctx, inst,937 &dpp_regs[inst], &tf_shift, &tf_mask))938 return &dpp3->base;939 940 BREAK_TO_DEBUGGER();941 kfree(dpp3);942 return NULL;943}944 945static struct mpc *dcn32_mpc_create(946 struct dc_context *ctx,947 int num_mpcc,948 int num_rmu)949{950 struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc),951 GFP_KERNEL);952 953 if (!mpc30)954 return NULL;955 956#undef REG_STRUCT957#define REG_STRUCT mpc_regs958 dcn_mpc_regs_init();959 960 dcn32_mpc_construct(mpc30, ctx,961 &mpc_regs,962 &mpc_shift,963 &mpc_mask,964 num_mpcc,965 num_rmu);966 967 return &mpc30->base;968}969 970static struct output_pixel_processor *dcn32_opp_create(971 struct dc_context *ctx, uint32_t inst)972{973 struct dcn20_opp *opp2 =974 kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL);975 976 if (!opp2) {977 BREAK_TO_DEBUGGER();978 return NULL;979 }980 981#undef REG_STRUCT982#define REG_STRUCT opp_regs983 opp_regs_init(0),984 opp_regs_init(1),985 opp_regs_init(2),986 opp_regs_init(3);987 988 dcn20_opp_construct(opp2, ctx, inst,989 &opp_regs[inst], &opp_shift, &opp_mask);990 return &opp2->base;991}992 993 994static struct timing_generator *dcn32_timing_generator_create(995 struct dc_context *ctx,996 uint32_t instance)997{998 struct optc *tgn10 =999 kzalloc(sizeof(struct optc), GFP_KERNEL);1000 1001 if (!tgn10)1002 return NULL;1003 1004#undef REG_STRUCT1005#define REG_STRUCT optc_regs1006 optc_regs_init(0),1007 optc_regs_init(1),1008 optc_regs_init(2),1009 optc_regs_init(3);1010 1011 tgn10->base.inst = instance;1012 tgn10->base.ctx = ctx;1013 1014 tgn10->tg_regs = &optc_regs[instance];1015 tgn10->tg_shift = &optc_shift;1016 tgn10->tg_mask = &optc_mask;1017 1018 dcn32_timing_generator_init(tgn10);1019 1020 return &tgn10->base;1021}1022 1023static const struct encoder_feature_support link_enc_feature = {1024 .max_hdmi_deep_color = COLOR_DEPTH_121212,1025 .max_hdmi_pixel_clock = 600000,1026 .hdmi_ycbcr420_supported = true,1027 .dp_ycbcr420_supported = true,1028 .fec_supported = true,1029 .flags.bits.IS_HBR2_CAPABLE = true,1030 .flags.bits.IS_HBR3_CAPABLE = true,1031 .flags.bits.IS_TPS3_CAPABLE = true,1032 .flags.bits.IS_TPS4_CAPABLE = true1033};1034 1035static struct link_encoder *dcn32_link_encoder_create(1036 struct dc_context *ctx,1037 const struct encoder_init_data *enc_init_data)1038{1039 struct dcn20_link_encoder *enc20 =1040 kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);1041 1042 if (!enc20)1043 return NULL;1044 1045#undef REG_STRUCT1046#define REG_STRUCT link_enc_aux_regs1047 aux_regs_init(0),1048 aux_regs_init(1),1049 aux_regs_init(2),1050 aux_regs_init(3),1051 aux_regs_init(4);1052 1053#undef REG_STRUCT1054#define REG_STRUCT link_enc_hpd_regs1055 hpd_regs_init(0),1056 hpd_regs_init(1),1057 hpd_regs_init(2),1058 hpd_regs_init(3),1059 hpd_regs_init(4);1060 1061#undef REG_STRUCT1062#define REG_STRUCT link_enc_regs1063 link_regs_init(0, A),1064 link_regs_init(1, B),1065 link_regs_init(2, C),1066 link_regs_init(3, D),1067 link_regs_init(4, E);1068 1069 dcn32_link_encoder_construct(enc20,1070 enc_init_data,1071 &link_enc_feature,1072 &link_enc_regs[enc_init_data->transmitter],1073 &link_enc_aux_regs[enc_init_data->channel - 1],1074 &link_enc_hpd_regs[enc_init_data->hpd_source],1075 &le_shift,1076 &le_mask);1077 1078 return &enc20->enc10.base;1079}1080 1081struct panel_cntl *dcn32_panel_cntl_create(const struct panel_cntl_init_data *init_data)1082{1083 struct dcn31_panel_cntl *panel_cntl =1084 kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL);1085 1086 if (!panel_cntl)1087 return NULL;1088 1089 dcn31_panel_cntl_construct(panel_cntl, init_data);1090 1091 return &panel_cntl->base;1092}1093 1094static void read_dce_straps(1095 struct dc_context *ctx,1096 struct resource_straps *straps)1097{1098 generic_reg_get(ctx, ctx->dcn_reg_offsets[regDC_PINSTRAPS_BASE_IDX] + regDC_PINSTRAPS,1099 FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio);1100 1101}1102 1103static struct audio *dcn32_create_audio(1104 struct dc_context *ctx, unsigned int inst)1105{1106 1107#undef REG_STRUCT1108#define REG_STRUCT audio_regs1109 audio_regs_init(0),1110 audio_regs_init(1),1111 audio_regs_init(2),1112 audio_regs_init(3),1113 audio_regs_init(4);1114 1115 return dce_audio_create(ctx, inst,1116 &audio_regs[inst], &audio_shift, &audio_mask);1117}1118 1119static struct vpg *dcn32_vpg_create(1120 struct dc_context *ctx,1121 uint32_t inst)1122{1123 struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL);1124 1125 if (!vpg3)1126 return NULL;1127 1128#undef REG_STRUCT1129#define REG_STRUCT vpg_regs1130 vpg_regs_init(0),1131 vpg_regs_init(1),1132 vpg_regs_init(2),1133 vpg_regs_init(3),1134 vpg_regs_init(4),1135 vpg_regs_init(5),1136 vpg_regs_init(6),1137 vpg_regs_init(7),1138 vpg_regs_init(8),1139 vpg_regs_init(9);1140 1141 vpg3_construct(vpg3, ctx, inst,1142 &vpg_regs[inst],1143 &vpg_shift,1144 &vpg_mask);1145 1146 return &vpg3->base;1147}1148 1149static struct afmt *dcn32_afmt_create(1150 struct dc_context *ctx,1151 uint32_t inst)1152{1153 struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL);1154 1155 if (!afmt3)1156 return NULL;1157 1158#undef REG_STRUCT1159#define REG_STRUCT afmt_regs1160 afmt_regs_init(0),1161 afmt_regs_init(1),1162 afmt_regs_init(2),1163 afmt_regs_init(3),1164 afmt_regs_init(4),1165 afmt_regs_init(5);1166 1167 afmt3_construct(afmt3, ctx, inst,1168 &afmt_regs[inst],1169 &afmt_shift,1170 &afmt_mask);1171 1172 return &afmt3->base;1173}1174 1175static struct apg *dcn31_apg_create(1176 struct dc_context *ctx,1177 uint32_t inst)1178{1179 struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);1180 1181 if (!apg31)1182 return NULL;1183 1184#undef REG_STRUCT1185#define REG_STRUCT apg_regs1186 apg_regs_init(0),1187 apg_regs_init(1),1188 apg_regs_init(2),1189 apg_regs_init(3);1190 1191 apg31_construct(apg31, ctx, inst,1192 &apg_regs[inst],1193 &apg_shift,1194 &apg_mask);1195 1196 return &apg31->base;1197}1198 1199static struct stream_encoder *dcn32_stream_encoder_create(1200 enum engine_id eng_id,1201 struct dc_context *ctx)1202{1203 struct dcn10_stream_encoder *enc1;1204 struct vpg *vpg;1205 struct afmt *afmt;1206 int vpg_inst;1207 int afmt_inst;1208 1209 /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */1210 if (eng_id <= ENGINE_ID_DIGF) {1211 vpg_inst = eng_id;1212 afmt_inst = eng_id;1213 } else1214 return NULL;1215 1216 enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);1217 vpg = dcn32_vpg_create(ctx, vpg_inst);1218 afmt = dcn32_afmt_create(ctx, afmt_inst);1219 1220 if (!enc1 || !vpg || !afmt) {1221 kfree(enc1);1222 kfree(vpg);1223 kfree(afmt);1224 return NULL;1225 }1226 1227#undef REG_STRUCT1228#define REG_STRUCT stream_enc_regs1229 stream_enc_regs_init(0),1230 stream_enc_regs_init(1),1231 stream_enc_regs_init(2),1232 stream_enc_regs_init(3),1233 stream_enc_regs_init(4);1234 1235 dcn32_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,1236 eng_id, vpg, afmt,1237 &stream_enc_regs[eng_id],1238 &se_shift, &se_mask);1239 1240 return &enc1->base;1241}1242 1243static struct hpo_dp_stream_encoder *dcn32_hpo_dp_stream_encoder_create(1244 enum engine_id eng_id,1245 struct dc_context *ctx)1246{1247 struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31;1248 struct vpg *vpg;1249 struct apg *apg;1250 uint32_t hpo_dp_inst;1251 uint32_t vpg_inst;1252 uint32_t apg_inst;1253 1254 ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3));1255 hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0;1256 1257 /* Mapping of VPG register blocks to HPO DP block instance:1258 * VPG[6] -> HPO_DP[0]1259 * VPG[7] -> HPO_DP[1]1260 * VPG[8] -> HPO_DP[2]1261 * VPG[9] -> HPO_DP[3]1262 */1263 vpg_inst = hpo_dp_inst + 6;1264 1265 /* Mapping of APG register blocks to HPO DP block instance:1266 * APG[0] -> HPO_DP[0]1267 * APG[1] -> HPO_DP[1]1268 * APG[2] -> HPO_DP[2]1269 * APG[3] -> HPO_DP[3]1270 */1271 apg_inst = hpo_dp_inst;1272 1273 /* allocate HPO stream encoder and create VPG sub-block */1274 hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL);1275 vpg = dcn32_vpg_create(ctx, vpg_inst);1276 apg = dcn31_apg_create(ctx, apg_inst);1277 1278 if (!hpo_dp_enc31 || !vpg || !apg) {1279 kfree(hpo_dp_enc31);1280 kfree(vpg);1281 kfree(apg);1282 return NULL;1283 }1284 1285#undef REG_STRUCT1286#define REG_STRUCT hpo_dp_stream_enc_regs1287 hpo_dp_stream_encoder_reg_init(0),1288 hpo_dp_stream_encoder_reg_init(1),1289 hpo_dp_stream_encoder_reg_init(2),1290 hpo_dp_stream_encoder_reg_init(3);1291 1292 dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios,1293 hpo_dp_inst, eng_id, vpg, apg,1294 &hpo_dp_stream_enc_regs[hpo_dp_inst],1295 &hpo_dp_se_shift, &hpo_dp_se_mask);1296 1297 return &hpo_dp_enc31->base;1298}1299 1300static struct hpo_dp_link_encoder *dcn32_hpo_dp_link_encoder_create(1301 uint8_t inst,1302 struct dc_context *ctx)1303{1304 struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31;1305 1306 /* allocate HPO link encoder */1307 hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL);1308 if (!hpo_dp_enc31)1309 return NULL; /* out of memory */1310 1311#undef REG_STRUCT1312#define REG_STRUCT hpo_dp_link_enc_regs1313 hpo_dp_link_encoder_reg_init(0),1314 hpo_dp_link_encoder_reg_init(1);1315 1316 hpo_dp_link_encoder32_construct(hpo_dp_enc31, ctx, inst,1317 &hpo_dp_link_enc_regs[inst],1318 &hpo_dp_le_shift, &hpo_dp_le_mask);1319 1320 return &hpo_dp_enc31->base;1321}1322 1323static struct dce_hwseq *dcn32_hwseq_create(1324 struct dc_context *ctx)1325{1326 struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);1327 1328#undef REG_STRUCT1329#define REG_STRUCT hwseq_reg1330 hwseq_reg_init();1331 1332 if (hws) {1333 hws->ctx = ctx;1334 hws->regs = &hwseq_reg;1335 hws->shifts = &hwseq_shift;1336 hws->masks = &hwseq_mask;1337 }1338 return hws;1339}1340static const struct resource_create_funcs res_create_funcs = {1341 .read_dce_straps = read_dce_straps,1342 .create_audio = dcn32_create_audio,1343 .create_stream_encoder = dcn32_stream_encoder_create,1344 .create_hpo_dp_stream_encoder = dcn32_hpo_dp_stream_encoder_create,1345 .create_hpo_dp_link_encoder = dcn32_hpo_dp_link_encoder_create,1346 .create_hwseq = dcn32_hwseq_create,1347};1348 1349static void dcn32_resource_destruct(struct dcn32_resource_pool *pool)1350{1351 unsigned int i;1352 1353 for (i = 0; i < pool->base.stream_enc_count; i++) {1354 if (pool->base.stream_enc[i] != NULL) {1355 if (pool->base.stream_enc[i]->vpg != NULL) {1356 kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg));1357 pool->base.stream_enc[i]->vpg = NULL;1358 }1359 if (pool->base.stream_enc[i]->afmt != NULL) {1360 kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt));1361 pool->base.stream_enc[i]->afmt = NULL;1362 }1363 kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i]));1364 pool->base.stream_enc[i] = NULL;1365 }1366 }1367 1368 for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) {1369 if (pool->base.hpo_dp_stream_enc[i] != NULL) {1370 if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) {1371 kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg));1372 pool->base.hpo_dp_stream_enc[i]->vpg = NULL;1373 }1374 if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) {1375 kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg));1376 pool->base.hpo_dp_stream_enc[i]->apg = NULL;1377 }1378 kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i]));1379 pool->base.hpo_dp_stream_enc[i] = NULL;1380 }1381 }1382 1383 for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) {1384 if (pool->base.hpo_dp_link_enc[i] != NULL) {1385 kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i]));1386 pool->base.hpo_dp_link_enc[i] = NULL;1387 }1388 }1389 1390 for (i = 0; i < pool->base.res_cap->num_dsc; i++) {1391 if (pool->base.dscs[i] != NULL)1392 dcn20_dsc_destroy(&pool->base.dscs[i]);1393 }1394 1395 if (pool->base.mpc != NULL) {1396 kfree(TO_DCN20_MPC(pool->base.mpc));1397 pool->base.mpc = NULL;1398 }1399 if (pool->base.hubbub != NULL) {1400 kfree(TO_DCN20_HUBBUB(pool->base.hubbub));1401 pool->base.hubbub = NULL;1402 }1403 for (i = 0; i < pool->base.pipe_count; i++) {1404 if (pool->base.dpps[i] != NULL)1405 dcn32_dpp_destroy(&pool->base.dpps[i]);1406 1407 if (pool->base.ipps[i] != NULL)1408 pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]);1409 1410 if (pool->base.hubps[i] != NULL) {1411 kfree(TO_DCN20_HUBP(pool->base.hubps[i]));1412 pool->base.hubps[i] = NULL;1413 }1414 1415 if (pool->base.irqs != NULL) {1416 dal_irq_service_destroy(&pool->base.irqs);1417 }1418 }1419 1420 for (i = 0; i < pool->base.res_cap->num_ddc; i++) {1421 if (pool->base.engines[i] != NULL)1422 dce110_engine_destroy(&pool->base.engines[i]);1423 if (pool->base.hw_i2cs[i] != NULL) {1424 kfree(pool->base.hw_i2cs[i]);1425 pool->base.hw_i2cs[i] = NULL;1426 }1427 if (pool->base.sw_i2cs[i] != NULL) {1428 kfree(pool->base.sw_i2cs[i]);1429 pool->base.sw_i2cs[i] = NULL;1430 }1431 }1432 1433 for (i = 0; i < pool->base.res_cap->num_opp; i++) {1434 if (pool->base.opps[i] != NULL)1435 pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]);1436 }1437 1438 for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {1439 if (pool->base.timing_generators[i] != NULL) {1440 kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i]));1441 pool->base.timing_generators[i] = NULL;1442 }1443 }1444 1445 for (i = 0; i < pool->base.res_cap->num_dwb; i++) {1446 if (pool->base.dwbc[i] != NULL) {1447 kfree(TO_DCN30_DWBC(pool->base.dwbc[i]));1448 pool->base.dwbc[i] = NULL;1449 }1450 if (pool->base.mcif_wb[i] != NULL) {1451 kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i]));1452 pool->base.mcif_wb[i] = NULL;1453 }1454 }1455 1456 for (i = 0; i < pool->base.audio_count; i++) {1457 if (pool->base.audios[i])1458 dce_aud_destroy(&pool->base.audios[i]);1459 }1460 1461 for (i = 0; i < pool->base.clk_src_count; i++) {1462 if (pool->base.clock_sources[i] != NULL) {1463 dcn20_clock_source_destroy(&pool->base.clock_sources[i]);1464 pool->base.clock_sources[i] = NULL;1465 }1466 }1467 1468 for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) {1469 if (pool->base.mpc_lut[i] != NULL) {1470 dc_3dlut_func_release(pool->base.mpc_lut[i]);1471 pool->base.mpc_lut[i] = NULL;1472 }1473 if (pool->base.mpc_shaper[i] != NULL) {1474 dc_transfer_func_release(pool->base.mpc_shaper[i]);1475 pool->base.mpc_shaper[i] = NULL;1476 }1477 }1478 1479 if (pool->base.dp_clock_source != NULL) {1480 dcn20_clock_source_destroy(&pool->base.dp_clock_source);1481 pool->base.dp_clock_source = NULL;1482 }1483 1484 for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {1485 if (pool->base.multiple_abms[i] != NULL)1486 dce_abm_destroy(&pool->base.multiple_abms[i]);1487 }1488 1489 if (pool->base.psr != NULL)1490 dmub_psr_destroy(&pool->base.psr);1491 1492 if (pool->base.dccg != NULL)1493 dcn_dccg_destroy(&pool->base.dccg);1494 1495 if (pool->base.oem_device != NULL) {1496 struct dc *dc = pool->base.oem_device->ctx->dc;1497 1498 dc->link_srv->destroy_ddc_service(&pool->base.oem_device);1499 }1500}1501 1502 1503static bool dcn32_dwbc_create(struct dc_context *ctx, struct resource_pool *pool)1504{1505 int i;1506 uint32_t dwb_count = pool->res_cap->num_dwb;1507 1508 for (i = 0; i < dwb_count; i++) {1509 struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc),1510 GFP_KERNEL);1511 1512 if (!dwbc30) {1513 dm_error("DC: failed to create dwbc30!\n");1514 return false;1515 }1516 1517#undef REG_STRUCT1518#define REG_STRUCT dwbc30_regs1519 dwbc_regs_dcn3_init(0);1520 1521 dcn30_dwbc_construct(dwbc30, ctx,1522 &dwbc30_regs[i],1523 &dwbc30_shift,1524 &dwbc30_mask,1525 i);1526 1527 pool->dwbc[i] = &dwbc30->base;1528 }1529 return true;1530}1531 1532static bool dcn32_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool)1533{1534 int i;1535 uint32_t dwb_count = pool->res_cap->num_dwb;1536 1537 for (i = 0; i < dwb_count; i++) {1538 struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub),1539 GFP_KERNEL);1540 1541 if (!mcif_wb30) {1542 dm_error("DC: failed to create mcif_wb30!\n");1543 return false;1544 }1545 1546#undef REG_STRUCT1547#define REG_STRUCT mcif_wb30_regs1548 mcif_wb_regs_dcn3_init(0);1549 1550 dcn32_mmhubbub_construct(mcif_wb30, ctx,1551 &mcif_wb30_regs[i],1552 &mcif_wb30_shift,1553 &mcif_wb30_mask,1554 i);1555 1556 pool->mcif_wb[i] = &mcif_wb30->base;1557 }1558 return true;1559}1560 1561static struct display_stream_compressor *dcn32_dsc_create(1562 struct dc_context *ctx, uint32_t inst)1563{1564 struct dcn20_dsc *dsc =1565 kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL);1566 1567 if (!dsc) {1568 BREAK_TO_DEBUGGER();1569 return NULL;1570 }1571 1572#undef REG_STRUCT1573#define REG_STRUCT dsc_regs1574 dsc_regsDCN20_init(0),1575 dsc_regsDCN20_init(1),1576 dsc_regsDCN20_init(2),1577 dsc_regsDCN20_init(3);1578 1579 dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask);1580 1581 dsc->max_image_width = 6016;1582 1583 return &dsc->base;1584}1585 1586static void dcn32_destroy_resource_pool(struct resource_pool **pool)1587{1588 struct dcn32_resource_pool *dcn32_pool = TO_DCN32_RES_POOL(*pool);1589 1590 dcn32_resource_destruct(dcn32_pool);1591 kfree(dcn32_pool);1592 *pool = NULL;1593}1594 1595bool dcn32_acquire_post_bldn_3dlut(1596 struct resource_context *res_ctx,1597 const struct resource_pool *pool,1598 int mpcc_id,1599 struct dc_3dlut **lut,1600 struct dc_transfer_func **shaper)1601{1602 bool ret = false;1603 1604 ASSERT(*lut == NULL && *shaper == NULL);1605 *lut = NULL;1606 *shaper = NULL;1607 1608 if (!res_ctx->is_mpc_3dlut_acquired[mpcc_id]) {1609 *lut = pool->mpc_lut[mpcc_id];1610 *shaper = pool->mpc_shaper[mpcc_id];1611 res_ctx->is_mpc_3dlut_acquired[mpcc_id] = true;1612 ret = true;1613 }1614 return ret;1615}1616 1617bool dcn32_release_post_bldn_3dlut(1618 struct resource_context *res_ctx,1619 const struct resource_pool *pool,1620 struct dc_3dlut **lut,1621 struct dc_transfer_func **shaper)1622{1623 int i;1624 bool ret = false;1625 1626 for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) {1627 if (pool->mpc_lut[i] == *lut && pool->mpc_shaper[i] == *shaper) {1628 res_ctx->is_mpc_3dlut_acquired[i] = false;1629 pool->mpc_lut[i]->state.raw = 0;1630 *lut = NULL;1631 *shaper = NULL;1632 ret = true;1633 break;1634 }1635 }1636 return ret;1637}1638 1639static void dcn32_enable_phantom_plane(struct dc *dc,1640 struct dc_state *context,1641 struct dc_stream_state *phantom_stream,1642 unsigned int dc_pipe_idx)1643{1644 struct dc_plane_state *phantom_plane = NULL;1645 struct dc_plane_state *prev_phantom_plane = NULL;1646 struct pipe_ctx *curr_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx];1647 1648 while (curr_pipe) {1649 if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state)1650 phantom_plane = prev_phantom_plane;1651 else1652 phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state);1653 1654 if (!phantom_plane)1655 continue;1656 1657 memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address));1658 memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality,1659 sizeof(phantom_plane->scaling_quality));1660 memcpy(&phantom_plane->src_rect, &curr_pipe->plane_state->src_rect, sizeof(phantom_plane->src_rect));1661 memcpy(&phantom_plane->dst_rect, &curr_pipe->plane_state->dst_rect, sizeof(phantom_plane->dst_rect));1662 memcpy(&phantom_plane->clip_rect, &curr_pipe->plane_state->clip_rect, sizeof(phantom_plane->clip_rect));1663 memcpy(&phantom_plane->plane_size, &curr_pipe->plane_state->plane_size,1664 sizeof(phantom_plane->plane_size));1665 memcpy(&phantom_plane->tiling_info, &curr_pipe->plane_state->tiling_info,1666 sizeof(phantom_plane->tiling_info));1667 memcpy(&phantom_plane->dcc, &curr_pipe->plane_state->dcc, sizeof(phantom_plane->dcc));1668 phantom_plane->format = curr_pipe->plane_state->format;1669 phantom_plane->rotation = curr_pipe->plane_state->rotation;1670 phantom_plane->visible = curr_pipe->plane_state->visible;1671 1672 /* Shadow pipe has small viewport. */1673 phantom_plane->clip_rect.y = 0;1674 phantom_plane->clip_rect.height = phantom_stream->src.height;1675 1676 dc_state_add_phantom_plane(dc, phantom_stream, phantom_plane, context);1677 1678 curr_pipe = curr_pipe->bottom_pipe;1679 prev_phantom_plane = phantom_plane;1680 }1681}1682 1683static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc,1684 struct dc_state *context,1685 display_e2e_pipe_params_st *pipes,1686 unsigned int pipe_cnt,1687 unsigned int dc_pipe_idx)1688{1689 struct dc_stream_state *phantom_stream = NULL;1690 struct pipe_ctx *ref_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx];1691 1692 phantom_stream = dc_state_create_phantom_stream(dc, context, ref_pipe->stream);1693 if (!phantom_stream)1694 return phantom_stream;1695 1696 /* stream has limited viewport and small timing */1697 memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing));1698 memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src));1699 memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst));1700 DC_FP_START();1701 dcn32_set_phantom_stream_timing(dc, context, ref_pipe, phantom_stream, pipes, pipe_cnt, dc_pipe_idx);1702 DC_FP_END();1703 1704 dc_state_add_phantom_stream(dc, context, phantom_stream, ref_pipe->stream);1705 return phantom_stream;1706}1707 1708/* TODO: Input to this function should indicate which pipe indexes (or streams)1709 * require a phantom pipe / stream1710 */1711void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context,1712 display_e2e_pipe_params_st *pipes,1713 unsigned int pipe_cnt,1714 unsigned int index)1715{1716 struct dc_stream_state *phantom_stream = NULL;1717 unsigned int i;1718 1719 // The index of the DC pipe passed into this function is guarenteed to1720 // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't1721 // already have phantom pipe assigned, etc.) by previous checks.1722 phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index);1723 if (!phantom_stream)1724 return;1725 1726 dcn32_enable_phantom_plane(dc, context, phantom_stream, index);1727 1728 for (i = 0; i < dc->res_pool->pipe_count; i++) {1729 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];1730 1731 // Build scaling params for phantom pipes which were newly added.1732 // We determine which phantom pipes were added by comparing with1733 // the phantom stream.1734 if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream &&1735 dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {1736 pipe->stream->use_dynamic_meta = false;1737 pipe->plane_state->flip_immediate = false;1738 if (!resource_build_scaling_params(pipe)) {1739 // Log / remove phantom pipes since failed to build scaling params1740 }1741 }1742 }1743}1744 1745static bool dml1_validate(struct dc *dc, struct dc_state *context, bool fast_validate)1746{1747 bool out = false;1748 1749 BW_VAL_TRACE_SETUP();1750 1751 int vlevel = 0;1752 int pipe_cnt = 0;1753 display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);1754 1755 /* To handle Freesync properly, setting FreeSync DML parameters1756 * to its default state for the first stage of validation1757 */1758 context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;1759 context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true;1760 1761 DC_LOGGER_INIT(dc->ctx->logger);1762 1763 BW_VAL_TRACE_COUNT();1764 1765 if (!pipes)1766 goto validate_fail;1767 1768 DC_FP_START();1769 out = dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);1770 DC_FP_END();1771 1772 if (pipe_cnt == 0)1773 goto validate_out;1774 1775 if (!out)1776 goto validate_fail;1777 1778 BW_VAL_TRACE_END_VOLTAGE_LEVEL();1779 1780 if (fast_validate) {1781 BW_VAL_TRACE_SKIP(fast);1782 goto validate_out;1783 }1784 1785 dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);1786 1787 dcn32_override_min_req_memclk(dc, context);1788 dcn32_override_min_req_dcfclk(dc, context);1789 1790 BW_VAL_TRACE_END_WATERMARKS();1791 1792 goto validate_out;1793 1794validate_fail:1795 DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",1796 dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));1797 1798 BW_VAL_TRACE_SKIP(fail);1799 out = false;1800 1801validate_out:1802 kfree(pipes);1803 1804 BW_VAL_TRACE_FINISH();1805 1806 return out;1807}1808 1809bool dcn32_validate_bandwidth(struct dc *dc,1810 struct dc_state *context,1811 bool fast_validate)1812{1813 bool out = false;1814 1815 if (dc->debug.using_dml2)1816 out = dml2_validate(dc, context,1817 context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,1818 fast_validate);1819 else1820 out = dml1_validate(dc, context, fast_validate);1821 return out;1822}1823 1824int dcn32_populate_dml_pipes_from_context(1825 struct dc *dc, struct dc_state *context,1826 display_e2e_pipe_params_st *pipes,1827 bool fast_validate)1828{1829 int i, pipe_cnt;1830 struct resource_context *res_ctx = &context->res_ctx;1831 struct pipe_ctx *pipe = NULL;1832 bool subvp_in_use = false;1833 struct dc_crtc_timing *timing;1834 int subvp_main_pipe_index = -1;1835 enum mall_stream_type mall_type;1836 bool single_display_subvp = false;1837 struct dc_stream_state *stream = NULL;1838 int num_subvp_main = 0;1839 int num_subvp_phantom = 0;1840 int num_subvp_none = 0;1841 int odm_slice_count;1842 1843 dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);1844 1845 /* For single display subvp, look for subvp main so if we have phantom1846 * pipe, we can set odm policy to match main pipe1847 */1848 for (i = 0; i < context->stream_count; i++) {1849 stream = context->streams[i];1850 mall_type = dc_state_get_stream_subvp_type(context, stream);1851 if (mall_type == SUBVP_MAIN)1852 num_subvp_main++;1853 else if (mall_type == SUBVP_PHANTOM)1854 num_subvp_phantom++;1855 else1856 num_subvp_none++;1857 }1858 if (num_subvp_main == 1 && num_subvp_phantom == 1 && num_subvp_none == 0)1859 single_display_subvp = true;1860 1861 if (single_display_subvp) {1862 for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {1863 pipe = &res_ctx->pipe_ctx[i];1864 if (!res_ctx->pipe_ctx[i].stream)1865 continue;1866 1867 mall_type = dc_state_get_pipe_subvp_type(context, pipe);1868 if (mall_type == SUBVP_MAIN) {1869 if (resource_is_pipe_type(pipe, OTG_MASTER))1870 subvp_main_pipe_index = i;1871 }1872 pipe_cnt++;1873 }1874 }1875 1876 for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {1877 1878 if (!res_ctx->pipe_ctx[i].stream)1879 continue;1880 pipe = &res_ctx->pipe_ctx[i];1881 timing = &pipe->stream->timing;1882 1883 pipes[pipe_cnt].pipe.src.gpuvm = true;1884 DC_FP_START();1885 dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt);1886 DC_FP_END();1887 pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;1888 if (dc->config.enable_windowed_mpo_odm &&1889 dc->debug.enable_single_display_2to1_odm_policy) {1890 /* For single display subvp, if pipe is phantom pipe,1891 * then copy odm policy from subvp main pipe1892 */1893 mall_type = dc_state_get_pipe_subvp_type(context, pipe);1894 if (single_display_subvp && (mall_type == SUBVP_PHANTOM)) {1895 if (subvp_main_pipe_index < 0) {1896 odm_slice_count = -1;1897 ASSERT(0);1898 } else {1899 odm_slice_count = resource_get_odm_slice_count(&res_ctx->pipe_ctx[subvp_main_pipe_index]);1900 }1901 } else {1902 odm_slice_count = resource_get_odm_slice_count(pipe);1903 }1904 switch (odm_slice_count) {1905 case 2:1906 pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1;1907 break;1908 case 4:1909 pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_4to1;1910 break;1911 default:1912 pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal;1913 }1914 } else {1915 pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal;1916 }1917 1918 pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet1919 pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;1920 pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_19;1921 1922 /* Only populate DML input with subvp info for full updates.1923 * This is just a workaround -- needs a proper fix.1924 */1925 if (!fast_validate) {1926 switch (dc_state_get_pipe_subvp_type(context, pipe)) {1927 case SUBVP_MAIN:1928 pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport;1929 subvp_in_use = true;1930 break;1931 case SUBVP_PHANTOM:1932 pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe;1933 pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;1934 // Disallow unbounded req for SubVP according to DCHUB programming guide1935 pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;1936 break;1937 case SUBVP_NONE:1938 pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_disable;1939 pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable;1940 break;1941 default:1942 break;1943 }1944 }1945 1946 pipes[pipe_cnt].dout.dsc_input_bpc = 0;1947 if (pipes[pipe_cnt].dout.dsc_enable) {1948 switch (timing->display_color_depth) {1949 case COLOR_DEPTH_888:1950 pipes[pipe_cnt].dout.dsc_input_bpc = 8;1951 break;1952 case COLOR_DEPTH_101010:1953 pipes[pipe_cnt].dout.dsc_input_bpc = 10;1954 break;1955 case COLOR_DEPTH_121212:1956 pipes[pipe_cnt].dout.dsc_input_bpc = 12;1957 break;1958 default:1959 ASSERT(0);1960 break;1961 }1962 }1963 1964 1965 pipe_cnt++;1966 }1967 1968 /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all1969 * the DET available for each pipe). Use the DET override input to maintain our driver1970 * policy.1971 */1972 dcn32_set_det_allocations(dc, context, pipes);1973 1974 // In general cases we want to keep the dram clock change requirement1975 // (prefer configs that support MCLK switch). Only override to false1976 // for SubVP1977 if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use)1978 context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false;1979 else1980 context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true;1981 1982 return pipe_cnt;1983}1984 1985unsigned int dcn32_calculate_mall_ways_from_bytes(const struct dc *dc, unsigned int total_size_in_mall_bytes)1986{1987 uint32_t cache_lines_used, lines_per_way, total_cache_lines, num_ways;1988 1989 if (total_size_in_mall_bytes == 0) {1990 return 0;1991 }1992 1993 /* add 2 lines for worst case alignment */1994 cache_lines_used = total_size_in_mall_bytes / dc->caps.cache_line_size + 2;1995 1996 total_cache_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size;1997 lines_per_way = total_cache_lines / dc->caps.cache_num_ways;1998 num_ways = cache_lines_used / lines_per_way;1999 if (cache_lines_used % lines_per_way > 0)2000 num_ways++;2001 2002 return num_ways;2003}2004 2005static struct dc_cap_funcs cap_funcs = {2006 .get_dcc_compression_cap = dcn20_get_dcc_compression_cap,2007 .get_subvp_en = dcn32_subvp_in_use,2008};2009 2010void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,2011 display_e2e_pipe_params_st *pipes,2012 int pipe_cnt,2013 int vlevel)2014{2015 DC_FP_START();2016 dcn32_calculate_wm_and_dlg_fpu(dc, context, pipes, pipe_cnt, vlevel);2017 DC_FP_END();2018}2019 2020static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)2021{2022 struct dml2_configuration_options *dml2_opt = &dc->dml2_tmp;2023 2024 memcpy(dml2_opt, &dc->dml2_options, sizeof(dc->dml2_options));2025 2026 DC_FP_START();2027 2028 dcn32_update_bw_bounding_box_fpu(dc, bw_params);2029 2030 dml2_opt->use_clock_dc_limits = false;2031 if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2)2032 dml2_reinit(dc, dml2_opt, &dc->current_state->bw_ctx.dml2);2033 2034 dml2_opt->use_clock_dc_limits = true;2035 if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2_dc_power_source)2036 dml2_reinit(dc, dml2_opt, &dc->current_state->bw_ctx.dml2_dc_power_source);2037 2038 DC_FP_END();2039}2040 2041static struct resource_funcs dcn32_res_pool_funcs = {2042 .destroy = dcn32_destroy_resource_pool,2043 .link_enc_create = dcn32_link_encoder_create,2044 .link_enc_create_minimal = NULL,2045 .panel_cntl_create = dcn32_panel_cntl_create,2046 .validate_bandwidth = dcn32_validate_bandwidth,2047 .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg,2048 .populate_dml_pipes = dcn32_populate_dml_pipes_from_context,2049 .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe,2050 .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head,2051 .release_pipe = dcn20_release_pipe,2052 .add_stream_to_ctx = dcn30_add_stream_to_ctx,2053 .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,2054 .remove_stream_from_ctx = dcn20_remove_stream_from_ctx,2055 .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context,2056 .set_mcif_arb_params = dcn30_set_mcif_arb_params,2057 .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,2058 .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut,2059 .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut,2060 .update_bw_bounding_box = dcn32_update_bw_bounding_box,2061 .patch_unknown_plane_state = dcn20_patch_unknown_plane_state,2062 .update_soc_for_wm_a = dcn30_update_soc_for_wm_a,2063 .add_phantom_pipes = dcn32_add_phantom_pipes,2064 .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params,2065 .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,2066};2067 2068static uint32_t read_pipe_fuses(struct dc_context *ctx)2069{2070 uint32_t value = REG_READ(CC_DC_PIPE_DIS);2071 /* DCN32 support max 4 pipes */2072 value = value & 0xf;2073 return value;2074}2075 2076 2077static bool dcn32_resource_construct(2078 uint8_t num_virtual_links,2079 struct dc *dc,2080 struct dcn32_resource_pool *pool)2081{2082 int i, j;2083 struct dc_context *ctx = dc->ctx;2084 struct irq_service_init_data init_data;2085 struct ddc_service_init_data ddc_init_data = {0};2086 uint32_t pipe_fuses = 0;2087 uint32_t num_pipes = 4;2088 2089#undef REG_STRUCT2090#define REG_STRUCT bios_regs2091 bios_regs_init();2092 2093#undef REG_STRUCT2094#define REG_STRUCT clk_src_regs2095 clk_src_regs_init(0, A),2096 clk_src_regs_init(1, B),2097 clk_src_regs_init(2, C),2098 clk_src_regs_init(3, D),2099 clk_src_regs_init(4, E);2100 2101#undef REG_STRUCT2102#define REG_STRUCT abm_regs2103 abm_regs_init(0),2104 abm_regs_init(1),2105 abm_regs_init(2),2106 abm_regs_init(3);2107 2108#undef REG_STRUCT2109#define REG_STRUCT dccg_regs2110 dccg_regs_init();2111 2112 DC_FP_START();2113 2114 ctx->dc_bios->regs = &bios_regs;2115 2116 pool->base.res_cap = &res_cap_dcn32;2117 /* max number of pipes for ASIC before checking for pipe fuses */2118 num_pipes = pool->base.res_cap->num_timing_generator;2119 pipe_fuses = read_pipe_fuses(ctx);2120 2121 for (i = 0; i < pool->base.res_cap->num_timing_generator; i++)2122 if (pipe_fuses & 1 << i)2123 num_pipes--;2124 2125 if (pipe_fuses & 1)2126 ASSERT(0); //Unexpected - Pipe 0 should always be fully functional!2127 2128 if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK)2129 ASSERT(0); //Entire DCN is harvested!2130 2131 /* within dml lib, initial value is hard coded, if ASIC pipe is fused, the2132 * value will be changed, update max_num_dpp and max_num_otg for dml.2133 */2134 dcn3_2_ip.max_num_dpp = num_pipes;2135 dcn3_2_ip.max_num_otg = num_pipes;2136 2137 pool->base.funcs = &dcn32_res_pool_funcs;2138 2139 /*************************************************2140 * Resource + asic cap harcoding *2141 *************************************************/2142 pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;2143 pool->base.timing_generator_count = num_pipes;2144 pool->base.pipe_count = num_pipes;2145 pool->base.mpcc_count = num_pipes;2146 dc->caps.max_downscale_ratio = 600;2147 dc->caps.i2c_speed_in_khz = 100;2148 dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/2149 /* TODO: Bring max_cursor_size back to 256 after subvp cursor corruption is fixed*/2150 dc->caps.max_cursor_size = 64;2151 dc->caps.min_horizontal_blanking_period = 80;2152 dc->caps.dmdata_alloc_size = 2048;2153 dc->caps.mall_size_per_mem_channel = 4;2154 /* total size = mall per channel * num channels * 1024 * 1024 */2155 dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576;2156 dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;2157 2158 dc->caps.cache_line_size = 64;2159 dc->caps.cache_num_ways = 16;2160 2161 /* Calculate the available MALL space */2162 dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(2163 dc, dc->ctx->dc_bios->vram_info.num_chans) *2164 dc->caps.mall_size_per_mem_channel * 1024 * 1024;2165 dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;2166 2167 dc->caps.subvp_fw_processing_delay_us = 15;2168 dc->caps.subvp_drr_max_vblank_margin_us = 40;2169 dc->caps.subvp_prefetch_end_to_mall_start_us = 15;2170 dc->caps.subvp_swath_height_margin_lines = 16;2171 dc->caps.subvp_pstate_allow_width_us = 20;2172 dc->caps.subvp_vertical_int_margin_us = 30;2173 dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin2174 2175 dc->caps.max_slave_planes = 2;2176 dc->caps.max_slave_yuv_planes = 2;2177 dc->caps.max_slave_rgb_planes = 2;2178 dc->caps.post_blend_color_processing = true;2179 dc->caps.force_dp_tps4_for_cp2520 = true;2180 if (dc->config.forceHBR2CP2520)2181 dc->caps.force_dp_tps4_for_cp2520 = false;2182 dc->caps.dp_hpo = true;2183 dc->caps.dp_hdmi21_pcon_support = true;2184 dc->caps.edp_dsc_support = true;2185 dc->caps.extended_aux_timeout_support = true;2186 dc->caps.dmcub_support = true;2187 dc->caps.seamless_odm = true;2188 dc->caps.max_v_total = (1 << 15) - 1;2189 2190 /* Color pipeline capabilities */2191 dc->caps.color.dpp.dcn_arch = 1;2192 dc->caps.color.dpp.input_lut_shared = 0;2193 dc->caps.color.dpp.icsc = 1;2194 dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr2195 dc->caps.color.dpp.dgam_rom_caps.srgb = 1;2196 dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1;2197 dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1;2198 dc->caps.color.dpp.dgam_rom_caps.pq = 1;2199 dc->caps.color.dpp.dgam_rom_caps.hlg = 1;2200 dc->caps.color.dpp.post_csc = 1;2201 dc->caps.color.dpp.gamma_corr = 1;2202 dc->caps.color.dpp.dgam_rom_for_yuv = 0;2203 2204 dc->caps.color.dpp.hw_3d_lut = 1;2205 dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN12206 // no OGAM ROM on DCN2 and later ASICs2207 dc->caps.color.dpp.ogam_rom_caps.srgb = 0;2208 dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;2209 dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0;2210 dc->caps.color.dpp.ogam_rom_caps.pq = 0;2211 dc->caps.color.dpp.ogam_rom_caps.hlg = 0;2212 dc->caps.color.dpp.ocsc = 0;2213 2214 dc->caps.color.mpc.gamut_remap = 1;2215 dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //4, configurable to be before or after BLND in MPCC2216 dc->caps.color.mpc.ogam_ram = 1;2217 dc->caps.color.mpc.ogam_rom_caps.srgb = 0;2218 dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0;2219 dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0;2220 dc->caps.color.mpc.ogam_rom_caps.pq = 0;2221 dc->caps.color.mpc.ogam_rom_caps.hlg = 0;2222 dc->caps.color.mpc.ocsc = 1;2223 2224 /* Use pipe context based otg sync logic */2225 dc->config.use_pipe_ctx_sync_logic = true;2226 2227 dc->config.dc_mode_clk_limit_support = true;2228 dc->config.enable_windowed_mpo_odm = true;2229 dc->config.disable_hbr_audio_dp2 = true;2230 /* read VBIOS LTTPR caps */2231 {2232 if (ctx->dc_bios->funcs->get_lttpr_caps) {2233 enum bp_result bp_query_result;2234 uint8_t is_vbios_lttpr_enable = 0;2235 2236 bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable);2237 dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable;2238 }2239 2240 /* interop bit is implicit */2241 {2242 dc->caps.vbios_lttpr_aware = true;2243 }2244 }2245 2246 if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)2247 dc->debug = debug_defaults_drv;2248 2249 // Init the vm_helper2250 if (dc->vm_helper)2251 vm_helper_init(dc->vm_helper, 16);2252 2253 /*************************************************2254 * Create resources *2255 *************************************************/2256 2257 /* Clock Sources for Pixel Clock*/2258 pool->base.clock_sources[DCN32_CLK_SRC_PLL0] =2259 dcn32_clock_source_create(ctx, ctx->dc_bios,2260 CLOCK_SOURCE_COMBO_PHY_PLL0,2261 &clk_src_regs[0], false);2262 pool->base.clock_sources[DCN32_CLK_SRC_PLL1] =2263 dcn32_clock_source_create(ctx, ctx->dc_bios,2264 CLOCK_SOURCE_COMBO_PHY_PLL1,2265 &clk_src_regs[1], false);2266 pool->base.clock_sources[DCN32_CLK_SRC_PLL2] =2267 dcn32_clock_source_create(ctx, ctx->dc_bios,2268 CLOCK_SOURCE_COMBO_PHY_PLL2,2269 &clk_src_regs[2], false);2270 pool->base.clock_sources[DCN32_CLK_SRC_PLL3] =2271 dcn32_clock_source_create(ctx, ctx->dc_bios,2272 CLOCK_SOURCE_COMBO_PHY_PLL3,2273 &clk_src_regs[3], false);2274 pool->base.clock_sources[DCN32_CLK_SRC_PLL4] =2275 dcn32_clock_source_create(ctx, ctx->dc_bios,2276 CLOCK_SOURCE_COMBO_PHY_PLL4,2277 &clk_src_regs[4], false);2278 2279 pool->base.clk_src_count = DCN32_CLK_SRC_TOTAL;2280 2281 /* todo: not reuse phy_pll registers */2282 pool->base.dp_clock_source =2283 dcn32_clock_source_create(ctx, ctx->dc_bios,2284 CLOCK_SOURCE_ID_DP_DTO,2285 &clk_src_regs[0], true);2286 2287 for (i = 0; i < pool->base.clk_src_count; i++) {2288 if (pool->base.clock_sources[i] == NULL) {2289 dm_error("DC: failed to create clock sources!\n");2290 BREAK_TO_DEBUGGER();2291 goto create_fail;2292 }2293 }2294 2295 /* DCCG */2296 pool->base.dccg = dccg32_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask);2297 if (pool->base.dccg == NULL) {2298 dm_error("DC: failed to create dccg!\n");2299 BREAK_TO_DEBUGGER();2300 goto create_fail;2301 }2302 2303 /* DML */2304 dml_init_instance(&dc->dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32);2305 2306 /* IRQ Service */2307 init_data.ctx = dc->ctx;2308 pool->base.irqs = dal_irq_service_dcn32_create(&init_data);2309 if (!pool->base.irqs)2310 goto create_fail;2311 2312 /* HUBBUB */2313 pool->base.hubbub = dcn32_hubbub_create(ctx);2314 if (pool->base.hubbub == NULL) {2315 BREAK_TO_DEBUGGER();2316 dm_error("DC: failed to create hubbub!\n");2317 goto create_fail;2318 }2319 2320 /* HUBPs, DPPs, OPPs, TGs, ABMs */2321 for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) {2322 2323 /* if pipe is disabled, skip instance of HW pipe,2324 * i.e, skip ASIC register instance2325 */2326 if (pipe_fuses & 1 << i)2327 continue;2328 2329 /* HUBPs */2330 pool->base.hubps[j] = dcn32_hubp_create(ctx, i);2331 if (pool->base.hubps[j] == NULL) {2332 BREAK_TO_DEBUGGER();2333 dm_error(2334 "DC: failed to create hubps!\n");2335 goto create_fail;2336 }2337 2338 /* DPPs */2339 pool->base.dpps[j] = dcn32_dpp_create(ctx, i);2340 if (pool->base.dpps[j] == NULL) {2341 BREAK_TO_DEBUGGER();2342 dm_error(2343 "DC: failed to create dpps!\n");2344 goto create_fail;2345 }2346 2347 /* OPPs */2348 pool->base.opps[j] = dcn32_opp_create(ctx, i);2349 if (pool->base.opps[j] == NULL) {2350 BREAK_TO_DEBUGGER();2351 dm_error(2352 "DC: failed to create output pixel processor!\n");2353 goto create_fail;2354 }2355 2356 /* TGs */2357 pool->base.timing_generators[j] = dcn32_timing_generator_create(2358 ctx, i);2359 if (pool->base.timing_generators[j] == NULL) {2360 BREAK_TO_DEBUGGER();2361 dm_error("DC: failed to create tg!\n");2362 goto create_fail;2363 }2364 2365 /* ABMs */2366 pool->base.multiple_abms[j] = dmub_abm_create(ctx,2367 &abm_regs[i],2368 &abm_shift,2369 &abm_mask);2370 if (pool->base.multiple_abms[j] == NULL) {2371 dm_error("DC: failed to create abm for pipe %d!\n", i);2372 BREAK_TO_DEBUGGER();2373 goto create_fail;2374 }2375 2376 /* index for resource pool arrays for next valid pipe */2377 j++;2378 }2379 2380 /* PSR */2381 pool->base.psr = dmub_psr_create(ctx);2382 if (pool->base.psr == NULL) {2383 dm_error("DC: failed to create psr obj!\n");2384 BREAK_TO_DEBUGGER();2385 goto create_fail;2386 }2387 2388 /* MPCCs */2389 pool->base.mpc = dcn32_mpc_create(ctx, pool->base.res_cap->num_timing_generator, pool->base.res_cap->num_mpc_3dlut);2390 if (pool->base.mpc == NULL) {2391 BREAK_TO_DEBUGGER();2392 dm_error("DC: failed to create mpc!\n");2393 goto create_fail;2394 }2395 2396 /* DSCs */2397 for (i = 0; i < pool->base.res_cap->num_dsc; i++) {2398 pool->base.dscs[i] = dcn32_dsc_create(ctx, i);2399 if (pool->base.dscs[i] == NULL) {2400 BREAK_TO_DEBUGGER();2401 dm_error("DC: failed to create display stream compressor %d!\n", i);2402 goto create_fail;2403 }2404 }2405 2406 /* DWB */2407 if (!dcn32_dwbc_create(ctx, &pool->base)) {2408 BREAK_TO_DEBUGGER();2409 dm_error("DC: failed to create dwbc!\n");2410 goto create_fail;2411 }2412 2413 /* MMHUBBUB */2414 if (!dcn32_mmhubbub_create(ctx, &pool->base)) {2415 BREAK_TO_DEBUGGER();2416 dm_error("DC: failed to create mcif_wb!\n");2417 goto create_fail;2418 }2419 2420 /* AUX and I2C */2421 for (i = 0; i < pool->base.res_cap->num_ddc; i++) {2422 pool->base.engines[i] = dcn32_aux_engine_create(ctx, i);2423 if (pool->base.engines[i] == NULL) {2424 BREAK_TO_DEBUGGER();2425 dm_error(2426 "DC:failed to create aux engine!!\n");2427 goto create_fail;2428 }2429 pool->base.hw_i2cs[i] = dcn32_i2c_hw_create(ctx, i);2430 if (pool->base.hw_i2cs[i] == NULL) {2431 BREAK_TO_DEBUGGER();2432 dm_error(2433 "DC:failed to create hw i2c!!\n");2434 goto create_fail;2435 }2436 pool->base.sw_i2cs[i] = NULL;2437 }2438 2439 /* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */2440 if (!resource_construct(num_virtual_links, dc, &pool->base,2441 &res_create_funcs))2442 goto create_fail;2443 2444 /* HW Sequencer init functions and Plane caps */2445 dcn32_hw_sequencer_init_functions(dc);2446 2447 dc->caps.max_planes = pool->base.pipe_count;2448 2449 for (i = 0; i < dc->caps.max_planes; ++i)2450 dc->caps.planes[i] = plane_cap;2451 2452 dc->cap_funcs = cap_funcs;2453 2454 if (dc->ctx->dc_bios->fw_info.oem_i2c_present) {2455 ddc_init_data.ctx = dc->ctx;2456 ddc_init_data.link = NULL;2457 ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;2458 ddc_init_data.id.enum_id = 0;2459 ddc_init_data.id.type = OBJECT_TYPE_GENERIC;2460 pool->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data);2461 } else {2462 pool->base.oem_device = NULL;2463 }2464 2465 dc->dml2_options.dcn_pipe_count = pool->base.pipe_count;2466 dc->dml2_options.use_native_pstate_optimization = false;2467 dc->dml2_options.use_native_soc_bb_construction = true;2468 dc->dml2_options.minimize_dispclk_using_odm = true;2469 2470 resource_init_common_dml2_callbacks(dc, &dc->dml2_options);2471 dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch;2472 dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc;2473 dc->dml2_options.svp_pstate.callbacks.calculate_mall_ways_from_bytes = pool->base.funcs->calculate_mall_ways_from_bytes;2474 2475 dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us;2476 dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us;2477 dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us;2478 dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines;2479 2480 dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp;2481 dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch;2482 2483 dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size;2484 dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways;2485 dc->dml2_options.mall_cfg.max_cab_allocation_bytes = dc->caps.max_cab_allocation_bytes;2486 dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE;2487 dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE;2488 dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES;2489 dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH;2490 2491 dc->dml2_options.max_segments_per_hubp = 18;2492 dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE;2493 dc->dml2_options.map_dc_pipes_with_callbacks = true;2494 2495 if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev) && (dc->config.sdpif_request_limit_words_per_umc == 0))2496 dc->config.sdpif_request_limit_words_per_umc = 16;2497 2498 DC_FP_END();2499 2500 return true;2501 2502create_fail:2503 2504 DC_FP_END();2505 2506 dcn32_resource_destruct(pool);2507 2508 return false;2509}2510 2511struct resource_pool *dcn32_create_resource_pool(2512 const struct dc_init_data *init_data,2513 struct dc *dc)2514{2515 struct dcn32_resource_pool *pool =2516 kzalloc(sizeof(struct dcn32_resource_pool), GFP_KERNEL);2517 2518 if (!pool)2519 return NULL;2520 2521 if (dcn32_resource_construct(init_data->num_virtual_links, dc, pool))2522 return &pool->base;2523 2524 BREAK_TO_DEBUGGER();2525 kfree(pool);2526 return NULL;2527}2528 2529/*2530 * Find the most optimal free pipe from res_ctx, which could be used as a2531 * secondary dpp pipe for input opp head pipe.2532 *2533 * a free pipe - a pipe in input res_ctx not yet used for any streams or2534 * planes.2535 * secondary dpp pipe - a pipe gets inserted to a head OPP pipe's MPC blending2536 * tree. This is typical used for rendering MPO planes or additional offset2537 * areas in MPCC combine.2538 *2539 * Hardware Transition Minimization Algorithm for Finding a Secondary DPP Pipe2540 * -------------------------------------------------------------------------2541 *2542 * PROBLEM:2543 *2544 * 1. There is a hardware limitation that a secondary DPP pipe cannot be2545 * transferred from one MPC blending tree to the other in a single frame.2546 * Otherwise it could cause glitches on the screen.2547 *2548 * For instance, we cannot transition from state 1 to state 2 in one frame. This2549 * is because PIPE1 is transferred from PIPE0's MPC blending tree over to2550 * PIPE2's MPC blending tree, which is not supported by hardware.2551 * To support this transition we need to first remove PIPE1 from PIPE0's MPC2552 * blending tree in one frame and then insert PIPE1 to PIPE2's MPC blending tree2553 * in the next frame. This is not optimal as it will delay the flip for two2554 * frames.2555 *2556 * State 1:2557 * PIPE0 -- secondary DPP pipe --> (PIPE1)2558 * PIPE2 -- secondary DPP pipe --> NONE2559 *2560 * State 2:2561 * PIPE0 -- secondary DPP pipe --> NONE2562 * PIPE2 -- secondary DPP pipe --> (PIPE1)2563 *2564 * 2. We want to in general minimize the unnecessary changes in pipe topology.2565 * If a pipe is already added in current blending tree and there are no changes2566 * to plane topology, we don't want to swap it with another free pipe2567 * unnecessarily in every update. Powering up and down a pipe would require a2568 * full update which delays the flip for 1 frame. If we use the original pipe2569 * we don't have to toggle its power. So we can flip faster.2570 */2571int dcn32_find_optimal_free_pipe_as_secondary_dpp_pipe(2572 const struct resource_context *cur_res_ctx,2573 struct resource_context *new_res_ctx,2574 const struct resource_pool *pool,2575 const struct pipe_ctx *new_opp_head)2576{2577 const struct pipe_ctx *cur_opp_head;2578 int free_pipe_idx;2579 2580 cur_opp_head = &cur_res_ctx->pipe_ctx[new_opp_head->pipe_idx];2581 free_pipe_idx = resource_find_free_pipe_used_in_cur_mpc_blending_tree(2582 cur_res_ctx, new_res_ctx, cur_opp_head);2583 2584 /* Up until here if we have not found a free secondary pipe, we will2585 * need to wait for at least one frame to complete the transition2586 * sequence.2587 */2588 if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)2589 free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx(2590 cur_res_ctx, new_res_ctx, pool);2591 2592 /* Up until here if we have not found a free secondary pipe, we will2593 * need to wait for at least two frames to complete the transition2594 * sequence. It really doesn't matter which pipe we decide take from2595 * current enabled pipes. It won't save our frame time when we swap only2596 * one pipe or more pipes.2597 */2598 if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)2599 free_pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(2600 cur_res_ctx, new_res_ctx, pool);2601 2602 if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)2603 free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool);2604 2605 return free_pipe_idx;2606}2607 2608static struct pipe_ctx *find_idle_secondary_pipe_check_mpo(2609 struct resource_context *res_ctx,2610 const struct resource_pool *pool,2611 const struct pipe_ctx *primary_pipe)2612{2613 int i;2614 struct pipe_ctx *secondary_pipe = NULL;2615 struct pipe_ctx *next_odm_mpo_pipe = NULL;2616 int primary_index, preferred_pipe_idx;2617 struct pipe_ctx *old_primary_pipe = NULL;2618 2619 /*2620 * Modified from find_idle_secondary_pipe2621 * With windowed MPO and ODM, we want to avoid the case where we want a2622 * free pipe for the left side but the free pipe is being used on the2623 * right side.2624 * Add check on current_state if the primary_pipe is the left side,2625 * to check the right side ( primary_pipe->next_odm_pipe ) to see if2626 * it is using a pipe for MPO ( primary_pipe->next_odm_pipe->bottom_pipe )2627 * - If so, then don't use this pipe2628 * EXCEPTION - 3 plane ( 2 MPO plane ) case2629 * - in this case, the primary pipe has already gotten a free pipe for the2630 * MPO window in the left2631 * - when it tries to get a free pipe for the MPO window on the right,2632 * it will see that it is already assigned to the right side2633 * ( primary_pipe->next_odm_pipe ). But in this case, we want this2634 * free pipe, since it will be for the right side. So add an2635 * additional condition, that skipping the free pipe on the right only2636 * applies if the primary pipe has no bottom pipe currently assigned2637 */2638 if (primary_pipe) {2639 primary_index = primary_pipe->pipe_idx;2640 old_primary_pipe = &primary_pipe->stream->ctx->dc->current_state->res_ctx.pipe_ctx[primary_index];2641 if ((old_primary_pipe->next_odm_pipe) && (old_primary_pipe->next_odm_pipe->bottom_pipe)2642 && (!primary_pipe->bottom_pipe))2643 next_odm_mpo_pipe = old_primary_pipe->next_odm_pipe->bottom_pipe;2644 2645 preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;2646 if ((res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) &&2647 !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == preferred_pipe_idx)) {2648 secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];2649 secondary_pipe->pipe_idx = preferred_pipe_idx;2650 }2651 }2652 2653 /*2654 * search backwards for the second pipe to keep pipe2655 * assignment more consistent2656 */2657 if (!secondary_pipe)2658 for (i = pool->pipe_count - 1; i >= 0; i--) {2659 if ((res_ctx->pipe_ctx[i].stream == NULL) &&2660 !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == i)) {2661 secondary_pipe = &res_ctx->pipe_ctx[i];2662 secondary_pipe->pipe_idx = i;2663 break;2664 }2665 }2666 2667 return secondary_pipe;2668}2669 2670static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(2671 struct dc_state *state,2672 const struct resource_pool *pool,2673 struct dc_stream_state *stream,2674 const struct pipe_ctx *head_pipe)2675{2676 struct resource_context *res_ctx = &state->res_ctx;2677 struct pipe_ctx *idle_pipe, *pipe;2678 struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx;2679 int head_index;2680 2681 if (!head_pipe) {2682 ASSERT(0);2683 return NULL;2684 }2685 2686 /*2687 * Modified from dcn20_acquire_idle_pipe_for_layer2688 * Check if head_pipe in old_context already has bottom_pipe allocated.2689 * - If so, check if that pipe is available in the current context.2690 * -- If so, reuse pipe from old_context2691 */2692 head_index = head_pipe->pipe_idx;2693 pipe = &old_ctx->pipe_ctx[head_index];2694 if (pipe->bottom_pipe && res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx].stream == NULL) {2695 idle_pipe = &res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx];2696 idle_pipe->pipe_idx = pipe->bottom_pipe->pipe_idx;2697 } else {2698 idle_pipe = find_idle_secondary_pipe_check_mpo(res_ctx, pool, head_pipe);2699 if (!idle_pipe)2700 return NULL;2701 }2702 2703 idle_pipe->stream = head_pipe->stream;2704 idle_pipe->stream_res.tg = head_pipe->stream_res.tg;2705 idle_pipe->stream_res.opp = head_pipe->stream_res.opp;2706 2707 idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx];2708 idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx];2709 idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx];2710 idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst;2711 2712 return idle_pipe;2713}2714 2715static int find_optimal_free_pipe_as_secondary_opp_head(2716 const struct resource_context *cur_res_ctx,2717 struct resource_context *new_res_ctx,2718 const struct resource_pool *pool,2719 const struct pipe_ctx *new_otg_master)2720{2721 const struct pipe_ctx *cur_otg_master;2722 int free_pipe_idx;2723 2724 cur_otg_master = &cur_res_ctx->pipe_ctx[new_otg_master->pipe_idx];2725 free_pipe_idx = resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(2726 cur_res_ctx, new_res_ctx, cur_otg_master);2727 2728 /* Up until here if we have not found a free secondary pipe, we will2729 * need to wait for at least one frame to complete the transition2730 * sequence.2731 */2732 if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)2733 free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx(2734 cur_res_ctx, new_res_ctx, pool);2735 2736 if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)2737 free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool);2738 2739 return free_pipe_idx;2740}2741 2742struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_dpp_pipe(2743 const struct dc_state *cur_ctx,2744 struct dc_state *new_ctx,2745 const struct resource_pool *pool,2746 const struct pipe_ctx *opp_head_pipe)2747{2748 2749 int free_pipe_idx;2750 struct pipe_ctx *free_pipe;2751 2752 if (!opp_head_pipe->stream->ctx->dc->config.enable_windowed_mpo_odm)2753 return dcn32_acquire_idle_pipe_for_head_pipe_in_layer(2754 new_ctx, pool, opp_head_pipe->stream, opp_head_pipe);2755 2756 free_pipe_idx = dcn32_find_optimal_free_pipe_as_secondary_dpp_pipe(2757 &cur_ctx->res_ctx, &new_ctx->res_ctx,2758 pool, opp_head_pipe);2759 if (free_pipe_idx >= 0) {2760 free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx];2761 free_pipe->pipe_idx = free_pipe_idx;2762 free_pipe->stream = opp_head_pipe->stream;2763 free_pipe->stream_res.tg = opp_head_pipe->stream_res.tg;2764 free_pipe->stream_res.opp = opp_head_pipe->stream_res.opp;2765 2766 free_pipe->plane_res.hubp = pool->hubps[free_pipe->pipe_idx];2767 free_pipe->plane_res.ipp = pool->ipps[free_pipe->pipe_idx];2768 free_pipe->plane_res.dpp = pool->dpps[free_pipe->pipe_idx];2769 free_pipe->plane_res.mpcc_inst =2770 pool->dpps[free_pipe->pipe_idx]->inst;2771 } else {2772 ASSERT(opp_head_pipe);2773 free_pipe = NULL;2774 }2775 2776 return free_pipe;2777}2778 2779struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head(2780 const struct dc_state *cur_ctx,2781 struct dc_state *new_ctx,2782 const struct resource_pool *pool,2783 const struct pipe_ctx *otg_master)2784{2785 int free_pipe_idx = find_optimal_free_pipe_as_secondary_opp_head(2786 &cur_ctx->res_ctx, &new_ctx->res_ctx,2787 pool, otg_master);2788 struct pipe_ctx *free_pipe;2789 2790 if (free_pipe_idx >= 0) {2791 free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx];2792 free_pipe->pipe_idx = free_pipe_idx;2793 free_pipe->stream = otg_master->stream;2794 free_pipe->stream_res.tg = otg_master->stream_res.tg;2795 free_pipe->stream_res.dsc = NULL;2796 free_pipe->stream_res.opp = pool->opps[free_pipe_idx];2797 free_pipe->plane_res.mi = pool->mis[free_pipe_idx];2798 free_pipe->plane_res.hubp = pool->hubps[free_pipe_idx];2799 free_pipe->plane_res.ipp = pool->ipps[free_pipe_idx];2800 free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx];2801 free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx];2802 free_pipe->plane_res.mpcc_inst = pool->dpps[free_pipe_idx]->inst;2803 if (free_pipe->stream->timing.flags.DSC == 1) {2804 dcn20_acquire_dsc(free_pipe->stream->ctx->dc,2805 &new_ctx->res_ctx,2806 &free_pipe->stream_res.dsc,2807 free_pipe_idx);2808 ASSERT(free_pipe->stream_res.dsc);2809 if (free_pipe->stream_res.dsc == NULL) {2810 memset(free_pipe, 0, sizeof(*free_pipe));2811 free_pipe = NULL;2812 }2813 }2814 } else {2815 ASSERT(otg_master);2816 free_pipe = NULL;2817 }2818 2819 return free_pipe;2820}2821 2822unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans)2823{2824 /*2825 * DCN32 and DCN321 SKUs may have different sizes for MALL2826 * but we may not be able to access all the MALL space.2827 * If the num_chans is power of 2, then we can access all2828 * of the available MALL space. Otherwise, we can only2829 * access:2830 *2831 * max_cab_size_in_bytes = total_cache_size_in_bytes *2832 * ((2^floor(log2(num_chans)))/num_chans)2833 *2834 * Calculating the MALL sizes for all available SKUs, we2835 * have come up with the follow simplified check.2836 * - we have max_chans which provides the max MALL size.2837 * Each chans supports 4MB of MALL so:2838 *2839 * total_cache_size_in_bytes = max_chans * 4 MB2840 *2841 * - we have avail_chans which shows the number of channels2842 * we can use if we can't access the entire MALL space.2843 * It is generally half of max_chans2844 * - so we use the following checks:2845 *2846 * if (num_chans == max_chans), return max_chans2847 * if (num_chans < max_chans), return avail_chans2848 *2849 * - exception is GC_11_0_0 where we can't access max_chans,2850 * so we define max_avail_chans as the maximum available2851 * MALL space2852 *2853 */2854 int gc_11_0_0_max_chans = 48;2855 int gc_11_0_0_max_avail_chans = 32;2856 int gc_11_0_0_avail_chans = 16;2857 int gc_11_0_3_max_chans = 16;2858 int gc_11_0_3_avail_chans = 8;2859 int gc_11_0_2_max_chans = 8;2860 int gc_11_0_2_avail_chans = 4;2861 2862 if (ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev)) {2863 return (num_chans == gc_11_0_0_max_chans) ?2864 gc_11_0_0_max_avail_chans : gc_11_0_0_avail_chans;2865 } else if (ASICREV_IS_GC_11_0_2(dc->ctx->asic_id.hw_internal_rev)) {2866 return (num_chans == gc_11_0_2_max_chans) ?2867 gc_11_0_2_max_chans : gc_11_0_2_avail_chans;2868 } else { // if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev)) {2869 return (num_chans == gc_11_0_3_max_chans) ?2870 gc_11_0_3_max_chans : gc_11_0_3_avail_chans;2871 }2872}2873