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