2 * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
4 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
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.
13 #include <linux/delay.h>
14 #include <media/s5p_fimc.h>
16 #include "fimc-lite-reg.h"
17 #include "fimc-lite.h"
18 #include "fimc-core.h"
20 #define FLITE_RESET_TIMEOUT 50 /* in ms */
22 void flite_hw_reset(struct fimc_lite
*dev
)
24 unsigned long end
= jiffies
+ msecs_to_jiffies(FLITE_RESET_TIMEOUT
);
27 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
28 cfg
|= FLITE_REG_CIGCTRL_SWRST_REQ
;
29 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
31 while (time_is_after_jiffies(end
)) {
32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
33 if (cfg
& FLITE_REG_CIGCTRL_SWRST_RDY
)
35 usleep_range(1000, 5000);
38 cfg
|= FLITE_REG_CIGCTRL_SWRST
;
39 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
42 void flite_hw_clear_pending_irq(struct fimc_lite
*dev
)
44 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
45 cfg
&= ~FLITE_REG_CISTATUS_IRQ_CAM
;
46 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS
);
49 u32
flite_hw_get_interrupt_source(struct fimc_lite
*dev
)
51 u32 intsrc
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
52 return intsrc
& FLITE_REG_CISTATUS_IRQ_MASK
;
55 void flite_hw_clear_last_capture_end(struct fimc_lite
*dev
)
58 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS2
);
59 cfg
&= ~FLITE_REG_CISTATUS2_LASTCAPEND
;
60 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS2
);
63 void flite_hw_set_interrupt_mask(struct fimc_lite
*dev
)
67 /* Select interrupts to be enabled for each output mode */
68 if (atomic_read(&dev
->out_path
) == FIMC_IO_DMA
) {
69 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
70 FLITE_REG_CIGCTRL_IRQ_LASTEN
|
71 FLITE_REG_CIGCTRL_IRQ_STARTEN
;
73 /* An output to the FIMC-IS */
74 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
75 FLITE_REG_CIGCTRL_IRQ_LASTEN
;
78 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
79 cfg
|= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK
;
81 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
84 void flite_hw_capture_start(struct fimc_lite
*dev
)
86 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
87 cfg
|= FLITE_REG_CIIMGCPT_IMGCPTEN
;
88 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
91 void flite_hw_capture_stop(struct fimc_lite
*dev
)
93 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
94 cfg
&= ~FLITE_REG_CIIMGCPT_IMGCPTEN
;
95 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
99 * Test pattern (color bars) enable/disable. External sensor
100 * pixel clock must be active for the test pattern to work.
102 void flite_hw_set_test_pattern(struct fimc_lite
*dev
, bool on
)
104 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
106 cfg
|= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
108 cfg
&= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
109 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
112 static const u32 src_pixfmt_map
[8][3] = {
113 { V4L2_MBUS_FMT_YUYV8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR
,
114 FLITE_REG_CIGCTRL_YUV422_1P
},
115 { V4L2_MBUS_FMT_YVYU8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB
,
116 FLITE_REG_CIGCTRL_YUV422_1P
},
117 { V4L2_MBUS_FMT_UYVY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY
,
118 FLITE_REG_CIGCTRL_YUV422_1P
},
119 { V4L2_MBUS_FMT_VYUY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY
,
120 FLITE_REG_CIGCTRL_YUV422_1P
},
121 { V4L2_MBUS_FMT_SGRBG8_1X8
, 0, FLITE_REG_CIGCTRL_RAW8
},
122 { V4L2_MBUS_FMT_SGRBG10_1X10
, 0, FLITE_REG_CIGCTRL_RAW10
},
123 { V4L2_MBUS_FMT_SGRBG12_1X12
, 0, FLITE_REG_CIGCTRL_RAW12
},
124 { V4L2_MBUS_FMT_JPEG_1X8
, 0, FLITE_REG_CIGCTRL_USER(1) },
127 /* Set camera input pixel format and resolution */
128 void flite_hw_set_source_format(struct fimc_lite
*dev
, struct flite_frame
*f
)
130 enum v4l2_mbus_pixelcode pixelcode
= f
->fmt
->mbus_code
;
131 int i
= ARRAY_SIZE(src_pixfmt_map
);
135 if (src_pixfmt_map
[i
][0] == pixelcode
)
139 if (i
== 0 && src_pixfmt_map
[i
][0] != pixelcode
) {
141 "Unsupported pixel code, falling back to %#08x\n",
142 src_pixfmt_map
[i
][0]);
145 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
146 cfg
&= ~FLITE_REG_CIGCTRL_FMT_MASK
;
147 cfg
|= src_pixfmt_map
[i
][2];
148 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
150 cfg
= readl(dev
->regs
+ FLITE_REG_CISRCSIZE
);
151 cfg
&= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK
|
152 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK
);
153 cfg
|= (f
->f_width
<< 16) | f
->f_height
;
154 cfg
|= src_pixfmt_map
[i
][1];
155 writel(cfg
, dev
->regs
+ FLITE_REG_CISRCSIZE
);
158 /* Set the camera host input window offsets (cropping) */
159 void flite_hw_set_window_offset(struct fimc_lite
*dev
, struct flite_frame
*f
)
164 cfg
= readl(dev
->regs
+ FLITE_REG_CIWDOFST
);
165 cfg
&= ~FLITE_REG_CIWDOFST_OFST_MASK
;
166 cfg
|= (f
->rect
.left
<< 16) | f
->rect
.top
;
167 cfg
|= FLITE_REG_CIWDOFST_WINOFSEN
;
168 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST
);
170 hoff2
= f
->f_width
- f
->rect
.width
- f
->rect
.left
;
171 voff2
= f
->f_height
- f
->rect
.height
- f
->rect
.top
;
173 cfg
= (hoff2
<< 16) | voff2
;
174 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST2
);
177 /* Select camera port (A, B) */
178 static void flite_hw_set_camera_port(struct fimc_lite
*dev
, int id
)
180 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGENERAL
);
182 cfg
&= ~FLITE_REG_CIGENERAL_CAM_B
;
184 cfg
|= FLITE_REG_CIGENERAL_CAM_B
;
185 writel(cfg
, dev
->regs
+ FLITE_REG_CIGENERAL
);
188 /* Select serial or parallel bus, camera port (A,B) and set signals polarity */
189 void flite_hw_set_camera_bus(struct fimc_lite
*dev
,
190 struct fimc_source_info
*si
)
192 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
193 unsigned int flags
= si
->flags
;
195 if (si
->sensor_bus_type
!= FIMC_BUS_TYPE_MIPI_CSI2
) {
196 cfg
&= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI
|
197 FLITE_REG_CIGCTRL_INVPOLPCLK
|
198 FLITE_REG_CIGCTRL_INVPOLVSYNC
|
199 FLITE_REG_CIGCTRL_INVPOLHREF
);
201 if (flags
& V4L2_MBUS_PCLK_SAMPLE_FALLING
)
202 cfg
|= FLITE_REG_CIGCTRL_INVPOLPCLK
;
204 if (flags
& V4L2_MBUS_VSYNC_ACTIVE_LOW
)
205 cfg
|= FLITE_REG_CIGCTRL_INVPOLVSYNC
;
207 if (flags
& V4L2_MBUS_HSYNC_ACTIVE_LOW
)
208 cfg
|= FLITE_REG_CIGCTRL_INVPOLHREF
;
210 cfg
|= FLITE_REG_CIGCTRL_SELCAM_MIPI
;
213 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
215 flite_hw_set_camera_port(dev
, si
->mux_id
);
218 static void flite_hw_set_out_order(struct fimc_lite
*dev
, struct flite_frame
*f
)
220 static const u32 pixcode
[4][2] = {
221 { V4L2_MBUS_FMT_YUYV8_2X8
, FLITE_REG_CIODMAFMT_YCBYCR
},
222 { V4L2_MBUS_FMT_YVYU8_2X8
, FLITE_REG_CIODMAFMT_YCRYCB
},
223 { V4L2_MBUS_FMT_UYVY8_2X8
, FLITE_REG_CIODMAFMT_CBYCRY
},
224 { V4L2_MBUS_FMT_VYUY8_2X8
, FLITE_REG_CIODMAFMT_CRYCBY
},
226 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIODMAFMT
);
227 int i
= ARRAY_SIZE(pixcode
);
230 if (pixcode
[i
][0] == f
->fmt
->mbus_code
)
232 cfg
&= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK
;
233 writel(cfg
| pixcode
[i
][1], dev
->regs
+ FLITE_REG_CIODMAFMT
);
236 void flite_hw_set_dma_window(struct fimc_lite
*dev
, struct flite_frame
*f
)
240 /* Maximum output pixel size */
241 cfg
= readl(dev
->regs
+ FLITE_REG_CIOCAN
);
242 cfg
&= ~FLITE_REG_CIOCAN_MASK
;
243 cfg
= (f
->f_height
<< 16) | f
->f_width
;
244 writel(cfg
, dev
->regs
+ FLITE_REG_CIOCAN
);
247 cfg
= readl(dev
->regs
+ FLITE_REG_CIOOFF
);
248 cfg
&= ~FLITE_REG_CIOOFF_MASK
;
249 cfg
|= (f
->rect
.top
<< 16) | f
->rect
.left
;
250 writel(cfg
, dev
->regs
+ FLITE_REG_CIOOFF
);
253 /* Enable/disable output DMA, set output pixel size and offsets (composition) */
254 void flite_hw_set_output_dma(struct fimc_lite
*dev
, struct flite_frame
*f
,
257 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
260 cfg
|= FLITE_REG_CIGCTRL_ODMA_DISABLE
;
261 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
265 cfg
&= ~FLITE_REG_CIGCTRL_ODMA_DISABLE
;
266 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
268 flite_hw_set_out_order(dev
, f
);
269 flite_hw_set_dma_window(dev
, f
);
272 void flite_hw_dump_regs(struct fimc_lite
*dev
, const char *label
)
276 const char * const name
;
278 { 0x00, "CISRCSIZE" },
280 { 0x08, "CIIMGCPT" },
281 { 0x0c, "CICPTSEQ" },
282 { 0x10, "CIWDOFST" },
283 { 0x14, "CIWDOFST2" },
284 { 0x18, "CIODMAFMT" },
288 { 0x40, "CISTATUS" },
289 { 0x44, "CISTATUS2" },
291 { 0xfc, "CIGENERAL" },
295 v4l2_info(&dev
->subdev
, "--- %s ---\n", label
);
297 for (i
= 0; i
< ARRAY_SIZE(registers
); i
++) {
298 u32 cfg
= readl(dev
->regs
+ registers
[i
].offset
);
299 v4l2_info(&dev
->subdev
, "%9s: 0x%08x\n",
300 registers
[i
].name
, cfg
);