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 27 #include "dcn30/dcn30_hubbub.h" 28 #include "dcn31_hubbub.h" 29 #include "dm_services.h" 30 #include "reg_helper.h" 31 32 33 #define CTX \ 34 hubbub2->base.ctx 35 #define DC_LOGGER \ 36 hubbub2->base.ctx->logger 37 #define REG(reg)\ 38 hubbub2->regs->reg 39 40 #undef FN 41 #define FN(reg_name, field_name) \ 42 hubbub2->shifts->field_name, hubbub2->masks->field_name 43 44 #ifdef NUM_VMID 45 #undef NUM_VMID 46 #endif 47 #define NUM_VMID 16 48 49 #define DCN31_CRB_SEGMENT_SIZE_KB 64 50 51 static void dcn31_init_crb(struct hubbub *hubbub) 52 { 53 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 54 55 REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, 56 &hubbub2->det0_size); 57 58 REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, 59 &hubbub2->det1_size); 60 61 REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, 62 &hubbub2->det2_size); 63 64 REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, 65 &hubbub2->det3_size); 66 67 REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, 68 &hubbub2->compbuf_size_segments); 69 70 REG_SET_2(COMPBUF_RESERVED_SPACE, 0, 71 COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32, 72 COMPBUF_RESERVED_SPACE_ZS, hubbub2->pixel_chunk_size / 128); 73 REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x17F); 74 } 75 76 static void dcn31_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte) 77 { 78 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 79 80 unsigned int det_size_segments = (det_buffer_size_in_kbyte + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB; 81 82 switch (hubp_inst) { 83 case 0: 84 REG_UPDATE(DCHUBBUB_DET0_CTRL, 85 DET0_SIZE, det_size_segments); 86 hubbub2->det0_size = det_size_segments; 87 break; 88 case 1: 89 REG_UPDATE(DCHUBBUB_DET1_CTRL, 90 DET1_SIZE, det_size_segments); 91 hubbub2->det1_size = det_size_segments; 92 break; 93 case 2: 94 REG_UPDATE(DCHUBBUB_DET2_CTRL, 95 DET2_SIZE, det_size_segments); 96 hubbub2->det2_size = det_size_segments; 97 break; 98 case 3: 99 REG_UPDATE(DCHUBBUB_DET3_CTRL, 100 DET3_SIZE, det_size_segments); 101 hubbub2->det3_size = det_size_segments; 102 break; 103 default: 104 break; 105 } 106 DC_LOG_DEBUG("Set DET%d to %d segments\n", hubp_inst, det_size_segments); 107 /* Should never be hit, if it is we have an erroneous hw config*/ 108 ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 109 + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs); 110 } 111 112 static void dcn31_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase) 113 { 114 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 115 unsigned int compbuf_size_segments = (compbuf_size_kb + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB; 116 117 if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) { 118 if (compbuf_size_segments > hubbub2->compbuf_size_segments) { 119 REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); 120 REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); 121 REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); 122 REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); 123 } 124 /* Should never be hit, if it is we have an erroneous hw config*/ 125 ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 126 + hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs); 127 REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments); 128 hubbub2->compbuf_size_segments = compbuf_size_segments; 129 ASSERT(REG_GET(DCHUBBUB_COMPBUF_CTRL, CONFIG_ERROR, &compbuf_size_segments) && !compbuf_size_segments); 130 } 131 } 132 133 static uint32_t convert_and_clamp( 134 uint32_t wm_ns, 135 uint32_t refclk_mhz, 136 uint32_t clamp_value) 137 { 138 uint32_t ret_val = 0; 139 ret_val = wm_ns * refclk_mhz; 140 ret_val /= 1000; 141 142 if (ret_val > clamp_value) { 143 /* clamping WMs is abnormal, unexpected and may lead to underflow*/ 144 ASSERT(0); 145 ret_val = clamp_value; 146 } 147 148 return ret_val; 149 } 150 151 static bool hubbub31_program_urgent_watermarks( 152 struct hubbub *hubbub, 153 struct dcn_watermark_set *watermarks, 154 unsigned int refclk_mhz, 155 bool safe_to_lower) 156 { 157 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 158 uint32_t prog_wm_value; 159 bool wm_pending = false; 160 161 /* Repeat for water mark set A, B, C and D. */ 162 /* clock state A */ 163 if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) { 164 hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns; 165 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, 166 refclk_mhz, 0x3fff); 167 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, 168 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); 169 170 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" 171 "HW register value = 0x%x\n", 172 watermarks->a.urgent_ns, prog_wm_value); 173 } else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns) 174 wm_pending = true; 175 176 /* determine the transfer time for a quantity of data for a particular requestor.*/ 177 if (safe_to_lower || watermarks->a.frac_urg_bw_flip 178 > hubbub2->watermarks.a.frac_urg_bw_flip) { 179 hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; 180 181 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, 182 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip); 183 } else if (watermarks->a.frac_urg_bw_flip 184 < hubbub2->watermarks.a.frac_urg_bw_flip) 185 wm_pending = true; 186 187 if (safe_to_lower || watermarks->a.frac_urg_bw_nom 188 > hubbub2->watermarks.a.frac_urg_bw_nom) { 189 hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; 190 191 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, 192 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom); 193 } else if (watermarks->a.frac_urg_bw_nom 194 < hubbub2->watermarks.a.frac_urg_bw_nom) 195 wm_pending = true; 196 197 if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) { 198 hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns; 199 prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns, 200 refclk_mhz, 0x3fff); 201 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0, 202 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value); 203 } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns) 204 wm_pending = true; 205 206 /* clock state B */ 207 if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) { 208 hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns; 209 prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, 210 refclk_mhz, 0x3fff); 211 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, 212 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); 213 214 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" 215 "HW register value = 0x%x\n", 216 watermarks->b.urgent_ns, prog_wm_value); 217 } else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns) 218 wm_pending = true; 219 220 /* determine the transfer time for a quantity of data for a particular requestor.*/ 221 if (safe_to_lower || watermarks->b.frac_urg_bw_flip 222 > hubbub2->watermarks.b.frac_urg_bw_flip) { 223 hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip; 224 225 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, 226 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip); 227 } else if (watermarks->b.frac_urg_bw_flip 228 < hubbub2->watermarks.b.frac_urg_bw_flip) 229 wm_pending = true; 230 231 if (safe_to_lower || watermarks->b.frac_urg_bw_nom 232 > hubbub2->watermarks.b.frac_urg_bw_nom) { 233 hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom; 234 235 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, 236 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom); 237 } else if (watermarks->b.frac_urg_bw_nom 238 < hubbub2->watermarks.b.frac_urg_bw_nom) 239 wm_pending = true; 240 241 if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) { 242 hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns; 243 prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns, 244 refclk_mhz, 0x3fff); 245 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0, 246 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value); 247 } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns) 248 wm_pending = true; 249 250 /* clock state C */ 251 if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) { 252 hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns; 253 prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, 254 refclk_mhz, 0x3fff); 255 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, 256 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); 257 258 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" 259 "HW register value = 0x%x\n", 260 watermarks->c.urgent_ns, prog_wm_value); 261 } else if (watermarks->c.urgent_ns < hubbub2->watermarks.c.urgent_ns) 262 wm_pending = true; 263 264 /* determine the transfer time for a quantity of data for a particular requestor.*/ 265 if (safe_to_lower || watermarks->c.frac_urg_bw_flip 266 > hubbub2->watermarks.c.frac_urg_bw_flip) { 267 hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.frac_urg_bw_flip; 268 269 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0, 270 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->c.frac_urg_bw_flip); 271 } else if (watermarks->c.frac_urg_bw_flip 272 < hubbub2->watermarks.c.frac_urg_bw_flip) 273 wm_pending = true; 274 275 if (safe_to_lower || watermarks->c.frac_urg_bw_nom 276 > hubbub2->watermarks.c.frac_urg_bw_nom) { 277 hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.frac_urg_bw_nom; 278 279 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0, 280 DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->c.frac_urg_bw_nom); 281 } else if (watermarks->c.frac_urg_bw_nom 282 < hubbub2->watermarks.c.frac_urg_bw_nom) 283 wm_pending = true; 284 285 if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) { 286 hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns; 287 prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns, 288 refclk_mhz, 0x3fff); 289 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0, 290 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value); 291 } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns) 292 wm_pending = true; 293 294 /* clock state D */ 295 if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) { 296 hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns; 297 prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, 298 refclk_mhz, 0x3fff); 299 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, 300 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); 301 302 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" 303 "HW register value = 0x%x\n", 304 watermarks->d.urgent_ns, prog_wm_value); 305 } else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns) 306 wm_pending = true; 307 308 /* determine the transfer time for a quantity of data for a particular requestor.*/ 309 if (safe_to_lower || watermarks->d.frac_urg_bw_flip 310 > hubbub2->watermarks.d.frac_urg_bw_flip) { 311 hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip; 312 313 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0, 314 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip); 315 } else if (watermarks->d.frac_urg_bw_flip 316 < hubbub2->watermarks.d.frac_urg_bw_flip) 317 wm_pending = true; 318 319 if (safe_to_lower || watermarks->d.frac_urg_bw_nom 320 > hubbub2->watermarks.d.frac_urg_bw_nom) { 321 hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom; 322 323 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0, 324 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom); 325 } else if (watermarks->d.frac_urg_bw_nom 326 < hubbub2->watermarks.d.frac_urg_bw_nom) 327 wm_pending = true; 328 329 if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) { 330 hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns; 331 prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns, 332 refclk_mhz, 0x3fff); 333 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0, 334 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value); 335 } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns) 336 wm_pending = true; 337 338 return wm_pending; 339 } 340 341 static bool hubbub31_program_stutter_watermarks( 342 struct hubbub *hubbub, 343 struct dcn_watermark_set *watermarks, 344 unsigned int refclk_mhz, 345 bool safe_to_lower) 346 { 347 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 348 uint32_t prog_wm_value; 349 bool wm_pending = false; 350 351 /* clock state A */ 352 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns 353 > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { 354 hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = 355 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; 356 prog_wm_value = convert_and_clamp( 357 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, 358 refclk_mhz, 0xffff); 359 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, 360 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); 361 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" 362 "HW register value = 0x%x\n", 363 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 364 } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns 365 < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) 366 wm_pending = true; 367 368 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns 369 > hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) { 370 hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns = 371 watermarks->a.cstate_pstate.cstate_exit_ns; 372 prog_wm_value = convert_and_clamp( 373 watermarks->a.cstate_pstate.cstate_exit_ns, 374 refclk_mhz, 0xffff); 375 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, 376 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); 377 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" 378 "HW register value = 0x%x\n", 379 watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); 380 } else if (watermarks->a.cstate_pstate.cstate_exit_ns 381 < hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) 382 wm_pending = true; 383 384 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns 385 > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 386 hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = 387 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns; 388 prog_wm_value = convert_and_clamp( 389 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, 390 refclk_mhz, 0xffff); 391 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0, 392 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value); 393 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n" 394 "HW register value = 0x%x\n", 395 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 396 } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns 397 < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) 398 wm_pending = true; 399 400 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_z8_ns 401 > hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) { 402 hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns = 403 watermarks->a.cstate_pstate.cstate_exit_z8_ns; 404 prog_wm_value = convert_and_clamp( 405 watermarks->a.cstate_pstate.cstate_exit_z8_ns, 406 refclk_mhz, 0xffff); 407 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0, 408 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value); 409 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n" 410 "HW register value = 0x%x\n", 411 watermarks->a.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 412 } else if (watermarks->a.cstate_pstate.cstate_exit_z8_ns 413 < hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) 414 wm_pending = true; 415 416 /* clock state B */ 417 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns 418 > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { 419 hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = 420 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; 421 prog_wm_value = convert_and_clamp( 422 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, 423 refclk_mhz, 0xffff); 424 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, 425 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); 426 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" 427 "HW register value = 0x%x\n", 428 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 429 } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns 430 < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) 431 wm_pending = true; 432 433 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns 434 > hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) { 435 hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns = 436 watermarks->b.cstate_pstate.cstate_exit_ns; 437 prog_wm_value = convert_and_clamp( 438 watermarks->b.cstate_pstate.cstate_exit_ns, 439 refclk_mhz, 0xffff); 440 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, 441 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); 442 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" 443 "HW register value = 0x%x\n", 444 watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); 445 } else if (watermarks->b.cstate_pstate.cstate_exit_ns 446 < hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) 447 wm_pending = true; 448 449 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns 450 > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 451 hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = 452 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns; 453 prog_wm_value = convert_and_clamp( 454 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, 455 refclk_mhz, 0xffff); 456 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0, 457 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value); 458 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n" 459 "HW register value = 0x%x\n", 460 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 461 } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns 462 < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) 463 wm_pending = true; 464 465 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_z8_ns 466 > hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) { 467 hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns = 468 watermarks->b.cstate_pstate.cstate_exit_z8_ns; 469 prog_wm_value = convert_and_clamp( 470 watermarks->b.cstate_pstate.cstate_exit_z8_ns, 471 refclk_mhz, 0xffff); 472 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0, 473 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value); 474 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n" 475 "HW register value = 0x%x\n", 476 watermarks->b.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 477 } else if (watermarks->b.cstate_pstate.cstate_exit_z8_ns 478 < hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) 479 wm_pending = true; 480 481 /* clock state C */ 482 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns 483 > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { 484 hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = 485 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; 486 prog_wm_value = convert_and_clamp( 487 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, 488 refclk_mhz, 0xffff); 489 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, 490 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); 491 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" 492 "HW register value = 0x%x\n", 493 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 494 } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns 495 < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) 496 wm_pending = true; 497 498 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns 499 > hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) { 500 hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns = 501 watermarks->c.cstate_pstate.cstate_exit_ns; 502 prog_wm_value = convert_and_clamp( 503 watermarks->c.cstate_pstate.cstate_exit_ns, 504 refclk_mhz, 0xffff); 505 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, 506 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); 507 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" 508 "HW register value = 0x%x\n", 509 watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); 510 } else if (watermarks->c.cstate_pstate.cstate_exit_ns 511 < hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) 512 wm_pending = true; 513 514 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns 515 > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 516 hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = 517 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns; 518 prog_wm_value = convert_and_clamp( 519 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, 520 refclk_mhz, 0xffff); 521 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0, 522 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value); 523 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n" 524 "HW register value = 0x%x\n", 525 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 526 } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns 527 < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) 528 wm_pending = true; 529 530 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_z8_ns 531 > hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) { 532 hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns = 533 watermarks->c.cstate_pstate.cstate_exit_z8_ns; 534 prog_wm_value = convert_and_clamp( 535 watermarks->c.cstate_pstate.cstate_exit_z8_ns, 536 refclk_mhz, 0xffff); 537 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0, 538 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value); 539 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n" 540 "HW register value = 0x%x\n", 541 watermarks->c.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 542 } else if (watermarks->c.cstate_pstate.cstate_exit_z8_ns 543 < hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) 544 wm_pending = true; 545 546 /* clock state D */ 547 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns 548 > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { 549 hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = 550 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; 551 prog_wm_value = convert_and_clamp( 552 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, 553 refclk_mhz, 0xffff); 554 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, 555 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); 556 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" 557 "HW register value = 0x%x\n", 558 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 559 } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns 560 < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) 561 wm_pending = true; 562 563 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns 564 > hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) { 565 hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns = 566 watermarks->d.cstate_pstate.cstate_exit_ns; 567 prog_wm_value = convert_and_clamp( 568 watermarks->d.cstate_pstate.cstate_exit_ns, 569 refclk_mhz, 0xffff); 570 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, 571 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); 572 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" 573 "HW register value = 0x%x\n", 574 watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); 575 } else if (watermarks->d.cstate_pstate.cstate_exit_ns 576 < hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) 577 wm_pending = true; 578 579 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns 580 > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 581 hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = 582 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns; 583 prog_wm_value = convert_and_clamp( 584 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, 585 refclk_mhz, 0xffff); 586 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0, 587 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value); 588 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n" 589 "HW register value = 0x%x\n", 590 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 591 } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns 592 < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) 593 wm_pending = true; 594 595 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_z8_ns 596 > hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) { 597 hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns = 598 watermarks->d.cstate_pstate.cstate_exit_z8_ns; 599 prog_wm_value = convert_and_clamp( 600 watermarks->d.cstate_pstate.cstate_exit_z8_ns, 601 refclk_mhz, 0xffff); 602 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0, 603 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value); 604 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n" 605 "HW register value = 0x%x\n", 606 watermarks->d.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 607 } else if (watermarks->d.cstate_pstate.cstate_exit_z8_ns 608 < hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) 609 wm_pending = true; 610 611 return wm_pending; 612 } 613 614 static bool hubbub31_program_pstate_watermarks( 615 struct hubbub *hubbub, 616 struct dcn_watermark_set *watermarks, 617 unsigned int refclk_mhz, 618 bool safe_to_lower) 619 { 620 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 621 uint32_t prog_wm_value; 622 623 bool wm_pending = false; 624 625 /* clock state A */ 626 if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns 627 > hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) { 628 hubbub2->watermarks.a.cstate_pstate.pstate_change_ns = 629 watermarks->a.cstate_pstate.pstate_change_ns; 630 prog_wm_value = convert_and_clamp( 631 watermarks->a.cstate_pstate.pstate_change_ns, 632 refclk_mhz, 0xffff); 633 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, 634 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); 635 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" 636 "HW register value = 0x%x\n\n", 637 watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); 638 } else if (watermarks->a.cstate_pstate.pstate_change_ns 639 < hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) 640 wm_pending = true; 641 642 /* clock state B */ 643 if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns 644 > hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) { 645 hubbub2->watermarks.b.cstate_pstate.pstate_change_ns = 646 watermarks->b.cstate_pstate.pstate_change_ns; 647 prog_wm_value = convert_and_clamp( 648 watermarks->b.cstate_pstate.pstate_change_ns, 649 refclk_mhz, 0xffff); 650 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, 651 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); 652 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" 653 "HW register value = 0x%x\n\n", 654 watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); 655 } else if (watermarks->b.cstate_pstate.pstate_change_ns 656 < hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) 657 wm_pending = false; 658 659 /* clock state C */ 660 if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns 661 > hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) { 662 hubbub2->watermarks.c.cstate_pstate.pstate_change_ns = 663 watermarks->c.cstate_pstate.pstate_change_ns; 664 prog_wm_value = convert_and_clamp( 665 watermarks->c.cstate_pstate.pstate_change_ns, 666 refclk_mhz, 0xffff); 667 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, 668 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); 669 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" 670 "HW register value = 0x%x\n\n", 671 watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); 672 } else if (watermarks->c.cstate_pstate.pstate_change_ns 673 < hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) 674 wm_pending = true; 675 676 /* clock state D */ 677 if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns 678 > hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) { 679 hubbub2->watermarks.d.cstate_pstate.pstate_change_ns = 680 watermarks->d.cstate_pstate.pstate_change_ns; 681 prog_wm_value = convert_and_clamp( 682 watermarks->d.cstate_pstate.pstate_change_ns, 683 refclk_mhz, 0xffff); 684 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0, 685 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); 686 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" 687 "HW register value = 0x%x\n\n", 688 watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); 689 } else if (watermarks->d.cstate_pstate.pstate_change_ns 690 < hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) 691 wm_pending = true; 692 693 return wm_pending; 694 } 695 696 static bool hubbub31_program_watermarks( 697 struct hubbub *hubbub, 698 struct dcn_watermark_set *watermarks, 699 unsigned int refclk_mhz, 700 bool safe_to_lower) 701 { 702 bool wm_pending = false; 703 704 if (hubbub31_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 705 wm_pending = true; 706 707 if (hubbub31_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 708 wm_pending = true; 709 710 if (hubbub31_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 711 wm_pending = true; 712 713 /* 714 * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric. 715 * If the memory controller is fully utilized and the DCHub requestors are 716 * well ahead of their amortized schedule, then it is safe to prevent the next winner 717 * from being committed and sent to the fabric. 718 * The utilization of the memory controller is approximated by ensuring that 719 * the number of outstanding requests is greater than a threshold specified 720 * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule, 721 * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles. 722 * 723 * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF) 724 * to turn off it for now. 725 */ 726 /*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, 727 DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); 728 REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, 729 DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/ 730 731 hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); 732 return wm_pending; 733 } 734 735 static void hubbub3_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, 736 unsigned int bytes_per_element) 737 { 738 /* copied from DML. might want to refactor DML to leverage from DML */ 739 /* DML : get_blk256_size */ 740 if (bytes_per_element == 1) { 741 *blk256_width = 16; 742 *blk256_height = 16; 743 } else if (bytes_per_element == 2) { 744 *blk256_width = 16; 745 *blk256_height = 8; 746 } else if (bytes_per_element == 4) { 747 *blk256_width = 8; 748 *blk256_height = 8; 749 } else if (bytes_per_element == 8) { 750 *blk256_width = 8; 751 *blk256_height = 4; 752 } 753 } 754 755 static void hubbub31_det_request_size( 756 unsigned int detile_buf_size, 757 unsigned int height, 758 unsigned int width, 759 unsigned int bpe, 760 bool *req128_horz_wc, 761 bool *req128_vert_wc) 762 { 763 unsigned int blk256_height = 0; 764 unsigned int blk256_width = 0; 765 unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; 766 767 hubbub3_get_blk256_size(&blk256_width, &blk256_height, bpe); 768 769 swath_bytes_horz_wc = width * blk256_height * bpe; 770 swath_bytes_vert_wc = height * blk256_width * bpe; 771 772 *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? 773 false : /* full 256B request */ 774 true; /* half 128b request */ 775 776 *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? 777 false : /* full 256B request */ 778 true; /* half 128b request */ 779 } 780 781 static bool hubbub31_get_dcc_compression_cap(struct hubbub *hubbub, 782 const struct dc_dcc_surface_param *input, 783 struct dc_surface_dcc_cap *output) 784 { 785 struct dc *dc = hubbub->ctx->dc; 786 enum dcc_control dcc_control; 787 unsigned int bpe; 788 enum segment_order segment_order_horz, segment_order_vert; 789 bool req128_horz_wc, req128_vert_wc; 790 791 memset(output, 0, sizeof(*output)); 792 793 if (dc->debug.disable_dcc == DCC_DISABLE) 794 return false; 795 796 if (!hubbub->funcs->dcc_support_pixel_format(input->format, 797 &bpe)) 798 return false; 799 800 if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, 801 &segment_order_horz, &segment_order_vert)) 802 return false; 803 804 hubbub31_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size, 805 input->surface_size.height, input->surface_size.width, 806 bpe, &req128_horz_wc, &req128_vert_wc); 807 808 if (!req128_horz_wc && !req128_vert_wc) { 809 dcc_control = dcc_control__256_256_xxx; 810 } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { 811 if (!req128_horz_wc) 812 dcc_control = dcc_control__256_256_xxx; 813 else if (segment_order_horz == segment_order__contiguous) 814 dcc_control = dcc_control__128_128_xxx; 815 else 816 dcc_control = dcc_control__256_64_64; 817 } else if (input->scan == SCAN_DIRECTION_VERTICAL) { 818 if (!req128_vert_wc) 819 dcc_control = dcc_control__256_256_xxx; 820 else if (segment_order_vert == segment_order__contiguous) 821 dcc_control = dcc_control__128_128_xxx; 822 else 823 dcc_control = dcc_control__256_64_64; 824 } else { 825 if ((req128_horz_wc && 826 segment_order_horz == segment_order__non_contiguous) || 827 (req128_vert_wc && 828 segment_order_vert == segment_order__non_contiguous)) 829 /* access_dir not known, must use most constraining */ 830 dcc_control = dcc_control__256_64_64; 831 else 832 /* reg128 is true for either horz and vert 833 * but segment_order is contiguous 834 */ 835 dcc_control = dcc_control__128_128_xxx; 836 } 837 838 /* Exception for 64KB_R_X */ 839 if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X)) 840 dcc_control = dcc_control__128_128_xxx; 841 842 if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && 843 dcc_control != dcc_control__256_256_xxx) 844 return false; 845 846 switch (dcc_control) { 847 case dcc_control__256_256_xxx: 848 output->grph.rgb.max_uncompressed_blk_size = 256; 849 output->grph.rgb.max_compressed_blk_size = 256; 850 output->grph.rgb.independent_64b_blks = false; 851 output->grph.rgb.dcc_controls.dcc_256_256_unconstrained = 1; 852 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 853 break; 854 case dcc_control__128_128_xxx: 855 output->grph.rgb.max_uncompressed_blk_size = 128; 856 output->grph.rgb.max_compressed_blk_size = 128; 857 output->grph.rgb.independent_64b_blks = false; 858 output->grph.rgb.dcc_controls.dcc_128_128_uncontrained = 1; 859 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 860 break; 861 case dcc_control__256_64_64: 862 output->grph.rgb.max_uncompressed_blk_size = 256; 863 output->grph.rgb.max_compressed_blk_size = 64; 864 output->grph.rgb.independent_64b_blks = true; 865 output->grph.rgb.dcc_controls.dcc_256_64_64 = 1; 866 break; 867 case dcc_control__256_128_128: 868 output->grph.rgb.max_uncompressed_blk_size = 256; 869 output->grph.rgb.max_compressed_blk_size = 128; 870 output->grph.rgb.independent_64b_blks = false; 871 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 872 break; 873 } 874 output->capable = true; 875 output->const_color_support = true; 876 877 return true; 878 } 879 880 int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, 881 struct dcn_hubbub_phys_addr_config *pa_config) 882 { 883 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 884 struct dcn_vmid_page_table_config phys_config; 885 886 REG_SET(DCN_VM_FB_LOCATION_BASE, 0, 887 FB_BASE, pa_config->system_aperture.fb_base >> 24); 888 REG_SET(DCN_VM_FB_LOCATION_TOP, 0, 889 FB_TOP, pa_config->system_aperture.fb_top >> 24); 890 REG_SET(DCN_VM_FB_OFFSET, 0, 891 FB_OFFSET, pa_config->system_aperture.fb_offset >> 24); 892 REG_SET(DCN_VM_AGP_BOT, 0, 893 AGP_BOT, pa_config->system_aperture.agp_bot >> 24); 894 REG_SET(DCN_VM_AGP_TOP, 0, 895 AGP_TOP, pa_config->system_aperture.agp_top >> 24); 896 REG_SET(DCN_VM_AGP_BASE, 0, 897 AGP_BASE, pa_config->system_aperture.agp_base >> 24); 898 899 if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) { 900 phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12; 901 phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12; 902 phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; 903 phys_config.depth = 0; 904 phys_config.block_size = 0; 905 // Init VMID 0 based on PA config 906 dcn20_vmid_setup(&hubbub2->vmid[0], &phys_config); 907 908 dcn20_vmid_setup(&hubbub2->vmid[15], &phys_config); 909 } 910 911 dcn21_dchvm_init(hubbub); 912 913 return NUM_VMID; 914 } 915 916 static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub, 917 unsigned int dccg_ref_freq_inKhz, 918 unsigned int *dchub_ref_freq_inKhz) 919 { 920 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 921 uint32_t ref_div = 0; 922 uint32_t ref_en = 0; 923 unsigned int dc_refclk_khz = 24000; 924 925 REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div, 926 DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en); 927 928 if (ref_en) { 929 if (ref_div == 2) 930 *dchub_ref_freq_inKhz = dc_refclk_khz / 2; 931 else 932 *dchub_ref_freq_inKhz = dc_refclk_khz; 933 934 /* 935 * The external Reference Clock may change based on the board or 936 * platform requirements and the programmable integer divide must 937 * be programmed to provide a suitable DLG RefClk frequency between 938 * a minimum of 20MHz and maximum of 50MHz 939 */ 940 if (*dchub_ref_freq_inKhz < 20000 || *dchub_ref_freq_inKhz > 50000) 941 ASSERT_CRITICAL(false); 942 943 return; 944 } else { 945 *dchub_ref_freq_inKhz = dc_refclk_khz; 946 947 // HUBBUB global timer must be enabled. 948 ASSERT_CRITICAL(false); 949 return; 950 } 951 } 952 953 static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub) 954 { 955 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 956 957 /* 958 * Pstate latency is ~20us so if we wait over 40us and pstate allow 959 * still not asserted, we are probably stuck and going to hang 960 */ 961 const unsigned int pstate_wait_timeout_us = 100; 962 const unsigned int pstate_wait_expected_timeout_us = 40; 963 964 static unsigned int max_sampled_pstate_wait_us; /* data collection */ 965 static bool forced_pstate_allow; /* help with revert wa */ 966 967 unsigned int debug_data = 0; 968 unsigned int i; 969 970 if (forced_pstate_allow) { 971 /* we hacked to force pstate allow to prevent hang last time 972 * we verify_allow_pstate_change_high. so disable force 973 * here so we can check status 974 */ 975 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, 976 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0, 977 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0); 978 forced_pstate_allow = false; 979 } 980 981 REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub2->debug_test_index_pstate); 982 983 for (i = 0; i < pstate_wait_timeout_us; i++) { 984 debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); 985 986 /* Debug bit is specific to ASIC. */ 987 if (debug_data & (1 << 26)) { 988 if (i > pstate_wait_expected_timeout_us) 989 DC_LOG_WARNING("pstate took longer than expected ~%dus\n", i); 990 return true; 991 } 992 if (max_sampled_pstate_wait_us < i) 993 max_sampled_pstate_wait_us = i; 994 995 udelay(1); 996 } 997 998 /* force pstate allow to prevent system hang 999 * and break to debugger to investigate 1000 */ 1001 REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, 1002 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1, 1003 DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); 1004 forced_pstate_allow = true; 1005 1006 DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n", 1007 debug_data); 1008 1009 return false; 1010 } 1011 1012 void hubbub31_init(struct hubbub *hubbub) 1013 { 1014 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1015 1016 /*Enable clock gate*/ 1017 if (hubbub->ctx->dc->debug.disable_clock_gate) { 1018 /*done in hwseq*/ 1019 /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/ 1020 REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL, 1021 DISPCLK_R_DCHUBBUB_GATE_DIS, 0, 1022 DCFCLK_R_DCHUBBUB_GATE_DIS, 0); 1023 } 1024 1025 /* 1026 only the DCN will determine when to connect the SDP port 1027 */ 1028 REG_UPDATE(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, 1); 1029 } 1030 static const struct hubbub_funcs hubbub31_funcs = { 1031 .update_dchub = hubbub2_update_dchub, 1032 .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx, 1033 .init_vm_ctx = hubbub2_init_vm_ctx, 1034 .dcc_support_swizzle = hubbub3_dcc_support_swizzle, 1035 .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, 1036 .get_dcc_compression_cap = hubbub31_get_dcc_compression_cap, 1037 .wm_read_state = hubbub21_wm_read_state, 1038 .get_dchub_ref_freq = hubbub31_get_dchub_ref_freq, 1039 .program_watermarks = hubbub31_program_watermarks, 1040 .allow_self_refresh_control = hubbub1_allow_self_refresh_control, 1041 .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, 1042 .verify_allow_pstate_change_high = hubbub31_verify_allow_pstate_change_high, 1043 .program_det_size = dcn31_program_det_size, 1044 .program_compbuf_size = dcn31_program_compbuf_size, 1045 .init_crb = dcn31_init_crb, 1046 .hubbub_read_state = hubbub2_read_state, 1047 }; 1048 1049 void hubbub31_construct(struct dcn20_hubbub *hubbub31, 1050 struct dc_context *ctx, 1051 const struct dcn_hubbub_registers *hubbub_regs, 1052 const struct dcn_hubbub_shift *hubbub_shift, 1053 const struct dcn_hubbub_mask *hubbub_mask, 1054 int det_size_kb, 1055 int pixel_chunk_size_kb, 1056 int config_return_buffer_size_kb) 1057 { 1058 1059 hubbub3_construct(hubbub31, ctx, hubbub_regs, hubbub_shift, hubbub_mask); 1060 hubbub31->base.funcs = &hubbub31_funcs; 1061 hubbub31->detile_buf_size = det_size_kb * 1024; 1062 hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024; 1063 hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB; 1064 1065 hubbub31->debug_test_index_pstate = 0x6; 1066 } 1067 1068