blob: 89ad4386552fa178c95362d79a914abafb706ace [file] [log] [blame]
Alan Kwong6ce448d2016-11-24 18:45:20 -08001/* 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/platform_device.h>
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/file.h>
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070020#include <linux/delay.h>
21#include <linux/debugfs.h>
22#include <linux/interrupt.h>
23
24#include "sde_rotator_r1_hwio.h"
25#include "sde_rotator_core.h"
26#include "sde_rotator_util.h"
27#include "sde_rotator_r1_internal.h"
28#include "sde_rotator_r1.h"
29#include "sde_rotator_r1_debug.h"
30
31struct sde_mdp_hw_resource {
32 struct sde_rot_hw_resource hw;
33 struct sde_mdp_ctl *ctl;
34 struct sde_mdp_mixer *mixer;
35 struct sde_mdp_pipe *pipe;
36 struct sde_mdp_writeback *wb;
37};
38
39struct sde_rotator_r1_data {
40 struct sde_rot_mgr *mgr;
41 int wb_id;
42 int ctl_id;
43 int irq_num;
44 struct sde_mdp_hw_resource *mdp_hw;
45};
46
Alan Kwongda16e442016-08-14 20:47:18 -040047static u32 sde_hw_rotator_input_pixfmts[] = {
48 SDE_PIX_FMT_XRGB_8888,
49 SDE_PIX_FMT_ARGB_8888,
50 SDE_PIX_FMT_ABGR_8888,
51 SDE_PIX_FMT_RGBA_8888,
52 SDE_PIX_FMT_BGRA_8888,
53 SDE_PIX_FMT_RGBX_8888,
54 SDE_PIX_FMT_BGRX_8888,
55 SDE_PIX_FMT_XBGR_8888,
56 SDE_PIX_FMT_RGBA_5551,
57 SDE_PIX_FMT_ARGB_1555,
58 SDE_PIX_FMT_ABGR_1555,
59 SDE_PIX_FMT_BGRA_5551,
60 SDE_PIX_FMT_BGRX_5551,
61 SDE_PIX_FMT_RGBX_5551,
62 SDE_PIX_FMT_XBGR_1555,
63 SDE_PIX_FMT_XRGB_1555,
64 SDE_PIX_FMT_ARGB_4444,
65 SDE_PIX_FMT_RGBA_4444,
66 SDE_PIX_FMT_BGRA_4444,
67 SDE_PIX_FMT_ABGR_4444,
68 SDE_PIX_FMT_RGBX_4444,
69 SDE_PIX_FMT_XRGB_4444,
70 SDE_PIX_FMT_BGRX_4444,
71 SDE_PIX_FMT_XBGR_4444,
72 SDE_PIX_FMT_RGB_888,
73 SDE_PIX_FMT_BGR_888,
74 SDE_PIX_FMT_RGB_565,
75 SDE_PIX_FMT_BGR_565,
76 SDE_PIX_FMT_Y_CB_CR_H2V2,
77 SDE_PIX_FMT_Y_CR_CB_H2V2,
78 SDE_PIX_FMT_Y_CR_CB_GH2V2,
79 SDE_PIX_FMT_Y_CBCR_H2V2,
80 SDE_PIX_FMT_Y_CRCB_H2V2,
81 SDE_PIX_FMT_Y_CBCR_H1V2,
82 SDE_PIX_FMT_Y_CRCB_H1V2,
83 SDE_PIX_FMT_Y_CBCR_H2V1,
84 SDE_PIX_FMT_Y_CRCB_H2V1,
85 SDE_PIX_FMT_YCBYCR_H2V1,
86 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
87 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
88 SDE_PIX_FMT_RGBA_8888_UBWC,
89 SDE_PIX_FMT_RGBX_8888_UBWC,
90 SDE_PIX_FMT_RGB_565_UBWC,
91 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
92};
93
94static u32 sde_hw_rotator_output_pixfmts[] = {
95 SDE_PIX_FMT_XRGB_8888,
96 SDE_PIX_FMT_ARGB_8888,
97 SDE_PIX_FMT_ABGR_8888,
98 SDE_PIX_FMT_RGBA_8888,
99 SDE_PIX_FMT_BGRA_8888,
100 SDE_PIX_FMT_RGBX_8888,
101 SDE_PIX_FMT_BGRX_8888,
102 SDE_PIX_FMT_XBGR_8888,
103 SDE_PIX_FMT_RGBA_5551,
104 SDE_PIX_FMT_ARGB_1555,
105 SDE_PIX_FMT_ABGR_1555,
106 SDE_PIX_FMT_BGRA_5551,
107 SDE_PIX_FMT_BGRX_5551,
108 SDE_PIX_FMT_RGBX_5551,
109 SDE_PIX_FMT_XBGR_1555,
110 SDE_PIX_FMT_XRGB_1555,
111 SDE_PIX_FMT_ARGB_4444,
112 SDE_PIX_FMT_RGBA_4444,
113 SDE_PIX_FMT_BGRA_4444,
114 SDE_PIX_FMT_ABGR_4444,
115 SDE_PIX_FMT_RGBX_4444,
116 SDE_PIX_FMT_XRGB_4444,
117 SDE_PIX_FMT_BGRX_4444,
118 SDE_PIX_FMT_XBGR_4444,
119 SDE_PIX_FMT_RGB_888,
120 SDE_PIX_FMT_BGR_888,
121 SDE_PIX_FMT_RGB_565,
122 SDE_PIX_FMT_BGR_565,
123 SDE_PIX_FMT_Y_CB_CR_H2V2,
124 SDE_PIX_FMT_Y_CR_CB_H2V2,
125 SDE_PIX_FMT_Y_CR_CB_GH2V2,
126 SDE_PIX_FMT_Y_CBCR_H2V2,
127 SDE_PIX_FMT_Y_CRCB_H2V2,
128 SDE_PIX_FMT_Y_CBCR_H1V2,
129 SDE_PIX_FMT_Y_CRCB_H1V2,
130 SDE_PIX_FMT_Y_CBCR_H2V1,
131 SDE_PIX_FMT_Y_CRCB_H2V1,
132 SDE_PIX_FMT_YCBYCR_H2V1,
133 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
134 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
135 SDE_PIX_FMT_RGBA_8888_UBWC,
136 SDE_PIX_FMT_RGBX_8888_UBWC,
137 SDE_PIX_FMT_RGB_565_UBWC,
138 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
139};
140
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700141static struct sde_mdp_hw_resource *sde_rotator_hw_alloc(
142 struct sde_rot_mgr *mgr, u32 ctl_id, u32 wb_id, int irq_num)
143{
144 struct sde_mdp_hw_resource *mdp_hw;
145 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
146 int pipe_ndx, offset = ctl_id;
Channagoud Kadabi075db3b2017-03-16 14:26:17 -0700147 int ret = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700148
149 mdp_hw = devm_kzalloc(&mgr->pdev->dev,
150 sizeof(struct sde_mdp_hw_resource), GFP_KERNEL);
151 if (!mdp_hw)
152 return ERR_PTR(-ENOMEM);
153
154 mdp_hw->ctl = sde_mdp_ctl_alloc(mdata, offset);
155 if (IS_ERR_OR_NULL(mdp_hw->ctl)) {
156 SDEROT_ERR("unable to allocate ctl\n");
157 ret = -ENODEV;
158 goto error;
159 }
160 mdp_hw->ctl->irq_num = irq_num;
161
162 mdp_hw->wb = sde_mdp_wb_assign(wb_id, mdp_hw->ctl->num);
163 if (IS_ERR_OR_NULL(mdp_hw->wb)) {
164 SDEROT_ERR("unable to allocate wb\n");
165 ret = -ENODEV;
166 goto error;
167 }
168
169 mdp_hw->ctl->wb = mdp_hw->wb;
170 mdp_hw->mixer = sde_mdp_mixer_assign(mdp_hw->wb->num, true);
171 if (IS_ERR_OR_NULL(mdp_hw->mixer)) {
172 SDEROT_ERR("unable to allocate wb mixer\n");
173 ret = -ENODEV;
174 goto error;
175 }
176
177 mdp_hw->ctl->mixer_left = mdp_hw->mixer;
178 mdp_hw->mixer->ctl = mdp_hw->ctl;
179
180 mdp_hw->mixer->rotator_mode = true;
181
182 switch (mdp_hw->mixer->num) {
183 case SDE_MDP_WB_LAYERMIXER0:
184 mdp_hw->ctl->opmode = SDE_MDP_CTL_OP_ROT0_MODE;
185 break;
186 case SDE_MDP_WB_LAYERMIXER1:
187 mdp_hw->ctl->opmode = SDE_MDP_CTL_OP_ROT1_MODE;
188 break;
189 default:
190 SDEROT_ERR("invalid layer mixer=%d\n", mdp_hw->mixer->num);
191 ret = -EINVAL;
192 goto error;
193 }
194
195 mdp_hw->ctl->ops.start_fnc = sde_mdp_writeback_start;
196 mdp_hw->ctl->wb_type = SDE_MDP_WB_CTL_TYPE_BLOCK;
197
198 if (mdp_hw->ctl->ops.start_fnc)
199 ret = mdp_hw->ctl->ops.start_fnc(mdp_hw->ctl);
200
201 if (ret)
202 goto error;
203
204 /* override from dt */
205 pipe_ndx = wb_id;
206 mdp_hw->pipe = sde_mdp_pipe_assign(mdata, mdp_hw->mixer, pipe_ndx);
207 if (IS_ERR_OR_NULL(mdp_hw->pipe)) {
208 SDEROT_ERR("dma pipe allocation failed\n");
209 ret = -ENODEV;
210 goto error;
211 }
212
213 mdp_hw->pipe->mixer_left = mdp_hw->mixer;
214 mdp_hw->hw.wb_id = mdp_hw->wb->num;
215 mdp_hw->hw.pending_count = 0;
216 atomic_set(&mdp_hw->hw.num_active, 0);
217 mdp_hw->hw.max_active = 1;
218 init_waitqueue_head(&mdp_hw->hw.wait_queue);
219
220 return mdp_hw;
221error:
222 if (!IS_ERR_OR_NULL(mdp_hw->pipe))
223 sde_mdp_pipe_destroy(mdp_hw->pipe);
224 if (!IS_ERR_OR_NULL(mdp_hw->ctl)) {
225 if (mdp_hw->ctl->ops.stop_fnc)
226 mdp_hw->ctl->ops.stop_fnc(mdp_hw->ctl, 0);
227 sde_mdp_ctl_free(mdp_hw->ctl);
228 }
229 devm_kfree(&mgr->pdev->dev, mdp_hw);
230
231 return ERR_PTR(ret);
232}
233
234static void sde_rotator_hw_free(struct sde_rot_mgr *mgr,
235 struct sde_mdp_hw_resource *mdp_hw)
236{
237 struct sde_mdp_mixer *mixer;
238 struct sde_mdp_ctl *ctl;
239
240 if (!mgr || !mdp_hw)
241 return;
242
243 mixer = mdp_hw->pipe->mixer_left;
244
245 sde_mdp_pipe_destroy(mdp_hw->pipe);
246
247 ctl = sde_mdp_ctl_mixer_switch(mixer->ctl,
248 SDE_MDP_WB_CTL_TYPE_BLOCK);
249 if (ctl) {
250 if (ctl->ops.stop_fnc)
251 ctl->ops.stop_fnc(ctl, 0);
252 sde_mdp_ctl_free(ctl);
253 }
254
255 devm_kfree(&mgr->pdev->dev, mdp_hw);
256}
257
258static struct sde_rot_hw_resource *sde_rotator_hw_alloc_ext(
259 struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id)
260{
261 struct sde_mdp_hw_resource *mdp_hw;
262 struct sde_rotator_r1_data *hw_data;
263
264 if (!mgr || !mgr->hw_data)
265 return NULL;
266
267 hw_data = mgr->hw_data;
268 mdp_hw = hw_data->mdp_hw;
269
270 return &mdp_hw->hw;
271}
272
273static void sde_rotator_hw_free_ext(struct sde_rot_mgr *mgr,
274 struct sde_rot_hw_resource *hw)
275{
276 /* currently nothing specific for this device */
277}
278
279static void sde_rotator_translate_rect(struct sde_rect *dst,
280 struct sde_rect *src)
281{
282 dst->x = src->x;
283 dst->y = src->y;
284 dst->w = src->w;
285 dst->h = src->h;
286}
287
288static u32 sde_rotator_translate_flags(u32 input)
289{
290 u32 output = 0;
291
292 if (input & SDE_ROTATION_NOP)
293 output |= SDE_ROT_NOP;
294 if (input & SDE_ROTATION_FLIP_LR)
295 output |= SDE_FLIP_LR;
296 if (input & SDE_ROTATION_FLIP_UD)
297 output |= SDE_FLIP_UD;
298 if (input & SDE_ROTATION_90)
299 output |= SDE_ROT_90;
300 if (input & SDE_ROTATION_DEINTERLACE)
301 output |= SDE_DEINTERLACE;
302 if (input & SDE_ROTATION_SECURE)
303 output |= SDE_SECURE_OVERLAY_SESSION;
304 return output;
305}
306
307static int sde_rotator_config_hw(struct sde_rot_hw_resource *hw,
308 struct sde_rot_entry *entry)
309{
310 struct sde_mdp_hw_resource *mdp_hw;
311 struct sde_mdp_pipe *pipe;
312 struct sde_rotation_item *item;
313 int ret;
314
315 if (!hw || !entry) {
316 SDEROT_ERR("null hw resource/entry");
317 return -EINVAL;
318 }
319
320 mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw);
321
322 pipe = mdp_hw->pipe;
323 item = &entry->item;
324
325 pipe->flags = sde_rotator_translate_flags(item->flags);
326 pipe->src_fmt = sde_get_format_params(item->input.format);
327 pipe->img_width = item->input.width;
328 pipe->img_height = item->input.height;
329 sde_rotator_translate_rect(&pipe->src, &item->src_rect);
330 sde_rotator_translate_rect(&pipe->dst, &item->src_rect);
331
332 pipe->params_changed++;
333
334 ret = sde_mdp_pipe_queue_data(pipe, &entry->src_buf);
335 SDEROT_DBG("Config pipe. src{%u,%u,%u,%u}f=%u\n"
336 "dst{%u,%u,%u,%u}f=%u session_id=%u\n",
337 item->src_rect.x, item->src_rect.y,
338 item->src_rect.w, item->src_rect.h, item->input.format,
339 item->dst_rect.x, item->dst_rect.y,
340 item->dst_rect.w, item->dst_rect.h, item->output.format,
341 item->session_id);
342
343 return ret;
344}
345
Clarence Ip3ce07c02017-08-11 16:21:45 -0400346static int sde_rotator_cancel_hw(struct sde_rot_hw_resource *hw,
347 struct sde_rot_entry *entry)
348{
349 return 0;
350}
351
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700352static int sde_rotator_kickoff_entry(struct sde_rot_hw_resource *hw,
353 struct sde_rot_entry *entry)
354{
355 struct sde_mdp_hw_resource *mdp_hw;
356 int ret;
357 struct sde_mdp_writeback_arg wb_args;
358
359 if (!hw || !entry) {
360 SDEROT_ERR("null hw resource/entry");
361 return -EINVAL;
362 }
363
364 wb_args.data = &entry->dst_buf;
365 wb_args.priv_data = entry;
366
367 mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw);
368
369 ret = sde_mdp_writeback_display_commit(mdp_hw->ctl, &wb_args);
370 return ret;
371}
372
373static int sde_rotator_wait_for_entry(struct sde_rot_hw_resource *hw,
374 struct sde_rot_entry *entry)
375{
376 struct sde_mdp_hw_resource *mdp_hw;
377 int ret;
378 struct sde_mdp_ctl *ctl;
379
380 if (!hw || !entry) {
381 SDEROT_ERR("null hw resource/entry");
382 return -EINVAL;
383 }
384
385 mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw);
386
387 ctl = mdp_hw->ctl;
388
389 ret = sde_mdp_display_wait4comp(ctl);
390
391 return ret;
392}
393
394static int sde_rotator_hw_validate_entry(struct sde_rot_mgr *mgr,
395 struct sde_rot_entry *entry)
396{
397 int ret = 0;
398 u16 src_w, src_h, dst_w, dst_h, bit;
399 struct sde_rotation_item *item = &entry->item;
400 struct sde_mdp_format_params *fmt;
401
402 src_w = item->src_rect.w;
403 src_h = item->src_rect.h;
404
405 if (item->flags & SDE_ROTATION_90) {
406 dst_w = item->dst_rect.h;
407 dst_h = item->dst_rect.w;
408 } else {
409 dst_w = item->dst_rect.w;
410 dst_h = item->dst_rect.h;
411 }
412
413 entry->dnsc_factor_w = 0;
414 entry->dnsc_factor_h = 0;
415
416 if ((src_w != dst_w) || (src_h != dst_h)) {
417 if ((src_w % dst_w) || (src_h % dst_h)) {
418 SDEROT_DBG("non integral scale not support\n");
419 ret = -EINVAL;
420 goto dnsc_err;
421 }
422 entry->dnsc_factor_w = src_w / dst_w;
423 bit = fls(entry->dnsc_factor_w);
424 if ((entry->dnsc_factor_w & ~BIT(bit - 1)) || (bit > 5)) {
425 SDEROT_DBG("non power-of-2 scale not support\n");
426 ret = -EINVAL;
427 goto dnsc_err;
428 }
429 entry->dnsc_factor_h = src_h / dst_h;
430 bit = fls(entry->dnsc_factor_h);
431 if ((entry->dnsc_factor_h & ~BIT(bit - 1)) || (bit > 5)) {
432 SDEROT_DBG("non power-of-2 dscale not support\n");
433 ret = -EINVAL;
434 goto dnsc_err;
435 }
436 }
437
438 fmt = sde_get_format_params(item->output.format);
439 if (sde_mdp_is_ubwc_format(fmt) &&
440 (entry->dnsc_factor_h || entry->dnsc_factor_w)) {
441 SDEROT_DBG("downscale with ubwc not support\n");
442 ret = -EINVAL;
443 }
444
445dnsc_err:
446
447 /* Downscaler does not support asymmetrical dnsc */
448 if (entry->dnsc_factor_w != entry->dnsc_factor_h) {
449 SDEROT_DBG("asymmetric downscale not support\n");
450 ret = -EINVAL;
451 }
452
453 if (ret) {
454 entry->dnsc_factor_w = 0;
455 entry->dnsc_factor_h = 0;
456 }
457 return ret;
458}
459
460static ssize_t sde_rotator_hw_show_caps(struct sde_rot_mgr *mgr,
461 struct device_attribute *attr, char *buf, ssize_t len)
462{
463 struct sde_rotator_r1_data *hw_data;
464 int cnt = 0;
465
466 if (!mgr || !buf)
467 return 0;
468
469 hw_data = mgr->hw_data;
470
471#define SPRINT(fmt, ...) \
472 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
473
474 SPRINT("wb_id=%d\n", hw_data->wb_id);
475 SPRINT("ctl_id=%d\n", hw_data->ctl_id);
476 return cnt;
477}
478
479static ssize_t sde_rotator_hw_show_state(struct sde_rot_mgr *mgr,
480 struct device_attribute *attr, char *buf, ssize_t len)
481{
482 struct sde_rotator_r1_data *hw_data;
483 int cnt = 0;
484
485 if (!mgr || !buf)
486 return 0;
487
488 hw_data = mgr->hw_data;
489
490#define SPRINT(fmt, ...) \
491 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
492
493 if (hw_data && hw_data->mdp_hw) {
494 struct sde_rot_hw_resource *hw = &hw_data->mdp_hw->hw;
495
496 SPRINT("irq_num=%d\n", hw_data->irq_num);
497 SPRINT("max_active=%d\n", hw->max_active);
498 SPRINT("num_active=%d\n", atomic_read(&hw->num_active));
499 SPRINT("pending_cnt=%u\n", hw->pending_count);
500 }
501
502 return cnt;
503}
504
Alan Kwongda16e442016-08-14 20:47:18 -0400505/*
506 * sde_hw_rotator_get_pixfmt - get the indexed pixel format
507 * @mgr: Pointer to rotator manager
508 * @index: index of pixel format
509 * @input: true for input port; false for output port
Alan Kwong4b416162017-08-11 21:03:10 -0400510 * @mode: operating mode
Alan Kwongda16e442016-08-14 20:47:18 -0400511 */
512static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
Alan Kwong4b416162017-08-11 21:03:10 -0400513 int index, bool input, u32 mode)
Alan Kwongda16e442016-08-14 20:47:18 -0400514{
515 if (input) {
516 if (index < ARRAY_SIZE(sde_hw_rotator_input_pixfmts))
517 return sde_hw_rotator_input_pixfmts[index];
518 else
519 return 0;
520 } else {
521 if (index < ARRAY_SIZE(sde_hw_rotator_output_pixfmts))
522 return sde_hw_rotator_output_pixfmts[index];
523 else
524 return 0;
525 }
526}
527
528/*
529 * sde_hw_rotator_is_valid_pixfmt - verify if the given pixel format is valid
530 * @mgr: Pointer to rotator manager
531 * @pixfmt: pixel format to be verified
532 * @input: true for input port; false for output port
Alan Kwong4b416162017-08-11 21:03:10 -0400533 * @mode: operating mode
Alan Kwongda16e442016-08-14 20:47:18 -0400534 */
535static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
Alan Kwong4b416162017-08-11 21:03:10 -0400536 bool input, u32 mode)
Alan Kwongda16e442016-08-14 20:47:18 -0400537{
538 int i;
539
540 if (input) {
541 for (i = 0; i < ARRAY_SIZE(sde_hw_rotator_input_pixfmts); i++)
542 if (sde_hw_rotator_input_pixfmts[i] == pixfmt)
543 return true;
544 } else {
545 for (i = 0; i < ARRAY_SIZE(sde_hw_rotator_output_pixfmts); i++)
546 if (sde_hw_rotator_output_pixfmts[i] == pixfmt)
547 return true;
548 }
549
550 return false;
551}
552
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700553static int sde_rotator_hw_parse_dt(struct sde_rotator_r1_data *hw_data,
554 struct platform_device *dev)
555{
556 int ret = 0;
557 u32 data;
558
559 if (!hw_data || !dev)
560 return -EINVAL;
561
562 ret = of_property_read_u32(dev->dev.of_node,
563 "qcom,mdss-wb-id", &data);
564 if (ret)
565 hw_data->wb_id = -1;
566 else
567 hw_data->wb_id = (int) data;
568 ret = of_property_read_u32(dev->dev.of_node,
569 "qcom,mdss-ctl-id", &data);
570 if (ret)
571 hw_data->ctl_id = -1;
572 else
573 hw_data->ctl_id = (int) data;
574
575 return ret;
576}
577
578static int sde_rotator_hw_rev_init(struct sde_rot_data_type *mdata)
579{
580 if (!mdata) {
581 SDEROT_ERR("null rotator data\n");
582 return -EINVAL;
583 }
584
585 clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
586 set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
587 clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
588 set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
589 set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
590 clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
591 set_bit(SDE_CAPS_R1_WB, mdata->sde_caps_map);
592
593 return 0;
594}
595
596enum {
597 SDE_ROTATOR_INTR_WB_0,
598 SDE_ROTATOR_INTR_WB_1,
599 SDE_ROTATOR_INTR_MAX,
600};
601
602struct intr_callback {
603 void (*func)(void *);
604 void *arg;
605};
606
607struct intr_callback sde_intr_cb[SDE_ROTATOR_INTR_MAX];
608
609int sde_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
610 void (*fnc_ptr)(void *), void *arg)
611{
612 if (intf_num >= SDE_ROTATOR_INTR_MAX) {
613 SDEROT_WARN("invalid intr type=%u intf_num=%u\n",
614 intr_type, intf_num);
615 return -EINVAL;
616 }
617
618 sde_intr_cb[intf_num].func = fnc_ptr;
619 sde_intr_cb[intf_num].arg = arg;
620
621 return 0;
622}
623
624static irqreturn_t sde_irq_handler(int irq, void *ptr)
625{
626 struct sde_rot_data_type *mdata = ptr;
627 irqreturn_t ret = IRQ_NONE;
628 u32 isr;
629
630 isr = readl_relaxed(mdata->mdp_base + SDE_MDP_REG_INTR_STATUS);
631
632 SDEROT_DBG("intr_status = %8.8x\n", isr);
633
634 if (isr & SDE_MDP_INTR_WB_0_DONE) {
635 struct intr_callback *cb = &sde_intr_cb[SDE_ROTATOR_INTR_WB_0];
636
637 if (cb->func) {
638 writel_relaxed(SDE_MDP_INTR_WB_0_DONE,
639 mdata->mdp_base + SDE_MDP_REG_INTR_CLEAR);
640 cb->func(cb->arg);
641 ret = IRQ_HANDLED;
642 }
643 }
644
645 if (isr & SDE_MDP_INTR_WB_1_DONE) {
646 struct intr_callback *cb = &sde_intr_cb[SDE_ROTATOR_INTR_WB_1];
647
648 if (cb->func) {
649 writel_relaxed(SDE_MDP_INTR_WB_1_DONE,
650 mdata->mdp_base + SDE_MDP_REG_INTR_CLEAR);
651 cb->func(cb->arg);
652 ret = IRQ_HANDLED;
653 }
654 }
655
656 return ret;
657}
658
659static void sde_rotator_hw_destroy(struct sde_rot_mgr *mgr)
660{
661 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
662 struct sde_rotator_r1_data *hw_data;
663
664 if (!mgr || !mgr->pdev || !mgr->hw_data)
665 return;
666
667 hw_data = mgr->hw_data;
668 if (hw_data->irq_num >= 0)
669 devm_free_irq(&mgr->pdev->dev, hw_data->irq_num, mdata);
670 sde_rotator_hw_free(mgr, hw_data->mdp_hw);
671 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
672 mgr->hw_data = NULL;
673}
674
675int sde_rotator_r1_init(struct sde_rot_mgr *mgr)
676{
677 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
678 struct sde_rotator_r1_data *hw_data;
679 int ret;
680
681 if (!mgr || !mgr->pdev) {
682 SDEROT_ERR("null rotator manager/platform device");
683 return -EINVAL;
684 }
685
686 hw_data = devm_kzalloc(&mgr->pdev->dev,
687 sizeof(struct sde_rotator_r1_data), GFP_KERNEL);
688 if (hw_data == NULL)
689 return -ENOMEM;
690
691 mgr->hw_data = hw_data;
692 mgr->ops_config_hw = sde_rotator_config_hw;
Clarence Ip3ce07c02017-08-11 16:21:45 -0400693 mgr->ops_cancel_hw = sde_rotator_cancel_hw;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700694 mgr->ops_kickoff_entry = sde_rotator_kickoff_entry;
695 mgr->ops_wait_for_entry = sde_rotator_wait_for_entry;
696 mgr->ops_hw_alloc = sde_rotator_hw_alloc_ext;
697 mgr->ops_hw_free = sde_rotator_hw_free_ext;
698 mgr->ops_hw_destroy = sde_rotator_hw_destroy;
699 mgr->ops_hw_validate_entry = sde_rotator_hw_validate_entry;
700 mgr->ops_hw_show_caps = sde_rotator_hw_show_caps;
701 mgr->ops_hw_show_state = sde_rotator_hw_show_state;
702 mgr->ops_hw_create_debugfs = sde_rotator_r1_create_debugfs;
Alan Kwongda16e442016-08-14 20:47:18 -0400703 mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt;
704 mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700705
706 ret = sde_rotator_hw_parse_dt(mgr->hw_data, mgr->pdev);
707 if (ret)
708 goto error_parse_dt;
709
710 hw_data->irq_num = platform_get_irq(mgr->pdev, 0);
711 if (hw_data->irq_num < 0) {
712 SDEROT_ERR("fail to get rotator irq\n");
713 } else {
714 ret = devm_request_threaded_irq(&mgr->pdev->dev,
715 hw_data->irq_num,
716 sde_irq_handler, NULL,
717 0, "sde_rotator_r1", mdata);
718 if (ret) {
719 SDEROT_ERR("fail to request irq r:%d\n", ret);
720 hw_data->irq_num = -1;
721 } else {
722 disable_irq(hw_data->irq_num);
723 }
724 }
725
726 hw_data->mdp_hw = sde_rotator_hw_alloc(mgr, hw_data->ctl_id,
727 hw_data->wb_id, hw_data->irq_num);
728 if (IS_ERR_OR_NULL(hw_data->mdp_hw))
729 goto error_hw_alloc;
730
731 ret = sde_rotator_hw_rev_init(sde_rot_get_mdata());
732 if (ret)
733 goto error_hw_rev_init;
734
735 hw_data->mgr = mgr;
736
737 return 0;
738error_hw_rev_init:
739 if (hw_data->irq_num >= 0)
740 devm_free_irq(&mgr->pdev->dev, hw_data->irq_num, mdata);
741 sde_rotator_hw_free(mgr, hw_data->mdp_hw);
742error_hw_alloc:
743 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
744error_parse_dt:
745 return ret;
746}