1 /* $NetBSD: amdgpu_dcn21_hubbub.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $ */
2
3 /*
4 * Copyright 2018 Advanced Micro Devices, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: AMD
25 *
26 */
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn21_hubbub.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $");
29
30 #include <linux/delay.h>
31 #include "dm_services.h"
32 #include "dcn20/dcn20_hubbub.h"
33 #include "dcn21_hubbub.h"
34 #include "reg_helper.h"
35
36 #define REG(reg)\
37 hubbub1->regs->reg
38 #define DC_LOGGER \
39 hubbub1->base.ctx->logger
40 #define CTX \
41 hubbub1->base.ctx
42
43 #undef FN
44 #define FN(reg_name, field_name) \
45 hubbub1->shifts->field_name, hubbub1->masks->field_name
46
47 #define REG(reg)\
48 hubbub1->regs->reg
49
50 #define CTX \
51 hubbub1->base.ctx
52
53 #undef FN
54 #define FN(reg_name, field_name) \
55 hubbub1->shifts->field_name, hubbub1->masks->field_name
56
57 #ifdef NUM_VMID
58 #undef NUM_VMID
59 #endif
60 #define NUM_VMID 16
61
convert_and_clamp(uint32_t wm_ns,uint32_t refclk_mhz,uint32_t clamp_value)62 static uint32_t convert_and_clamp(
63 uint32_t wm_ns,
64 uint32_t refclk_mhz,
65 uint32_t clamp_value)
66 {
67 uint32_t ret_val = 0;
68 ret_val = wm_ns * refclk_mhz;
69 ret_val /= 1000;
70
71 if (ret_val > clamp_value)
72 ret_val = clamp_value;
73
74 return ret_val;
75 }
76
dcn21_dchvm_init(struct hubbub * hubbub)77 void dcn21_dchvm_init(struct hubbub *hubbub)
78 {
79 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
80 uint32_t riommu_active;
81 int i;
82
83 //Init DCHVM block
84 REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
85
86 //Poll until RIOMMU_ACTIVE = 1
87 for (i = 0; i < 100; i++) {
88 REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active);
89
90 if (riommu_active)
91 break;
92 else
93 udelay(5);
94 }
95
96 if (riommu_active) {
97 //Reflect the power status of DCHUBBUB
98 REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
99
100 //Start rIOMMU prefetching
101 REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
102
103 // Enable dynamic clock gating
104 REG_UPDATE_4(DCHVM_CLK_CTRL,
105 HVM_DISPCLK_R_GATE_DIS, 0,
106 HVM_DISPCLK_G_GATE_DIS, 0,
107 HVM_DCFCLK_R_GATE_DIS, 0,
108 HVM_DCFCLK_G_GATE_DIS, 0);
109
110 //Poll until HOSTVM_PREFETCH_DONE = 1
111 REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
112 }
113 }
114
hubbub21_init_dchub(struct hubbub * hubbub,struct dcn_hubbub_phys_addr_config * pa_config)115 int hubbub21_init_dchub(struct hubbub *hubbub,
116 struct dcn_hubbub_phys_addr_config *pa_config)
117 {
118 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
119 struct dcn_vmid_page_table_config phys_config;
120
121 REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
122 FB_BASE, pa_config->system_aperture.fb_base >> 24);
123 REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
124 FB_TOP, pa_config->system_aperture.fb_top >> 24);
125 REG_SET(DCN_VM_FB_OFFSET, 0,
126 FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
127 REG_SET(DCN_VM_AGP_BOT, 0,
128 AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
129 REG_SET(DCN_VM_AGP_TOP, 0,
130 AGP_TOP, pa_config->system_aperture.agp_top >> 24);
131 REG_SET(DCN_VM_AGP_BASE, 0,
132 AGP_BASE, pa_config->system_aperture.agp_base >> 24);
133
134 if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
135 phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
136 phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
137 phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr | 1; //Note: hack
138 phys_config.depth = 0;
139 phys_config.block_size = 0;
140 // Init VMID 0 based on PA config
141 dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
142 }
143
144 dcn21_dchvm_init(hubbub);
145
146 return NUM_VMID;
147 }
148
hubbub21_program_urgent_watermarks(struct hubbub * hubbub,struct dcn_watermark_set * watermarks,unsigned int refclk_mhz,bool safe_to_lower)149 void hubbub21_program_urgent_watermarks(
150 struct hubbub *hubbub,
151 struct dcn_watermark_set *watermarks,
152 unsigned int refclk_mhz,
153 bool safe_to_lower)
154 {
155 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
156 uint32_t prog_wm_value;
157
158 /* Repeat for water mark set A, B, C and D. */
159 /* clock state A */
160 if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
161 hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
162 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
163 refclk_mhz, 0x1fffff);
164 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
165 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value,
166 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value);
167
168 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
169 "HW register value = 0x%x\n",
170 watermarks->a.urgent_ns, prog_wm_value);
171 }
172
173 /* determine the transfer time for a quantity of data for a particular requestor.*/
174 if (safe_to_lower || watermarks->a.frac_urg_bw_flip
175 > hubbub1->watermarks.a.frac_urg_bw_flip) {
176 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
177
178 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
179 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
180 }
181
182 if (safe_to_lower || watermarks->a.frac_urg_bw_nom
183 > hubbub1->watermarks.a.frac_urg_bw_nom) {
184 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
185
186 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
187 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
188 }
189 if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub1->watermarks.a.urgent_latency_ns) {
190 hubbub1->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
191 prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
192 refclk_mhz, 0x1fffff);
193 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
194 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
195 }
196
197 /* clock state B */
198 if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
199 hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
200 prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
201 refclk_mhz, 0x1fffff);
202 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
203 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value,
204 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, prog_wm_value);
205
206 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
207 "HW register value = 0x%x\n",
208 watermarks->b.urgent_ns, prog_wm_value);
209 }
210
211 /* determine the transfer time for a quantity of data for a particular requestor.*/
212 if (safe_to_lower || watermarks->a.frac_urg_bw_flip
213 > hubbub1->watermarks.a.frac_urg_bw_flip) {
214 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
215
216 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
217 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->a.frac_urg_bw_flip);
218 }
219
220 if (safe_to_lower || watermarks->a.frac_urg_bw_nom
221 > hubbub1->watermarks.a.frac_urg_bw_nom) {
222 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
223
224 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
225 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->a.frac_urg_bw_nom);
226 }
227
228 if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub1->watermarks.b.urgent_latency_ns) {
229 hubbub1->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
230 prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
231 refclk_mhz, 0x1fffff);
232 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
233 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
234 }
235
236 /* clock state C */
237 if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
238 hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
239 prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
240 refclk_mhz, 0x1fffff);
241 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
242 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value,
243 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, prog_wm_value);
244
245 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
246 "HW register value = 0x%x\n",
247 watermarks->c.urgent_ns, prog_wm_value);
248 }
249
250 /* determine the transfer time for a quantity of data for a particular requestor.*/
251 if (safe_to_lower || watermarks->a.frac_urg_bw_flip
252 > hubbub1->watermarks.a.frac_urg_bw_flip) {
253 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
254
255 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
256 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->a.frac_urg_bw_flip);
257 }
258
259 if (safe_to_lower || watermarks->a.frac_urg_bw_nom
260 > hubbub1->watermarks.a.frac_urg_bw_nom) {
261 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
262
263 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
264 DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->a.frac_urg_bw_nom);
265 }
266
267 if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub1->watermarks.c.urgent_latency_ns) {
268 hubbub1->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
269 prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
270 refclk_mhz, 0x1fffff);
271 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
272 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
273 }
274
275 /* clock state D */
276 if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
277 hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
278 prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
279 refclk_mhz, 0x1fffff);
280 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
281 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value,
282 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, prog_wm_value);
283
284 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
285 "HW register value = 0x%x\n",
286 watermarks->d.urgent_ns, prog_wm_value);
287 }
288
289 /* determine the transfer time for a quantity of data for a particular requestor.*/
290 if (safe_to_lower || watermarks->a.frac_urg_bw_flip
291 > hubbub1->watermarks.a.frac_urg_bw_flip) {
292 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
293
294 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
295 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->a.frac_urg_bw_flip);
296 }
297
298 if (safe_to_lower || watermarks->a.frac_urg_bw_nom
299 > hubbub1->watermarks.a.frac_urg_bw_nom) {
300 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
301
302 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
303 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->a.frac_urg_bw_nom);
304 }
305
306 if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub1->watermarks.d.urgent_latency_ns) {
307 hubbub1->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
308 prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
309 refclk_mhz, 0x1fffff);
310 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
311 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
312 }
313 }
314
hubbub21_program_stutter_watermarks(struct hubbub * hubbub,struct dcn_watermark_set * watermarks,unsigned int refclk_mhz,bool safe_to_lower)315 void hubbub21_program_stutter_watermarks(
316 struct hubbub *hubbub,
317 struct dcn_watermark_set *watermarks,
318 unsigned int refclk_mhz,
319 bool safe_to_lower)
320 {
321 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
322 uint32_t prog_wm_value;
323
324 /* clock state A */
325 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
326 > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
327 hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
328 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
329 prog_wm_value = convert_and_clamp(
330 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
331 refclk_mhz, 0x1fffff);
332 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
333 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value,
334 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
335 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
336 "HW register value = 0x%x\n",
337 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
338 }
339
340 if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
341 > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
342 hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
343 watermarks->a.cstate_pstate.cstate_exit_ns;
344 prog_wm_value = convert_and_clamp(
345 watermarks->a.cstate_pstate.cstate_exit_ns,
346 refclk_mhz, 0x1fffff);
347 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
348 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value,
349 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
350 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
351 "HW register value = 0x%x\n",
352 watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
353 }
354
355 /* clock state B */
356 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
357 > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
358 hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
359 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
360 prog_wm_value = convert_and_clamp(
361 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
362 refclk_mhz, 0x1fffff);
363 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
364 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value,
365 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
366 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
367 "HW register value = 0x%x\n",
368 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
369 }
370
371 if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
372 > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
373 hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
374 watermarks->b.cstate_pstate.cstate_exit_ns;
375 prog_wm_value = convert_and_clamp(
376 watermarks->b.cstate_pstate.cstate_exit_ns,
377 refclk_mhz, 0x1fffff);
378 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
379 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value,
380 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
381 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
382 "HW register value = 0x%x\n",
383 watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
384 }
385
386 /* clock state C */
387 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
388 > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
389 hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
390 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
391 prog_wm_value = convert_and_clamp(
392 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
393 refclk_mhz, 0x1fffff);
394 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
395 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value,
396 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
397 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
398 "HW register value = 0x%x\n",
399 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
400 }
401
402 if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
403 > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
404 hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
405 watermarks->c.cstate_pstate.cstate_exit_ns;
406 prog_wm_value = convert_and_clamp(
407 watermarks->c.cstate_pstate.cstate_exit_ns,
408 refclk_mhz, 0x1fffff);
409 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
410 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value,
411 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
412 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
413 "HW register value = 0x%x\n",
414 watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
415 }
416
417 /* clock state D */
418 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
419 > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
420 hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
421 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
422 prog_wm_value = convert_and_clamp(
423 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
424 refclk_mhz, 0x1fffff);
425 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
426 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value,
427 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
428 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
429 "HW register value = 0x%x\n",
430 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
431 }
432
433 if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
434 > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
435 hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
436 watermarks->d.cstate_pstate.cstate_exit_ns;
437 prog_wm_value = convert_and_clamp(
438 watermarks->d.cstate_pstate.cstate_exit_ns,
439 refclk_mhz, 0x1fffff);
440 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
441 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value,
442 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
443 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
444 "HW register value = 0x%x\n",
445 watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
446 }
447 }
448
hubbub21_program_pstate_watermarks(struct hubbub * hubbub,struct dcn_watermark_set * watermarks,unsigned int refclk_mhz,bool safe_to_lower)449 void hubbub21_program_pstate_watermarks(
450 struct hubbub *hubbub,
451 struct dcn_watermark_set *watermarks,
452 unsigned int refclk_mhz,
453 bool safe_to_lower)
454 {
455 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
456 uint32_t prog_wm_value;
457
458 /* clock state A */
459 if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
460 > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
461 hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
462 watermarks->a.cstate_pstate.pstate_change_ns;
463 prog_wm_value = convert_and_clamp(
464 watermarks->a.cstate_pstate.pstate_change_ns,
465 refclk_mhz, 0x1fffff);
466 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
467 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value,
468 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
469 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
470 "HW register value = 0x%x\n\n",
471 watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
472 }
473
474 /* clock state B */
475 if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
476 > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
477 hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
478 watermarks->b.cstate_pstate.pstate_change_ns;
479 prog_wm_value = convert_and_clamp(
480 watermarks->b.cstate_pstate.pstate_change_ns,
481 refclk_mhz, 0x1fffff);
482 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
483 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value,
484 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
485 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
486 "HW register value = 0x%x\n\n",
487 watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
488 }
489
490 /* clock state C */
491 if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
492 > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
493 hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
494 watermarks->c.cstate_pstate.pstate_change_ns;
495 prog_wm_value = convert_and_clamp(
496 watermarks->c.cstate_pstate.pstate_change_ns,
497 refclk_mhz, 0x1fffff);
498 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
499 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value,
500 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
501 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
502 "HW register value = 0x%x\n\n",
503 watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
504 }
505
506 /* clock state D */
507 if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
508 > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
509 hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
510 watermarks->d.cstate_pstate.pstate_change_ns;
511 prog_wm_value = convert_and_clamp(
512 watermarks->d.cstate_pstate.pstate_change_ns,
513 refclk_mhz, 0x1fffff);
514 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
515 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value,
516 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
517 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
518 "HW register value = 0x%x\n\n",
519 watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
520 }
521 }
522
hubbub21_program_watermarks(struct hubbub * hubbub,struct dcn_watermark_set * watermarks,unsigned int refclk_mhz,bool safe_to_lower)523 void hubbub21_program_watermarks(
524 struct hubbub *hubbub,
525 struct dcn_watermark_set *watermarks,
526 unsigned int refclk_mhz,
527 bool safe_to_lower)
528 {
529 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
530
531 hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
532 hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
533 hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
534
535 /*
536 * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
537 * If the memory controller is fully utilized and the DCHub requestors are
538 * well ahead of their amortized schedule, then it is safe to prevent the next winner
539 * from being committed and sent to the fabric.
540 * The utilization of the memory controller is approximated by ensuring that
541 * the number of outstanding requests is greater than a threshold specified
542 * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
543 * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
544 *
545 * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF)
546 * to turn off it for now.
547 */
548 REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
549 DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
550 REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
551 DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF,
552 DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA);
553 REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL,
554 DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF);
555
556 hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
557 }
558
hubbub21_wm_read_state(struct hubbub * hubbub,struct dcn_hubbub_wm * wm)559 void hubbub21_wm_read_state(struct hubbub *hubbub,
560 struct dcn_hubbub_wm *wm)
561 {
562 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
563 struct dcn_hubbub_wm_set *s;
564
565 memset(wm, 0, sizeof(struct dcn_hubbub_wm));
566
567 s = &wm->sets[0];
568 s->wm_set = 0;
569 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A,
570 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent);
571
572 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A,
573 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter);
574
575 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A,
576 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit);
577
578 REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A,
579 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, &s->dram_clk_chanage);
580
581 s = &wm->sets[1];
582 s->wm_set = 1;
583 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B,
584 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent);
585
586 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B,
587 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter);
588
589 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B,
590 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit);
591
592 REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B,
593 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, &s->dram_clk_chanage);
594
595 s = &wm->sets[2];
596 s->wm_set = 2;
597 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C,
598 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent);
599
600 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C,
601 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter);
602
603 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C,
604 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit);
605
606 REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C,
607 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, &s->dram_clk_chanage);
608
609 s = &wm->sets[3];
610 s->wm_set = 3;
611 REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D,
612 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent);
613
614 REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D,
615 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter);
616
617 REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D,
618 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit);
619
620 REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D,
621 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, &s->dram_clk_chanage);
622 }
623
hubbub21_apply_DEDCN21_147_wa(struct hubbub * hubbub)624 void hubbub21_apply_DEDCN21_147_wa(struct hubbub *hubbub)
625 {
626 struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
627 uint32_t prog_wm_value;
628
629 prog_wm_value = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
630 REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
631 }
632
633 static const struct hubbub_funcs hubbub21_funcs = {
634 .update_dchub = hubbub2_update_dchub,
635 .init_dchub_sys_ctx = hubbub21_init_dchub,
636 .init_vm_ctx = hubbub2_init_vm_ctx,
637 .dcc_support_swizzle = hubbub2_dcc_support_swizzle,
638 .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
639 .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap,
640 .wm_read_state = hubbub21_wm_read_state,
641 .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
642 .program_watermarks = hubbub21_program_watermarks,
643 .apply_DEDCN21_147_wa = hubbub21_apply_DEDCN21_147_wa,
644 };
645
hubbub21_construct(struct dcn20_hubbub * hubbub,struct dc_context * ctx,const struct dcn_hubbub_registers * hubbub_regs,const struct dcn_hubbub_shift * hubbub_shift,const struct dcn_hubbub_mask * hubbub_mask)646 void hubbub21_construct(struct dcn20_hubbub *hubbub,
647 struct dc_context *ctx,
648 const struct dcn_hubbub_registers *hubbub_regs,
649 const struct dcn_hubbub_shift *hubbub_shift,
650 const struct dcn_hubbub_mask *hubbub_mask)
651 {
652 hubbub->base.ctx = ctx;
653
654 hubbub->base.funcs = &hubbub21_funcs;
655
656 hubbub->regs = hubbub_regs;
657 hubbub->shifts = hubbub_shift;
658 hubbub->masks = hubbub_mask;
659
660 hubbub->debug_test_index_pstate = 0xB;
661 hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */
662 }
663