blob: 2cce97d42ece94eff705e95285fc8ffc27112967 [file] [log] [blame]
Eunchul Kim16102ed2012-12-14 17:58:55 +09001/*
2 * Copyright (C) 2012 Samsung Electronics Co.Ltd
3 * Authors:
4 * Eunchul Kim <chulspro.kim@samsung.com>
5 * Jinyoung Jeon <jy0.jeon@samsung.com>
6 * Sangmin Lee <lsmin.lee@samsung.com>
7 *
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.
12 *
13 */
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/pm_runtime.h>
19#include <plat/map-base.h>
20
21#include <drm/drmP.h>
22#include <drm/exynos_drm.h>
23#include "regs-fimc.h"
24#include "exynos_drm_ipp.h"
25#include "exynos_drm_fimc.h"
26
27/*
Eunchul Kim6fe891f2012-12-22 17:49:26 +090028 * FIMC stands for Fully Interactive Mobile Camera and
Eunchul Kim16102ed2012-12-14 17:58:55 +090029 * supports image scaler/rotator and input/output DMA operations.
30 * input DMA reads image data from the memory.
31 * output DMA writes image data to memory.
32 * FIMC supports image rotation and image effect functions.
33 *
34 * M2M operation : supports crop/scale/rotation/csc so on.
35 * Memory ----> FIMC H/W ----> Memory.
36 * Writeback operation : supports cloned screen with FIMD.
37 * FIMD ----> FIMC H/W ----> Memory.
38 * Output operation : supports direct display using local path.
39 * Memory ----> FIMC H/W ----> FIMD.
40 */
41
42/*
43 * TODO
44 * 1. check suspend/resume api if needed.
45 * 2. need to check use case platform_device_id.
46 * 3. check src/dst size with, height.
47 * 4. added check_prepare api for right register.
48 * 5. need to add supported list in prop_list.
49 * 6. check prescaler/scaler optimization.
50 */
51
52#define FIMC_MAX_DEVS 4
53#define FIMC_MAX_SRC 2
54#define FIMC_MAX_DST 32
55#define FIMC_SHFACTOR 10
56#define FIMC_BUF_STOP 1
57#define FIMC_BUF_START 2
58#define FIMC_REG_SZ 32
59#define FIMC_WIDTH_ITU_709 1280
60#define FIMC_REFRESH_MAX 60
61#define FIMC_REFRESH_MIN 12
62#define FIMC_CROP_MAX 8192
63#define FIMC_CROP_MIN 32
64#define FIMC_SCALE_MAX 4224
65#define FIMC_SCALE_MIN 32
66
67#define get_fimc_context(dev) platform_get_drvdata(to_platform_device(dev))
68#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
69 struct fimc_context, ippdrv);
70#define fimc_read(offset) readl(ctx->regs + (offset))
71#define fimc_write(cfg, offset) writel(cfg, ctx->regs + (offset))
72
73enum fimc_wb {
74 FIMC_WB_NONE,
75 FIMC_WB_A,
76 FIMC_WB_B,
77};
78
Sylwester Nawrockie5f86832013-04-23 13:34:37 +020079enum {
80 FIMC_CLK_LCLK,
81 FIMC_CLK_GATE,
82 FIMC_CLK_WB_A,
83 FIMC_CLK_WB_B,
84 FIMC_CLK_MUX,
85 FIMC_CLK_PARENT,
86 FIMC_CLKS_MAX
87};
88
89static const char * const fimc_clock_names[] = {
90 [FIMC_CLK_LCLK] = "sclk_fimc",
91 [FIMC_CLK_GATE] = "fimc",
92 [FIMC_CLK_WB_A] = "pxl_async0",
93 [FIMC_CLK_WB_B] = "pxl_async1",
94 [FIMC_CLK_MUX] = "mux",
95 [FIMC_CLK_PARENT] = "parent",
96};
97
98#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
99
Eunchul Kim16102ed2012-12-14 17:58:55 +0900100/*
101 * A structure of scaler.
102 *
103 * @range: narrow, wide.
104 * @bypass: unused scaler path.
105 * @up_h: horizontal scale up.
106 * @up_v: vertical scale up.
107 * @hratio: horizontal ratio.
108 * @vratio: vertical ratio.
109 */
110struct fimc_scaler {
111 bool range;
112 bool bypass;
113 bool up_h;
114 bool up_v;
115 u32 hratio;
116 u32 vratio;
117};
118
119/*
120 * A structure of scaler capability.
121 *
122 * find user manual table 43-1.
123 * @in_hori: scaler input horizontal size.
124 * @bypass: scaler bypass mode.
125 * @dst_h_wo_rot: target horizontal size without output rotation.
126 * @dst_h_rot: target horizontal size with output rotation.
127 * @rl_w_wo_rot: real width without input rotation.
128 * @rl_h_rot: real height without output rotation.
129 */
130struct fimc_capability {
131 /* scaler */
132 u32 in_hori;
133 u32 bypass;
134 /* output rotator */
135 u32 dst_h_wo_rot;
136 u32 dst_h_rot;
137 /* input rotator */
138 u32 rl_w_wo_rot;
139 u32 rl_h_rot;
140};
141
142/*
143 * A structure of fimc driver data.
144 *
145 * @parent_clk: name of parent clock.
146 */
147struct fimc_driverdata {
148 char *parent_clk;
149};
150
151/*
152 * A structure of fimc context.
153 *
154 * @ippdrv: prepare initialization using ippdrv.
155 * @regs_res: register resources.
156 * @regs: memory mapped io registers.
157 * @lock: locking of operations.
Sylwester Nawrockie5f86832013-04-23 13:34:37 +0200158 * @clocks: fimc clocks.
159 * @clk_frequency: LCLK clock frequency.
Eunchul Kim16102ed2012-12-14 17:58:55 +0900160 * @sc: scaler infomations.
Eunchul Kim16102ed2012-12-14 17:58:55 +0900161 * @pol: porarity of writeback.
162 * @id: fimc id.
163 * @irq: irq number.
164 * @suspended: qos operations.
165 */
166struct fimc_context {
167 struct exynos_drm_ippdrv ippdrv;
168 struct resource *regs_res;
169 void __iomem *regs;
170 struct mutex lock;
Sylwester Nawrockie5f86832013-04-23 13:34:37 +0200171 struct clk *clocks[FIMC_CLKS_MAX];
172 u32 clk_frequency;
Eunchul Kim16102ed2012-12-14 17:58:55 +0900173 struct fimc_scaler sc;
174 struct fimc_driverdata *ddata;
175 struct exynos_drm_ipp_pol pol;
176 int id;
177 int irq;
178 bool suspended;
179};
180
JoongMock Shinb5c0b552012-12-22 17:49:27 +0900181static void fimc_sw_reset(struct fimc_context *ctx)
Eunchul Kim16102ed2012-12-14 17:58:55 +0900182{
183 u32 cfg;
184
JoongMock Shinb5c0b552012-12-22 17:49:27 +0900185 DRM_DEBUG_KMS("%s\n", __func__);
Eunchul Kim16102ed2012-12-14 17:58:55 +0900186
Jinyoung Jeone39d5ce2012-12-22 17:49:28 +0900187 /* stop dma operation */
188 cfg = fimc_read(EXYNOS_CISTATUS);
189 if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) {
190 cfg = fimc_read(EXYNOS_MSCTRL);
191 cfg &= ~EXYNOS_MSCTRL_ENVID;
192 fimc_write(cfg, EXYNOS_MSCTRL);
193 }
Eunchul Kim16102ed2012-12-14 17:58:55 +0900194
195 cfg = fimc_read(EXYNOS_CISRCFMT);
196 cfg |= EXYNOS_CISRCFMT_ITU601_8BIT;
Eunchul Kim16102ed2012-12-14 17:58:55 +0900197 fimc_write(cfg, EXYNOS_CISRCFMT);
198
Jinyoung Jeone39d5ce2012-12-22 17:49:28 +0900199 /* disable image capture */
200 cfg = fimc_read(EXYNOS_CIIMGCPT);
201 cfg &= ~(EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);
202 fimc_write(cfg, EXYNOS_CIIMGCPT);
203
Eunchul Kim16102ed2012-12-14 17:58:55 +0900204 /* s/w reset */
205 cfg = fimc_read(EXYNOS_CIGCTRL);
206 cfg |= (EXYNOS_CIGCTRL_SWRST);
207 fimc_write(cfg, EXYNOS_CIGCTRL);
208
209 /* s/w reset complete */
210 cfg = fimc_read(EXYNOS_CIGCTRL);
211 cfg &= ~EXYNOS_CIGCTRL_SWRST;
212 fimc_write(cfg, EXYNOS_CIGCTRL);
213
214 /* reset sequence */
215 fimc_write(0x0, EXYNOS_CIFCNTSEQ);
216}
217
218static void fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
219{
220 u32 camblk_cfg;
221
222 DRM_DEBUG_KMS("%s\n", __func__);
223
224 camblk_cfg = readl(SYSREG_CAMERA_BLK);
225 camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK);
226 camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT);
227
228 writel(camblk_cfg, SYSREG_CAMERA_BLK);
229}
230
231static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
232{
233 u32 cfg;
234
235 DRM_DEBUG_KMS("%s:wb[%d]\n", __func__, wb);
236
237 cfg = fimc_read(EXYNOS_CIGCTRL);
238 cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |
239 EXYNOS_CIGCTRL_SELCAM_ITU_MASK |
240 EXYNOS_CIGCTRL_SELCAM_MIPI_MASK |
241 EXYNOS_CIGCTRL_SELCAM_FIMC_MASK |
242 EXYNOS_CIGCTRL_SELWB_CAMIF_MASK |
243 EXYNOS_CIGCTRL_SELWRITEBACK_MASK);
244
245 switch (wb) {
246 case FIMC_WB_A:
247 cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_A |
248 EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK);
249 break;
250 case FIMC_WB_B:
251 cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_B |
252 EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK);
253 break;
254 case FIMC_WB_NONE:
255 default:
256 cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A |
257 EXYNOS_CIGCTRL_SELWRITEBACK_A |
258 EXYNOS_CIGCTRL_SELCAM_MIPI_A |
259 EXYNOS_CIGCTRL_SELCAM_FIMC_ITU);
260 break;
261 }
262
263 fimc_write(cfg, EXYNOS_CIGCTRL);
264}
265
266static void fimc_set_polarity(struct fimc_context *ctx,
267 struct exynos_drm_ipp_pol *pol)
268{
269 u32 cfg;
270
271 DRM_DEBUG_KMS("%s:inv_pclk[%d]inv_vsync[%d]\n",
272 __func__, pol->inv_pclk, pol->inv_vsync);
273 DRM_DEBUG_KMS("%s:inv_href[%d]inv_hsync[%d]\n",
274 __func__, pol->inv_href, pol->inv_hsync);
275
276 cfg = fimc_read(EXYNOS_CIGCTRL);
277 cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC |
278 EXYNOS_CIGCTRL_INVPOLHREF | EXYNOS_CIGCTRL_INVPOLHSYNC);
279
280 if (pol->inv_pclk)
281 cfg |= EXYNOS_CIGCTRL_INVPOLPCLK;
282 if (pol->inv_vsync)
283 cfg |= EXYNOS_CIGCTRL_INVPOLVSYNC;
284 if (pol->inv_href)
285 cfg |= EXYNOS_CIGCTRL_INVPOLHREF;
286 if (pol->inv_hsync)
287 cfg |= EXYNOS_CIGCTRL_INVPOLHSYNC;
288
289 fimc_write(cfg, EXYNOS_CIGCTRL);
290}
291
292static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable)
293{
294 u32 cfg;
295
296 DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
297
298 cfg = fimc_read(EXYNOS_CIGCTRL);
299 if (enable)
300 cfg |= EXYNOS_CIGCTRL_CAM_JPEG;
301 else
302 cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG;
303
304 fimc_write(cfg, EXYNOS_CIGCTRL);
305}
306
307static void fimc_handle_irq(struct fimc_context *ctx, bool enable,
308 bool overflow, bool level)
309{
310 u32 cfg;
311
312 DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__,
313 enable, overflow, level);
314
315 cfg = fimc_read(EXYNOS_CIGCTRL);
316 if (enable) {
317 cfg &= ~(EXYNOS_CIGCTRL_IRQ_OVFEN | EXYNOS_CIGCTRL_IRQ_LEVEL);
318 cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE;
319 if (overflow)
320 cfg |= EXYNOS_CIGCTRL_IRQ_OVFEN;
321 if (level)
322 cfg |= EXYNOS_CIGCTRL_IRQ_LEVEL;
323 } else
324 cfg &= ~(EXYNOS_CIGCTRL_IRQ_OVFEN | EXYNOS_CIGCTRL_IRQ_ENABLE);
325
326 fimc_write(cfg, EXYNOS_CIGCTRL);
327}
328
329static void fimc_clear_irq(struct fimc_context *ctx)
330{
331 u32 cfg;
332
333 DRM_DEBUG_KMS("%s\n", __func__);
334
335 cfg = fimc_read(EXYNOS_CIGCTRL);
336 cfg |= EXYNOS_CIGCTRL_IRQ_CLR;
337 fimc_write(cfg, EXYNOS_CIGCTRL);
338}
339
340static bool fimc_check_ovf(struct fimc_context *ctx)
341{
342 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
343 u32 cfg, status, flag;
344
345 status = fimc_read(EXYNOS_CISTATUS);
346 flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB |
347 EXYNOS_CISTATUS_OVFICR;
348
349 DRM_DEBUG_KMS("%s:flag[0x%x]\n", __func__, flag);
350
351 if (status & flag) {
352 cfg = fimc_read(EXYNOS_CIWDOFST);
353 cfg |= (EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
354 EXYNOS_CIWDOFST_CLROVFICR);
355
356 fimc_write(cfg, EXYNOS_CIWDOFST);
357
358 cfg = fimc_read(EXYNOS_CIWDOFST);
359 cfg &= ~(EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
360 EXYNOS_CIWDOFST_CLROVFICR);
361
362 fimc_write(cfg, EXYNOS_CIWDOFST);
363
364 dev_err(ippdrv->dev, "occured overflow at %d, status 0x%x.\n",
365 ctx->id, status);
366 return true;
367 }
368
369 return false;
370}
371
372static bool fimc_check_frame_end(struct fimc_context *ctx)
373{
374 u32 cfg;
375
376 cfg = fimc_read(EXYNOS_CISTATUS);
377
378 DRM_DEBUG_KMS("%s:cfg[0x%x]\n", __func__, cfg);
379
380 if (!(cfg & EXYNOS_CISTATUS_FRAMEEND))
381 return false;
382
383 cfg &= ~(EXYNOS_CISTATUS_FRAMEEND);
384 fimc_write(cfg, EXYNOS_CISTATUS);
385
386 return true;
387}
388
389static int fimc_get_buf_id(struct fimc_context *ctx)
390{
391 u32 cfg;
392 int frame_cnt, buf_id;
393
394 DRM_DEBUG_KMS("%s\n", __func__);
395
396 cfg = fimc_read(EXYNOS_CISTATUS2);
397 frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg);
398
399 if (frame_cnt == 0)
400 frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg);
401
402 DRM_DEBUG_KMS("%s:present[%d]before[%d]\n", __func__,
403 EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg),
404 EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg));
405
406 if (frame_cnt == 0) {
407 DRM_ERROR("failed to get frame count.\n");
408 return -EIO;
409 }
410
411 buf_id = frame_cnt - 1;
412 DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
413
414 return buf_id;
415}
416
417static void fimc_handle_lastend(struct fimc_context *ctx, bool enable)
418{
419 u32 cfg;
420
421 DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
422
423 cfg = fimc_read(EXYNOS_CIOCTRL);
424 if (enable)
425 cfg |= EXYNOS_CIOCTRL_LASTENDEN;
426 else
427 cfg &= ~EXYNOS_CIOCTRL_LASTENDEN;
428
429 fimc_write(cfg, EXYNOS_CIOCTRL);
430}
431
432
433static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
434{
435 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
436 u32 cfg;
437
438 DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
439
440 /* RGB */
441 cfg = fimc_read(EXYNOS_CISCCTRL);
442 cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK;
443
444 switch (fmt) {
445 case DRM_FORMAT_RGB565:
446 cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565;
447 fimc_write(cfg, EXYNOS_CISCCTRL);
448 return 0;
449 case DRM_FORMAT_RGB888:
450 case DRM_FORMAT_XRGB8888:
451 cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888;
452 fimc_write(cfg, EXYNOS_CISCCTRL);
453 return 0;
454 default:
455 /* bypass */
456 break;
457 }
458
459 /* YUV */
460 cfg = fimc_read(EXYNOS_MSCTRL);
461 cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK |
462 EXYNOS_MSCTRL_C_INT_IN_2PLANE |
463 EXYNOS_MSCTRL_ORDER422_YCBYCR);
464
465 switch (fmt) {
466 case DRM_FORMAT_YUYV:
467 cfg |= EXYNOS_MSCTRL_ORDER422_YCBYCR;
468 break;
469 case DRM_FORMAT_YVYU:
470 cfg |= EXYNOS_MSCTRL_ORDER422_YCRYCB;
471 break;
472 case DRM_FORMAT_UYVY:
473 cfg |= EXYNOS_MSCTRL_ORDER422_CBYCRY;
474 break;
475 case DRM_FORMAT_VYUY:
476 case DRM_FORMAT_YUV444:
477 cfg |= EXYNOS_MSCTRL_ORDER422_CRYCBY;
478 break;
479 case DRM_FORMAT_NV21:
480 case DRM_FORMAT_NV61:
481 cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB |
482 EXYNOS_MSCTRL_C_INT_IN_2PLANE);
483 break;
484 case DRM_FORMAT_YUV422:
485 case DRM_FORMAT_YUV420:
486 case DRM_FORMAT_YVU420:
487 cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE;
488 break;
489 case DRM_FORMAT_NV12:
490 case DRM_FORMAT_NV12MT:
491 case DRM_FORMAT_NV16:
492 cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |
493 EXYNOS_MSCTRL_C_INT_IN_2PLANE);
494 break;
495 default:
496 dev_err(ippdrv->dev, "inavlid source yuv order 0x%x.\n", fmt);
497 return -EINVAL;
498 }
499
500 fimc_write(cfg, EXYNOS_MSCTRL);
501
502 return 0;
503}
504
505static int fimc_src_set_fmt(struct device *dev, u32 fmt)
506{
507 struct fimc_context *ctx = get_fimc_context(dev);
508 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
509 u32 cfg;
510
511 DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
512
513 cfg = fimc_read(EXYNOS_MSCTRL);
514 cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB;
515
516 switch (fmt) {
517 case DRM_FORMAT_RGB565:
518 case DRM_FORMAT_RGB888:
519 case DRM_FORMAT_XRGB8888:
520 cfg |= EXYNOS_MSCTRL_INFORMAT_RGB;
521 break;
522 case DRM_FORMAT_YUV444:
523 cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
524 break;
525 case DRM_FORMAT_YUYV:
526 case DRM_FORMAT_YVYU:
527 case DRM_FORMAT_UYVY:
528 case DRM_FORMAT_VYUY:
529 cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE;
530 break;
531 case DRM_FORMAT_NV16:
532 case DRM_FORMAT_NV61:
533 case DRM_FORMAT_YUV422:
534 cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422;
535 break;
536 case DRM_FORMAT_YUV420:
537 case DRM_FORMAT_YVU420:
538 case DRM_FORMAT_NV12:
539 case DRM_FORMAT_NV21:
540 case DRM_FORMAT_NV12MT:
541 cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
542 break;
543 default:
544 dev_err(ippdrv->dev, "inavlid source format 0x%x.\n", fmt);
545 return -EINVAL;
546 }
547
548 fimc_write(cfg, EXYNOS_MSCTRL);
549
550 cfg = fimc_read(EXYNOS_CIDMAPARAM);
551 cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;
552
553 if (fmt == DRM_FORMAT_NV12MT)
554 cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;
555 else
556 cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
557
558 fimc_write(cfg, EXYNOS_CIDMAPARAM);
559
560 return fimc_src_set_fmt_order(ctx, fmt);
561}
562
563static int fimc_src_set_transf(struct device *dev,
564 enum drm_exynos_degree degree,
565 enum drm_exynos_flip flip, bool *swap)
566{
567 struct fimc_context *ctx = get_fimc_context(dev);
568 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
569 u32 cfg1, cfg2;
570
571 DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
572 degree, flip);
573
574 cfg1 = fimc_read(EXYNOS_MSCTRL);
575 cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |
576 EXYNOS_MSCTRL_FLIP_Y_MIRROR);
577
578 cfg2 = fimc_read(EXYNOS_CITRGFMT);
579 cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
580
581 switch (degree) {
582 case EXYNOS_DRM_DEGREE_0:
583 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
584 cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
585 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
586 cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
587 break;
588 case EXYNOS_DRM_DEGREE_90:
589 cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
590 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
591 cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
592 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
593 cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
594 break;
595 case EXYNOS_DRM_DEGREE_180:
596 cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
597 EXYNOS_MSCTRL_FLIP_Y_MIRROR);
598 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
599 cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
600 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
601 cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
602 break;
603 case EXYNOS_DRM_DEGREE_270:
604 cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
605 EXYNOS_MSCTRL_FLIP_Y_MIRROR);
606 cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
607 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
608 cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
609 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
610 cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
611 break;
612 default:
613 dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
614 return -EINVAL;
615 }
616
617 fimc_write(cfg1, EXYNOS_MSCTRL);
618 fimc_write(cfg2, EXYNOS_CITRGFMT);
619 *swap = (cfg2 & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) ? 1 : 0;
620
621 return 0;
622}
623
624static int fimc_set_window(struct fimc_context *ctx,
625 struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
626{
627 u32 cfg, h1, h2, v1, v2;
628
629 /* cropped image */
630 h1 = pos->x;
631 h2 = sz->hsize - pos->w - pos->x;
632 v1 = pos->y;
633 v2 = sz->vsize - pos->h - pos->y;
634
635 DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
636 __func__, pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
637 DRM_DEBUG_KMS("%s:h1[%d]h2[%d]v1[%d]v2[%d]\n", __func__,
638 h1, h2, v1, v2);
639
640 /*
641 * set window offset 1, 2 size
642 * check figure 43-21 in user manual
643 */
644 cfg = fimc_read(EXYNOS_CIWDOFST);
645 cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK |
646 EXYNOS_CIWDOFST_WINVEROFST_MASK);
647 cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) |
648 EXYNOS_CIWDOFST_WINVEROFST(v1));
649 cfg |= EXYNOS_CIWDOFST_WINOFSEN;
650 fimc_write(cfg, EXYNOS_CIWDOFST);
651
652 cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) |
653 EXYNOS_CIWDOFST2_WINVEROFST2(v2));
654 fimc_write(cfg, EXYNOS_CIWDOFST2);
655
656 return 0;
657}
658
659static int fimc_src_set_size(struct device *dev, int swap,
660 struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
661{
662 struct fimc_context *ctx = get_fimc_context(dev);
663 struct drm_exynos_pos img_pos = *pos;
664 struct drm_exynos_sz img_sz = *sz;
665 u32 cfg;
666
667 DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
668 __func__, swap, sz->hsize, sz->vsize);
669
670 /* original size */
671 cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) |
672 EXYNOS_ORGISIZE_VERTICAL(img_sz.vsize));
673
674 fimc_write(cfg, EXYNOS_ORGISIZE);
675
676 DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n", __func__,
677 pos->x, pos->y, pos->w, pos->h);
678
679 if (swap) {
680 img_pos.w = pos->h;
681 img_pos.h = pos->w;
682 img_sz.hsize = sz->vsize;
683 img_sz.vsize = sz->hsize;
684 }
685
686 /* set input DMA image size */
687 cfg = fimc_read(EXYNOS_CIREAL_ISIZE);
688 cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK |
689 EXYNOS_CIREAL_ISIZE_WIDTH_MASK);
690 cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos.w) |
691 EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos.h));
692 fimc_write(cfg, EXYNOS_CIREAL_ISIZE);
693
694 /*
695 * set input FIFO image size
696 * for now, we support only ITU601 8 bit mode
697 */
698 cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |
699 EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz.hsize) |
700 EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz.vsize));
701 fimc_write(cfg, EXYNOS_CISRCFMT);
702
703 /* offset Y(RGB), Cb, Cr */
704 cfg = (EXYNOS_CIIYOFF_HORIZONTAL(img_pos.x) |
705 EXYNOS_CIIYOFF_VERTICAL(img_pos.y));
706 fimc_write(cfg, EXYNOS_CIIYOFF);
707 cfg = (EXYNOS_CIICBOFF_HORIZONTAL(img_pos.x) |
708 EXYNOS_CIICBOFF_VERTICAL(img_pos.y));
709 fimc_write(cfg, EXYNOS_CIICBOFF);
710 cfg = (EXYNOS_CIICROFF_HORIZONTAL(img_pos.x) |
711 EXYNOS_CIICROFF_VERTICAL(img_pos.y));
712 fimc_write(cfg, EXYNOS_CIICROFF);
713
714 return fimc_set_window(ctx, &img_pos, &img_sz);
715}
716
717static int fimc_src_set_addr(struct device *dev,
718 struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
719 enum drm_exynos_ipp_buf_type buf_type)
720{
721 struct fimc_context *ctx = get_fimc_context(dev);
722 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
Eunchul Kim7259c3d2012-12-22 17:49:22 +0900723 struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
Eunchul Kim16102ed2012-12-14 17:58:55 +0900724 struct drm_exynos_ipp_property *property;
725 struct drm_exynos_ipp_config *config;
726
727 if (!c_node) {
728 DRM_ERROR("failed to get c_node.\n");
729 return -EINVAL;
730 }
731
732 property = &c_node->property;
Eunchul Kim16102ed2012-12-14 17:58:55 +0900733
734 DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
735 property->prop_id, buf_id, buf_type);
736
737 if (buf_id > FIMC_MAX_SRC) {
738 dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
739 return -ENOMEM;
740 }
741
742 /* address register set */
743 switch (buf_type) {
744 case IPP_BUF_ENQUEUE:
745 config = &property->config[EXYNOS_DRM_OPS_SRC];
746 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],
747 EXYNOS_CIIYSA(buf_id));
748
749 if (config->fmt == DRM_FORMAT_YVU420) {
750 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
751 EXYNOS_CIICBSA(buf_id));
752 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
753 EXYNOS_CIICRSA(buf_id));
754 } else {
755 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
756 EXYNOS_CIICBSA(buf_id));
757 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
758 EXYNOS_CIICRSA(buf_id));
759 }
760 break;
761 case IPP_BUF_DEQUEUE:
762 fimc_write(0x0, EXYNOS_CIIYSA(buf_id));
763 fimc_write(0x0, EXYNOS_CIICBSA(buf_id));
764 fimc_write(0x0, EXYNOS_CIICRSA(buf_id));
765 break;
766 default:
767 /* bypass */
768 break;
769 }
770
771 return 0;
772}
773
774static struct exynos_drm_ipp_ops fimc_src_ops = {
775 .set_fmt = fimc_src_set_fmt,
776 .set_transf = fimc_src_set_transf,
777 .set_size = fimc_src_set_size,
778 .set_addr = fimc_src_set_addr,
779};
780
781static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
782{
783 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
784 u32 cfg;
785
786 DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
787
788 /* RGB */
789 cfg = fimc_read(EXYNOS_CISCCTRL);
790 cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK;
791
792 switch (fmt) {
793 case DRM_FORMAT_RGB565:
794 cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565;
795 fimc_write(cfg, EXYNOS_CISCCTRL);
796 return 0;
797 case DRM_FORMAT_RGB888:
798 cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888;
799 fimc_write(cfg, EXYNOS_CISCCTRL);
800 return 0;
801 case DRM_FORMAT_XRGB8888:
802 cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 |
803 EXYNOS_CISCCTRL_EXTRGB_EXTENSION);
804 fimc_write(cfg, EXYNOS_CISCCTRL);
805 break;
806 default:
807 /* bypass */
808 break;
809 }
810
811 /* YUV */
812 cfg = fimc_read(EXYNOS_CIOCTRL);
813 cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK |
814 EXYNOS_CIOCTRL_ORDER422_MASK |
815 EXYNOS_CIOCTRL_YCBCR_PLANE_MASK);
816
817 switch (fmt) {
818 case DRM_FORMAT_XRGB8888:
819 cfg |= EXYNOS_CIOCTRL_ALPHA_OUT;
820 break;
821 case DRM_FORMAT_YUYV:
822 cfg |= EXYNOS_CIOCTRL_ORDER422_YCBYCR;
823 break;
824 case DRM_FORMAT_YVYU:
825 cfg |= EXYNOS_CIOCTRL_ORDER422_YCRYCB;
826 break;
827 case DRM_FORMAT_UYVY:
828 cfg |= EXYNOS_CIOCTRL_ORDER422_CBYCRY;
829 break;
830 case DRM_FORMAT_VYUY:
831 cfg |= EXYNOS_CIOCTRL_ORDER422_CRYCBY;
832 break;
833 case DRM_FORMAT_NV21:
834 case DRM_FORMAT_NV61:
835 cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB;
836 cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
837 break;
838 case DRM_FORMAT_YUV422:
839 case DRM_FORMAT_YUV420:
840 case DRM_FORMAT_YVU420:
841 cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE;
842 break;
843 case DRM_FORMAT_NV12:
844 case DRM_FORMAT_NV12MT:
845 case DRM_FORMAT_NV16:
846 cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;
847 cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
848 break;
849 default:
850 dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
851 return -EINVAL;
852 }
853
854 fimc_write(cfg, EXYNOS_CIOCTRL);
855
856 return 0;
857}
858
859static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
860{
861 struct fimc_context *ctx = get_fimc_context(dev);
862 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
863 u32 cfg;
864
865 DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
866
867 cfg = fimc_read(EXYNOS_CIEXTEN);
868
869 if (fmt == DRM_FORMAT_AYUV) {
870 cfg |= EXYNOS_CIEXTEN_YUV444_OUT;
871 fimc_write(cfg, EXYNOS_CIEXTEN);
872 } else {
873 cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT;
874 fimc_write(cfg, EXYNOS_CIEXTEN);
875
876 cfg = fimc_read(EXYNOS_CITRGFMT);
877 cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK;
878
879 switch (fmt) {
880 case DRM_FORMAT_RGB565:
881 case DRM_FORMAT_RGB888:
882 case DRM_FORMAT_XRGB8888:
883 cfg |= EXYNOS_CITRGFMT_OUTFORMAT_RGB;
884 break;
885 case DRM_FORMAT_YUYV:
886 case DRM_FORMAT_YVYU:
887 case DRM_FORMAT_UYVY:
888 case DRM_FORMAT_VYUY:
889 cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE;
890 break;
891 case DRM_FORMAT_NV16:
892 case DRM_FORMAT_NV61:
893 case DRM_FORMAT_YUV422:
894 cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422;
895 break;
896 case DRM_FORMAT_YUV420:
897 case DRM_FORMAT_YVU420:
898 case DRM_FORMAT_NV12:
899 case DRM_FORMAT_NV12MT:
900 case DRM_FORMAT_NV21:
901 cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
902 break;
903 default:
904 dev_err(ippdrv->dev, "inavlid target format 0x%x.\n",
905 fmt);
906 return -EINVAL;
907 }
908
909 fimc_write(cfg, EXYNOS_CITRGFMT);
910 }
911
912 cfg = fimc_read(EXYNOS_CIDMAPARAM);
913 cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;
914
915 if (fmt == DRM_FORMAT_NV12MT)
916 cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;
917 else
918 cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
919
920 fimc_write(cfg, EXYNOS_CIDMAPARAM);
921
922 return fimc_dst_set_fmt_order(ctx, fmt);
923}
924
925static int fimc_dst_set_transf(struct device *dev,
926 enum drm_exynos_degree degree,
927 enum drm_exynos_flip flip, bool *swap)
928{
929 struct fimc_context *ctx = get_fimc_context(dev);
930 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
931 u32 cfg;
932
933 DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
934 degree, flip);
935
936 cfg = fimc_read(EXYNOS_CITRGFMT);
937 cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;
938 cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
939
940 switch (degree) {
941 case EXYNOS_DRM_DEGREE_0:
942 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
943 cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
944 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
945 cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
946 break;
947 case EXYNOS_DRM_DEGREE_90:
948 cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
949 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
950 cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
951 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
952 cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
953 break;
954 case EXYNOS_DRM_DEGREE_180:
955 cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR |
956 EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
957 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
958 cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
959 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
960 cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
961 break;
962 case EXYNOS_DRM_DEGREE_270:
963 cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE |
964 EXYNOS_CITRGFMT_FLIP_X_MIRROR |
965 EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
966 if (flip & EXYNOS_DRM_FLIP_VERTICAL)
967 cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
968 if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
969 cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
970 break;
971 default:
972 dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree);
973 return -EINVAL;
974 }
975
976 fimc_write(cfg, EXYNOS_CITRGFMT);
977 *swap = (cfg & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) ? 1 : 0;
978
979 return 0;
980}
981
982static int fimc_get_ratio_shift(u32 src, u32 dst, u32 *ratio, u32 *shift)
983{
984 DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst);
985
986 if (src >= dst * 64) {
987 DRM_ERROR("failed to make ratio and shift.\n");
988 return -EINVAL;
989 } else if (src >= dst * 32) {
990 *ratio = 32;
991 *shift = 5;
992 } else if (src >= dst * 16) {
993 *ratio = 16;
994 *shift = 4;
995 } else if (src >= dst * 8) {
996 *ratio = 8;
997 *shift = 3;
998 } else if (src >= dst * 4) {
999 *ratio = 4;
1000 *shift = 2;
1001 } else if (src >= dst * 2) {
1002 *ratio = 2;
1003 *shift = 1;
1004 } else {
1005 *ratio = 1;
1006 *shift = 0;
1007 }
1008
1009 return 0;
1010}
1011
1012static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc,
1013 struct drm_exynos_pos *src, struct drm_exynos_pos *dst)
1014{
1015 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1016 u32 cfg, cfg_ext, shfactor;
1017 u32 pre_dst_width, pre_dst_height;
1018 u32 pre_hratio, hfactor, pre_vratio, vfactor;
1019 int ret = 0;
1020 u32 src_w, src_h, dst_w, dst_h;
1021
1022 cfg_ext = fimc_read(EXYNOS_CITRGFMT);
1023 if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) {
1024 src_w = src->h;
1025 src_h = src->w;
1026 } else {
1027 src_w = src->w;
1028 src_h = src->h;
1029 }
1030
1031 if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) {
1032 dst_w = dst->h;
1033 dst_h = dst->w;
1034 } else {
1035 dst_w = dst->w;
1036 dst_h = dst->h;
1037 }
1038
1039 ret = fimc_get_ratio_shift(src_w, dst_w, &pre_hratio, &hfactor);
1040 if (ret) {
1041 dev_err(ippdrv->dev, "failed to get ratio horizontal.\n");
1042 return ret;
1043 }
1044
1045 ret = fimc_get_ratio_shift(src_h, dst_h, &pre_vratio, &vfactor);
1046 if (ret) {
1047 dev_err(ippdrv->dev, "failed to get ratio vertical.\n");
1048 return ret;
1049 }
1050
1051 pre_dst_width = src_w / pre_hratio;
1052 pre_dst_height = src_h / pre_vratio;
1053 DRM_DEBUG_KMS("%s:pre_dst_width[%d]pre_dst_height[%d]\n", __func__,
1054 pre_dst_width, pre_dst_height);
1055 DRM_DEBUG_KMS("%s:pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n",
1056 __func__, pre_hratio, hfactor, pre_vratio, vfactor);
1057
1058 sc->hratio = (src_w << 14) / (dst_w << hfactor);
1059 sc->vratio = (src_h << 14) / (dst_h << vfactor);
1060 sc->up_h = (dst_w >= src_w) ? true : false;
1061 sc->up_v = (dst_h >= src_h) ? true : false;
1062 DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
1063 __func__, sc->hratio, sc->vratio, sc->up_h, sc->up_v);
1064
1065 shfactor = FIMC_SHFACTOR - (hfactor + vfactor);
1066 DRM_DEBUG_KMS("%s:shfactor[%d]\n", __func__, shfactor);
1067
1068 cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) |
1069 EXYNOS_CISCPRERATIO_PREHORRATIO(pre_hratio) |
1070 EXYNOS_CISCPRERATIO_PREVERRATIO(pre_vratio));
1071 fimc_write(cfg, EXYNOS_CISCPRERATIO);
1072
1073 cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) |
1074 EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height));
1075 fimc_write(cfg, EXYNOS_CISCPREDST);
1076
1077 return ret;
1078}
1079
1080static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)
1081{
1082 u32 cfg, cfg_ext;
1083
1084 DRM_DEBUG_KMS("%s:range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
1085 __func__, sc->range, sc->bypass, sc->up_h, sc->up_v);
1086 DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]\n",
1087 __func__, sc->hratio, sc->vratio);
1088
1089 cfg = fimc_read(EXYNOS_CISCCTRL);
1090 cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS |
1091 EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V |
1092 EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK |
1093 EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK |
1094 EXYNOS_CISCCTRL_CSCR2Y_WIDE |
1095 EXYNOS_CISCCTRL_CSCY2R_WIDE);
1096
1097 if (sc->range)
1098 cfg |= (EXYNOS_CISCCTRL_CSCR2Y_WIDE |
1099 EXYNOS_CISCCTRL_CSCY2R_WIDE);
1100 if (sc->bypass)
1101 cfg |= EXYNOS_CISCCTRL_SCALERBYPASS;
1102 if (sc->up_h)
1103 cfg |= EXYNOS_CISCCTRL_SCALEUP_H;
1104 if (sc->up_v)
1105 cfg |= EXYNOS_CISCCTRL_SCALEUP_V;
1106
1107 cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) |
1108 EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6)));
1109 fimc_write(cfg, EXYNOS_CISCCTRL);
1110
1111 cfg_ext = fimc_read(EXYNOS_CIEXTEN);
1112 cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK;
1113 cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK;
1114 cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) |
1115 EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio));
1116 fimc_write(cfg_ext, EXYNOS_CIEXTEN);
1117}
1118
1119static int fimc_dst_set_size(struct device *dev, int swap,
1120 struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
1121{
1122 struct fimc_context *ctx = get_fimc_context(dev);
1123 struct drm_exynos_pos img_pos = *pos;
1124 struct drm_exynos_sz img_sz = *sz;
1125 u32 cfg;
1126
1127 DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
1128 __func__, swap, sz->hsize, sz->vsize);
1129
1130 /* original size */
1131 cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) |
1132 EXYNOS_ORGOSIZE_VERTICAL(img_sz.vsize));
1133
1134 fimc_write(cfg, EXYNOS_ORGOSIZE);
1135
1136 DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n",
1137 __func__, pos->x, pos->y, pos->w, pos->h);
1138
1139 /* CSC ITU */
1140 cfg = fimc_read(EXYNOS_CIGCTRL);
1141 cfg &= ~EXYNOS_CIGCTRL_CSC_MASK;
1142
1143 if (sz->hsize >= FIMC_WIDTH_ITU_709)
1144 cfg |= EXYNOS_CIGCTRL_CSC_ITU709;
1145 else
1146 cfg |= EXYNOS_CIGCTRL_CSC_ITU601;
1147
1148 fimc_write(cfg, EXYNOS_CIGCTRL);
1149
1150 if (swap) {
1151 img_pos.w = pos->h;
1152 img_pos.h = pos->w;
1153 img_sz.hsize = sz->vsize;
1154 img_sz.vsize = sz->hsize;
1155 }
1156
1157 /* target image size */
1158 cfg = fimc_read(EXYNOS_CITRGFMT);
1159 cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK |
1160 EXYNOS_CITRGFMT_TARGETV_MASK);
1161 cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos.w) |
1162 EXYNOS_CITRGFMT_TARGETVSIZE(img_pos.h));
1163 fimc_write(cfg, EXYNOS_CITRGFMT);
1164
1165 /* target area */
1166 cfg = EXYNOS_CITAREA_TARGET_AREA(img_pos.w * img_pos.h);
1167 fimc_write(cfg, EXYNOS_CITAREA);
1168
1169 /* offset Y(RGB), Cb, Cr */
1170 cfg = (EXYNOS_CIOYOFF_HORIZONTAL(img_pos.x) |
1171 EXYNOS_CIOYOFF_VERTICAL(img_pos.y));
1172 fimc_write(cfg, EXYNOS_CIOYOFF);
1173 cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos.x) |
1174 EXYNOS_CIOCBOFF_VERTICAL(img_pos.y));
1175 fimc_write(cfg, EXYNOS_CIOCBOFF);
1176 cfg = (EXYNOS_CIOCROFF_HORIZONTAL(img_pos.x) |
1177 EXYNOS_CIOCROFF_VERTICAL(img_pos.y));
1178 fimc_write(cfg, EXYNOS_CIOCROFF);
1179
1180 return 0;
1181}
1182
1183static int fimc_dst_get_buf_seq(struct fimc_context *ctx)
1184{
1185 u32 cfg, i, buf_num = 0;
1186 u32 mask = 0x00000001;
1187
1188 cfg = fimc_read(EXYNOS_CIFCNTSEQ);
1189
1190 for (i = 0; i < FIMC_REG_SZ; i++)
1191 if (cfg & (mask << i))
1192 buf_num++;
1193
1194 DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num);
1195
1196 return buf_num;
1197}
1198
1199static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
1200 enum drm_exynos_ipp_buf_type buf_type)
1201{
1202 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1203 bool enable;
1204 u32 cfg;
1205 u32 mask = 0x00000001 << buf_id;
1206 int ret = 0;
1207
1208 DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
1209 buf_id, buf_type);
1210
1211 mutex_lock(&ctx->lock);
1212
1213 /* mask register set */
1214 cfg = fimc_read(EXYNOS_CIFCNTSEQ);
1215
1216 switch (buf_type) {
1217 case IPP_BUF_ENQUEUE:
1218 enable = true;
1219 break;
1220 case IPP_BUF_DEQUEUE:
1221 enable = false;
1222 break;
1223 default:
1224 dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");
1225 ret = -EINVAL;
1226 goto err_unlock;
1227 }
1228
1229 /* sequence id */
Eunchul Kim13a32eb2012-12-22 17:49:29 +09001230 cfg &= ~mask;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001231 cfg |= (enable << buf_id);
1232 fimc_write(cfg, EXYNOS_CIFCNTSEQ);
1233
1234 /* interrupt enable */
1235 if (buf_type == IPP_BUF_ENQUEUE &&
1236 fimc_dst_get_buf_seq(ctx) >= FIMC_BUF_START)
1237 fimc_handle_irq(ctx, true, false, true);
1238
1239 /* interrupt disable */
1240 if (buf_type == IPP_BUF_DEQUEUE &&
1241 fimc_dst_get_buf_seq(ctx) <= FIMC_BUF_STOP)
1242 fimc_handle_irq(ctx, false, false, true);
1243
1244err_unlock:
1245 mutex_unlock(&ctx->lock);
1246 return ret;
1247}
1248
1249static int fimc_dst_set_addr(struct device *dev,
1250 struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
1251 enum drm_exynos_ipp_buf_type buf_type)
1252{
1253 struct fimc_context *ctx = get_fimc_context(dev);
1254 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
Eunchul Kim7259c3d2012-12-22 17:49:22 +09001255 struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001256 struct drm_exynos_ipp_property *property;
1257 struct drm_exynos_ipp_config *config;
1258
1259 if (!c_node) {
1260 DRM_ERROR("failed to get c_node.\n");
1261 return -EINVAL;
1262 }
1263
1264 property = &c_node->property;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001265
1266 DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
1267 property->prop_id, buf_id, buf_type);
1268
1269 if (buf_id > FIMC_MAX_DST) {
1270 dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id);
1271 return -ENOMEM;
1272 }
1273
1274 /* address register set */
1275 switch (buf_type) {
1276 case IPP_BUF_ENQUEUE:
1277 config = &property->config[EXYNOS_DRM_OPS_DST];
1278
1279 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],
1280 EXYNOS_CIOYSA(buf_id));
1281
1282 if (config->fmt == DRM_FORMAT_YVU420) {
1283 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
1284 EXYNOS_CIOCBSA(buf_id));
1285 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
1286 EXYNOS_CIOCRSA(buf_id));
1287 } else {
1288 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
1289 EXYNOS_CIOCBSA(buf_id));
1290 fimc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
1291 EXYNOS_CIOCRSA(buf_id));
1292 }
1293 break;
1294 case IPP_BUF_DEQUEUE:
1295 fimc_write(0x0, EXYNOS_CIOYSA(buf_id));
1296 fimc_write(0x0, EXYNOS_CIOCBSA(buf_id));
1297 fimc_write(0x0, EXYNOS_CIOCRSA(buf_id));
1298 break;
1299 default:
1300 /* bypass */
1301 break;
1302 }
1303
1304 return fimc_dst_set_buf_seq(ctx, buf_id, buf_type);
1305}
1306
1307static struct exynos_drm_ipp_ops fimc_dst_ops = {
1308 .set_fmt = fimc_dst_set_fmt,
1309 .set_transf = fimc_dst_set_transf,
1310 .set_size = fimc_dst_set_size,
1311 .set_addr = fimc_dst_set_addr,
1312};
1313
1314static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
1315{
1316 DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
1317
1318 if (enable) {
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001319 clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
1320 clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001321 ctx->suspended = false;
1322 } else {
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001323 clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
1324 clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001325 ctx->suspended = true;
1326 }
1327
1328 return 0;
1329}
1330
1331static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
1332{
1333 struct fimc_context *ctx = dev_id;
1334 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
Eunchul Kim7259c3d2012-12-22 17:49:22 +09001335 struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001336 struct drm_exynos_ipp_event_work *event_work =
1337 c_node->event_work;
1338 int buf_id;
1339
1340 DRM_DEBUG_KMS("%s:fimc id[%d]\n", __func__, ctx->id);
1341
1342 fimc_clear_irq(ctx);
1343 if (fimc_check_ovf(ctx))
1344 return IRQ_NONE;
1345
1346 if (!fimc_check_frame_end(ctx))
1347 return IRQ_NONE;
1348
1349 buf_id = fimc_get_buf_id(ctx);
1350 if (buf_id < 0)
1351 return IRQ_HANDLED;
1352
1353 DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
1354
1355 if (fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE) < 0) {
1356 DRM_ERROR("failed to dequeue.\n");
1357 return IRQ_HANDLED;
1358 }
1359
1360 event_work->ippdrv = ippdrv;
1361 event_work->buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
1362 queue_work(ippdrv->event_workq, (struct work_struct *)event_work);
1363
1364 return IRQ_HANDLED;
1365}
1366
1367static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
1368{
1369 struct drm_exynos_ipp_prop_list *prop_list;
1370
1371 DRM_DEBUG_KMS("%s\n", __func__);
1372
1373 prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
1374 if (!prop_list) {
1375 DRM_ERROR("failed to alloc property list.\n");
1376 return -ENOMEM;
1377 }
1378
1379 prop_list->version = 1;
1380 prop_list->writeback = 1;
1381 prop_list->refresh_min = FIMC_REFRESH_MIN;
1382 prop_list->refresh_max = FIMC_REFRESH_MAX;
1383 prop_list->flip = (1 << EXYNOS_DRM_FLIP_NONE) |
1384 (1 << EXYNOS_DRM_FLIP_VERTICAL) |
1385 (1 << EXYNOS_DRM_FLIP_HORIZONTAL);
1386 prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
1387 (1 << EXYNOS_DRM_DEGREE_90) |
1388 (1 << EXYNOS_DRM_DEGREE_180) |
1389 (1 << EXYNOS_DRM_DEGREE_270);
1390 prop_list->csc = 1;
1391 prop_list->crop = 1;
1392 prop_list->crop_max.hsize = FIMC_CROP_MAX;
1393 prop_list->crop_max.vsize = FIMC_CROP_MAX;
1394 prop_list->crop_min.hsize = FIMC_CROP_MIN;
1395 prop_list->crop_min.vsize = FIMC_CROP_MIN;
1396 prop_list->scale = 1;
1397 prop_list->scale_max.hsize = FIMC_SCALE_MAX;
1398 prop_list->scale_max.vsize = FIMC_SCALE_MAX;
1399 prop_list->scale_min.hsize = FIMC_SCALE_MIN;
1400 prop_list->scale_min.vsize = FIMC_SCALE_MIN;
1401
1402 ippdrv->prop_list = prop_list;
1403
1404 return 0;
1405}
1406
1407static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip)
1408{
1409 switch (flip) {
1410 case EXYNOS_DRM_FLIP_NONE:
1411 case EXYNOS_DRM_FLIP_VERTICAL:
1412 case EXYNOS_DRM_FLIP_HORIZONTAL:
Eunchul Kim4f218772012-12-22 17:49:24 +09001413 case EXYNOS_DRM_FLIP_BOTH:
Eunchul Kim16102ed2012-12-14 17:58:55 +09001414 return true;
1415 default:
1416 DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
1417 return false;
1418 }
1419}
1420
1421static int fimc_ippdrv_check_property(struct device *dev,
1422 struct drm_exynos_ipp_property *property)
1423{
1424 struct fimc_context *ctx = get_fimc_context(dev);
1425 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1426 struct drm_exynos_ipp_prop_list *pp = ippdrv->prop_list;
1427 struct drm_exynos_ipp_config *config;
1428 struct drm_exynos_pos *pos;
1429 struct drm_exynos_sz *sz;
1430 bool swap;
1431 int i;
1432
1433 DRM_DEBUG_KMS("%s\n", __func__);
1434
1435 for_each_ipp_ops(i) {
1436 if ((i == EXYNOS_DRM_OPS_SRC) &&
1437 (property->cmd == IPP_CMD_WB))
1438 continue;
1439
1440 config = &property->config[i];
1441 pos = &config->pos;
1442 sz = &config->sz;
1443
1444 /* check for flip */
1445 if (!fimc_check_drm_flip(config->flip)) {
1446 DRM_ERROR("invalid flip.\n");
1447 goto err_property;
1448 }
1449
1450 /* check for degree */
1451 switch (config->degree) {
1452 case EXYNOS_DRM_DEGREE_90:
1453 case EXYNOS_DRM_DEGREE_270:
1454 swap = true;
1455 break;
1456 case EXYNOS_DRM_DEGREE_0:
1457 case EXYNOS_DRM_DEGREE_180:
1458 swap = false;
1459 break;
1460 default:
1461 DRM_ERROR("invalid degree.\n");
1462 goto err_property;
1463 }
1464
1465 /* check for buffer bound */
1466 if ((pos->x + pos->w > sz->hsize) ||
1467 (pos->y + pos->h > sz->vsize)) {
1468 DRM_ERROR("out of buf bound.\n");
1469 goto err_property;
1470 }
1471
1472 /* check for crop */
1473 if ((i == EXYNOS_DRM_OPS_SRC) && (pp->crop)) {
1474 if (swap) {
1475 if ((pos->h < pp->crop_min.hsize) ||
1476 (sz->vsize > pp->crop_max.hsize) ||
1477 (pos->w < pp->crop_min.vsize) ||
1478 (sz->hsize > pp->crop_max.vsize)) {
1479 DRM_ERROR("out of crop size.\n");
1480 goto err_property;
1481 }
1482 } else {
1483 if ((pos->w < pp->crop_min.hsize) ||
1484 (sz->hsize > pp->crop_max.hsize) ||
1485 (pos->h < pp->crop_min.vsize) ||
1486 (sz->vsize > pp->crop_max.vsize)) {
1487 DRM_ERROR("out of crop size.\n");
1488 goto err_property;
1489 }
1490 }
1491 }
1492
1493 /* check for scale */
1494 if ((i == EXYNOS_DRM_OPS_DST) && (pp->scale)) {
1495 if (swap) {
1496 if ((pos->h < pp->scale_min.hsize) ||
1497 (sz->vsize > pp->scale_max.hsize) ||
1498 (pos->w < pp->scale_min.vsize) ||
1499 (sz->hsize > pp->scale_max.vsize)) {
1500 DRM_ERROR("out of scale size.\n");
1501 goto err_property;
1502 }
1503 } else {
1504 if ((pos->w < pp->scale_min.hsize) ||
1505 (sz->hsize > pp->scale_max.hsize) ||
1506 (pos->h < pp->scale_min.vsize) ||
1507 (sz->vsize > pp->scale_max.vsize)) {
1508 DRM_ERROR("out of scale size.\n");
1509 goto err_property;
1510 }
1511 }
1512 }
1513 }
1514
1515 return 0;
1516
1517err_property:
1518 for_each_ipp_ops(i) {
1519 if ((i == EXYNOS_DRM_OPS_SRC) &&
1520 (property->cmd == IPP_CMD_WB))
1521 continue;
1522
1523 config = &property->config[i];
1524 pos = &config->pos;
1525 sz = &config->sz;
1526
1527 DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n",
1528 i ? "dst" : "src", config->flip, config->degree,
1529 pos->x, pos->y, pos->w, pos->h,
1530 sz->hsize, sz->vsize);
1531 }
1532
1533 return -EINVAL;
1534}
1535
1536static void fimc_clear_addr(struct fimc_context *ctx)
1537{
1538 int i;
1539
1540 DRM_DEBUG_KMS("%s:\n", __func__);
1541
1542 for (i = 0; i < FIMC_MAX_SRC; i++) {
1543 fimc_write(0, EXYNOS_CIIYSA(i));
1544 fimc_write(0, EXYNOS_CIICBSA(i));
1545 fimc_write(0, EXYNOS_CIICRSA(i));
1546 }
1547
1548 for (i = 0; i < FIMC_MAX_DST; i++) {
1549 fimc_write(0, EXYNOS_CIOYSA(i));
1550 fimc_write(0, EXYNOS_CIOCBSA(i));
1551 fimc_write(0, EXYNOS_CIOCRSA(i));
1552 }
1553}
1554
1555static int fimc_ippdrv_reset(struct device *dev)
1556{
1557 struct fimc_context *ctx = get_fimc_context(dev);
1558
1559 DRM_DEBUG_KMS("%s\n", __func__);
1560
1561 /* reset h/w block */
JoongMock Shinb5c0b552012-12-22 17:49:27 +09001562 fimc_sw_reset(ctx);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001563
1564 /* reset scaler capability */
1565 memset(&ctx->sc, 0x0, sizeof(ctx->sc));
1566
1567 fimc_clear_addr(ctx);
1568
1569 return 0;
1570}
1571
1572static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1573{
1574 struct fimc_context *ctx = get_fimc_context(dev);
1575 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
Eunchul Kim7259c3d2012-12-22 17:49:22 +09001576 struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001577 struct drm_exynos_ipp_property *property;
1578 struct drm_exynos_ipp_config *config;
1579 struct drm_exynos_pos img_pos[EXYNOS_DRM_OPS_MAX];
1580 struct drm_exynos_ipp_set_wb set_wb;
1581 int ret, i;
1582 u32 cfg0, cfg1;
1583
1584 DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
1585
1586 if (!c_node) {
1587 DRM_ERROR("failed to get c_node.\n");
1588 return -EINVAL;
1589 }
1590
1591 property = &c_node->property;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001592
1593 fimc_handle_irq(ctx, true, false, true);
1594
1595 for_each_ipp_ops(i) {
1596 config = &property->config[i];
1597 img_pos[i] = config->pos;
1598 }
1599
1600 ret = fimc_set_prescaler(ctx, &ctx->sc,
1601 &img_pos[EXYNOS_DRM_OPS_SRC],
1602 &img_pos[EXYNOS_DRM_OPS_DST]);
1603 if (ret) {
1604 dev_err(dev, "failed to set precalser.\n");
1605 return ret;
1606 }
1607
1608 /* If set ture, we can save jpeg about screen */
1609 fimc_handle_jpeg(ctx, false);
1610 fimc_set_scaler(ctx, &ctx->sc);
1611 fimc_set_polarity(ctx, &ctx->pol);
1612
1613 switch (cmd) {
1614 case IPP_CMD_M2M:
1615 fimc_set_type_ctrl(ctx, FIMC_WB_NONE);
1616 fimc_handle_lastend(ctx, false);
1617
1618 /* setup dma */
1619 cfg0 = fimc_read(EXYNOS_MSCTRL);
1620 cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK;
1621 cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY;
1622 fimc_write(cfg0, EXYNOS_MSCTRL);
1623 break;
1624 case IPP_CMD_WB:
1625 fimc_set_type_ctrl(ctx, FIMC_WB_A);
1626 fimc_handle_lastend(ctx, true);
1627
1628 /* setup FIMD */
1629 fimc_set_camblk_fimd0_wb(ctx);
1630
1631 set_wb.enable = 1;
1632 set_wb.refresh = property->refresh_rate;
1633 exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1634 break;
1635 case IPP_CMD_OUTPUT:
1636 default:
1637 ret = -EINVAL;
1638 dev_err(dev, "invalid operations.\n");
1639 return ret;
1640 }
1641
1642 /* Reset status */
1643 fimc_write(0x0, EXYNOS_CISTATUS);
1644
1645 cfg0 = fimc_read(EXYNOS_CIIMGCPT);
1646 cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC;
1647 cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC;
1648
1649 /* Scaler */
1650 cfg1 = fimc_read(EXYNOS_CISCCTRL);
1651 cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK;
1652 cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE |
1653 EXYNOS_CISCCTRL_SCALERSTART);
1654
1655 fimc_write(cfg1, EXYNOS_CISCCTRL);
1656
1657 /* Enable image capture*/
1658 cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN;
1659 fimc_write(cfg0, EXYNOS_CIIMGCPT);
1660
1661 /* Disable frame end irq */
1662 cfg0 = fimc_read(EXYNOS_CIGCTRL);
1663 cfg0 &= ~EXYNOS_CIGCTRL_IRQ_END_DISABLE;
1664 fimc_write(cfg0, EXYNOS_CIGCTRL);
1665
1666 cfg0 = fimc_read(EXYNOS_CIOCTRL);
1667 cfg0 &= ~EXYNOS_CIOCTRL_WEAVE_MASK;
1668 fimc_write(cfg0, EXYNOS_CIOCTRL);
1669
1670 if (cmd == IPP_CMD_M2M) {
1671 cfg0 = fimc_read(EXYNOS_MSCTRL);
1672 cfg0 |= EXYNOS_MSCTRL_ENVID;
1673 fimc_write(cfg0, EXYNOS_MSCTRL);
1674
1675 cfg0 = fimc_read(EXYNOS_MSCTRL);
1676 cfg0 |= EXYNOS_MSCTRL_ENVID;
1677 fimc_write(cfg0, EXYNOS_MSCTRL);
1678 }
1679
1680 return 0;
1681}
1682
1683static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1684{
1685 struct fimc_context *ctx = get_fimc_context(dev);
1686 struct drm_exynos_ipp_set_wb set_wb = {0, 0};
1687 u32 cfg;
1688
1689 DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
1690
1691 switch (cmd) {
1692 case IPP_CMD_M2M:
1693 /* Source clear */
1694 cfg = fimc_read(EXYNOS_MSCTRL);
1695 cfg &= ~EXYNOS_MSCTRL_INPUT_MASK;
1696 cfg &= ~EXYNOS_MSCTRL_ENVID;
1697 fimc_write(cfg, EXYNOS_MSCTRL);
1698 break;
1699 case IPP_CMD_WB:
1700 exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1701 break;
1702 case IPP_CMD_OUTPUT:
1703 default:
1704 dev_err(dev, "invalid operations.\n");
1705 break;
1706 }
1707
1708 fimc_handle_irq(ctx, false, false, true);
1709
1710 /* reset sequence */
1711 fimc_write(0x0, EXYNOS_CIFCNTSEQ);
1712
1713 /* Scaler disable */
1714 cfg = fimc_read(EXYNOS_CISCCTRL);
1715 cfg &= ~EXYNOS_CISCCTRL_SCALERSTART;
1716 fimc_write(cfg, EXYNOS_CISCCTRL);
1717
1718 /* Disable image capture */
1719 cfg = fimc_read(EXYNOS_CIIMGCPT);
1720 cfg &= ~(EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);
1721 fimc_write(cfg, EXYNOS_CIIMGCPT);
1722
1723 /* Enable frame end irq */
1724 cfg = fimc_read(EXYNOS_CIGCTRL);
1725 cfg |= EXYNOS_CIGCTRL_IRQ_END_DISABLE;
1726 fimc_write(cfg, EXYNOS_CIGCTRL);
1727}
1728
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001729static void fimc_put_clocks(struct fimc_context *ctx)
1730{
1731 int i;
1732
1733 for (i = 0; i < FIMC_CLKS_MAX; i++) {
1734 if (IS_ERR(ctx->clocks[i]))
1735 continue;
1736 clk_put(ctx->clocks[i]);
1737 ctx->clocks[i] = ERR_PTR(-EINVAL);
1738 }
1739}
1740
1741static int fimc_setup_clocks(struct fimc_context *ctx)
1742{
1743 struct device *fimc_dev = ctx->ippdrv.dev;
1744 struct device *dev;
1745 int ret, i;
1746
1747 for (i = 0; i < FIMC_CLKS_MAX; i++)
1748 ctx->clocks[i] = ERR_PTR(-EINVAL);
1749
1750 for (i = 0; i < FIMC_CLKS_MAX; i++) {
1751 if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B)
1752 dev = fimc_dev->parent;
1753 else
1754 dev = fimc_dev;
1755
1756 ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);
1757 if (IS_ERR(ctx->clocks[i])) {
1758 if (i >= FIMC_CLK_MUX)
1759 break;
1760 ret = PTR_ERR(ctx->clocks[i]);
1761 dev_err(fimc_dev, "failed to get clock: %s\n",
1762 fimc_clock_names[i]);
1763 goto e_clk_free;
1764 }
1765 }
1766
1767 /* Optional FIMC LCLK parent clock setting */
1768 if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) {
1769 ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX],
1770 ctx->clocks[FIMC_CLK_PARENT]);
1771 if (ret < 0) {
1772 dev_err(fimc_dev, "failed to set parent.\n");
1773 goto e_clk_free;
1774 }
1775 }
1776
1777 ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency);
1778 if (ret < 0)
1779 goto e_clk_free;
1780
1781 ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);
1782 if (!ret)
1783 return ret;
1784e_clk_free:
1785 fimc_put_clocks(ctx);
1786 return ret;
1787}
1788
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001789static int fimc_probe(struct platform_device *pdev)
Eunchul Kim16102ed2012-12-14 17:58:55 +09001790{
1791 struct device *dev = &pdev->dev;
1792 struct fimc_context *ctx;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001793 struct resource *res;
1794 struct exynos_drm_ippdrv *ippdrv;
1795 struct exynos_drm_fimc_pdata *pdata;
1796 struct fimc_driverdata *ddata;
1797 int ret;
1798
1799 pdata = pdev->dev.platform_data;
1800 if (!pdata) {
1801 dev_err(dev, "no platform data specified.\n");
1802 return -EINVAL;
1803 }
1804
1805 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
1806 if (!ctx)
1807 return -ENOMEM;
1808
Eunchul Kim16102ed2012-12-14 17:58:55 +09001809 /* resource memory */
1810 ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001811 ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
1812 if (IS_ERR(ctx->regs))
1813 return PTR_ERR(ctx->regs);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001814
1815 /* resource irq */
1816 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1817 if (!res) {
1818 dev_err(dev, "failed to request irq resource.\n");
Sachin Kamat15b32632012-12-28 15:56:18 +05301819 return -ENOENT;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001820 }
1821
1822 ctx->irq = res->start;
1823 ret = request_threaded_irq(ctx->irq, NULL, fimc_irq_handler,
1824 IRQF_ONESHOT, "drm_fimc", ctx);
1825 if (ret < 0) {
1826 dev_err(dev, "failed to request irq.\n");
Sachin Kamat15b32632012-12-28 15:56:18 +05301827 return ret;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001828 }
1829
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001830 ret = fimc_setup_clocks(ctx);
1831 if (ret < 0)
1832 goto err_free_irq;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001833 /* context initailization */
1834 ctx->id = pdev->id;
1835 ctx->pol = pdata->pol;
1836 ctx->ddata = ddata;
1837
1838 ippdrv = &ctx->ippdrv;
1839 ippdrv->dev = dev;
1840 ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
1841 ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
1842 ippdrv->check_property = fimc_ippdrv_check_property;
1843 ippdrv->reset = fimc_ippdrv_reset;
1844 ippdrv->start = fimc_ippdrv_start;
1845 ippdrv->stop = fimc_ippdrv_stop;
1846 ret = fimc_init_prop_list(ippdrv);
1847 if (ret < 0) {
1848 dev_err(dev, "failed to init property list.\n");
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001849 goto err_put_clk;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001850 }
1851
1852 DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
1853 (int)ippdrv);
1854
1855 mutex_init(&ctx->lock);
1856 platform_set_drvdata(pdev, ctx);
1857
1858 pm_runtime_set_active(dev);
1859 pm_runtime_enable(dev);
1860
1861 ret = exynos_drm_ippdrv_register(ippdrv);
1862 if (ret < 0) {
1863 dev_err(dev, "failed to register drm fimc device.\n");
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001864 goto err_pm_dis;
Eunchul Kim16102ed2012-12-14 17:58:55 +09001865 }
1866
1867 dev_info(&pdev->dev, "drm fimc registered successfully.\n");
1868
1869 return 0;
1870
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001871err_pm_dis:
Eunchul Kim16102ed2012-12-14 17:58:55 +09001872 pm_runtime_disable(dev);
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001873err_put_clk:
1874 fimc_put_clocks(ctx);
1875err_free_irq:
Eunchul Kim16102ed2012-12-14 17:58:55 +09001876 free_irq(ctx->irq, ctx);
Sachin Kamat87acdde2012-12-24 14:03:43 +05301877
Eunchul Kim16102ed2012-12-14 17:58:55 +09001878 return ret;
1879}
1880
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001881static int fimc_remove(struct platform_device *pdev)
Eunchul Kim16102ed2012-12-14 17:58:55 +09001882{
1883 struct device *dev = &pdev->dev;
1884 struct fimc_context *ctx = get_fimc_context(dev);
1885 struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1886
Eunchul Kim16102ed2012-12-14 17:58:55 +09001887 exynos_drm_ippdrv_unregister(ippdrv);
1888 mutex_destroy(&ctx->lock);
1889
Sylwester Nawrockie5f86832013-04-23 13:34:37 +02001890 fimc_put_clocks(ctx);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001891 pm_runtime_set_suspended(dev);
1892 pm_runtime_disable(dev);
1893
1894 free_irq(ctx->irq, ctx);
Eunchul Kim16102ed2012-12-14 17:58:55 +09001895
1896 return 0;
1897}
1898
1899#ifdef CONFIG_PM_SLEEP
1900static int fimc_suspend(struct device *dev)
1901{
1902 struct fimc_context *ctx = get_fimc_context(dev);
1903
1904 DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
1905
1906 if (pm_runtime_suspended(dev))
1907 return 0;
1908
1909 return fimc_clk_ctrl(ctx, false);
1910}
1911
1912static int fimc_resume(struct device *dev)
1913{
1914 struct fimc_context *ctx = get_fimc_context(dev);
1915
1916 DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
1917
1918 if (!pm_runtime_suspended(dev))
1919 return fimc_clk_ctrl(ctx, true);
1920
1921 return 0;
1922}
1923#endif
1924
1925#ifdef CONFIG_PM_RUNTIME
1926static int fimc_runtime_suspend(struct device *dev)
1927{
1928 struct fimc_context *ctx = get_fimc_context(dev);
1929
1930 DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
1931
1932 return fimc_clk_ctrl(ctx, false);
1933}
1934
1935static int fimc_runtime_resume(struct device *dev)
1936{
1937 struct fimc_context *ctx = get_fimc_context(dev);
1938
1939 DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
1940
1941 return fimc_clk_ctrl(ctx, true);
1942}
1943#endif
1944
1945static struct fimc_driverdata exynos4210_fimc_data = {
1946 .parent_clk = "mout_mpll",
1947};
1948
1949static struct fimc_driverdata exynos4410_fimc_data = {
1950 .parent_clk = "mout_mpll_user",
1951};
1952
1953static struct platform_device_id fimc_driver_ids[] = {
1954 {
1955 .name = "exynos4210-fimc",
1956 .driver_data = (unsigned long)&exynos4210_fimc_data,
1957 }, {
1958 .name = "exynos4412-fimc",
1959 .driver_data = (unsigned long)&exynos4410_fimc_data,
1960 },
1961 {},
1962};
1963MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
1964
1965static const struct dev_pm_ops fimc_pm_ops = {
1966 SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
1967 SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
1968};
1969
1970struct platform_driver fimc_driver = {
1971 .probe = fimc_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001972 .remove = fimc_remove,
Eunchul Kim16102ed2012-12-14 17:58:55 +09001973 .id_table = fimc_driver_ids,
1974 .driver = {
1975 .name = "exynos-drm-fimc",
1976 .owner = THIS_MODULE,
1977 .pm = &fimc_pm_ops,
1978 },
1979};
1980