1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 5 #include "dcn60_hubbub.h" 6 #include "dm_services.h" 7 #include "reg_helper.h" 8 #include "fixed31_32.h" 9 10 #define CTX \ 11 hubbub2->base.ctx 12 #define DC_LOGGER \ 13 hubbub2->base.ctx->logger 14 #define REG(reg)\ 15 hubbub2->regs->reg 16 17 #undef FN 18 #define FN(reg_name, field_name) \ 19 hubbub2->shifts->field_name, hubbub2->masks->field_name 20 21 static void dcn60_init_crb(struct hubbub *hubbub) 22 { 23 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 24 25 REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, 26 &hubbub2->det0_size); 27 28 REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, 29 &hubbub2->det1_size); 30 31 REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, 32 &hubbub2->det2_size); 33 34 REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, 35 &hubbub2->det3_size); 36 37 REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, 38 &hubbub2->compbuf_size_segments); 39 40 REG_SET(COMPBUF_RESERVED_SPACE, 0, 41 COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32); // 256 64Bytes 42 } 43 44 static void dcn60_program_det_segments(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_seg) 45 { 46 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 47 48 switch (hubp_inst) { 49 case 0: 50 REG_UPDATE(DCHUBBUB_DET0_CTRL, 51 DET0_SIZE, det_buffer_size_seg); 52 hubbub2->det0_size = det_buffer_size_seg; 53 break; 54 case 1: 55 REG_UPDATE(DCHUBBUB_DET1_CTRL, 56 DET1_SIZE, det_buffer_size_seg); 57 hubbub2->det1_size = det_buffer_size_seg; 58 break; 59 case 2: 60 REG_UPDATE(DCHUBBUB_DET2_CTRL, 61 DET2_SIZE, det_buffer_size_seg); 62 hubbub2->det2_size = det_buffer_size_seg; 63 break; 64 case 3: 65 REG_UPDATE(DCHUBBUB_DET3_CTRL, 66 DET3_SIZE, det_buffer_size_seg); 67 hubbub2->det3_size = det_buffer_size_seg; 68 break; 69 default: 70 break; 71 } 72 if (hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 73 + hubbub2->det3_size + hubbub2->compbuf_size_segments > hubbub2->crb_size_segs) { 74 /* This may happen during seamless transition from ODM 2:1 to ODM4:1 */ 75 DC_LOG_WARNING("CRB Config Warning: DET size (%d,%d,%d,%d) + Compbuf size (%d) > CRB segments (%d)\n", 76 hubbub2->det0_size, hubbub2->det1_size, hubbub2->det2_size, hubbub2->det3_size, 77 hubbub2->compbuf_size_segments, hubbub2->crb_size_segs); 78 } 79 } 80 81 static void dcn60_program_compbuf_segments(struct hubbub *hubbub, unsigned int compbuf_size_seg, bool safe_to_increase) 82 { 83 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 84 85 if (safe_to_increase || compbuf_size_seg <= hubbub2->compbuf_size_segments) { 86 if (compbuf_size_seg > hubbub2->compbuf_size_segments) { 87 REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); 88 REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); 89 REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); 90 REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); 91 } 92 /* Should never be hit, if it is we have an erroneous hw config*/ 93 ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size 94 + hubbub2->det3_size + compbuf_size_seg <= hubbub2->crb_size_segs); 95 REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_seg); 96 hubbub2->compbuf_size_segments = compbuf_size_seg; 97 } 98 } 99 100 static void dcn60_wait_for_det_update(struct hubbub *hubbub, int hubp_inst) 101 { 102 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 103 104 switch (hubp_inst) { 105 case 0: 106 REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100000); /* 1 vupdate at 10hz */ 107 break; 108 case 1: 109 REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100000); 110 break; 111 case 2: 112 REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100000); 113 break; 114 case 3: 115 REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100000); 116 break; 117 default: 118 break; 119 } 120 } 121 122 static bool hubbub60_program_urgent_watermarks( 123 struct hubbub *hubbub, 124 union dcn_watermark_set *watermarks, 125 unsigned int refclk_mhz, 126 bool safe_to_lower) 127 { 128 (void)refclk_mhz; 129 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 130 bool wm_pending = false; 131 132 /* Repeat for water mark set A and B */ 133 /* clock state A */ 134 if (safe_to_lower || watermarks->dcn4x.a.urgent > hubbub2->watermarks.dcn4x.a.urgent) { 135 hubbub2->watermarks.dcn4x.a.urgent = watermarks->dcn4x.a.urgent; 136 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, 137 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, watermarks->dcn4x.a.urgent); 138 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" 139 "HW register value = 0x%x\n", 140 watermarks->dcn4x.a.urgent, watermarks->dcn4x.a.urgent); 141 } else if (watermarks->dcn4x.a.urgent < hubbub2->watermarks.dcn4x.a.urgent) 142 wm_pending = true; 143 144 /* determine the transfer time for a quantity of data for a particular requestor.*/ 145 if (safe_to_lower || watermarks->dcn4x.a.frac_urg_bw_flip 146 > hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip) { 147 hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip = watermarks->dcn4x.a.frac_urg_bw_flip; 148 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, 149 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->dcn4x.a.frac_urg_bw_flip); 150 } else if (watermarks->dcn4x.a.frac_urg_bw_flip 151 < hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip) 152 wm_pending = true; 153 154 if (safe_to_lower || watermarks->dcn4x.a.frac_urg_bw_nom 155 > hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom) { 156 hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom = watermarks->dcn4x.a.frac_urg_bw_nom; 157 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, 158 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->dcn4x.a.frac_urg_bw_nom); 159 } else if (watermarks->dcn4x.a.frac_urg_bw_nom 160 < hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom) 161 wm_pending = true; 162 163 if (safe_to_lower || 164 watermarks->dcn4x.a.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem) { 165 hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem = watermarks->dcn4x.a.refcyc_per_trip_to_mem; 166 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0, 167 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, watermarks->dcn4x.a.refcyc_per_trip_to_mem); 168 } else if (watermarks->dcn4x.a.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem) 169 wm_pending = true; 170 171 if (safe_to_lower || 172 watermarks->dcn4x.a.refcyc_per_meta_trip_to_mem > hubbub2->watermarks.dcn4x.a.refcyc_per_meta_trip_to_mem) { 173 hubbub2->watermarks.dcn4x.a.refcyc_per_meta_trip_to_mem = watermarks->dcn4x.a.refcyc_per_meta_trip_to_mem; 174 REG_SET(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_A, 0, 175 DCHUBBUB_ARB_REFCYC_PER_META_TRIP_A, watermarks->dcn4x.a.refcyc_per_meta_trip_to_mem); 176 } else if (watermarks->dcn4x.a.refcyc_per_meta_trip_to_mem < 177 hubbub2->watermarks.dcn4x.a.refcyc_per_meta_trip_to_mem) 178 wm_pending = true; 179 180 if (safe_to_lower || watermarks->dcn4x.a.buffer_fullness > hubbub2->watermarks.dcn4x.a.buffer_fullness) { 181 hubbub2->watermarks.dcn4x.a.buffer_fullness = watermarks->dcn4x.a.buffer_fullness; 182 REG_SET(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_A, 0, 183 DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_A, watermarks->dcn4x.a.buffer_fullness); 184 } else if (watermarks->dcn4x.a.buffer_fullness < hubbub2->watermarks.dcn4x.a.buffer_fullness) 185 wm_pending = true; 186 187 /* clock state B */ 188 if (safe_to_lower || watermarks->dcn4x.b.urgent > hubbub2->watermarks.dcn4x.b.urgent) { 189 hubbub2->watermarks.dcn4x.b.urgent = watermarks->dcn4x.b.urgent; 190 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, 191 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, watermarks->dcn4x.b.urgent); 192 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" 193 "HW register value = 0x%x\n", 194 watermarks->dcn4x.b.urgent, watermarks->dcn4x.b.urgent); 195 } else if (watermarks->dcn4x.b.urgent < hubbub2->watermarks.dcn4x.b.urgent) 196 wm_pending = true; 197 198 /* determine the transfer time for a quantity of data for a particular requestor.*/ 199 if (safe_to_lower || watermarks->dcn4x.b.frac_urg_bw_flip 200 > hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip) { 201 hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip = watermarks->dcn4x.b.frac_urg_bw_flip; 202 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, 203 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->dcn4x.b.frac_urg_bw_flip); 204 } else if (watermarks->dcn4x.b.frac_urg_bw_flip 205 < hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip) 206 wm_pending = true; 207 208 if (safe_to_lower || watermarks->dcn4x.b.frac_urg_bw_nom 209 > hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom) { 210 hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom = watermarks->dcn4x.b.frac_urg_bw_nom; 211 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, 212 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->dcn4x.b.frac_urg_bw_nom); 213 } else if (watermarks->dcn4x.b.frac_urg_bw_nom 214 < hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom) 215 wm_pending = true; 216 217 if (safe_to_lower || 218 watermarks->dcn4x.b.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem) { 219 hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem = watermarks->dcn4x.b.refcyc_per_trip_to_mem; 220 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0, 221 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, watermarks->dcn4x.b.refcyc_per_trip_to_mem); 222 } else if (watermarks->dcn4x.b.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem) 223 wm_pending = true; 224 225 if (safe_to_lower || 226 watermarks->dcn4x.b.refcyc_per_meta_trip_to_mem > hubbub2->watermarks.dcn4x.b.refcyc_per_meta_trip_to_mem) { 227 hubbub2->watermarks.dcn4x.b.refcyc_per_meta_trip_to_mem = watermarks->dcn4x.b.refcyc_per_meta_trip_to_mem; 228 REG_SET(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B, 0, 229 DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B, watermarks->dcn4x.b.refcyc_per_meta_trip_to_mem); 230 } else if (watermarks->dcn4x.b.refcyc_per_meta_trip_to_mem < 231 hubbub2->watermarks.dcn4x.b.refcyc_per_meta_trip_to_mem) 232 wm_pending = true; 233 234 if (safe_to_lower || watermarks->dcn4x.b.buffer_fullness > hubbub2->watermarks.dcn4x.b.buffer_fullness) { 235 hubbub2->watermarks.dcn4x.b.buffer_fullness = watermarks->dcn4x.b.buffer_fullness; 236 REG_SET(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_B, 0, 237 DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_B, watermarks->dcn4x.b.buffer_fullness); 238 } else if (watermarks->dcn4x.b.buffer_fullness < hubbub2->watermarks.dcn4x.b.buffer_fullness) 239 wm_pending = true; 240 241 return wm_pending; 242 } 243 244 static bool hubbub60_program_pstate_watermarks( 245 struct hubbub *hubbub, 246 union dcn_watermark_set *watermarks, 247 unsigned int refclk_mhz, 248 bool safe_to_lower) 249 { 250 (void)refclk_mhz; 251 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 252 bool wm_pending = false; 253 254 /* Section for UCLK_PSTATE_CHANGE_WATERMARKS, used for UCLK change (UCLK/FCLK PState) */ 255 /* clock state A */ 256 if (safe_to_lower || watermarks->dcn4x.a.uclk_pstate 257 > hubbub2->watermarks.dcn4x.a.uclk_pstate) { 258 hubbub2->watermarks.dcn4x.a.uclk_pstate = 259 watermarks->dcn4x.a.uclk_pstate; 260 REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, 0, 261 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, watermarks->dcn4x.a.uclk_pstate); 262 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" 263 "HW register value = 0x%x\n\n", 264 watermarks->dcn4x.a.uclk_pstate, watermarks->dcn4x.a.uclk_pstate); 265 } else if (watermarks->dcn4x.a.uclk_pstate 266 < hubbub2->watermarks.dcn4x.a.uclk_pstate) 267 wm_pending = true; 268 269 /* clock state B */ 270 if (safe_to_lower || watermarks->dcn4x.b.uclk_pstate 271 > hubbub2->watermarks.dcn4x.b.uclk_pstate) { 272 hubbub2->watermarks.dcn4x.b.uclk_pstate = 273 watermarks->dcn4x.b.uclk_pstate; 274 REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, 0, 275 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, watermarks->dcn4x.b.uclk_pstate); 276 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" 277 "HW register value = 0x%x\n\n", 278 watermarks->dcn4x.b.uclk_pstate, watermarks->dcn4x.b.uclk_pstate); 279 } else if (watermarks->dcn4x.b.uclk_pstate 280 < hubbub2->watermarks.dcn4x.b.uclk_pstate) 281 wm_pending = true; 282 283 /* Section for UCLK_PSTATE_CHANGE_WATERMARKS1 (Reserved set, can be used for FCLK Pstate only) */ 284 if (safe_to_lower || watermarks->dcn4x.a.fclk_pstate 285 > hubbub2->watermarks.dcn4x.a.fclk_pstate) { 286 hubbub2->watermarks.dcn4x.a.fclk_pstate = 287 watermarks->dcn4x.a.fclk_pstate; 288 REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, 0, 289 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, watermarks->dcn4x.a.fclk_pstate); 290 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK1_A calculated =%d\n" 291 "HW register value = 0x%x\n\n", 292 watermarks->dcn4x.a.fclk_pstate, watermarks->dcn4x.a.fclk_pstate); 293 } else if (watermarks->dcn4x.a.fclk_pstate 294 < hubbub2->watermarks.dcn4x.a.fclk_pstate) 295 wm_pending = true; 296 297 /* clock state B */ 298 if (safe_to_lower || watermarks->dcn4x.b.fclk_pstate 299 > hubbub2->watermarks.dcn4x.b.fclk_pstate) { 300 hubbub2->watermarks.dcn4x.b.fclk_pstate = 301 watermarks->dcn4x.b.fclk_pstate; 302 REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, 0, 303 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, watermarks->dcn4x.b.fclk_pstate); 304 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK1_B calculated =%d\n" 305 "HW register value = 0x%x\n\n", 306 watermarks->dcn4x.b.fclk_pstate, watermarks->dcn4x.b.fclk_pstate); 307 } else if (watermarks->dcn4x.b.fclk_pstate 308 < hubbub2->watermarks.dcn4x.b.fclk_pstate) 309 wm_pending = true; 310 311 /* Section for FCLK_PSTATE_CHANGE_WATERMARKS, instance 0 used for G7 PPT */ 312 /* clock state A */ 313 if (safe_to_lower || watermarks->dcn4x.a.ppt 314 > hubbub2->watermarks.dcn4x.a.ppt) { 315 hubbub2->watermarks.dcn4x.a.ppt = 316 watermarks->dcn4x.a.ppt; 317 REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, 0, 318 DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, watermarks->dcn4x.a.ppt); 319 DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_A calculated =%d\n" 320 "HW register value = 0x%x\n\n", 321 watermarks->dcn4x.a.ppt, watermarks->dcn4x.a.ppt); 322 } else if (watermarks->dcn4x.a.ppt 323 < hubbub2->watermarks.dcn4x.a.ppt) 324 wm_pending = true; 325 326 /* clock state B */ 327 if (safe_to_lower || watermarks->dcn4x.b.ppt 328 > hubbub2->watermarks.dcn4x.b.ppt) { 329 hubbub2->watermarks.dcn4x.b.ppt = 330 watermarks->dcn4x.b.ppt; 331 REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, 0, 332 DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, watermarks->dcn4x.b.ppt); 333 DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_B calculated =%d\n" 334 "HW register value = 0x%x\n\n", 335 watermarks->dcn4x.b.ppt, watermarks->dcn4x.b.ppt); 336 } else if (watermarks->dcn4x.b.ppt 337 < hubbub2->watermarks.dcn4x.b.ppt) 338 wm_pending = true; 339 340 /* Section for FCLK_CHANGE_WATERMARKS1, instance 1 used for G7 Temp Read */ 341 if (safe_to_lower || watermarks->dcn4x.a.temp_read 342 > hubbub2->watermarks.dcn4x.a.temp_read) { 343 hubbub2->watermarks.dcn4x.a.temp_read = 344 watermarks->dcn4x.a.temp_read; 345 REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_A, 0, 346 DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_A, watermarks->dcn4x.a.temp_read); 347 DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK1_A calculated =%d\n" 348 "HW register value = 0x%x\n\n", 349 watermarks->dcn4x.a.temp_read, watermarks->dcn4x.a.temp_read); 350 } else if (watermarks->dcn4x.a.temp_read 351 < hubbub2->watermarks.dcn4x.a.temp_read) 352 wm_pending = true; 353 354 /* clock state B */ 355 if (safe_to_lower || watermarks->dcn4x.b.temp_read 356 > hubbub2->watermarks.dcn4x.b.temp_read) { 357 hubbub2->watermarks.dcn4x.b.temp_read = 358 watermarks->dcn4x.b.temp_read; 359 REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_B, 0, 360 DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_B, watermarks->dcn4x.b.temp_read); 361 DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK1_B calculated =%d\n" 362 "HW register value = 0x%x\n\n", 363 watermarks->dcn4x.b.temp_read, watermarks->dcn4x.b.temp_read); 364 } else if (watermarks->dcn4x.b.temp_read 365 < hubbub2->watermarks.dcn4x.b.temp_read) 366 wm_pending = true; 367 368 return wm_pending; 369 } 370 371 static bool hubbub60_program_stutter_watermarks( 372 struct hubbub *hubbub, 373 union dcn_watermark_set *watermarks, 374 unsigned int refclk_mhz, 375 bool safe_to_lower) 376 { 377 (void)refclk_mhz; 378 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 379 bool wm_pending = false; 380 381 /* clock state A */ 382 if (safe_to_lower || watermarks->dcn4x.a.sr_enter 383 > hubbub2->watermarks.dcn4x.a.sr_enter) { 384 hubbub2->watermarks.dcn4x.a.sr_enter = 385 watermarks->dcn4x.a.sr_enter; 386 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, 387 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, watermarks->dcn4x.a.sr_enter); 388 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" 389 "HW register value = 0x%x\n", 390 watermarks->dcn4x.a.sr_enter, watermarks->dcn4x.a.sr_enter); 391 // On dGPU Z states are N/A, so program unused Stutter Enter wm A with the same value 392 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_A, 0, 393 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_A, watermarks->dcn4x.a.sr_enter); 394 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_A, 0, 395 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_A, watermarks->dcn4x.a.sr_enter); 396 397 } 398 /* possible 2nd stutter watermark. PMFW to choose which one to use */ 399 if (safe_to_lower || watermarks->dcn4x.a.sr_enter_low_power 400 > hubbub2->watermarks.dcn4x.a.sr_enter_low_power) { 401 hubbub2->watermarks.dcn4x.a.sr_enter_low_power = 402 watermarks->dcn4x.a.sr_enter_low_power; 403 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_A, 0, 404 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_A, watermarks->dcn4x.a.sr_enter_low_power); 405 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK1_A calculated =%d\n" 406 "HW register value = 0x%x\n", 407 watermarks->dcn4x.a.sr_enter_low_power, watermarks->dcn4x.a.sr_enter_low_power); 408 } 409 410 if (watermarks->dcn4x.a.sr_enter 411 < hubbub2->watermarks.dcn4x.a.sr_enter || 412 watermarks->dcn4x.a.sr_enter_low_power 413 < hubbub2->watermarks.dcn4x.a.sr_enter_low_power) 414 wm_pending = true; 415 416 if (safe_to_lower || watermarks->dcn4x.a.sr_exit 417 > hubbub2->watermarks.dcn4x.a.sr_exit) { 418 hubbub2->watermarks.dcn4x.a.sr_exit = 419 watermarks->dcn4x.a.sr_exit; 420 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, 421 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, watermarks->dcn4x.a.sr_exit); 422 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" 423 "HW register value = 0x%x\n", 424 watermarks->dcn4x.a.sr_exit, watermarks->dcn4x.a.sr_exit); 425 // On dGPU Z states are N/A, so program unused Stutter Exit wm A with the same value 426 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_A, 0, 427 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_A, watermarks->dcn4x.a.sr_exit); 428 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_A, 0, 429 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_A, watermarks->dcn4x.a.sr_exit); 430 } 431 /* possible 2nd stutter exit watermark. PMFW to choose which one to use */ 432 if (safe_to_lower || watermarks->dcn4x.a.sr_exit_low_power 433 > hubbub2->watermarks.dcn4x.a.sr_exit_low_power) { 434 hubbub2->watermarks.dcn4x.a.sr_exit_low_power = 435 watermarks->dcn4x.a.sr_exit_low_power; 436 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_A, 0, 437 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_A, watermarks->dcn4x.a.sr_exit_low_power); 438 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK1_A calculated =%d\n" 439 "HW register value = 0x%x\n", 440 watermarks->dcn4x.a.sr_exit_low_power, watermarks->dcn4x.a.sr_exit_low_power); 441 } 442 443 if (watermarks->dcn4x.a.sr_exit 444 < hubbub2->watermarks.dcn4x.a.sr_exit || 445 watermarks->dcn4x.a.sr_exit_low_power 446 < hubbub2->watermarks.dcn4x.a.sr_exit_low_power) 447 wm_pending = true; 448 449 /* clock state B */ 450 if (safe_to_lower || watermarks->dcn4x.b.sr_enter 451 > hubbub2->watermarks.dcn4x.b.sr_enter) { 452 hubbub2->watermarks.dcn4x.b.sr_enter = 453 watermarks->dcn4x.b.sr_enter; 454 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, 455 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, watermarks->dcn4x.b.sr_enter); 456 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" 457 "HW register value = 0x%x\n", 458 watermarks->dcn4x.b.sr_enter, watermarks->dcn4x.b.sr_enter); 459 // On dGPU Z states are N/A, so program unused Stutter Enter wm B with the same value 460 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_B, 0, 461 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_B, watermarks->dcn4x.b.sr_enter); 462 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_B, 0, 463 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_B, watermarks->dcn4x.b.sr_enter); 464 } 465 /* possible 2nd stutter enter watermark. PMFW to choose which one to use */ 466 if (safe_to_lower || watermarks->dcn4x.b.sr_enter_low_power 467 > hubbub2->watermarks.dcn4x.b.sr_enter_low_power) { 468 hubbub2->watermarks.dcn4x.b.sr_enter_low_power = 469 watermarks->dcn4x.b.sr_enter_low_power; 470 REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_B, 0, 471 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_B, watermarks->dcn4x.b.sr_enter_low_power); 472 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK1_B calculated =%d\n" 473 "HW register value = 0x%x\n", 474 watermarks->dcn4x.b.sr_enter_low_power, watermarks->dcn4x.b.sr_enter_low_power); 475 } 476 477 if (watermarks->dcn4x.b.sr_enter 478 < hubbub2->watermarks.dcn4x.b.sr_enter || 479 watermarks->dcn4x.b.sr_enter_low_power 480 < hubbub2->watermarks.dcn4x.b.sr_enter_low_power) 481 wm_pending = true; 482 483 if (safe_to_lower || watermarks->dcn4x.b.sr_exit 484 > hubbub2->watermarks.dcn4x.b.sr_exit) { 485 hubbub2->watermarks.dcn4x.b.sr_exit = 486 watermarks->dcn4x.b.sr_exit; 487 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, 488 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, watermarks->dcn4x.b.sr_exit); 489 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" 490 "HW register value = 0x%x\n", 491 watermarks->dcn4x.b.sr_exit, watermarks->dcn4x.b.sr_exit); 492 // On dGPU Z states are N/A, so program unused Stutter Exit wm B with the same value 493 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_B, 0, 494 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_B, watermarks->dcn4x.b.sr_exit); 495 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_B, 0, 496 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_B, watermarks->dcn4x.b.sr_exit); 497 } 498 /* possible 2nd stutter exit watermark. PMFW to choose which one to use */ 499 if (safe_to_lower || watermarks->dcn4x.b.sr_exit_low_power 500 > hubbub2->watermarks.dcn4x.b.sr_exit_low_power) { 501 hubbub2->watermarks.dcn4x.b.sr_exit_low_power = 502 watermarks->dcn4x.b.sr_exit_low_power; 503 REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_B, 0, 504 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_B, watermarks->dcn4x.b.sr_exit_low_power); 505 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK1_B calculated =%d\n" 506 "HW register value = 0x%x\n", 507 watermarks->dcn4x.b.sr_exit_low_power, watermarks->dcn4x.b.sr_exit_low_power); 508 } 509 510 if (watermarks->dcn4x.b.sr_exit 511 < hubbub2->watermarks.dcn4x.b.sr_exit || 512 watermarks->dcn4x.b.sr_exit_low_power 513 < hubbub2->watermarks.dcn4x.b.sr_exit_low_power) 514 wm_pending = true; 515 516 return wm_pending; 517 } 518 519 static bool hubbub60_program_watermarks( 520 struct hubbub *hubbub, 521 union dcn_watermark_set *watermarks, 522 unsigned int refclk_mhz, 523 bool safe_to_lower) 524 { 525 bool wm_pending = false; 526 527 if (hubbub60_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 528 wm_pending = true; 529 530 if (hubbub60_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 531 wm_pending = true; 532 533 if (hubbub60_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) 534 wm_pending = true; 535 536 hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); 537 538 return wm_pending; 539 } 540 541 /* Copy values from WM set A to all other sets */ 542 static void hubbub60_init_watermarks(struct hubbub *hubbub) 543 { 544 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 545 uint32_t reg; 546 547 reg = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); 548 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, reg); 549 550 reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A); 551 REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, reg); 552 553 reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A); 554 REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, reg); 555 556 reg = REG_READ(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A); 557 REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, reg); 558 559 reg = REG_READ(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_A); 560 REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B, reg); 561 562 reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); 563 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, reg); 564 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_A, reg); 565 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_B, reg); 566 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_A, reg); 567 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_B, reg); 568 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_A, reg); 569 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_B, reg); 570 571 reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); 572 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, reg); 573 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_A, reg); 574 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_B, reg); 575 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_A, reg); 576 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_B, reg); 577 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_A, reg); 578 REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_B, reg); 579 580 reg = REG_READ(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A); 581 REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, reg); 582 reg = REG_READ(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A); 583 REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, reg); 584 585 reg = REG_READ(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A); 586 REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, reg); 587 reg = REG_READ(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_A); 588 REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_B, reg); 589 590 reg = REG_READ(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_A); 591 REG_WRITE(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_B, reg); 592 } 593 594 static void hubbub60_force_wm_propagate_to_pipes(struct hubbub *hubbub) 595 { 596 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 597 598 REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, 599 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, hubbub2->watermarks.dcn4x.a.urgent); 600 601 } 602 603 static void hubbub60_wm_read_state(struct hubbub *hubbub, 604 struct dcn_hubbub_wm *wm) 605 { 606 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 607 struct dcn_hubbub_wm_set *s; 608 609 memset(wm, 0, sizeof(struct dcn_hubbub_wm)); 610 611 s = &wm->sets[0]; 612 s->wm_set = 0; 613 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 614 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent); 615 616 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 617 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter); 618 619 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 620 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit); 621 622 REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, 623 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, &s->dram_clk_change); 624 625 REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, 626 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, &s->fclk_pstate_change); 627 628 s = &wm->sets[1]; 629 s->wm_set = 1; 630 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 631 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent); 632 633 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 634 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter); 635 636 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 637 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit); 638 639 REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, 640 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, &s->dram_clk_change); 641 642 REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, 643 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, &s->fclk_pstate_change); 644 } 645 646 /** 647 * @brief Resets the performance monitor for the DCN 6.0 hubbub. 648 * 649 * This function resets the performance monitoring counters and related 650 * state for the specified hubbub instance. It is typically called to 651 * clear performance statistics before starting a new measurement period. 652 * 653 * @param hubbub Pointer to the hubbub structure to reset performance monitoring 654 * for. 655 */ 656 static void hubbub60_perfmon_reset(struct hubbub *hubbub) 657 { 658 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 659 660 REG_WRITE(DC_PERFMON5_PERFMON_CNTL, 0); 661 REG_WRITE(DC_PERFMON5_PERFMON_CNTL2, 0); 662 REG_WRITE(DC_PERFMON5_PERFCOUNTER_STATE, 0); 663 REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, 0xFF00); 664 REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_LOW, 0); 665 REG_WRITE(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0); 666 REG_WRITE(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0); 667 } 668 669 /** 670 * Starts measuring memory latencies (maximum, minimum, and average) in 671 * nanoseconds using performance counters. 672 * 673 * This function configures and enables performance monitoring counters 4, 5, 674 * 6, and 7 to track memory latency within the hubbub hardware block. The 675 * function sets up: 676 * 677 * Counter 4: Counts the number of memory latency samples 678 * (PERFCOUNTER_INC_MODE = 0x3 for positive edge counting) 679 * Counter 5: Accumulates total latency cycles for average calculation 680 * (PERFCOUNTER_INC_MODE = 0x2 for LSB level counting) 681 * Counter 6: Tracks maximum latency values (PERFCOUNTER_COUNTED_VALUE_TYPE = 682 * 0x1, event 74 for frame_window_refclk) 683 * Counter 7: Tracks minimum latency values (PERFCOUNTER_COUNTED_VALUE_TYPE = 684 * 0x2, event 74 for frame_window_refclk) 685 * 686 * Configuration details: 687 * - Uses Data Fabric latency source (LATENCY_SOURCE_SEL = 0x2) 688 * - Monitors all request types (UTM_FILTER_SEL = 0) 689 * - Event 79 for memory latency monitoring (counters 4, 5) 690 * - Event 74 for frame_window_refclk timing (counters 6, 7) 691 * - Counters 6 and 7 use independent state mode with restart enabled 692 * - All counters run on refclk cycles for consistent timing measurement 693 * 694 * @param hubbub Pointer to the hubbub structure representing the hardware 695 * instance. 696 */ 697 static void hubbub60_perfmon_start_measuring_memory_latencies( 698 struct hubbub *hubbub) 699 { 700 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 701 702 /* configure measurement control */ 703 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 704 DCHUBBUB_LATENCY_CNT_EN, 0x1, 705 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 706 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 707 LATENCY_SOURCE_SEL, 0x2, 708 UTM_FILTER_SEL, 0); 709 710 /* program counter 4 to count until duration */ 711 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 712 PERFCOUNTER_CNTL_SEL, 0x4, 713 PERFCOUNTER_EVENT_SEL, 79, 714 PERFCOUNTER_CVALUE_SEL, 0x0, 715 PERFCOUNTER_INC_MODE, 0x3, 716 PERFCOUNTER_HW_CNTL_SEL, 0x0, 717 PERFCOUNTER_RUNEN_MODE, 0x0, 718 PERFCOUNTER_RESTART_EN, 0x0, 719 PERFCOUNTER_ACTIVE, 0x1); 720 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 721 PERFCOUNTER_CNTL2_SEL, 0x4, 722 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, 723 PERFCOUNTER_HW_STOP1_SEL, 0x0, 724 PERFCOUNTER_HW_STOP2_SEL, 0x0); 725 726 /* program counter 5 to measure accumulated latency */ 727 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 728 PERFCOUNTER_CNTL_SEL, 0x5, 729 PERFCOUNTER_EVENT_SEL, 79, 730 PERFCOUNTER_CVALUE_SEL, 0x0, 731 PERFCOUNTER_INC_MODE, 0x2, 732 PERFCOUNTER_HW_CNTL_SEL, 0x0, 733 PERFCOUNTER_RUNEN_MODE, 0x0, 734 PERFCOUNTER_RESTART_EN, 0x0, 735 PERFCOUNTER_ACTIVE, 1); 736 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 737 PERFCOUNTER_CNTL2_SEL, 0x5, 738 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, 739 PERFCOUNTER_HW_STOP1_SEL, 0x0, 740 PERFCOUNTER_HW_STOP2_SEL, 0x0); 741 742 /* program counter 6 to measure max latency */ 743 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 744 PERFCOUNTER_CNTL_SEL, 0x6, 745 PERFCOUNTER_EVENT_SEL, 74, 746 PERFCOUNTER_CVALUE_SEL, 0x0, 747 PERFCOUNTER_INC_MODE, 0x2, 748 PERFCOUNTER_HW_CNTL_SEL, 0x0, 749 PERFCOUNTER_RUNEN_MODE, 0x0, 750 PERFCOUNTER_RESTART_EN, 0x1, 751 PERFCOUNTER_ACTIVE, 1); 752 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 753 PERFCOUNTER_CNTL2_SEL, 0x6, 754 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x1, 755 PERFCOUNTER_HW_STOP1_SEL, 0x0, 756 PERFCOUNTER_HW_STOP2_SEL, 0x0); 757 758 /* program counter 7 to measure min latency */ 759 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 760 PERFCOUNTER_CNTL_SEL, 0x7, 761 PERFCOUNTER_EVENT_SEL, 74, 762 PERFCOUNTER_CVALUE_SEL, 0x0, 763 PERFCOUNTER_INC_MODE, 0x2, 764 PERFCOUNTER_HW_CNTL_SEL, 0x0, 765 PERFCOUNTER_RUNEN_MODE, 0x0, 766 PERFCOUNTER_RESTART_EN, 0x1, 767 PERFCOUNTER_ACTIVE, 1); 768 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 769 PERFCOUNTER_CNTL2_SEL, 0x7, 770 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x2, 771 PERFCOUNTER_HW_STOP1_SEL, 0x0, 772 PERFCOUNTER_HW_STOP2_SEL, 0x0); 773 774 /* Program perfcounter states */ 775 REG_SET_4(DC_PERFMON5_PERFCOUNTER_STATE, 0, 776 PERFCOUNTER_STATE_SEL6, 0x1, 777 PERFCOUNTER_CNT6_STATE, 0x3, 778 PERFCOUNTER_STATE_SEL7, 0x1, 779 PERFCOUNTER_CNT7_STATE, 0x3); 780 781 REG_SET_2(DC_PERFMON5_PERFMON_CNTL2, 0, 782 PERFMON_RUN_ENABLE_START_SEL, 0x0, 783 PERFMON_RUN_ENABLE_STOP_SEL, 0); 784 785 /* start the counters */ 786 REG_SET_2(DC_PERFMON5_PERFMON_CNTL, 0, 787 PERFMON_STATE, 0x1, 788 PERFMON_RPT_COUNT, 0xFFFFF); 789 } 790 791 /** 792 * @brief Reads the current performance monitor results and calculates 793 * memory latencies in nanoseconds. 794 * 795 * This function reads the values from the DCN 6.0 hubbub performance monitor 796 * counters, then calculates the minimum, maximum, and average observed 797 * memory latencies in nanoseconds. 798 * 799 * @param hubbub Pointer to the hubbub structure representing the hardware 800 * instance. 801 * @param refclk_mhz Reference clock frequency in MHz, used for time 802 * conversion. 803 * @param min_latency_ns Optional pointer to store the minimum latency in 804 * nanoseconds. 805 * @param max_latency_ns Optional pointer to store the maximum latency in 806 * nanoseconds. 807 * @param avg_latency_ns Optional pointer to store the average latency in 808 * nanoseconds. 809 * 810 * @return The number of memory latency samples measured as a 32-bit 811 * unsigned integer. 812 */ 813 static uint32_t hubbub60_perfmon_get_memory_latencies_ns( 814 struct hubbub *hubbub, uint32_t refclk_mhz, 815 uint32_t *min_latency_ns, uint32_t *max_latency_ns, 816 uint32_t *avg_latency_ns) 817 { 818 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 819 uint32_t count4 = 0, count5 = 0, count6 = 0, count7 = 0; 820 struct fixed31_32 temp; 821 822 ASSERT(refclk_mhz != 0); 823 if (refclk_mhz == 0) 824 return 0; 825 826 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x4); 827 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count4); 828 829 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x5); 830 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count5); 831 832 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x6); 833 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count6); 834 835 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x7); 836 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count7); 837 838 if (avg_latency_ns && count4) { 839 temp = dc_fixpt_from_fraction(count5, count4); 840 temp = dc_fixpt_div_int(temp, refclk_mhz); 841 *avg_latency_ns = dc_fixpt_ceil(dc_fixpt_mul_int(temp, 1000)); 842 } 843 844 if (max_latency_ns) { 845 temp = dc_fixpt_from_fraction(count6, refclk_mhz); 846 *max_latency_ns = dc_fixpt_ceil(dc_fixpt_mul_int(temp, 1000)); 847 } 848 849 if (min_latency_ns) { 850 temp = dc_fixpt_from_fraction(count7, refclk_mhz); 851 *min_latency_ns = dc_fixpt_ceil(dc_fixpt_mul_int(temp, 1000)); 852 } 853 854 return count4; 855 } 856 857 /** 858 * Starts measuring urgent assertion and deassertion counts using 859 * performance counters. 860 * 861 * This function configures and enables performance monitoring counters 0, 862 * 1, and 4 to track urgent assertion and deassertion events within the 863 * hubbub hardware block. The function sets up: 864 * 865 * Counter 0: Counts urgent assertion events (PERFCOUNTER_INC_MODE = 0x3 for 866 * positive edge counting) 867 * Counter 1: Counts urgent deassertion events (PERFCOUNTER_INC_MODE = 0x4 for 868 * negative edge counting) 869 * Counter 4: Gets the current timestamp in reference clock cycles 870 * 871 * Configuration details: 872 * - Uses UTM urgent latency source (LATENCY_SOURCE_SEL = 0x4) 873 * - Monitors all request types (UTM_FILTER_SEL = 0) 874 * - Event 65 for urgent assertion/deassertion monitoring (counters 0, 1) 875 * - Event 19 for current timestamp (counter 4) 876 * 877 * @param hubbub Pointer to the hubbub structure representing the hardware 878 * instance. 879 */ 880 static void hubbub60_perfmon_start_measuring_urgent_assertion_count( 881 struct hubbub *hubbub) 882 { 883 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 884 885 /* configure measurement control */ 886 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 887 DCHUBBUB_LATENCY_CNT_EN, 0x1, 888 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 889 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 890 LATENCY_SOURCE_SEL, 0x4, 891 UTM_FILTER_SEL, 0); 892 893 /* program counter 0 to urgent assertions */ 894 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 895 PERFCOUNTER_CNTL_SEL, 0x0, 896 PERFCOUNTER_EVENT_SEL, 65, 897 PERFCOUNTER_CVALUE_SEL, 0x0, 898 PERFCOUNTER_INC_MODE, 0x3, 899 PERFCOUNTER_HW_CNTL_SEL, 0x0, 900 PERFCOUNTER_RUNEN_MODE, 0x1, 901 PERFCOUNTER_RESTART_EN, 0x0, 902 PERFCOUNTER_ACTIVE, 1); 903 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 904 PERFCOUNTER_CNTL2_SEL, 0x0, 905 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, 906 PERFCOUNTER_HW_STOP1_SEL, 0x0, 907 PERFCOUNTER_HW_STOP2_SEL, 0x0); 908 909 /* program counter 1 to urgent assertions */ 910 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 911 PERFCOUNTER_CNTL_SEL, 0x1, 912 PERFCOUNTER_EVENT_SEL, 65, 913 PERFCOUNTER_CVALUE_SEL, 0x0, 914 PERFCOUNTER_INC_MODE, 0x4, 915 PERFCOUNTER_HW_CNTL_SEL, 0x0, 916 PERFCOUNTER_RUNEN_MODE, 0x1, 917 PERFCOUNTER_RESTART_EN, 0x0, 918 PERFCOUNTER_ACTIVE, 1); 919 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 920 PERFCOUNTER_CNTL2_SEL, 0x1, 921 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, 922 PERFCOUNTER_HW_STOP1_SEL, 0x0, 923 PERFCOUNTER_HW_STOP2_SEL, 0x0); 924 925 /* program counter 4 to get current timestamp in refclk cycles */ 926 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 927 PERFCOUNTER_CNTL_SEL, 0x4, 928 PERFCOUNTER_EVENT_SEL, 19, 929 PERFCOUNTER_CVALUE_SEL, 0x0, 930 PERFCOUNTER_INC_MODE, 0x2, 931 PERFCOUNTER_HW_CNTL_SEL, 0x0, 932 PERFCOUNTER_RUNEN_MODE, 0x0, 933 PERFCOUNTER_RESTART_EN, 0x0, 934 PERFCOUNTER_ACTIVE, 1); 935 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 936 PERFCOUNTER_CNTL2_SEL, 0x4, 937 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, 938 PERFCOUNTER_HW_STOP1_SEL, 0x0, 939 PERFCOUNTER_HW_STOP2_SEL, 0x0); 940 941 REG_WRITE(DC_PERFMON5_PERFCOUNTER_STATE, 0); 942 943 /* start the counters */ 944 REG_SET_2(DC_PERFMON5_PERFMON_CNTL, 0, 945 PERFMON_STATE, 0x1, 946 PERFMON_RPT_COUNT, 0xFFFFF); 947 } 948 949 /** 950 * @brief Reads the urgent assertion and deassertion counts from the 951 * performance monitor. 952 * 953 * This function reads the values from the DCN 6.0 hubbub performance monitor 954 * counters for urgent assertion and deassertion events. It also retrieves 955 * a timestamp in microseconds based on the reference clock frequency. 956 * 957 * @param hubbub Pointer to the hubbub structure representing the hardware 958 * instance. 959 * @param refclk_mhz Reference clock frequency in MHz, used for time 960 * conversion. 961 * @param assertion_count Optional pointer to store the urgent assertion count. 962 * @param deassertion_count Optional pointer to store the urgent deassertion 963 * count. 964 * @param timestamp_us Optional pointer to store the timestamp in microseconds. 965 * 966 * @return A boolean indicating whether the assertion or deassertion counts 967 * have been updated since the last read. 968 */ 969 static bool hubbub60_perfmon_get_urgent_assertion_count( 970 struct hubbub *hubbub, uint32_t refclk_mhz, 971 uint32_t *assertion_count, uint32_t *deassertion_count, 972 uint32_t *timestamp_us) 973 { 974 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 975 uint32_t count0 = 0, count1 = 0, count4 = 0; 976 bool updated = false; 977 978 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x0); 979 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count0); 980 981 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x1); 982 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count1); 983 984 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x4); 985 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count4); 986 987 if (refclk_mhz != 0 && timestamp_us) 988 *timestamp_us = count4 / refclk_mhz; 989 990 if (assertion_count && (*assertion_count != count0)) { 991 *assertion_count = count0; 992 updated = true; 993 } 994 995 if (deassertion_count && (*deassertion_count != count1)) { 996 *deassertion_count = count1; 997 updated = true; 998 } 999 1000 return updated; 1001 } 1002 1003 /** 1004 * @brief Configures the performance monitor to measure the urgent ramp 1005 * latency. 1006 * 1007 * This function configures the performance monitoring counters to measure 1008 * the urgent ramp latency. It uses hardware counters 0, 1, 2, 4, 5, 6, 7 1009 * for this purpose: 1010 * 1011 * Counter 4: 1012 * - Purpose: Begins counting on the first urgent data return, marking 1013 * the start of the first rolling window (t_win). 1014 * - Behavior: Signals a stop event at the end of every t_win period. 1015 * 1016 * Counter 5: 1017 * - Purpose: Starts counting at the beginning of t_win. 1018 * - Behavior: Signals a stop event at 1/3 of t_win. 1019 * 1020 * Counter 6: 1021 * - Purpose: Starts counting at the beginning of t_win. 1022 * - Behavior: Signals a stop event at 2/3 of t_win. 1023 * 1024 * After the first t_win period, counters 4, 5, and 6 will generate stop 1025 * events every 1/3 t_win. These stop events trigger counters 0, 1, and 2 1026 * respectively: 1027 * 1028 * Counter 0, 1, 2: 1029 * - Purpose: Track the total accumulated data received during each 1/3 1030 * t_win interval. 1031 * - Behavior: Each counter starts on its respective stop event and stops 1032 * after 1/3 t_win. 1033 * - Threshold: If the total data size exceeds a precalculated threshold, 1034 * it indicates bandwidth higher than the target for that 1/3 t_win 1035 * period. 1036 * - When the counter reaches the threshold cvalue, it signals a stop 1037 * interrupt for counter 7. 1038 * 1039 * Counter 7: 1040 * - Purpose: Measures the total time in reference clock (refclk) cycles. 1041 * - Behavior: Starts from the first data return and stops when any of 1042 * counters 0, 1, or 2 signal a stop interrupt. 1043 * - Usage: The total time counted in refclk cycles is converted into 1044 * urgent ramp latency. 1045 * 1046 * @param hubbub Pointer to the hubbub structure representing the hardware 1047 * instance. 1048 * @param params Pointer to the urgent latency measurement parameters. 1049 */ 1050 static void hubbub60_perfmon_start_measuring_urgent_ramp_latency( 1051 struct hubbub *hubbub, 1052 const struct hubbub_urgent_latency_params *params) 1053 { 1054 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1055 1056 /* configure measurement control */ 1057 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 1058 DCHUBBUB_LATENCY_CNT_EN, 0x1, 1059 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 1060 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 1061 LATENCY_SOURCE_SEL, 0x4, // df_urgent 1062 UTM_FILTER_SEL, 0x1); // urgent requests 1063 1064 /* program counter 0 as the first bw counter */ 1065 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1066 PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0 1067 PERFCOUNTER_EVENT_SEL, 257, // ROB output valid event 1068 PERFCOUNTER_CVALUE_SEL, 0x7, // use cvalue bits 47-36 1069 PERFCOUNTER_HW_CNTL_SEL, 0x1, // individual mode 1070 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1071 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1072 PERFCOUNTER_RESTART_EN, 0x1, // restart the counter while it is active 1073 PERFCOUNTER_INT_EN, 0x1, // signal when the measurement is complete 1074 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1075 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1076 PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0 1077 PERFCOUNTER_CNTOFF_SEL, 0x4, // start when counter 4 stops 1078 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1079 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1080 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1081 REG_SET_2(DC_PERFMON5_PERFCOUNTER_STATE, 0, 1082 PERFCOUNTER_STATE_SEL0, 0x1, // independent state mode 1083 PERFCOUNTER_CNT0_STATE, 0x3); // hw mode 1084 1085 /* program counter 1 as the second bw counter */ 1086 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1087 PERFCOUNTER_CNTL_SEL, 0x1, // select counter 1 1088 PERFCOUNTER_EVENT_SEL, 257, // ROB output valid event 1089 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1090 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1091 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1092 PERFCOUNTER_CVALUE_SEL, 0x7, // use cvalue bits 47-36 1093 PERFCOUNTER_RESTART_EN, 0x1, // restart the counter while it is active 1094 PERFCOUNTER_INT_EN, 0x1, // signal when the measurement is complete 1095 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1096 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1097 PERFCOUNTER_CNTL2_SEL, 0x1, // select counter 1 1098 PERFCOUNTER_CNTOFF_SEL, 0x5, // start when counter 5 stops 1099 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1100 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1101 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1102 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1103 PERFCOUNTER_STATE_SEL1, 0x1, // independent state mode 1104 PERFCOUNTER_CNT1_STATE, 0x3); // hw mode 1105 1106 /* program counter 2 as the third bw counter */ 1107 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1108 PERFCOUNTER_CNTL_SEL, 0x2, // select counter 2 1109 PERFCOUNTER_EVENT_SEL, 257, // ROB output valid event 1110 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1111 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1112 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1113 PERFCOUNTER_CVALUE_SEL, 0x7, // use cvalue bits 47-36 1114 PERFCOUNTER_RESTART_EN, 0x1, // restart the counter while it is active 1115 PERFCOUNTER_INT_EN, 0x1, // signal when the measurement is complete 1116 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1117 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1118 PERFCOUNTER_CNTL2_SEL, 0x2, // select counter 2 1119 PERFCOUNTER_CNTOFF_SEL, 0x6, // start when counter 6 stops 1120 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1121 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1122 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1123 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1124 PERFCOUNTER_STATE_SEL2, 0x1, // independent state mode 1125 PERFCOUNTER_CNT2_STATE, 0x3); // hw mode 1126 1127 /* program counter 4 as the first time window */ 1128 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1129 PERFCOUNTER_CNTL_SEL, 0x4, // select counter 4 1130 PERFCOUNTER_EVENT_SEL, 19, // Always 1 event 1131 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1132 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1133 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1134 PERFCOUNTER_CVALUE_SEL, 0x4, // use cvalue bits 11-0 1135 PERFCOUNTER_RESTART_EN, 0x0, // do not restart the counter while active. 1136 PERFCOUNTER_INT_EN, 0x0, // used for timing only, do not enable interrupt 1137 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1138 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1139 PERFCOUNTER_CNTL2_SEL, 0x4, // select counter 4 1140 PERFCOUNTER_CNTOFF_SEL, 0x8, // start on custom signal: latency start | counter interrupt 1141 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1142 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1143 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1144 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1145 PERFCOUNTER_STATE_SEL4, 0x1, // independent state mode 1146 PERFCOUNTER_CNT4_STATE, 0x3); // hw mode 1147 1148 /* program counter 5 as the second time window */ 1149 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1150 PERFCOUNTER_CNTL_SEL, 0x5, // select counter 5 1151 PERFCOUNTER_EVENT_SEL, 19, // Always 1 event 1152 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1153 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1154 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1155 PERFCOUNTER_CVALUE_SEL, 0x5, // use cvalue bits 23-12 1156 PERFCOUNTER_RESTART_EN, 0x1, // restart the counter while it's active 1157 PERFCOUNTER_OFF_MASK, 0x1, // Don't allow this counter to trigger counter 4 restart 1158 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1159 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1160 PERFCOUNTER_CNTL2_SEL, 0x5, // select counter 5 1161 PERFCOUNTER_CNTOFF_SEL, 0x4, // start when counter 4 stops 1162 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1163 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1164 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1165 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1166 PERFCOUNTER_STATE_SEL5, 0x1, // independent state mode 1167 PERFCOUNTER_CNT5_STATE, 0x3); // hw mode 1168 1169 /* program counter 6 as the third time window */ 1170 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1171 PERFCOUNTER_CNTL_SEL, 0x6, // select counter 6 1172 PERFCOUNTER_EVENT_SEL, 19, // Always 1 event 1173 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1174 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1175 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1176 PERFCOUNTER_CVALUE_SEL, 0x6, // use cvalue bits 35-24 1177 PERFCOUNTER_RESTART_EN, 0x1, // restart the counter while it's active 1178 PERFCOUNTER_OFF_MASK, 0x1, // Don't allow this counter to trigger counter 4 restart 1179 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1180 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1181 PERFCOUNTER_CNTL2_SEL, 0x6, // select counter 6 1182 PERFCOUNTER_CNTOFF_SEL, 0x4, // start when counter 4 stops 1183 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1184 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1185 PERFCOUNTER_HW_STOP2_SEL, 0x0); // stop when count reaches cvalue 1186 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1187 PERFCOUNTER_STATE_SEL6, 0x1, // independent state mode 1188 PERFCOUNTER_CNT6_STATE, 0x3); // hw mode 1189 1190 /* program counter 7 to count urgent ramp latency from urg asserted until bw reaches threshold */ 1191 REG_SET_10(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1192 PERFCOUNTER_CNTL_SEL, 0x7, // select counter 7 1193 PERFCOUNTER_EVENT_SEL, 19, // Always 1 event 1194 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1195 PERFCOUNTER_HW_CNTL_SEL, 0x1, // hw indepedennt mode: start event on perfmon off and stop counting on cvalue reached. 1196 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1197 PERFCOUNTER_CVALUE_SEL, 0x0, // default/not used 1198 PERFCOUNTER_RESTART_EN, 0x0, // do not restart counter 1199 PERFCOUNTER_INT_EN, 0x0, // Final measurement; doesn't need to interrupt 1200 PERFCOUNTER_OFF_MASK, 0x0, // default 1201 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1202 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1203 PERFCOUNTER_CNTL2_SEL, 0x7, // select counter 7 1204 PERFCOUNTER_CNTOFF_SEL, 0x8, // start on custom signal: latency start | counter interrupt 1205 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1206 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored for hardware independent mode 1207 PERFCOUNTER_HW_STOP2_SEL, 0x1); // stop on external event 1208 REG_UPDATE_2(DC_PERFMON5_PERFCOUNTER_STATE, 1209 PERFCOUNTER_STATE_SEL7, 0x1, // independent state mode 1210 PERFCOUNTER_CNT7_STATE, 0x3); // hw mode 1211 1212 REG_SET_3(DC_PERFMON5_PERFMON_CNTL2, 0, 1213 PERFMON_RUN_ENABLE_START_SEL, 0x0, // start on first urgent request from lat mon 1214 PERFMON_RUN_ENABLE_STOP_SEL, 11, // stop on counter interrupt 1215 PERFMON_CNTOFF_INT_TYPE, 0x0); 1216 1217 // Program Perfmon cvalue registers (example values, should be 1218 // calculated as per doc) refclk_hz = refclk_mhz * 1,000,000 t_win_s = 1219 // t_win_ns / 1,000,000,000 CVALUE[11:0] = refclk_hz * t_win_s = 1220 // (refclk_mhz * t_win_ns) / 1000 1221 struct fixed31_32 slice_size = 1222 dc_fixpt_from_fraction((uint64_t)params->refclk_mhz * params->t_win_ns, 3000); 1223 struct fixed31_32 threshold_bytes = dc_fixpt_div_int( 1224 dc_fixpt_from_int(params->bandwidth_mbps * params->t_win_ns), 1225 1000); 1226 1227 uint32_t cvalue_0 = dc_fixpt_floor(dc_fixpt_mul_int(slice_size, 3)); 1228 uint32_t cvalue_1 = dc_fixpt_floor(slice_size); 1229 uint32_t cvalue_2 = dc_fixpt_floor(dc_fixpt_mul_int(slice_size, 2)); 1230 uint32_t cvalue_3 = dc_fixpt_floor(dc_fixpt_mul( 1231 dc_fixpt_div_int(threshold_bytes, 64), 1232 dc_fixpt_from_fraction(params->bw_factor_x1000, 1000))); 1233 1234 // Pack into 48 bits: [47:36][35:24][23:12][11:0] 1235 uint64_t cvalue = ((uint64_t)cvalue_3 << 36) | 1236 ((uint64_t)cvalue_2 << 24) | 1237 ((uint64_t)cvalue_1 << 12) | 1238 ((uint64_t)cvalue_0); 1239 1240 REG_SET(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, 0, PERFMON_CVALUE_HI, (uint32_t) (cvalue >> 32)); 1241 REG_SET(DC_PERFMON5_PERFMON_CVALUE_LOW, 0, PERFMON_CVALUE_LOW, (uint32_t) (cvalue & 0xFFFFFFFF)); 1242 1243 /* start the counters */ 1244 REG_SET_3(DC_PERFMON5_PERFMON_CNTL, 0, 1245 PERFMON_STATE, 0x3, 1246 PERFMON_RPT_COUNT, 1, 1247 PERFMON_CNTOFF_INT_EN, 0x1); 1248 } 1249 1250 /** 1251 * @brief Reads the current performance monitor result and calculates 1252 * the urgent ramp latency in nanoseconds. 1253 * 1254 * This function reads the values from the DCN 6.0 hubbub performance 1255 * monitor counters, then calculates the urgent ramp latency in 1256 * nanoseconds. 1257 * 1258 * @param hubbub Pointer to the hubbub structure representing the 1259 * hardware instance. 1260 * @param refclk_mhz Reference clock frequency in MHz, used for time 1261 * conversion. 1262 * 1263 * @return The urgent ramp latency in nanoseconds as a 32-bit unsigned 1264 * integer. 1265 */ 1266 static uint32_t hubbub60_perfmon_get_urgent_ramp_latency_ns( 1267 struct hubbub *hubbub, uint32_t refclk_mhz) 1268 { 1269 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1270 uint32_t count7 = 0, latency_ns = 0; 1271 struct fixed31_32 temp; 1272 1273 if (refclk_mhz == 0) 1274 return 0; 1275 1276 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x7); 1277 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count7); 1278 1279 temp = dc_fixpt_from_fraction(count7, refclk_mhz); 1280 temp = dc_fixpt_mul_int(temp, 1000); 1281 latency_ns = dc_fixpt_ceil(temp); 1282 1283 return latency_ns; 1284 } 1285 1286 /** 1287 * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth - Configure the out-of-order BW counter. 1288 * @hubbub: pointer to the hubbub hardware instance 1289 * 1290 * Configures the performance monitoring counters to measure out-of-order 1291 * (peak prefetch) bandwidth using hardware counters 0, 1, and 4: 1292 * 1293 * Counter 0: count-off counter — counts response-valid events and gates the 1294 * measurement window once it reaches its target value. 1295 * Counter 1: data counter — tracks total data received during the measurement 1296 * period; generates an interrupt when measurement completes. 1297 * Counter 4: duration timer — measures elapsed time in refclk cycles. 1298 * 1299 * UTM_FILTER_SEL is set to 0 so that isolation comes from OTG-vblank gating 1300 * rather than the silicon-broken HW filter. The first 200 prefetch requests 1301 * are skipped (ramp-up), and the subsequent 200 are the measurement window. 1302 * 1303 * This function configures counters only; call 1304 * hubbub60_perfmon_start_measuring_out_of_order_bandwidth() to enable them. 1305 */ 1306 static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth( 1307 struct hubbub *hubbub) 1308 { 1309 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1310 1311 /* configure measurement control */ 1312 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 1313 DCHUBBUB_LATENCY_CNT_EN, 0x1, 1314 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 1315 /* 1316 * UTM_FILTER_SEL = 0: time-domain gating (OTG vblank) replaces the 1317 * silicon-broken HW filter that can no longer isolate prefetch traffic. 1318 */ 1319 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 1320 LATENCY_SOURCE_SEL, 0x2, 1321 UTM_FILTER_SEL, 0x0); 1322 1323 /* Program counter 0 as the count off counter */ 1324 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1325 PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0 1326 PERFCOUNTER_EVENT_SEL, 259, // response vld 1327 PERFCOUNTER_CVALUE_SEL, 0x1, // use cvalue bits 15-0 1328 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1329 PERFCOUNTER_HW_CNTL_SEL, 0x0, // simutaneous mode 1330 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1331 PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done 1332 PERFCOUNTER_ACTIVE, 1); 1333 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1334 PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0 1335 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1336 PERFCOUNTER_HW_STOP1_SEL, 0x1, // the stop trigger is that perfcounter meet the target CVALUE 1337 PERFCOUNTER_HW_STOP2_SEL, 0x0); // ignored 1338 1339 /* Program counter 1 to count total data received */ 1340 REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1341 PERFCOUNTER_CNTL_SEL, 0x1, // select counter 1 1342 PERFCOUNTER_EVENT_SEL, 259, // response vld 1343 PERFCOUNTER_CVALUE_SEL, 0x2, // use cvalue bits 31-16 1344 PERFCOUNTER_INC_MODE, 0x2, // count LSB level 1345 PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode 1346 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1347 PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done 1348 PERFCOUNTER_INT_EN, 1, // signal when the measurement is complete 1349 PERFCOUNTER_ACTIVE, 0x1); 1350 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1351 PERFCOUNTER_CNTL2_SEL, 0x1, 1352 PERFCOUNTER_CNTOFF_SEL, 0, // start when count0 stops 1353 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1354 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored 1355 PERFCOUNTER_HW_STOP2_SEL, 0x0); // the stop trigger is that perfcounter meet the target CVALUE 1356 1357 /* Program counter 4 to count the measuring time */ 1358 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1359 PERFCOUNTER_CNTL_SEL, 0x4, // select counter 4 1360 PERFCOUNTER_EVENT_SEL, 19, // always 1 event 1361 PERFCOUNTER_CVALUE_SEL, 0x0, // ignored 1362 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1363 PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode 1364 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1365 PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done 1366 PERFCOUNTER_ACTIVE, 1); 1367 REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1368 PERFCOUNTER_CNTL2_SEL, 0x4, // select counter 4 1369 PERFCOUNTER_CNTOFF_SEL, 0, // start when count0 stops 1370 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1371 PERFCOUNTER_HW_STOP1_SEL, 0x0, // ignored 1372 PERFCOUNTER_HW_STOP2_SEL, 0x1); // the stop trigger is from the external 64 pairs of start/stop events 1373 1374 /* Program perfcounter states */ 1375 REG_SET_6(DC_PERFMON5_PERFCOUNTER_STATE, 0, 1376 PERFCOUNTER_STATE_SEL0, 0x1, // independent state mode 1377 PERFCOUNTER_CNT0_STATE, 0x3, // hw mode 1378 PERFCOUNTER_STATE_SEL1, 0x1, // independent state mode 1379 PERFCOUNTER_CNT1_STATE, 0x3, // hw mode 1380 PERFCOUNTER_STATE_SEL4, 0x1, // independent state mode 1381 PERFCOUNTER_CNT4_STATE, 0x3); // hw mode 1382 1383 /* 1384 * The cvalue is derived based on experimental results at the lowest 1385 * clock state. Out-of-order bandwidth requires ~200 prefetch requests 1386 * to ramp up to full speed; the subsequent 200 requests form the 1387 * measurement window. 1388 */ 1389 REG_SET(DC_PERFMON5_PERFMON_CVALUE_LOW, 0, PERFMON_CVALUE_LOW, 200 | 200 << 16); 1390 1391 REG_SET_2(DC_PERFMON5_PERFMON_CNTL2, 0, 1392 PERFMON_RUN_ENABLE_START_SEL, 0x0, 1393 PERFMON_RUN_ENABLE_STOP_SEL, 11); // perfmon counter off event 1394 } 1395 1396 /** 1397 * hubbub60_perfmon_start_measuring_out_of_order_bandwidth - Enable the out-of-order BW counter. 1398 * @hubbub: pointer to the hubbub hardware instance 1399 * 1400 * Enables the performance monitor counters previously configured by 1401 * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(). The counter 1402 * self-stops once the count-off counter reaches its target; there is no 1403 * explicit stop step for the peak-BW path. 1404 */ 1405 static void hubbub60_perfmon_start_measuring_out_of_order_bandwidth( 1406 struct hubbub *hubbub) 1407 { 1408 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1409 1410 REG_SET_2(DC_PERFMON5_PERFMON_CNTL, 0, 1411 PERFMON_STATE, 0x3, 1412 PERFMON_RPT_COUNT, 1); 1413 } 1414 1415 /** 1416 * hubbub60_perfmon_get_out_of_order_bandwidth_mbps - Read out-of-order BW counter result. 1417 * @hubbub: pointer to the hubbub hardware instance 1418 * @refclk_mhz: reference clock frequency in MHz, used for duration conversion 1419 * @duration_ns: output parameter; receives the measured duration in nanoseconds 1420 * 1421 * Reads hardware counters 1 (data) and 4 (duration) and converts the raw 1422 * refclk-cycle count into bandwidth in Mbps. 1423 * 1424 * Return: out-of-order bandwidth in Mbps 1425 */ 1426 static uint32_t hubbub60_perfmon_get_out_of_order_bandwidth_mbps( 1427 struct hubbub *hubbub, uint32_t refclk_mhz, uint32_t *duration_ns) 1428 { 1429 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1430 uint32_t count0 = 0, count1 = 0, count4 = 0, 1431 out_of_order_bandwidth_mbps = 0, measuring_duration_ns = 0; 1432 struct fixed31_32 temp; 1433 1434 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x0); 1435 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count0); 1436 1437 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x1); 1438 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count1); 1439 1440 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x4); 1441 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count4); 1442 1443 if (refclk_mhz == 0) 1444 return 0; 1445 1446 temp = dc_fixpt_from_fraction(count4, refclk_mhz); 1447 temp = dc_fixpt_mul_int(temp, 1000); 1448 measuring_duration_ns = dc_fixpt_ceil(temp); 1449 1450 if (duration_ns) 1451 *duration_ns = measuring_duration_ns; 1452 if (measuring_duration_ns == 0) 1453 return 0; 1454 1455 temp = dc_fixpt_from_fraction(count1, measuring_duration_ns); 1456 temp = dc_fixpt_mul_int(temp, 64 * 1000); 1457 out_of_order_bandwidth_mbps = dc_fixpt_floor(temp); 1458 1459 return out_of_order_bandwidth_mbps; 1460 } 1461 1462 /** 1463 * @brief Configures the performance monitor to measure in-order 1464 * bandwidth in megabits per second (Mbps). 1465 * 1466 * This function sets up performance monitoring counters to measure 1467 * in-order bandwidth. It uses hardware counters 0 and 4 for this 1468 * purpose: 1469 * 1470 * Counter 0: 1471 * - Purpose: Tracks the total data received during the measurement 1472 * period. 1473 * - Behavior: Starts counting when the measurement starts and stops 1474 * when the measurement is stopped manually. 1475 * 1476 * Counter 4: 1477 * - Purpose: Measures the total time taken during the measurement 1478 * period in reference clock (refclk) cycles. 1479 * - Behavior: Starts counting when the measurement starts and stops 1480 * when the measurement is stopped manually. 1481 * 1482 * @param hubbub Pointer to the hubbub structure representing the hardware 1483 * instance. 1484 */ 1485 static void hubbub60_perfmon_start_measuring_in_order_bandwidth( 1486 struct hubbub *hubbub) 1487 { 1488 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1489 1490 /* Program Latency Monitor Registers */ 1491 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 1492 DCHUBBUB_LATENCY_CNT_EN, 0x1, 1493 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 1494 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 1495 LATENCY_SOURCE_SEL, 0x8, // ROB latency 1496 UTM_FILTER_SEL, 0x0); 1497 1498 /* Program counter 0 to count total data received */ 1499 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1500 PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0 1501 PERFCOUNTER_EVENT_SEL, 257, // in order data 1502 PERFCOUNTER_CVALUE_SEL, 0x0, // ignored 1503 PERFCOUNTER_INC_MODE, 0x2, // count LSB level 1504 PERFCOUNTER_HW_CNTL_SEL, 0x0, // simutaneous mode 1505 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1506 PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done 1507 PERFCOUNTER_ACTIVE, 0x1); 1508 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1509 PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0 1510 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1511 PERFCOUNTER_HW_STOP1_SEL, 0x0, // stop when other counters are done 1512 PERFCOUNTER_HW_STOP2_SEL, 0x0); 1513 1514 /* Program counter 4 to count the measuring time */ 1515 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1516 PERFCOUNTER_CNTL_SEL, 0x4, // select counter 4 1517 PERFCOUNTER_EVENT_SEL, 19, // always 1 event 1518 PERFCOUNTER_CVALUE_SEL, 0x0, // all cvalue range 1519 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1520 PERFCOUNTER_HW_CNTL_SEL, 0x0, // simutaneous mode 1521 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1522 PERFCOUNTER_RESTART_EN, 0x0, // stops after counting is done 1523 PERFCOUNTER_ACTIVE, 0x1); // enable the counter 1524 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1525 PERFCOUNTER_CNTL2_SEL, 0x4, // select counter 4 1526 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1527 PERFCOUNTER_HW_STOP1_SEL, 0x0, // stop when count reaches cvalue 1528 PERFCOUNTER_HW_STOP2_SEL, 0x0); // ignored 1529 1530 /* Program perfcounter states */ 1531 REG_SET_4(DC_PERFMON5_PERFCOUNTER_STATE, 0, 1532 PERFCOUNTER_STATE_SEL0, 0x0, // global state mode 1533 PERFCOUNTER_CNT0_STATE, 0x0, // ignored 1534 PERFCOUNTER_STATE_SEL4, 0x0, // global state mode 1535 PERFCOUNTER_CNT4_STATE, 0x0); // ignored 1536 1537 /* start the counters */ 1538 REG_SET_2(DC_PERFMON5_PERFMON_CNTL, 0, 1539 PERFMON_STATE, 1, 1540 PERFMON_RPT_COUNT, 0xFFFFF); 1541 } 1542 1543 /** 1544 * @brief Reads the current performance monitor result and calculates 1545 * the in-order bandwidth in Mbps. 1546 * 1547 * This function reads the values from the DCN 6.0 hubbub performance 1548 * monitor counters, then calculates the in-order bandwidth in Mbps. 1549 * 1550 * @param hubbub Pointer to the hubbub structure representing the 1551 * hardware instance. 1552 * @param refclk_mhz Reference clock frequency in MHz, used for time 1553 * conversion. 1554 * @param min_duration_ns Minimum duration in nanoseconds required for 1555 * a valid measurement. 1556 * @param duration_ns Measured duration in nanoseconds. 1557 * 1558 * @return The in-order bandwidth in Mbps as a 32-bit unsigned integer. 1559 */ 1560 static uint32_t hubbub60_perfmon_get_in_order_bandwidth_mbps( 1561 struct hubbub *hubbub, uint32_t refclk_mhz, 1562 uint32_t min_duration_ns, uint32_t *duration_ns) 1563 { 1564 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1565 uint32_t count0 = 0, count4 = 0, in_order_bandwidth_mbps = 0, 1566 measuring_duration_ns = 0; 1567 struct fixed31_32 temp; 1568 1569 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x4); 1570 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count4); 1571 1572 if (refclk_mhz == 0) 1573 return 0; 1574 1575 measuring_duration_ns = count4 * 1000 / refclk_mhz; 1576 *duration_ns = measuring_duration_ns; 1577 if (min_duration_ns > measuring_duration_ns) 1578 return 0; 1579 1580 /* stop the counters */ 1581 REG_SET(DC_PERFMON5_PERFMON_CNTL, 0, PERFMON_STATE, 2); 1582 1583 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x0); 1584 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count0); 1585 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x4); 1586 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count4); 1587 1588 ASSERT(count4); 1589 temp = dc_fixpt_from_fraction(count4, refclk_mhz); 1590 temp = dc_fixpt_mul_int(temp, 1000); 1591 measuring_duration_ns = dc_fixpt_ceil(temp); 1592 if (duration_ns) 1593 *duration_ns = measuring_duration_ns; 1594 1595 temp = dc_fixpt_from_fraction(count0, measuring_duration_ns); 1596 temp = dc_fixpt_mul_int(temp, 64 * 1000); 1597 in_order_bandwidth_mbps = dc_fixpt_floor(temp); 1598 1599 return in_order_bandwidth_mbps; 1600 } 1601 1602 /** 1603 * @brief Configures the performance monitor to measure prefetch data size. 1604 * 1605 * This function sets up performance monitoring counter 0 to measure 1606 * the total prefetch data size in bytes. It configures the necessary 1607 * registers to count the number of valid ROB output events, which 1608 * correspond to prefetch data. 1609 * 1610 * @param hubbub Pointer to the hubbub structure representing the hardware 1611 * instance. 1612 */ 1613 static void hubbub60_perfmon_start_measuring_prefetch_data_size( 1614 struct hubbub *hubbub) 1615 { 1616 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1617 1618 /* configure measurement control */ 1619 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, 0, 1620 DCHUBBUB_LATENCY_CNT_EN, 0x1, 1621 DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, 0x1); 1622 REG_SET_2(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, 0, 1623 LATENCY_SOURCE_SEL, 0x2, 1624 UTM_FILTER_SEL, 0x2); // prefetch only 1625 1626 /* program counter 0 to count prefetch data size */ 1627 REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0, 1628 PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0 1629 PERFCOUNTER_EVENT_SEL, 259, // ROB output valid event 1630 PERFCOUNTER_CVALUE_SEL, 0x0, // ignored 1631 PERFCOUNTER_INC_MODE, 0x2, // Count LSB level 1632 PERFCOUNTER_HW_CNTL_SEL, 0x0, // simultaneous mode 1633 PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high 1634 PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done 1635 PERFCOUNTER_ACTIVE, 1); 1636 REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0, 1637 PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0 1638 PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value 1639 PERFCOUNTER_HW_STOP1_SEL, 0x0, // stop when counting is done 1640 PERFCOUNTER_HW_STOP2_SEL, 0x0); // ignored 1641 1642 REG_SET_2(DC_PERFMON5_PERFCOUNTER_STATE, 0, 1643 PERFCOUNTER_STATE_SEL0, 0x1, // simultaneous state mode 1644 PERFCOUNTER_CNT0_STATE, 0x3); // hw mode 1645 1646 REG_SET_2(DC_PERFMON5_PERFMON_CNTL2, 0, 1647 PERFMON_RUN_ENABLE_START_SEL, 0x0, 1648 PERFMON_RUN_ENABLE_STOP_SEL, 0); 1649 1650 /* start the counters */ 1651 REG_SET_2(DC_PERFMON5_PERFMON_CNTL, 0, 1652 PERFMON_STATE, 0x3, 1653 PERFMON_RPT_COUNT, 0x1); 1654 } 1655 1656 /** 1657 * @brief Reads the current performance monitor result and calculates 1658 * the prefetch data size in bytes. 1659 * 1660 * This function reads the value from the DCN 6.0 hubbub performance 1661 * monitor counter 0, then calculates the prefetch data size in bytes. 1662 * 1663 * @param hubbub Pointer to the hubbub structure representing the 1664 * hardware instance. 1665 * 1666 * @return The prefetch data size in bytes as a 32-bit unsigned integer. 1667 */ 1668 static uint32_t hubbub60_perfmon_get_prefetch_data_size( 1669 struct hubbub *hubbub) 1670 { 1671 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1672 uint32_t count0 = 0; 1673 uint32_t prefetch_data_size_bytes = 0; 1674 1675 REG_SET(DC_PERFMON5_PERFMON_HI, 0, PERFMON_READ_SEL, 0x0); 1676 REG_GET(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, &count0); 1677 1678 prefetch_data_size_bytes = count0 * 64; 1679 return prefetch_data_size_bytes; 1680 } 1681 1682 /** 1683 * @brief Forces the display to use the nominal QoS profile. 1684 * 1685 * This function configures the hubbub to force the display to use 1686 * the nominal QoS profile by updating the relevant registers. 1687 * 1688 * @param hubbub Pointer to the hubbub structure representing the 1689 * hardware instance. 1690 */ 1691 static void hubbub60_force_display_nominal_profile(struct hubbub *hubbub) 1692 { 1693 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1694 1695 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_URGENT, 0); 1696 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_ENABLE, 1); 1697 } 1698 1699 /** 1700 * @brief Forces the display to use the urgent QoS profile. 1701 * 1702 * This function configures the hubbub to force the display to use 1703 * the urgent QoS profile by updating the relevant registers. 1704 * 1705 * @param hubbub Pointer to the hubbub structure representing the 1706 * hardware instance. 1707 */ 1708 static void hubbub60_force_display_urgent_profile(struct hubbub *hubbub) 1709 { 1710 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1711 1712 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_URGENT, 1); 1713 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_ENABLE, 1); 1714 } 1715 1716 /** 1717 * @brief Resets the display QoS profile to default. 1718 * 1719 * This function resets the display QoS profile by disabling any 1720 * forced QoS settings in the hubbub. 1721 * 1722 * @param hubbub Pointer to the hubbub structure representing the 1723 * hardware instance. 1724 */ 1725 static void hubbub60_reset_display_qos_profile(struct hubbub *hubbub) 1726 { 1727 struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); 1728 1729 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_ENABLE, 0); 1730 REG_UPDATE(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_URGENT, 0); 1731 } 1732 1733 static const struct hubbub_funcs hubbub60_funcs = { 1734 .update_dchub = hubbub2_update_dchub, 1735 .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx, 1736 .init_vm_ctx = hubbub2_init_vm_ctx, 1737 .dcc_support_swizzle_addr3 = hubbub401_dcc_support_swizzle, 1738 .dcc_support_pixel_format_plane0_plane1 = 1739 hubbub401_dcc_support_pixel_format, 1740 .get_dcc_compression_cap = hubbub401_get_dcc_compression_cap, 1741 .wm_read_state = hubbub60_wm_read_state, 1742 .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, 1743 .program_watermarks = hubbub60_program_watermarks, 1744 .allow_self_refresh_control = hubbub1_allow_self_refresh_control, 1745 .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, 1746 .verify_allow_pstate_change_high = NULL, 1747 .force_wm_propagate_to_pipes = hubbub60_force_wm_propagate_to_pipes, 1748 .force_pstate_change_control = hubbub3_force_pstate_change_control, 1749 .init_watermarks = hubbub60_init_watermarks, 1750 .init_crb = dcn60_init_crb, 1751 .hubbub_read_state = hubbub2_read_state, 1752 .force_usr_retraining_allow = NULL, 1753 .set_request_limit = hubbub32_set_request_limit, 1754 .program_det_segments = dcn60_program_det_segments, 1755 .program_compbuf_segments = dcn60_program_compbuf_segments, 1756 .wait_for_det_update = dcn60_wait_for_det_update, 1757 .program_arbiter = dcn401_program_arbiter, 1758 .hubbub_read_reg_state = hubbub3_read_reg_state, 1759 .perfmon = { 1760 .reset = hubbub60_perfmon_reset, 1761 .start_measuring_memory_latencies = 1762 hubbub60_perfmon_start_measuring_memory_latencies, 1763 .get_memory_latencies_ns = 1764 hubbub60_perfmon_get_memory_latencies_ns, 1765 .start_measuring_urgent_assertion_count = 1766 hubbub60_perfmon_start_measuring_urgent_assertion_count, 1767 .get_urgent_assertion_count = 1768 hubbub60_perfmon_get_urgent_assertion_count, 1769 .start_measuring_urgent_ramp_latency = 1770 hubbub60_perfmon_start_measuring_urgent_ramp_latency, 1771 .get_urgent_ramp_latency_ns = 1772 hubbub60_perfmon_get_urgent_ramp_latency_ns, 1773 .arm_measuring_out_of_order_bandwidth = 1774 hubbub60_perfmon_arm_measuring_out_of_order_bandwidth, 1775 .start_measuring_out_of_order_bandwidth = 1776 hubbub60_perfmon_start_measuring_out_of_order_bandwidth, 1777 .get_out_of_order_bandwidth_mbps = 1778 hubbub60_perfmon_get_out_of_order_bandwidth_mbps, 1779 .start_measuring_in_order_bandwidth = 1780 hubbub60_perfmon_start_measuring_in_order_bandwidth, 1781 .get_in_order_bandwidth_mbps = 1782 hubbub60_perfmon_get_in_order_bandwidth_mbps, 1783 .start_measuring_prefetch_data_size = 1784 hubbub60_perfmon_start_measuring_prefetch_data_size, 1785 .get_prefetch_data_size = 1786 hubbub60_perfmon_get_prefetch_data_size, 1787 }, 1788 .qos = { 1789 .force_display_nominal_profile = 1790 hubbub60_force_display_nominal_profile, 1791 .force_display_urgent_profile = 1792 hubbub60_force_display_urgent_profile, 1793 .reset_display_qos_profile = 1794 hubbub60_reset_display_qos_profile, 1795 }, 1796 }; 1797 1798 void hubbub60_construct(struct dcn20_hubbub *hubbub2, 1799 struct dc_context *ctx, 1800 const struct dcn_hubbub_registers *hubbub_regs, 1801 const struct dcn_hubbub_shift *hubbub_shift, 1802 const struct dcn_hubbub_mask *hubbub_mask, 1803 int det_size_kb, 1804 int pixel_chunk_size_kb, 1805 int config_return_buffer_size_kb) 1806 { 1807 hubbub2->base.ctx = ctx; 1808 hubbub2->base.funcs = &hubbub60_funcs; 1809 hubbub2->regs = hubbub_regs; 1810 hubbub2->shifts = hubbub_shift; 1811 hubbub2->masks = hubbub_mask; 1812 1813 hubbub2->detile_buf_size = det_size_kb * 1024; 1814 hubbub2->pixel_chunk_size = pixel_chunk_size_kb * 1024; 1815 hubbub2->crb_size_segs = config_return_buffer_size_kb / DCN6_0_CRB_SEGMENT_SIZE_KB; 1816 } 1817