1 // SPDX-License-Identifier: GPL-2.0-only
3 * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
5 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
9 #include <linux/bitops.h>
10 #include <linux/delay.h>
12 #include <media/drv-intf/exynos-fimc.h>
14 #include "fimc-lite-reg.h"
15 #include "fimc-lite.h"
16 #include "fimc-core.h"
18 #define FLITE_RESET_TIMEOUT 50 /* in ms */
20 void flite_hw_reset(struct fimc_lite
*dev
)
22 unsigned long end
= jiffies
+ msecs_to_jiffies(FLITE_RESET_TIMEOUT
);
25 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
26 cfg
|= FLITE_REG_CIGCTRL_SWRST_REQ
;
27 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
29 while (time_is_after_jiffies(end
)) {
30 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
31 if (cfg
& FLITE_REG_CIGCTRL_SWRST_RDY
)
33 usleep_range(1000, 5000);
36 cfg
|= FLITE_REG_CIGCTRL_SWRST
;
37 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
40 void flite_hw_clear_pending_irq(struct fimc_lite
*dev
)
42 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
43 cfg
&= ~FLITE_REG_CISTATUS_IRQ_CAM
;
44 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS
);
47 u32
flite_hw_get_interrupt_source(struct fimc_lite
*dev
)
49 u32 intsrc
= readl(dev
->regs
+ FLITE_REG_CISTATUS
);
50 return intsrc
& FLITE_REG_CISTATUS_IRQ_MASK
;
53 void flite_hw_clear_last_capture_end(struct fimc_lite
*dev
)
56 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CISTATUS2
);
57 cfg
&= ~FLITE_REG_CISTATUS2_LASTCAPEND
;
58 writel(cfg
, dev
->regs
+ FLITE_REG_CISTATUS2
);
61 void flite_hw_set_interrupt_mask(struct fimc_lite
*dev
)
65 /* Select interrupts to be enabled for each output mode */
66 if (atomic_read(&dev
->out_path
) == FIMC_IO_DMA
) {
67 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
68 FLITE_REG_CIGCTRL_IRQ_LASTEN
|
69 FLITE_REG_CIGCTRL_IRQ_STARTEN
|
70 FLITE_REG_CIGCTRL_IRQ_ENDEN
;
72 /* An output to the FIMC-IS */
73 intsrc
= FLITE_REG_CIGCTRL_IRQ_OVFEN
|
74 FLITE_REG_CIGCTRL_IRQ_LASTEN
;
77 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
78 cfg
|= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK
;
80 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
83 void flite_hw_capture_start(struct fimc_lite
*dev
)
85 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
86 cfg
|= FLITE_REG_CIIMGCPT_IMGCPTEN
;
87 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
90 void flite_hw_capture_stop(struct fimc_lite
*dev
)
92 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIIMGCPT
);
93 cfg
&= ~FLITE_REG_CIIMGCPT_IMGCPTEN
;
94 writel(cfg
, dev
->regs
+ FLITE_REG_CIIMGCPT
);
98 * Test pattern (color bars) enable/disable. External sensor
99 * pixel clock must be active for the test pattern to work.
101 void flite_hw_set_test_pattern(struct fimc_lite
*dev
, bool on
)
103 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
105 cfg
|= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
107 cfg
&= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR
;
108 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
111 static const u32 src_pixfmt_map
[8][3] = {
112 { MEDIA_BUS_FMT_YUYV8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR
,
113 FLITE_REG_CIGCTRL_YUV422_1P
},
114 { MEDIA_BUS_FMT_YVYU8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB
,
115 FLITE_REG_CIGCTRL_YUV422_1P
},
116 { MEDIA_BUS_FMT_UYVY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY
,
117 FLITE_REG_CIGCTRL_YUV422_1P
},
118 { MEDIA_BUS_FMT_VYUY8_2X8
, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY
,
119 FLITE_REG_CIGCTRL_YUV422_1P
},
120 { MEDIA_BUS_FMT_SGRBG8_1X8
, 0, FLITE_REG_CIGCTRL_RAW8
},
121 { MEDIA_BUS_FMT_SGRBG10_1X10
, 0, FLITE_REG_CIGCTRL_RAW10
},
122 { MEDIA_BUS_FMT_SGRBG12_1X12
, 0, FLITE_REG_CIGCTRL_RAW12
},
123 { MEDIA_BUS_FMT_JPEG_1X8
, 0, FLITE_REG_CIGCTRL_USER(1) },
126 /* Set camera input pixel format and resolution */
127 void flite_hw_set_source_format(struct fimc_lite
*dev
, struct flite_frame
*f
)
129 u32 pixelcode
= f
->fmt
->mbus_code
;
130 int i
= ARRAY_SIZE(src_pixfmt_map
);
134 if (src_pixfmt_map
[i
][0] == pixelcode
)
138 if (i
== 0 && src_pixfmt_map
[i
][0] != pixelcode
) {
139 v4l2_err(&dev
->ve
.vdev
,
140 "Unsupported pixel code, falling back to %#08x\n",
141 src_pixfmt_map
[i
][0]);
144 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
145 cfg
&= ~FLITE_REG_CIGCTRL_FMT_MASK
;
146 cfg
|= src_pixfmt_map
[i
][2];
147 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
149 cfg
= readl(dev
->regs
+ FLITE_REG_CISRCSIZE
);
150 cfg
&= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK
|
151 FLITE_REG_CISRCSIZE_SIZE_CAM_MASK
);
152 cfg
|= (f
->f_width
<< 16) | f
->f_height
;
153 cfg
|= src_pixfmt_map
[i
][1];
154 writel(cfg
, dev
->regs
+ FLITE_REG_CISRCSIZE
);
157 /* Set the camera host input window offsets (cropping) */
158 void flite_hw_set_window_offset(struct fimc_lite
*dev
, struct flite_frame
*f
)
163 cfg
= readl(dev
->regs
+ FLITE_REG_CIWDOFST
);
164 cfg
&= ~FLITE_REG_CIWDOFST_OFST_MASK
;
165 cfg
|= (f
->rect
.left
<< 16) | f
->rect
.top
;
166 cfg
|= FLITE_REG_CIWDOFST_WINOFSEN
;
167 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST
);
169 hoff2
= f
->f_width
- f
->rect
.width
- f
->rect
.left
;
170 voff2
= f
->f_height
- f
->rect
.height
- f
->rect
.top
;
172 cfg
= (hoff2
<< 16) | voff2
;
173 writel(cfg
, dev
->regs
+ FLITE_REG_CIWDOFST2
);
176 /* Select camera port (A, B) */
177 static void flite_hw_set_camera_port(struct fimc_lite
*dev
, int id
)
179 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGENERAL
);
181 cfg
&= ~FLITE_REG_CIGENERAL_CAM_B
;
183 cfg
|= FLITE_REG_CIGENERAL_CAM_B
;
184 writel(cfg
, dev
->regs
+ FLITE_REG_CIGENERAL
);
187 /* Select serial or parallel bus, camera port (A,B) and set signals polarity */
188 void flite_hw_set_camera_bus(struct fimc_lite
*dev
,
189 struct fimc_source_info
*si
)
191 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
192 unsigned int flags
= si
->flags
;
194 if (si
->sensor_bus_type
!= FIMC_BUS_TYPE_MIPI_CSI2
) {
195 cfg
&= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI
|
196 FLITE_REG_CIGCTRL_INVPOLPCLK
|
197 FLITE_REG_CIGCTRL_INVPOLVSYNC
|
198 FLITE_REG_CIGCTRL_INVPOLHREF
);
200 if (flags
& V4L2_MBUS_PCLK_SAMPLE_FALLING
)
201 cfg
|= FLITE_REG_CIGCTRL_INVPOLPCLK
;
203 if (flags
& V4L2_MBUS_VSYNC_ACTIVE_LOW
)
204 cfg
|= FLITE_REG_CIGCTRL_INVPOLVSYNC
;
206 if (flags
& V4L2_MBUS_HSYNC_ACTIVE_LOW
)
207 cfg
|= FLITE_REG_CIGCTRL_INVPOLHREF
;
209 cfg
|= FLITE_REG_CIGCTRL_SELCAM_MIPI
;
212 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
214 flite_hw_set_camera_port(dev
, si
->mux_id
);
217 static void flite_hw_set_pack12(struct fimc_lite
*dev
, int on
)
219 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIODMAFMT
);
221 cfg
&= ~FLITE_REG_CIODMAFMT_PACK12
;
224 cfg
|= FLITE_REG_CIODMAFMT_PACK12
;
226 writel(cfg
, dev
->regs
+ FLITE_REG_CIODMAFMT
);
229 static void flite_hw_set_out_order(struct fimc_lite
*dev
, struct flite_frame
*f
)
231 static const u32 pixcode
[4][2] = {
232 { MEDIA_BUS_FMT_YUYV8_2X8
, FLITE_REG_CIODMAFMT_YCBYCR
},
233 { MEDIA_BUS_FMT_YVYU8_2X8
, FLITE_REG_CIODMAFMT_YCRYCB
},
234 { MEDIA_BUS_FMT_UYVY8_2X8
, FLITE_REG_CIODMAFMT_CBYCRY
},
235 { MEDIA_BUS_FMT_VYUY8_2X8
, FLITE_REG_CIODMAFMT_CRYCBY
},
237 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIODMAFMT
);
238 int i
= ARRAY_SIZE(pixcode
);
241 if (pixcode
[i
][0] == f
->fmt
->mbus_code
)
243 cfg
&= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK
;
244 writel(cfg
| pixcode
[i
][1], dev
->regs
+ FLITE_REG_CIODMAFMT
);
247 void flite_hw_set_dma_window(struct fimc_lite
*dev
, struct flite_frame
*f
)
251 /* Maximum output pixel size */
252 cfg
= readl(dev
->regs
+ FLITE_REG_CIOCAN
);
253 cfg
&= ~FLITE_REG_CIOCAN_MASK
;
254 cfg
|= (f
->f_height
<< 16) | f
->f_width
;
255 writel(cfg
, dev
->regs
+ FLITE_REG_CIOCAN
);
258 cfg
= readl(dev
->regs
+ FLITE_REG_CIOOFF
);
259 cfg
&= ~FLITE_REG_CIOOFF_MASK
;
260 cfg
|= (f
->rect
.top
<< 16) | f
->rect
.left
;
261 writel(cfg
, dev
->regs
+ FLITE_REG_CIOOFF
);
264 void flite_hw_set_dma_buffer(struct fimc_lite
*dev
, struct flite_buffer
*buf
)
269 if (dev
->dd
->max_dma_bufs
== 1)
275 writel(buf
->addr
, dev
->regs
+ FLITE_REG_CIOSA
);
277 writel(buf
->addr
, dev
->regs
+ FLITE_REG_CIOSAN(index
- 1));
279 cfg
= readl(dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
281 writel(cfg
, dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
284 void flite_hw_mask_dma_buffer(struct fimc_lite
*dev
, u32 index
)
288 if (dev
->dd
->max_dma_bufs
== 1)
291 cfg
= readl(dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
293 writel(cfg
, dev
->regs
+ FLITE_REG_CIFCNTSEQ
);
296 /* Enable/disable output DMA, set output pixel size and offsets (composition) */
297 void flite_hw_set_output_dma(struct fimc_lite
*dev
, struct flite_frame
*f
,
300 u32 cfg
= readl(dev
->regs
+ FLITE_REG_CIGCTRL
);
303 cfg
|= FLITE_REG_CIGCTRL_ODMA_DISABLE
;
304 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
308 cfg
&= ~FLITE_REG_CIGCTRL_ODMA_DISABLE
;
309 writel(cfg
, dev
->regs
+ FLITE_REG_CIGCTRL
);
311 flite_hw_set_out_order(dev
, f
);
312 flite_hw_set_dma_window(dev
, f
);
313 flite_hw_set_pack12(dev
, 0);
316 void flite_hw_dump_regs(struct fimc_lite
*dev
, const char *label
)
320 const char * const name
;
322 { 0x00, "CISRCSIZE" },
324 { 0x08, "CIIMGCPT" },
325 { 0x0c, "CICPTSEQ" },
326 { 0x10, "CIWDOFST" },
327 { 0x14, "CIWDOFST2" },
328 { 0x18, "CIODMAFMT" },
332 { 0x40, "CISTATUS" },
333 { 0x44, "CISTATUS2" },
335 { 0xfc, "CIGENERAL" },
339 v4l2_info(&dev
->subdev
, "--- %s ---\n", label
);
341 for (i
= 0; i
< ARRAY_SIZE(registers
); i
++) {
342 u32 cfg
= readl(dev
->regs
+ registers
[i
].offset
);
343 v4l2_info(&dev
->subdev
, "%9s: 0x%08x\n",
344 registers
[i
].name
, cfg
);