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 /* Should never be hit, if it is we have an erroneous hw config*/ 107 ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 108 + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs); 109 } 110 111 static void dcn31_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase) 112 { 113 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 114 unsigned int compbuf_size_segments = (compbuf_size_kb + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB; 115 116 if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) { 117 if (compbuf_size_segments > hubbub2->compbuf_size_segments) { 118 REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); 119 REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); 120 REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); 121 REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); 122 } 123 /* Should never be hit, if it is we have an erroneous hw config*/ 124 ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 125 + hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs); 126 REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments); 127 REG_WAIT(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, compbuf_size_segments, 1, 100); 128 hubbub2->compbuf_size_segments = compbuf_size_segments; 129 } 130 } 131 132 static uint32_t convert_and_clamp( 133 uint32_t wm_ns, 134 uint32_t refclk_mhz, 135 uint32_t clamp_value) 136 { 137 uint32_t ret_val = 0; 138 ret_val = wm_ns * refclk_mhz; 139 ret_val /= 1000; 140 141 if (ret_val > clamp_value) 142 ret_val = clamp_value; 143 144 return ret_val; 145 } 146 147 static bool hubbub31_program_urgent_watermarks( 148 struct hubbub *hubbub, 149 struct dcn_watermark_set *watermarks, 150 unsigned int refclk_mhz, 151 bool safe_to_lower) 152 { 153 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 154 uint32_t prog_wm_value; 155 bool wm_pending = false; 156 157 /* Repeat for water mark set A, B, C and D. */ 158 /* clock state A */ 159 if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) { 160 hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns; 161 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, 162 refclk_mhz, 0x1fffff); 163 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, 164 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); 165 166 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" 167 "HW register value = 0x%x\n", 168 watermarks->a.urgent_ns, prog_wm_value); 169 } else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns) 170 wm_pending = true; 171 172 /* determine the transfer time for a quantity of data for a particular requestor.*/ 173 if (safe_to_lower || watermarks->a.frac_urg_bw_flip 174 > hubbub2->watermarks.a.frac_urg_bw_flip) { 175 hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; 176 177 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, 178 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip); 179 } else if (watermarks->a.frac_urg_bw_flip 180 < hubbub2->watermarks.a.frac_urg_bw_flip) 181 wm_pending = true; 182 183 if (safe_to_lower || watermarks->a.frac_urg_bw_nom 184 > hubbub2->watermarks.a.frac_urg_bw_nom) { 185 hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; 186 187 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, 188 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom); 189 } else if (watermarks->a.frac_urg_bw_nom 190 < hubbub2->watermarks.a.frac_urg_bw_nom) 191 wm_pending = true; 192 193 if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) { 194 hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns; 195 prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns, 196 refclk_mhz, 0x1fffff); 197 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0, 198 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value); 199 } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns) 200 wm_pending = true; 201 202 /* clock state B */ 203 if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) { 204 hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns; 205 prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, 206 refclk_mhz, 0x1fffff); 207 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, 208 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); 209 210 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" 211 "HW register value = 0x%x\n", 212 watermarks->b.urgent_ns, prog_wm_value); 213 } else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns) 214 wm_pending = true; 215 216 /* determine the transfer time for a quantity of data for a particular requestor.*/ 217 if (safe_to_lower || watermarks->b.frac_urg_bw_flip 218 > hubbub2->watermarks.b.frac_urg_bw_flip) { 219 hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip; 220 221 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, 222 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip); 223 } else if (watermarks->b.frac_urg_bw_flip 224 < hubbub2->watermarks.b.frac_urg_bw_flip) 225 wm_pending = true; 226 227 if (safe_to_lower || watermarks->b.frac_urg_bw_nom 228 > hubbub2->watermarks.b.frac_urg_bw_nom) { 229 hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom; 230 231 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, 232 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom); 233 } else if (watermarks->b.frac_urg_bw_nom 234 < hubbub2->watermarks.b.frac_urg_bw_nom) 235 wm_pending = true; 236 237 if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) { 238 hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns; 239 prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns, 240 refclk_mhz, 0x1fffff); 241 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0, 242 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value); 243 } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns) 244 wm_pending = true; 245 246 /* clock state C */ 247 if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) { 248 hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns; 249 prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, 250 refclk_mhz, 0x1fffff); 251 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, 252 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); 253 254 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" 255 "HW register value = 0x%x\n", 256 watermarks->c.urgent_ns, prog_wm_value); 257 } else if (watermarks->c.urgent_ns < hubbub2->watermarks.c.urgent_ns) 258 wm_pending = true; 259 260 /* determine the transfer time for a quantity of data for a particular requestor.*/ 261 if (safe_to_lower || watermarks->c.frac_urg_bw_flip 262 > hubbub2->watermarks.c.frac_urg_bw_flip) { 263 hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.frac_urg_bw_flip; 264 265 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0, 266 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->c.frac_urg_bw_flip); 267 } else if (watermarks->c.frac_urg_bw_flip 268 < hubbub2->watermarks.c.frac_urg_bw_flip) 269 wm_pending = true; 270 271 if (safe_to_lower || watermarks->c.frac_urg_bw_nom 272 > hubbub2->watermarks.c.frac_urg_bw_nom) { 273 hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.frac_urg_bw_nom; 274 275 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0, 276 DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->c.frac_urg_bw_nom); 277 } else if (watermarks->c.frac_urg_bw_nom 278 < hubbub2->watermarks.c.frac_urg_bw_nom) 279 wm_pending = true; 280 281 if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) { 282 hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns; 283 prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns, 284 refclk_mhz, 0x1fffff); 285 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0, 286 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value); 287 } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns) 288 wm_pending = true; 289 290 /* clock state D */ 291 if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) { 292 hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns; 293 prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, 294 refclk_mhz, 0x1fffff); 295 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, 296 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); 297 298 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" 299 "HW register value = 0x%x\n", 300 watermarks->d.urgent_ns, prog_wm_value); 301 } else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns) 302 wm_pending = true; 303 304 /* determine the transfer time for a quantity of data for a particular requestor.*/ 305 if (safe_to_lower || watermarks->d.frac_urg_bw_flip 306 > hubbub2->watermarks.d.frac_urg_bw_flip) { 307 hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip; 308 309 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0, 310 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip); 311 } else if (watermarks->d.frac_urg_bw_flip 312 < hubbub2->watermarks.d.frac_urg_bw_flip) 313 wm_pending = true; 314 315 if (safe_to_lower || watermarks->d.frac_urg_bw_nom 316 > hubbub2->watermarks.d.frac_urg_bw_nom) { 317 hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom; 318 319 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0, 320 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom); 321 } else if (watermarks->d.frac_urg_bw_nom 322 < hubbub2->watermarks.d.frac_urg_bw_nom) 323 wm_pending = true; 324 325 if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) { 326 hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns; 327 prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns, 328 refclk_mhz, 0x1fffff); 329 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0, 330 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value); 331 } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns) 332 wm_pending = true; 333 334 return wm_pending; 335 } 336 337 static bool hubbub31_program_stutter_watermarks( 338 struct hubbub *hubbub, 339 struct dcn_watermark_set *watermarks, 340 unsigned int refclk_mhz, 341 bool safe_to_lower) 342 { 343 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 344 uint32_t prog_wm_value; 345 bool wm_pending = false; 346 347 /* clock state A */ 348 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns 349 > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { 350 hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = 351 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; 352 prog_wm_value = convert_and_clamp( 353 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, 354 refclk_mhz, 0x1fffff); 355 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, 356 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); 357 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" 358 "HW register value = 0x%x\n", 359 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 360 } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns 361 < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) 362 wm_pending = true; 363 364 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns 365 > hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) { 366 hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns = 367 watermarks->a.cstate_pstate.cstate_exit_ns; 368 prog_wm_value = convert_and_clamp( 369 watermarks->a.cstate_pstate.cstate_exit_ns, 370 refclk_mhz, 0x1fffff); 371 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, 372 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); 373 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" 374 "HW register value = 0x%x\n", 375 watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); 376 } else if (watermarks->a.cstate_pstate.cstate_exit_ns 377 < hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) 378 wm_pending = true; 379 380 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns 381 > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 382 hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = 383 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns; 384 prog_wm_value = convert_and_clamp( 385 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, 386 refclk_mhz, 0x1fffff); 387 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0, 388 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value); 389 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n" 390 "HW register value = 0x%x\n", 391 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 392 } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns 393 < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) 394 wm_pending = true; 395 396 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_z8_ns 397 > hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) { 398 hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns = 399 watermarks->a.cstate_pstate.cstate_exit_z8_ns; 400 prog_wm_value = convert_and_clamp( 401 watermarks->a.cstate_pstate.cstate_exit_z8_ns, 402 refclk_mhz, 0x1fffff); 403 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0, 404 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value); 405 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n" 406 "HW register value = 0x%x\n", 407 watermarks->a.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 408 } else if (watermarks->a.cstate_pstate.cstate_exit_z8_ns 409 < hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) 410 wm_pending = true; 411 412 /* clock state B */ 413 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns 414 > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { 415 hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = 416 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; 417 prog_wm_value = convert_and_clamp( 418 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, 419 refclk_mhz, 0x1fffff); 420 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, 421 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); 422 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" 423 "HW register value = 0x%x\n", 424 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 425 } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns 426 < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) 427 wm_pending = true; 428 429 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns 430 > hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) { 431 hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns = 432 watermarks->b.cstate_pstate.cstate_exit_ns; 433 prog_wm_value = convert_and_clamp( 434 watermarks->b.cstate_pstate.cstate_exit_ns, 435 refclk_mhz, 0x1fffff); 436 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, 437 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); 438 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" 439 "HW register value = 0x%x\n", 440 watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); 441 } else if (watermarks->b.cstate_pstate.cstate_exit_ns 442 < hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) 443 wm_pending = true; 444 445 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns 446 > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 447 hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = 448 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns; 449 prog_wm_value = convert_and_clamp( 450 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, 451 refclk_mhz, 0x1fffff); 452 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0, 453 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value); 454 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n" 455 "HW register value = 0x%x\n", 456 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 457 } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns 458 < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) 459 wm_pending = true; 460 461 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_z8_ns 462 > hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) { 463 hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns = 464 watermarks->b.cstate_pstate.cstate_exit_z8_ns; 465 prog_wm_value = convert_and_clamp( 466 watermarks->b.cstate_pstate.cstate_exit_z8_ns, 467 refclk_mhz, 0x1fffff); 468 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0, 469 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value); 470 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n" 471 "HW register value = 0x%x\n", 472 watermarks->b.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 473 } else if (watermarks->b.cstate_pstate.cstate_exit_z8_ns 474 < hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) 475 wm_pending = true; 476 477 /* clock state C */ 478 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns 479 > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { 480 hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = 481 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; 482 prog_wm_value = convert_and_clamp( 483 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, 484 refclk_mhz, 0x1fffff); 485 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, 486 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); 487 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" 488 "HW register value = 0x%x\n", 489 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 490 } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns 491 < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) 492 wm_pending = true; 493 494 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns 495 > hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) { 496 hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns = 497 watermarks->c.cstate_pstate.cstate_exit_ns; 498 prog_wm_value = convert_and_clamp( 499 watermarks->c.cstate_pstate.cstate_exit_ns, 500 refclk_mhz, 0x1fffff); 501 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, 502 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); 503 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" 504 "HW register value = 0x%x\n", 505 watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); 506 } else if (watermarks->c.cstate_pstate.cstate_exit_ns 507 < hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) 508 wm_pending = true; 509 510 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns 511 > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 512 hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = 513 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns; 514 prog_wm_value = convert_and_clamp( 515 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, 516 refclk_mhz, 0x1fffff); 517 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0, 518 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value); 519 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n" 520 "HW register value = 0x%x\n", 521 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 522 } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns 523 < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) 524 wm_pending = true; 525 526 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_z8_ns 527 > hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) { 528 hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns = 529 watermarks->c.cstate_pstate.cstate_exit_z8_ns; 530 prog_wm_value = convert_and_clamp( 531 watermarks->c.cstate_pstate.cstate_exit_z8_ns, 532 refclk_mhz, 0x1fffff); 533 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0, 534 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value); 535 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n" 536 "HW register value = 0x%x\n", 537 watermarks->c.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 538 } else if (watermarks->c.cstate_pstate.cstate_exit_z8_ns 539 < hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) 540 wm_pending = true; 541 542 /* clock state D */ 543 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns 544 > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { 545 hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = 546 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; 547 prog_wm_value = convert_and_clamp( 548 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, 549 refclk_mhz, 0x1fffff); 550 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, 551 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); 552 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" 553 "HW register value = 0x%x\n", 554 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); 555 } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns 556 < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) 557 wm_pending = true; 558 559 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns 560 > hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) { 561 hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns = 562 watermarks->d.cstate_pstate.cstate_exit_ns; 563 prog_wm_value = convert_and_clamp( 564 watermarks->d.cstate_pstate.cstate_exit_ns, 565 refclk_mhz, 0x1fffff); 566 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, 567 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); 568 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" 569 "HW register value = 0x%x\n", 570 watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); 571 } else if (watermarks->d.cstate_pstate.cstate_exit_ns 572 < hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) 573 wm_pending = true; 574 575 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns 576 > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) { 577 hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = 578 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns; 579 prog_wm_value = convert_and_clamp( 580 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, 581 refclk_mhz, 0x1fffff); 582 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0, 583 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value); 584 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n" 585 "HW register value = 0x%x\n", 586 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value); 587 } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns 588 < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) 589 wm_pending = true; 590 591 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_z8_ns 592 > hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) { 593 hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns = 594 watermarks->d.cstate_pstate.cstate_exit_z8_ns; 595 prog_wm_value = convert_and_clamp( 596 watermarks->d.cstate_pstate.cstate_exit_z8_ns, 597 refclk_mhz, 0x1fffff); 598 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0, 599 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value); 600 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n" 601 "HW register value = 0x%x\n", 602 watermarks->d.cstate_pstate.cstate_exit_z8_ns, prog_wm_value); 603 } else if (watermarks->d.cstate_pstate.cstate_exit_z8_ns 604 < hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) 605 wm_pending = true; 606 607 return wm_pending; 608 } 609 610 static bool hubbub31_program_pstate_watermarks( 611 struct hubbub *hubbub, 612 struct dcn_watermark_set *watermarks, 613 unsigned int refclk_mhz, 614 bool safe_to_lower) 615 { 616 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 617 uint32_t prog_wm_value; 618 619 bool wm_pending = false; 620 621 /* clock state A */ 622 if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns 623 > hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) { 624 hubbub2->watermarks.a.cstate_pstate.pstate_change_ns = 625 watermarks->a.cstate_pstate.pstate_change_ns; 626 prog_wm_value = convert_and_clamp( 627 watermarks->a.cstate_pstate.pstate_change_ns, 628 refclk_mhz, 0x1fffff); 629 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, 630 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); 631 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" 632 "HW register value = 0x%x\n\n", 633 watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); 634 } else if (watermarks->a.cstate_pstate.pstate_change_ns 635 < hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) 636 wm_pending = true; 637 638 /* clock state B */ 639 if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns 640 > hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) { 641 hubbub2->watermarks.b.cstate_pstate.pstate_change_ns = 642 watermarks->b.cstate_pstate.pstate_change_ns; 643 prog_wm_value = convert_and_clamp( 644 watermarks->b.cstate_pstate.pstate_change_ns, 645 refclk_mhz, 0x1fffff); 646 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, 647 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); 648 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" 649 "HW register value = 0x%x\n\n", 650 watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); 651 } else if (watermarks->b.cstate_pstate.pstate_change_ns 652 < hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) 653 wm_pending = false; 654 655 /* clock state C */ 656 if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns 657 > hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) { 658 hubbub2->watermarks.c.cstate_pstate.pstate_change_ns = 659 watermarks->c.cstate_pstate.pstate_change_ns; 660 prog_wm_value = convert_and_clamp( 661 watermarks->c.cstate_pstate.pstate_change_ns, 662 refclk_mhz, 0x1fffff); 663 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, 664 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); 665 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" 666 "HW register value = 0x%x\n\n", 667 watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); 668 } else if (watermarks->c.cstate_pstate.pstate_change_ns 669 < hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) 670 wm_pending = true; 671 672 /* clock state D */ 673 if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns 674 > hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) { 675 hubbub2->watermarks.d.cstate_pstate.pstate_change_ns = 676 watermarks->d.cstate_pstate.pstate_change_ns; 677 prog_wm_value = convert_and_clamp( 678 watermarks->d.cstate_pstate.pstate_change_ns, 679 refclk_mhz, 0x1fffff); 680 REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0, 681 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); 682 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" 683 "HW register value = 0x%x\n\n", 684 watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); 685 } else if (watermarks->d.cstate_pstate.pstate_change_ns 686 < hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) 687 wm_pending = true; 688 689 return wm_pending; 690 } 691 692 static bool hubbub31_program_watermarks( 693 struct hubbub *hubbub, 694 struct dcn_watermark_set *watermarks, 695 unsigned int refclk_mhz, 696 bool safe_to_lower) 697 { 698 bool wm_pending = false; 699 700 if (hubbub31_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 701 wm_pending = true; 702 703 if (hubbub31_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 704 wm_pending = true; 705 706 if (hubbub31_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 707 wm_pending = true; 708 709 /* 710 * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric. 711 * If the memory controller is fully utilized and the DCHub requestors are 712 * well ahead of their amortized schedule, then it is safe to prevent the next winner 713 * from being committed and sent to the fabric. 714 * The utilization of the memory controller is approximated by ensuring that 715 * the number of outstanding requests is greater than a threshold specified 716 * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule, 717 * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles. 718 * 719 * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF) 720 * to turn off it for now. 721 */ 722 /*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, 723 DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); 724 REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, 725 DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/ 726 727 hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); 728 return wm_pending; 729 } 730 731 static void hubbub3_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, 732 unsigned int bytes_per_element) 733 { 734 /* copied from DML. might want to refactor DML to leverage from DML */ 735 /* DML : get_blk256_size */ 736 if (bytes_per_element == 1) { 737 *blk256_width = 16; 738 *blk256_height = 16; 739 } else if (bytes_per_element == 2) { 740 *blk256_width = 16; 741 *blk256_height = 8; 742 } else if (bytes_per_element == 4) { 743 *blk256_width = 8; 744 *blk256_height = 8; 745 } else if (bytes_per_element == 8) { 746 *blk256_width = 8; 747 *blk256_height = 4; 748 } 749 } 750 751 static void hubbub31_det_request_size( 752 unsigned int detile_buf_size, 753 unsigned int height, 754 unsigned int width, 755 unsigned int bpe, 756 bool *req128_horz_wc, 757 bool *req128_vert_wc) 758 { 759 unsigned int blk256_height = 0; 760 unsigned int blk256_width = 0; 761 unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; 762 763 hubbub3_get_blk256_size(&blk256_width, &blk256_height, bpe); 764 765 swath_bytes_horz_wc = width * blk256_height * bpe; 766 swath_bytes_vert_wc = height * blk256_width * bpe; 767 768 *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? 769 false : /* full 256B request */ 770 true; /* half 128b request */ 771 772 *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? 773 false : /* full 256B request */ 774 true; /* half 128b request */ 775 } 776 777 static bool hubbub31_get_dcc_compression_cap(struct hubbub *hubbub, 778 const struct dc_dcc_surface_param *input, 779 struct dc_surface_dcc_cap *output) 780 { 781 struct dc *dc = hubbub->ctx->dc; 782 enum dcc_control dcc_control; 783 unsigned int bpe; 784 enum segment_order segment_order_horz, segment_order_vert; 785 bool req128_horz_wc, req128_vert_wc; 786 787 memset(output, 0, sizeof(*output)); 788 789 if (dc->debug.disable_dcc == DCC_DISABLE) 790 return false; 791 792 if (!hubbub->funcs->dcc_support_pixel_format(input->format, 793 &bpe)) 794 return false; 795 796 if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, 797 &segment_order_horz, &segment_order_vert)) 798 return false; 799 800 hubbub31_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size, 801 input->surface_size.height, input->surface_size.width, 802 bpe, &req128_horz_wc, &req128_vert_wc); 803 804 if (!req128_horz_wc && !req128_vert_wc) { 805 dcc_control = dcc_control__256_256_xxx; 806 } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { 807 if (!req128_horz_wc) 808 dcc_control = dcc_control__256_256_xxx; 809 else if (segment_order_horz == segment_order__contiguous) 810 dcc_control = dcc_control__128_128_xxx; 811 else 812 dcc_control = dcc_control__256_64_64; 813 } else if (input->scan == SCAN_DIRECTION_VERTICAL) { 814 if (!req128_vert_wc) 815 dcc_control = dcc_control__256_256_xxx; 816 else if (segment_order_vert == segment_order__contiguous) 817 dcc_control = dcc_control__128_128_xxx; 818 else 819 dcc_control = dcc_control__256_64_64; 820 } else { 821 if ((req128_horz_wc && 822 segment_order_horz == segment_order__non_contiguous) || 823 (req128_vert_wc && 824 segment_order_vert == segment_order__non_contiguous)) 825 /* access_dir not known, must use most constraining */ 826 dcc_control = dcc_control__256_64_64; 827 else 828 /* reg128 is true for either horz and vert 829 * but segment_order is contiguous 830 */ 831 dcc_control = dcc_control__128_128_xxx; 832 } 833 834 /* Exception for 64KB_R_X */ 835 if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X)) 836 dcc_control = dcc_control__128_128_xxx; 837 838 if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && 839 dcc_control != dcc_control__256_256_xxx) 840 return false; 841 842 switch (dcc_control) { 843 case dcc_control__256_256_xxx: 844 output->grph.rgb.max_uncompressed_blk_size = 256; 845 output->grph.rgb.max_compressed_blk_size = 256; 846 output->grph.rgb.independent_64b_blks = false; 847 output->grph.rgb.dcc_controls.dcc_256_256_unconstrained = 1; 848 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 849 break; 850 case dcc_control__128_128_xxx: 851 output->grph.rgb.max_uncompressed_blk_size = 128; 852 output->grph.rgb.max_compressed_blk_size = 128; 853 output->grph.rgb.independent_64b_blks = false; 854 output->grph.rgb.dcc_controls.dcc_128_128_uncontrained = 1; 855 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 856 break; 857 case dcc_control__256_64_64: 858 output->grph.rgb.max_uncompressed_blk_size = 256; 859 output->grph.rgb.max_compressed_blk_size = 64; 860 output->grph.rgb.independent_64b_blks = true; 861 output->grph.rgb.dcc_controls.dcc_256_64_64 = 1; 862 break; 863 case dcc_control__256_128_128: 864 output->grph.rgb.max_uncompressed_blk_size = 256; 865 output->grph.rgb.max_compressed_blk_size = 128; 866 output->grph.rgb.independent_64b_blks = false; 867 output->grph.rgb.dcc_controls.dcc_256_128_128 = 1; 868 break; 869 } 870 output->capable = true; 871 output->const_color_support = true; 872 873 return true; 874 } 875 876 static int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub, 877 struct dcn_hubbub_phys_addr_config *pa_config) 878 { 879 hubbub3_init_dchub_sys_ctx(hubbub, pa_config); 880 881 dcn21_dchvm_init(hubbub); 882 883 return NUM_VMID; 884 } 885 886 static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub, 887 unsigned int dccg_ref_freq_inKhz, 888 unsigned int *dchub_ref_freq_inKhz) 889 { 890 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 891 uint32_t ref_div = 0; 892 uint32_t ref_en = 0; 893 unsigned int dc_refclk_khz = 24000; 894 895 REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div, 896 DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en); 897 898 if (ref_en) { 899 if (ref_div == 2) 900 *dchub_ref_freq_inKhz = dc_refclk_khz / 2; 901 else 902 *dchub_ref_freq_inKhz = dc_refclk_khz; 903 904 /* 905 * The external Reference Clock may change based on the board or 906 * platform requirements and the programmable integer divide must 907 * be programmed to provide a suitable DLG RefClk frequency between 908 * a minimum of 20MHz and maximum of 50MHz 909 */ 910 if (*dchub_ref_freq_inKhz < 20000 || *dchub_ref_freq_inKhz > 50000) 911 ASSERT_CRITICAL(false); 912 913 return; 914 } else { 915 *dchub_ref_freq_inKhz = dc_refclk_khz; 916 917 // HUBBUB global timer must be enabled. 918 ASSERT_CRITICAL(false); 919 return; 920 } 921 } 922 923 static const struct hubbub_funcs hubbub31_funcs = { 924 .update_dchub = hubbub2_update_dchub, 925 .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx, 926 .init_vm_ctx = hubbub2_init_vm_ctx, 927 .dcc_support_swizzle = hubbub3_dcc_support_swizzle, 928 .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, 929 .get_dcc_compression_cap = hubbub31_get_dcc_compression_cap, 930 .wm_read_state = hubbub21_wm_read_state, 931 .get_dchub_ref_freq = hubbub31_get_dchub_ref_freq, 932 .program_watermarks = hubbub31_program_watermarks, 933 .allow_self_refresh_control = hubbub1_allow_self_refresh_control, 934 .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, 935 .program_det_size = dcn31_program_det_size, 936 .program_compbuf_size = dcn31_program_compbuf_size, 937 .init_crb = dcn31_init_crb 938 }; 939 940 void hubbub31_construct(struct dcn20_hubbub *hubbub31, 941 struct dc_context *ctx, 942 const struct dcn_hubbub_registers *hubbub_regs, 943 const struct dcn_hubbub_shift *hubbub_shift, 944 const struct dcn_hubbub_mask *hubbub_mask, 945 int det_size_kb, 946 int pixel_chunk_size_kb, 947 int config_return_buffer_size_kb) 948 { 949 950 hubbub3_construct(hubbub31, ctx, hubbub_regs, hubbub_shift, hubbub_mask); 951 hubbub31->base.funcs = &hubbub31_funcs; 952 hubbub31->detile_buf_size = det_size_kb * 1024; 953 hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024; 954 hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB; 955 } 956 957