GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_vbif.c
1 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12
13 #define pr_fmt(fmt)     "[drm:%s:%d] " fmt, __func__, __LINE__
14
15 #include <linux/debugfs.h>
16
17 #include "dpu_vbif.h"
18 #include "dpu_hw_vbif.h"
19 #include "dpu_trace.h"
20
21 /**
22  * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt
23  * @vbif:       Pointer to hardware vbif driver
24  * @xin_id:     Client interface identifier
25  * @return:     0 if success; error code otherwise
26  */
27 static int _dpu_vbif_wait_for_xin_halt(struct dpu_hw_vbif *vbif, u32 xin_id)
28 {
29         ktime_t timeout;
30         bool status;
31         int rc;
32
33         if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) {
34                 DPU_ERROR("invalid arguments vbif %d\n", vbif != 0);
35                 return -EINVAL;
36         }
37
38         timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout);
39         for (;;) {
40                 status = vbif->ops.get_halt_ctrl(vbif, xin_id);
41                 if (status)
42                         break;
43                 if (ktime_compare_safe(ktime_get(), timeout) > 0) {
44                         status = vbif->ops.get_halt_ctrl(vbif, xin_id);
45                         break;
46                 }
47                 usleep_range(501, 1000);
48         }
49
50         if (!status) {
51                 rc = -ETIMEDOUT;
52                 DPU_ERROR("VBIF %d client %d not halting. TIMEDOUT.\n",
53                                 vbif->idx - VBIF_0, xin_id);
54         } else {
55                 rc = 0;
56                 DPU_DEBUG("VBIF %d client %d is halted\n",
57                                 vbif->idx - VBIF_0, xin_id);
58         }
59
60         return rc;
61 }
62
63 /**
64  * _dpu_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters
65  * @vbif:       Pointer to hardware vbif driver
66  * @ot_lim:     Pointer to OT limit to be modified
67  * @params:     Pointer to usecase parameters
68  */
69 static void _dpu_vbif_apply_dynamic_ot_limit(struct dpu_hw_vbif *vbif,
70                 u32 *ot_lim, struct dpu_vbif_set_ot_params *params)
71 {
72         u64 pps;
73         const struct dpu_vbif_dynamic_ot_tbl *tbl;
74         u32 i;
75
76         if (!vbif || !(vbif->cap->features & BIT(DPU_VBIF_QOS_OTLIM)))
77                 return;
78
79         /* Dynamic OT setting done only for WFD */
80         if (!params->is_wfd)
81                 return;
82
83         pps = params->frame_rate;
84         pps *= params->width;
85         pps *= params->height;
86
87         tbl = params->rd ? &vbif->cap->dynamic_ot_rd_tbl :
88                         &vbif->cap->dynamic_ot_wr_tbl;
89
90         for (i = 0; i < tbl->count; i++) {
91                 if (pps <= tbl->cfg[i].pps) {
92                         *ot_lim = tbl->cfg[i].ot_limit;
93                         break;
94                 }
95         }
96
97         DPU_DEBUG("vbif:%d xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n",
98                         vbif->idx - VBIF_0, params->xin_id,
99                         params->width, params->height, params->frame_rate,
100                         pps, *ot_lim);
101 }
102
103 /**
104  * _dpu_vbif_get_ot_limit - get OT based on usecase & configuration parameters
105  * @vbif:       Pointer to hardware vbif driver
106  * @params:     Pointer to usecase parameters
107  * @return:     OT limit
108  */
109 static u32 _dpu_vbif_get_ot_limit(struct dpu_hw_vbif *vbif,
110         struct dpu_vbif_set_ot_params *params)
111 {
112         u32 ot_lim = 0;
113         u32 val;
114
115         if (!vbif || !vbif->cap) {
116                 DPU_ERROR("invalid arguments vbif %d\n", vbif != 0);
117                 return -EINVAL;
118         }
119
120         if (vbif->cap->default_ot_wr_limit && !params->rd)
121                 ot_lim = vbif->cap->default_ot_wr_limit;
122         else if (vbif->cap->default_ot_rd_limit && params->rd)
123                 ot_lim = vbif->cap->default_ot_rd_limit;
124
125         /*
126          * If default ot is not set from dt/catalog,
127          * then do not configure it.
128          */
129         if (ot_lim == 0)
130                 goto exit;
131
132         /* Modify the limits if the target and the use case requires it */
133         _dpu_vbif_apply_dynamic_ot_limit(vbif, &ot_lim, params);
134
135         if (vbif && vbif->ops.get_limit_conf) {
136                 val = vbif->ops.get_limit_conf(vbif,
137                                 params->xin_id, params->rd);
138                 if (val == ot_lim)
139                         ot_lim = 0;
140         }
141
142 exit:
143         DPU_DEBUG("vbif:%d xin:%d ot_lim:%d\n",
144                         vbif->idx - VBIF_0, params->xin_id, ot_lim);
145         return ot_lim;
146 }
147
148 /**
149  * dpu_vbif_set_ot_limit - set OT based on usecase & configuration parameters
150  * @vbif:       Pointer to hardware vbif driver
151  * @params:     Pointer to usecase parameters
152  *
153  * Note this function would block waiting for bus halt.
154  */
155 void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms,
156                 struct dpu_vbif_set_ot_params *params)
157 {
158         struct dpu_hw_vbif *vbif = NULL;
159         struct dpu_hw_mdp *mdp;
160         bool forced_on = false;
161         u32 ot_lim;
162         int ret, i;
163
164         if (!dpu_kms) {
165                 DPU_ERROR("invalid arguments\n");
166                 return;
167         }
168         mdp = dpu_kms->hw_mdp;
169
170         for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
171                 if (dpu_kms->hw_vbif[i] &&
172                                 dpu_kms->hw_vbif[i]->idx == params->vbif_idx)
173                         vbif = dpu_kms->hw_vbif[i];
174         }
175
176         if (!vbif || !mdp) {
177                 DPU_DEBUG("invalid arguments vbif %d mdp %d\n",
178                                 vbif != 0, mdp != 0);
179                 return;
180         }
181
182         if (!mdp->ops.setup_clk_force_ctrl ||
183                         !vbif->ops.set_limit_conf ||
184                         !vbif->ops.set_halt_ctrl)
185                 return;
186
187         /* set write_gather_en for all write clients */
188         if (vbif->ops.set_write_gather_en && !params->rd)
189                 vbif->ops.set_write_gather_en(vbif, params->xin_id);
190
191         ot_lim = _dpu_vbif_get_ot_limit(vbif, params) & 0xFF;
192
193         if (ot_lim == 0)
194                 goto exit;
195
196         trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim,
197                 params->vbif_idx);
198
199         forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
200
201         vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim);
202
203         vbif->ops.set_halt_ctrl(vbif, params->xin_id, true);
204
205         ret = _dpu_vbif_wait_for_xin_halt(vbif, params->xin_id);
206         if (ret)
207                 trace_dpu_vbif_wait_xin_halt_fail(vbif->idx, params->xin_id);
208
209         vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);
210
211         if (forced_on)
212                 mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
213 exit:
214         return;
215 }
216
217 void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms,
218                 struct dpu_vbif_set_qos_params *params)
219 {
220         struct dpu_hw_vbif *vbif = NULL;
221         struct dpu_hw_mdp *mdp;
222         bool forced_on = false;
223         const struct dpu_vbif_qos_tbl *qos_tbl;
224         int i;
225
226         if (!dpu_kms || !params || !dpu_kms->hw_mdp) {
227                 DPU_ERROR("invalid arguments\n");
228                 return;
229         }
230         mdp = dpu_kms->hw_mdp;
231
232         for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
233                 if (dpu_kms->hw_vbif[i] &&
234                                 dpu_kms->hw_vbif[i]->idx == params->vbif_idx) {
235                         vbif = dpu_kms->hw_vbif[i];
236                         break;
237                 }
238         }
239
240         if (!vbif || !vbif->cap) {
241                 DPU_ERROR("invalid vbif %d\n", params->vbif_idx);
242                 return;
243         }
244
245         if (!vbif->ops.set_qos_remap || !mdp->ops.setup_clk_force_ctrl) {
246                 DPU_DEBUG("qos remap not supported\n");
247                 return;
248         }
249
250         qos_tbl = params->is_rt ? &vbif->cap->qos_rt_tbl :
251                         &vbif->cap->qos_nrt_tbl;
252
253         if (!qos_tbl->npriority_lvl || !qos_tbl->priority_lvl) {
254                 DPU_DEBUG("qos tbl not defined\n");
255                 return;
256         }
257
258         forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
259
260         for (i = 0; i < qos_tbl->npriority_lvl; i++) {
261                 DPU_DEBUG("vbif:%d xin:%d lvl:%d/%d\n",
262                                 params->vbif_idx, params->xin_id, i,
263                                 qos_tbl->priority_lvl[i]);
264                 vbif->ops.set_qos_remap(vbif, params->xin_id, i,
265                                 qos_tbl->priority_lvl[i]);
266         }
267
268         if (forced_on)
269                 mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
270 }
271
272 void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms)
273 {
274         struct dpu_hw_vbif *vbif;
275         u32 i, pnd, src;
276
277         if (!dpu_kms) {
278                 DPU_ERROR("invalid argument\n");
279                 return;
280         }
281
282         for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
283                 vbif = dpu_kms->hw_vbif[i];
284                 if (vbif && vbif->ops.clear_errors) {
285                         vbif->ops.clear_errors(vbif, &pnd, &src);
286                         if (pnd || src) {
287                                 DRM_DEBUG_KMS("VBIF %d: pnd 0x%X, src 0x%X\n",
288                                               vbif->idx - VBIF_0, pnd, src);
289                         }
290                 }
291         }
292 }
293
294 void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms)
295 {
296         struct dpu_hw_vbif *vbif;
297         int i, j;
298
299         if (!dpu_kms) {
300                 DPU_ERROR("invalid argument\n");
301                 return;
302         }
303
304         for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {
305                 vbif = dpu_kms->hw_vbif[i];
306                 if (vbif && vbif->cap && vbif->ops.set_mem_type) {
307                         for (j = 0; j < vbif->cap->memtype_count; j++)
308                                 vbif->ops.set_mem_type(
309                                                 vbif, j, vbif->cap->memtype[j]);
310                 }
311         }
312 }
313
314 #ifdef CONFIG_DEBUG_FS
315 void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms)
316 {
317         debugfs_remove_recursive(dpu_kms->debugfs_vbif);
318         dpu_kms->debugfs_vbif = NULL;
319 }
320
321 int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)
322 {
323         char vbif_name[32];
324         struct dentry *debugfs_vbif;
325         int i, j;
326
327         dpu_kms->debugfs_vbif = debugfs_create_dir("vbif", debugfs_root);
328         if (!dpu_kms->debugfs_vbif) {
329                 DPU_ERROR("failed to create vbif debugfs\n");
330                 return -EINVAL;
331         }
332
333         for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {
334                 struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i];
335
336                 snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id);
337
338                 debugfs_vbif = debugfs_create_dir(vbif_name,
339                                 dpu_kms->debugfs_vbif);
340
341                 debugfs_create_u32("features", 0600, debugfs_vbif,
342                         (u32 *)&vbif->features);
343
344                 debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif,
345                         (u32 *)&vbif->xin_halt_timeout);
346
347                 debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif,
348                         (u32 *)&vbif->default_ot_rd_limit);
349
350                 debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif,
351                         (u32 *)&vbif->default_ot_wr_limit);
352
353                 for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) {
354                         struct dpu_vbif_dynamic_ot_cfg *cfg =
355                                         &vbif->dynamic_ot_rd_tbl.cfg[j];
356
357                         snprintf(vbif_name, sizeof(vbif_name),
358                                         "dynamic_ot_rd_%d_pps", j);
359                         debugfs_create_u64(vbif_name, 0400, debugfs_vbif,
360                                         (u64 *)&cfg->pps);
361                         snprintf(vbif_name, sizeof(vbif_name),
362                                         "dynamic_ot_rd_%d_ot_limit", j);
363                         debugfs_create_u32(vbif_name, 0400, debugfs_vbif,
364                                         (u32 *)&cfg->ot_limit);
365                 }
366
367                 for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) {
368                         struct dpu_vbif_dynamic_ot_cfg *cfg =
369                                         &vbif->dynamic_ot_wr_tbl.cfg[j];
370
371                         snprintf(vbif_name, sizeof(vbif_name),
372                                         "dynamic_ot_wr_%d_pps", j);
373                         debugfs_create_u64(vbif_name, 0400, debugfs_vbif,
374                                         (u64 *)&cfg->pps);
375                         snprintf(vbif_name, sizeof(vbif_name),
376                                         "dynamic_ot_wr_%d_ot_limit", j);
377                         debugfs_create_u32(vbif_name, 0400, debugfs_vbif,
378                                         (u32 *)&cfg->ot_limit);
379                 }
380         }
381
382         return 0;
383 }
384 #endif