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