1 /*
2  * Copyright 2016 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 
26 #include "dm_services.h"
27 #include "dcn10_hubp.h"
28 #include "dcn10_hubbub.h"
29 #include "reg_helper.h"
30 
31 #define CTX \
32 	hubbub->ctx
33 #define DC_LOGGER \
34 	hubbub->ctx->logger
35 #define REG(reg)\
36 	hubbub->regs->reg
37 
38 #undef FN
39 #define FN(reg_name, field_name) \
40 	hubbub->shifts->field_name, hubbub->masks->field_name
41 
42 void hubbub1_wm_read_state(struct hubbub *hubbub,
43 		struct dcn_hubbub_wm *wm)
44 {
45 	struct dcn_hubbub_wm_set *s;
46 
47 	memset(wm, 0, sizeof(struct dcn_hubbub_wm));
48 
49 	s = &wm->sets[0];
50 	s->wm_set = 0;
51 	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
52 	s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
53 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
54 		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
55 		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
56 	}
57 	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
58 
59 	s = &wm->sets[1];
60 	s->wm_set = 1;
61 	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
62 	s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
63 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
64 		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
65 		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
66 	}
67 	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
68 
69 	s = &wm->sets[2];
70 	s->wm_set = 2;
71 	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
72 	s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
73 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
74 		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
75 		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
76 	}
77 	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
78 
79 	s = &wm->sets[3];
80 	s->wm_set = 3;
81 	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
82 	s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
83 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
84 		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
85 		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
86 	}
87 	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
88 }
89 
90 void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub)
91 {
92 	REG_UPDATE(DCHUBBUB_ARB_DRAM_STATE_CNTL,
93 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, 0);
94 }
95 
96 bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
97 {
98 	uint32_t enable = 0;
99 
100 	REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
101 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable);
102 
103 	return true ? false : enable;
104 }
105 
106 
107 bool hubbub1_verify_allow_pstate_change_high(
108 	struct hubbub *hubbub)
109 {
110 	/* pstate latency is ~20us so if we wait over 40us and pstate allow
111 	 * still not asserted, we are probably stuck and going to hang
112 	 *
113 	 * TODO: Figure out why it takes ~100us on linux
114 	 * pstate takes around ~100us on linux. Unknown currently as to
115 	 * why it takes that long on linux
116 	 */
117 	static unsigned int pstate_wait_timeout_us = 200;
118 	static unsigned int pstate_wait_expected_timeout_us = 40;
119 	static unsigned int max_sampled_pstate_wait_us; /* data collection */
120 	static bool forced_pstate_allow; /* help with revert wa */
121 
122 	unsigned int debug_data;
123 	unsigned int i;
124 
125 	if (forced_pstate_allow) {
126 		/* we hacked to force pstate allow to prevent hang last time
127 		 * we verify_allow_pstate_change_high.  so disable force
128 		 * here so we can check status
129 		 */
130 		REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
131 			     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
132 			     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
133 		forced_pstate_allow = false;
134 	}
135 
136 	/* RV2:
137 	 * dchubbubdebugind, at: 0xB
138 	 * description
139 	 * 0:     Pipe0 Plane0 Allow Pstate Change
140 	 * 1:     Pipe0 Plane1 Allow Pstate Change
141 	 * 2:     Pipe0 Cursor0 Allow Pstate Change
142 	 * 3:     Pipe0 Cursor1 Allow Pstate Change
143 	 * 4:     Pipe1 Plane0 Allow Pstate Change
144 	 * 5:     Pipe1 Plane1 Allow Pstate Change
145 	 * 6:     Pipe1 Cursor0 Allow Pstate Change
146 	 * 7:     Pipe1 Cursor1 Allow Pstate Change
147 	 * 8:     Pipe2 Plane0 Allow Pstate Change
148 	 * 9:     Pipe2 Plane1 Allow Pstate Change
149 	 * 10:    Pipe2 Cursor0 Allow Pstate Change
150 	 * 11:    Pipe2 Cursor1 Allow Pstate Change
151 	 * 12:    Pipe3 Plane0 Allow Pstate Change
152 	 * 13:    Pipe3 Plane1 Allow Pstate Change
153 	 * 14:    Pipe3 Cursor0 Allow Pstate Change
154 	 * 15:    Pipe3 Cursor1 Allow Pstate Change
155 	 * 16:    Pipe4 Plane0 Allow Pstate Change
156 	 * 17:    Pipe4 Plane1 Allow Pstate Change
157 	 * 18:    Pipe4 Cursor0 Allow Pstate Change
158 	 * 19:    Pipe4 Cursor1 Allow Pstate Change
159 	 * 20:    Pipe5 Plane0 Allow Pstate Change
160 	 * 21:    Pipe5 Plane1 Allow Pstate Change
161 	 * 22:    Pipe5 Cursor0 Allow Pstate Change
162 	 * 23:    Pipe5 Cursor1 Allow Pstate Change
163 	 * 24:    Pipe6 Plane0 Allow Pstate Change
164 	 * 25:    Pipe6 Plane1 Allow Pstate Change
165 	 * 26:    Pipe6 Cursor0 Allow Pstate Change
166 	 * 27:    Pipe6 Cursor1 Allow Pstate Change
167 	 * 28:    WB0 Allow Pstate Change
168 	 * 29:    WB1 Allow Pstate Change
169 	 * 30:    Arbiter's allow_pstate_change
170 	 * 31:    SOC pstate change request"
171 	 *
172 	 * RV1:
173 	 * dchubbubdebugind, at: 0x7
174 	 * description "3-0:   Pipe0 cursor0 QOS
175 	 * 7-4:   Pipe1 cursor0 QOS
176 	 * 11-8:  Pipe2 cursor0 QOS
177 	 * 15-12: Pipe3 cursor0 QOS
178 	 * 16:    Pipe0 Plane0 Allow Pstate Change
179 	 * 17:    Pipe1 Plane0 Allow Pstate Change
180 	 * 18:    Pipe2 Plane0 Allow Pstate Change
181 	 * 19:    Pipe3 Plane0 Allow Pstate Change
182 	 * 20:    Pipe0 Plane1 Allow Pstate Change
183 	 * 21:    Pipe1 Plane1 Allow Pstate Change
184 	 * 22:    Pipe2 Plane1 Allow Pstate Change
185 	 * 23:    Pipe3 Plane1 Allow Pstate Change
186 	 * 24:    Pipe0 cursor0 Allow Pstate Change
187 	 * 25:    Pipe1 cursor0 Allow Pstate Change
188 	 * 26:    Pipe2 cursor0 Allow Pstate Change
189 	 * 27:    Pipe3 cursor0 Allow Pstate Change
190 	 * 28:    WB0 Allow Pstate Change
191 	 * 29:    WB1 Allow Pstate Change
192 	 * 30:    Arbiter's allow_pstate_change
193 	 * 31:    SOC pstate change request
194 	 */
195 
196 	REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub->debug_test_index_pstate);
197 
198 	for (i = 0; i < pstate_wait_timeout_us; i++) {
199 		debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
200 
201 		if (debug_data & (1 << 30)) {
202 
203 			if (i > pstate_wait_expected_timeout_us)
204 				DC_LOG_WARNING("pstate took longer than expected ~%dus\n",
205 						i);
206 
207 			return true;
208 		}
209 		if (max_sampled_pstate_wait_us < i)
210 			max_sampled_pstate_wait_us = i;
211 
212 		udelay(1);
213 	}
214 
215 	/* force pstate allow to prevent system hang
216 	 * and break to debugger to investigate
217 	 */
218 	REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
219 		     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
220 		     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
221 	forced_pstate_allow = true;
222 
223 	DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
224 			debug_data);
225 
226 	return false;
227 }
228 
229 static uint32_t convert_and_clamp(
230 	uint32_t wm_ns,
231 	uint32_t refclk_mhz,
232 	uint32_t clamp_value)
233 {
234 	uint32_t ret_val = 0;
235 	ret_val = wm_ns * refclk_mhz;
236 	ret_val /= 1000;
237 
238 	if (ret_val > clamp_value)
239 		ret_val = clamp_value;
240 
241 	return ret_val;
242 }
243 
244 
245 void hubbub1_wm_change_req_wa(struct hubbub *hubbub)
246 {
247 	REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
248 			DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1);
249 }
250 
251 void hubbub1_program_watermarks(
252 		struct hubbub *hubbub,
253 		struct dcn_watermark_set *watermarks,
254 		unsigned int refclk_mhz,
255 		bool safe_to_lower)
256 {
257 	uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0;
258 	/*
259 	 * Need to clamp to max of the register values (i.e. no wrap)
260 	 * for dcn1, all wm registers are 21-bit wide
261 	 */
262 	uint32_t prog_wm_value;
263 
264 
265 	/* Repeat for water mark set A, B, C and D. */
266 	/* clock state A */
267 	if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) {
268 		hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
269 		prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
270 				refclk_mhz, 0x1fffff);
271 		REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
272 
273 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
274 			"HW register value = 0x%x\n",
275 			watermarks->a.urgent_ns, prog_wm_value);
276 	}
277 
278 	if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) {
279 		hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
280 		prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
281 				refclk_mhz, 0x1fffff);
282 		REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
283 		DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
284 			"HW register value = 0x%x\n",
285 			watermarks->a.pte_meta_urgent_ns, prog_wm_value);
286 	}
287 
288 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
289 		if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
290 				> hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
291 			hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
292 					watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
293 			prog_wm_value = convert_and_clamp(
294 					watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
295 					refclk_mhz, 0x1fffff);
296 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
297 			DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
298 				"HW register value = 0x%x\n",
299 				watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
300 		}
301 
302 		if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
303 				> hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) {
304 			hubbub->watermarks.a.cstate_pstate.cstate_exit_ns =
305 					watermarks->a.cstate_pstate.cstate_exit_ns;
306 			prog_wm_value = convert_and_clamp(
307 					watermarks->a.cstate_pstate.cstate_exit_ns,
308 					refclk_mhz, 0x1fffff);
309 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
310 			DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
311 				"HW register value = 0x%x\n",
312 				watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
313 		}
314 	}
315 
316 	if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
317 			> hubbub->watermarks.a.cstate_pstate.pstate_change_ns) {
318 		hubbub->watermarks.a.cstate_pstate.pstate_change_ns =
319 				watermarks->a.cstate_pstate.pstate_change_ns;
320 		prog_wm_value = convert_and_clamp(
321 				watermarks->a.cstate_pstate.pstate_change_ns,
322 				refclk_mhz, 0x1fffff);
323 		REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
324 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
325 			"HW register value = 0x%x\n\n",
326 			watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
327 	}
328 
329 	/* clock state B */
330 	if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) {
331 		hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
332 		prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
333 				refclk_mhz, 0x1fffff);
334 		REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
335 
336 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
337 			"HW register value = 0x%x\n",
338 			watermarks->b.urgent_ns, prog_wm_value);
339 	}
340 
341 	if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) {
342 		hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
343 		prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
344 				refclk_mhz, 0x1fffff);
345 		REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
346 		DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
347 			"HW register value = 0x%x\n",
348 			watermarks->b.pte_meta_urgent_ns, prog_wm_value);
349 	}
350 
351 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
352 		if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
353 				> hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
354 			hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
355 					watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
356 			prog_wm_value = convert_and_clamp(
357 					watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
358 					refclk_mhz, 0x1fffff);
359 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
360 			DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
361 				"HW register value = 0x%x\n",
362 				watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
363 		}
364 
365 		if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
366 				> hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) {
367 			hubbub->watermarks.b.cstate_pstate.cstate_exit_ns =
368 					watermarks->b.cstate_pstate.cstate_exit_ns;
369 			prog_wm_value = convert_and_clamp(
370 					watermarks->b.cstate_pstate.cstate_exit_ns,
371 					refclk_mhz, 0x1fffff);
372 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
373 			DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
374 				"HW register value = 0x%x\n",
375 				watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
376 		}
377 	}
378 
379 	if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
380 			> hubbub->watermarks.b.cstate_pstate.pstate_change_ns) {
381 		hubbub->watermarks.b.cstate_pstate.pstate_change_ns =
382 				watermarks->b.cstate_pstate.pstate_change_ns;
383 		prog_wm_value = convert_and_clamp(
384 				watermarks->b.cstate_pstate.pstate_change_ns,
385 				refclk_mhz, 0x1fffff);
386 		REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
387 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
388 			"HW register value = 0x%x\n\n",
389 			watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
390 	}
391 
392 	/* clock state C */
393 	if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) {
394 		hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
395 		prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
396 				refclk_mhz, 0x1fffff);
397 		REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
398 
399 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
400 			"HW register value = 0x%x\n",
401 			watermarks->c.urgent_ns, prog_wm_value);
402 	}
403 
404 	if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) {
405 		hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
406 		prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
407 				refclk_mhz, 0x1fffff);
408 		REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
409 		DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
410 			"HW register value = 0x%x\n",
411 			watermarks->c.pte_meta_urgent_ns, prog_wm_value);
412 	}
413 
414 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
415 		if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
416 				> hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
417 			hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
418 					watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
419 			prog_wm_value = convert_and_clamp(
420 					watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
421 					refclk_mhz, 0x1fffff);
422 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
423 			DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
424 				"HW register value = 0x%x\n",
425 				watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
426 		}
427 
428 		if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
429 				> hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) {
430 			hubbub->watermarks.c.cstate_pstate.cstate_exit_ns =
431 					watermarks->c.cstate_pstate.cstate_exit_ns;
432 			prog_wm_value = convert_and_clamp(
433 					watermarks->c.cstate_pstate.cstate_exit_ns,
434 					refclk_mhz, 0x1fffff);
435 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
436 			DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
437 				"HW register value = 0x%x\n",
438 				watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
439 		}
440 	}
441 
442 	if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
443 			> hubbub->watermarks.c.cstate_pstate.pstate_change_ns) {
444 		hubbub->watermarks.c.cstate_pstate.pstate_change_ns =
445 				watermarks->c.cstate_pstate.pstate_change_ns;
446 		prog_wm_value = convert_and_clamp(
447 				watermarks->c.cstate_pstate.pstate_change_ns,
448 				refclk_mhz, 0x1fffff);
449 		REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
450 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
451 			"HW register value = 0x%x\n\n",
452 			watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
453 	}
454 
455 	/* clock state D */
456 	if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) {
457 		hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
458 		prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
459 				refclk_mhz, 0x1fffff);
460 		REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
461 
462 		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
463 			"HW register value = 0x%x\n",
464 			watermarks->d.urgent_ns, prog_wm_value);
465 	}
466 
467 	if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) {
468 		hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
469 		prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
470 				refclk_mhz, 0x1fffff);
471 		REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
472 		DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
473 			"HW register value = 0x%x\n",
474 			watermarks->d.pte_meta_urgent_ns, prog_wm_value);
475 	}
476 
477 	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
478 		if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
479 				> hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
480 			hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
481 					watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
482 			prog_wm_value = convert_and_clamp(
483 					watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
484 					refclk_mhz, 0x1fffff);
485 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
486 			DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
487 				"HW register value = 0x%x\n",
488 				watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
489 		}
490 
491 		if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
492 				> hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) {
493 			hubbub->watermarks.d.cstate_pstate.cstate_exit_ns =
494 					watermarks->d.cstate_pstate.cstate_exit_ns;
495 			prog_wm_value = convert_and_clamp(
496 					watermarks->d.cstate_pstate.cstate_exit_ns,
497 					refclk_mhz, 0x1fffff);
498 			REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
499 			DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
500 				"HW register value = 0x%x\n",
501 				watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
502 		}
503 	}
504 
505 	if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
506 			> hubbub->watermarks.d.cstate_pstate.pstate_change_ns) {
507 		hubbub->watermarks.d.cstate_pstate.pstate_change_ns =
508 				watermarks->d.cstate_pstate.pstate_change_ns;
509 		prog_wm_value = convert_and_clamp(
510 				watermarks->d.cstate_pstate.pstate_change_ns,
511 				refclk_mhz, 0x1fffff);
512 		REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
513 		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
514 			"HW register value = 0x%x\n\n",
515 			watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
516 	}
517 
518 	REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL,
519 			DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
520 	REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
521 			DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
522 
523 	REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
524 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
525 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en);
526 
527 #if 0
528 	REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
529 			DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1,
530 			DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
531 #endif
532 }
533 
534 void hubbub1_update_dchub(
535 	struct hubbub *hubbub,
536 	struct dchub_init_data *dh_data)
537 {
538 	if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) {
539 		ASSERT(false);
540 		/*should not come here*/
541 		return;
542 	}
543 	/* TODO: port code from dal2 */
544 	switch (dh_data->fb_mode) {
545 	case FRAME_BUFFER_MODE_ZFB_ONLY:
546 		/*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
547 		REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP,
548 				SDPIF_FB_TOP, 0);
549 
550 		REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
551 				SDPIF_FB_BASE, 0x0FFFF);
552 
553 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
554 				SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
555 
556 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
557 				SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
558 
559 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
560 				SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
561 						dh_data->zfb_size_in_byte - 1) >> 22);
562 		break;
563 	case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
564 		/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
565 
566 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
567 				SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
568 
569 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
570 				SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
571 
572 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
573 				SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
574 						dh_data->zfb_size_in_byte - 1) >> 22);
575 		break;
576 	case FRAME_BUFFER_MODE_LOCAL_ONLY:
577 		/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
578 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
579 				SDPIF_AGP_BASE, 0);
580 
581 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
582 				SDPIF_AGP_BOT, 0X03FFFF);
583 
584 		REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
585 				SDPIF_AGP_TOP, 0);
586 		break;
587 	default:
588 		break;
589 	}
590 
591 	dh_data->dchub_initialzied = true;
592 	dh_data->dchub_info_valid = false;
593 }
594 
595 void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
596 {
597 	uint32_t watermark_change_req;
598 
599 	REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
600 			DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req);
601 
602 	if (watermark_change_req)
603 		watermark_change_req = 0;
604 	else
605 		watermark_change_req = 1;
606 
607 	REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
608 			DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
609 }
610 
611 void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
612 {
613 	uint32_t reset_en = reset ? 1 : 0;
614 
615 	REG_UPDATE(DCHUBBUB_SOFT_RESET,
616 			DCHUBBUB_GLOBAL_SOFT_RESET, reset_en);
617 }
618 
619 static bool hubbub1_dcc_support_swizzle(
620 		enum swizzle_mode_values swizzle,
621 		unsigned int bytes_per_element,
622 		enum segment_order *segment_order_horz,
623 		enum segment_order *segment_order_vert)
624 {
625 	bool standard_swizzle = false;
626 	bool display_swizzle = false;
627 
628 	switch (swizzle) {
629 	case DC_SW_4KB_S:
630 	case DC_SW_64KB_S:
631 	case DC_SW_VAR_S:
632 	case DC_SW_4KB_S_X:
633 	case DC_SW_64KB_S_X:
634 	case DC_SW_VAR_S_X:
635 		standard_swizzle = true;
636 		break;
637 	case DC_SW_4KB_D:
638 	case DC_SW_64KB_D:
639 	case DC_SW_VAR_D:
640 	case DC_SW_4KB_D_X:
641 	case DC_SW_64KB_D_X:
642 	case DC_SW_VAR_D_X:
643 		display_swizzle = true;
644 		break;
645 	default:
646 		break;
647 	}
648 
649 	if (bytes_per_element == 1 && standard_swizzle) {
650 		*segment_order_horz = segment_order__contiguous;
651 		*segment_order_vert = segment_order__na;
652 		return true;
653 	}
654 	if (bytes_per_element == 2 && standard_swizzle) {
655 		*segment_order_horz = segment_order__non_contiguous;
656 		*segment_order_vert = segment_order__contiguous;
657 		return true;
658 	}
659 	if (bytes_per_element == 4 && standard_swizzle) {
660 		*segment_order_horz = segment_order__non_contiguous;
661 		*segment_order_vert = segment_order__contiguous;
662 		return true;
663 	}
664 	if (bytes_per_element == 8 && standard_swizzle) {
665 		*segment_order_horz = segment_order__na;
666 		*segment_order_vert = segment_order__contiguous;
667 		return true;
668 	}
669 	if (bytes_per_element == 8 && display_swizzle) {
670 		*segment_order_horz = segment_order__contiguous;
671 		*segment_order_vert = segment_order__non_contiguous;
672 		return true;
673 	}
674 
675 	return false;
676 }
677 
678 static bool hubbub1_dcc_support_pixel_format(
679 		enum surface_pixel_format format,
680 		unsigned int *bytes_per_element)
681 {
682 	/* DML: get_bytes_per_element */
683 	switch (format) {
684 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
685 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
686 		*bytes_per_element = 2;
687 		return true;
688 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
689 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
690 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
691 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
692 		*bytes_per_element = 4;
693 		return true;
694 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
695 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
696 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
697 		*bytes_per_element = 8;
698 		return true;
699 	default:
700 		return false;
701 	}
702 }
703 
704 static void hubbub1_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
705 		unsigned int bytes_per_element)
706 {
707 	/* copied from DML.  might want to refactor DML to leverage from DML */
708 	/* DML : get_blk256_size */
709 	if (bytes_per_element == 1) {
710 		*blk256_width = 16;
711 		*blk256_height = 16;
712 	} else if (bytes_per_element == 2) {
713 		*blk256_width = 16;
714 		*blk256_height = 8;
715 	} else if (bytes_per_element == 4) {
716 		*blk256_width = 8;
717 		*blk256_height = 8;
718 	} else if (bytes_per_element == 8) {
719 		*blk256_width = 8;
720 		*blk256_height = 4;
721 	}
722 }
723 
724 static void hubbub1_det_request_size(
725 		unsigned int height,
726 		unsigned int width,
727 		unsigned int bpe,
728 		bool *req128_horz_wc,
729 		bool *req128_vert_wc)
730 {
731 	unsigned int detile_buf_size = 164 * 1024;  /* 164KB for DCN1.0 */
732 
733 	unsigned int blk256_height = 0;
734 	unsigned int blk256_width = 0;
735 	unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
736 
737 	hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
738 
739 	swath_bytes_horz_wc = height * blk256_height * bpe;
740 	swath_bytes_vert_wc = width * blk256_width * bpe;
741 
742 	*req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
743 			false : /* full 256B request */
744 			true; /* half 128b request */
745 
746 	*req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
747 			false : /* full 256B request */
748 			true; /* half 128b request */
749 }
750 
751 static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub,
752 		const struct dc_dcc_surface_param *input,
753 		struct dc_surface_dcc_cap *output)
754 {
755 	struct dc *dc = hubbub->ctx->dc;
756 	/* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
757 	enum dcc_control dcc_control;
758 	unsigned int bpe;
759 	enum segment_order segment_order_horz, segment_order_vert;
760 	bool req128_horz_wc, req128_vert_wc;
761 
762 	memset(output, 0, sizeof(*output));
763 
764 	if (dc->debug.disable_dcc == DCC_DISABLE)
765 		return false;
766 
767 	if (!hubbub->funcs->dcc_support_pixel_format(input->format, &bpe))
768 		return false;
769 
770 	if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
771 			&segment_order_horz, &segment_order_vert))
772 		return false;
773 
774 	hubbub1_det_request_size(input->surface_size.height,  input->surface_size.width,
775 			bpe, &req128_horz_wc, &req128_vert_wc);
776 
777 	if (!req128_horz_wc && !req128_vert_wc) {
778 		dcc_control = dcc_control__256_256_xxx;
779 	} else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
780 		if (!req128_horz_wc)
781 			dcc_control = dcc_control__256_256_xxx;
782 		else if (segment_order_horz == segment_order__contiguous)
783 			dcc_control = dcc_control__128_128_xxx;
784 		else
785 			dcc_control = dcc_control__256_64_64;
786 	} else if (input->scan == SCAN_DIRECTION_VERTICAL) {
787 		if (!req128_vert_wc)
788 			dcc_control = dcc_control__256_256_xxx;
789 		else if (segment_order_vert == segment_order__contiguous)
790 			dcc_control = dcc_control__128_128_xxx;
791 		else
792 			dcc_control = dcc_control__256_64_64;
793 	} else {
794 		if ((req128_horz_wc &&
795 			segment_order_horz == segment_order__non_contiguous) ||
796 			(req128_vert_wc &&
797 			segment_order_vert == segment_order__non_contiguous))
798 			/* access_dir not known, must use most constraining */
799 			dcc_control = dcc_control__256_64_64;
800 		else
801 			/* reg128 is true for either horz and vert
802 			 * but segment_order is contiguous
803 			 */
804 			dcc_control = dcc_control__128_128_xxx;
805 	}
806 
807 	if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
808 		dcc_control != dcc_control__256_256_xxx)
809 		return false;
810 
811 	switch (dcc_control) {
812 	case dcc_control__256_256_xxx:
813 		output->grph.rgb.max_uncompressed_blk_size = 256;
814 		output->grph.rgb.max_compressed_blk_size = 256;
815 		output->grph.rgb.independent_64b_blks = false;
816 		break;
817 	case dcc_control__128_128_xxx:
818 		output->grph.rgb.max_uncompressed_blk_size = 128;
819 		output->grph.rgb.max_compressed_blk_size = 128;
820 		output->grph.rgb.independent_64b_blks = false;
821 		break;
822 	case dcc_control__256_64_64:
823 		output->grph.rgb.max_uncompressed_blk_size = 256;
824 		output->grph.rgb.max_compressed_blk_size = 64;
825 		output->grph.rgb.independent_64b_blks = true;
826 		break;
827 	}
828 
829 	output->capable = true;
830 	output->const_color_support = false;
831 
832 	return true;
833 }
834 
835 static const struct hubbub_funcs hubbub1_funcs = {
836 	.update_dchub = hubbub1_update_dchub,
837 	.dcc_support_swizzle = hubbub1_dcc_support_swizzle,
838 	.dcc_support_pixel_format = hubbub1_dcc_support_pixel_format,
839 	.get_dcc_compression_cap = hubbub1_get_dcc_compression_cap,
840 };
841 
842 void hubbub1_construct(struct hubbub *hubbub,
843 	struct dc_context *ctx,
844 	const struct dcn_hubbub_registers *hubbub_regs,
845 	const struct dcn_hubbub_shift *hubbub_shift,
846 	const struct dcn_hubbub_mask *hubbub_mask)
847 {
848 	hubbub->ctx = ctx;
849 
850 	hubbub->funcs = &hubbub1_funcs;
851 
852 	hubbub->regs = hubbub_regs;
853 	hubbub->shifts = hubbub_shift;
854 	hubbub->masks = hubbub_mask;
855 
856 	hubbub->debug_test_index_pstate = 0x7;
857 #if defined(CONFIG_DRM_AMD_DC_DCN1_01)
858 	if (ctx->dce_version == DCN_VERSION_1_01)
859 		hubbub->debug_test_index_pstate = 0xB;
860 #endif
861 }
862 
863