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