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