Merge branches 'clk-baikal', 'clk-broadcom', 'clk-vc5' and 'clk-versaclock' into...
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / amd / display / dc / dcn21 / dcn21_hubbub.c
1 /*
2 * Copyright 2018 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 #include <linux/delay.h>
26 #include "dm_services.h"
27 #include "dcn20/dcn20_hubbub.h"
28 #include "dcn21_hubbub.h"
29 #include "reg_helper.h"
30
31 #define REG(reg)\
32         hubbub1->regs->reg
33 #define DC_LOGGER \
34         hubbub1->base.ctx->logger
35 #define CTX \
36         hubbub1->base.ctx
37
38 #undef FN
39 #define FN(reg_name, field_name) \
40         hubbub1->shifts->field_name, hubbub1->masks->field_name
41
42 #define REG(reg)\
43         hubbub1->regs->reg
44
45 #define CTX \
46         hubbub1->base.ctx
47
48 #undef FN
49 #define FN(reg_name, field_name) \
50         hubbub1->shifts->field_name, hubbub1->masks->field_name
51
52 static uint32_t convert_and_clamp(
53         uint32_t wm_ns,
54         uint32_t refclk_mhz,
55         uint32_t clamp_value)
56 {
57         uint32_t ret_val = 0;
58         ret_val = wm_ns * refclk_mhz;
59         ret_val /= 1000;
60
61         if (ret_val > clamp_value)
62                 ret_val = clamp_value;
63
64         return ret_val;
65 }
66
67 void dcn21_dchvm_init(struct hubbub *hubbub)
68 {
69         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
70         uint32_t riommu_active, prefetch_done;
71         int i;
72
73         REG_GET(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, &prefetch_done);
74
75         if (prefetch_done) {
76                 hubbub->riommu_active = true;
77                 return;
78         }
79         //Init DCHVM block
80         REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
81
82         //Poll until RIOMMU_ACTIVE = 1
83         for (i = 0; i < 100; i++) {
84                 REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active);
85
86                 if (riommu_active)
87                         break;
88                 else
89                         udelay(5);
90         }
91
92         if (riommu_active) {
93                 //Reflect the power status of DCHUBBUB
94                 REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
95
96                 //Start rIOMMU prefetching
97                 REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
98
99                 // Enable dynamic clock gating
100                 REG_UPDATE_4(DCHVM_CLK_CTRL,
101                                                 HVM_DISPCLK_R_GATE_DIS, 0,
102                                                 HVM_DISPCLK_G_GATE_DIS, 0,
103                                                 HVM_DCFCLK_R_GATE_DIS, 0,
104                                                 HVM_DCFCLK_G_GATE_DIS, 0);
105
106                 //Poll until HOSTVM_PREFETCH_DONE = 1
107                 REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
108
109                 hubbub->riommu_active = true;
110         }
111 }
112
113 int hubbub21_init_dchub(struct hubbub *hubbub,
114                 struct dcn_hubbub_phys_addr_config *pa_config)
115 {
116         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
117         struct dcn_vmid_page_table_config phys_config;
118
119         REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
120                         FB_BASE, pa_config->system_aperture.fb_base >> 24);
121         REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
122                         FB_TOP, pa_config->system_aperture.fb_top >> 24);
123         REG_SET(DCN_VM_FB_OFFSET, 0,
124                         FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
125         REG_SET(DCN_VM_AGP_BOT, 0,
126                         AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
127         REG_SET(DCN_VM_AGP_TOP, 0,
128                         AGP_TOP, pa_config->system_aperture.agp_top >> 24);
129         REG_SET(DCN_VM_AGP_BASE, 0,
130                         AGP_BASE, pa_config->system_aperture.agp_base >> 24);
131
132         if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
133                 phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
134                 phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
135                 phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr | 1; //Note: hack
136                 phys_config.depth = 0;
137                 phys_config.block_size = 0;
138                 // Init VMID 0 based on PA config
139                 dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
140         }
141
142         dcn21_dchvm_init(hubbub);
143
144         return hubbub1->num_vmid;
145 }
146
147 bool hubbub21_program_urgent_watermarks(
148                 struct hubbub *hubbub,
149                 struct dcn_watermark_set *watermarks,
150                 unsigned int refclk_mhz,
151                 bool safe_to_lower)
152 {
153         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
154         uint32_t prog_wm_value;
155         bool wm_pending = false;
156
157         /* Repeat for water mark set A, B, C and D. */
158         /* clock state A */
159         if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
160                 hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
161                 prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
162                                 refclk_mhz, 0x1fffff);
163                 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
164                                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value,
165                                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value);
166
167                 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
168                         "HW register value = 0x%x\n",
169                         watermarks->a.urgent_ns, prog_wm_value);
170         } else if (watermarks->a.urgent_ns < hubbub1->watermarks.a.urgent_ns)
171                 wm_pending = true;
172
173         /* determine the transfer time for a quantity of data for a particular requestor.*/
174         if (safe_to_lower || watermarks->a.frac_urg_bw_flip
175                         > hubbub1->watermarks.a.frac_urg_bw_flip) {
176                 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
177
178                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
179                                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
180         } else if (watermarks->a.frac_urg_bw_flip
181                         < hubbub1->watermarks.a.frac_urg_bw_flip)
182                 wm_pending = true;
183
184         if (safe_to_lower || watermarks->a.frac_urg_bw_nom
185                         > hubbub1->watermarks.a.frac_urg_bw_nom) {
186                 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
187
188                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
189                                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
190         } else if (watermarks->a.frac_urg_bw_nom
191                         < hubbub1->watermarks.a.frac_urg_bw_nom)
192                 wm_pending = true;
193
194         if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub1->watermarks.a.urgent_latency_ns) {
195                 hubbub1->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
196                 prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
197                                 refclk_mhz, 0x1fffff);
198                 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
199                                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
200         } else if (watermarks->a.urgent_latency_ns < hubbub1->watermarks.a.urgent_latency_ns)
201                 wm_pending = true;
202
203         /* clock state B */
204         if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
205                 hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
206                 prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
207                                 refclk_mhz, 0x1fffff);
208                 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
209                                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value,
210                                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, prog_wm_value);
211
212                 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
213                         "HW register value = 0x%x\n",
214                         watermarks->b.urgent_ns, prog_wm_value);
215         } else if (watermarks->b.urgent_ns < hubbub1->watermarks.b.urgent_ns)
216                 wm_pending = true;
217
218         /* determine the transfer time for a quantity of data for a particular requestor.*/
219         if (safe_to_lower || watermarks->a.frac_urg_bw_flip
220                         > hubbub1->watermarks.a.frac_urg_bw_flip) {
221                 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
222
223                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
224                                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->a.frac_urg_bw_flip);
225         } else if (watermarks->a.frac_urg_bw_flip
226                         < hubbub1->watermarks.a.frac_urg_bw_flip)
227                 wm_pending = true;
228
229         if (safe_to_lower || watermarks->a.frac_urg_bw_nom
230                         > hubbub1->watermarks.a.frac_urg_bw_nom) {
231                 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
232
233                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
234                                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->a.frac_urg_bw_nom);
235         } else if (watermarks->a.frac_urg_bw_nom
236                         < hubbub1->watermarks.a.frac_urg_bw_nom)
237                 wm_pending = true;
238
239         if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub1->watermarks.b.urgent_latency_ns) {
240                 hubbub1->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
241                 prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
242                                 refclk_mhz, 0x1fffff);
243                 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
244                                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
245         } else if (watermarks->b.urgent_latency_ns < hubbub1->watermarks.b.urgent_latency_ns)
246                 wm_pending = true;
247
248         /* clock state C */
249         if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
250                 hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
251                 prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
252                                 refclk_mhz, 0x1fffff);
253                 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
254                                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value,
255                                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, prog_wm_value);
256
257                 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
258                         "HW register value = 0x%x\n",
259                         watermarks->c.urgent_ns, prog_wm_value);
260         } else if (watermarks->c.urgent_ns < hubbub1->watermarks.c.urgent_ns)
261                 wm_pending = true;
262
263         /* determine the transfer time for a quantity of data for a particular requestor.*/
264         if (safe_to_lower || watermarks->a.frac_urg_bw_flip
265                         > hubbub1->watermarks.a.frac_urg_bw_flip) {
266                 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
267
268                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
269                                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->a.frac_urg_bw_flip);
270         } else if (watermarks->a.frac_urg_bw_flip
271                         < hubbub1->watermarks.a.frac_urg_bw_flip)
272                 wm_pending = true;
273
274         if (safe_to_lower || watermarks->a.frac_urg_bw_nom
275                         > hubbub1->watermarks.a.frac_urg_bw_nom) {
276                 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
277
278                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
279                                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->a.frac_urg_bw_nom);
280         } else if (watermarks->a.frac_urg_bw_nom
281                         < hubbub1->watermarks.a.frac_urg_bw_nom)
282                 wm_pending = true;
283
284         if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub1->watermarks.c.urgent_latency_ns) {
285                 hubbub1->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
286                 prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
287                                 refclk_mhz, 0x1fffff);
288                 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
289                                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
290         } else if (watermarks->c.urgent_latency_ns < hubbub1->watermarks.c.urgent_latency_ns)
291                 wm_pending = true;
292
293         /* clock state D */
294         if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
295                 hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
296                 prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
297                                 refclk_mhz, 0x1fffff);
298                 REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
299                                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value,
300                                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, prog_wm_value);
301
302                 DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
303                         "HW register value = 0x%x\n",
304                         watermarks->d.urgent_ns, prog_wm_value);
305         } else if (watermarks->d.urgent_ns < hubbub1->watermarks.d.urgent_ns)
306                 wm_pending = true;
307
308         /* determine the transfer time for a quantity of data for a particular requestor.*/
309         if (safe_to_lower || watermarks->a.frac_urg_bw_flip
310                         > hubbub1->watermarks.a.frac_urg_bw_flip) {
311                 hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
312
313                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
314                                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->a.frac_urg_bw_flip);
315         } else if (watermarks->a.frac_urg_bw_flip
316                         < hubbub1->watermarks.a.frac_urg_bw_flip)
317                 wm_pending = true;
318
319         if (safe_to_lower || watermarks->a.frac_urg_bw_nom
320                         > hubbub1->watermarks.a.frac_urg_bw_nom) {
321                 hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
322
323                 REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
324                                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->a.frac_urg_bw_nom);
325         } else if (watermarks->a.frac_urg_bw_nom
326                         < hubbub1->watermarks.a.frac_urg_bw_nom)
327                 wm_pending = true;
328
329         if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub1->watermarks.d.urgent_latency_ns) {
330                 hubbub1->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
331                 prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
332                                 refclk_mhz, 0x1fffff);
333                 REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
334                                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
335         } else if (watermarks->d.urgent_latency_ns < hubbub1->watermarks.d.urgent_latency_ns)
336                 wm_pending = true;
337
338         return wm_pending;
339 }
340
341 bool hubbub21_program_stutter_watermarks(
342                 struct hubbub *hubbub,
343                 struct dcn_watermark_set *watermarks,
344                 unsigned int refclk_mhz,
345                 bool safe_to_lower)
346 {
347         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
348         uint32_t prog_wm_value;
349         bool wm_pending = false;
350
351         /* clock state A */
352         if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
353                         > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
354                 hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
355                                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
356                 prog_wm_value = convert_and_clamp(
357                                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
358                                 refclk_mhz, 0x1fffff);
359                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
360                                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value,
361                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
362                 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
363                         "HW register value = 0x%x\n",
364                         watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
365         } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
366                         < hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
367                 wm_pending = true;
368
369         if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
370                         > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
371                 hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
372                                 watermarks->a.cstate_pstate.cstate_exit_ns;
373                 prog_wm_value = convert_and_clamp(
374                                 watermarks->a.cstate_pstate.cstate_exit_ns,
375                                 refclk_mhz, 0x1fffff);
376                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
377                                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value,
378                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
379                 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
380                         "HW register value = 0x%x\n",
381                         watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
382         } else if (watermarks->a.cstate_pstate.cstate_exit_ns
383                         < hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns)
384                 wm_pending = true;
385
386         /* clock state B */
387         if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
388                         > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
389                 hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
390                                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
391                 prog_wm_value = convert_and_clamp(
392                                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
393                                 refclk_mhz, 0x1fffff);
394                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
395                                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value,
396                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
397                 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
398                         "HW register value = 0x%x\n",
399                         watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
400         } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
401                         < hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
402                 wm_pending = true;
403
404         if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
405                         > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
406                 hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
407                                 watermarks->b.cstate_pstate.cstate_exit_ns;
408                 prog_wm_value = convert_and_clamp(
409                                 watermarks->b.cstate_pstate.cstate_exit_ns,
410                                 refclk_mhz, 0x1fffff);
411                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
412                                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value,
413                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
414                 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
415                         "HW register value = 0x%x\n",
416                         watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
417         } else if (watermarks->b.cstate_pstate.cstate_exit_ns
418                         < hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns)
419                 wm_pending = true;
420
421         /* clock state C */
422         if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
423                         > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
424                 hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
425                                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
426                 prog_wm_value = convert_and_clamp(
427                                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
428                                 refclk_mhz, 0x1fffff);
429                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
430                                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value,
431                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
432                 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
433                         "HW register value = 0x%x\n",
434                         watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
435         } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
436                         < hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
437                 wm_pending = true;
438
439         if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
440                         > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
441                 hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
442                                 watermarks->c.cstate_pstate.cstate_exit_ns;
443                 prog_wm_value = convert_and_clamp(
444                                 watermarks->c.cstate_pstate.cstate_exit_ns,
445                                 refclk_mhz, 0x1fffff);
446                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
447                                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value,
448                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
449                 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
450                         "HW register value = 0x%x\n",
451                         watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
452         } else if (watermarks->c.cstate_pstate.cstate_exit_ns
453                         < hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns)
454                 wm_pending = true;
455
456         /* clock state D */
457         if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
458                         > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
459                 hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
460                                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
461                 prog_wm_value = convert_and_clamp(
462                                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
463                                 refclk_mhz, 0x1fffff);
464                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
465                                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value,
466                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
467                 DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
468                         "HW register value = 0x%x\n",
469                         watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
470         } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
471                         < hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
472                 wm_pending = true;
473
474         if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
475                         > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
476                 hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
477                                 watermarks->d.cstate_pstate.cstate_exit_ns;
478                 prog_wm_value = convert_and_clamp(
479                                 watermarks->d.cstate_pstate.cstate_exit_ns,
480                                 refclk_mhz, 0x1fffff);
481                 REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
482                                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value,
483                                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
484                 DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
485                         "HW register value = 0x%x\n",
486                         watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
487         } else if (watermarks->d.cstate_pstate.cstate_exit_ns
488                         < hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns)
489                 wm_pending = true;
490
491         return wm_pending;
492 }
493
494 bool hubbub21_program_pstate_watermarks(
495                 struct hubbub *hubbub,
496                 struct dcn_watermark_set *watermarks,
497                 unsigned int refclk_mhz,
498                 bool safe_to_lower)
499 {
500         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
501         uint32_t prog_wm_value;
502
503         bool wm_pending = false;
504
505         /* clock state A */
506         if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
507                         > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
508                 hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
509                                 watermarks->a.cstate_pstate.pstate_change_ns;
510                 prog_wm_value = convert_and_clamp(
511                                 watermarks->a.cstate_pstate.pstate_change_ns,
512                                 refclk_mhz, 0x1fffff);
513                 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
514                                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value,
515                                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
516                 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
517                         "HW register value = 0x%x\n\n",
518                         watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
519         } else if (watermarks->a.cstate_pstate.pstate_change_ns
520                         < hubbub1->watermarks.a.cstate_pstate.pstate_change_ns)
521                 wm_pending = true;
522
523         /* clock state B */
524         if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
525                         > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
526                 hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
527                                 watermarks->b.cstate_pstate.pstate_change_ns;
528                 prog_wm_value = convert_and_clamp(
529                                 watermarks->b.cstate_pstate.pstate_change_ns,
530                                 refclk_mhz, 0x1fffff);
531                 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
532                                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value,
533                                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
534                 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
535                         "HW register value = 0x%x\n\n",
536                         watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
537         } else if (watermarks->b.cstate_pstate.pstate_change_ns
538                         < hubbub1->watermarks.b.cstate_pstate.pstate_change_ns)
539                 wm_pending = false;
540
541         /* clock state C */
542         if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
543                         > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
544                 hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
545                                 watermarks->c.cstate_pstate.pstate_change_ns;
546                 prog_wm_value = convert_and_clamp(
547                                 watermarks->c.cstate_pstate.pstate_change_ns,
548                                 refclk_mhz, 0x1fffff);
549                 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
550                                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value,
551                                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
552                 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
553                         "HW register value = 0x%x\n\n",
554                         watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
555         } else if (watermarks->c.cstate_pstate.pstate_change_ns
556                         < hubbub1->watermarks.c.cstate_pstate.pstate_change_ns)
557                 wm_pending = true;
558
559         /* clock state D */
560         if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
561                         > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
562                 hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
563                                 watermarks->d.cstate_pstate.pstate_change_ns;
564                 prog_wm_value = convert_and_clamp(
565                                 watermarks->d.cstate_pstate.pstate_change_ns,
566                                 refclk_mhz, 0x1fffff);
567                 REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
568                                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value,
569                                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
570                 DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
571                         "HW register value = 0x%x\n\n",
572                         watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
573         } else if (watermarks->d.cstate_pstate.pstate_change_ns
574                         < hubbub1->watermarks.d.cstate_pstate.pstate_change_ns)
575                 wm_pending = true;
576
577         return wm_pending;
578 }
579
580 bool hubbub21_program_watermarks(
581                 struct hubbub *hubbub,
582                 struct dcn_watermark_set *watermarks,
583                 unsigned int refclk_mhz,
584                 bool safe_to_lower)
585 {
586         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
587         bool wm_pending = false;
588
589         if (hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
590                 wm_pending = true;
591
592         if (hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
593                 wm_pending = true;
594
595         if (hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
596                 wm_pending = true;
597
598         /*
599          * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
600          * If the memory controller is fully utilized and the DCHub requestors are
601          * well ahead of their amortized schedule, then it is safe to prevent the next winner
602          * from being committed and sent to the fabric.
603          * The utilization of the memory controller is approximated by ensuring that
604          * the number of outstanding requests is greater than a threshold specified
605          * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
606          * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
607          *
608          * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF)
609          * to turn off it for now.
610          */
611         REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
612                         DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
613         REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
614                         DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF,
615                         DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA);
616         REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL,
617                         DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF);
618
619         hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
620
621         return wm_pending;
622 }
623
624 void hubbub21_wm_read_state(struct hubbub *hubbub,
625                 struct dcn_hubbub_wm *wm)
626 {
627         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
628         struct dcn_hubbub_wm_set *s;
629
630         memset(wm, 0, sizeof(struct dcn_hubbub_wm));
631
632         s = &wm->sets[0];
633         s->wm_set = 0;
634         REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A,
635                         DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent);
636
637         REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A,
638                         DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter);
639
640         REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A,
641                         DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit);
642
643         REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A,
644                          DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, &s->dram_clk_chanage);
645
646         s = &wm->sets[1];
647         s->wm_set = 1;
648         REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B,
649                         DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent);
650
651         REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B,
652                         DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter);
653
654         REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B,
655                         DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit);
656
657         REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B,
658                         DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, &s->dram_clk_chanage);
659
660         s = &wm->sets[2];
661         s->wm_set = 2;
662         REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C,
663                         DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent);
664
665         REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C,
666                         DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter);
667
668         REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C,
669                         DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit);
670
671         REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C,
672                         DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, &s->dram_clk_chanage);
673
674         s = &wm->sets[3];
675         s->wm_set = 3;
676         REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D,
677                         DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent);
678
679         REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D,
680                         DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter);
681
682         REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D,
683                         DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit);
684
685         REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D,
686                         DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, &s->dram_clk_chanage);
687 }
688
689 static void hubbub21_apply_DEDCN21_147_wa(struct hubbub *hubbub)
690 {
691         struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
692         uint32_t prog_wm_value;
693
694         prog_wm_value = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
695         REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
696 }
697
698 static const struct hubbub_funcs hubbub21_funcs = {
699         .update_dchub = hubbub2_update_dchub,
700         .init_dchub_sys_ctx = hubbub21_init_dchub,
701         .init_vm_ctx = hubbub2_init_vm_ctx,
702         .dcc_support_swizzle = hubbub2_dcc_support_swizzle,
703         .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
704         .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap,
705         .wm_read_state = hubbub21_wm_read_state,
706         .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
707         .program_watermarks = hubbub21_program_watermarks,
708         .allow_self_refresh_control = hubbub1_allow_self_refresh_control,
709         .apply_DEDCN21_147_wa = hubbub21_apply_DEDCN21_147_wa,
710         .hubbub_read_state = hubbub2_read_state,
711 };
712
713 void hubbub21_construct(struct dcn20_hubbub *hubbub,
714         struct dc_context *ctx,
715         const struct dcn_hubbub_registers *hubbub_regs,
716         const struct dcn_hubbub_shift *hubbub_shift,
717         const struct dcn_hubbub_mask *hubbub_mask)
718 {
719         hubbub->base.ctx = ctx;
720
721         hubbub->base.funcs = &hubbub21_funcs;
722
723         hubbub->regs = hubbub_regs;
724         hubbub->shifts = hubbub_shift;
725         hubbub->masks = hubbub_mask;
726
727         hubbub->debug_test_index_pstate = 0xB;
728         hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */
729 }