1 /* 2 * Copyright 2016 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 26 #include "dm_services.h" 27 #include "dcn10_hubp.h" 28 #include "dcn10_hubbub.h" 29 #include "reg_helper.h" 30 31 #define CTX \ 32 hubbub1->base.ctx 33 #define DC_LOGGER \ 34 hubbub1->base.ctx->logger 35 #define REG(reg)\ 36 hubbub1->regs->reg 37 38 #undef FN 39 #define FN(reg_name, field_name) \ 40 hubbub1->shifts->field_name, hubbub1->masks->field_name 41 42 void hubbub1_wm_read_state(struct hubbub *hubbub, 43 struct dcn_hubbub_wm *wm) 44 { 45 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 46 struct dcn_hubbub_wm_set *s; 47 48 memset(wm, 0, sizeof(struct dcn_hubbub_wm)); 49 50 s = &wm->sets[0]; 51 s->wm_set = 0; 52 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); 53 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A); 54 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { 55 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); 56 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); 57 } 58 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A); 59 60 s = &wm->sets[1]; 61 s->wm_set = 1; 62 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B); 63 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B); 64 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { 65 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B); 66 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B); 67 } 68 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B); 69 70 s = &wm->sets[2]; 71 s->wm_set = 2; 72 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C); 73 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C); 74 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { 75 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C); 76 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C); 77 } 78 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C); 79 80 s = &wm->sets[3]; 81 s->wm_set = 3; 82 s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D); 83 s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D); 84 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { 85 s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D); 86 s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D); 87 } 88 s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); 89 } 90 91 void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow) 92 { 93 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 94 95 /* 96 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter 97 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter 98 */ 99 100 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, 101 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, 102 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); 103 } 104 105 bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) 106 { 107 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 108 uint32_t enable = 0; 109 110 REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL, 111 DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable); 112 113 return enable ? true : false; 114 } 115 116 117 bool hubbub1_verify_allow_pstate_change_high( 118 struct hubbub *hubbub) 119 { 120 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 121 122 /* pstate latency is ~20us so if we wait over 40us and pstate allow 123 * still not asserted, we are probably stuck and going to hang 124 * 125 * TODO: Figure out why it takes ~100us on linux 126 * pstate takes around ~100us on linux. Unknown currently as to 127 * why it takes that long on linux 128 */ 129 static unsigned int pstate_wait_timeout_us = 200; 130 static unsigned int pstate_wait_expected_timeout_us = 40; 131 static unsigned int max_sampled_pstate_wait_us; /* data collection */ 132 static bool forced_pstate_allow; /* help with revert wa */ 133 134 unsigned int debug_data; 135 unsigned int i; 136 137 if (forced_pstate_allow) { 138 /* we hacked to force pstate allow to prevent hang last time 139 * we verify_allow_pstate_change_high. so disable force 140 * here so we can check status 141 */ 142 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, 143 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0, 144 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0); 145 forced_pstate_allow = false; 146 } 147 148 /* RV2: 149 * dchubbubdebugind, at: 0xB 150 * description 151 * 0: Pipe0 Plane0 Allow Pstate Change 152 * 1: Pipe0 Plane1 Allow Pstate Change 153 * 2: Pipe0 Cursor0 Allow Pstate Change 154 * 3: Pipe0 Cursor1 Allow Pstate Change 155 * 4: Pipe1 Plane0 Allow Pstate Change 156 * 5: Pipe1 Plane1 Allow Pstate Change 157 * 6: Pipe1 Cursor0 Allow Pstate Change 158 * 7: Pipe1 Cursor1 Allow Pstate Change 159 * 8: Pipe2 Plane0 Allow Pstate Change 160 * 9: Pipe2 Plane1 Allow Pstate Change 161 * 10: Pipe2 Cursor0 Allow Pstate Change 162 * 11: Pipe2 Cursor1 Allow Pstate Change 163 * 12: Pipe3 Plane0 Allow Pstate Change 164 * 13: Pipe3 Plane1 Allow Pstate Change 165 * 14: Pipe3 Cursor0 Allow Pstate Change 166 * 15: Pipe3 Cursor1 Allow Pstate Change 167 * 16: Pipe4 Plane0 Allow Pstate Change 168 * 17: Pipe4 Plane1 Allow Pstate Change 169 * 18: Pipe4 Cursor0 Allow Pstate Change 170 * 19: Pipe4 Cursor1 Allow Pstate Change 171 * 20: Pipe5 Plane0 Allow Pstate Change 172 * 21: Pipe5 Plane1 Allow Pstate Change 173 * 22: Pipe5 Cursor0 Allow Pstate Change 174 * 23: Pipe5 Cursor1 Allow Pstate Change 175 * 24: Pipe6 Plane0 Allow Pstate Change 176 * 25: Pipe6 Plane1 Allow Pstate Change 177 * 26: Pipe6 Cursor0 Allow Pstate Change 178 * 27: Pipe6 Cursor1 Allow Pstate Change 179 * 28: WB0 Allow Pstate Change 180 * 29: WB1 Allow Pstate Change 181 * 30: Arbiter's allow_pstate_change 182 * 31: SOC pstate change request" 183 * 184 * RV1: 185 * dchubbubdebugind, at: 0x7 186 * description "3-0: Pipe0 cursor0 QOS 187 * 7-4: Pipe1 cursor0 QOS 188 * 11-8: Pipe2 cursor0 QOS 189 * 15-12: Pipe3 cursor0 QOS 190 * 16: Pipe0 Plane0 Allow Pstate Change 191 * 17: Pipe1 Plane0 Allow Pstate Change 192 * 18: Pipe2 Plane0 Allow Pstate Change 193 * 19: Pipe3 Plane0 Allow Pstate Change 194 * 20: Pipe0 Plane1 Allow Pstate Change 195 * 21: Pipe1 Plane1 Allow Pstate Change 196 * 22: Pipe2 Plane1 Allow Pstate Change 197 * 23: Pipe3 Plane1 Allow Pstate Change 198 * 24: Pipe0 cursor0 Allow Pstate Change 199 * 25: Pipe1 cursor0 Allow Pstate Change 200 * 26: Pipe2 cursor0 Allow Pstate Change 201 * 27: Pipe3 cursor0 Allow Pstate Change 202 * 28: WB0 Allow Pstate Change 203 * 29: WB1 Allow Pstate Change 204 * 30: Arbiter's allow_pstate_change 205 * 31: SOC pstate change request 206 */ 207 208 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub1->debug_test_index_pstate); 209 210 for (i = 0; i < pstate_wait_timeout_us; i++) { 211 debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); 212 213 if (debug_data & (1 << 30)) { 214 215 if (i > pstate_wait_expected_timeout_us) 216 DC_LOG_WARNING("pstate took longer than expected ~%dus\n", 217 i); 218 219 return true; 220 } 221 if (max_sampled_pstate_wait_us < i) 222 max_sampled_pstate_wait_us = i; 223 224 udelay(1); 225 } 226 227 /* force pstate allow to prevent system hang 228 * and break to debugger to investigate 229 */ 230 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, 231 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1, 232 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); 233 forced_pstate_allow = true; 234 235 DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n", 236 debug_data); 237 238 return false; 239 } 240 241 static uint32_t convert_and_clamp( 242 uint32_t wm_ns, 243 uint32_t refclk_mhz, 244 uint32_t clamp_value) 245 { 246 uint32_t ret_val = 0; 247 ret_val = wm_ns * refclk_mhz; 248 ret_val /= 1000; 249 250 if (ret_val > clamp_value) 251 ret_val = clamp_value; 252 253 return ret_val; 254 } 255 256 257 void hubbub1_wm_change_req_wa(struct hubbub *hubbub) 258 { 259 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 260 261 REG_UPDATE_SEQ_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, 262 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 263 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); 264 } 265 266 void hubbub1_program_watermarks( 267 struct hubbub *hubbub, 268 struct dcn_watermark_set *watermarks, 269 unsigned int refclk_mhz, 270 bool safe_to_lower) 271 { 272 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 273 /* 274 * Need to clamp to max of the register values (i.e. no wrap) 275 * for dcn1, all wm registers are 21-bit wide 276 */ 277 uint32_t prog_wm_value; 278 279 280 /* Repeat for water mark set A, B, C and D. */ 281 /* clock state A */ 282 if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) { 283 hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns; 284 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, 285 refclk_mhz, 0x1fffff); 286 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, 287 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); 288 289 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" 290 "HW register value = 0x%x\n", 291 watermarks->a.urgent_ns, prog_wm_value); 292 } 293 294 if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) { 295 if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) { 296 hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; 297 prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, 298 refclk_mhz, 0x1fffff); 299 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); 300 DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" 301 "HW register value = 0x%x\n", 302 watermarks->a.pte_meta_urgent_ns, prog_wm_value); 303 } 304 } 305 306 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { 307 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns 308 > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { 309 hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = 310 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; 311 prog_wm_value = convert_and_clamp( 312 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, 313 refclk_mhz, 0x1fffff); 314 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, 315 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); 316 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" 317 "HW register value = 0x%x\n", 318 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 319 } 320 321 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns 322 > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) { 323 hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns = 324 watermarks->a.cstate_pstate.cstate_exit_ns; 325 prog_wm_value = convert_and_clamp( 326 watermarks->a.cstate_pstate.cstate_exit_ns, 327 refclk_mhz, 0x1fffff); 328 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, 329 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); 330 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" 331 "HW register value = 0x%x\n", 332 watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); 333 } 334 } 335 336 if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns 337 > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) { 338 hubbub1->watermarks.a.cstate_pstate.pstate_change_ns = 339 watermarks->a.cstate_pstate.pstate_change_ns; 340 prog_wm_value = convert_and_clamp( 341 watermarks->a.cstate_pstate.pstate_change_ns, 342 refclk_mhz, 0x1fffff); 343 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, 344 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); 345 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" 346 "HW register value = 0x%x\n\n", 347 watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); 348 } 349 350 /* clock state B */ 351 if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) { 352 hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns; 353 prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, 354 refclk_mhz, 0x1fffff); 355 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, 356 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); 357 358 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" 359 "HW register value = 0x%x\n", 360 watermarks->b.urgent_ns, prog_wm_value); 361 } 362 363 if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) { 364 if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) { 365 hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; 366 prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, 367 refclk_mhz, 0x1fffff); 368 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); 369 DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" 370 "HW register value = 0x%x\n", 371 watermarks->b.pte_meta_urgent_ns, prog_wm_value); 372 } 373 } 374 375 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { 376 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns 377 > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { 378 hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = 379 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; 380 prog_wm_value = convert_and_clamp( 381 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, 382 refclk_mhz, 0x1fffff); 383 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, 384 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); 385 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" 386 "HW register value = 0x%x\n", 387 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 388 } 389 390 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns 391 > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) { 392 hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns = 393 watermarks->b.cstate_pstate.cstate_exit_ns; 394 prog_wm_value = convert_and_clamp( 395 watermarks->b.cstate_pstate.cstate_exit_ns, 396 refclk_mhz, 0x1fffff); 397 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, 398 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); 399 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" 400 "HW register value = 0x%x\n", 401 watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); 402 } 403 } 404 405 if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns 406 > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) { 407 hubbub1->watermarks.b.cstate_pstate.pstate_change_ns = 408 watermarks->b.cstate_pstate.pstate_change_ns; 409 prog_wm_value = convert_and_clamp( 410 watermarks->b.cstate_pstate.pstate_change_ns, 411 refclk_mhz, 0x1fffff); 412 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, 413 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); 414 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" 415 "HW register value = 0x%x\n\n", 416 watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); 417 } 418 419 /* clock state C */ 420 if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) { 421 hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns; 422 prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, 423 refclk_mhz, 0x1fffff); 424 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, 425 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); 426 427 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" 428 "HW register value = 0x%x\n", 429 watermarks->c.urgent_ns, prog_wm_value); 430 } 431 432 if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) { 433 if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) { 434 hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; 435 prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, 436 refclk_mhz, 0x1fffff); 437 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); 438 DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" 439 "HW register value = 0x%x\n", 440 watermarks->c.pte_meta_urgent_ns, prog_wm_value); 441 } 442 } 443 444 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { 445 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns 446 > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { 447 hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = 448 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; 449 prog_wm_value = convert_and_clamp( 450 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, 451 refclk_mhz, 0x1fffff); 452 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, 453 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); 454 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" 455 "HW register value = 0x%x\n", 456 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 457 } 458 459 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns 460 > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) { 461 hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns = 462 watermarks->c.cstate_pstate.cstate_exit_ns; 463 prog_wm_value = convert_and_clamp( 464 watermarks->c.cstate_pstate.cstate_exit_ns, 465 refclk_mhz, 0x1fffff); 466 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, 467 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); 468 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" 469 "HW register value = 0x%x\n", 470 watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); 471 } 472 } 473 474 if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns 475 > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) { 476 hubbub1->watermarks.c.cstate_pstate.pstate_change_ns = 477 watermarks->c.cstate_pstate.pstate_change_ns; 478 prog_wm_value = convert_and_clamp( 479 watermarks->c.cstate_pstate.pstate_change_ns, 480 refclk_mhz, 0x1fffff); 481 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, 482 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); 483 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" 484 "HW register value = 0x%x\n\n", 485 watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); 486 } 487 488 /* clock state D */ 489 if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) { 490 hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns; 491 prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, 492 refclk_mhz, 0x1fffff); 493 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, 494 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); 495 496 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" 497 "HW register value = 0x%x\n", 498 watermarks->d.urgent_ns, prog_wm_value); 499 } 500 501 if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) { 502 if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) { 503 hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; 504 prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, 505 refclk_mhz, 0x1fffff); 506 REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); 507 DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" 508 "HW register value = 0x%x\n", 509 watermarks->d.pte_meta_urgent_ns, prog_wm_value); 510 } 511 } 512 513 if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { 514 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns 515 > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { 516 hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = 517 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; 518 prog_wm_value = convert_and_clamp( 519 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, 520 refclk_mhz, 0x1fffff); 521 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, 522 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); 523 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" 524 "HW register value = 0x%x\n", 525 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 526 } 527 528 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns 529 > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) { 530 hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns = 531 watermarks->d.cstate_pstate.cstate_exit_ns; 532 prog_wm_value = convert_and_clamp( 533 watermarks->d.cstate_pstate.cstate_exit_ns, 534 refclk_mhz, 0x1fffff); 535 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, 536 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); 537 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" 538 "HW register value = 0x%x\n", 539 watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); 540 } 541 } 542 543 if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns 544 > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) { 545 hubbub1->watermarks.d.cstate_pstate.pstate_change_ns = 546 watermarks->d.cstate_pstate.pstate_change_ns; 547 prog_wm_value = convert_and_clamp( 548 watermarks->d.cstate_pstate.pstate_change_ns, 549 refclk_mhz, 0x1fffff); 550 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0, 551 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); 552 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" 553 "HW register value = 0x%x\n\n", 554 watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); 555 } 556 557 REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, 558 DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); 559 REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, 560 DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68); 561 562 hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); 563 564 #if 0 565 REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, 566 DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1, 567 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); 568 #endif 569 } 570 571 void hubbub1_update_dchub( 572 struct hubbub *hubbub, 573 struct dchub_init_data *dh_data) 574 { 575 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 576 577 if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { 578 ASSERT(false); 579 /*should not come here*/ 580 return; 581 } 582 /* TODO: port code from dal2 */ 583 switch (dh_data->fb_mode) { 584 case FRAME_BUFFER_MODE_ZFB_ONLY: 585 /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ 586 REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP, 587 SDPIF_FB_TOP, 0); 588 589 REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE, 590 SDPIF_FB_BASE, 0x0FFFF); 591 592 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, 593 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); 594 595 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, 596 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); 597 598 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, 599 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + 600 dh_data->zfb_size_in_byte - 1) >> 22); 601 break; 602 case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: 603 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ 604 605 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, 606 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); 607 608 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, 609 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); 610 611 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, 612 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + 613 dh_data->zfb_size_in_byte - 1) >> 22); 614 break; 615 case FRAME_BUFFER_MODE_LOCAL_ONLY: 616 /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ 617 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, 618 SDPIF_AGP_BASE, 0); 619 620 REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, 621 SDPIF_AGP_BOT, 0X03FFFF); 622 623 REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, 624 SDPIF_AGP_TOP, 0); 625 break; 626 default: 627 break; 628 } 629 630 dh_data->dchub_initialzied = true; 631 dh_data->dchub_info_valid = false; 632 } 633 634 void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub) 635 { 636 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 637 638 uint32_t watermark_change_req; 639 640 REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, 641 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req); 642 643 if (watermark_change_req) 644 watermark_change_req = 0; 645 else 646 watermark_change_req = 1; 647 648 REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, 649 DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req); 650 } 651 652 void hubbub1_soft_reset(struct hubbub *hubbub, bool reset) 653 { 654 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 655 656 uint32_t reset_en = reset ? 1 : 0; 657 658 REG_UPDATE(DCHUBBUB_SOFT_RESET, 659 DCHUBBUB_GLOBAL_SOFT_RESET, reset_en); 660 } 661 662 static bool hubbub1_dcc_support_swizzle( 663 enum swizzle_mode_values swizzle, 664 unsigned int bytes_per_element, 665 enum segment_order *segment_order_horz, 666 enum segment_order *segment_order_vert) 667 { 668 bool standard_swizzle = false; 669 bool display_swizzle = false; 670 671 switch (swizzle) { 672 case DC_SW_4KB_S: 673 case DC_SW_64KB_S: 674 case DC_SW_VAR_S: 675 case DC_SW_4KB_S_X: 676 case DC_SW_64KB_S_X: 677 case DC_SW_VAR_S_X: 678 standard_swizzle = true; 679 break; 680 case DC_SW_4KB_D: 681 case DC_SW_64KB_D: 682 case DC_SW_VAR_D: 683 case DC_SW_4KB_D_X: 684 case DC_SW_64KB_D_X: 685 case DC_SW_VAR_D_X: 686 display_swizzle = true; 687 break; 688 default: 689 break; 690 } 691 692 if (bytes_per_element == 1 && standard_swizzle) { 693 *segment_order_horz = segment_order__contiguous; 694 *segment_order_vert = segment_order__na; 695 return true; 696 } 697 if (bytes_per_element == 2 && standard_swizzle) { 698 *segment_order_horz = segment_order__non_contiguous; 699 *segment_order_vert = segment_order__contiguous; 700 return true; 701 } 702 if (bytes_per_element == 4 && standard_swizzle) { 703 *segment_order_horz = segment_order__non_contiguous; 704 *segment_order_vert = segment_order__contiguous; 705 return true; 706 } 707 if (bytes_per_element == 8 && standard_swizzle) { 708 *segment_order_horz = segment_order__na; 709 *segment_order_vert = segment_order__contiguous; 710 return true; 711 } 712 if (bytes_per_element == 8 && display_swizzle) { 713 *segment_order_horz = segment_order__contiguous; 714 *segment_order_vert = segment_order__non_contiguous; 715 return true; 716 } 717 718 return false; 719 } 720 721 static bool hubbub1_dcc_support_pixel_format( 722 enum surface_pixel_format format, 723 unsigned int *bytes_per_element) 724 { 725 /* DML: get_bytes_per_element */ 726 switch (format) { 727 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 728 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 729 *bytes_per_element = 2; 730 return true; 731 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 732 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 733 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 734 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 735 *bytes_per_element = 4; 736 return true; 737 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 738 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 739 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 740 *bytes_per_element = 8; 741 return true; 742 default: 743 return false; 744 } 745 } 746 747 static void hubbub1_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, 748 unsigned int bytes_per_element) 749 { 750 /* copied from DML. might want to refactor DML to leverage from DML */ 751 /* DML : get_blk256_size */ 752 if (bytes_per_element == 1) { 753 *blk256_width = 16; 754 *blk256_height = 16; 755 } else if (bytes_per_element == 2) { 756 *blk256_width = 16; 757 *blk256_height = 8; 758 } else if (bytes_per_element == 4) { 759 *blk256_width = 8; 760 *blk256_height = 8; 761 } else if (bytes_per_element == 8) { 762 *blk256_width = 8; 763 *blk256_height = 4; 764 } 765 } 766 767 static void hubbub1_det_request_size( 768 unsigned int height, 769 unsigned int width, 770 unsigned int bpe, 771 bool *req128_horz_wc, 772 bool *req128_vert_wc) 773 { 774 unsigned int detile_buf_size = 164 * 1024; /* 164KB for DCN1.0 */ 775 776 unsigned int blk256_height = 0; 777 unsigned int blk256_width = 0; 778 unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; 779 780 hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe); 781 782 swath_bytes_horz_wc = height * blk256_height * bpe; 783 swath_bytes_vert_wc = width * blk256_width * bpe; 784 785 *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? 786 false : /* full 256B request */ 787 true; /* half 128b request */ 788 789 *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? 790 false : /* full 256B request */ 791 true; /* half 128b request */ 792 } 793 794 static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub, 795 const struct dc_dcc_surface_param *input, 796 struct dc_surface_dcc_cap *output) 797 { 798 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 799 struct dc *dc = hubbub1->base.ctx->dc; 800 801 /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */ 802 enum dcc_control dcc_control; 803 unsigned int bpe; 804 enum segment_order segment_order_horz, segment_order_vert; 805 bool req128_horz_wc, req128_vert_wc; 806 807 memset(output, 0, sizeof(*output)); 808 809 if (dc->debug.disable_dcc == DCC_DISABLE) 810 return false; 811 812 if (!hubbub1->base.funcs->dcc_support_pixel_format(input->format, &bpe)) 813 return false; 814 815 if (!hubbub1->base.funcs->dcc_support_swizzle(input->swizzle_mode, bpe, 816 &segment_order_horz, &segment_order_vert)) 817 return false; 818 819 hubbub1_det_request_size(input->surface_size.height, input->surface_size.width, 820 bpe, &req128_horz_wc, &req128_vert_wc); 821 822 if (!req128_horz_wc && !req128_vert_wc) { 823 dcc_control = dcc_control__256_256_xxx; 824 } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { 825 if (!req128_horz_wc) 826 dcc_control = dcc_control__256_256_xxx; 827 else if (segment_order_horz == segment_order__contiguous) 828 dcc_control = dcc_control__128_128_xxx; 829 else 830 dcc_control = dcc_control__256_64_64; 831 } else if (input->scan == SCAN_DIRECTION_VERTICAL) { 832 if (!req128_vert_wc) 833 dcc_control = dcc_control__256_256_xxx; 834 else if (segment_order_vert == segment_order__contiguous) 835 dcc_control = dcc_control__128_128_xxx; 836 else 837 dcc_control = dcc_control__256_64_64; 838 } else { 839 if ((req128_horz_wc && 840 segment_order_horz == segment_order__non_contiguous) || 841 (req128_vert_wc && 842 segment_order_vert == segment_order__non_contiguous)) 843 /* access_dir not known, must use most constraining */ 844 dcc_control = dcc_control__256_64_64; 845 else 846 /* reg128 is true for either horz and vert 847 * but segment_order is contiguous 848 */ 849 dcc_control = dcc_control__128_128_xxx; 850 } 851 852 if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && 853 dcc_control != dcc_control__256_256_xxx) 854 return false; 855 856 switch (dcc_control) { 857 case dcc_control__256_256_xxx: 858 output->grph.rgb.max_uncompressed_blk_size = 256; 859 output->grph.rgb.max_compressed_blk_size = 256; 860 output->grph.rgb.independent_64b_blks = false; 861 break; 862 case dcc_control__128_128_xxx: 863 output->grph.rgb.max_uncompressed_blk_size = 128; 864 output->grph.rgb.max_compressed_blk_size = 128; 865 output->grph.rgb.independent_64b_blks = false; 866 break; 867 case dcc_control__256_64_64: 868 output->grph.rgb.max_uncompressed_blk_size = 256; 869 output->grph.rgb.max_compressed_blk_size = 64; 870 output->grph.rgb.independent_64b_blks = true; 871 break; 872 } 873 874 output->capable = true; 875 output->const_color_support = false; 876 877 return true; 878 } 879 880 static const struct hubbub_funcs hubbub1_funcs = { 881 .update_dchub = hubbub1_update_dchub, 882 .dcc_support_swizzle = hubbub1_dcc_support_swizzle, 883 .dcc_support_pixel_format = hubbub1_dcc_support_pixel_format, 884 .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap, 885 .wm_read_state = hubbub1_wm_read_state, 886 .program_watermarks = hubbub1_program_watermarks, 887 }; 888 889 void hubbub1_construct(struct hubbub *hubbub, 890 struct dc_context *ctx, 891 const struct dcn_hubbub_registers *hubbub_regs, 892 const struct dcn_hubbub_shift *hubbub_shift, 893 const struct dcn_hubbub_mask *hubbub_mask) 894 { 895 struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); 896 897 hubbub1->base.ctx = ctx; 898 899 hubbub1->base.funcs = &hubbub1_funcs; 900 901 hubbub1->regs = hubbub_regs; 902 hubbub1->shifts = hubbub_shift; 903 hubbub1->masks = hubbub_mask; 904 905 hubbub1->debug_test_index_pstate = 0x7; 906 #if defined(CONFIG_DRM_AMD_DC_DCN1_01) 907 if (ctx->dce_version == DCN_VERSION_1_01) 908 hubbub1->debug_test_index_pstate = 0xB; 909 #endif 910 } 911 912