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