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