xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/display/dc/dcn21/amdgpu_dcn21_hubbub.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
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