Merge tag 'tilcdc-4.22' of https://github.com/jsarha/linux into drm-next
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / dc / dcn10 / dcn10_hubbub.c
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 enable ? true : false;
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