Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[deliverable/linux.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 }
This page took 0.047497 seconds and 5 git commands to generate.