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