2 * Copyright (C) 2012 Samsung Electronics Co.Ltd
4 * Eunchul Kim <chulspro.kim@samsung.com>
5 * Jinyoung Jeon <jy0.jeon@samsung.com>
6 * Sangmin Lee <lsmin.lee@samsung.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/kernel.h>
15 #include <linux/platform_device.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/regmap.h>
18 #include <linux/clk.h>
19 #include <linux/pm_runtime.h>
21 #include <linux/spinlock.h>
24 #include <drm/exynos_drm.h>
25 #include "regs-fimc.h"
26 #include "exynos_drm_drv.h"
27 #include "exynos_drm_ipp.h"
28 #include "exynos_drm_fimc.h"
31 * FIMC stands for Fully Interactive Mobile Camera and
32 * supports image scaler/rotator and input/output DMA operations.
33 * input DMA reads image data from the memory.
34 * output DMA writes image data to memory.
35 * FIMC supports image rotation and image effect functions.
37 * M2M operation : supports crop/scale/rotation/csc so on.
38 * Memory ----> FIMC H/W ----> Memory.
39 * Writeback operation : supports cloned screen with FIMD.
40 * FIMD ----> FIMC H/W ----> Memory.
41 * Output operation : supports direct display using local path.
42 * Memory ----> FIMC H/W ----> FIMD.
47 * 1. check suspend/resume api if needed.
48 * 2. need to check use case platform_device_id.
49 * 3. check src/dst size with, height.
50 * 4. added check_prepare api for right register.
51 * 5. need to add supported list in prop_list.
52 * 6. check prescaler/scaler optimization.
55 #define FIMC_MAX_DEVS 4
56 #define FIMC_MAX_SRC 2
57 #define FIMC_MAX_DST 32
58 #define FIMC_SHFACTOR 10
59 #define FIMC_BUF_STOP 1
60 #define FIMC_BUF_START 2
61 #define FIMC_WIDTH_ITU_709 1280
62 #define FIMC_REFRESH_MAX 60
63 #define FIMC_REFRESH_MIN 12
64 #define FIMC_CROP_MAX 8192
65 #define FIMC_CROP_MIN 32
66 #define FIMC_SCALE_MAX 4224
67 #define FIMC_SCALE_MIN 32
69 #define get_fimc_context(dev) platform_get_drvdata(to_platform_device(dev))
70 #define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
71 struct fimc_context, ippdrv);
88 static const char * const fimc_clock_names
[] = {
89 [FIMC_CLK_LCLK
] = "sclk_fimc",
90 [FIMC_CLK_GATE
] = "fimc",
91 [FIMC_CLK_WB_A
] = "pxl_async0",
92 [FIMC_CLK_WB_B
] = "pxl_async1",
93 [FIMC_CLK_MUX
] = "mux",
94 [FIMC_CLK_PARENT
] = "parent",
97 #define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
100 * A structure of scaler.
102 * @range: narrow, wide.
103 * @bypass: unused scaler path.
104 * @up_h: horizontal scale up.
105 * @up_v: vertical scale up.
106 * @hratio: horizontal ratio.
107 * @vratio: vertical ratio.
119 * A structure of scaler capability.
121 * find user manual table 43-1.
122 * @in_hori: scaler input horizontal size.
123 * @bypass: scaler bypass mode.
124 * @dst_h_wo_rot: target horizontal size without output rotation.
125 * @dst_h_rot: target horizontal size with output rotation.
126 * @rl_w_wo_rot: real width without input rotation.
127 * @rl_h_rot: real height without output rotation.
129 struct fimc_capability
{
142 * A structure of fimc context.
144 * @ippdrv: prepare initialization using ippdrv.
145 * @regs_res: register resources.
146 * @regs: memory mapped io registers.
147 * @lock: locking of operations.
148 * @clocks: fimc clocks.
149 * @clk_frequency: LCLK clock frequency.
150 * @sysreg: handle to SYSREG block regmap.
151 * @sc: scaler infomations.
152 * @pol: porarity of writeback.
155 * @suspended: qos operations.
157 struct fimc_context
{
158 struct exynos_drm_ippdrv ippdrv
;
159 struct resource
*regs_res
;
162 struct clk
*clocks
[FIMC_CLKS_MAX
];
164 struct regmap
*sysreg
;
165 struct fimc_scaler sc
;
171 static u32
fimc_read(struct fimc_context
*ctx
, u32 reg
)
173 return readl(ctx
->regs
+ reg
);
176 static void fimc_write(struct fimc_context
*ctx
, u32 val
, u32 reg
)
178 writel(val
, ctx
->regs
+ reg
);
181 static void fimc_set_bits(struct fimc_context
*ctx
, u32 reg
, u32 bits
)
183 void __iomem
*r
= ctx
->regs
+ reg
;
185 writel(readl(r
) | bits
, r
);
188 static void fimc_clear_bits(struct fimc_context
*ctx
, u32 reg
, u32 bits
)
190 void __iomem
*r
= ctx
->regs
+ reg
;
192 writel(readl(r
) & ~bits
, r
);
195 static void fimc_sw_reset(struct fimc_context
*ctx
)
199 /* stop dma operation */
200 cfg
= fimc_read(ctx
, EXYNOS_CISTATUS
);
201 if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg
))
202 fimc_clear_bits(ctx
, EXYNOS_MSCTRL
, EXYNOS_MSCTRL_ENVID
);
204 fimc_set_bits(ctx
, EXYNOS_CISRCFMT
, EXYNOS_CISRCFMT_ITU601_8BIT
);
206 /* disable image capture */
207 fimc_clear_bits(ctx
, EXYNOS_CIIMGCPT
,
208 EXYNOS_CIIMGCPT_IMGCPTEN_SC
| EXYNOS_CIIMGCPT_IMGCPTEN
);
211 fimc_set_bits(ctx
, EXYNOS_CIGCTRL
, EXYNOS_CIGCTRL_SWRST
);
213 /* s/w reset complete */
214 fimc_clear_bits(ctx
, EXYNOS_CIGCTRL
, EXYNOS_CIGCTRL_SWRST
);
217 fimc_write(ctx
, 0x0, EXYNOS_CIFCNTSEQ
);
220 static int fimc_set_camblk_fimd0_wb(struct fimc_context
*ctx
)
222 return regmap_update_bits(ctx
->sysreg
, SYSREG_CAMERA_BLK
,
223 SYSREG_FIMD0WB_DEST_MASK
,
224 ctx
->id
<< SYSREG_FIMD0WB_DEST_SHIFT
);
227 static void fimc_set_type_ctrl(struct fimc_context
*ctx
, enum fimc_wb wb
)
231 DRM_DEBUG_KMS("wb[%d]\n", wb
);
233 cfg
= fimc_read(ctx
, EXYNOS_CIGCTRL
);
234 cfg
&= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK
|
235 EXYNOS_CIGCTRL_SELCAM_ITU_MASK
|
236 EXYNOS_CIGCTRL_SELCAM_MIPI_MASK
|
237 EXYNOS_CIGCTRL_SELCAM_FIMC_MASK
|
238 EXYNOS_CIGCTRL_SELWB_CAMIF_MASK
|
239 EXYNOS_CIGCTRL_SELWRITEBACK_MASK
);
243 cfg
|= (EXYNOS_CIGCTRL_SELWRITEBACK_A
|
244 EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK
);
247 cfg
|= (EXYNOS_CIGCTRL_SELWRITEBACK_B
|
248 EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK
);
252 cfg
|= (EXYNOS_CIGCTRL_SELCAM_ITU_A
|
253 EXYNOS_CIGCTRL_SELWRITEBACK_A
|
254 EXYNOS_CIGCTRL_SELCAM_MIPI_A
|
255 EXYNOS_CIGCTRL_SELCAM_FIMC_ITU
);
259 fimc_write(ctx
, cfg
, EXYNOS_CIGCTRL
);
262 static void fimc_handle_jpeg(struct fimc_context
*ctx
, bool enable
)
266 DRM_DEBUG_KMS("enable[%d]\n", enable
);
268 cfg
= fimc_read(ctx
, EXYNOS_CIGCTRL
);
270 cfg
|= EXYNOS_CIGCTRL_CAM_JPEG
;
272 cfg
&= ~EXYNOS_CIGCTRL_CAM_JPEG
;
274 fimc_write(ctx
, cfg
, EXYNOS_CIGCTRL
);
277 static void fimc_mask_irq(struct fimc_context
*ctx
, bool enable
)
281 DRM_DEBUG_KMS("enable[%d]\n", enable
);
283 cfg
= fimc_read(ctx
, EXYNOS_CIGCTRL
);
285 cfg
&= ~EXYNOS_CIGCTRL_IRQ_OVFEN
;
286 cfg
|= EXYNOS_CIGCTRL_IRQ_ENABLE
| EXYNOS_CIGCTRL_IRQ_LEVEL
;
288 cfg
&= ~EXYNOS_CIGCTRL_IRQ_ENABLE
;
289 fimc_write(ctx
, cfg
, EXYNOS_CIGCTRL
);
292 static void fimc_clear_irq(struct fimc_context
*ctx
)
294 fimc_set_bits(ctx
, EXYNOS_CIGCTRL
, EXYNOS_CIGCTRL_IRQ_CLR
);
297 static bool fimc_check_ovf(struct fimc_context
*ctx
)
299 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
302 status
= fimc_read(ctx
, EXYNOS_CISTATUS
);
303 flag
= EXYNOS_CISTATUS_OVFIY
| EXYNOS_CISTATUS_OVFICB
|
304 EXYNOS_CISTATUS_OVFICR
;
306 DRM_DEBUG_KMS("flag[0x%x]\n", flag
);
309 fimc_set_bits(ctx
, EXYNOS_CIWDOFST
,
310 EXYNOS_CIWDOFST_CLROVFIY
| EXYNOS_CIWDOFST_CLROVFICB
|
311 EXYNOS_CIWDOFST_CLROVFICR
);
313 dev_err(ippdrv
->dev
, "occurred overflow at %d, status 0x%x.\n",
321 static bool fimc_check_frame_end(struct fimc_context
*ctx
)
325 cfg
= fimc_read(ctx
, EXYNOS_CISTATUS
);
327 DRM_DEBUG_KMS("cfg[0x%x]\n", cfg
);
329 if (!(cfg
& EXYNOS_CISTATUS_FRAMEEND
))
332 cfg
&= ~(EXYNOS_CISTATUS_FRAMEEND
);
333 fimc_write(ctx
, cfg
, EXYNOS_CISTATUS
);
338 static int fimc_get_buf_id(struct fimc_context
*ctx
)
341 int frame_cnt
, buf_id
;
343 cfg
= fimc_read(ctx
, EXYNOS_CISTATUS2
);
344 frame_cnt
= EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg
);
347 frame_cnt
= EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg
);
349 DRM_DEBUG_KMS("present[%d]before[%d]\n",
350 EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg
),
351 EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg
));
353 if (frame_cnt
== 0) {
354 DRM_ERROR("failed to get frame count.\n");
358 buf_id
= frame_cnt
- 1;
359 DRM_DEBUG_KMS("buf_id[%d]\n", buf_id
);
364 static void fimc_handle_lastend(struct fimc_context
*ctx
, bool enable
)
368 DRM_DEBUG_KMS("enable[%d]\n", enable
);
370 cfg
= fimc_read(ctx
, EXYNOS_CIOCTRL
);
372 cfg
|= EXYNOS_CIOCTRL_LASTENDEN
;
374 cfg
&= ~EXYNOS_CIOCTRL_LASTENDEN
;
376 fimc_write(ctx
, cfg
, EXYNOS_CIOCTRL
);
380 static int fimc_src_set_fmt_order(struct fimc_context
*ctx
, u32 fmt
)
382 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
385 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt
);
388 cfg
= fimc_read(ctx
, EXYNOS_CISCCTRL
);
389 cfg
&= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK
;
392 case DRM_FORMAT_RGB565
:
393 cfg
|= EXYNOS_CISCCTRL_INRGB_FMT_RGB565
;
394 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
396 case DRM_FORMAT_RGB888
:
397 case DRM_FORMAT_XRGB8888
:
398 cfg
|= EXYNOS_CISCCTRL_INRGB_FMT_RGB888
;
399 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
407 cfg
= fimc_read(ctx
, EXYNOS_MSCTRL
);
408 cfg
&= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK
|
409 EXYNOS_MSCTRL_C_INT_IN_2PLANE
|
410 EXYNOS_MSCTRL_ORDER422_YCBYCR
);
413 case DRM_FORMAT_YUYV
:
414 cfg
|= EXYNOS_MSCTRL_ORDER422_YCBYCR
;
416 case DRM_FORMAT_YVYU
:
417 cfg
|= EXYNOS_MSCTRL_ORDER422_YCRYCB
;
419 case DRM_FORMAT_UYVY
:
420 cfg
|= EXYNOS_MSCTRL_ORDER422_CBYCRY
;
422 case DRM_FORMAT_VYUY
:
423 case DRM_FORMAT_YUV444
:
424 cfg
|= EXYNOS_MSCTRL_ORDER422_CRYCBY
;
426 case DRM_FORMAT_NV21
:
427 case DRM_FORMAT_NV61
:
428 cfg
|= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB
|
429 EXYNOS_MSCTRL_C_INT_IN_2PLANE
);
431 case DRM_FORMAT_YUV422
:
432 case DRM_FORMAT_YUV420
:
433 case DRM_FORMAT_YVU420
:
434 cfg
|= EXYNOS_MSCTRL_C_INT_IN_3PLANE
;
436 case DRM_FORMAT_NV12
:
437 case DRM_FORMAT_NV16
:
438 cfg
|= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR
|
439 EXYNOS_MSCTRL_C_INT_IN_2PLANE
);
442 dev_err(ippdrv
->dev
, "invalid source yuv order 0x%x.\n", fmt
);
446 fimc_write(ctx
, cfg
, EXYNOS_MSCTRL
);
451 static int fimc_src_set_fmt(struct device
*dev
, u32 fmt
)
453 struct fimc_context
*ctx
= get_fimc_context(dev
);
454 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
457 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt
);
459 cfg
= fimc_read(ctx
, EXYNOS_MSCTRL
);
460 cfg
&= ~EXYNOS_MSCTRL_INFORMAT_RGB
;
463 case DRM_FORMAT_RGB565
:
464 case DRM_FORMAT_RGB888
:
465 case DRM_FORMAT_XRGB8888
:
466 cfg
|= EXYNOS_MSCTRL_INFORMAT_RGB
;
468 case DRM_FORMAT_YUV444
:
469 cfg
|= EXYNOS_MSCTRL_INFORMAT_YCBCR420
;
471 case DRM_FORMAT_YUYV
:
472 case DRM_FORMAT_YVYU
:
473 case DRM_FORMAT_UYVY
:
474 case DRM_FORMAT_VYUY
:
475 cfg
|= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE
;
477 case DRM_FORMAT_NV16
:
478 case DRM_FORMAT_NV61
:
479 case DRM_FORMAT_YUV422
:
480 cfg
|= EXYNOS_MSCTRL_INFORMAT_YCBCR422
;
482 case DRM_FORMAT_YUV420
:
483 case DRM_FORMAT_YVU420
:
484 case DRM_FORMAT_NV12
:
485 case DRM_FORMAT_NV21
:
486 cfg
|= EXYNOS_MSCTRL_INFORMAT_YCBCR420
;
489 dev_err(ippdrv
->dev
, "invalid source format 0x%x.\n", fmt
);
493 fimc_write(ctx
, cfg
, EXYNOS_MSCTRL
);
495 cfg
= fimc_read(ctx
, EXYNOS_CIDMAPARAM
);
496 cfg
&= ~EXYNOS_CIDMAPARAM_R_MODE_MASK
;
498 cfg
|= EXYNOS_CIDMAPARAM_R_MODE_LINEAR
;
500 fimc_write(ctx
, cfg
, EXYNOS_CIDMAPARAM
);
502 return fimc_src_set_fmt_order(ctx
, fmt
);
505 static int fimc_src_set_transf(struct device
*dev
,
506 enum drm_exynos_degree degree
,
507 enum drm_exynos_flip flip
, bool *swap
)
509 struct fimc_context
*ctx
= get_fimc_context(dev
);
510 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
513 DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree
, flip
);
515 cfg1
= fimc_read(ctx
, EXYNOS_MSCTRL
);
516 cfg1
&= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR
|
517 EXYNOS_MSCTRL_FLIP_Y_MIRROR
);
519 cfg2
= fimc_read(ctx
, EXYNOS_CITRGFMT
);
520 cfg2
&= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE
;
523 case EXYNOS_DRM_DEGREE_0
:
524 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
525 cfg1
|= EXYNOS_MSCTRL_FLIP_X_MIRROR
;
526 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
527 cfg1
|= EXYNOS_MSCTRL_FLIP_Y_MIRROR
;
529 case EXYNOS_DRM_DEGREE_90
:
530 cfg2
|= EXYNOS_CITRGFMT_INROT90_CLOCKWISE
;
531 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
532 cfg1
|= EXYNOS_MSCTRL_FLIP_X_MIRROR
;
533 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
534 cfg1
|= EXYNOS_MSCTRL_FLIP_Y_MIRROR
;
536 case EXYNOS_DRM_DEGREE_180
:
537 cfg1
|= (EXYNOS_MSCTRL_FLIP_X_MIRROR
|
538 EXYNOS_MSCTRL_FLIP_Y_MIRROR
);
539 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
540 cfg1
&= ~EXYNOS_MSCTRL_FLIP_X_MIRROR
;
541 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
542 cfg1
&= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR
;
544 case EXYNOS_DRM_DEGREE_270
:
545 cfg1
|= (EXYNOS_MSCTRL_FLIP_X_MIRROR
|
546 EXYNOS_MSCTRL_FLIP_Y_MIRROR
);
547 cfg2
|= EXYNOS_CITRGFMT_INROT90_CLOCKWISE
;
548 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
549 cfg1
&= ~EXYNOS_MSCTRL_FLIP_X_MIRROR
;
550 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
551 cfg1
&= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR
;
554 dev_err(ippdrv
->dev
, "invalid degree value %d.\n", degree
);
558 fimc_write(ctx
, cfg1
, EXYNOS_MSCTRL
);
559 fimc_write(ctx
, cfg2
, EXYNOS_CITRGFMT
);
560 *swap
= (cfg2
& EXYNOS_CITRGFMT_INROT90_CLOCKWISE
) ? 1 : 0;
565 static int fimc_set_window(struct fimc_context
*ctx
,
566 struct drm_exynos_pos
*pos
, struct drm_exynos_sz
*sz
)
568 u32 cfg
, h1
, h2
, v1
, v2
;
572 h2
= sz
->hsize
- pos
->w
- pos
->x
;
574 v2
= sz
->vsize
- pos
->h
- pos
->y
;
576 DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
577 pos
->x
, pos
->y
, pos
->w
, pos
->h
, sz
->hsize
, sz
->vsize
);
578 DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1
, h2
, v1
, v2
);
581 * set window offset 1, 2 size
582 * check figure 43-21 in user manual
584 cfg
= fimc_read(ctx
, EXYNOS_CIWDOFST
);
585 cfg
&= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK
|
586 EXYNOS_CIWDOFST_WINVEROFST_MASK
);
587 cfg
|= (EXYNOS_CIWDOFST_WINHOROFST(h1
) |
588 EXYNOS_CIWDOFST_WINVEROFST(v1
));
589 cfg
|= EXYNOS_CIWDOFST_WINOFSEN
;
590 fimc_write(ctx
, cfg
, EXYNOS_CIWDOFST
);
592 cfg
= (EXYNOS_CIWDOFST2_WINHOROFST2(h2
) |
593 EXYNOS_CIWDOFST2_WINVEROFST2(v2
));
594 fimc_write(ctx
, cfg
, EXYNOS_CIWDOFST2
);
599 static int fimc_src_set_size(struct device
*dev
, int swap
,
600 struct drm_exynos_pos
*pos
, struct drm_exynos_sz
*sz
)
602 struct fimc_context
*ctx
= get_fimc_context(dev
);
603 struct drm_exynos_pos img_pos
= *pos
;
604 struct drm_exynos_sz img_sz
= *sz
;
607 DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
608 swap
, sz
->hsize
, sz
->vsize
);
611 cfg
= (EXYNOS_ORGISIZE_HORIZONTAL(img_sz
.hsize
) |
612 EXYNOS_ORGISIZE_VERTICAL(img_sz
.vsize
));
614 fimc_write(ctx
, cfg
, EXYNOS_ORGISIZE
);
616 DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos
->x
, pos
->y
, pos
->w
, pos
->h
);
621 img_sz
.hsize
= sz
->vsize
;
622 img_sz
.vsize
= sz
->hsize
;
625 /* set input DMA image size */
626 cfg
= fimc_read(ctx
, EXYNOS_CIREAL_ISIZE
);
627 cfg
&= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK
|
628 EXYNOS_CIREAL_ISIZE_WIDTH_MASK
);
629 cfg
|= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos
.w
) |
630 EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos
.h
));
631 fimc_write(ctx
, cfg
, EXYNOS_CIREAL_ISIZE
);
634 * set input FIFO image size
635 * for now, we support only ITU601 8 bit mode
637 cfg
= (EXYNOS_CISRCFMT_ITU601_8BIT
|
638 EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz
.hsize
) |
639 EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz
.vsize
));
640 fimc_write(ctx
, cfg
, EXYNOS_CISRCFMT
);
642 /* offset Y(RGB), Cb, Cr */
643 cfg
= (EXYNOS_CIIYOFF_HORIZONTAL(img_pos
.x
) |
644 EXYNOS_CIIYOFF_VERTICAL(img_pos
.y
));
645 fimc_write(ctx
, cfg
, EXYNOS_CIIYOFF
);
646 cfg
= (EXYNOS_CIICBOFF_HORIZONTAL(img_pos
.x
) |
647 EXYNOS_CIICBOFF_VERTICAL(img_pos
.y
));
648 fimc_write(ctx
, cfg
, EXYNOS_CIICBOFF
);
649 cfg
= (EXYNOS_CIICROFF_HORIZONTAL(img_pos
.x
) |
650 EXYNOS_CIICROFF_VERTICAL(img_pos
.y
));
651 fimc_write(ctx
, cfg
, EXYNOS_CIICROFF
);
653 return fimc_set_window(ctx
, &img_pos
, &img_sz
);
656 static int fimc_src_set_addr(struct device
*dev
,
657 struct drm_exynos_ipp_buf_info
*buf_info
, u32 buf_id
,
658 enum drm_exynos_ipp_buf_type buf_type
)
660 struct fimc_context
*ctx
= get_fimc_context(dev
);
661 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
662 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
663 struct drm_exynos_ipp_property
*property
;
664 struct drm_exynos_ipp_config
*config
;
667 DRM_ERROR("failed to get c_node.\n");
671 property
= &c_node
->property
;
673 DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
674 property
->prop_id
, buf_id
, buf_type
);
676 if (buf_id
> FIMC_MAX_SRC
) {
677 dev_info(ippdrv
->dev
, "invalid buf_id %d.\n", buf_id
);
681 /* address register set */
683 case IPP_BUF_ENQUEUE
:
684 config
= &property
->config
[EXYNOS_DRM_OPS_SRC
];
685 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_Y
],
688 if (config
->fmt
== DRM_FORMAT_YVU420
) {
689 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CR
],
691 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CB
],
694 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CB
],
696 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CR
],
700 case IPP_BUF_DEQUEUE
:
701 fimc_write(ctx
, 0x0, EXYNOS_CIIYSA0
);
702 fimc_write(ctx
, 0x0, EXYNOS_CIICBSA0
);
703 fimc_write(ctx
, 0x0, EXYNOS_CIICRSA0
);
713 static struct exynos_drm_ipp_ops fimc_src_ops
= {
714 .set_fmt
= fimc_src_set_fmt
,
715 .set_transf
= fimc_src_set_transf
,
716 .set_size
= fimc_src_set_size
,
717 .set_addr
= fimc_src_set_addr
,
720 static int fimc_dst_set_fmt_order(struct fimc_context
*ctx
, u32 fmt
)
722 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
725 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt
);
728 cfg
= fimc_read(ctx
, EXYNOS_CISCCTRL
);
729 cfg
&= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK
;
732 case DRM_FORMAT_RGB565
:
733 cfg
|= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565
;
734 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
736 case DRM_FORMAT_RGB888
:
737 cfg
|= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888
;
738 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
740 case DRM_FORMAT_XRGB8888
:
741 cfg
|= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888
|
742 EXYNOS_CISCCTRL_EXTRGB_EXTENSION
);
743 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
751 cfg
= fimc_read(ctx
, EXYNOS_CIOCTRL
);
752 cfg
&= ~(EXYNOS_CIOCTRL_ORDER2P_MASK
|
753 EXYNOS_CIOCTRL_ORDER422_MASK
|
754 EXYNOS_CIOCTRL_YCBCR_PLANE_MASK
);
757 case DRM_FORMAT_XRGB8888
:
758 cfg
|= EXYNOS_CIOCTRL_ALPHA_OUT
;
760 case DRM_FORMAT_YUYV
:
761 cfg
|= EXYNOS_CIOCTRL_ORDER422_YCBYCR
;
763 case DRM_FORMAT_YVYU
:
764 cfg
|= EXYNOS_CIOCTRL_ORDER422_YCRYCB
;
766 case DRM_FORMAT_UYVY
:
767 cfg
|= EXYNOS_CIOCTRL_ORDER422_CBYCRY
;
769 case DRM_FORMAT_VYUY
:
770 cfg
|= EXYNOS_CIOCTRL_ORDER422_CRYCBY
;
772 case DRM_FORMAT_NV21
:
773 case DRM_FORMAT_NV61
:
774 cfg
|= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB
;
775 cfg
|= EXYNOS_CIOCTRL_YCBCR_2PLANE
;
777 case DRM_FORMAT_YUV422
:
778 case DRM_FORMAT_YUV420
:
779 case DRM_FORMAT_YVU420
:
780 cfg
|= EXYNOS_CIOCTRL_YCBCR_3PLANE
;
782 case DRM_FORMAT_NV12
:
783 case DRM_FORMAT_NV16
:
784 cfg
|= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR
;
785 cfg
|= EXYNOS_CIOCTRL_YCBCR_2PLANE
;
788 dev_err(ippdrv
->dev
, "invalid target yuv order 0x%x.\n", fmt
);
792 fimc_write(ctx
, cfg
, EXYNOS_CIOCTRL
);
797 static int fimc_dst_set_fmt(struct device
*dev
, u32 fmt
)
799 struct fimc_context
*ctx
= get_fimc_context(dev
);
800 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
803 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt
);
805 cfg
= fimc_read(ctx
, EXYNOS_CIEXTEN
);
807 if (fmt
== DRM_FORMAT_AYUV
) {
808 cfg
|= EXYNOS_CIEXTEN_YUV444_OUT
;
809 fimc_write(ctx
, cfg
, EXYNOS_CIEXTEN
);
811 cfg
&= ~EXYNOS_CIEXTEN_YUV444_OUT
;
812 fimc_write(ctx
, cfg
, EXYNOS_CIEXTEN
);
814 cfg
= fimc_read(ctx
, EXYNOS_CITRGFMT
);
815 cfg
&= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK
;
818 case DRM_FORMAT_RGB565
:
819 case DRM_FORMAT_RGB888
:
820 case DRM_FORMAT_XRGB8888
:
821 cfg
|= EXYNOS_CITRGFMT_OUTFORMAT_RGB
;
823 case DRM_FORMAT_YUYV
:
824 case DRM_FORMAT_YVYU
:
825 case DRM_FORMAT_UYVY
:
826 case DRM_FORMAT_VYUY
:
827 cfg
|= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE
;
829 case DRM_FORMAT_NV16
:
830 case DRM_FORMAT_NV61
:
831 case DRM_FORMAT_YUV422
:
832 cfg
|= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422
;
834 case DRM_FORMAT_YUV420
:
835 case DRM_FORMAT_YVU420
:
836 case DRM_FORMAT_NV12
:
837 case DRM_FORMAT_NV21
:
838 cfg
|= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420
;
841 dev_err(ippdrv
->dev
, "invalid target format 0x%x.\n",
846 fimc_write(ctx
, cfg
, EXYNOS_CITRGFMT
);
849 cfg
= fimc_read(ctx
, EXYNOS_CIDMAPARAM
);
850 cfg
&= ~EXYNOS_CIDMAPARAM_W_MODE_MASK
;
852 cfg
|= EXYNOS_CIDMAPARAM_W_MODE_LINEAR
;
854 fimc_write(ctx
, cfg
, EXYNOS_CIDMAPARAM
);
856 return fimc_dst_set_fmt_order(ctx
, fmt
);
859 static int fimc_dst_set_transf(struct device
*dev
,
860 enum drm_exynos_degree degree
,
861 enum drm_exynos_flip flip
, bool *swap
)
863 struct fimc_context
*ctx
= get_fimc_context(dev
);
864 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
867 DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree
, flip
);
869 cfg
= fimc_read(ctx
, EXYNOS_CITRGFMT
);
870 cfg
&= ~EXYNOS_CITRGFMT_FLIP_MASK
;
871 cfg
&= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE
;
874 case EXYNOS_DRM_DEGREE_0
:
875 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
876 cfg
|= EXYNOS_CITRGFMT_FLIP_X_MIRROR
;
877 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
878 cfg
|= EXYNOS_CITRGFMT_FLIP_Y_MIRROR
;
880 case EXYNOS_DRM_DEGREE_90
:
881 cfg
|= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE
;
882 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
883 cfg
|= EXYNOS_CITRGFMT_FLIP_X_MIRROR
;
884 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
885 cfg
|= EXYNOS_CITRGFMT_FLIP_Y_MIRROR
;
887 case EXYNOS_DRM_DEGREE_180
:
888 cfg
|= (EXYNOS_CITRGFMT_FLIP_X_MIRROR
|
889 EXYNOS_CITRGFMT_FLIP_Y_MIRROR
);
890 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
891 cfg
&= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR
;
892 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
893 cfg
&= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR
;
895 case EXYNOS_DRM_DEGREE_270
:
896 cfg
|= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE
|
897 EXYNOS_CITRGFMT_FLIP_X_MIRROR
|
898 EXYNOS_CITRGFMT_FLIP_Y_MIRROR
);
899 if (flip
& EXYNOS_DRM_FLIP_VERTICAL
)
900 cfg
&= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR
;
901 if (flip
& EXYNOS_DRM_FLIP_HORIZONTAL
)
902 cfg
&= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR
;
905 dev_err(ippdrv
->dev
, "invalid degree value %d.\n", degree
);
909 fimc_write(ctx
, cfg
, EXYNOS_CITRGFMT
);
910 *swap
= (cfg
& EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE
) ? 1 : 0;
915 static int fimc_set_prescaler(struct fimc_context
*ctx
, struct fimc_scaler
*sc
,
916 struct drm_exynos_pos
*src
, struct drm_exynos_pos
*dst
)
918 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
919 u32 cfg
, cfg_ext
, shfactor
;
920 u32 pre_dst_width
, pre_dst_height
;
921 u32 hfactor
, vfactor
;
923 u32 src_w
, src_h
, dst_w
, dst_h
;
925 cfg_ext
= fimc_read(ctx
, EXYNOS_CITRGFMT
);
926 if (cfg_ext
& EXYNOS_CITRGFMT_INROT90_CLOCKWISE
) {
934 if (cfg_ext
& EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE
) {
942 /* fimc_ippdrv_check_property assures that dividers are not null */
943 hfactor
= fls(src_w
/ dst_w
/ 2);
944 if (hfactor
> FIMC_SHFACTOR
/ 2) {
945 dev_err(ippdrv
->dev
, "failed to get ratio horizontal.\n");
949 vfactor
= fls(src_h
/ dst_h
/ 2);
950 if (vfactor
> FIMC_SHFACTOR
/ 2) {
951 dev_err(ippdrv
->dev
, "failed to get ratio vertical.\n");
955 pre_dst_width
= src_w
>> hfactor
;
956 pre_dst_height
= src_h
>> vfactor
;
957 DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n",
958 pre_dst_width
, pre_dst_height
);
959 DRM_DEBUG_KMS("hfactor[%d]vfactor[%d]\n", hfactor
, vfactor
);
961 sc
->hratio
= (src_w
<< 14) / (dst_w
<< hfactor
);
962 sc
->vratio
= (src_h
<< 14) / (dst_h
<< vfactor
);
963 sc
->up_h
= (dst_w
>= src_w
) ? true : false;
964 sc
->up_v
= (dst_h
>= src_h
) ? true : false;
965 DRM_DEBUG_KMS("hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
966 sc
->hratio
, sc
->vratio
, sc
->up_h
, sc
->up_v
);
968 shfactor
= FIMC_SHFACTOR
- (hfactor
+ vfactor
);
969 DRM_DEBUG_KMS("shfactor[%d]\n", shfactor
);
971 cfg
= (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor
) |
972 EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor
) |
973 EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor
));
974 fimc_write(ctx
, cfg
, EXYNOS_CISCPRERATIO
);
976 cfg
= (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width
) |
977 EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height
));
978 fimc_write(ctx
, cfg
, EXYNOS_CISCPREDST
);
983 static void fimc_set_scaler(struct fimc_context
*ctx
, struct fimc_scaler
*sc
)
987 DRM_DEBUG_KMS("range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
988 sc
->range
, sc
->bypass
, sc
->up_h
, sc
->up_v
);
989 DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n",
990 sc
->hratio
, sc
->vratio
);
992 cfg
= fimc_read(ctx
, EXYNOS_CISCCTRL
);
993 cfg
&= ~(EXYNOS_CISCCTRL_SCALERBYPASS
|
994 EXYNOS_CISCCTRL_SCALEUP_H
| EXYNOS_CISCCTRL_SCALEUP_V
|
995 EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK
|
996 EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK
|
997 EXYNOS_CISCCTRL_CSCR2Y_WIDE
|
998 EXYNOS_CISCCTRL_CSCY2R_WIDE
);
1001 cfg
|= (EXYNOS_CISCCTRL_CSCR2Y_WIDE
|
1002 EXYNOS_CISCCTRL_CSCY2R_WIDE
);
1004 cfg
|= EXYNOS_CISCCTRL_SCALERBYPASS
;
1006 cfg
|= EXYNOS_CISCCTRL_SCALEUP_H
;
1008 cfg
|= EXYNOS_CISCCTRL_SCALEUP_V
;
1010 cfg
|= (EXYNOS_CISCCTRL_MAINHORRATIO((sc
->hratio
>> 6)) |
1011 EXYNOS_CISCCTRL_MAINVERRATIO((sc
->vratio
>> 6)));
1012 fimc_write(ctx
, cfg
, EXYNOS_CISCCTRL
);
1014 cfg_ext
= fimc_read(ctx
, EXYNOS_CIEXTEN
);
1015 cfg_ext
&= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK
;
1016 cfg_ext
&= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK
;
1017 cfg_ext
|= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc
->hratio
) |
1018 EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc
->vratio
));
1019 fimc_write(ctx
, cfg_ext
, EXYNOS_CIEXTEN
);
1022 static int fimc_dst_set_size(struct device
*dev
, int swap
,
1023 struct drm_exynos_pos
*pos
, struct drm_exynos_sz
*sz
)
1025 struct fimc_context
*ctx
= get_fimc_context(dev
);
1026 struct drm_exynos_pos img_pos
= *pos
;
1027 struct drm_exynos_sz img_sz
= *sz
;
1030 DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
1031 swap
, sz
->hsize
, sz
->vsize
);
1034 cfg
= (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz
.hsize
) |
1035 EXYNOS_ORGOSIZE_VERTICAL(img_sz
.vsize
));
1037 fimc_write(ctx
, cfg
, EXYNOS_ORGOSIZE
);
1039 DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos
->x
, pos
->y
, pos
->w
, pos
->h
);
1042 cfg
= fimc_read(ctx
, EXYNOS_CIGCTRL
);
1043 cfg
&= ~EXYNOS_CIGCTRL_CSC_MASK
;
1045 if (sz
->hsize
>= FIMC_WIDTH_ITU_709
)
1046 cfg
|= EXYNOS_CIGCTRL_CSC_ITU709
;
1048 cfg
|= EXYNOS_CIGCTRL_CSC_ITU601
;
1050 fimc_write(ctx
, cfg
, EXYNOS_CIGCTRL
);
1055 img_sz
.hsize
= sz
->vsize
;
1056 img_sz
.vsize
= sz
->hsize
;
1059 /* target image size */
1060 cfg
= fimc_read(ctx
, EXYNOS_CITRGFMT
);
1061 cfg
&= ~(EXYNOS_CITRGFMT_TARGETH_MASK
|
1062 EXYNOS_CITRGFMT_TARGETV_MASK
);
1063 cfg
|= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos
.w
) |
1064 EXYNOS_CITRGFMT_TARGETVSIZE(img_pos
.h
));
1065 fimc_write(ctx
, cfg
, EXYNOS_CITRGFMT
);
1068 cfg
= EXYNOS_CITAREA_TARGET_AREA(img_pos
.w
* img_pos
.h
);
1069 fimc_write(ctx
, cfg
, EXYNOS_CITAREA
);
1071 /* offset Y(RGB), Cb, Cr */
1072 cfg
= (EXYNOS_CIOYOFF_HORIZONTAL(img_pos
.x
) |
1073 EXYNOS_CIOYOFF_VERTICAL(img_pos
.y
));
1074 fimc_write(ctx
, cfg
, EXYNOS_CIOYOFF
);
1075 cfg
= (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos
.x
) |
1076 EXYNOS_CIOCBOFF_VERTICAL(img_pos
.y
));
1077 fimc_write(ctx
, cfg
, EXYNOS_CIOCBOFF
);
1078 cfg
= (EXYNOS_CIOCROFF_HORIZONTAL(img_pos
.x
) |
1079 EXYNOS_CIOCROFF_VERTICAL(img_pos
.y
));
1080 fimc_write(ctx
, cfg
, EXYNOS_CIOCROFF
);
1085 static void fimc_dst_set_buf_seq(struct fimc_context
*ctx
, u32 buf_id
,
1086 enum drm_exynos_ipp_buf_type buf_type
)
1088 unsigned long flags
;
1092 DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id
, buf_type
);
1094 spin_lock_irqsave(&ctx
->lock
, flags
);
1096 cfg
= fimc_read(ctx
, EXYNOS_CIFCNTSEQ
);
1098 if (buf_type
== IPP_BUF_ENQUEUE
)
1099 cfg
|= (1 << buf_id
);
1101 cfg
&= ~(1 << buf_id
);
1103 fimc_write(ctx
, cfg
, EXYNOS_CIFCNTSEQ
);
1105 buf_num
= hweight32(cfg
);
1107 if (buf_type
== IPP_BUF_ENQUEUE
&& buf_num
>= FIMC_BUF_START
)
1108 fimc_mask_irq(ctx
, true);
1109 else if (buf_type
== IPP_BUF_DEQUEUE
&& buf_num
<= FIMC_BUF_STOP
)
1110 fimc_mask_irq(ctx
, false);
1112 spin_unlock_irqrestore(&ctx
->lock
, flags
);
1115 static int fimc_dst_set_addr(struct device
*dev
,
1116 struct drm_exynos_ipp_buf_info
*buf_info
, u32 buf_id
,
1117 enum drm_exynos_ipp_buf_type buf_type
)
1119 struct fimc_context
*ctx
= get_fimc_context(dev
);
1120 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
1121 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
1122 struct drm_exynos_ipp_property
*property
;
1123 struct drm_exynos_ipp_config
*config
;
1126 DRM_ERROR("failed to get c_node.\n");
1130 property
= &c_node
->property
;
1132 DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
1133 property
->prop_id
, buf_id
, buf_type
);
1135 if (buf_id
> FIMC_MAX_DST
) {
1136 dev_info(ippdrv
->dev
, "invalid buf_id %d.\n", buf_id
);
1140 /* address register set */
1142 case IPP_BUF_ENQUEUE
:
1143 config
= &property
->config
[EXYNOS_DRM_OPS_DST
];
1145 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_Y
],
1146 EXYNOS_CIOYSA(buf_id
));
1148 if (config
->fmt
== DRM_FORMAT_YVU420
) {
1149 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CR
],
1150 EXYNOS_CIOCBSA(buf_id
));
1151 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CB
],
1152 EXYNOS_CIOCRSA(buf_id
));
1154 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CB
],
1155 EXYNOS_CIOCBSA(buf_id
));
1156 fimc_write(ctx
, buf_info
->base
[EXYNOS_DRM_PLANAR_CR
],
1157 EXYNOS_CIOCRSA(buf_id
));
1160 case IPP_BUF_DEQUEUE
:
1161 fimc_write(ctx
, 0x0, EXYNOS_CIOYSA(buf_id
));
1162 fimc_write(ctx
, 0x0, EXYNOS_CIOCBSA(buf_id
));
1163 fimc_write(ctx
, 0x0, EXYNOS_CIOCRSA(buf_id
));
1170 fimc_dst_set_buf_seq(ctx
, buf_id
, buf_type
);
1175 static struct exynos_drm_ipp_ops fimc_dst_ops
= {
1176 .set_fmt
= fimc_dst_set_fmt
,
1177 .set_transf
= fimc_dst_set_transf
,
1178 .set_size
= fimc_dst_set_size
,
1179 .set_addr
= fimc_dst_set_addr
,
1182 static irqreturn_t
fimc_irq_handler(int irq
, void *dev_id
)
1184 struct fimc_context
*ctx
= dev_id
;
1185 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
1186 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
1187 struct drm_exynos_ipp_event_work
*event_work
=
1191 DRM_DEBUG_KMS("fimc id[%d]\n", ctx
->id
);
1193 fimc_clear_irq(ctx
);
1194 if (fimc_check_ovf(ctx
))
1197 if (!fimc_check_frame_end(ctx
))
1200 buf_id
= fimc_get_buf_id(ctx
);
1204 DRM_DEBUG_KMS("buf_id[%d]\n", buf_id
);
1206 fimc_dst_set_buf_seq(ctx
, buf_id
, IPP_BUF_DEQUEUE
);
1208 event_work
->ippdrv
= ippdrv
;
1209 event_work
->buf_id
[EXYNOS_DRM_OPS_DST
] = buf_id
;
1210 queue_work(ippdrv
->event_workq
, &event_work
->work
);
1215 static int fimc_init_prop_list(struct exynos_drm_ippdrv
*ippdrv
)
1217 struct drm_exynos_ipp_prop_list
*prop_list
= &ippdrv
->prop_list
;
1219 prop_list
->version
= 1;
1220 prop_list
->writeback
= 1;
1221 prop_list
->refresh_min
= FIMC_REFRESH_MIN
;
1222 prop_list
->refresh_max
= FIMC_REFRESH_MAX
;
1223 prop_list
->flip
= (1 << EXYNOS_DRM_FLIP_NONE
) |
1224 (1 << EXYNOS_DRM_FLIP_VERTICAL
) |
1225 (1 << EXYNOS_DRM_FLIP_HORIZONTAL
);
1226 prop_list
->degree
= (1 << EXYNOS_DRM_DEGREE_0
) |
1227 (1 << EXYNOS_DRM_DEGREE_90
) |
1228 (1 << EXYNOS_DRM_DEGREE_180
) |
1229 (1 << EXYNOS_DRM_DEGREE_270
);
1231 prop_list
->crop
= 1;
1232 prop_list
->crop_max
.hsize
= FIMC_CROP_MAX
;
1233 prop_list
->crop_max
.vsize
= FIMC_CROP_MAX
;
1234 prop_list
->crop_min
.hsize
= FIMC_CROP_MIN
;
1235 prop_list
->crop_min
.vsize
= FIMC_CROP_MIN
;
1236 prop_list
->scale
= 1;
1237 prop_list
->scale_max
.hsize
= FIMC_SCALE_MAX
;
1238 prop_list
->scale_max
.vsize
= FIMC_SCALE_MAX
;
1239 prop_list
->scale_min
.hsize
= FIMC_SCALE_MIN
;
1240 prop_list
->scale_min
.vsize
= FIMC_SCALE_MIN
;
1245 static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip
)
1248 case EXYNOS_DRM_FLIP_NONE
:
1249 case EXYNOS_DRM_FLIP_VERTICAL
:
1250 case EXYNOS_DRM_FLIP_HORIZONTAL
:
1251 case EXYNOS_DRM_FLIP_BOTH
:
1254 DRM_DEBUG_KMS("invalid flip\n");
1259 static int fimc_ippdrv_check_property(struct device
*dev
,
1260 struct drm_exynos_ipp_property
*property
)
1262 struct fimc_context
*ctx
= get_fimc_context(dev
);
1263 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
1264 struct drm_exynos_ipp_prop_list
*pp
= &ippdrv
->prop_list
;
1265 struct drm_exynos_ipp_config
*config
;
1266 struct drm_exynos_pos
*pos
;
1267 struct drm_exynos_sz
*sz
;
1271 for_each_ipp_ops(i
) {
1272 if ((i
== EXYNOS_DRM_OPS_SRC
) &&
1273 (property
->cmd
== IPP_CMD_WB
))
1276 config
= &property
->config
[i
];
1280 /* check for flip */
1281 if (!fimc_check_drm_flip(config
->flip
)) {
1282 DRM_ERROR("invalid flip.\n");
1286 /* check for degree */
1287 switch (config
->degree
) {
1288 case EXYNOS_DRM_DEGREE_90
:
1289 case EXYNOS_DRM_DEGREE_270
:
1292 case EXYNOS_DRM_DEGREE_0
:
1293 case EXYNOS_DRM_DEGREE_180
:
1297 DRM_ERROR("invalid degree.\n");
1301 /* check for buffer bound */
1302 if ((pos
->x
+ pos
->w
> sz
->hsize
) ||
1303 (pos
->y
+ pos
->h
> sz
->vsize
)) {
1304 DRM_ERROR("out of buf bound.\n");
1308 /* check for crop */
1309 if ((i
== EXYNOS_DRM_OPS_SRC
) && (pp
->crop
)) {
1311 if ((pos
->h
< pp
->crop_min
.hsize
) ||
1312 (sz
->vsize
> pp
->crop_max
.hsize
) ||
1313 (pos
->w
< pp
->crop_min
.vsize
) ||
1314 (sz
->hsize
> pp
->crop_max
.vsize
)) {
1315 DRM_ERROR("out of crop size.\n");
1319 if ((pos
->w
< pp
->crop_min
.hsize
) ||
1320 (sz
->hsize
> pp
->crop_max
.hsize
) ||
1321 (pos
->h
< pp
->crop_min
.vsize
) ||
1322 (sz
->vsize
> pp
->crop_max
.vsize
)) {
1323 DRM_ERROR("out of crop size.\n");
1329 /* check for scale */
1330 if ((i
== EXYNOS_DRM_OPS_DST
) && (pp
->scale
)) {
1332 if ((pos
->h
< pp
->scale_min
.hsize
) ||
1333 (sz
->vsize
> pp
->scale_max
.hsize
) ||
1334 (pos
->w
< pp
->scale_min
.vsize
) ||
1335 (sz
->hsize
> pp
->scale_max
.vsize
)) {
1336 DRM_ERROR("out of scale size.\n");
1340 if ((pos
->w
< pp
->scale_min
.hsize
) ||
1341 (sz
->hsize
> pp
->scale_max
.hsize
) ||
1342 (pos
->h
< pp
->scale_min
.vsize
) ||
1343 (sz
->vsize
> pp
->scale_max
.vsize
)) {
1344 DRM_ERROR("out of scale size.\n");
1354 for_each_ipp_ops(i
) {
1355 if ((i
== EXYNOS_DRM_OPS_SRC
) &&
1356 (property
->cmd
== IPP_CMD_WB
))
1359 config
= &property
->config
[i
];
1363 DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n",
1364 i
? "dst" : "src", config
->flip
, config
->degree
,
1365 pos
->x
, pos
->y
, pos
->w
, pos
->h
,
1366 sz
->hsize
, sz
->vsize
);
1372 static void fimc_clear_addr(struct fimc_context
*ctx
)
1376 for (i
= 0; i
< FIMC_MAX_SRC
; i
++) {
1377 fimc_write(ctx
, 0, EXYNOS_CIIYSA(i
));
1378 fimc_write(ctx
, 0, EXYNOS_CIICBSA(i
));
1379 fimc_write(ctx
, 0, EXYNOS_CIICRSA(i
));
1382 for (i
= 0; i
< FIMC_MAX_DST
; i
++) {
1383 fimc_write(ctx
, 0, EXYNOS_CIOYSA(i
));
1384 fimc_write(ctx
, 0, EXYNOS_CIOCBSA(i
));
1385 fimc_write(ctx
, 0, EXYNOS_CIOCRSA(i
));
1389 static int fimc_ippdrv_reset(struct device
*dev
)
1391 struct fimc_context
*ctx
= get_fimc_context(dev
);
1393 /* reset h/w block */
1396 /* reset scaler capability */
1397 memset(&ctx
->sc
, 0x0, sizeof(ctx
->sc
));
1399 fimc_clear_addr(ctx
);
1404 static int fimc_ippdrv_start(struct device
*dev
, enum drm_exynos_ipp_cmd cmd
)
1406 struct fimc_context
*ctx
= get_fimc_context(dev
);
1407 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
1408 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
1409 struct drm_exynos_ipp_property
*property
;
1410 struct drm_exynos_ipp_config
*config
;
1411 struct drm_exynos_pos img_pos
[EXYNOS_DRM_OPS_MAX
];
1412 struct drm_exynos_ipp_set_wb set_wb
;
1416 DRM_DEBUG_KMS("cmd[%d]\n", cmd
);
1419 DRM_ERROR("failed to get c_node.\n");
1423 property
= &c_node
->property
;
1425 fimc_mask_irq(ctx
, true);
1427 for_each_ipp_ops(i
) {
1428 config
= &property
->config
[i
];
1429 img_pos
[i
] = config
->pos
;
1432 ret
= fimc_set_prescaler(ctx
, &ctx
->sc
,
1433 &img_pos
[EXYNOS_DRM_OPS_SRC
],
1434 &img_pos
[EXYNOS_DRM_OPS_DST
]);
1436 dev_err(dev
, "failed to set precalser.\n");
1440 /* If set ture, we can save jpeg about screen */
1441 fimc_handle_jpeg(ctx
, false);
1442 fimc_set_scaler(ctx
, &ctx
->sc
);
1446 fimc_set_type_ctrl(ctx
, FIMC_WB_NONE
);
1447 fimc_handle_lastend(ctx
, false);
1450 cfg0
= fimc_read(ctx
, EXYNOS_MSCTRL
);
1451 cfg0
&= ~EXYNOS_MSCTRL_INPUT_MASK
;
1452 cfg0
|= EXYNOS_MSCTRL_INPUT_MEMORY
;
1453 fimc_write(ctx
, cfg0
, EXYNOS_MSCTRL
);
1456 fimc_set_type_ctrl(ctx
, FIMC_WB_A
);
1457 fimc_handle_lastend(ctx
, true);
1460 ret
= fimc_set_camblk_fimd0_wb(ctx
);
1462 dev_err(dev
, "camblk setup failed.\n");
1467 set_wb
.refresh
= property
->refresh_rate
;
1468 exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK
, (void *)&set_wb
);
1470 case IPP_CMD_OUTPUT
:
1473 dev_err(dev
, "invalid operations.\n");
1478 fimc_write(ctx
, 0x0, EXYNOS_CISTATUS
);
1480 cfg0
= fimc_read(ctx
, EXYNOS_CIIMGCPT
);
1481 cfg0
&= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC
;
1482 cfg0
|= EXYNOS_CIIMGCPT_IMGCPTEN_SC
;
1485 cfg1
= fimc_read(ctx
, EXYNOS_CISCCTRL
);
1486 cfg1
&= ~EXYNOS_CISCCTRL_SCAN_MASK
;
1487 cfg1
|= (EXYNOS_CISCCTRL_PROGRESSIVE
|
1488 EXYNOS_CISCCTRL_SCALERSTART
);
1490 fimc_write(ctx
, cfg1
, EXYNOS_CISCCTRL
);
1492 /* Enable image capture*/
1493 cfg0
|= EXYNOS_CIIMGCPT_IMGCPTEN
;
1494 fimc_write(ctx
, cfg0
, EXYNOS_CIIMGCPT
);
1496 /* Disable frame end irq */
1497 fimc_clear_bits(ctx
, EXYNOS_CIGCTRL
, EXYNOS_CIGCTRL_IRQ_END_DISABLE
);
1499 fimc_clear_bits(ctx
, EXYNOS_CIOCTRL
, EXYNOS_CIOCTRL_WEAVE_MASK
);
1501 if (cmd
== IPP_CMD_M2M
)
1502 fimc_set_bits(ctx
, EXYNOS_MSCTRL
, EXYNOS_MSCTRL_ENVID
);
1507 static void fimc_ippdrv_stop(struct device
*dev
, enum drm_exynos_ipp_cmd cmd
)
1509 struct fimc_context
*ctx
= get_fimc_context(dev
);
1510 struct drm_exynos_ipp_set_wb set_wb
= {0, 0};
1513 DRM_DEBUG_KMS("cmd[%d]\n", cmd
);
1518 cfg
= fimc_read(ctx
, EXYNOS_MSCTRL
);
1519 cfg
&= ~EXYNOS_MSCTRL_INPUT_MASK
;
1520 cfg
&= ~EXYNOS_MSCTRL_ENVID
;
1521 fimc_write(ctx
, cfg
, EXYNOS_MSCTRL
);
1524 exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK
, (void *)&set_wb
);
1526 case IPP_CMD_OUTPUT
:
1528 dev_err(dev
, "invalid operations.\n");
1532 fimc_mask_irq(ctx
, false);
1534 /* reset sequence */
1535 fimc_write(ctx
, 0x0, EXYNOS_CIFCNTSEQ
);
1537 /* Scaler disable */
1538 fimc_clear_bits(ctx
, EXYNOS_CISCCTRL
, EXYNOS_CISCCTRL_SCALERSTART
);
1540 /* Disable image capture */
1541 fimc_clear_bits(ctx
, EXYNOS_CIIMGCPT
,
1542 EXYNOS_CIIMGCPT_IMGCPTEN_SC
| EXYNOS_CIIMGCPT_IMGCPTEN
);
1544 /* Enable frame end irq */
1545 fimc_set_bits(ctx
, EXYNOS_CIGCTRL
, EXYNOS_CIGCTRL_IRQ_END_DISABLE
);
1548 static void fimc_put_clocks(struct fimc_context
*ctx
)
1552 for (i
= 0; i
< FIMC_CLKS_MAX
; i
++) {
1553 if (IS_ERR(ctx
->clocks
[i
]))
1555 clk_put(ctx
->clocks
[i
]);
1556 ctx
->clocks
[i
] = ERR_PTR(-EINVAL
);
1560 static int fimc_setup_clocks(struct fimc_context
*ctx
)
1562 struct device
*fimc_dev
= ctx
->ippdrv
.dev
;
1566 for (i
= 0; i
< FIMC_CLKS_MAX
; i
++)
1567 ctx
->clocks
[i
] = ERR_PTR(-EINVAL
);
1569 for (i
= 0; i
< FIMC_CLKS_MAX
; i
++) {
1570 if (i
== FIMC_CLK_WB_A
|| i
== FIMC_CLK_WB_B
)
1571 dev
= fimc_dev
->parent
;
1575 ctx
->clocks
[i
] = clk_get(dev
, fimc_clock_names
[i
]);
1576 if (IS_ERR(ctx
->clocks
[i
])) {
1577 if (i
>= FIMC_CLK_MUX
)
1579 ret
= PTR_ERR(ctx
->clocks
[i
]);
1580 dev_err(fimc_dev
, "failed to get clock: %s\n",
1581 fimc_clock_names
[i
]);
1586 /* Optional FIMC LCLK parent clock setting */
1587 if (!IS_ERR(ctx
->clocks
[FIMC_CLK_PARENT
])) {
1588 ret
= clk_set_parent(ctx
->clocks
[FIMC_CLK_MUX
],
1589 ctx
->clocks
[FIMC_CLK_PARENT
]);
1591 dev_err(fimc_dev
, "failed to set parent.\n");
1596 ret
= clk_set_rate(ctx
->clocks
[FIMC_CLK_LCLK
], ctx
->clk_frequency
);
1600 ret
= clk_prepare_enable(ctx
->clocks
[FIMC_CLK_LCLK
]);
1604 fimc_put_clocks(ctx
);
1608 static int fimc_parse_dt(struct fimc_context
*ctx
)
1610 struct device_node
*node
= ctx
->ippdrv
.dev
->of_node
;
1612 /* Handle only devices that support the LCD Writeback data path */
1613 if (!of_property_read_bool(node
, "samsung,lcd-wb"))
1616 if (of_property_read_u32(node
, "clock-frequency",
1617 &ctx
->clk_frequency
))
1618 ctx
->clk_frequency
= FIMC_DEFAULT_LCLK_FREQUENCY
;
1620 ctx
->id
= of_alias_get_id(node
, "fimc");
1623 dev_err(ctx
->ippdrv
.dev
, "failed to get node alias id.\n");
1630 static int fimc_probe(struct platform_device
*pdev
)
1632 struct device
*dev
= &pdev
->dev
;
1633 struct fimc_context
*ctx
;
1634 struct resource
*res
;
1635 struct exynos_drm_ippdrv
*ippdrv
;
1638 if (!dev
->of_node
) {
1639 dev_err(dev
, "device tree node not found.\n");
1643 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
1647 ctx
->ippdrv
.dev
= dev
;
1649 ret
= fimc_parse_dt(ctx
);
1653 ctx
->sysreg
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
1655 if (IS_ERR(ctx
->sysreg
)) {
1656 dev_err(dev
, "syscon regmap lookup failed.\n");
1657 return PTR_ERR(ctx
->sysreg
);
1660 /* resource memory */
1661 ctx
->regs_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1662 ctx
->regs
= devm_ioremap_resource(dev
, ctx
->regs_res
);
1663 if (IS_ERR(ctx
->regs
))
1664 return PTR_ERR(ctx
->regs
);
1667 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
1669 dev_err(dev
, "failed to request irq resource.\n");
1673 ctx
->irq
= res
->start
;
1674 ret
= devm_request_threaded_irq(dev
, ctx
->irq
, NULL
, fimc_irq_handler
,
1675 IRQF_ONESHOT
, "drm_fimc", ctx
);
1677 dev_err(dev
, "failed to request irq.\n");
1681 ret
= fimc_setup_clocks(ctx
);
1685 ippdrv
= &ctx
->ippdrv
;
1686 ippdrv
->ops
[EXYNOS_DRM_OPS_SRC
] = &fimc_src_ops
;
1687 ippdrv
->ops
[EXYNOS_DRM_OPS_DST
] = &fimc_dst_ops
;
1688 ippdrv
->check_property
= fimc_ippdrv_check_property
;
1689 ippdrv
->reset
= fimc_ippdrv_reset
;
1690 ippdrv
->start
= fimc_ippdrv_start
;
1691 ippdrv
->stop
= fimc_ippdrv_stop
;
1692 ret
= fimc_init_prop_list(ippdrv
);
1694 dev_err(dev
, "failed to init property list.\n");
1698 DRM_DEBUG_KMS("id[%d]ippdrv[%p]\n", ctx
->id
, ippdrv
);
1700 spin_lock_init(&ctx
->lock
);
1701 platform_set_drvdata(pdev
, ctx
);
1703 pm_runtime_enable(dev
);
1705 ret
= exynos_drm_ippdrv_register(ippdrv
);
1707 dev_err(dev
, "failed to register drm fimc device.\n");
1711 dev_info(dev
, "drm fimc registered successfully.\n");
1716 pm_runtime_disable(dev
);
1718 fimc_put_clocks(ctx
);
1723 static int fimc_remove(struct platform_device
*pdev
)
1725 struct device
*dev
= &pdev
->dev
;
1726 struct fimc_context
*ctx
= get_fimc_context(dev
);
1727 struct exynos_drm_ippdrv
*ippdrv
= &ctx
->ippdrv
;
1729 exynos_drm_ippdrv_unregister(ippdrv
);
1731 fimc_put_clocks(ctx
);
1732 pm_runtime_set_suspended(dev
);
1733 pm_runtime_disable(dev
);
1739 static int fimc_clk_ctrl(struct fimc_context
*ctx
, bool enable
)
1741 DRM_DEBUG_KMS("enable[%d]\n", enable
);
1744 clk_prepare_enable(ctx
->clocks
[FIMC_CLK_GATE
]);
1745 clk_prepare_enable(ctx
->clocks
[FIMC_CLK_WB_A
]);
1746 ctx
->suspended
= false;
1748 clk_disable_unprepare(ctx
->clocks
[FIMC_CLK_GATE
]);
1749 clk_disable_unprepare(ctx
->clocks
[FIMC_CLK_WB_A
]);
1750 ctx
->suspended
= true;
1756 static int fimc_runtime_suspend(struct device
*dev
)
1758 struct fimc_context
*ctx
= get_fimc_context(dev
);
1760 DRM_DEBUG_KMS("id[%d]\n", ctx
->id
);
1762 return fimc_clk_ctrl(ctx
, false);
1765 static int fimc_runtime_resume(struct device
*dev
)
1767 struct fimc_context
*ctx
= get_fimc_context(dev
);
1769 DRM_DEBUG_KMS("id[%d]\n", ctx
->id
);
1771 return fimc_clk_ctrl(ctx
, true);
1775 static const struct dev_pm_ops fimc_pm_ops
= {
1776 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
1777 pm_runtime_force_resume
)
1778 SET_RUNTIME_PM_OPS(fimc_runtime_suspend
, fimc_runtime_resume
, NULL
)
1781 static const struct of_device_id fimc_of_match
[] = {
1782 { .compatible
= "samsung,exynos4210-fimc" },
1783 { .compatible
= "samsung,exynos4212-fimc" },
1786 MODULE_DEVICE_TABLE(of
, fimc_of_match
);
1788 struct platform_driver fimc_driver
= {
1789 .probe
= fimc_probe
,
1790 .remove
= fimc_remove
,
1792 .of_match_table
= fimc_of_match
,
1793 .name
= "exynos-drm-fimc",
1794 .owner
= THIS_MODULE
,