2 * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
4 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
5 * Author: 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.
12 #include <linux/bitops.h>
13 #include <linux/delay.h>
15 #include <media/drv-intf/exynos-fimc.h>
17 #include "fimc-lite-reg.h"
18 #include "fimc-lite.h"
19 #include "fimc-core.h"
21 #define FLITE_RESET_TIMEOUT 50 /* in ms */
23 void flite_hw_reset(struct fimc_lite
*dev
)
25 unsigned long end
= jiffies
+ msecs_to_jiffies(FLITE_RESET_TIMEOUT
);
28 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
29 cfg
|= FLITE_REG_CIGCTRL_SWRST_REQ
;
30 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
32 while (time_is_after_jiffies(end
)) {
33 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
34 if (cfg
& FLITE_REG_CIGCTRL_SWRST_RDY
)
36 usleep_range(1000, 5000);
39 cfg
|= FLITE_REG_CIGCTRL_SWRST
;
40 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
43 void flite_hw_clear_pending_irq(struct fimc_lite
*dev
)
45 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
46 cfg
&= ~FLITE_REG_CISTATUS_IRQ_CAM
;
47 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS
);
50 u32
flite_hw_get_interrupt_source(struct fimc_lite
*dev
)
52 u32 intsrc
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
53 return intsrc
& FLITE_REG_CISTATUS_IRQ_MASK
;
56 void flite_hw_clear_last_capture_end(struct fimc_lite
*dev
)
59 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS2
);
60 cfg
&= ~FLITE_REG_CISTATUS2_LASTCAPEND
;
61 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS2
);
64 void flite_hw_set_interrupt_mask(struct fimc_lite
*dev
)
68 /* Select interrupts to be enabled for each output mode */
69 if (atomic_read(&dev
->out_path
) == FIMC_IO_DMA
) {
70 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
71 FLITE_REG_CIGCTRL_IRQ_LASTEN
|
72 FLITE_REG_CIGCTRL_IRQ_STARTEN
|
73 FLITE_REG_CIGCTRL_IRQ_ENDEN
;
75 /* An output to the FIMC-IS */
76 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
77 FLITE_REG_CIGCTRL_IRQ_LASTEN
;
80 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
81 cfg
|= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK
;
83 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
86 void flite_hw_capture_start(struct fimc_lite
*dev
)
88 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
89 cfg
|= FLITE_REG_CIIMGCPT_IMGCPTEN
;
90 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
93 void flite_hw_capture_stop(struct fimc_lite
*dev
)
95 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
96 cfg
&= ~FLITE_REG_CIIMGCPT_IMGCPTEN
;
97 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
101 * Test pattern (color bars) enable/disable. External sensor
102 * pixel clock must be active for the test pattern to work.
104 void flite_hw_set_test_pattern(struct fimc_lite
*dev
, bool on
)
106 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
108 cfg
|= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
110 cfg
&= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
111 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
114 static const u32 src_pixfmt_map
[8][3] = {
115 { MEDIA_BUS_FMT_YUYV8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR
,
116 FLITE_REG_CIGCTRL_YUV422_1P
},
117 { MEDIA_BUS_FMT_YVYU8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB
,
118 FLITE_REG_CIGCTRL_YUV422_1P
},
119 { MEDIA_BUS_FMT_UYVY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY
,
120 FLITE_REG_CIGCTRL_YUV422_1P
},
121 { MEDIA_BUS_FMT_VYUY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY
,
122 FLITE_REG_CIGCTRL_YUV422_1P
},
123 { MEDIA_BUS_FMT_SGRBG8_1X8
, 0, FLITE_REG_CIGCTRL_RAW8
},
124 { MEDIA_BUS_FMT_SGRBG10_1X10
, 0, FLITE_REG_CIGCTRL_RAW10
},
125 { MEDIA_BUS_FMT_SGRBG12_1X12
, 0, FLITE_REG_CIGCTRL_RAW12
},
126 { MEDIA_BUS_FMT_JPEG_1X8
, 0, FLITE_REG_CIGCTRL_USER(1) },
129 /* Set camera input pixel format and resolution */
130 void flite_hw_set_source_format(struct fimc_lite
*dev
, struct flite_frame
*f
)
132 u32 pixelcode
= f
->fmt
->mbus_code
;
133 int i
= ARRAY_SIZE(src_pixfmt_map
);
137 if (src_pixfmt_map
[i
][0] == pixelcode
)
141 if (i
== 0 && src_pixfmt_map
[i
][0] != pixelcode
) {
142 v4l2_err(&dev
->ve
.vdev
,
143 "Unsupported pixel code, falling back to %#08x\n",
144 src_pixfmt_map
[i
][0]);
147 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
148 cfg
&= ~FLITE_REG_CIGCTRL_FMT_MASK
;
149 cfg
|= src_pixfmt_map
[i
][2];
150 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
152 cfg
= readl(dev
->regs
+ FLITE_REG_CISRCSIZE
);
153 cfg
&= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK
|
154 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK
);
155 cfg
|= (f
->f_width
<< 16) | f
->f_height
;
156 cfg
|= src_pixfmt_map
[i
][1];
157 writel(cfg
, dev
->regs
+ FLITE_REG_CISRCSIZE
);
160 /* Set the camera host input window offsets (cropping) */
161 void flite_hw_set_window_offset(struct fimc_lite
*dev
, struct flite_frame
*f
)
166 cfg
= readl(dev
->regs
+ FLITE_REG_CIWDOFST
);
167 cfg
&= ~FLITE_REG_CIWDOFST_OFST_MASK
;
168 cfg
|= (f
->rect
.left
<< 16) | f
->rect
.top
;
169 cfg
|= FLITE_REG_CIWDOFST_WINOFSEN
;
170 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST
);
172 hoff2
= f
->f_width
- f
->rect
.width
- f
->rect
.left
;
173 voff2
= f
->f_height
- f
->rect
.height
- f
->rect
.top
;
175 cfg
= (hoff2
<< 16) | voff2
;
176 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST2
);
179 /* Select camera port (A, B) */
180 static void flite_hw_set_camera_port(struct fimc_lite
*dev
, int id
)
182 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGENERAL
);
184 cfg
&= ~FLITE_REG_CIGENERAL_CAM_B
;
186 cfg
|= FLITE_REG_CIGENERAL_CAM_B
;
187 writel(cfg
, dev
->regs
+ FLITE_REG_CIGENERAL
);
190 /* Select serial or parallel bus, camera port (A,B) and set signals polarity */
191 void flite_hw_set_camera_bus(struct fimc_lite
*dev
,
192 struct fimc_source_info
*si
)
194 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
195 unsigned int flags
= si
->flags
;
197 if (si
->sensor_bus_type
!= FIMC_BUS_TYPE_MIPI_CSI2
) {
198 cfg
&= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI
|
199 FLITE_REG_CIGCTRL_INVPOLPCLK
|
200 FLITE_REG_CIGCTRL_INVPOLVSYNC
|
201 FLITE_REG_CIGCTRL_INVPOLHREF
);
203 if (flags
& V4L2_MBUS_PCLK_SAMPLE_FALLING
)
204 cfg
|= FLITE_REG_CIGCTRL_INVPOLPCLK
;
206 if (flags
& V4L2_MBUS_VSYNC_ACTIVE_LOW
)
207 cfg
|= FLITE_REG_CIGCTRL_INVPOLVSYNC
;
209 if (flags
& V4L2_MBUS_HSYNC_ACTIVE_LOW
)
210 cfg
|= FLITE_REG_CIGCTRL_INVPOLHREF
;
212 cfg
|= FLITE_REG_CIGCTRL_SELCAM_MIPI
;
215 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
217 flite_hw_set_camera_port(dev
, si
->mux_id
);
220 static void flite_hw_set_pack12(struct fimc_lite
*dev
, int on
)
222 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIODMAFMT
);
224 cfg
&= ~FLITE_REG_CIODMAFMT_PACK12
;
227 cfg
|= FLITE_REG_CIODMAFMT_PACK12
;
229 writel(cfg
, dev
->regs
+ FLITE_REG_CIODMAFMT
);
232 static void flite_hw_set_out_order(struct fimc_lite
*dev
, struct flite_frame
*f
)
234 static const u32 pixcode
[4][2] = {
235 { MEDIA_BUS_FMT_YUYV8_2X8
, FLITE_REG_CIODMAFMT_YCBYCR
},
236 { MEDIA_BUS_FMT_YVYU8_2X8
, FLITE_REG_CIODMAFMT_YCRYCB
},
237 { MEDIA_BUS_FMT_UYVY8_2X8
, FLITE_REG_CIODMAFMT_CBYCRY
},
238 { MEDIA_BUS_FMT_VYUY8_2X8
, FLITE_REG_CIODMAFMT_CRYCBY
},
240 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIODMAFMT
);
241 int i
= ARRAY_SIZE(pixcode
);
244 if (pixcode
[i
][0] == f
->fmt
->mbus_code
)
246 cfg
&= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK
;
247 writel(cfg
| pixcode
[i
][1], dev
->regs
+ FLITE_REG_CIODMAFMT
);
250 void flite_hw_set_dma_window(struct fimc_lite
*dev
, struct flite_frame
*f
)
254 /* Maximum output pixel size */
255 cfg
= readl(dev
->regs
+ FLITE_REG_CIOCAN
);
256 cfg
&= ~FLITE_REG_CIOCAN_MASK
;
257 cfg
= (f
->f_height
<< 16) | f
->f_width
;
258 writel(cfg
, dev
->regs
+ FLITE_REG_CIOCAN
);
261 cfg
= readl(dev
->regs
+ FLITE_REG_CIOOFF
);
262 cfg
&= ~FLITE_REG_CIOOFF_MASK
;
263 cfg
|= (f
->rect
.top
<< 16) | f
->rect
.left
;
264 writel(cfg
, dev
->regs
+ FLITE_REG_CIOOFF
);
267 void flite_hw_set_dma_buffer(struct fimc_lite
*dev
, struct flite_buffer
*buf
)
272 if (dev
->dd
->max_dma_bufs
== 1)
278 writel(buf
->paddr
, dev
->regs
+ FLITE_REG_CIOSA
);
280 writel(buf
->paddr
, dev
->regs
+ FLITE_REG_CIOSAN(index
- 1));
282 cfg
= readl(dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
284 writel(cfg
, dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
287 void flite_hw_mask_dma_buffer(struct fimc_lite
*dev
, u32 index
)
291 if (dev
->dd
->max_dma_bufs
== 1)
294 cfg
= readl(dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
296 writel(cfg
, dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
299 /* Enable/disable output DMA, set output pixel size and offsets (composition) */
300 void flite_hw_set_output_dma(struct fimc_lite
*dev
, struct flite_frame
*f
,
303 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
306 cfg
|= FLITE_REG_CIGCTRL_ODMA_DISABLE
;
307 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
311 cfg
&= ~FLITE_REG_CIGCTRL_ODMA_DISABLE
;
312 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
314 flite_hw_set_out_order(dev
, f
);
315 flite_hw_set_dma_window(dev
, f
);
316 flite_hw_set_pack12(dev
, 0);
319 void flite_hw_dump_regs(struct fimc_lite
*dev
, const char *label
)
323 const char * const name
;
325 { 0x00, "CISRCSIZE" },
327 { 0x08, "CIIMGCPT" },
328 { 0x0c, "CICPTSEQ" },
329 { 0x10, "CIWDOFST" },
330 { 0x14, "CIWDOFST2" },
331 { 0x18, "CIODMAFMT" },
335 { 0x40, "CISTATUS" },
336 { 0x44, "CISTATUS2" },
338 { 0xfc, "CIGENERAL" },
342 v4l2_info(&dev
->subdev
, "--- %s ---\n", label
);
344 for (i
= 0; i
< ARRAY_SIZE(registers
); i
++) {
345 u32 cfg
= readl(dev
->regs
+ registers
[i
].offset
);
346 v4l2_info(&dev
->subdev
, "%9s: 0x%08x\n",
347 registers
[i
].name
, cfg
);