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