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