Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fimc-reg.c
Go to the documentation of this file.
1 /*
2  * Register interface file for Samsung Camera Interface (FIMC) driver
3  *
4  * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
5  * Sylwester Nawrocki, <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11 
12 #include <linux/io.h>
13 #include <linux/delay.h>
14 #include <media/s5p_fimc.h>
15 
16 #include "fimc-reg.h"
17 #include "fimc-core.h"
18 
19 
20 void fimc_hw_reset(struct fimc_dev *dev)
21 {
22  u32 cfg;
23 
24  cfg = readl(dev->regs + FIMC_REG_CISRCFMT);
26  writel(cfg, dev->regs + FIMC_REG_CISRCFMT);
27 
28  /* Software reset. */
29  cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
31  writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
32  udelay(10);
33 
34  cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
35  cfg &= ~FIMC_REG_CIGCTRL_SWRST;
36  writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
37 
38  if (dev->variant->out_buf_count > 4)
39  fimc_hw_set_dma_seq(dev, 0xF);
40 }
41 
42 static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
43 {
45 
46  if (ctx->hflip)
48  if (ctx->vflip)
50 
51  if (ctx->rotation <= 90)
52  return flip;
53 
55 }
56 
57 static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
58 {
60 
61  if (ctx->hflip)
63  if (ctx->vflip)
65 
66  if (ctx->rotation <= 90)
67  return flip;
68 
70 }
71 
72 void fimc_hw_set_rotation(struct fimc_ctx *ctx)
73 {
74  u32 cfg, flip;
75  struct fimc_dev *dev = ctx->fimc_dev;
76 
77  cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
80 
81  /*
82  * The input and output rotator cannot work simultaneously.
83  * Use the output rotator in output DMA mode or the input rotator
84  * in direct fifo output mode.
85  */
86  if (ctx->rotation == 90 || ctx->rotation == 270) {
87  if (ctx->out_path == FIMC_IO_LCDFIFO)
89  else
91  }
92 
93  if (ctx->out_path == FIMC_IO_DMA) {
94  cfg |= fimc_hw_get_target_flip(ctx);
95  writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
96  } else {
97  /* LCD FIFO path */
98  flip = readl(dev->regs + FIMC_REG_MSCTRL);
100  flip |= fimc_hw_get_in_flip(ctx);
101  writel(flip, dev->regs + FIMC_REG_MSCTRL);
102  }
103 }
104 
106 {
107  u32 cfg;
108  struct fimc_dev *dev = ctx->fimc_dev;
109  struct fimc_frame *frame = &ctx->d_frame;
110 
111  dbg("w= %d, h= %d color: %d", frame->width,
112  frame->height, frame->fmt->color);
113 
114  cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
117 
118  switch (frame->fmt->color) {
119  case FIMC_FMT_RGB444...FIMC_FMT_RGB888:
120  cfg |= FIMC_REG_CITRGFMT_RGB;
121  break;
122  case FIMC_FMT_YCBCR420:
124  break;
125  case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
126  if (frame->fmt->colplanes == 1)
128  else
130  break;
131  default:
132  break;
133  }
134 
135  if (ctx->rotation == 90 || ctx->rotation == 270)
136  cfg |= (frame->height << 16) | frame->width;
137  else
138  cfg |= (frame->width << 16) | frame->height;
139 
140  writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
141 
142  cfg = readl(dev->regs + FIMC_REG_CITAREA);
143  cfg &= ~FIMC_REG_CITAREA_MASK;
144  cfg |= (frame->width * frame->height);
145  writel(cfg, dev->regs + FIMC_REG_CITAREA);
146 }
147 
148 static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
149 {
150  struct fimc_dev *dev = ctx->fimc_dev;
151  struct fimc_frame *frame = &ctx->d_frame;
152  u32 cfg;
153 
154  cfg = (frame->f_height << 16) | frame->f_width;
155  writel(cfg, dev->regs + FIMC_REG_ORGOSIZE);
156 
157  /* Select color space conversion equation (HD/SD size).*/
158  cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
159  if (frame->f_width >= 1280) /* HD */
161  else /* SD */
163  writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
164 
165 }
166 
167 void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
168 {
169  struct fimc_dev *dev = ctx->fimc_dev;
170  struct fimc_frame *frame = &ctx->d_frame;
171  struct fimc_dma_offset *offset = &frame->dma_offset;
172  struct fimc_fmt *fmt = frame->fmt;
173  u32 cfg;
174 
175  /* Set the input dma offsets. */
176  cfg = (offset->y_v << 16) | offset->y_h;
177  writel(cfg, dev->regs + FIMC_REG_CIOYOFF);
178 
179  cfg = (offset->cb_v << 16) | offset->cb_h;
180  writel(cfg, dev->regs + FIMC_REG_CIOCBOFF);
181 
182  cfg = (offset->cr_v << 16) | offset->cr_h;
183  writel(cfg, dev->regs + FIMC_REG_CIOCROFF);
184 
185  fimc_hw_set_out_dma_size(ctx);
186 
187  /* Configure chroma components order. */
188  cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
189 
194 
195  if (fmt->colplanes == 1)
196  cfg |= ctx->out_order_1p;
197  else if (fmt->colplanes == 2)
199  else if (fmt->colplanes == 3)
201 
202  if (fmt->color == FIMC_FMT_RGB565)
204  else if (fmt->color == FIMC_FMT_RGB555)
206  else if (fmt->color == FIMC_FMT_RGB444)
208 
209  writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
210 }
211 
212 static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
213 {
214  u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE);
215  if (enable)
217  else
219  writel(cfg, dev->regs + FIMC_REG_ORGISIZE);
220 }
221 
222 void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
223 {
224  u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
225  if (enable)
227  else
229  writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
230 }
231 
233 {
234  struct fimc_dev *dev = ctx->fimc_dev;
235  struct fimc_scaler *sc = &ctx->scaler;
236  u32 cfg, shfactor;
237 
238  shfactor = 10 - (sc->hfactor + sc->vfactor);
239  cfg = shfactor << 28;
240 
241  cfg |= (sc->pre_hratio << 16) | sc->pre_vratio;
242  writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO);
243 
244  cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
245  writel(cfg, dev->regs + FIMC_REG_CISCPREDST);
246 }
247 
248 static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
249 {
250  struct fimc_dev *dev = ctx->fimc_dev;
251  struct fimc_scaler *sc = &ctx->scaler;
252  struct fimc_frame *src_frame = &ctx->s_frame;
253  struct fimc_frame *dst_frame = &ctx->d_frame;
254 
255  u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
256 
262 
263  if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
266 
267  if (!sc->enabled)
269 
270  if (sc->scaleup_h)
272 
273  if (sc->scaleup_v)
275 
276  if (sc->copy_mode)
278 
279  if (ctx->in_path == FIMC_IO_DMA) {
280  switch (src_frame->fmt->color) {
281  case FIMC_FMT_RGB565:
283  break;
284  case FIMC_FMT_RGB666:
286  break;
287  case FIMC_FMT_RGB888:
289  break;
290  }
291  }
292 
293  if (ctx->out_path == FIMC_IO_DMA) {
294  u32 color = dst_frame->fmt->color;
295 
296  if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565)
298  else if (color == FIMC_FMT_RGB666)
300  else if (color == FIMC_FMT_RGB888)
302  } else {
304 
305  if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
307  }
308 
309  writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
310 }
311 
313 {
314  struct fimc_dev *dev = ctx->fimc_dev;
315  struct fimc_variant *variant = dev->variant;
316  struct fimc_scaler *sc = &ctx->scaler;
317  u32 cfg;
318 
319  dbg("main_hratio= 0x%X main_vratio= 0x%X",
320  sc->main_hratio, sc->main_vratio);
321 
322  fimc_hw_set_scaler(ctx);
323 
324  cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
327 
328  if (variant->has_mainscaler_ext) {
331  writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
332 
333  cfg = readl(dev->regs + FIMC_REG_CIEXTEN);
334 
339  writel(cfg, dev->regs + FIMC_REG_CIEXTEN);
340  } else {
343  writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
344  }
345 }
346 
347 void fimc_hw_en_capture(struct fimc_ctx *ctx)
348 {
349  struct fimc_dev *dev = ctx->fimc_dev;
350 
351  u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
352 
353  if (ctx->out_path == FIMC_IO_DMA) {
354  /* one shot mode */
357  } else {
358  /* Continuous frame capture mode (freerun). */
362  }
363 
364  if (ctx->scaler.enabled)
366 
368  writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
369 }
370 
371 void fimc_hw_set_effect(struct fimc_ctx *ctx)
372 {
373  struct fimc_dev *dev = ctx->fimc_dev;
374  struct fimc_effect *effect = &ctx->effect;
375  u32 cfg = 0;
376 
377  if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
380  cfg |= effect->type;
381  if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY)
382  cfg |= (effect->pat_cb << 13) | effect->pat_cr;
383  }
384 
385  writel(cfg, dev->regs + FIMC_REG_CIIMGEFF);
386 }
387 
389 {
390  struct fimc_dev *dev = ctx->fimc_dev;
391  struct fimc_frame *frame = &ctx->d_frame;
392  u32 cfg;
393 
394  if (!(frame->fmt->flags & FMT_HAS_ALPHA))
395  return;
396 
397  cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
399  cfg |= (frame->alpha << 4);
400  writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
401 }
402 
403 static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
404 {
405  struct fimc_dev *dev = ctx->fimc_dev;
406  struct fimc_frame *frame = &ctx->s_frame;
407  u32 cfg_o = 0;
408  u32 cfg_r = 0;
409 
410  if (FIMC_IO_LCDFIFO == ctx->out_path)
412 
413  cfg_o |= (frame->f_height << 16) | frame->f_width;
414  cfg_r |= (frame->height << 16) | frame->width;
415 
416  writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE);
417  writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE);
418 }
419 
420 void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
421 {
422  struct fimc_dev *dev = ctx->fimc_dev;
423  struct fimc_frame *frame = &ctx->s_frame;
424  struct fimc_dma_offset *offset = &frame->dma_offset;
425  u32 cfg;
426 
427  /* Set the pixel offsets. */
428  cfg = (offset->y_v << 16) | offset->y_h;
429  writel(cfg, dev->regs + FIMC_REG_CIIYOFF);
430 
431  cfg = (offset->cb_v << 16) | offset->cb_h;
432  writel(cfg, dev->regs + FIMC_REG_CIICBOFF);
433 
434  cfg = (offset->cr_v << 16) | offset->cr_h;
435  writel(cfg, dev->regs + FIMC_REG_CIICROFF);
436 
437  /* Input original and real size. */
438  fimc_hw_set_in_dma_size(ctx);
439 
440  /* Use DMA autoload only in FIFO mode. */
441  fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO);
442 
443  /* Set the input DMA to process single frame only. */
444  cfg = readl(dev->regs + FIMC_REG_MSCTRL);
450 
454 
455  switch (frame->fmt->color) {
456  case FIMC_FMT_RGB565...FIMC_FMT_RGB888:
458  break;
459  case FIMC_FMT_YCBCR420:
461 
462  if (frame->fmt->colplanes == 2)
464  else
466 
467  break;
468  case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
469  if (frame->fmt->colplanes == 1) {
470  cfg |= ctx->in_order_1p
472  } else {
474 
475  if (frame->fmt->colplanes == 2)
476  cfg |= ctx->in_order_2p
478  else
480  }
481  break;
482  default:
483  break;
484  }
485 
486  writel(cfg, dev->regs + FIMC_REG_MSCTRL);
487 
488  /* Input/output DMA linear/tiled mode. */
489  cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM);
491 
492  if (tiled_fmt(ctx->s_frame.fmt))
494 
495  if (tiled_fmt(ctx->d_frame.fmt))
497 
498  writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM);
499 }
500 
501 
503 {
504  struct fimc_dev *dev = ctx->fimc_dev;
505 
506  u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
508 
509  if (ctx->in_path == FIMC_IO_DMA)
511  else
513 
514  writel(cfg, dev->regs + FIMC_REG_MSCTRL);
515 }
516 
518 {
519  struct fimc_dev *dev = ctx->fimc_dev;
520 
521  u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
523  if (ctx->out_path == FIMC_IO_LCDFIFO)
525  writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
526 }
527 
528 void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
529 {
530  u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE);
532  writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
533 
534  writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0));
535  writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0));
536  writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0));
537 
539  writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
540 }
541 
543  struct fimc_addr *paddr, int index)
544 {
545  int i = (index == -1) ? 0 : index;
546  do {
547  writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i));
548  writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i));
549  writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i));
550  dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
551  i, paddr->y, paddr->cb, paddr->cr);
552  } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
553 }
554 
556  struct s5p_fimc_isp_info *cam)
557 {
558  u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
559 
563 
566 
569 
572 
575 
576  if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
578 
579  writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
580 
581  return 0;
582 }
583 
588 };
589 
590 static const struct mbus_pixfmt_desc pix_desc[] = {
595 };
596 
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  if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
606  for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
607  if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
608  cfg = pix_desc[i].cisrcfmt;
609  bus_width = pix_desc[i].bus_width;
610  break;
611  }
612  }
613 
614  if (i == ARRAY_SIZE(pix_desc)) {
615  v4l2_err(&fimc->vid_cap.vfd,
616  "Camera color format not supported: %d\n",
617  fimc->vid_cap.mf.code);
618  return -EINVAL;
619  }
620 
621  if (cam->bus_type == FIMC_ITU_601) {
622  if (bus_width == 8)
624  else if (bus_width == 16)
626  } /* else defaults to ITU-R BT.656 8-bit */
627  } else if (cam->bus_type == FIMC_MIPI_CSI2) {
628  if (fimc_fmt_is_user_defined(f->fmt->color))
630  }
631 
632  cfg |= (f->o_width << 16) | f->o_height;
633  writel(cfg, fimc->regs + FIMC_REG_CISRCFMT);
634  return 0;
635 }
636 
637 void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
638 {
639  u32 hoff2, voff2;
640 
641  u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST);
642 
644  cfg |= FIMC_REG_CIWDOFST_OFF_EN |
645  (f->offs_h << 16) | f->offs_v;
646 
647  writel(cfg, fimc->regs + FIMC_REG_CIWDOFST);
648 
649  /* See CIWDOFSTn register description in the datasheet for details. */
650  hoff2 = f->o_width - f->width - f->offs_h;
651  voff2 = f->o_height - f->height - f->offs_v;
652  cfg = (hoff2 << 16) | voff2;
653  writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2);
654 }
655 
657  struct s5p_fimc_isp_info *cam)
658 {
659  u32 cfg, tmp;
660  struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
661  u32 csis_data_alignment = 32;
662 
663  cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
664 
665  /* Select ITU B interface, disable Writeback path and test pattern. */
669 
670  switch (cam->bus_type) {
671  case FIMC_MIPI_CSI2:
673 
674  if (cam->mux_id == 0)
676 
677  /* TODO: add remaining supported formats. */
678  switch (vid_cap->mf.code) {
681  break;
684  tmp = FIMC_REG_CSIIMGFMT_USER(1);
686  break;
687  default:
688  v4l2_err(&vid_cap->vfd,
689  "Not supported camera pixel format: %#x\n",
690  vid_cap->mf.code);
691  return -EINVAL;
692  }
693  tmp |= (csis_data_alignment == 32) << 8;
694 
695  writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
696  break;
697  case FIMC_ITU_601...FIMC_ITU_656:
698  if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
700  break;
701  case FIMC_LCD_WB:
703  break;
704  default:
705  v4l2_err(&vid_cap->vfd, "Invalid camera bus type selected\n");
706  return -EINVAL;
707  }
708  writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
709 
710  return 0;
711 }
712 
713 void fimc_hw_clear_irq(struct fimc_dev *dev)
714 {
715  u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
717  writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
718 }
719 
720 void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
721 {
722  u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
723  if (on)
725  else
727  writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
728 }
729 
730 void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
731 {
732  u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
733  if (on)
734  cfg |= FIMC_REG_MSCTRL_ENVID;
735  else
736  cfg &= ~FIMC_REG_MSCTRL_ENVID;
737  writel(cfg, dev->regs + FIMC_REG_MSCTRL);
738 }
739 
740 void fimc_hw_dis_capture(struct fimc_dev *dev)
741 {
742  u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
744  writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
745 }
746 
747 /* Return an index to the buffer actually being written. */
749 {
750  s32 reg;
751 
752  if (dev->variant->has_cistatus2) {
753  reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f;
754  return reg - 1;
755  }
756 
757  reg = readl(dev->regs + FIMC_REG_CISTATUS);
758 
759  return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >>
761 }
762 
763 /* Return an index to the buffer being written previously. */
765 {
766  s32 reg;
767 
768  if (!dev->variant->has_cistatus2)
769  return -1;
770 
771  reg = readl(dev->regs + FIMC_REG_CISTATUS2);
772  return ((reg >> 7) & 0x3f) - 1;
773 }
774 
775 /* Locking: the caller holds fimc->slock */
777 {
778  fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
779  fimc_hw_en_capture(ctx);
780 }
781 
783 {
784  fimc_hw_en_lastirq(fimc, true);
785  fimc_hw_dis_capture(fimc);
786  fimc_hw_enable_scaler(fimc, false);
787  fimc_hw_en_lastirq(fimc, false);
788 }