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