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