1 | /* |
2 | * Copyright 2021 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | |
27 | #include "dcn30/dcn30_hubbub.h" |
28 | #include "dcn32_hubbub.h" |
29 | #include "dm_services.h" |
30 | #include "reg_helper.h" |
31 | |
32 | |
33 | #define CTX \ |
34 | hubbub2->base.ctx |
35 | #define DC_LOGGER \ |
36 | hubbub2->base.ctx->logger |
37 | #define REG(reg)\ |
38 | hubbub2->regs->reg |
39 | |
40 | #undef FN |
41 | #define FN(reg_name, field_name) \ |
42 | hubbub2->shifts->field_name, hubbub2->masks->field_name |
43 | |
44 | /** |
45 | * DCN32_CRB_SEGMENT_SIZE_KB: Maximum Configurable Return Buffer size for |
46 | * DCN32 |
47 | */ |
48 | #define DCN32_CRB_SEGMENT_SIZE_KB 64 |
49 | |
50 | static void dcn32_init_crb(struct hubbub *hubbub) |
51 | { |
52 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
53 | |
54 | REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, |
55 | &hubbub2->det0_size); |
56 | |
57 | REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, |
58 | &hubbub2->det1_size); |
59 | |
60 | REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, |
61 | &hubbub2->det2_size); |
62 | |
63 | REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, |
64 | &hubbub2->det3_size); |
65 | |
66 | REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, |
67 | &hubbub2->compbuf_size_segments); |
68 | |
69 | REG_SET_2(COMPBUF_RESERVED_SPACE, 0, |
70 | COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32, |
71 | COMPBUF_RESERVED_SPACE_ZS, hubbub2->pixel_chunk_size / 128); |
72 | REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x47F); |
73 | } |
74 | |
75 | void hubbub32_set_request_limit(struct hubbub *hubbub, int memory_channel_count, int words_per_channel) |
76 | { |
77 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
78 | |
79 | uint32_t request_limit = 3 * memory_channel_count * words_per_channel / 4; |
80 | |
81 | ASSERT((request_limit & (~0xFFF)) == 0); //field is only 24 bits long |
82 | ASSERT(request_limit > 0); //field is only 24 bits long |
83 | |
84 | if (request_limit > 0xFFF) |
85 | request_limit = 0xFFF; |
86 | |
87 | if (request_limit > 0) |
88 | REG_UPDATE(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, request_limit); |
89 | } |
90 | |
91 | |
92 | void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte) |
93 | { |
94 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
95 | |
96 | unsigned int det_size_segments = (det_buffer_size_in_kbyte + DCN32_CRB_SEGMENT_SIZE_KB - 1) / DCN32_CRB_SEGMENT_SIZE_KB; |
97 | |
98 | switch (hubp_inst) { |
99 | case 0: |
100 | REG_UPDATE(DCHUBBUB_DET0_CTRL, |
101 | DET0_SIZE, det_size_segments); |
102 | hubbub2->det0_size = det_size_segments; |
103 | break; |
104 | case 1: |
105 | REG_UPDATE(DCHUBBUB_DET1_CTRL, |
106 | DET1_SIZE, det_size_segments); |
107 | hubbub2->det1_size = det_size_segments; |
108 | break; |
109 | case 2: |
110 | REG_UPDATE(DCHUBBUB_DET2_CTRL, |
111 | DET2_SIZE, det_size_segments); |
112 | hubbub2->det2_size = det_size_segments; |
113 | break; |
114 | case 3: |
115 | REG_UPDATE(DCHUBBUB_DET3_CTRL, |
116 | DET3_SIZE, det_size_segments); |
117 | hubbub2->det3_size = det_size_segments; |
118 | break; |
119 | default: |
120 | break; |
121 | } |
122 | if (hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size |
123 | + hubbub2->det3_size + hubbub2->compbuf_size_segments > hubbub2->crb_size_segs) { |
124 | /* This may happen during seamless transition from ODM 2:1 to ODM4:1 */ |
125 | DC_LOG_WARNING("CRB Config Warning: DET size (%d,%d,%d,%d) + Compbuf size (%d) > CRB segments (%d)\n" , |
126 | hubbub2->det0_size, hubbub2->det1_size, hubbub2->det2_size, hubbub2->det3_size, |
127 | hubbub2->compbuf_size_segments, hubbub2->crb_size_segs); |
128 | } |
129 | } |
130 | |
131 | static void dcn32_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase) |
132 | { |
133 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
134 | unsigned int compbuf_size_segments = (compbuf_size_kb + DCN32_CRB_SEGMENT_SIZE_KB - 1) / DCN32_CRB_SEGMENT_SIZE_KB; |
135 | |
136 | if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) { |
137 | if (compbuf_size_segments > hubbub2->compbuf_size_segments) { |
138 | REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); |
139 | REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); |
140 | REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); |
141 | REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); |
142 | } |
143 | /* Should never be hit, if it is we have an erroneous hw config*/ |
144 | ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size |
145 | + hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs); |
146 | REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments); |
147 | hubbub2->compbuf_size_segments = compbuf_size_segments; |
148 | ASSERT(REG_GET(DCHUBBUB_COMPBUF_CTRL, CONFIG_ERROR, &compbuf_size_segments) && !compbuf_size_segments); |
149 | } |
150 | } |
151 | |
152 | static uint32_t convert_and_clamp( |
153 | uint32_t wm_ns, |
154 | uint32_t refclk_mhz, |
155 | uint32_t clamp_value) |
156 | { |
157 | uint32_t ret_val = 0; |
158 | ret_val = wm_ns * refclk_mhz; |
159 | |
160 | ret_val /= 1000; |
161 | |
162 | if (ret_val > clamp_value) |
163 | ret_val = clamp_value; |
164 | |
165 | return ret_val; |
166 | } |
167 | |
168 | bool hubbub32_program_urgent_watermarks( |
169 | struct hubbub *hubbub, |
170 | struct dcn_watermark_set *watermarks, |
171 | unsigned int refclk_mhz, |
172 | bool safe_to_lower) |
173 | { |
174 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
175 | uint32_t prog_wm_value; |
176 | bool wm_pending = false; |
177 | |
178 | /* Repeat for water mark set A, B, C and D. */ |
179 | /* clock state A */ |
180 | if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) { |
181 | hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns; |
182 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->a.urgent_ns, |
183 | refclk_mhz, clamp_value: 0x3fff); |
184 | REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, |
185 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); |
186 | |
187 | DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" |
188 | "HW register value = 0x%x\n" , |
189 | watermarks->a.urgent_ns, prog_wm_value); |
190 | } else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns) |
191 | wm_pending = true; |
192 | |
193 | /* determine the transfer time for a quantity of data for a particular requestor.*/ |
194 | if (safe_to_lower || watermarks->a.frac_urg_bw_flip |
195 | > hubbub2->watermarks.a.frac_urg_bw_flip) { |
196 | hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; |
197 | |
198 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, |
199 | DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip); |
200 | } else if (watermarks->a.frac_urg_bw_flip |
201 | < hubbub2->watermarks.a.frac_urg_bw_flip) |
202 | wm_pending = true; |
203 | |
204 | if (safe_to_lower || watermarks->a.frac_urg_bw_nom |
205 | > hubbub2->watermarks.a.frac_urg_bw_nom) { |
206 | hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; |
207 | |
208 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, |
209 | DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom); |
210 | } else if (watermarks->a.frac_urg_bw_nom |
211 | < hubbub2->watermarks.a.frac_urg_bw_nom) |
212 | wm_pending = true; |
213 | |
214 | if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) { |
215 | hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns; |
216 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->a.urgent_latency_ns, |
217 | refclk_mhz, clamp_value: 0x3fff); |
218 | REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0, |
219 | DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value); |
220 | } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns) |
221 | wm_pending = true; |
222 | |
223 | /* clock state B */ |
224 | if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) { |
225 | hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns; |
226 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->b.urgent_ns, |
227 | refclk_mhz, clamp_value: 0x3fff); |
228 | REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, |
229 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); |
230 | |
231 | DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" |
232 | "HW register value = 0x%x\n" , |
233 | watermarks->b.urgent_ns, prog_wm_value); |
234 | } else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns) |
235 | wm_pending = true; |
236 | |
237 | /* determine the transfer time for a quantity of data for a particular requestor.*/ |
238 | if (safe_to_lower || watermarks->b.frac_urg_bw_flip |
239 | > hubbub2->watermarks.b.frac_urg_bw_flip) { |
240 | hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip; |
241 | |
242 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, |
243 | DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip); |
244 | } else if (watermarks->b.frac_urg_bw_flip |
245 | < hubbub2->watermarks.b.frac_urg_bw_flip) |
246 | wm_pending = true; |
247 | |
248 | if (safe_to_lower || watermarks->b.frac_urg_bw_nom |
249 | > hubbub2->watermarks.b.frac_urg_bw_nom) { |
250 | hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom; |
251 | |
252 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, |
253 | DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom); |
254 | } else if (watermarks->b.frac_urg_bw_nom |
255 | < hubbub2->watermarks.b.frac_urg_bw_nom) |
256 | wm_pending = true; |
257 | |
258 | if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) { |
259 | hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns; |
260 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->b.urgent_latency_ns, |
261 | refclk_mhz, clamp_value: 0x3fff); |
262 | REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0, |
263 | DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value); |
264 | } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns) |
265 | wm_pending = true; |
266 | |
267 | /* clock state C */ |
268 | if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) { |
269 | hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns; |
270 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->c.urgent_ns, |
271 | refclk_mhz, clamp_value: 0x3fff); |
272 | REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, |
273 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); |
274 | |
275 | DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" |
276 | "HW register value = 0x%x\n" , |
277 | watermarks->c.urgent_ns, prog_wm_value); |
278 | } else if (watermarks->c.urgent_ns < hubbub2->watermarks.c.urgent_ns) |
279 | wm_pending = true; |
280 | |
281 | /* determine the transfer time for a quantity of data for a particular requestor.*/ |
282 | if (safe_to_lower || watermarks->c.frac_urg_bw_flip |
283 | > hubbub2->watermarks.c.frac_urg_bw_flip) { |
284 | hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.frac_urg_bw_flip; |
285 | |
286 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0, |
287 | DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->c.frac_urg_bw_flip); |
288 | } else if (watermarks->c.frac_urg_bw_flip |
289 | < hubbub2->watermarks.c.frac_urg_bw_flip) |
290 | wm_pending = true; |
291 | |
292 | if (safe_to_lower || watermarks->c.frac_urg_bw_nom |
293 | > hubbub2->watermarks.c.frac_urg_bw_nom) { |
294 | hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.frac_urg_bw_nom; |
295 | |
296 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0, |
297 | DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->c.frac_urg_bw_nom); |
298 | } else if (watermarks->c.frac_urg_bw_nom |
299 | < hubbub2->watermarks.c.frac_urg_bw_nom) |
300 | wm_pending = true; |
301 | |
302 | if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) { |
303 | hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns; |
304 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->c.urgent_latency_ns, |
305 | refclk_mhz, clamp_value: 0x3fff); |
306 | REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0, |
307 | DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value); |
308 | } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns) |
309 | wm_pending = true; |
310 | |
311 | /* clock state D */ |
312 | if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) { |
313 | hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns; |
314 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->d.urgent_ns, |
315 | refclk_mhz, clamp_value: 0x3fff); |
316 | REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, |
317 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); |
318 | |
319 | DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" |
320 | "HW register value = 0x%x\n" , |
321 | watermarks->d.urgent_ns, prog_wm_value); |
322 | } else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns) |
323 | wm_pending = true; |
324 | |
325 | /* determine the transfer time for a quantity of data for a particular requestor.*/ |
326 | if (safe_to_lower || watermarks->d.frac_urg_bw_flip |
327 | > hubbub2->watermarks.d.frac_urg_bw_flip) { |
328 | hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip; |
329 | |
330 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0, |
331 | DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip); |
332 | } else if (watermarks->d.frac_urg_bw_flip |
333 | < hubbub2->watermarks.d.frac_urg_bw_flip) |
334 | wm_pending = true; |
335 | |
336 | if (safe_to_lower || watermarks->d.frac_urg_bw_nom |
337 | > hubbub2->watermarks.d.frac_urg_bw_nom) { |
338 | hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom; |
339 | |
340 | REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0, |
341 | DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom); |
342 | } else if (watermarks->d.frac_urg_bw_nom |
343 | < hubbub2->watermarks.d.frac_urg_bw_nom) |
344 | wm_pending = true; |
345 | |
346 | if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) { |
347 | hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns; |
348 | prog_wm_value = convert_and_clamp(wm_ns: watermarks->d.urgent_latency_ns, |
349 | refclk_mhz, clamp_value: 0x3fff); |
350 | REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0, |
351 | DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value); |
352 | } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns) |
353 | wm_pending = true; |
354 | |
355 | return wm_pending; |
356 | } |
357 | |
358 | bool hubbub32_program_stutter_watermarks( |
359 | struct hubbub *hubbub, |
360 | struct dcn_watermark_set *watermarks, |
361 | unsigned int refclk_mhz, |
362 | bool safe_to_lower) |
363 | { |
364 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
365 | uint32_t prog_wm_value; |
366 | bool wm_pending = false; |
367 | |
368 | /* clock state A */ |
369 | if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns |
370 | > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { |
371 | hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = |
372 | watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; |
373 | prog_wm_value = convert_and_clamp( |
374 | wm_ns: watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, |
375 | refclk_mhz, clamp_value: 0xffff); |
376 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, |
377 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); |
378 | DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" |
379 | "HW register value = 0x%x\n" , |
380 | watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); |
381 | } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns |
382 | < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) |
383 | wm_pending = true; |
384 | |
385 | if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns |
386 | > hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) { |
387 | hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns = |
388 | watermarks->a.cstate_pstate.cstate_exit_ns; |
389 | prog_wm_value = convert_and_clamp( |
390 | wm_ns: watermarks->a.cstate_pstate.cstate_exit_ns, |
391 | refclk_mhz, clamp_value: 0xffff); |
392 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, |
393 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); |
394 | DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" |
395 | "HW register value = 0x%x\n" , |
396 | watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); |
397 | } else if (watermarks->a.cstate_pstate.cstate_exit_ns |
398 | < hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) |
399 | wm_pending = true; |
400 | |
401 | /* clock state B */ |
402 | if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns |
403 | > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { |
404 | hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = |
405 | watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; |
406 | prog_wm_value = convert_and_clamp( |
407 | wm_ns: watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, |
408 | refclk_mhz, clamp_value: 0xffff); |
409 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, |
410 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); |
411 | DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" |
412 | "HW register value = 0x%x\n" , |
413 | watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); |
414 | } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns |
415 | < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) |
416 | wm_pending = true; |
417 | |
418 | if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns |
419 | > hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) { |
420 | hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns = |
421 | watermarks->b.cstate_pstate.cstate_exit_ns; |
422 | prog_wm_value = convert_and_clamp( |
423 | wm_ns: watermarks->b.cstate_pstate.cstate_exit_ns, |
424 | refclk_mhz, clamp_value: 0xffff); |
425 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, |
426 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); |
427 | DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" |
428 | "HW register value = 0x%x\n" , |
429 | watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); |
430 | } else if (watermarks->b.cstate_pstate.cstate_exit_ns |
431 | < hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) |
432 | wm_pending = true; |
433 | |
434 | /* clock state C */ |
435 | if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns |
436 | > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { |
437 | hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = |
438 | watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; |
439 | prog_wm_value = convert_and_clamp( |
440 | wm_ns: watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, |
441 | refclk_mhz, clamp_value: 0xffff); |
442 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, |
443 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); |
444 | DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" |
445 | "HW register value = 0x%x\n" , |
446 | watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); |
447 | } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns |
448 | < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) |
449 | wm_pending = true; |
450 | |
451 | if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns |
452 | > hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) { |
453 | hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns = |
454 | watermarks->c.cstate_pstate.cstate_exit_ns; |
455 | prog_wm_value = convert_and_clamp( |
456 | wm_ns: watermarks->c.cstate_pstate.cstate_exit_ns, |
457 | refclk_mhz, clamp_value: 0xffff); |
458 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, |
459 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); |
460 | DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" |
461 | "HW register value = 0x%x\n" , |
462 | watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); |
463 | } else if (watermarks->c.cstate_pstate.cstate_exit_ns |
464 | < hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) |
465 | wm_pending = true; |
466 | |
467 | /* clock state D */ |
468 | if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns |
469 | > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { |
470 | hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = |
471 | watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; |
472 | prog_wm_value = convert_and_clamp( |
473 | wm_ns: watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, |
474 | refclk_mhz, clamp_value: 0xffff); |
475 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, |
476 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); |
477 | DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" |
478 | "HW register value = 0x%x\n" , |
479 | watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); |
480 | } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns |
481 | < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) |
482 | wm_pending = true; |
483 | |
484 | if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns |
485 | > hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) { |
486 | hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns = |
487 | watermarks->d.cstate_pstate.cstate_exit_ns; |
488 | prog_wm_value = convert_and_clamp( |
489 | wm_ns: watermarks->d.cstate_pstate.cstate_exit_ns, |
490 | refclk_mhz, clamp_value: 0xffff); |
491 | REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, |
492 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); |
493 | DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" |
494 | "HW register value = 0x%x\n" , |
495 | watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); |
496 | } else if (watermarks->d.cstate_pstate.cstate_exit_ns |
497 | < hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) |
498 | wm_pending = true; |
499 | |
500 | return wm_pending; |
501 | } |
502 | |
503 | |
504 | bool hubbub32_program_pstate_watermarks( |
505 | struct hubbub *hubbub, |
506 | struct dcn_watermark_set *watermarks, |
507 | unsigned int refclk_mhz, |
508 | bool safe_to_lower) |
509 | { |
510 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
511 | uint32_t prog_wm_value; |
512 | |
513 | bool wm_pending = false; |
514 | |
515 | /* Section for UCLK_PSTATE_CHANGE_WATERMARKS */ |
516 | /* clock state A */ |
517 | if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns |
518 | > hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) { |
519 | hubbub2->watermarks.a.cstate_pstate.pstate_change_ns = |
520 | watermarks->a.cstate_pstate.pstate_change_ns; |
521 | prog_wm_value = convert_and_clamp( |
522 | wm_ns: watermarks->a.cstate_pstate.pstate_change_ns, |
523 | refclk_mhz, clamp_value: 0xffff); |
524 | REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, 0, |
525 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, prog_wm_value); |
526 | DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" |
527 | "HW register value = 0x%x\n\n" , |
528 | watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); |
529 | } else if (watermarks->a.cstate_pstate.pstate_change_ns |
530 | < hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) |
531 | wm_pending = true; |
532 | |
533 | /* clock state B */ |
534 | if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns |
535 | > hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) { |
536 | hubbub2->watermarks.b.cstate_pstate.pstate_change_ns = |
537 | watermarks->b.cstate_pstate.pstate_change_ns; |
538 | prog_wm_value = convert_and_clamp( |
539 | wm_ns: watermarks->b.cstate_pstate.pstate_change_ns, |
540 | refclk_mhz, clamp_value: 0xffff); |
541 | REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, 0, |
542 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, prog_wm_value); |
543 | DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" |
544 | "HW register value = 0x%x\n\n" , |
545 | watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); |
546 | } else if (watermarks->b.cstate_pstate.pstate_change_ns |
547 | < hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) |
548 | wm_pending = true; |
549 | |
550 | /* clock state C */ |
551 | if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns |
552 | > hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) { |
553 | hubbub2->watermarks.c.cstate_pstate.pstate_change_ns = |
554 | watermarks->c.cstate_pstate.pstate_change_ns; |
555 | prog_wm_value = convert_and_clamp( |
556 | wm_ns: watermarks->c.cstate_pstate.pstate_change_ns, |
557 | refclk_mhz, clamp_value: 0xffff); |
558 | REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, 0, |
559 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, prog_wm_value); |
560 | DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" |
561 | "HW register value = 0x%x\n\n" , |
562 | watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); |
563 | } else if (watermarks->c.cstate_pstate.pstate_change_ns |
564 | < hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) |
565 | wm_pending = true; |
566 | |
567 | /* clock state D */ |
568 | if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns |
569 | > hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) { |
570 | hubbub2->watermarks.d.cstate_pstate.pstate_change_ns = |
571 | watermarks->d.cstate_pstate.pstate_change_ns; |
572 | prog_wm_value = convert_and_clamp( |
573 | wm_ns: watermarks->d.cstate_pstate.pstate_change_ns, |
574 | refclk_mhz, clamp_value: 0xffff); |
575 | REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, 0, |
576 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, prog_wm_value); |
577 | DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" |
578 | "HW register value = 0x%x\n\n" , |
579 | watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); |
580 | } else if (watermarks->d.cstate_pstate.pstate_change_ns |
581 | < hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) |
582 | wm_pending = true; |
583 | |
584 | /* Section for FCLK_PSTATE_CHANGE_WATERMARKS */ |
585 | /* clock state A */ |
586 | if (safe_to_lower || watermarks->a.cstate_pstate.fclk_pstate_change_ns |
587 | > hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns) { |
588 | hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns = |
589 | watermarks->a.cstate_pstate.fclk_pstate_change_ns; |
590 | prog_wm_value = convert_and_clamp( |
591 | wm_ns: watermarks->a.cstate_pstate.fclk_pstate_change_ns, |
592 | refclk_mhz, clamp_value: 0xffff); |
593 | REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, 0, |
594 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, prog_wm_value); |
595 | DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_A calculated =%d\n" |
596 | "HW register value = 0x%x\n\n" , |
597 | watermarks->a.cstate_pstate.fclk_pstate_change_ns, prog_wm_value); |
598 | } else if (watermarks->a.cstate_pstate.fclk_pstate_change_ns |
599 | < hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns) |
600 | wm_pending = true; |
601 | |
602 | /* clock state B */ |
603 | if (safe_to_lower || watermarks->b.cstate_pstate.fclk_pstate_change_ns |
604 | > hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns) { |
605 | hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns = |
606 | watermarks->b.cstate_pstate.fclk_pstate_change_ns; |
607 | prog_wm_value = convert_and_clamp( |
608 | wm_ns: watermarks->b.cstate_pstate.fclk_pstate_change_ns, |
609 | refclk_mhz, clamp_value: 0xffff); |
610 | REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, 0, |
611 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, prog_wm_value); |
612 | DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_B calculated =%d\n" |
613 | "HW register value = 0x%x\n\n" , |
614 | watermarks->b.cstate_pstate.fclk_pstate_change_ns, prog_wm_value); |
615 | } else if (watermarks->b.cstate_pstate.fclk_pstate_change_ns |
616 | < hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns) |
617 | wm_pending = true; |
618 | |
619 | /* clock state C */ |
620 | if (safe_to_lower || watermarks->c.cstate_pstate.fclk_pstate_change_ns |
621 | > hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns) { |
622 | hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns = |
623 | watermarks->c.cstate_pstate.fclk_pstate_change_ns; |
624 | prog_wm_value = convert_and_clamp( |
625 | wm_ns: watermarks->c.cstate_pstate.fclk_pstate_change_ns, |
626 | refclk_mhz, clamp_value: 0xffff); |
627 | REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, 0, |
628 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, prog_wm_value); |
629 | DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_C calculated =%d\n" |
630 | "HW register value = 0x%x\n\n" , |
631 | watermarks->c.cstate_pstate.fclk_pstate_change_ns, prog_wm_value); |
632 | } else if (watermarks->c.cstate_pstate.fclk_pstate_change_ns |
633 | < hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns) |
634 | wm_pending = true; |
635 | |
636 | /* clock state D */ |
637 | if (safe_to_lower || watermarks->d.cstate_pstate.fclk_pstate_change_ns |
638 | > hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns) { |
639 | hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns = |
640 | watermarks->d.cstate_pstate.fclk_pstate_change_ns; |
641 | prog_wm_value = convert_and_clamp( |
642 | wm_ns: watermarks->d.cstate_pstate.fclk_pstate_change_ns, |
643 | refclk_mhz, clamp_value: 0xffff); |
644 | REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, 0, |
645 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, prog_wm_value); |
646 | DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_D calculated =%d\n" |
647 | "HW register value = 0x%x\n\n" , |
648 | watermarks->d.cstate_pstate.fclk_pstate_change_ns, prog_wm_value); |
649 | } else if (watermarks->d.cstate_pstate.fclk_pstate_change_ns |
650 | < hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns) |
651 | wm_pending = true; |
652 | |
653 | return wm_pending; |
654 | } |
655 | |
656 | |
657 | bool hubbub32_program_usr_watermarks( |
658 | struct hubbub *hubbub, |
659 | struct dcn_watermark_set *watermarks, |
660 | unsigned int refclk_mhz, |
661 | bool safe_to_lower) |
662 | { |
663 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
664 | uint32_t prog_wm_value; |
665 | |
666 | bool wm_pending = false; |
667 | |
668 | /* clock state A */ |
669 | if (safe_to_lower || watermarks->a.usr_retraining_ns |
670 | > hubbub2->watermarks.a.usr_retraining_ns) { |
671 | hubbub2->watermarks.a.usr_retraining_ns = watermarks->a.usr_retraining_ns; |
672 | prog_wm_value = convert_and_clamp( |
673 | wm_ns: watermarks->a.usr_retraining_ns, |
674 | refclk_mhz, clamp_value: 0x3fff); |
675 | REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, 0, |
676 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, prog_wm_value); |
677 | DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_A calculated =%d\n" |
678 | "HW register value = 0x%x\n\n" , |
679 | watermarks->a.usr_retraining_ns, prog_wm_value); |
680 | } else if (watermarks->a.usr_retraining_ns |
681 | < hubbub2->watermarks.a.usr_retraining_ns) |
682 | wm_pending = true; |
683 | |
684 | /* clock state B */ |
685 | if (safe_to_lower || watermarks->b.usr_retraining_ns |
686 | > hubbub2->watermarks.b.usr_retraining_ns) { |
687 | hubbub2->watermarks.b.usr_retraining_ns = watermarks->b.usr_retraining_ns; |
688 | prog_wm_value = convert_and_clamp( |
689 | wm_ns: watermarks->b.usr_retraining_ns, |
690 | refclk_mhz, clamp_value: 0x3fff); |
691 | REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, 0, |
692 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, prog_wm_value); |
693 | DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_B calculated =%d\n" |
694 | "HW register value = 0x%x\n\n" , |
695 | watermarks->b.usr_retraining_ns, prog_wm_value); |
696 | } else if (watermarks->b.usr_retraining_ns |
697 | < hubbub2->watermarks.b.usr_retraining_ns) |
698 | wm_pending = true; |
699 | |
700 | /* clock state C */ |
701 | if (safe_to_lower || watermarks->c.usr_retraining_ns |
702 | > hubbub2->watermarks.c.usr_retraining_ns) { |
703 | hubbub2->watermarks.c.usr_retraining_ns = |
704 | watermarks->c.usr_retraining_ns; |
705 | prog_wm_value = convert_and_clamp( |
706 | wm_ns: watermarks->c.usr_retraining_ns, |
707 | refclk_mhz, clamp_value: 0x3fff); |
708 | REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, 0, |
709 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, prog_wm_value); |
710 | DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_C calculated =%d\n" |
711 | "HW register value = 0x%x\n\n" , |
712 | watermarks->c.usr_retraining_ns, prog_wm_value); |
713 | } else if (watermarks->c.usr_retraining_ns |
714 | < hubbub2->watermarks.c.usr_retraining_ns) |
715 | wm_pending = true; |
716 | |
717 | /* clock state D */ |
718 | if (safe_to_lower || watermarks->d.usr_retraining_ns |
719 | > hubbub2->watermarks.d.usr_retraining_ns) { |
720 | hubbub2->watermarks.d.usr_retraining_ns = |
721 | watermarks->d.usr_retraining_ns; |
722 | prog_wm_value = convert_and_clamp( |
723 | wm_ns: watermarks->d.usr_retraining_ns, |
724 | refclk_mhz, clamp_value: 0x3fff); |
725 | REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, 0, |
726 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, prog_wm_value); |
727 | DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_D calculated =%d\n" |
728 | "HW register value = 0x%x\n\n" , |
729 | watermarks->d.usr_retraining_ns, prog_wm_value); |
730 | } else if (watermarks->d.usr_retraining_ns |
731 | < hubbub2->watermarks.d.usr_retraining_ns) |
732 | wm_pending = true; |
733 | |
734 | return wm_pending; |
735 | } |
736 | |
737 | void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow) |
738 | { |
739 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
740 | |
741 | /* |
742 | * DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_ENABLE = 1 means enabling forcing value |
743 | * DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_VALUE = 1 or 0, means value to be forced when force enable |
744 | */ |
745 | |
746 | REG_UPDATE_2(DCHUBBUB_ARB_USR_RETRAINING_CNTL, |
747 | DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_VALUE, allow, |
748 | DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_ENABLE, allow); |
749 | } |
750 | |
751 | static bool hubbub32_program_watermarks( |
752 | struct hubbub *hubbub, |
753 | struct dcn_watermark_set *watermarks, |
754 | unsigned int refclk_mhz, |
755 | bool safe_to_lower) |
756 | { |
757 | bool wm_pending = false; |
758 | |
759 | if (hubbub32_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
760 | wm_pending = true; |
761 | |
762 | if (hubbub32_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
763 | wm_pending = true; |
764 | |
765 | if (hubbub32_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
766 | wm_pending = true; |
767 | |
768 | if (hubbub32_program_usr_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
769 | wm_pending = true; |
770 | |
771 | /* |
772 | * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric. |
773 | * If the memory controller is fully utilized and the DCHub requestors are |
774 | * well ahead of their amortized schedule, then it is safe to prevent the next winner |
775 | * from being committed and sent to the fabric. |
776 | * The utilization of the memory controller is approximated by ensuring that |
777 | * the number of outstanding requests is greater than a threshold specified |
778 | * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule, |
779 | * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles. |
780 | * |
781 | * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF) |
782 | * to turn off it for now. |
783 | */ |
784 | /*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, |
785 | DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); |
786 | REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, |
787 | DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/ |
788 | |
789 | hubbub1_allow_self_refresh_control(hubbub, allow: !hubbub->ctx->dc->debug.disable_stutter); |
790 | |
791 | hubbub32_force_usr_retraining_allow(hubbub, allow: hubbub->ctx->dc->debug.force_usr_allow); |
792 | |
793 | return wm_pending; |
794 | } |
795 | |
796 | /* Copy values from WM set A to all other sets */ |
797 | static void hubbub32_init_watermarks(struct hubbub *hubbub) |
798 | { |
799 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
800 | uint32_t reg; |
801 | |
802 | reg = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); |
803 | REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, reg); |
804 | REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, reg); |
805 | REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, reg); |
806 | |
807 | reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A); |
808 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, reg); |
809 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, reg); |
810 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, reg); |
811 | |
812 | reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A); |
813 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, reg); |
814 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, reg); |
815 | REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, reg); |
816 | |
817 | reg = REG_READ(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A); |
818 | REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, reg); |
819 | REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, reg); |
820 | REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, reg); |
821 | |
822 | reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); |
823 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, reg); |
824 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, reg); |
825 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, reg); |
826 | |
827 | reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); |
828 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, reg); |
829 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, reg); |
830 | REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, reg); |
831 | |
832 | reg = REG_READ(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A); |
833 | REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, reg); |
834 | REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, reg); |
835 | REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, reg); |
836 | |
837 | reg = REG_READ(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A); |
838 | REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, reg); |
839 | REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, reg); |
840 | REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, reg); |
841 | |
842 | reg = REG_READ(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A); |
843 | REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, reg); |
844 | REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, reg); |
845 | REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, reg); |
846 | } |
847 | |
848 | static void hubbub32_wm_read_state(struct hubbub *hubbub, |
849 | struct dcn_hubbub_wm *wm) |
850 | { |
851 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
852 | struct dcn_hubbub_wm_set *s; |
853 | |
854 | memset(wm, 0, sizeof(struct dcn_hubbub_wm)); |
855 | |
856 | s = &wm->sets[0]; |
857 | s->wm_set = 0; |
858 | REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, |
859 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent); |
860 | |
861 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, |
862 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter); |
863 | |
864 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, |
865 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit); |
866 | |
867 | REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, |
868 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, &s->dram_clk_change); |
869 | |
870 | REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, |
871 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, &s->usr_retrain); |
872 | |
873 | REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, |
874 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, &s->fclk_pstate_change); |
875 | |
876 | s = &wm->sets[1]; |
877 | s->wm_set = 1; |
878 | REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, |
879 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent); |
880 | |
881 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, |
882 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter); |
883 | |
884 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, |
885 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit); |
886 | |
887 | REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, |
888 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, &s->dram_clk_change); |
889 | |
890 | REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, |
891 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, &s->usr_retrain); |
892 | |
893 | REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, |
894 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, &s->fclk_pstate_change); |
895 | |
896 | s = &wm->sets[2]; |
897 | s->wm_set = 2; |
898 | REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, |
899 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent); |
900 | |
901 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, |
902 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter); |
903 | |
904 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, |
905 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit); |
906 | |
907 | REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, |
908 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, &s->dram_clk_change); |
909 | |
910 | REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, |
911 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, &s->usr_retrain); |
912 | |
913 | REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, |
914 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, &s->fclk_pstate_change); |
915 | |
916 | s = &wm->sets[3]; |
917 | s->wm_set = 3; |
918 | REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, |
919 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent); |
920 | |
921 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, |
922 | DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter); |
923 | |
924 | REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, |
925 | DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit); |
926 | |
927 | REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, |
928 | DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, &s->dram_clk_change); |
929 | |
930 | REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, |
931 | DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, &s->usr_retrain); |
932 | |
933 | REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, |
934 | DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, &s->fclk_pstate_change); |
935 | } |
936 | |
937 | void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub) |
938 | { |
939 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
940 | uint32_t refclk_mhz = hubbub->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; |
941 | uint32_t prog_wm_value = convert_and_clamp(wm_ns: hubbub2->watermarks.a.urgent_ns, |
942 | refclk_mhz, clamp_value: 0x3fff); |
943 | |
944 | REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, |
945 | DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); |
946 | } |
947 | |
948 | void hubbub32_get_mall_en(struct hubbub *hubbub, unsigned int *mall_in_use) |
949 | { |
950 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
951 | uint32_t prefetch_complete, mall_en; |
952 | |
953 | REG_GET_2(DCHUBBUB_ARB_MALL_CNTL, MALL_IN_USE, &mall_en, |
954 | MALL_PREFETCH_COMPLETE, &prefetch_complete); |
955 | |
956 | *mall_in_use = prefetch_complete && mall_en; |
957 | } |
958 | |
959 | void hubbub32_init(struct hubbub *hubbub) |
960 | { |
961 | struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); |
962 | |
963 | /* Enable clock gate*/ |
964 | if (hubbub->ctx->dc->debug.disable_clock_gate) { |
965 | /*done in hwseq*/ |
966 | /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/ |
967 | |
968 | REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL, |
969 | DISPCLK_R_DCHUBBUB_GATE_DIS, 1, |
970 | DCFCLK_R_DCHUBBUB_GATE_DIS, 1); |
971 | } |
972 | /* |
973 | ignore the "df_pre_cstate_req" from the SDP port control. |
974 | only the DCN will determine when to connect the SDP port |
975 | */ |
976 | REG_UPDATE(DCHUBBUB_SDPIF_CFG0, |
977 | SDPIF_PORT_CONTROL, 1); |
978 | /*Set SDP's max outstanding request to 512 |
979 | must set the register back to 0 (max outstanding = 256) in zero frame buffer mode*/ |
980 | REG_UPDATE(DCHUBBUB_SDPIF_CFG1, |
981 | SDPIF_MAX_NUM_OUTSTANDING, 1); |
982 | /*must set the registers back to 256 in zero frame buffer mode*/ |
983 | REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND, |
984 | DCHUBBUB_ARB_MAX_REQ_OUTSTAND, 512, |
985 | DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 512); |
986 | } |
987 | |
988 | static const struct hubbub_funcs hubbub32_funcs = { |
989 | .update_dchub = hubbub2_update_dchub, |
990 | .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx, |
991 | .init_vm_ctx = hubbub2_init_vm_ctx, |
992 | .dcc_support_swizzle = hubbub3_dcc_support_swizzle, |
993 | .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, |
994 | .get_dcc_compression_cap = hubbub3_get_dcc_compression_cap, |
995 | .wm_read_state = hubbub32_wm_read_state, |
996 | .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, |
997 | .program_watermarks = hubbub32_program_watermarks, |
998 | .allow_self_refresh_control = hubbub1_allow_self_refresh_control, |
999 | .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, |
1000 | .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high, |
1001 | .force_wm_propagate_to_pipes = hubbub32_force_wm_propagate_to_pipes, |
1002 | .force_pstate_change_control = hubbub3_force_pstate_change_control, |
1003 | .init_watermarks = hubbub32_init_watermarks, |
1004 | .program_det_size = dcn32_program_det_size, |
1005 | .program_compbuf_size = dcn32_program_compbuf_size, |
1006 | .init_crb = dcn32_init_crb, |
1007 | .hubbub_read_state = hubbub2_read_state, |
1008 | .force_usr_retraining_allow = hubbub32_force_usr_retraining_allow, |
1009 | .set_request_limit = hubbub32_set_request_limit, |
1010 | .get_mall_en = hubbub32_get_mall_en, |
1011 | }; |
1012 | |
1013 | void hubbub32_construct(struct dcn20_hubbub *hubbub2, |
1014 | struct dc_context *ctx, |
1015 | const struct dcn_hubbub_registers *hubbub_regs, |
1016 | const struct dcn_hubbub_shift *hubbub_shift, |
1017 | const struct dcn_hubbub_mask *hubbub_mask, |
1018 | int det_size_kb, |
1019 | int pixel_chunk_size_kb, |
1020 | int config_return_buffer_size_kb) |
1021 | { |
1022 | hubbub2->base.ctx = ctx; |
1023 | hubbub2->base.funcs = &hubbub32_funcs; |
1024 | hubbub2->regs = hubbub_regs; |
1025 | hubbub2->shifts = hubbub_shift; |
1026 | hubbub2->masks = hubbub_mask; |
1027 | |
1028 | hubbub2->debug_test_index_pstate = 0xB; |
1029 | hubbub2->detile_buf_size = det_size_kb * 1024; |
1030 | hubbub2->pixel_chunk_size = pixel_chunk_size_kb * 1024; |
1031 | hubbub2->crb_size_segs = config_return_buffer_size_kb / DCN32_CRB_SEGMENT_SIZE_KB; |
1032 | } |
1033 | |