2 * Copyright (C) 2012 Samsung Electronics Co.Ltd
4 * YoungJun Cho <yj44.cho@samsung.com>
5 * Eunchul Kim <chulspro.kim@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundationr
12 #include <linux/kernel.h>
13 #include <linux/err.h>
14 #include <linux/interrupt.h>
16 #include <linux/platform_device.h>
17 #include <linux/clk.h>
18 #include <linux/pm_runtime.h>
21 #include <drm/exynos_drm.h>
22 #include "regs-rotator.h"
23 #include "exynos_drm.h"
24 #include "exynos_drm_ipp.h"
27 * Rotator supports image crop/rotator and input/output DMA operations.
28 * input DMA reads image data from the memory.
29 * output DMA writes image data to memory.
31 * M2M operation : supports crop/scale/rotation/csc so on.
32 * Memory ----> Rotator H/W ----> Memory.
37 * 1. check suspend/resume api if needed.
38 * 2. need to check use case platform_device_id.
39 * 3. check src/dst size with, height.
40 * 4. need to add supported list in prop_list.
43 #define get_rot_context(dev) platform_get_drvdata(to_platform_device(dev))
44 #define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
45 struct rot_context, ippdrv);
46 #define rot_read(offset) readl(rot->regs + (offset))
47 #define rot_write(cfg, offset) writel(cfg, rot->regs + (offset))
50 ROT_IRQ_STATUS_COMPLETE
= 8,
51 ROT_IRQ_STATUS_ILLEGAL
= 9,
55 * A structure of limitation.
57 * @min_w: minimum width.
58 * @min_h: minimum height.
59 * @max_w: maximum width.
60 * @max_h: maximum height.
72 * A structure of limitation table.
74 * @ycbcr420_2p: case of YUV.
75 * @rgb888: case of RGB.
77 struct rot_limit_table
{
78 struct rot_limit ycbcr420_2p
;
79 struct rot_limit rgb888
;
83 * A structure of rotator context.
84 * @ippdrv: prepare initialization using ippdrv.
85 * @regs_res: register resources.
86 * @regs: memory mapped io registers.
87 * @clock: rotator gate clock.
88 * @limit_tbl: limitation of rotator.
90 * @cur_buf_id: current operation buffer id.
91 * @suspended: suspended state.
94 struct exynos_drm_ippdrv ippdrv
;
95 struct resource
*regs_res
;
98 struct rot_limit_table
*limit_tbl
;
100 int cur_buf_id
[EXYNOS_DRM_OPS_MAX
];
104 static void rotator_reg_set_irq(struct rot_context
*rot
, bool enable
)
106 u32 val
= rot_read(ROT_CONFIG
);
109 val
|= ROT_CONFIG_IRQ
;
111 val
&= ~ROT_CONFIG_IRQ
;
113 rot_write(val
, ROT_CONFIG
);
116 static u32
rotator_reg_get_fmt(struct rot_context
*rot
)
118 u32 val
= rot_read(ROT_CONTROL
);
120 val
&= ROT_CONTROL_FMT_MASK
;
125 static enum rot_irq_status
rotator_reg_get_irq_status(struct rot_context
*rot
)
127 u32 val
= rot_read(ROT_STATUS
);
129 val
= ROT_STATUS_IRQ(val
);
131 if (val
== ROT_STATUS_IRQ_VAL_COMPLETE
)
132 return ROT_IRQ_STATUS_COMPLETE
;
134 return ROT_IRQ_STATUS_ILLEGAL
;
137 static irqreturn_t
rotator_irq_handler(int irq
, void *arg
)
139 struct rot_context
*rot
= arg
;
140 struct exynos_drm_ippdrv
*ippdrv
= &rot
->ippdrv
;
141 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
142 struct drm_exynos_ipp_event_work
*event_work
= c_node
->event_work
;
143 enum rot_irq_status irq_status
;
146 /* Get execution result */
147 irq_status
= rotator_reg_get_irq_status(rot
);
150 val
= rot_read(ROT_STATUS
);
151 val
|= ROT_STATUS_IRQ_PENDING((u32
)irq_status
);
152 rot_write(val
, ROT_STATUS
);
154 if (irq_status
== ROT_IRQ_STATUS_COMPLETE
) {
155 event_work
->ippdrv
= ippdrv
;
156 event_work
->buf_id
[EXYNOS_DRM_OPS_DST
] =
157 rot
->cur_buf_id
[EXYNOS_DRM_OPS_DST
];
158 queue_work(ippdrv
->event_workq
,
159 (struct work_struct
*)event_work
);
161 DRM_ERROR("the SFR is set illegally\n");
166 static void rotator_align_size(struct rot_context
*rot
, u32 fmt
, u32
*hsize
,
169 struct rot_limit_table
*limit_tbl
= rot
->limit_tbl
;
170 struct rot_limit
*limit
;
174 if (fmt
== ROT_CONTROL_FMT_RGB888
)
175 limit
= &limit_tbl
->rgb888
;
177 limit
= &limit_tbl
->ycbcr420_2p
;
179 /* Get mask for rounding to nearest aligned val */
180 mask
= ~((1 << limit
->align
) - 1);
182 /* Set aligned width */
183 val
= ROT_ALIGN(*hsize
, limit
->align
, mask
);
184 if (val
< limit
->min_w
)
185 *hsize
= ROT_MIN(limit
->min_w
, mask
);
186 else if (val
> limit
->max_w
)
187 *hsize
= ROT_MAX(limit
->max_w
, mask
);
191 /* Set aligned height */
192 val
= ROT_ALIGN(*vsize
, limit
->align
, mask
);
193 if (val
< limit
->min_h
)
194 *vsize
= ROT_MIN(limit
->min_h
, mask
);
195 else if (val
> limit
->max_h
)
196 *vsize
= ROT_MAX(limit
->max_h
, mask
);
201 static int rotator_src_set_fmt(struct device
*dev
, u32 fmt
)
203 struct rot_context
*rot
= dev_get_drvdata(dev
);
206 val
= rot_read(ROT_CONTROL
);
207 val
&= ~ROT_CONTROL_FMT_MASK
;
210 case DRM_FORMAT_NV12
:
211 val
|= ROT_CONTROL_FMT_YCBCR420_2P
;
213 case DRM_FORMAT_XRGB8888
:
214 val
|= ROT_CONTROL_FMT_RGB888
;
217 DRM_ERROR("invalid image format\n");
221 rot_write(val
, ROT_CONTROL
);
226 static inline bool rotator_check_reg_fmt(u32 fmt
)
228 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) ||
229 (fmt
== ROT_CONTROL_FMT_RGB888
))
235 static int rotator_src_set_size(struct device
*dev
, int swap
,
236 struct drm_exynos_pos
*pos
,
237 struct drm_exynos_sz
*sz
)
239 struct rot_context
*rot
= dev_get_drvdata(dev
);
240 u32 fmt
, hsize
, vsize
;
244 fmt
= rotator_reg_get_fmt(rot
);
245 if (!rotator_check_reg_fmt(fmt
)) {
246 DRM_ERROR("invalid format.\n");
250 /* Align buffer size */
253 rotator_align_size(rot
, fmt
, &hsize
, &vsize
);
255 /* Set buffer size configuration */
256 val
= ROT_SET_BUF_SIZE_H(vsize
) | ROT_SET_BUF_SIZE_W(hsize
);
257 rot_write(val
, ROT_SRC_BUF_SIZE
);
259 /* Set crop image position configuration */
260 val
= ROT_CROP_POS_Y(pos
->y
) | ROT_CROP_POS_X(pos
->x
);
261 rot_write(val
, ROT_SRC_CROP_POS
);
262 val
= ROT_SRC_CROP_SIZE_H(pos
->h
) | ROT_SRC_CROP_SIZE_W(pos
->w
);
263 rot_write(val
, ROT_SRC_CROP_SIZE
);
268 static int rotator_src_set_addr(struct device
*dev
,
269 struct drm_exynos_ipp_buf_info
*buf_info
,
270 u32 buf_id
, enum drm_exynos_ipp_buf_type buf_type
)
272 struct rot_context
*rot
= dev_get_drvdata(dev
);
273 dma_addr_t addr
[EXYNOS_DRM_PLANAR_MAX
];
274 u32 val
, fmt
, hsize
, vsize
;
277 /* Set current buf_id */
278 rot
->cur_buf_id
[EXYNOS_DRM_OPS_SRC
] = buf_id
;
281 case IPP_BUF_ENQUEUE
:
282 /* Set address configuration */
283 for_each_ipp_planar(i
)
284 addr
[i
] = buf_info
->base
[i
];
287 fmt
= rotator_reg_get_fmt(rot
);
288 if (!rotator_check_reg_fmt(fmt
)) {
289 DRM_ERROR("invalid format.\n");
293 /* Re-set cb planar for NV12 format */
294 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) &&
295 !addr
[EXYNOS_DRM_PLANAR_CB
]) {
297 val
= rot_read(ROT_SRC_BUF_SIZE
);
298 hsize
= ROT_GET_BUF_SIZE_W(val
);
299 vsize
= ROT_GET_BUF_SIZE_H(val
);
302 addr
[EXYNOS_DRM_PLANAR_CB
] =
303 addr
[EXYNOS_DRM_PLANAR_Y
] + hsize
* vsize
;
306 for_each_ipp_planar(i
)
307 rot_write(addr
[i
], ROT_SRC_BUF_ADDR(i
));
309 case IPP_BUF_DEQUEUE
:
310 for_each_ipp_planar(i
)
311 rot_write(0x0, ROT_SRC_BUF_ADDR(i
));
321 static int rotator_dst_set_transf(struct device
*dev
,
322 enum drm_exynos_degree degree
,
323 enum drm_exynos_flip flip
, bool *swap
)
325 struct rot_context
*rot
= dev_get_drvdata(dev
);
328 /* Set transform configuration */
329 val
= rot_read(ROT_CONTROL
);
330 val
&= ~ROT_CONTROL_FLIP_MASK
;
333 case EXYNOS_DRM_FLIP_VERTICAL
:
334 val
|= ROT_CONTROL_FLIP_VERTICAL
;
336 case EXYNOS_DRM_FLIP_HORIZONTAL
:
337 val
|= ROT_CONTROL_FLIP_HORIZONTAL
;
344 val
&= ~ROT_CONTROL_ROT_MASK
;
347 case EXYNOS_DRM_DEGREE_90
:
348 val
|= ROT_CONTROL_ROT_90
;
350 case EXYNOS_DRM_DEGREE_180
:
351 val
|= ROT_CONTROL_ROT_180
;
353 case EXYNOS_DRM_DEGREE_270
:
354 val
|= ROT_CONTROL_ROT_270
;
357 /* Rotation 0 Degree */
361 rot_write(val
, ROT_CONTROL
);
363 /* Check degree for setting buffer size swap */
364 if ((degree
== EXYNOS_DRM_DEGREE_90
) ||
365 (degree
== EXYNOS_DRM_DEGREE_270
))
373 static int rotator_dst_set_size(struct device
*dev
, int swap
,
374 struct drm_exynos_pos
*pos
,
375 struct drm_exynos_sz
*sz
)
377 struct rot_context
*rot
= dev_get_drvdata(dev
);
378 u32 val
, fmt
, hsize
, vsize
;
381 fmt
= rotator_reg_get_fmt(rot
);
382 if (!rotator_check_reg_fmt(fmt
)) {
383 DRM_ERROR("invalid format.\n");
387 /* Align buffer size */
390 rotator_align_size(rot
, fmt
, &hsize
, &vsize
);
392 /* Set buffer size configuration */
393 val
= ROT_SET_BUF_SIZE_H(vsize
) | ROT_SET_BUF_SIZE_W(hsize
);
394 rot_write(val
, ROT_DST_BUF_SIZE
);
396 /* Set crop image position configuration */
397 val
= ROT_CROP_POS_Y(pos
->y
) | ROT_CROP_POS_X(pos
->x
);
398 rot_write(val
, ROT_DST_CROP_POS
);
403 static int rotator_dst_set_addr(struct device
*dev
,
404 struct drm_exynos_ipp_buf_info
*buf_info
,
405 u32 buf_id
, enum drm_exynos_ipp_buf_type buf_type
)
407 struct rot_context
*rot
= dev_get_drvdata(dev
);
408 dma_addr_t addr
[EXYNOS_DRM_PLANAR_MAX
];
409 u32 val
, fmt
, hsize
, vsize
;
412 /* Set current buf_id */
413 rot
->cur_buf_id
[EXYNOS_DRM_OPS_DST
] = buf_id
;
416 case IPP_BUF_ENQUEUE
:
417 /* Set address configuration */
418 for_each_ipp_planar(i
)
419 addr
[i
] = buf_info
->base
[i
];
422 fmt
= rotator_reg_get_fmt(rot
);
423 if (!rotator_check_reg_fmt(fmt
)) {
424 DRM_ERROR("invalid format.\n");
428 /* Re-set cb planar for NV12 format */
429 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) &&
430 !addr
[EXYNOS_DRM_PLANAR_CB
]) {
432 val
= rot_read(ROT_DST_BUF_SIZE
);
434 hsize
= ROT_GET_BUF_SIZE_W(val
);
435 vsize
= ROT_GET_BUF_SIZE_H(val
);
438 addr
[EXYNOS_DRM_PLANAR_CB
] =
439 addr
[EXYNOS_DRM_PLANAR_Y
] + hsize
* vsize
;
442 for_each_ipp_planar(i
)
443 rot_write(addr
[i
], ROT_DST_BUF_ADDR(i
));
445 case IPP_BUF_DEQUEUE
:
446 for_each_ipp_planar(i
)
447 rot_write(0x0, ROT_DST_BUF_ADDR(i
));
457 static struct exynos_drm_ipp_ops rot_src_ops
= {
458 .set_fmt
= rotator_src_set_fmt
,
459 .set_size
= rotator_src_set_size
,
460 .set_addr
= rotator_src_set_addr
,
463 static struct exynos_drm_ipp_ops rot_dst_ops
= {
464 .set_transf
= rotator_dst_set_transf
,
465 .set_size
= rotator_dst_set_size
,
466 .set_addr
= rotator_dst_set_addr
,
469 static int rotator_init_prop_list(struct exynos_drm_ippdrv
*ippdrv
)
471 struct drm_exynos_ipp_prop_list
*prop_list
;
473 prop_list
= devm_kzalloc(ippdrv
->dev
, sizeof(*prop_list
), GFP_KERNEL
);
475 DRM_ERROR("failed to alloc property list.\n");
479 prop_list
->version
= 1;
480 prop_list
->flip
= (1 << EXYNOS_DRM_FLIP_VERTICAL
) |
481 (1 << EXYNOS_DRM_FLIP_HORIZONTAL
);
482 prop_list
->degree
= (1 << EXYNOS_DRM_DEGREE_0
) |
483 (1 << EXYNOS_DRM_DEGREE_90
) |
484 (1 << EXYNOS_DRM_DEGREE_180
) |
485 (1 << EXYNOS_DRM_DEGREE_270
);
488 prop_list
->scale
= 0;
490 ippdrv
->prop_list
= prop_list
;
495 static inline bool rotator_check_drm_fmt(u32 fmt
)
498 case DRM_FORMAT_XRGB8888
:
499 case DRM_FORMAT_NV12
:
502 DRM_DEBUG_KMS("not support format\n");
507 static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip
)
510 case EXYNOS_DRM_FLIP_NONE
:
511 case EXYNOS_DRM_FLIP_VERTICAL
:
512 case EXYNOS_DRM_FLIP_HORIZONTAL
:
513 case EXYNOS_DRM_FLIP_BOTH
:
516 DRM_DEBUG_KMS("invalid flip\n");
521 static int rotator_ippdrv_check_property(struct device
*dev
,
522 struct drm_exynos_ipp_property
*property
)
524 struct drm_exynos_ipp_config
*src_config
=
525 &property
->config
[EXYNOS_DRM_OPS_SRC
];
526 struct drm_exynos_ipp_config
*dst_config
=
527 &property
->config
[EXYNOS_DRM_OPS_DST
];
528 struct drm_exynos_pos
*src_pos
= &src_config
->pos
;
529 struct drm_exynos_pos
*dst_pos
= &dst_config
->pos
;
530 struct drm_exynos_sz
*src_sz
= &src_config
->sz
;
531 struct drm_exynos_sz
*dst_sz
= &dst_config
->sz
;
534 /* Check format configuration */
535 if (src_config
->fmt
!= dst_config
->fmt
) {
536 DRM_DEBUG_KMS("not support csc feature\n");
540 if (!rotator_check_drm_fmt(dst_config
->fmt
)) {
541 DRM_DEBUG_KMS("invalid format\n");
545 /* Check transform configuration */
546 if (src_config
->degree
!= EXYNOS_DRM_DEGREE_0
) {
547 DRM_DEBUG_KMS("not support source-side rotation\n");
551 switch (dst_config
->degree
) {
552 case EXYNOS_DRM_DEGREE_90
:
553 case EXYNOS_DRM_DEGREE_270
:
555 case EXYNOS_DRM_DEGREE_0
:
556 case EXYNOS_DRM_DEGREE_180
:
560 DRM_DEBUG_KMS("invalid degree\n");
564 if (src_config
->flip
!= EXYNOS_DRM_FLIP_NONE
) {
565 DRM_DEBUG_KMS("not support source-side flip\n");
569 if (!rotator_check_drm_flip(dst_config
->flip
)) {
570 DRM_DEBUG_KMS("invalid flip\n");
574 /* Check size configuration */
575 if ((src_pos
->x
+ src_pos
->w
> src_sz
->hsize
) ||
576 (src_pos
->y
+ src_pos
->h
> src_sz
->vsize
)) {
577 DRM_DEBUG_KMS("out of source buffer bound\n");
582 if ((dst_pos
->x
+ dst_pos
->h
> dst_sz
->vsize
) ||
583 (dst_pos
->y
+ dst_pos
->w
> dst_sz
->hsize
)) {
584 DRM_DEBUG_KMS("out of destination buffer bound\n");
588 if ((src_pos
->w
!= dst_pos
->h
) || (src_pos
->h
!= dst_pos
->w
)) {
589 DRM_DEBUG_KMS("not support scale feature\n");
593 if ((dst_pos
->x
+ dst_pos
->w
> dst_sz
->hsize
) ||
594 (dst_pos
->y
+ dst_pos
->h
> dst_sz
->vsize
)) {
595 DRM_DEBUG_KMS("out of destination buffer bound\n");
599 if ((src_pos
->w
!= dst_pos
->w
) || (src_pos
->h
!= dst_pos
->h
)) {
600 DRM_DEBUG_KMS("not support scale feature\n");
608 static int rotator_ippdrv_start(struct device
*dev
, enum drm_exynos_ipp_cmd cmd
)
610 struct rot_context
*rot
= dev_get_drvdata(dev
);
613 if (rot
->suspended
) {
614 DRM_ERROR("suspended state\n");
618 if (cmd
!= IPP_CMD_M2M
) {
619 DRM_ERROR("not support cmd: %d\n", cmd
);
623 /* Set interrupt enable */
624 rotator_reg_set_irq(rot
, true);
626 val
= rot_read(ROT_CONTROL
);
627 val
|= ROT_CONTROL_START
;
629 rot_write(val
, ROT_CONTROL
);
634 static int rotator_probe(struct platform_device
*pdev
)
636 struct device
*dev
= &pdev
->dev
;
637 struct rot_context
*rot
;
638 struct exynos_drm_ippdrv
*ippdrv
;
641 rot
= devm_kzalloc(dev
, sizeof(*rot
), GFP_KERNEL
);
643 dev_err(dev
, "failed to allocate rot\n");
647 rot
->limit_tbl
= (struct rot_limit_table
*)
648 platform_get_device_id(pdev
)->driver_data
;
650 rot
->regs_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
651 rot
->regs
= devm_ioremap_resource(dev
, rot
->regs_res
);
652 if (IS_ERR(rot
->regs
))
653 return PTR_ERR(rot
->regs
);
655 rot
->irq
= platform_get_irq(pdev
, 0);
657 dev_err(dev
, "failed to get irq\n");
661 ret
= devm_request_threaded_irq(dev
, rot
->irq
, NULL
,
662 rotator_irq_handler
, IRQF_ONESHOT
, "drm_rotator", rot
);
664 dev_err(dev
, "failed to request irq\n");
668 rot
->clock
= devm_clk_get(dev
, "rotator");
669 if (IS_ERR(rot
->clock
)) {
670 dev_err(dev
, "failed to get clock\n");
671 return PTR_ERR(rot
->clock
);
674 pm_runtime_enable(dev
);
676 ippdrv
= &rot
->ippdrv
;
678 ippdrv
->ops
[EXYNOS_DRM_OPS_SRC
] = &rot_src_ops
;
679 ippdrv
->ops
[EXYNOS_DRM_OPS_DST
] = &rot_dst_ops
;
680 ippdrv
->check_property
= rotator_ippdrv_check_property
;
681 ippdrv
->start
= rotator_ippdrv_start
;
682 ret
= rotator_init_prop_list(ippdrv
);
684 dev_err(dev
, "failed to init property list.\n");
685 goto err_ippdrv_register
;
688 DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv
);
690 platform_set_drvdata(pdev
, rot
);
692 ret
= exynos_drm_ippdrv_register(ippdrv
);
694 dev_err(dev
, "failed to register drm rotator device\n");
695 goto err_ippdrv_register
;
698 dev_info(dev
, "The exynos rotator is probed successfully\n");
703 pm_runtime_disable(dev
);
707 static int rotator_remove(struct platform_device
*pdev
)
709 struct device
*dev
= &pdev
->dev
;
710 struct rot_context
*rot
= dev_get_drvdata(dev
);
711 struct exynos_drm_ippdrv
*ippdrv
= &rot
->ippdrv
;
713 exynos_drm_ippdrv_unregister(ippdrv
);
715 pm_runtime_disable(dev
);
720 static struct rot_limit_table rot_limit_tbl
= {
737 static struct platform_device_id rotator_driver_ids
[] = {
739 .name
= "exynos-rot",
740 .driver_data
= (unsigned long)&rot_limit_tbl
,
745 static int rotator_clk_crtl(struct rot_context
*rot
, bool enable
)
748 clk_enable(rot
->clock
);
749 rot
->suspended
= false;
751 clk_disable(rot
->clock
);
752 rot
->suspended
= true;
759 #ifdef CONFIG_PM_SLEEP
760 static int rotator_suspend(struct device
*dev
)
762 struct rot_context
*rot
= dev_get_drvdata(dev
);
764 if (pm_runtime_suspended(dev
))
767 return rotator_clk_crtl(rot
, false);
770 static int rotator_resume(struct device
*dev
)
772 struct rot_context
*rot
= dev_get_drvdata(dev
);
774 if (!pm_runtime_suspended(dev
))
775 return rotator_clk_crtl(rot
, true);
781 #ifdef CONFIG_PM_RUNTIME
782 static int rotator_runtime_suspend(struct device
*dev
)
784 struct rot_context
*rot
= dev_get_drvdata(dev
);
786 return rotator_clk_crtl(rot
, false);
789 static int rotator_runtime_resume(struct device
*dev
)
791 struct rot_context
*rot
= dev_get_drvdata(dev
);
793 return rotator_clk_crtl(rot
, true);
797 static const struct dev_pm_ops rotator_pm_ops
= {
798 SET_SYSTEM_SLEEP_PM_OPS(rotator_suspend
, rotator_resume
)
799 SET_RUNTIME_PM_OPS(rotator_runtime_suspend
, rotator_runtime_resume
,
803 struct platform_driver rotator_driver
= {
804 .probe
= rotator_probe
,
805 .remove
= rotator_remove
,
806 .id_table
= rotator_driver_ids
,
808 .name
= "exynos-rot",
809 .owner
= THIS_MODULE
,
810 .pm
= &rotator_pm_ops
,