blob: 360dfbb30c67ce814c021da7d06a84c3ba016338 [file] [log] [blame]
Benjamin Chan869179a2017-01-11 02:41:56 -05001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002 *
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
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/delay.h>
17#include <linux/interrupt.h>
18
19#include "sde_rotator_r1_hwio.h"
20#include "sde_rotator_util.h"
21#include "sde_rotator_r1_internal.h"
22#include "sde_rotator_core.h"
23
24/* wait for at most 2 vsync for lowest refresh rate (24hz) */
25#define KOFF_TIMEOUT msecs_to_jiffies(84)
26
27/*
28 * if BWC enabled and format is H1V2 or 420, do not use site C or I.
29 * Hence, set the bits 29:26 in format register, as zero.
30 */
31#define BWC_FMT_MASK 0xC3FFFFFF
32#define MDSS_DEFAULT_OT_SETTING 0x10
33
34enum sde_mdp_writeback_type {
35 SDE_MDP_WRITEBACK_TYPE_ROTATOR,
36 SDE_MDP_WRITEBACK_TYPE_LINE,
37 SDE_MDP_WRITEBACK_TYPE_WFD,
38};
39
40struct sde_mdp_writeback_ctx {
41 u32 wb_num;
42 char __iomem *base;
43 u8 ref_cnt;
44 u8 type;
45 struct completion wb_comp;
46 int comp_cnt;
47
48 u32 intr_type;
49 u32 intf_num;
50
51 u32 xin_id;
52 u32 wr_lim;
53 struct sde_mdp_shared_reg_ctrl clk_ctrl;
54
55 u32 opmode;
56 struct sde_mdp_format_params *dst_fmt;
57 u16 img_width;
58 u16 img_height;
59 u16 width;
60 u16 height;
61 struct sde_rect dst_rect;
62
63 u32 dnsc_factor_w;
64 u32 dnsc_factor_h;
65
66 u8 rot90;
67 u32 bwc_mode;
68
69 struct sde_mdp_plane_sizes dst_planes;
70
71 ktime_t start_time;
72 ktime_t end_time;
73 u32 offset;
74};
75
76static struct sde_mdp_writeback_ctx wb_ctx_list[SDE_MDP_MAX_WRITEBACK] = {
77 {
78 .type = SDE_MDP_WRITEBACK_TYPE_ROTATOR,
79 .intr_type = SDE_MDP_IRQ_WB_ROT_COMP,
80 .intf_num = 0,
81 .xin_id = 3,
82 .clk_ctrl.reg_off = 0x2BC,
83 .clk_ctrl.bit_off = 0x8,
84 },
85 {
86 .type = SDE_MDP_WRITEBACK_TYPE_ROTATOR,
87 .intr_type = SDE_MDP_IRQ_WB_ROT_COMP,
88 .intf_num = 1,
89 .xin_id = 11,
90 .clk_ctrl.reg_off = 0x2BC,
91 .clk_ctrl.bit_off = 0xC,
92 },
93};
94
95static inline void sde_wb_write(struct sde_mdp_writeback_ctx *ctx,
96 u32 reg, u32 val)
97{
98 SDEROT_DBG("wb%d:%6.6x:%8.8x\n", ctx->wb_num, ctx->offset + reg, val);
99 writel_relaxed(val, ctx->base + reg);
100}
101
102static int sde_mdp_writeback_addr_setup(struct sde_mdp_writeback_ctx *ctx,
103 const struct sde_mdp_data *in_data)
104{
105 int ret;
106 struct sde_mdp_data data;
107
108 if (!in_data)
109 return -EINVAL;
110 data = *in_data;
111
112 SDEROT_DBG("wb_num=%d addr=0x%pa\n", ctx->wb_num, &data.p[0].addr);
113
114 ret = sde_mdp_data_check(&data, &ctx->dst_planes, ctx->dst_fmt);
115 if (ret)
116 return ret;
117
118 sde_rot_data_calc_offset(&data, ctx->dst_rect.x, ctx->dst_rect.y,
119 &ctx->dst_planes, ctx->dst_fmt);
120
121 if ((ctx->dst_fmt->fetch_planes == SDE_MDP_PLANE_PLANAR) &&
122 (ctx->dst_fmt->element[0] == C1_B_Cb))
123 swap(data.p[1].addr, data.p[2].addr);
124
125 sde_wb_write(ctx, SDE_MDP_REG_WB_DST0_ADDR, data.p[0].addr);
126 sde_wb_write(ctx, SDE_MDP_REG_WB_DST1_ADDR, data.p[1].addr);
127 sde_wb_write(ctx, SDE_MDP_REG_WB_DST2_ADDR, data.p[2].addr);
128 sde_wb_write(ctx, SDE_MDP_REG_WB_DST3_ADDR, data.p[3].addr);
129
130 return 0;
131}
132
133static int sde_mdp_writeback_format_setup(struct sde_mdp_writeback_ctx *ctx,
134 u32 format, struct sde_mdp_ctl *ctl)
135{
136 struct sde_mdp_format_params *fmt;
137 u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
138 u32 dnsc_factor, write_config = 0;
139 u32 opmode = ctx->opmode;
140 bool rotation = false;
141 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
142
143 SDEROT_DBG("wb_num=%d format=%d\n", ctx->wb_num, format);
144
145 if (ctx->rot90)
146 rotation = true;
147
148 fmt = sde_get_format_params(format);
149 if (!fmt) {
150 SDEROT_ERR("wb format=%d not supported\n", format);
151 return -EINVAL;
152 }
153
154 sde_mdp_get_plane_sizes(fmt, ctx->img_width, ctx->img_height,
155 &ctx->dst_planes,
156 ctx->opmode & SDE_MDP_OP_BWC_EN, rotation);
157
158 ctx->dst_fmt = fmt;
159
160 chroma_samp = fmt->chroma_sample;
161
162 dst_format = (chroma_samp << 23) |
163 (fmt->fetch_planes << 19) |
164 (fmt->bits[C3_ALPHA] << 6) |
165 (fmt->bits[C2_R_Cr] << 4) |
166 (fmt->bits[C1_B_Cb] << 2) |
167 (fmt->bits[C0_G_Y] << 0);
168
169 dst_format &= BWC_FMT_MASK;
170
171 if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
172 dst_format |= BIT(8); /* DSTC3_EN */
173 if (!fmt->alpha_enable)
174 dst_format |= BIT(14); /* DST_ALPHA_X */
175 }
176
177 if (fmt->is_yuv)
178 dst_format |= BIT(15);
179
180 pattern = (fmt->element[3] << 24) |
181 (fmt->element[2] << 16) |
182 (fmt->element[1] << 8) |
183 (fmt->element[0] << 0);
184
185 dst_format |= (fmt->unpack_align_msb << 18) |
186 (fmt->unpack_tight << 17) |
187 ((fmt->unpack_count - 1) << 12) |
188 ((fmt->bpp - 1) << 9);
189
190 ystride0 = (ctx->dst_planes.ystride[0]) |
191 (ctx->dst_planes.ystride[1] << 16);
192 ystride1 = (ctx->dst_planes.ystride[2]) |
193 (ctx->dst_planes.ystride[3] << 16);
194 outsize = (ctx->dst_rect.h << 16) | ctx->dst_rect.w;
195
196 if (sde_mdp_is_ubwc_format(fmt)) {
197 opmode |= BIT(0);
198
199 dst_format |= BIT(31);
200 if (mdata->highest_bank_bit)
201 write_config |= (mdata->highest_bank_bit << 8);
202
203 if (fmt->format == SDE_PIX_FMT_RGB_565_UBWC)
204 write_config |= 0x8;
205 }
206
207 if (ctx->type == SDE_MDP_WRITEBACK_TYPE_ROTATOR) {
208 dnsc_factor = (ctx->dnsc_factor_h) | (ctx->dnsc_factor_w << 16);
209 sde_wb_write(ctx, SDE_MDP_REG_WB_ROTATOR_PIPE_DOWNSCALER,
210 dnsc_factor);
211 }
212 sde_wb_write(ctx, SDE_MDP_REG_WB_ALPHA_X_VALUE, 0xFF);
213 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_FORMAT, dst_format);
214 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_OP_MODE, opmode);
215 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_PACK_PATTERN, pattern);
216 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_YSTRIDE0, ystride0);
217 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_YSTRIDE1, ystride1);
218 sde_wb_write(ctx, SDE_MDP_REG_WB_OUT_SIZE, outsize);
219 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_WRITE_CONFIG, write_config);
220 return 0;
221}
222
223static int sde_mdp_writeback_prepare_rot(struct sde_mdp_ctl *ctl, void *arg)
224{
225 struct sde_mdp_writeback_ctx *ctx;
226 struct sde_mdp_writeback_arg *wb_args;
227 struct sde_rot_entry *entry;
228 struct sde_rotation_item *item;
229 struct sde_rot_data_type *mdata;
230 u32 format;
231
232 ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data;
233 if (!ctx)
234 return -ENODEV;
235 wb_args = (struct sde_mdp_writeback_arg *) arg;
236 if (!wb_args)
237 return -ENOENT;
238
239 entry = (struct sde_rot_entry *) wb_args->priv_data;
240 if (!entry) {
241 SDEROT_ERR("unable to retrieve rot session ctl=%d\n", ctl->num);
242 return -ENODEV;
243 }
244 item = &entry->item;
245 mdata = ctl->mdata;
246 if (!mdata) {
247 SDEROT_ERR("no mdata attached to ctl=%d", ctl->num);
248 return -ENODEV;
249 }
250 SDEROT_DBG("rot setup wb_num=%d\n", ctx->wb_num);
251
252 ctx->opmode = BIT(6); /* ROT EN */
253 if (ctl->mdata->rot_block_size == 128)
254 ctx->opmode |= BIT(4); /* block size 128 */
255
256 ctx->bwc_mode = 0;
257 ctx->opmode |= ctx->bwc_mode;
258
259 ctx->img_width = item->output.width;
260 ctx->img_height = item->output.height;
261 ctx->width = ctx->dst_rect.w = item->dst_rect.w;
262 ctx->height = ctx->dst_rect.h = item->dst_rect.h;
263 ctx->dst_rect.x = item->dst_rect.x;
264 ctx->dst_rect.y = item->dst_rect.y;
265 ctx->dnsc_factor_w = entry->dnsc_factor_w;
266 ctx->dnsc_factor_h = entry->dnsc_factor_h;
267
268 ctx->rot90 = !!(item->flags & SDE_ROTATION_90);
269
270 format = item->output.format;
271
272 if (ctx->rot90)
273 ctx->opmode |= BIT(5); /* ROT 90 */
274
275 return sde_mdp_writeback_format_setup(ctx, format, ctl);
276}
277
278static int sde_mdp_writeback_stop(struct sde_mdp_ctl *ctl,
279 int panel_power_state)
280{
281 struct sde_mdp_writeback_ctx *ctx;
282
283 SDEROT_DBG("stop ctl=%d\n", ctl->num);
284
285 ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data;
286 if (ctx) {
287 sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
288 NULL, NULL);
289
290 complete_all(&ctx->wb_comp);
291
292 ctl->priv_data = NULL;
293 ctx->ref_cnt--;
294 }
295
296 return 0;
297}
298
299static void sde_mdp_writeback_intr_done(void *arg)
300{
301 struct sde_mdp_ctl *ctl = arg;
302 struct sde_mdp_writeback_ctx *ctx = ctl->priv_data;
303
304 if (!ctx) {
305 SDEROT_ERR("invalid ctx\n");
306 return;
307 }
308
309 SDEROT_DBG("intr wb_num=%d\n", ctx->wb_num);
310 if (ctl->irq_num >= 0)
311 disable_irq_nosync(ctl->irq_num);
312 complete_all(&ctx->wb_comp);
313}
314
315static int sde_mdp_wb_wait4comp(struct sde_mdp_ctl *ctl, void *arg)
316{
317 struct sde_mdp_writeback_ctx *ctx;
318 int rc = 0;
Benjamin Chan62b94ed2016-08-18 23:55:21 -0400319 u64 rot_time = 0;
Benjamin Chan869179a2017-01-11 02:41:56 -0500320 u32 status, mask, isr = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700321
322 ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data;
323 if (!ctx) {
324 SDEROT_ERR("invalid ctx\n");
325 return -ENODEV;
326 }
327
328 if (ctx->comp_cnt == 0)
329 return rc;
330
331 if (ctl->irq_num >= 0) {
332 rc = wait_for_completion_timeout(&ctx->wb_comp,
333 KOFF_TIMEOUT);
334 sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
335 NULL, NULL);
336
337 if (rc == 0) {
338 mask = BIT(ctx->intr_type + ctx->intf_num);
339
340 isr = readl_relaxed(ctl->mdata->mdp_base +
341 SDE_MDP_REG_INTR_STATUS);
342 status = mask & isr;
343
344 SDEROT_INFO_ONCE(
345 "mask: 0x%x, isr: 0x%x, status: 0x%x\n",
346 mask, isr, status);
347
348 if (status) {
349 SDEROT_WARN("wb done but irq not triggered\n");
350 writel_relaxed(BIT(ctl->wb->num),
351 ctl->mdata->mdp_base +
352 SDE_MDP_REG_INTR_CLEAR);
353 sde_mdp_writeback_intr_done(ctl);
354 rc = 0;
355 } else {
356 rc = -ENODEV;
357 WARN(1, "wb timeout (%d) ctl=%d\n",
358 rc, ctl->num);
359 if (ctl->irq_num >= 0)
360 disable_irq_nosync(ctl->irq_num);
361 }
362 } else {
363 rc = 0;
364 }
365 } else {
366 /* use polling if interrupt is not available */
367 int cnt = 200;
368
369 mask = BIT(ctl->wb->num);
370 do {
371 udelay(500);
372 isr = readl_relaxed(ctl->mdata->mdp_base +
373 SDE_MDP_REG_INTR_STATUS);
374 status = mask & isr;
375 cnt--;
376 } while (cnt > 0 && !status);
377 writel_relaxed(mask, ctl->mdata->mdp_base +
378 SDE_MDP_REG_INTR_CLEAR);
379
380 rc = (status) ? 0 : -ENODEV;
381 }
382
383 if (rc == 0)
384 ctx->end_time = ktime_get();
385
386 sde_smmu_ctrl(0);
387 ctx->comp_cnt--;
388
389 if (!rc) {
390 rot_time = (u64)ktime_to_us(ctx->end_time) -
391 (u64)ktime_to_us(ctx->start_time);
392 SDEROT_DBG(
393 "ctx%d type:%d xin_id:%d intf_num:%d took %llu microsecs\n",
394 ctx->wb_num, ctx->type, ctx->xin_id,
395 ctx->intf_num, rot_time);
396 }
397
398 SDEROT_DBG("s:%8.8x %s t:%llu c:%d\n", isr,
399 (rc)?"Timeout":"Done", rot_time, ctx->comp_cnt);
400 return rc;
401}
402
403static void sde_mdp_set_ot_limit_wb(struct sde_mdp_writeback_ctx *ctx)
404{
Benjamin Chan1b94f952017-01-23 17:42:30 -0500405 struct sde_mdp_set_ot_params ot_params = {0,};
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700406
407 ot_params.xin_id = ctx->xin_id;
408 ot_params.num = ctx->wb_num;
409 ot_params.width = ctx->width;
410 ot_params.height = ctx->height;
Alan Kwongeffb5ee2016-03-12 19:47:45 -0500411 ot_params.fps = 60;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700412 ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF;
413 ot_params.reg_off_mdp_clk_ctrl = ctx->clk_ctrl.reg_off;
414 ot_params.bit_off_mdp_clk_ctrl = ctx->clk_ctrl.bit_off;
Alan Kwongeffb5ee2016-03-12 19:47:45 -0500415 ot_params.fmt = (ctx->dst_fmt) ? ctx->dst_fmt->format : 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700416
417 sde_mdp_set_ot_limit(&ot_params);
418}
419
420static int sde_mdp_writeback_display(struct sde_mdp_ctl *ctl, void *arg)
421{
422 struct sde_mdp_writeback_ctx *ctx;
423 struct sde_mdp_writeback_arg *wb_args;
424 u32 flush_bits = 0;
425 int ret;
426
427 if (!ctl || !ctl->mdata)
428 return -ENODEV;
429
430 ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data;
431 if (!ctx)
432 return -ENODEV;
433
434 if (ctx->comp_cnt) {
435 SDEROT_ERR("previous kickoff not completed yet, ctl=%d\n",
436 ctl->num);
437 return -EPERM;
438 }
439
440 if (ctl->mdata->default_ot_wr_limit ||
441 ctl->mdata->default_ot_rd_limit)
442 sde_mdp_set_ot_limit_wb(ctx);
443
444 wb_args = (struct sde_mdp_writeback_arg *) arg;
445 if (!wb_args)
446 return -ENOENT;
447
448 ret = sde_mdp_writeback_addr_setup(ctx, wb_args->data);
449 if (ret) {
450 SDEROT_ERR("writeback data setup error ctl=%d\n", ctl->num);
451 return ret;
452 }
453
454 sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
455 sde_mdp_writeback_intr_done, ctl);
456
457 flush_bits |= ctl->flush_reg_data;
458 flush_bits |= BIT(16); /* WB */
459 sde_wb_write(ctx, SDE_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure);
460 sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_FLUSH, flush_bits);
461
462 reinit_completion(&ctx->wb_comp);
463 if (ctl->irq_num >= 0)
464 enable_irq(ctl->irq_num);
465 ret = sde_smmu_ctrl(1);
Alan Kwong6ce448d2016-11-24 18:45:20 -0800466 if (ret < 0) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700467 SDEROT_ERR("IOMMU attach failed\n");
468 return ret;
469 }
470
471 ctx->start_time = ktime_get();
472 sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_START, 1);
473 /* ensure that start command is issued after the barrier */
474 wmb();
475
476 SDEROT_DBG("ctx%d type:%d xin_id:%d intf_num:%d start\n",
477 ctx->wb_num, ctx->type, ctx->xin_id, ctx->intf_num);
478
479 ctx->comp_cnt++;
480
481 return 0;
482}
483
484int sde_mdp_writeback_start(struct sde_mdp_ctl *ctl)
485{
486 struct sde_mdp_writeback_ctx *ctx;
487 struct sde_mdp_writeback *wb;
488 u32 mem_sel;
489
490 SDEROT_DBG("start ctl=%d\n", ctl->num);
491
492 if (!ctl->wb) {
493 SDEROT_DBG("wb not setup in the ctl\n");
494 return 0;
495 }
496
497 wb = ctl->wb;
498 mem_sel = (ctl->opmode & 0xF) - 1;
499 if (mem_sel < SDE_MDP_MAX_WRITEBACK) {
500 ctx = &wb_ctx_list[mem_sel];
501 if (ctx->ref_cnt) {
502 SDEROT_ERR("writeback in use %d\n", mem_sel);
503 return -EBUSY;
504 }
505 ctx->ref_cnt++;
506 } else {
507 SDEROT_ERR("invalid writeback mode %d\n", mem_sel);
508 return -EINVAL;
509 }
510
511 ctl->priv_data = ctx;
512 ctx->wb_num = wb->num;
513 ctx->base = wb->base;
514 ctx->offset = wb->offset;
515
516 init_completion(&ctx->wb_comp);
517
518 if (ctx->type == SDE_MDP_WRITEBACK_TYPE_ROTATOR)
519 ctl->ops.prepare_fnc = sde_mdp_writeback_prepare_rot;
520
521 ctl->ops.stop_fnc = sde_mdp_writeback_stop;
522 ctl->ops.display_fnc = sde_mdp_writeback_display;
523 ctl->ops.wait_fnc = sde_mdp_wb_wait4comp;
524
525 return 0;
526}
527
528int sde_mdp_writeback_display_commit(struct sde_mdp_ctl *ctl, void *arg)
529{
530 return sde_mdp_display_commit(ctl, arg, NULL);
531}