Line data Source code
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 : 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 :
42 0 : void hubbub1_wm_read_state(struct hubbub *hubbub,
43 : struct dcn_hubbub_wm *wm)
44 : {
45 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
46 : struct dcn_hubbub_wm_set *s;
47 :
48 0 : memset(wm, 0, sizeof(struct dcn_hubbub_wm));
49 :
50 0 : s = &wm->sets[0];
51 0 : s->wm_set = 0;
52 0 : s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
53 0 : s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
54 0 : if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
55 0 : s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
56 0 : s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
57 : }
58 0 : s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
59 :
60 0 : s = &wm->sets[1];
61 0 : s->wm_set = 1;
62 0 : s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
63 0 : s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
64 0 : if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
65 0 : s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
66 0 : s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
67 : }
68 0 : s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
69 :
70 0 : s = &wm->sets[2];
71 0 : s->wm_set = 2;
72 0 : s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
73 0 : s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
74 0 : if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
75 0 : s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
76 0 : s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
77 : }
78 0 : s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
79 :
80 0 : s = &wm->sets[3];
81 0 : s->wm_set = 3;
82 0 : s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
83 0 : s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
84 0 : if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
85 0 : s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
86 0 : s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
87 : }
88 0 : s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
89 0 : }
90 :
91 0 : void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow)
92 : {
93 0 : 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 0 : 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 0 : }
103 :
104 0 : bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
105 : {
106 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
107 0 : uint32_t enable = 0;
108 :
109 0 : REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
110 : DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable);
111 :
112 0 : return enable ? true : false;
113 : }
114 :
115 :
116 0 : bool hubbub1_verify_allow_pstate_change_high(
117 : struct hubbub *hubbub)
118 : {
119 0 : 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 0 : const unsigned int pstate_wait_timeout_us = 200;
129 0 : 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;
134 : unsigned int i;
135 :
136 0 : 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 0 : 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 0 : 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 0 : REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub1->debug_test_index_pstate);
186 :
187 0 : for (i = 0; i < pstate_wait_timeout_us; i++) {
188 0 : debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
189 :
190 0 : if (debug_data & (1 << 30)) {
191 :
192 0 : if (i > pstate_wait_expected_timeout_us)
193 0 : DC_LOG_WARNING("pstate took longer than expected ~%dus\n",
194 : i);
195 :
196 : return true;
197 : }
198 0 : if (max_sampled_pstate_wait_us < i)
199 0 : max_sampled_pstate_wait_us = i;
200 :
201 0 : udelay(1);
202 : }
203 :
204 : /* force pstate allow to prevent system hang
205 : * and break to debugger to investigate
206 : */
207 0 : 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 0 : forced_pstate_allow = true;
211 :
212 0 : DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
213 : debug_data);
214 :
215 0 : return false;
216 : }
217 :
218 : static uint32_t convert_and_clamp(
219 : uint32_t wm_ns,
220 : uint32_t refclk_mhz,
221 : uint32_t clamp_value)
222 : {
223 0 : uint32_t ret_val = 0;
224 0 : ret_val = wm_ns * refclk_mhz;
225 0 : ret_val /= 1000;
226 :
227 0 : if (ret_val > clamp_value)
228 0 : ret_val = clamp_value;
229 :
230 : return ret_val;
231 : }
232 :
233 :
234 0 : void hubbub1_wm_change_req_wa(struct hubbub *hubbub)
235 : {
236 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
237 :
238 0 : REG_UPDATE_SEQ_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
239 : DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0,
240 : DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
241 0 : }
242 :
243 0 : bool hubbub1_program_urgent_watermarks(
244 : struct hubbub *hubbub,
245 : struct dcn_watermark_set *watermarks,
246 : unsigned int refclk_mhz,
247 : bool safe_to_lower)
248 : {
249 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
250 : uint32_t prog_wm_value;
251 0 : bool wm_pending = false;
252 :
253 : /* Repeat for water mark set A, B, C and D. */
254 : /* clock state A */
255 0 : if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
256 0 : hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
257 0 : prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
258 : refclk_mhz, 0x1fffff);
259 0 : REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
260 : DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
261 :
262 0 : 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 0 : } else if (watermarks->a.urgent_ns < hubbub1->watermarks.a.urgent_ns)
266 0 : wm_pending = true;
267 :
268 0 : if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) {
269 0 : hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
270 0 : prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
271 : refclk_mhz, 0x1fffff);
272 0 : REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
273 0 : 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 0 : } else if (watermarks->a.pte_meta_urgent_ns < hubbub1->watermarks.a.pte_meta_urgent_ns)
277 0 : wm_pending = true;
278 :
279 : /* clock state B */
280 0 : if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
281 0 : hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
282 0 : prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
283 : refclk_mhz, 0x1fffff);
284 0 : REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
285 : DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
286 :
287 0 : 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 0 : } else if (watermarks->b.urgent_ns < hubbub1->watermarks.b.urgent_ns)
291 0 : wm_pending = true;
292 :
293 0 : if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) {
294 0 : hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
295 0 : prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
296 : refclk_mhz, 0x1fffff);
297 0 : REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
298 0 : 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 0 : } else if (watermarks->b.pte_meta_urgent_ns < hubbub1->watermarks.b.pte_meta_urgent_ns)
302 0 : wm_pending = true;
303 :
304 : /* clock state C */
305 0 : if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
306 0 : hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
307 0 : prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
308 : refclk_mhz, 0x1fffff);
309 0 : REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
310 : DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
311 :
312 0 : 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 0 : } else if (watermarks->c.urgent_ns < hubbub1->watermarks.c.urgent_ns)
316 0 : wm_pending = true;
317 :
318 0 : if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) {
319 0 : hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
320 0 : prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
321 : refclk_mhz, 0x1fffff);
322 0 : REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
323 0 : 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 0 : } else if (watermarks->c.pte_meta_urgent_ns < hubbub1->watermarks.c.pte_meta_urgent_ns)
327 0 : wm_pending = true;
328 :
329 : /* clock state D */
330 0 : if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
331 0 : hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
332 0 : prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
333 : refclk_mhz, 0x1fffff);
334 0 : REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
335 : DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
336 :
337 0 : 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 0 : } else if (watermarks->d.urgent_ns < hubbub1->watermarks.d.urgent_ns)
341 0 : wm_pending = true;
342 :
343 0 : if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) {
344 0 : hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
345 0 : prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
346 : refclk_mhz, 0x1fffff);
347 0 : REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
348 0 : 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 0 : } else if (watermarks->d.pte_meta_urgent_ns < hubbub1->watermarks.d.pte_meta_urgent_ns)
352 0 : wm_pending = true;
353 :
354 0 : return wm_pending;
355 : }
356 :
357 0 : bool hubbub1_program_stutter_watermarks(
358 : struct hubbub *hubbub,
359 : struct dcn_watermark_set *watermarks,
360 : unsigned int refclk_mhz,
361 : bool safe_to_lower)
362 : {
363 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
364 : uint32_t prog_wm_value;
365 0 : bool wm_pending = false;
366 :
367 : /* clock state A */
368 0 : if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
369 0 : > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
370 0 : hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
371 0 : watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
372 0 : prog_wm_value = convert_and_clamp(
373 : watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
374 : refclk_mhz, 0x1fffff);
375 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
376 : DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
377 0 : 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 0 : } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
381 : < hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
382 0 : wm_pending = true;
383 :
384 0 : if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
385 0 : > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
386 0 : hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
387 0 : watermarks->a.cstate_pstate.cstate_exit_ns;
388 0 : prog_wm_value = convert_and_clamp(
389 : watermarks->a.cstate_pstate.cstate_exit_ns,
390 : refclk_mhz, 0x1fffff);
391 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
392 : DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
393 0 : 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 0 : } else if (watermarks->a.cstate_pstate.cstate_exit_ns
397 : < hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns)
398 0 : wm_pending = true;
399 :
400 : /* clock state B */
401 0 : if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
402 0 : > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
403 0 : hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
404 0 : watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
405 0 : prog_wm_value = convert_and_clamp(
406 : watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
407 : refclk_mhz, 0x1fffff);
408 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
409 : DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
410 0 : 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 0 : } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
414 : < hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
415 0 : wm_pending = true;
416 :
417 0 : if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
418 0 : > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
419 0 : hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
420 0 : watermarks->b.cstate_pstate.cstate_exit_ns;
421 0 : prog_wm_value = convert_and_clamp(
422 : watermarks->b.cstate_pstate.cstate_exit_ns,
423 : refclk_mhz, 0x1fffff);
424 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
425 : DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
426 0 : 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 0 : } else if (watermarks->b.cstate_pstate.cstate_exit_ns
430 : < hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns)
431 0 : wm_pending = true;
432 :
433 : /* clock state C */
434 0 : if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
435 0 : > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
436 0 : hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
437 0 : watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
438 0 : prog_wm_value = convert_and_clamp(
439 : watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
440 : refclk_mhz, 0x1fffff);
441 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
442 : DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
443 0 : 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 0 : } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
447 : < hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
448 0 : wm_pending = true;
449 :
450 0 : if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
451 0 : > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
452 0 : hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
453 0 : watermarks->c.cstate_pstate.cstate_exit_ns;
454 0 : prog_wm_value = convert_and_clamp(
455 : watermarks->c.cstate_pstate.cstate_exit_ns,
456 : refclk_mhz, 0x1fffff);
457 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
458 : DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
459 0 : 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 0 : } else if (watermarks->c.cstate_pstate.cstate_exit_ns
463 : < hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns)
464 0 : wm_pending = true;
465 :
466 : /* clock state D */
467 0 : if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
468 0 : > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
469 0 : hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
470 0 : watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
471 0 : prog_wm_value = convert_and_clamp(
472 : watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
473 : refclk_mhz, 0x1fffff);
474 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
475 : DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
476 0 : 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 0 : } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
480 : < hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
481 0 : wm_pending = true;
482 :
483 0 : if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
484 0 : > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
485 0 : hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
486 0 : watermarks->d.cstate_pstate.cstate_exit_ns;
487 0 : prog_wm_value = convert_and_clamp(
488 : watermarks->d.cstate_pstate.cstate_exit_ns,
489 : refclk_mhz, 0x1fffff);
490 0 : REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
491 : DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
492 0 : 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 0 : } else if (watermarks->d.cstate_pstate.cstate_exit_ns
496 : < hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns)
497 0 : wm_pending = true;
498 :
499 0 : return wm_pending;
500 : }
501 :
502 0 : bool hubbub1_program_pstate_watermarks(
503 : struct hubbub *hubbub,
504 : struct dcn_watermark_set *watermarks,
505 : unsigned int refclk_mhz,
506 : bool safe_to_lower)
507 : {
508 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
509 : uint32_t prog_wm_value;
510 0 : bool wm_pending = false;
511 :
512 : /* clock state A */
513 0 : if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
514 0 : > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
515 0 : hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
516 0 : watermarks->a.cstate_pstate.pstate_change_ns;
517 0 : prog_wm_value = convert_and_clamp(
518 : watermarks->a.cstate_pstate.pstate_change_ns,
519 : refclk_mhz, 0x1fffff);
520 0 : REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
521 : DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
522 0 : 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 0 : } else if (watermarks->a.cstate_pstate.pstate_change_ns
526 : < hubbub1->watermarks.a.cstate_pstate.pstate_change_ns)
527 0 : wm_pending = true;
528 :
529 : /* clock state B */
530 0 : if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
531 0 : > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
532 0 : hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
533 0 : watermarks->b.cstate_pstate.pstate_change_ns;
534 0 : prog_wm_value = convert_and_clamp(
535 : watermarks->b.cstate_pstate.pstate_change_ns,
536 : refclk_mhz, 0x1fffff);
537 0 : REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
538 : DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
539 0 : 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 0 : } else if (watermarks->b.cstate_pstate.pstate_change_ns
543 : < hubbub1->watermarks.b.cstate_pstate.pstate_change_ns)
544 0 : wm_pending = true;
545 :
546 : /* clock state C */
547 0 : if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
548 0 : > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
549 0 : hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
550 0 : watermarks->c.cstate_pstate.pstate_change_ns;
551 0 : prog_wm_value = convert_and_clamp(
552 : watermarks->c.cstate_pstate.pstate_change_ns,
553 : refclk_mhz, 0x1fffff);
554 0 : REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
555 : DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
556 0 : 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 0 : } else if (watermarks->c.cstate_pstate.pstate_change_ns
560 : < hubbub1->watermarks.c.cstate_pstate.pstate_change_ns)
561 0 : wm_pending = true;
562 :
563 : /* clock state D */
564 0 : if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
565 0 : > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
566 0 : hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
567 0 : watermarks->d.cstate_pstate.pstate_change_ns;
568 0 : prog_wm_value = convert_and_clamp(
569 : watermarks->d.cstate_pstate.pstate_change_ns,
570 : refclk_mhz, 0x1fffff);
571 0 : REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
572 : DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
573 0 : 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 0 : } else if (watermarks->d.cstate_pstate.pstate_change_ns
577 : < hubbub1->watermarks.d.cstate_pstate.pstate_change_ns)
578 0 : wm_pending = true;
579 :
580 0 : return wm_pending;
581 : }
582 :
583 0 : bool hubbub1_program_watermarks(
584 : struct hubbub *hubbub,
585 : struct dcn_watermark_set *watermarks,
586 : unsigned int refclk_mhz,
587 : bool safe_to_lower)
588 : {
589 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
590 0 : 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 0 : if (hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
596 0 : wm_pending = true;
597 :
598 0 : if (hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
599 0 : wm_pending = true;
600 :
601 0 : if (hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
602 0 : wm_pending = true;
603 :
604 0 : REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL,
605 : DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
606 0 : REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
607 : DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
608 :
609 0 : 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 0 : return wm_pending;
617 : }
618 :
619 0 : void hubbub1_update_dchub(
620 : struct hubbub *hubbub,
621 : struct dchub_init_data *dh_data)
622 : {
623 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
624 :
625 0 : if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) {
626 0 : ASSERT(false);
627 : /*should not come here*/
628 : return;
629 : }
630 : /* TODO: port code from dal2 */
631 0 : 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 0 : REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP,
635 : SDPIF_FB_TOP, 0);
636 :
637 0 : REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
638 : SDPIF_FB_BASE, 0x0FFFF);
639 :
640 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
641 : SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
642 :
643 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
644 : SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
645 :
646 0 : 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 0 : break;
650 : case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
651 : /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
652 :
653 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
654 : SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
655 :
656 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
657 : SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
658 :
659 0 : 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 0 : break;
663 : case FRAME_BUFFER_MODE_LOCAL_ONLY:
664 : /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
665 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
666 : SDPIF_AGP_BASE, 0);
667 :
668 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
669 : SDPIF_AGP_BOT, 0X03FFFF);
670 :
671 0 : REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
672 : SDPIF_AGP_TOP, 0);
673 0 : break;
674 : default:
675 : break;
676 : }
677 :
678 0 : dh_data->dchub_initialzied = true;
679 0 : dh_data->dchub_info_valid = false;
680 : }
681 :
682 0 : void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
683 : {
684 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
685 :
686 : uint32_t watermark_change_req;
687 :
688 0 : REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
689 : DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req);
690 :
691 0 : if (watermark_change_req)
692 0 : watermark_change_req = 0;
693 : else
694 0 : watermark_change_req = 1;
695 :
696 0 : REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
697 : DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
698 0 : }
699 :
700 0 : void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
701 : {
702 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
703 :
704 0 : uint32_t reset_en = reset ? 1 : 0;
705 :
706 0 : REG_UPDATE(DCHUBBUB_SOFT_RESET,
707 : DCHUBBUB_GLOBAL_SOFT_RESET, reset_en);
708 0 : }
709 :
710 0 : 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 0 : bool standard_swizzle = false;
717 0 : 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 0 : standard_swizzle = true;
727 0 : 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 0 : display_swizzle = true;
735 0 : break;
736 : default:
737 : break;
738 : }
739 :
740 0 : if (bytes_per_element == 1 && standard_swizzle) {
741 0 : *segment_order_horz = segment_order__contiguous;
742 0 : *segment_order_vert = segment_order__na;
743 0 : return true;
744 : }
745 0 : if (bytes_per_element == 2 && standard_swizzle) {
746 0 : *segment_order_horz = segment_order__non_contiguous;
747 0 : *segment_order_vert = segment_order__contiguous;
748 0 : return true;
749 : }
750 0 : if (bytes_per_element == 4 && standard_swizzle) {
751 0 : *segment_order_horz = segment_order__non_contiguous;
752 0 : *segment_order_vert = segment_order__contiguous;
753 0 : return true;
754 : }
755 0 : if (bytes_per_element == 8 && standard_swizzle) {
756 0 : *segment_order_horz = segment_order__na;
757 0 : *segment_order_vert = segment_order__contiguous;
758 0 : return true;
759 : }
760 0 : if (bytes_per_element == 8 && display_swizzle) {
761 0 : *segment_order_horz = segment_order__contiguous;
762 0 : *segment_order_vert = segment_order__non_contiguous;
763 0 : return true;
764 : }
765 :
766 : return false;
767 : }
768 :
769 0 : 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 0 : *bytes_per_element = 2;
778 0 : 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 0 : *bytes_per_element = 4;
784 0 : 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 0 : *bytes_per_element = 8;
790 0 : return true;
791 : default:
792 : return false;
793 : }
794 : }
795 :
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 0 : if (bytes_per_element == 1) {
802 : *blk256_width = 16;
803 : *blk256_height = 16;
804 0 : } else if (bytes_per_element == 2) {
805 : *blk256_width = 16;
806 : *blk256_height = 8;
807 0 : } else if (bytes_per_element == 4) {
808 : *blk256_width = 8;
809 : *blk256_height = 8;
810 0 : } else if (bytes_per_element == 8) {
811 0 : *blk256_width = 8;
812 0 : *blk256_height = 4;
813 : }
814 : }
815 :
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 0 : unsigned int detile_buf_size = 164 * 1024; /* 164KB for DCN1.0 */
824 :
825 0 : unsigned int blk256_height = 0;
826 0 : unsigned int blk256_width = 0;
827 : unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
828 :
829 0 : hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
830 :
831 0 : swath_bytes_horz_wc = width * blk256_height * bpe;
832 0 : swath_bytes_vert_wc = height * blk256_width * bpe;
833 :
834 0 : *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
835 : false : /* full 256B request */
836 : true; /* half 128b request */
837 :
838 0 : *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
839 : false : /* full 256B request */
840 : true; /* half 128b request */
841 : }
842 :
843 0 : 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 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
848 0 : 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 0 : memset(output, 0, sizeof(*output));
857 :
858 0 : if (dc->debug.disable_dcc == DCC_DISABLE)
859 : return false;
860 :
861 0 : if (!hubbub1->base.funcs->dcc_support_pixel_format(input->format, &bpe))
862 : return false;
863 :
864 0 : if (!hubbub1->base.funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
865 : &segment_order_horz, &segment_order_vert))
866 : return false;
867 :
868 0 : hubbub1_det_request_size(input->surface_size.height, input->surface_size.width,
869 : bpe, &req128_horz_wc, &req128_vert_wc);
870 :
871 0 : if (!req128_horz_wc && !req128_vert_wc) {
872 : dcc_control = dcc_control__256_256_xxx;
873 0 : } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
874 0 : if (!req128_horz_wc)
875 : dcc_control = dcc_control__256_256_xxx;
876 0 : else if (segment_order_horz == segment_order__contiguous)
877 : dcc_control = dcc_control__128_128_xxx;
878 : else
879 0 : dcc_control = dcc_control__256_64_64;
880 0 : } else if (input->scan == SCAN_DIRECTION_VERTICAL) {
881 0 : if (!req128_vert_wc)
882 : dcc_control = dcc_control__256_256_xxx;
883 0 : else if (segment_order_vert == segment_order__contiguous)
884 : dcc_control = dcc_control__128_128_xxx;
885 : else
886 0 : dcc_control = dcc_control__256_64_64;
887 : } else {
888 0 : if ((req128_horz_wc &&
889 0 : segment_order_horz == segment_order__non_contiguous) ||
890 0 : (req128_vert_wc &&
891 0 : 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 0 : dcc_control = dcc_control__128_128_xxx;
899 : }
900 :
901 0 : if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
902 : dcc_control != dcc_control__256_256_xxx)
903 : return false;
904 :
905 0 : switch (dcc_control) {
906 : case dcc_control__256_256_xxx:
907 0 : output->grph.rgb.max_uncompressed_blk_size = 256;
908 0 : output->grph.rgb.max_compressed_blk_size = 256;
909 0 : output->grph.rgb.independent_64b_blks = false;
910 0 : break;
911 : case dcc_control__128_128_xxx:
912 0 : output->grph.rgb.max_uncompressed_blk_size = 128;
913 0 : output->grph.rgb.max_compressed_blk_size = 128;
914 0 : output->grph.rgb.independent_64b_blks = false;
915 0 : break;
916 : case dcc_control__256_64_64:
917 0 : output->grph.rgb.max_uncompressed_blk_size = 256;
918 0 : output->grph.rgb.max_compressed_blk_size = 64;
919 0 : output->grph.rgb.independent_64b_blks = true;
920 0 : break;
921 : default:
922 0 : ASSERT(false);
923 : break;
924 : }
925 :
926 0 : output->capable = true;
927 0 : output->const_color_support = false;
928 :
929 0 : 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 :
944 0 : 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 0 : struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
951 :
952 0 : hubbub1->base.ctx = ctx;
953 :
954 0 : hubbub1->base.funcs = &hubbub1_funcs;
955 :
956 0 : hubbub1->regs = hubbub_regs;
957 0 : hubbub1->shifts = hubbub_shift;
958 0 : hubbub1->masks = hubbub_mask;
959 :
960 0 : hubbub1->debug_test_index_pstate = 0x7;
961 0 : if (ctx->dce_version == DCN_VERSION_1_01)
962 0 : hubbub1->debug_test_index_pstate = 0xB;
963 0 : }
964 :
|