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