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