1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2012-2014 Mentor Graphics Inc.
4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
6 #include <linux/export.h>
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/platform_device.h>
14 #include <linux/videodev2.h>
15 #include <uapi/linux/v4l2-mediabus.h>
16 #include <linux/clk.h>
17 #include <linux/clk-provider.h>
18 #include <linux/clkdev.h>
26 struct clk
*clk_ipu
; /* IPU bus clock */
32 /* CSI Register Offsets */
33 #define CSI_SENS_CONF 0x0000
34 #define CSI_SENS_FRM_SIZE 0x0004
35 #define CSI_ACT_FRM_SIZE 0x0008
36 #define CSI_OUT_FRM_CTRL 0x000c
37 #define CSI_TST_CTRL 0x0010
38 #define CSI_CCIR_CODE_1 0x0014
39 #define CSI_CCIR_CODE_2 0x0018
40 #define CSI_CCIR_CODE_3 0x001c
41 #define CSI_MIPI_DI 0x0020
42 #define CSI_SKIP 0x0024
43 #define CSI_CPD_CTRL 0x0028
44 #define CSI_CPD_RC(n) (0x002c + ((n)*4))
45 #define CSI_CPD_RS(n) (0x004c + ((n)*4))
46 #define CSI_CPD_GRC(n) (0x005c + ((n)*4))
47 #define CSI_CPD_GRS(n) (0x007c + ((n)*4))
48 #define CSI_CPD_GBC(n) (0x008c + ((n)*4))
49 #define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
50 #define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
51 #define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
52 #define CSI_CPD_OFFSET1 0x00ec
53 #define CSI_CPD_OFFSET2 0x00f0
55 /* CSI Register Fields */
56 #define CSI_SENS_CONF_DATA_FMT_SHIFT 8
57 #define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
58 #define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
59 #define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
60 #define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
61 #define CSI_SENS_CONF_DATA_FMT_BAYER 3L
62 #define CSI_SENS_CONF_DATA_FMT_RGB565 4L
63 #define CSI_SENS_CONF_DATA_FMT_RGB555 5L
64 #define CSI_SENS_CONF_DATA_FMT_RGB444 6L
65 #define CSI_SENS_CONF_DATA_FMT_JPEG 7L
67 #define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
68 #define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
69 #define CSI_SENS_CONF_DATA_POL_SHIFT 2
70 #define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
71 #define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
72 #define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
73 #define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
74 #define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
75 #define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
76 #define CSI_SENS_CONF_DIVRATIO_SHIFT 16
78 #define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
79 #define CSI_SENS_CONF_DATA_DEST_SHIFT 24
80 #define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
81 #define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
82 #define CSI_SENS_CONF_JPEG_EN_SHIFT 28
83 #define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
84 #define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
86 #define CSI_DATA_DEST_IC 2
87 #define CSI_DATA_DEST_IDMAC 4
89 #define CSI_CCIR_ERR_DET_EN 0x01000000
90 #define CSI_HORI_DOWNSIZE_EN 0x80000000
91 #define CSI_VERT_DOWNSIZE_EN 0x40000000
92 #define CSI_TEST_GEN_MODE_EN 0x01000000
94 #define CSI_HSC_MASK 0x1fff0000
95 #define CSI_HSC_SHIFT 16
96 #define CSI_VSC_MASK 0x00000fff
97 #define CSI_VSC_SHIFT 0
99 #define CSI_TEST_GEN_R_MASK 0x000000ff
100 #define CSI_TEST_GEN_R_SHIFT 0
101 #define CSI_TEST_GEN_G_MASK 0x0000ff00
102 #define CSI_TEST_GEN_G_SHIFT 8
103 #define CSI_TEST_GEN_B_MASK 0x00ff0000
104 #define CSI_TEST_GEN_B_SHIFT 16
106 #define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
107 #define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
108 #define CSI_SKIP_SMFC_MASK 0x000000f8
109 #define CSI_SKIP_SMFC_SHIFT 3
110 #define CSI_ID_2_SKIP_MASK 0x00000300
111 #define CSI_ID_2_SKIP_SHIFT 8
113 #define CSI_COLOR_FIRST_ROW_MASK 0x00000002
114 #define CSI_COLOR_FIRST_COMP_MASK 0x00000001
116 /* MIPI CSI-2 data types */
117 #define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
118 #define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
119 #define MIPI_DT_YUV422 0x1e /* UYVY... */
120 #define MIPI_DT_RGB444 0x20
121 #define MIPI_DT_RGB555 0x21
122 #define MIPI_DT_RGB565 0x22
123 #define MIPI_DT_RGB666 0x23
124 #define MIPI_DT_RGB888 0x24
125 #define MIPI_DT_RAW6 0x28
126 #define MIPI_DT_RAW7 0x29
127 #define MIPI_DT_RAW8 0x2a
128 #define MIPI_DT_RAW10 0x2b
129 #define MIPI_DT_RAW12 0x2c
130 #define MIPI_DT_RAW14 0x2d
133 * Bitfield of CSI bus signal polarities and modes.
135 struct ipu_csi_bus_config
{
136 unsigned data_width
:4;
138 unsigned ext_vsync
:1;
139 unsigned vsync_pol
:1;
140 unsigned hsync_pol
:1;
141 unsigned pixclk_pol
:1;
143 unsigned sens_clksrc
:1;
144 unsigned pack_tight
:1;
145 unsigned force_eof
:1;
146 unsigned data_en_pol
:1;
153 * Enumeration of CSI data bus widths.
155 enum ipu_csi_data_width
{
156 IPU_CSI_DATA_WIDTH_4
= 0,
157 IPU_CSI_DATA_WIDTH_8
= 1,
158 IPU_CSI_DATA_WIDTH_10
= 3,
159 IPU_CSI_DATA_WIDTH_12
= 5,
160 IPU_CSI_DATA_WIDTH_16
= 9,
164 * Enumeration of CSI clock modes.
166 enum ipu_csi_clk_mode
{
167 IPU_CSI_CLK_MODE_GATED_CLK
,
168 IPU_CSI_CLK_MODE_NONGATED_CLK
,
169 IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE
,
170 IPU_CSI_CLK_MODE_CCIR656_INTERLACED
,
171 IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR
,
172 IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR
,
173 IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR
,
174 IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR
,
177 static inline u32
ipu_csi_read(struct ipu_csi
*csi
, unsigned offset
)
179 return readl(csi
->base
+ offset
);
182 static inline void ipu_csi_write(struct ipu_csi
*csi
, u32 value
,
185 writel(value
, csi
->base
+ offset
);
189 * Set mclk division ratio for generating test mode mclk. Only used
190 * for test generator.
192 static int ipu_csi_set_testgen_mclk(struct ipu_csi
*csi
, u32 pixel_clk
,
198 div_ratio
= (ipu_clk
/ pixel_clk
) - 1;
200 if (div_ratio
> 0xFF || div_ratio
< 0) {
201 dev_err(csi
->ipu
->dev
,
202 "value of pixel_clk extends normal range\n");
206 temp
= ipu_csi_read(csi
, CSI_SENS_CONF
);
207 temp
&= ~CSI_SENS_CONF_DIVRATIO_MASK
;
208 ipu_csi_write(csi
, temp
| (div_ratio
<< CSI_SENS_CONF_DIVRATIO_SHIFT
),
215 * Find the CSI data format and data width for the given V4L2 media
216 * bus pixel format code.
218 static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config
*cfg
, u32 mbus_code
,
219 enum v4l2_mbus_type mbus_type
)
222 case MEDIA_BUS_FMT_BGR565_2X8_BE
:
223 case MEDIA_BUS_FMT_BGR565_2X8_LE
:
224 case MEDIA_BUS_FMT_RGB565_2X8_BE
:
225 case MEDIA_BUS_FMT_RGB565_2X8_LE
:
226 if (mbus_type
== V4L2_MBUS_CSI2_DPHY
)
227 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_RGB565
;
229 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
230 cfg
->mipi_dt
= MIPI_DT_RGB565
;
231 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
233 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE
:
234 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE
:
235 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_RGB444
;
236 cfg
->mipi_dt
= MIPI_DT_RGB444
;
237 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
239 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE
:
240 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE
:
241 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_RGB555
;
242 cfg
->mipi_dt
= MIPI_DT_RGB555
;
243 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
245 case MEDIA_BUS_FMT_RGB888_1X24
:
246 case MEDIA_BUS_FMT_BGR888_1X24
:
247 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_RGB_YUV444
;
248 cfg
->mipi_dt
= MIPI_DT_RGB888
;
249 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
251 case MEDIA_BUS_FMT_UYVY8_2X8
:
252 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_YUV422_UYVY
;
253 cfg
->mipi_dt
= MIPI_DT_YUV422
;
254 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
256 case MEDIA_BUS_FMT_YUYV8_2X8
:
257 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_YUV422_YUYV
;
258 cfg
->mipi_dt
= MIPI_DT_YUV422
;
259 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
261 case MEDIA_BUS_FMT_UYVY8_1X16
:
262 case MEDIA_BUS_FMT_YUYV8_1X16
:
263 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
264 cfg
->mipi_dt
= MIPI_DT_YUV422
;
265 cfg
->data_width
= IPU_CSI_DATA_WIDTH_16
;
267 case MEDIA_BUS_FMT_SBGGR8_1X8
:
268 case MEDIA_BUS_FMT_SGBRG8_1X8
:
269 case MEDIA_BUS_FMT_SGRBG8_1X8
:
270 case MEDIA_BUS_FMT_SRGGB8_1X8
:
271 case MEDIA_BUS_FMT_Y8_1X8
:
272 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
273 cfg
->mipi_dt
= MIPI_DT_RAW8
;
274 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
276 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8
:
277 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8
:
278 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8
:
279 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8
:
280 case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE
:
281 case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE
:
282 case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE
:
283 case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE
:
284 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
285 cfg
->mipi_dt
= MIPI_DT_RAW10
;
286 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
288 case MEDIA_BUS_FMT_SBGGR10_1X10
:
289 case MEDIA_BUS_FMT_SGBRG10_1X10
:
290 case MEDIA_BUS_FMT_SGRBG10_1X10
:
291 case MEDIA_BUS_FMT_SRGGB10_1X10
:
292 case MEDIA_BUS_FMT_Y10_1X10
:
293 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
294 cfg
->mipi_dt
= MIPI_DT_RAW10
;
295 cfg
->data_width
= IPU_CSI_DATA_WIDTH_10
;
297 case MEDIA_BUS_FMT_SBGGR12_1X12
:
298 case MEDIA_BUS_FMT_SGBRG12_1X12
:
299 case MEDIA_BUS_FMT_SGRBG12_1X12
:
300 case MEDIA_BUS_FMT_SRGGB12_1X12
:
301 case MEDIA_BUS_FMT_Y12_1X12
:
302 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_BAYER
;
303 cfg
->mipi_dt
= MIPI_DT_RAW12
;
304 cfg
->data_width
= IPU_CSI_DATA_WIDTH_12
;
306 case MEDIA_BUS_FMT_JPEG_1X8
:
308 cfg
->data_fmt
= CSI_SENS_CONF_DATA_FMT_JPEG
;
309 cfg
->mipi_dt
= MIPI_DT_RAW8
;
310 cfg
->data_width
= IPU_CSI_DATA_WIDTH_8
;
319 /* translate alternate field mode based on given standard */
320 static inline enum v4l2_field
321 ipu_csi_translate_field(enum v4l2_field field
, v4l2_std_id std
)
323 return (field
!= V4L2_FIELD_ALTERNATE
) ? field
:
324 ((std
& V4L2_STD_525_60
) ?
325 V4L2_FIELD_SEQ_BT
: V4L2_FIELD_SEQ_TB
);
329 * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
331 static int fill_csi_bus_cfg(struct ipu_csi_bus_config
*csicfg
,
332 const struct v4l2_mbus_config
*mbus_cfg
,
333 const struct v4l2_mbus_framefmt
*mbus_fmt
)
337 memset(csicfg
, 0, sizeof(*csicfg
));
339 ret
= mbus_code_to_bus_cfg(csicfg
, mbus_fmt
->code
, mbus_cfg
->type
);
343 switch (mbus_cfg
->type
) {
344 case V4L2_MBUS_PARALLEL
:
345 csicfg
->ext_vsync
= 1;
346 csicfg
->vsync_pol
= (mbus_cfg
->flags
&
347 V4L2_MBUS_VSYNC_ACTIVE_LOW
) ? 1 : 0;
348 csicfg
->hsync_pol
= (mbus_cfg
->flags
&
349 V4L2_MBUS_HSYNC_ACTIVE_LOW
) ? 1 : 0;
350 csicfg
->pixclk_pol
= (mbus_cfg
->flags
&
351 V4L2_MBUS_PCLK_SAMPLE_FALLING
) ? 1 : 0;
352 csicfg
->clk_mode
= IPU_CSI_CLK_MODE_GATED_CLK
;
354 case V4L2_MBUS_BT656
:
355 csicfg
->ext_vsync
= 0;
356 if (V4L2_FIELD_HAS_BOTH(mbus_fmt
->field
) ||
357 mbus_fmt
->field
== V4L2_FIELD_ALTERNATE
)
358 csicfg
->clk_mode
= IPU_CSI_CLK_MODE_CCIR656_INTERLACED
;
360 csicfg
->clk_mode
= IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE
;
362 case V4L2_MBUS_CSI2_DPHY
:
364 * MIPI CSI-2 requires non gated clock mode, all other
365 * parameters are not applicable for MIPI CSI-2 bus.
367 csicfg
->clk_mode
= IPU_CSI_CLK_MODE_NONGATED_CLK
;
370 /* will never get here, keep compiler quiet */
378 ipu_csi_set_bt_interlaced_codes(struct ipu_csi
*csi
,
379 const struct v4l2_mbus_framefmt
*infmt
,
380 const struct v4l2_mbus_framefmt
*outfmt
,
383 enum v4l2_field infield
, outfield
;
386 /* get translated field type of input and output */
387 infield
= ipu_csi_translate_field(infmt
->field
, std
);
388 outfield
= ipu_csi_translate_field(outfmt
->field
, std
);
391 * Write the H-V-F codes the CSI will match against the
392 * incoming data for start/end of active and blanking
393 * field intervals. If input and output field types are
394 * sequential but not the same (one is SEQ_BT and the other
395 * is SEQ_TB), swap the F-bit so that the CSI will capture
396 * field 1 lines before field 0 lines.
398 swap_fields
= (V4L2_FIELD_IS_SEQUENTIAL(infield
) &&
399 V4L2_FIELD_IS_SEQUENTIAL(outfield
) &&
400 infield
!= outfield
);
404 * Field0BlankEnd = 110, Field0BlankStart = 010
405 * Field0ActiveEnd = 100, Field0ActiveStart = 000
406 * Field1BlankEnd = 111, Field1BlankStart = 011
407 * Field1ActiveEnd = 101, Field1ActiveStart = 001
409 ipu_csi_write(csi
, 0x40596 | CSI_CCIR_ERR_DET_EN
,
411 ipu_csi_write(csi
, 0xD07DF, CSI_CCIR_CODE_2
);
413 dev_dbg(csi
->ipu
->dev
, "capture field swap\n");
415 /* same as above but with F-bit inverted */
416 ipu_csi_write(csi
, 0xD07DF | CSI_CCIR_ERR_DET_EN
,
418 ipu_csi_write(csi
, 0x40596, CSI_CCIR_CODE_2
);
421 ipu_csi_write(csi
, 0xFF0000, CSI_CCIR_CODE_3
);
427 int ipu_csi_init_interface(struct ipu_csi
*csi
,
428 const struct v4l2_mbus_config
*mbus_cfg
,
429 const struct v4l2_mbus_framefmt
*infmt
,
430 const struct v4l2_mbus_framefmt
*outfmt
)
432 struct ipu_csi_bus_config cfg
;
434 u32 width
, height
, data
= 0;
438 ret
= fill_csi_bus_cfg(&cfg
, mbus_cfg
, infmt
);
442 /* set default sensor frame width and height */
443 width
= infmt
->width
;
444 height
= infmt
->height
;
445 if (infmt
->field
== V4L2_FIELD_ALTERNATE
)
448 /* Set the CSI_SENS_CONF register remaining fields */
449 data
|= cfg
.data_width
<< CSI_SENS_CONF_DATA_WIDTH_SHIFT
|
450 cfg
.data_fmt
<< CSI_SENS_CONF_DATA_FMT_SHIFT
|
451 cfg
.data_pol
<< CSI_SENS_CONF_DATA_POL_SHIFT
|
452 cfg
.vsync_pol
<< CSI_SENS_CONF_VSYNC_POL_SHIFT
|
453 cfg
.hsync_pol
<< CSI_SENS_CONF_HSYNC_POL_SHIFT
|
454 cfg
.pixclk_pol
<< CSI_SENS_CONF_PIX_CLK_POL_SHIFT
|
455 cfg
.ext_vsync
<< CSI_SENS_CONF_EXT_VSYNC_SHIFT
|
456 cfg
.clk_mode
<< CSI_SENS_CONF_SENS_PRTCL_SHIFT
|
457 cfg
.pack_tight
<< CSI_SENS_CONF_PACK_TIGHT_SHIFT
|
458 cfg
.force_eof
<< CSI_SENS_CONF_FORCE_EOF_SHIFT
|
459 cfg
.data_en_pol
<< CSI_SENS_CONF_DATA_EN_POL_SHIFT
;
461 spin_lock_irqsave(&csi
->lock
, flags
);
463 ipu_csi_write(csi
, data
, CSI_SENS_CONF
);
465 /* Set CCIR registers */
467 switch (cfg
.clk_mode
) {
468 case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE
:
469 ipu_csi_write(csi
, 0x40030, CSI_CCIR_CODE_1
);
470 ipu_csi_write(csi
, 0xFF0000, CSI_CCIR_CODE_3
);
472 case IPU_CSI_CLK_MODE_CCIR656_INTERLACED
:
473 if (width
== 720 && height
== 480) {
476 } else if (width
== 720 && height
== 576) {
480 dev_err(csi
->ipu
->dev
,
481 "Unsupported interlaced video mode\n");
486 ret
= ipu_csi_set_bt_interlaced_codes(csi
, infmt
, outfmt
, std
);
490 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR
:
491 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR
:
492 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR
:
493 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR
:
494 ipu_csi_write(csi
, 0x40030 | CSI_CCIR_ERR_DET_EN
,
496 ipu_csi_write(csi
, 0xFF0000, CSI_CCIR_CODE_3
);
498 case IPU_CSI_CLK_MODE_GATED_CLK
:
499 case IPU_CSI_CLK_MODE_NONGATED_CLK
:
500 ipu_csi_write(csi
, 0, CSI_CCIR_CODE_1
);
504 /* Setup sensor frame size */
505 ipu_csi_write(csi
, (width
- 1) | ((height
- 1) << 16),
508 dev_dbg(csi
->ipu
->dev
, "CSI_SENS_CONF = 0x%08X\n",
509 ipu_csi_read(csi
, CSI_SENS_CONF
));
510 dev_dbg(csi
->ipu
->dev
, "CSI_ACT_FRM_SIZE = 0x%08X\n",
511 ipu_csi_read(csi
, CSI_ACT_FRM_SIZE
));
514 spin_unlock_irqrestore(&csi
->lock
, flags
);
518 EXPORT_SYMBOL_GPL(ipu_csi_init_interface
);
520 bool ipu_csi_is_interlaced(struct ipu_csi
*csi
)
525 spin_lock_irqsave(&csi
->lock
, flags
);
527 (ipu_csi_read(csi
, CSI_SENS_CONF
) &
528 CSI_SENS_CONF_SENS_PRTCL_MASK
) >>
529 CSI_SENS_CONF_SENS_PRTCL_SHIFT
;
530 spin_unlock_irqrestore(&csi
->lock
, flags
);
532 switch (sensor_protocol
) {
533 case IPU_CSI_CLK_MODE_GATED_CLK
:
534 case IPU_CSI_CLK_MODE_NONGATED_CLK
:
535 case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE
:
536 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR
:
537 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR
:
539 case IPU_CSI_CLK_MODE_CCIR656_INTERLACED
:
540 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR
:
541 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR
:
544 dev_err(csi
->ipu
->dev
,
545 "CSI %d sensor protocol unsupported\n", csi
->id
);
549 EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced
);
551 void ipu_csi_get_window(struct ipu_csi
*csi
, struct v4l2_rect
*w
)
556 spin_lock_irqsave(&csi
->lock
, flags
);
558 reg
= ipu_csi_read(csi
, CSI_ACT_FRM_SIZE
);
559 w
->width
= (reg
& 0xFFFF) + 1;
560 w
->height
= (reg
>> 16 & 0xFFFF) + 1;
562 reg
= ipu_csi_read(csi
, CSI_OUT_FRM_CTRL
);
563 w
->left
= (reg
& CSI_HSC_MASK
) >> CSI_HSC_SHIFT
;
564 w
->top
= (reg
& CSI_VSC_MASK
) >> CSI_VSC_SHIFT
;
566 spin_unlock_irqrestore(&csi
->lock
, flags
);
568 EXPORT_SYMBOL_GPL(ipu_csi_get_window
);
570 void ipu_csi_set_window(struct ipu_csi
*csi
, struct v4l2_rect
*w
)
575 spin_lock_irqsave(&csi
->lock
, flags
);
577 ipu_csi_write(csi
, (w
->width
- 1) | ((w
->height
- 1) << 16),
580 reg
= ipu_csi_read(csi
, CSI_OUT_FRM_CTRL
);
581 reg
&= ~(CSI_HSC_MASK
| CSI_VSC_MASK
);
582 reg
|= ((w
->top
<< CSI_VSC_SHIFT
) | (w
->left
<< CSI_HSC_SHIFT
));
583 ipu_csi_write(csi
, reg
, CSI_OUT_FRM_CTRL
);
585 spin_unlock_irqrestore(&csi
->lock
, flags
);
587 EXPORT_SYMBOL_GPL(ipu_csi_set_window
);
589 void ipu_csi_set_downsize(struct ipu_csi
*csi
, bool horiz
, bool vert
)
594 spin_lock_irqsave(&csi
->lock
, flags
);
596 reg
= ipu_csi_read(csi
, CSI_OUT_FRM_CTRL
);
597 reg
&= ~(CSI_HORI_DOWNSIZE_EN
| CSI_VERT_DOWNSIZE_EN
);
598 reg
|= (horiz
? CSI_HORI_DOWNSIZE_EN
: 0) |
599 (vert
? CSI_VERT_DOWNSIZE_EN
: 0);
600 ipu_csi_write(csi
, reg
, CSI_OUT_FRM_CTRL
);
602 spin_unlock_irqrestore(&csi
->lock
, flags
);
604 EXPORT_SYMBOL_GPL(ipu_csi_set_downsize
);
606 void ipu_csi_set_test_generator(struct ipu_csi
*csi
, bool active
,
607 u32 r_value
, u32 g_value
, u32 b_value
,
611 u32 ipu_clk
= clk_get_rate(csi
->clk_ipu
);
614 spin_lock_irqsave(&csi
->lock
, flags
);
616 temp
= ipu_csi_read(csi
, CSI_TST_CTRL
);
619 temp
&= ~CSI_TEST_GEN_MODE_EN
;
620 ipu_csi_write(csi
, temp
, CSI_TST_CTRL
);
622 /* Set sensb_mclk div_ratio */
623 ipu_csi_set_testgen_mclk(csi
, pix_clk
, ipu_clk
);
625 temp
&= ~(CSI_TEST_GEN_R_MASK
| CSI_TEST_GEN_G_MASK
|
626 CSI_TEST_GEN_B_MASK
);
627 temp
|= CSI_TEST_GEN_MODE_EN
;
628 temp
|= (r_value
<< CSI_TEST_GEN_R_SHIFT
) |
629 (g_value
<< CSI_TEST_GEN_G_SHIFT
) |
630 (b_value
<< CSI_TEST_GEN_B_SHIFT
);
631 ipu_csi_write(csi
, temp
, CSI_TST_CTRL
);
634 spin_unlock_irqrestore(&csi
->lock
, flags
);
636 EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator
);
638 int ipu_csi_set_mipi_datatype(struct ipu_csi
*csi
, u32 vc
,
639 struct v4l2_mbus_framefmt
*mbus_fmt
)
641 struct ipu_csi_bus_config cfg
;
649 ret
= mbus_code_to_bus_cfg(&cfg
, mbus_fmt
->code
, V4L2_MBUS_CSI2_DPHY
);
653 spin_lock_irqsave(&csi
->lock
, flags
);
655 temp
= ipu_csi_read(csi
, CSI_MIPI_DI
);
656 temp
&= ~(0xff << (vc
* 8));
657 temp
|= (cfg
.mipi_dt
<< (vc
* 8));
658 ipu_csi_write(csi
, temp
, CSI_MIPI_DI
);
660 spin_unlock_irqrestore(&csi
->lock
, flags
);
664 EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype
);
666 int ipu_csi_set_skip_smfc(struct ipu_csi
*csi
, u32 skip
,
667 u32 max_ratio
, u32 id
)
672 if (max_ratio
> 5 || id
> 3)
675 spin_lock_irqsave(&csi
->lock
, flags
);
677 temp
= ipu_csi_read(csi
, CSI_SKIP
);
678 temp
&= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK
| CSI_ID_2_SKIP_MASK
|
680 temp
|= (max_ratio
<< CSI_MAX_RATIO_SKIP_SMFC_SHIFT
) |
681 (id
<< CSI_ID_2_SKIP_SHIFT
) |
682 (skip
<< CSI_SKIP_SMFC_SHIFT
);
683 ipu_csi_write(csi
, temp
, CSI_SKIP
);
685 spin_unlock_irqrestore(&csi
->lock
, flags
);
689 EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc
);
691 int ipu_csi_set_dest(struct ipu_csi
*csi
, enum ipu_csi_dest csi_dest
)
694 u32 csi_sens_conf
, dest
;
696 if (csi_dest
== IPU_CSI_DEST_IDMAC
)
697 dest
= CSI_DATA_DEST_IDMAC
;
699 dest
= CSI_DATA_DEST_IC
; /* IC or VDIC */
701 spin_lock_irqsave(&csi
->lock
, flags
);
703 csi_sens_conf
= ipu_csi_read(csi
, CSI_SENS_CONF
);
704 csi_sens_conf
&= ~CSI_SENS_CONF_DATA_DEST_MASK
;
705 csi_sens_conf
|= (dest
<< CSI_SENS_CONF_DATA_DEST_SHIFT
);
706 ipu_csi_write(csi
, csi_sens_conf
, CSI_SENS_CONF
);
708 spin_unlock_irqrestore(&csi
->lock
, flags
);
712 EXPORT_SYMBOL_GPL(ipu_csi_set_dest
);
714 int ipu_csi_enable(struct ipu_csi
*csi
)
716 ipu_module_enable(csi
->ipu
, csi
->module
);
720 EXPORT_SYMBOL_GPL(ipu_csi_enable
);
722 int ipu_csi_disable(struct ipu_csi
*csi
)
724 ipu_module_disable(csi
->ipu
, csi
->module
);
728 EXPORT_SYMBOL_GPL(ipu_csi_disable
);
730 struct ipu_csi
*ipu_csi_get(struct ipu_soc
*ipu
, int id
)
733 struct ipu_csi
*csi
, *ret
;
736 return ERR_PTR(-EINVAL
);
738 csi
= ipu
->csi_priv
[id
];
741 spin_lock_irqsave(&csi
->lock
, flags
);
744 ret
= ERR_PTR(-EBUSY
);
750 spin_unlock_irqrestore(&csi
->lock
, flags
);
753 EXPORT_SYMBOL_GPL(ipu_csi_get
);
755 void ipu_csi_put(struct ipu_csi
*csi
)
759 spin_lock_irqsave(&csi
->lock
, flags
);
761 spin_unlock_irqrestore(&csi
->lock
, flags
);
763 EXPORT_SYMBOL_GPL(ipu_csi_put
);
765 int ipu_csi_init(struct ipu_soc
*ipu
, struct device
*dev
, int id
,
766 unsigned long base
, u32 module
, struct clk
*clk_ipu
)
773 csi
= devm_kzalloc(dev
, sizeof(*csi
), GFP_KERNEL
);
777 ipu
->csi_priv
[id
] = csi
;
779 spin_lock_init(&csi
->lock
);
780 csi
->module
= module
;
782 csi
->clk_ipu
= clk_ipu
;
783 csi
->base
= devm_ioremap(dev
, base
, PAGE_SIZE
);
787 dev_dbg(dev
, "CSI%d base: 0x%08lx remapped to %p\n",
788 id
, base
, csi
->base
);
794 void ipu_csi_exit(struct ipu_soc
*ipu
, int id
)
798 void ipu_csi_dump(struct ipu_csi
*csi
)
800 dev_dbg(csi
->ipu
->dev
, "CSI_SENS_CONF: %08x\n",
801 ipu_csi_read(csi
, CSI_SENS_CONF
));
802 dev_dbg(csi
->ipu
->dev
, "CSI_SENS_FRM_SIZE: %08x\n",
803 ipu_csi_read(csi
, CSI_SENS_FRM_SIZE
));
804 dev_dbg(csi
->ipu
->dev
, "CSI_ACT_FRM_SIZE: %08x\n",
805 ipu_csi_read(csi
, CSI_ACT_FRM_SIZE
));
806 dev_dbg(csi
->ipu
->dev
, "CSI_OUT_FRM_CTRL: %08x\n",
807 ipu_csi_read(csi
, CSI_OUT_FRM_CTRL
));
808 dev_dbg(csi
->ipu
->dev
, "CSI_TST_CTRL: %08x\n",
809 ipu_csi_read(csi
, CSI_TST_CTRL
));
810 dev_dbg(csi
->ipu
->dev
, "CSI_CCIR_CODE_1: %08x\n",
811 ipu_csi_read(csi
, CSI_CCIR_CODE_1
));
812 dev_dbg(csi
->ipu
->dev
, "CSI_CCIR_CODE_2: %08x\n",
813 ipu_csi_read(csi
, CSI_CCIR_CODE_2
));
814 dev_dbg(csi
->ipu
->dev
, "CSI_CCIR_CODE_3: %08x\n",
815 ipu_csi_read(csi
, CSI_CCIR_CODE_3
));
816 dev_dbg(csi
->ipu
->dev
, "CSI_MIPI_DI: %08x\n",
817 ipu_csi_read(csi
, CSI_MIPI_DI
));
818 dev_dbg(csi
->ipu
->dev
, "CSI_SKIP: %08x\n",
819 ipu_csi_read(csi
, CSI_SKIP
));
821 EXPORT_SYMBOL_GPL(ipu_csi_dump
);