Home | History | Annotate | Line # | Download | only in dcn21
      1 /*	$NetBSD: amdgpu_dcn21_hubbub.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $	*/
      2 
      3 /*
      4 * Copyright 2018 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn21_hubbub.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $");
     29 
     30 #include <linux/delay.h>
     31 #include "dm_services.h"
     32 #include "dcn20/dcn20_hubbub.h"
     33 #include "dcn21_hubbub.h"
     34 #include "reg_helper.h"
     35 
     36 #define REG(reg)\
     37 	hubbub1->regs->reg
     38 #define DC_LOGGER \
     39 	hubbub1->base.ctx->logger
     40 #define CTX \
     41 	hubbub1->base.ctx
     42 
     43 #undef FN
     44 #define FN(reg_name, field_name) \
     45 	hubbub1->shifts->field_name, hubbub1->masks->field_name
     46 
     47 #define REG(reg)\
     48 	hubbub1->regs->reg
     49 
     50 #define CTX \
     51 	hubbub1->base.ctx
     52 
     53 #undef FN
     54 #define FN(reg_name, field_name) \
     55 	hubbub1->shifts->field_name, hubbub1->masks->field_name
     56 
     57 #ifdef NUM_VMID
     58 #undef NUM_VMID
     59 #endif
     60 #define NUM_VMID 16
     61 
     62 static uint32_t convert_and_clamp(
     63 	uint32_t wm_ns,
     64 	uint32_t refclk_mhz,
     65 	uint32_t clamp_value)
     66 {
     67 	uint32_t ret_val = 0;
     68 	ret_val = wm_ns * refclk_mhz;
     69 	ret_val /= 1000;
     70 
     71 	if (ret_val > clamp_value)
     72 		ret_val = clamp_value;
     73 
     74 	return ret_val;
     75 }
     76 
     77 void dcn21_dchvm_init(struct hubbub *hubbub)
     78 {
     79 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
     80 	uint32_t riommu_active;
     81 	int i;
     82 
     83 	//Init DCHVM block
     84 	REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
     85 
     86 	//Poll until RIOMMU_ACTIVE = 1
     87 	for (i = 0; i < 100; i++) {
     88 		REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active);
     89 
     90 		if (riommu_active)
     91 			break;
     92 		else
     93 			udelay(5);
     94 	}
     95 
     96 	if (riommu_active) {
     97 		//Reflect the power status of DCHUBBUB
     98 		REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
     99 
    100 		//Start rIOMMU prefetching
    101 		REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
    102 
    103 		// Enable dynamic clock gating
    104 		REG_UPDATE_4(DCHVM_CLK_CTRL,
    105 						HVM_DISPCLK_R_GATE_DIS, 0,
    106 						HVM_DISPCLK_G_GATE_DIS, 0,
    107 						HVM_DCFCLK_R_GATE_DIS, 0,
    108 						HVM_DCFCLK_G_GATE_DIS, 0);
    109 
    110 		//Poll until HOSTVM_PREFETCH_DONE = 1
    111 		REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
    112 	}
    113 }
    114 
    115 int hubbub21_init_dchub(struct hubbub *hubbub,
    116 		struct dcn_hubbub_phys_addr_config *pa_config)
    117 {
    118 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    119 	struct dcn_vmid_page_table_config phys_config;
    120 
    121 	REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
    122 			FB_BASE, pa_config->system_aperture.fb_base >> 24);
    123 	REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
    124 			FB_TOP, pa_config->system_aperture.fb_top >> 24);
    125 	REG_SET(DCN_VM_FB_OFFSET, 0,
    126 			FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
    127 	REG_SET(DCN_VM_AGP_BOT, 0,
    128 			AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
    129 	REG_SET(DCN_VM_AGP_TOP, 0,
    130 			AGP_TOP, pa_config->system_aperture.agp_top >> 24);
    131 	REG_SET(DCN_VM_AGP_BASE, 0,
    132 			AGP_BASE, pa_config->system_aperture.agp_base >> 24);
    133 
    134 	if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
    135 		phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
    136 		phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
    137 		phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr | 1; //Note: hack
    138 		phys_config.depth = 0;
    139 		phys_config.block_size = 0;
    140 		// Init VMID 0 based on PA config
    141 		dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
    142 	}
    143 
    144 	dcn21_dchvm_init(hubbub);
    145 
    146 	return NUM_VMID;
    147 }
    148 
    149 void hubbub21_program_urgent_watermarks(
    150 		struct hubbub *hubbub,
    151 		struct dcn_watermark_set *watermarks,
    152 		unsigned int refclk_mhz,
    153 		bool safe_to_lower)
    154 {
    155 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    156 	uint32_t prog_wm_value;
    157 
    158 	/* Repeat for water mark set A, B, C and D. */
    159 	/* clock state A */
    160 	if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
    161 		hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
    162 		prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
    163 				refclk_mhz, 0x1fffff);
    164 		REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
    165 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value,
    166 				DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value);
    167 
    168 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
    169 			"HW register value = 0x%x\n",
    170 			watermarks->a.urgent_ns, prog_wm_value);
    171 	}
    172 
    173 	/* determine the transfer time for a quantity of data for a particular requestor.*/
    174 	if (safe_to_lower || watermarks->a.frac_urg_bw_flip
    175 			> hubbub1->watermarks.a.frac_urg_bw_flip) {
    176 		hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
    177 
    178 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
    179 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
    180 	}
    181 
    182 	if (safe_to_lower || watermarks->a.frac_urg_bw_nom
    183 			> hubbub1->watermarks.a.frac_urg_bw_nom) {
    184 		hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
    185 
    186 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
    187 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
    188 	}
    189 	if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub1->watermarks.a.urgent_latency_ns) {
    190 		hubbub1->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
    191 		prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
    192 				refclk_mhz, 0x1fffff);
    193 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
    194 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
    195 	}
    196 
    197 	/* clock state B */
    198 	if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
    199 		hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
    200 		prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
    201 				refclk_mhz, 0x1fffff);
    202 		REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
    203 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value,
    204 				DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, prog_wm_value);
    205 
    206 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
    207 			"HW register value = 0x%x\n",
    208 			watermarks->b.urgent_ns, prog_wm_value);
    209 	}
    210 
    211 	/* determine the transfer time for a quantity of data for a particular requestor.*/
    212 	if (safe_to_lower || watermarks->a.frac_urg_bw_flip
    213 			> hubbub1->watermarks.a.frac_urg_bw_flip) {
    214 		hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
    215 
    216 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
    217 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->a.frac_urg_bw_flip);
    218 	}
    219 
    220 	if (safe_to_lower || watermarks->a.frac_urg_bw_nom
    221 			> hubbub1->watermarks.a.frac_urg_bw_nom) {
    222 		hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
    223 
    224 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
    225 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->a.frac_urg_bw_nom);
    226 	}
    227 
    228 	if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub1->watermarks.b.urgent_latency_ns) {
    229 		hubbub1->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
    230 		prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
    231 				refclk_mhz, 0x1fffff);
    232 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
    233 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
    234 	}
    235 
    236 	/* clock state C */
    237 	if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
    238 		hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
    239 		prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
    240 				refclk_mhz, 0x1fffff);
    241 		REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
    242 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value,
    243 				DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, prog_wm_value);
    244 
    245 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
    246 			"HW register value = 0x%x\n",
    247 			watermarks->c.urgent_ns, prog_wm_value);
    248 	}
    249 
    250 	/* determine the transfer time for a quantity of data for a particular requestor.*/
    251 	if (safe_to_lower || watermarks->a.frac_urg_bw_flip
    252 			> hubbub1->watermarks.a.frac_urg_bw_flip) {
    253 		hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
    254 
    255 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
    256 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->a.frac_urg_bw_flip);
    257 	}
    258 
    259 	if (safe_to_lower || watermarks->a.frac_urg_bw_nom
    260 			> hubbub1->watermarks.a.frac_urg_bw_nom) {
    261 		hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
    262 
    263 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
    264 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->a.frac_urg_bw_nom);
    265 	}
    266 
    267 	if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub1->watermarks.c.urgent_latency_ns) {
    268 		hubbub1->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
    269 		prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
    270 				refclk_mhz, 0x1fffff);
    271 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
    272 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
    273 	}
    274 
    275 	/* clock state D */
    276 	if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
    277 		hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
    278 		prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
    279 				refclk_mhz, 0x1fffff);
    280 		REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
    281 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value,
    282 				DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, prog_wm_value);
    283 
    284 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
    285 			"HW register value = 0x%x\n",
    286 			watermarks->d.urgent_ns, prog_wm_value);
    287 	}
    288 
    289 	/* determine the transfer time for a quantity of data for a particular requestor.*/
    290 	if (safe_to_lower || watermarks->a.frac_urg_bw_flip
    291 			> hubbub1->watermarks.a.frac_urg_bw_flip) {
    292 		hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
    293 
    294 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
    295 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->a.frac_urg_bw_flip);
    296 	}
    297 
    298 	if (safe_to_lower || watermarks->a.frac_urg_bw_nom
    299 			> hubbub1->watermarks.a.frac_urg_bw_nom) {
    300 		hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
    301 
    302 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
    303 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->a.frac_urg_bw_nom);
    304 	}
    305 
    306 	if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub1->watermarks.d.urgent_latency_ns) {
    307 		hubbub1->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
    308 		prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
    309 				refclk_mhz, 0x1fffff);
    310 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
    311 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
    312 	}
    313 }
    314 
    315 void hubbub21_program_stutter_watermarks(
    316 		struct hubbub *hubbub,
    317 		struct dcn_watermark_set *watermarks,
    318 		unsigned int refclk_mhz,
    319 		bool safe_to_lower)
    320 {
    321 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    322 	uint32_t prog_wm_value;
    323 
    324 	/* clock state A */
    325 	if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
    326 			> hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
    327 		hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
    328 				watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
    329 		prog_wm_value = convert_and_clamp(
    330 				watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
    331 				refclk_mhz, 0x1fffff);
    332 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
    333 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value,
    334 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
    335 		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
    336 			"HW register value = 0x%x\n",
    337 			watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
    338 	}
    339 
    340 	if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
    341 			> hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
    342 		hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
    343 				watermarks->a.cstate_pstate.cstate_exit_ns;
    344 		prog_wm_value = convert_and_clamp(
    345 				watermarks->a.cstate_pstate.cstate_exit_ns,
    346 				refclk_mhz, 0x1fffff);
    347 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
    348 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value,
    349 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
    350 		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
    351 			"HW register value = 0x%x\n",
    352 			watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
    353 	}
    354 
    355 	/* clock state B */
    356 	if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
    357 			> hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
    358 		hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
    359 				watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
    360 		prog_wm_value = convert_and_clamp(
    361 				watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
    362 				refclk_mhz, 0x1fffff);
    363 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
    364 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value,
    365 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
    366 		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
    367 			"HW register value = 0x%x\n",
    368 			watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
    369 	}
    370 
    371 	if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
    372 			> hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
    373 		hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
    374 				watermarks->b.cstate_pstate.cstate_exit_ns;
    375 		prog_wm_value = convert_and_clamp(
    376 				watermarks->b.cstate_pstate.cstate_exit_ns,
    377 				refclk_mhz, 0x1fffff);
    378 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
    379 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value,
    380 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
    381 		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
    382 			"HW register value = 0x%x\n",
    383 			watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
    384 	}
    385 
    386 	/* clock state C */
    387 	if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
    388 			> hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
    389 		hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
    390 				watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
    391 		prog_wm_value = convert_and_clamp(
    392 				watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
    393 				refclk_mhz, 0x1fffff);
    394 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
    395 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value,
    396 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
    397 		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
    398 			"HW register value = 0x%x\n",
    399 			watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
    400 	}
    401 
    402 	if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
    403 			> hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
    404 		hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
    405 				watermarks->c.cstate_pstate.cstate_exit_ns;
    406 		prog_wm_value = convert_and_clamp(
    407 				watermarks->c.cstate_pstate.cstate_exit_ns,
    408 				refclk_mhz, 0x1fffff);
    409 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
    410 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value,
    411 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
    412 		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
    413 			"HW register value = 0x%x\n",
    414 			watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
    415 	}
    416 
    417 	/* clock state D */
    418 	if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
    419 			> hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
    420 		hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
    421 				watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
    422 		prog_wm_value = convert_and_clamp(
    423 				watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
    424 				refclk_mhz, 0x1fffff);
    425 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
    426 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value,
    427 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
    428 		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
    429 			"HW register value = 0x%x\n",
    430 			watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
    431 	}
    432 
    433 	if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
    434 			> hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
    435 		hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
    436 				watermarks->d.cstate_pstate.cstate_exit_ns;
    437 		prog_wm_value = convert_and_clamp(
    438 				watermarks->d.cstate_pstate.cstate_exit_ns,
    439 				refclk_mhz, 0x1fffff);
    440 		REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
    441 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value,
    442 				DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
    443 		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
    444 			"HW register value = 0x%x\n",
    445 			watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
    446 	}
    447 }
    448 
    449 void hubbub21_program_pstate_watermarks(
    450 		struct hubbub *hubbub,
    451 		struct dcn_watermark_set *watermarks,
    452 		unsigned int refclk_mhz,
    453 		bool safe_to_lower)
    454 {
    455 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    456 	uint32_t prog_wm_value;
    457 
    458 	/* clock state A */
    459 	if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
    460 			> hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
    461 		hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
    462 				watermarks->a.cstate_pstate.pstate_change_ns;
    463 		prog_wm_value = convert_and_clamp(
    464 				watermarks->a.cstate_pstate.pstate_change_ns,
    465 				refclk_mhz, 0x1fffff);
    466 		REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
    467 				DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value,
    468 				DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
    469 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
    470 			"HW register value = 0x%x\n\n",
    471 			watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
    472 	}
    473 
    474 	/* clock state B */
    475 	if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
    476 			> hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
    477 		hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
    478 				watermarks->b.cstate_pstate.pstate_change_ns;
    479 		prog_wm_value = convert_and_clamp(
    480 				watermarks->b.cstate_pstate.pstate_change_ns,
    481 				refclk_mhz, 0x1fffff);
    482 		REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
    483 				DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value,
    484 				DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
    485 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
    486 			"HW register value = 0x%x\n\n",
    487 			watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
    488 	}
    489 
    490 	/* clock state C */
    491 	if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
    492 			> hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
    493 		hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
    494 				watermarks->c.cstate_pstate.pstate_change_ns;
    495 		prog_wm_value = convert_and_clamp(
    496 				watermarks->c.cstate_pstate.pstate_change_ns,
    497 				refclk_mhz, 0x1fffff);
    498 		REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
    499 				DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value,
    500 				DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
    501 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
    502 			"HW register value = 0x%x\n\n",
    503 			watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
    504 	}
    505 
    506 	/* clock state D */
    507 	if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
    508 			> hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
    509 		hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
    510 				watermarks->d.cstate_pstate.pstate_change_ns;
    511 		prog_wm_value = convert_and_clamp(
    512 				watermarks->d.cstate_pstate.pstate_change_ns,
    513 				refclk_mhz, 0x1fffff);
    514 		REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
    515 				DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value,
    516 				DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
    517 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
    518 			"HW register value = 0x%x\n\n",
    519 			watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
    520 	}
    521 }
    522 
    523 void hubbub21_program_watermarks(
    524 		struct hubbub *hubbub,
    525 		struct dcn_watermark_set *watermarks,
    526 		unsigned int refclk_mhz,
    527 		bool safe_to_lower)
    528 {
    529 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    530 
    531 	hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
    532 	hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
    533 	hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
    534 
    535 	/*
    536 	 * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
    537 	 * If the memory controller is fully utilized and the DCHub requestors are
    538 	 * well ahead of their amortized schedule, then it is safe to prevent the next winner
    539 	 * from being committed and sent to the fabric.
    540 	 * The utilization of the memory controller is approximated by ensuring that
    541 	 * the number of outstanding requests is greater than a threshold specified
    542 	 * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
    543 	 * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
    544 	 *
    545 	 * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF)
    546 	 * to turn off it for now.
    547 	 */
    548 	REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
    549 			DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
    550 	REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
    551 			DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF,
    552 			DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA);
    553 	REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL,
    554 			DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF);
    555 
    556 	hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
    557 }
    558 
    559 void hubbub21_wm_read_state(struct hubbub *hubbub,
    560 		struct dcn_hubbub_wm *wm)
    561 {
    562 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    563 	struct dcn_hubbub_wm_set *s;
    564 
    565 	memset(wm, 0, sizeof(struct dcn_hubbub_wm));
    566 
    567 	s = &wm->sets[0];
    568 	s->wm_set = 0;
    569 	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A,
    570 			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent);
    571 
    572 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A,
    573 			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter);
    574 
    575 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A,
    576 			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit);
    577 
    578 	REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A,
    579 			 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, &s->dram_clk_chanage);
    580 
    581 	s = &wm->sets[1];
    582 	s->wm_set = 1;
    583 	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B,
    584 			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent);
    585 
    586 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B,
    587 			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter);
    588 
    589 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B,
    590 			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit);
    591 
    592 	REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B,
    593 			DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, &s->dram_clk_chanage);
    594 
    595 	s = &wm->sets[2];
    596 	s->wm_set = 2;
    597 	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C,
    598 			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent);
    599 
    600 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C,
    601 			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter);
    602 
    603 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C,
    604 			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit);
    605 
    606 	REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C,
    607 			DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, &s->dram_clk_chanage);
    608 
    609 	s = &wm->sets[3];
    610 	s->wm_set = 3;
    611 	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D,
    612 			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent);
    613 
    614 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D,
    615 			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter);
    616 
    617 	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D,
    618 			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit);
    619 
    620 	REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D,
    621 			DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, &s->dram_clk_chanage);
    622 }
    623 
    624 void hubbub21_apply_DEDCN21_147_wa(struct hubbub *hubbub)
    625 {
    626 	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    627 	uint32_t prog_wm_value;
    628 
    629 	prog_wm_value = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
    630 	REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
    631 }
    632 
    633 static const struct hubbub_funcs hubbub21_funcs = {
    634 	.update_dchub = hubbub2_update_dchub,
    635 	.init_dchub_sys_ctx = hubbub21_init_dchub,
    636 	.init_vm_ctx = hubbub2_init_vm_ctx,
    637 	.dcc_support_swizzle = hubbub2_dcc_support_swizzle,
    638 	.dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
    639 	.get_dcc_compression_cap = hubbub2_get_dcc_compression_cap,
    640 	.wm_read_state = hubbub21_wm_read_state,
    641 	.get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
    642 	.program_watermarks = hubbub21_program_watermarks,
    643 	.apply_DEDCN21_147_wa = hubbub21_apply_DEDCN21_147_wa,
    644 };
    645 
    646 void hubbub21_construct(struct dcn20_hubbub *hubbub,
    647 	struct dc_context *ctx,
    648 	const struct dcn_hubbub_registers *hubbub_regs,
    649 	const struct dcn_hubbub_shift *hubbub_shift,
    650 	const struct dcn_hubbub_mask *hubbub_mask)
    651 {
    652 	hubbub->base.ctx = ctx;
    653 
    654 	hubbub->base.funcs = &hubbub21_funcs;
    655 
    656 	hubbub->regs = hubbub_regs;
    657 	hubbub->shifts = hubbub_shift;
    658 	hubbub->masks = hubbub_mask;
    659 
    660 	hubbub->debug_test_index_pstate = 0xB;
    661 	hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */
    662 }
    663