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