upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / s5p-fimc / fimc-reg.c
1 /*
2  * Register interface file for Samsung Camera Interface (FIMC) driver
3  *
4  * Copyright (c) 2010 Samsung Electronics
5  *
6  * Sylwester Nawrocki, s.nawrocki@samsung.com
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/io.h>
14 #include <linux/delay.h>
15 #include <mach/map.h>
16 #include <media/s5p_fimc.h>
17
18 #include "fimc-core.h"
19
20
21 void fimc_hw_reset(struct fimc_dev *dev)
22 {
23         u32 cfg;
24
25         cfg = readl(dev->regs + S5P_CISRCFMT);
26         cfg |= S5P_CISRCFMT_ITU601_8BIT;
27         writel(cfg, dev->regs + S5P_CISRCFMT);
28
29         /* Software reset. */
30         cfg = readl(dev->regs + S5P_CIGCTRL);
31         cfg |= S5P_CIGCTRL_SWRST;
32         writel(cfg, dev->regs + S5P_CIGCTRL);
33         udelay(1000);
34
35         cfg = readl(dev->regs + S5P_CIGCTRL);
36         cfg &= ~S5P_CIGCTRL_SWRST;
37         writel(cfg, dev->regs + S5P_CIGCTRL);
38 }
39
40 void fimc_hw_set_irq_level(struct fimc_dev *dev)
41 {
42         u32 cfg;
43         cfg = readl(dev->regs + S5P_CIGCTRL);
44         cfg |= S5P_CIGCTRL_IRQ_LEVEL;
45         writel(cfg, dev->regs + S5P_CIGCTRL);
46 }
47
48 static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
49 {
50         u32 flip = S5P_MSCTRL_FLIP_NORMAL;
51
52         switch (ctx->flip) {
53         case FLIP_X_AXIS:
54                 flip = S5P_MSCTRL_FLIP_X_MIRROR;
55                 break;
56         case FLIP_Y_AXIS:
57                 flip = S5P_MSCTRL_FLIP_Y_MIRROR;
58                 break;
59         case FLIP_XY_AXIS:
60                 flip = S5P_MSCTRL_FLIP_180;
61                 break;
62         default:
63                 return flip;
64         }
65         if (ctx->rotation <= 90)
66                 return flip;
67
68         return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180;
69 }
70
71 static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
72 {
73         u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
74
75         switch (ctx->flip) {
76         case FLIP_X_AXIS:
77                 flip = S5P_CITRGFMT_FLIP_X_MIRROR;
78                 break;
79         case FLIP_Y_AXIS:
80                 flip = S5P_CITRGFMT_FLIP_Y_MIRROR;
81                 break;
82         case FLIP_XY_AXIS:
83                 flip = S5P_CITRGFMT_FLIP_180;
84                 break;
85         default:
86                 return flip;
87         }
88         if (ctx->rotation <= 90)
89                 return flip;
90
91         return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180;
92 }
93
94 void fimc_hw_set_rotation(struct fimc_ctx *ctx)
95 {
96         u32 cfg, flip;
97         struct fimc_dev *dev = ctx->fimc_dev;
98
99         cfg = readl(dev->regs + S5P_CITRGFMT);
100         cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
101                  S5P_CITRGFMT_FLIP_180);
102
103         /*
104          * The input and output rotator cannot work simultaneously.
105          * Use the output rotator in output DMA mode or the input rotator
106          * in direct fifo output mode.
107          */
108         if (ctx->rotation == 90 || ctx->rotation == 270) {
109                 if (ctx->out_path == FIMC_LCDFIFO)
110                         cfg |= S5P_CITRGFMT_INROT90;
111                 else
112                         cfg |= S5P_CITRGFMT_OUTROT90;
113         }
114
115         if (ctx->out_path == FIMC_DMA) {
116                 cfg |= fimc_hw_get_target_flip(ctx);
117                 writel(cfg, dev->regs + S5P_CITRGFMT);
118         } else {
119                 /* LCD FIFO path */
120                 flip = readl(dev->regs + S5P_MSCTRL);
121                 flip &= ~S5P_MSCTRL_FLIP_MASK;
122                 flip |= fimc_hw_get_in_flip(ctx);
123                 writel(flip, dev->regs + S5P_MSCTRL);
124         }
125 }
126
127 void fimc_hw_set_target_format(struct fimc_ctx *ctx)
128 {
129         u32 cfg, cfg_ext;
130         struct fimc_dev *dev = ctx->fimc_dev;
131         struct fimc_frame *frame = &ctx->d_frame;
132
133         dbg("w= %d, h= %d color: %d", frame->width,
134                 frame->height, frame->fmt->color);
135
136         cfg_ext = readl(dev->regs + S5P_CIEXTEN);
137         cfg_ext &= ~(S5P_CIEXTEN_TRGHSIZE_EXT_MASK |
138                      S5P_CIEXTEN_TRGVSIZE_EXT_MASK);
139         cfg = readl(dev->regs + S5P_CITRGFMT);
140         cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK |
141                   S5P_CITRGFMT_VSIZE_MASK);
142
143         switch (frame->fmt->color) {
144         case S5P_FIMC_RGB565...S5P_FIMC_RGB444:
145                 cfg |= S5P_CITRGFMT_RGB;
146                 break;
147         case S5P_FIMC_YCBCR420: /* fall through */
148         case S5P_FIMC_YCRCB420:
149                 cfg |= S5P_CITRGFMT_YCBCR420;
150                 break;
151         case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
152                 if (frame->fmt->colplanes == 1)
153                         cfg |= S5P_CITRGFMT_YCBCR422_1P;
154                 else
155                         cfg |= S5P_CITRGFMT_YCBCR422;
156                 break;
157         default:
158                 break;
159         }
160
161         if (ctx->rotation == 90 || ctx->rotation == 270) {
162                 cfg |= S5P_CITRGFMT_HSIZE(frame->height);
163                 cfg |= S5P_CITRGFMT_VSIZE(frame->width);
164                 cfg_ext |= S5P_CIEXTEN_TRGHSIZE_EXT(frame->height);
165                 cfg_ext |= S5P_CIEXTEN_TRGVSIZE_EXT(frame->width);
166         } else {
167
168                 cfg |= S5P_CITRGFMT_HSIZE(frame->width);
169                 cfg |= S5P_CITRGFMT_VSIZE(frame->height);
170                 cfg_ext |= S5P_CIEXTEN_TRGHSIZE_EXT(frame->width);
171                 cfg_ext |= S5P_CIEXTEN_TRGVSIZE_EXT(frame->height);
172         }
173
174         writel(cfg, dev->regs + S5P_CITRGFMT);
175         writel(cfg_ext, dev->regs + S5P_CIEXTEN);
176
177         cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
178         cfg |= (frame->width * frame->height);
179         writel(cfg, dev->regs + S5P_CITAREA);
180 }
181
182 static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
183 {
184         struct fimc_dev *dev = ctx->fimc_dev;
185         struct fimc_frame *frame = &ctx->d_frame;
186         u32 cfg;
187
188         cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
189         cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
190         writel(cfg, dev->regs + S5P_ORGOSIZE);
191
192         /* Select color space conversion equation (HD/SD size).*/
193         cfg = readl(dev->regs + S5P_CIGCTRL);
194         if (frame->f_width >= 1280) /* HD */
195                 cfg |= S5P_CIGCTRL_CSC_ITU601_709;
196         else    /* SD */
197                 cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
198         writel(cfg, dev->regs + S5P_CIGCTRL);
199
200 }
201
202 void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
203 {
204         u32 cfg;
205         struct fimc_dev *dev = ctx->fimc_dev;
206         struct fimc_frame *frame = &ctx->d_frame;
207         struct fimc_dma_offset *offset = &frame->dma_offset;
208
209         /* Set the input dma offsets. */
210         cfg = 0;
211         cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
212         cfg |= S5P_CIO_OFFS_VER(offset->y_v);
213         writel(cfg, dev->regs + S5P_CIOYOFF);
214
215         cfg = 0;
216         cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
217         cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
218         writel(cfg, dev->regs + S5P_CIOCBOFF);
219
220         cfg = 0;
221         cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
222         cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
223         writel(cfg, dev->regs + S5P_CIOCROFF);
224
225         fimc_hw_set_out_dma_size(ctx);
226
227         /* Configure chroma components order. */
228         cfg = readl(dev->regs + S5P_CIOCTRL);
229
230         cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
231                  S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
232
233         if (frame->fmt->colplanes == 1)
234                 cfg |= ctx->out_order_1p;
235         else if (frame->fmt->colplanes == 2)
236                 cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
237         else if (frame->fmt->colplanes == 3)
238                 cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
239
240         if (frame->fmt->color == S5P_FIMC_RGB565)
241                 cfg |= S5P_CIOCTRL_RGB565;
242         else if (frame->fmt->color == S5P_FIMC_RGB555)
243                 cfg |= S5P_CIOCTRL_ARGB1555;
244         else if (frame->fmt->color == S5P_FIMC_RGB444)
245                 cfg |= S5P_CIOCTRL_ARGB4444;
246         else if (frame->fmt->color == S5P_FIMC_YCRCB420)
247                 cfg |= S5P_CIOCTRL_ORDER422_2P_LSB_CBCR;
248
249         writel(cfg, dev->regs + S5P_CIOCTRL);
250 }
251
252 static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
253 {
254         u32 cfg = readl(dev->regs + S5P_ORGISIZE);
255         if (enable)
256                 cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
257         else
258                 cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN;
259         writel(cfg, dev->regs + S5P_ORGISIZE);
260 }
261
262 void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
263 {
264         u32 cfg = readl(dev->regs + S5P_CIOCTRL);
265         if (enable)
266                 cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
267         else
268                 cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
269         writel(cfg, dev->regs + S5P_CIOCTRL);
270 }
271
272 void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
273 {
274         struct fimc_dev *dev =  ctx->fimc_dev;
275         struct fimc_scaler *sc = &ctx->scaler;
276         u32 cfg, shfactor;
277
278         shfactor = 10 - (sc->hfactor + sc->vfactor);
279
280         cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
281         cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
282         cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
283         writel(cfg, dev->regs + S5P_CISCPRERATIO);
284
285         cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
286         cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
287         writel(cfg, dev->regs + S5P_CISCPREDST);
288 }
289
290 static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
291 {
292         struct fimc_dev *dev = ctx->fimc_dev;
293         struct fimc_scaler *sc = &ctx->scaler;
294         struct fimc_frame *src_frame = &ctx->s_frame;
295         struct fimc_frame *dst_frame = &ctx->d_frame;
296         u32 cfg = 0;
297
298         if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
299                 cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
300
301         if (!sc->enabled)
302                 cfg |= S5P_CISCCTRL_SCALERBYPASS;
303
304         if (sc->scaleup_h)
305                 cfg |= S5P_CISCCTRL_SCALEUP_H;
306
307         if (sc->scaleup_v)
308                 cfg |= S5P_CISCCTRL_SCALEUP_V;
309
310         if (sc->copy_mode)
311                 cfg |= S5P_CISCCTRL_ONE2ONE;
312
313
314         if (ctx->in_path == FIMC_DMA) {
315                 if (src_frame->fmt->color == S5P_FIMC_RGB565)
316                         cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
317                 else if (src_frame->fmt->color == S5P_FIMC_RGB666)
318                         cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
319                 else if (src_frame->fmt->color == S5P_FIMC_RGB888)
320                         cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
321         }
322
323         if (ctx->out_path == FIMC_DMA) {
324                 if ((dst_frame->fmt->color == S5P_FIMC_RGB565)
325                     | (dst_frame->fmt->color == S5P_FIMC_RGB555)
326                     | (dst_frame->fmt->color == S5P_FIMC_RGB444))
327                         cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
328                 else if (dst_frame->fmt->color == S5P_FIMC_RGB666)
329                         cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
330                 else if (dst_frame->fmt->color == S5P_FIMC_RGB888)
331                         cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
332                 cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO;
333         } else {
334                 cfg |= (S5P_CISCCTRL_OUTRGB_FMT_RGB888
335                         | S5P_CISCCTRL_LCDPATHEN_FIFO);
336
337                 if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
338                         cfg |= S5P_CISCCTRL_INTERLACE;
339         }
340
341         writel(cfg, dev->regs + S5P_CISCCTRL);
342 }
343
344 void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
345 {
346         struct fimc_dev *dev = ctx->fimc_dev;
347         struct samsung_fimc_variant *variant = dev->variant;
348         struct fimc_scaler *sc = &ctx->scaler;
349         u32 cfg;
350
351         dbg("main_hratio= 0x%X  main_vratio= 0x%X",
352                 sc->main_hratio, sc->main_vratio);
353
354         fimc_hw_set_scaler(ctx);
355
356         cfg = readl(dev->regs + S5P_CISCCTRL);
357
358         if (variant->has_mainscaler_ext) {
359                 cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
360                 cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
361                 cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
362                 writel(cfg, dev->regs + S5P_CISCCTRL);
363
364                 cfg = readl(dev->regs + S5P_CIEXTEN);
365
366                 cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK |
367                          S5P_CIEXTEN_MHRATIO_EXT_MASK);
368                 cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
369                 cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
370                 writel(cfg, dev->regs + S5P_CIEXTEN);
371         } else {
372                 cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
373                 cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio);
374                 cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio);
375                 writel(cfg, dev->regs + S5P_CISCCTRL);
376         }
377 }
378
379 void fimc_hw_en_capture(struct fimc_ctx *ctx)
380 {
381         struct fimc_dev *dev = ctx->fimc_dev;
382
383         u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
384
385         if (ctx->out_path == FIMC_DMA) {
386                 /* one shot mode */
387                 cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
388         } else {
389                 /* Continous frame capture mode (freerun). */
390                 cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
391                          S5P_CIIMGCPT_CPT_FRMOD_CNT);
392                 cfg |= S5P_CIIMGCPT_IMGCPTEN;
393         }
394
395         if (ctx->scaler.enabled)
396                 cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
397
398         writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
399 }
400
401 void fimc_hw_set_effect(struct fimc_ctx *ctx)
402 {
403         struct fimc_dev *dev = ctx->fimc_dev;
404         struct fimc_effect *effect = &ctx->effect;
405         u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER);
406
407         cfg |= effect->type;
408
409         if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
410                 cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
411                 cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
412         }
413
414         writel(cfg, dev->regs + S5P_CIIMGEFF);
415 }
416
417 void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
418 {
419         struct fimc_dev *dev = ctx->fimc_dev;
420         struct fimc_frame *frame = &ctx->d_frame;
421         u32 cfg;
422
423         if (!((frame->fmt->color == S5P_FIMC_RGB555)
424             | (frame->fmt->color == S5P_FIMC_RGB444)
425             | (frame->fmt->color == S5P_FIMC_RGB888)))
426                 return;
427
428         cfg = readl(dev->regs + S5P_CIOCTRL);
429         cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
430         cfg |= (frame->alpha << 4);
431         writel(cfg, dev->regs + S5P_CIOCTRL);
432 }
433
434 static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
435 {
436         struct fimc_dev *dev = ctx->fimc_dev;
437         struct fimc_frame *frame = &ctx->s_frame;
438         u32 cfg_o = 0;
439         u32 cfg_r = 0;
440
441         if (FIMC_LCDFIFO == ctx->out_path)
442                 cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
443
444         cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
445         cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
446         cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width);
447         cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height);
448
449         writel(cfg_o, dev->regs + S5P_ORGISIZE);
450         writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE);
451 }
452
453 void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
454 {
455         struct fimc_dev *dev = ctx->fimc_dev;
456         struct fimc_frame *frame = &ctx->s_frame;
457         struct fimc_dma_offset *offset = &frame->dma_offset;
458         u32 cfg;
459
460         /* Set the pixel offsets. */
461         cfg = S5P_CIO_OFFS_HOR(offset->y_h);
462         cfg |= S5P_CIO_OFFS_VER(offset->y_v);
463         writel(cfg, dev->regs + S5P_CIIYOFF);
464
465         cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
466         cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
467         writel(cfg, dev->regs + S5P_CIICBOFF);
468
469         cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
470         cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
471         writel(cfg, dev->regs + S5P_CIICROFF);
472
473         /* Input original and real size. */
474         fimc_hw_set_in_dma_size(ctx);
475
476         /* Use DMA autoload only in FIFO mode. */
477         fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
478
479         /* Set the input DMA to process single frame only. */
480         cfg = readl(dev->regs + S5P_MSCTRL);
481         cfg &= ~(S5P_MSCTRL_INFORMAT_MASK
482                 | S5P_MSCTRL_IN_BURST_COUNT_MASK
483                 | S5P_MSCTRL_INPUT_MASK
484                 | S5P_MSCTRL_C_INT_IN_MASK
485                 | S5P_MSCTRL_2P_IN_ORDER_MASK);
486
487         cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4)
488                 | S5P_MSCTRL_INPUT_MEMORY
489                 | S5P_MSCTRL_FIFO_CTRL_FULL);
490
491         switch (frame->fmt->color) {
492         case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
493                 cfg |= S5P_MSCTRL_INFORMAT_RGB;
494                 break;
495         case S5P_FIMC_YCBCR420: /* fall through */
496         case S5P_FIMC_YCRCB420:
497                 cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
498
499                 if (frame->fmt->colplanes == 2)
500                         cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
501                 else
502                         cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
503
504                 if (frame->fmt->color == S5P_FIMC_YCRCB420)
505                         cfg |= S5P_MSCTRL_2P_IN_YCRCB;
506                 break;
507         case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
508                 if (frame->fmt->colplanes == 1) {
509                         cfg |= ctx->in_order_1p
510                                 | S5P_MSCTRL_INFORMAT_YCBCR422_1P;
511                 } else {
512                         cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
513
514                         if (frame->fmt->colplanes == 2)
515                                 cfg |= ctx->in_order_2p
516                                         | S5P_MSCTRL_C_INT_IN_2PLANE;
517                         else
518                                 cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
519                 }
520                 break;
521         default:
522                 break;
523         }
524
525         writel(cfg, dev->regs + S5P_MSCTRL);
526
527         /* Input/output DMA linear/tiled mode. */
528         cfg = readl(dev->regs + S5P_CIDMAPARAM);
529         cfg &= ~S5P_CIDMAPARAM_TILE_MASK;
530
531         if (tiled_fmt(ctx->s_frame.fmt))
532                 cfg |= S5P_CIDMAPARAM_R_64X32;
533
534         if (tiled_fmt(ctx->d_frame.fmt))
535                 cfg |= S5P_CIDMAPARAM_W_64X32;
536
537         writel(cfg, dev->regs + S5P_CIDMAPARAM);
538 }
539
540
541 void fimc_hw_set_input_path(struct fimc_ctx *ctx)
542 {
543         struct fimc_dev *dev = ctx->fimc_dev;
544
545         u32 cfg = readl(dev->regs + S5P_MSCTRL);
546         cfg &= ~S5P_MSCTRL_INPUT_MASK;
547
548         if (ctx->in_path == FIMC_DMA)
549                 cfg |= S5P_MSCTRL_INPUT_MEMORY;
550         else
551                 cfg |= S5P_MSCTRL_INPUT_EXTCAM;
552
553         writel(cfg, dev->regs + S5P_MSCTRL);
554 }
555
556 void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
557 {
558         u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
559         cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
560         writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
561
562         writel(paddr->y, dev->regs + S5P_CIIYSA(0));
563         writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
564         writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
565
566         cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
567         writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
568 }
569
570 void fimc_hw_set_output_addr(struct fimc_dev *dev,
571                              struct fimc_addr *paddr, int index)
572 {
573         int i = (index == -1) ? 0 : index;
574         do {
575                 writel(paddr->y, dev->regs + S5P_CIOYSA(i));
576                 writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
577                 writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
578                 dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
579                     i, paddr->y, paddr->cb, paddr->cr);
580         } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
581 }
582
583 int fimc_hw_save_output_addr(struct fimc_dev *fimc)
584 {
585         int i;
586         for (i = 0; i < FIMC_MAX_OUT_BUFS; i++) {
587                 fimc->paddr[i].y = readl(fimc->regs + S5P_CIOYSA(i));
588                 fimc->paddr[i].cb = readl(fimc->regs + S5P_CIOCBSA(i));
589                 fimc->paddr[i].cr = readl(fimc->regs + S5P_CIOCRSA(i));
590         }
591
592         return 0;
593 }
594 int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
595                                 struct s5p_fimc_isp_info *cam)
596 {
597         u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
598
599         cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
600                  S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
601
602         if (cam->flags & FIMC_CLK_INV_PCLK)
603                 cfg |= S5P_CIGCTRL_INVPOLPCLK;
604
605         if (cam->flags & FIMC_CLK_INV_VSYNC)
606                 cfg |= S5P_CIGCTRL_INVPOLVSYNC;
607
608         if (cam->flags & FIMC_CLK_INV_HREF)
609                 cfg |= S5P_CIGCTRL_INVPOLHREF;
610
611         if (cam->flags & FIMC_CLK_INV_HSYNC)
612                 cfg |= S5P_CIGCTRL_INVPOLHSYNC;
613
614         writel(cfg, fimc->regs + S5P_CIGCTRL);
615
616         return 0;
617 }
618
619 int fimc_hw_set_camera_source(struct fimc_dev *fimc,
620                               struct s5p_fimc_isp_info *cam)
621 {
622         struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
623         u32 cfg = 0;
624         u32 bus_width;
625         int i;
626
627         static const struct {
628                 u32 pixelcode;
629                 u32 cisrcfmt;
630                 u16 bus_width;
631         } pix_desc[] = {
632                 { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 },
633                 { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 },
634                 { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 },
635                 { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 },
636                 /* TODO: Add pixel codes for 16-bit bus width */
637         };
638
639         if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
640                 for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
641                         if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) {
642                                 cfg = pix_desc[i].cisrcfmt;
643                                 bus_width = pix_desc[i].bus_width;
644                                 break;
645                         }
646                 }
647
648                 if (i == ARRAY_SIZE(pix_desc)) {
649                         v4l2_err(&fimc->vid_cap.v4l2_dev,
650                                  "Camera color format not supported: %d\n",
651                                  fimc->vid_cap.fmt.code);
652                         return -EINVAL;
653                 }
654
655                 if (cam->bus_type == FIMC_ITU_601) {
656                         if (bus_width == 8)
657                                 cfg |= S5P_CISRCFMT_ITU601_8BIT;
658                         else if (bus_width == 16)
659                                 cfg |= S5P_CISRCFMT_ITU601_16BIT;
660                 } /* else defaults to ITU-R BT.656 8-bit */
661         }
662
663         cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
664         writel(cfg, fimc->regs + S5P_CISRCFMT);
665         return 0;
666 }
667
668
669 int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
670 {
671         u32 hoff2, voff2;
672
673         u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
674
675         cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
676         cfg |=  S5P_CIWDOFST_OFF_EN |
677                 S5P_CIWDOFST_HOROFF(f->offs_h) |
678                 S5P_CIWDOFST_VEROFF(f->offs_v);
679
680         writel(cfg, fimc->regs + S5P_CIWDOFST);
681
682         /* See CIWDOFSTn register description in the datasheet for details. */
683         hoff2 = f->o_width - f->width - f->offs_h;
684         voff2 = f->o_height - f->height - f->offs_v;
685         cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
686
687         writel(cfg, fimc->regs + S5P_CIWDOFST2);
688         return 0;
689 }
690
691 int fimc_hw_set_camera_type(struct fimc_dev *fimc,
692                             struct s5p_fimc_isp_info *cam)
693 {
694         u32 cfg, tmp;
695         struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
696
697         cfg = readl(fimc->regs + S5P_CIGCTRL);
698
699         /* Select ITU B interface, disable Writeback path and test pattern. */
700         cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
701                 S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
702                 S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG |
703                 S5P_CIGCTRL_SELWRITEBACK_A);
704
705         if (cam->bus_type == FIMC_MIPI_CSI2) {
706                 cfg |= S5P_CIGCTRL_SELCAM_MIPI;
707
708                 if (cam->mux_id == 0)
709                         cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
710
711                 /* TODO: add remaining supported formats. */
712                 if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8 ||
713                                 vid_cap->fmt.code == V4L2_MBUS_FMT_UYVY8_2X8) {
714                         tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
715                 } else if (vid_cap->fmt.code == V4L2_MBUS_FMT_JPEG_1X8) {
716                         tmp = S5P_CSIIMGFMT_USER(1);
717                         cfg |= S5P_CIGCTRL_CAM_JPEG;
718                 } else {
719                         err("camera image format not supported: %d",
720                             vid_cap->fmt.code);
721                         return -EINVAL;
722                 }
723                 tmp |= (cam->csi_data_align == 32) << 8;
724
725                 writel(tmp, fimc->regs + S5P_CSIIMGFMT);
726         } else if (cam->bus_type == FIMC_ITU_601 ||
727                   cam->bus_type == FIMC_ITU_656) {
728                 if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
729                         cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
730         } else if (cam->bus_type == FIMC_LCD_WB) {
731                 cfg |= S5P_CIGCTRL_CAMIF_SELWB;
732                 if (cam->mux_id == 0)
733                         cfg |= S5P_CIGCTRL_SELWRITEBACK_A;
734         } else {
735                 err("invalid camera bus type selected\n");
736                 return -EINVAL;
737         }
738         writel(cfg, fimc->regs + S5P_CIGCTRL);
739
740         return 0;
741 }
742
743 int fimc_hwset_sysreg_camblk_fimd0_wb(struct fimc_dev *fimc)
744 {
745         u32 cfg = readl(SYSREG_CAMERA_BLK);
746         cfg = cfg & (~(0x3 << 14));
747         if (fimc->id == 0)
748                 cfg = cfg | FIMD0_WB_DEST_FIMC0;
749         else if (fimc->id == 1)
750                 cfg = cfg | FIMD0_WB_DEST_FIMC1;
751         else if (fimc->id == 2)
752                 cfg = cfg | FIMD0_WB_DEST_FIMC2;
753         else if (fimc->id == 3)
754                 cfg = cfg | FIMD0_WB_DEST_FIMC3;
755         else
756                 err("%s: not supported id : %d\n", __func__, fimc->id);
757
758         writel(cfg, SYSREG_CAMERA_BLK);
759
760         return 0;
761 }
762 int fimc_hwset_sysreg_camblk_fimd1_wb(struct fimc_dev *fimc)
763 {
764         u32 cfg = readl(SYSREG_CAMERA_BLK);
765         cfg = cfg & (~(0x3 << 10));
766         if (fimc->id == 0)
767                 cfg = cfg | FIMD1_WB_DEST_FIMC0;
768         else if (fimc->id == 1)
769                 cfg = cfg | FIMD1_WB_DEST_FIMC1;
770         else if (fimc->id == 2)
771                 cfg = cfg | FIMD1_WB_DEST_FIMC2;
772         else if (fimc->id == 3)
773                 cfg = cfg | FIMD1_WB_DEST_FIMC3;
774         else
775                 err("%s: not supported id : %d\n", __func__, fimc->id);
776
777         writel(cfg, SYSREG_CAMERA_BLK);
778
779         return 0;
780 }