1 // SPDX-License-Identifier: GPL-2.0
5 * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
7 * Copyright (C) 2020 Linaro Ltd.
9 #include <linux/completion.h>
10 #include <linux/interrupt.h>
12 #include <linux/kernel.h>
15 #include "camss-csid.h"
16 #include "camss-csid-gen2.h"
19 /* The CSID 2 IP-block is different from the others,
20 * and is of a bare-bones Lite version, with no PIX
21 * interface support. As a result of that it has an
22 * alternate register layout.
25 #define CSID_HW_VERSION 0x0
26 #define HW_VERSION_STEPPING 0
27 #define HW_VERSION_REVISION 16
28 #define HW_VERSION_GENERATION 28
30 #define CSID_RST_STROBES 0x10
33 #define CSID_CSI2_RX_IRQ_STATUS 0x20
34 #define CSID_CSI2_RX_IRQ_MASK 0x24
35 #define CSID_CSI2_RX_IRQ_CLEAR 0x28
37 #define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((csid_is_lite(csid) ? 0x30 : 0x40) \
39 #define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((csid_is_lite(csid) ? 0x34 : 0x44) \
41 #define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((csid_is_lite(csid) ? 0x38 : 0x48) \
43 #define CSID_CSI2_RDIN_IRQ_SET(rdi) ((csid_is_lite(csid) ? 0x3C : 0x4C) \
46 #define CSID_TOP_IRQ_STATUS 0x70
47 #define TOP_IRQ_STATUS_RESET_DONE 0
48 #define CSID_TOP_IRQ_MASK 0x74
49 #define CSID_TOP_IRQ_CLEAR 0x78
50 #define CSID_TOP_IRQ_SET 0x7C
51 #define CSID_IRQ_CMD 0x80
52 #define IRQ_CMD_CLEAR 0
55 #define CSID_CSI2_RX_CFG0 0x100
56 #define CSI2_RX_CFG0_NUM_ACTIVE_LANES 0
57 #define CSI2_RX_CFG0_DL0_INPUT_SEL 4
58 #define CSI2_RX_CFG0_DL1_INPUT_SEL 8
59 #define CSI2_RX_CFG0_DL2_INPUT_SEL 12
60 #define CSI2_RX_CFG0_DL3_INPUT_SEL 16
61 #define CSI2_RX_CFG0_PHY_NUM_SEL 20
62 #define CSI2_RX_CFG0_PHY_TYPE_SEL 24
64 #define CSID_CSI2_RX_CFG1 0x104
65 #define CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN 0
66 #define CSI2_RX_CFG1_DE_SCRAMBLE_EN 1
67 #define CSI2_RX_CFG1_VC_MODE 2
68 #define CSI2_RX_CFG1_COMPLETE_STREAM_EN 4
69 #define CSI2_RX_CFG1_COMPLETE_STREAM_FRAME_TIMING 5
70 #define CSI2_RX_CFG1_MISR_EN 6
71 #define CSI2_RX_CFG1_CGC_MODE 7
72 #define CGC_MODE_DYNAMIC_GATING 0
73 #define CGC_MODE_ALWAYS_ON 1
75 #define CSID_RDI_CFG0(rdi) ((csid_is_lite(csid) ? 0x200 : 0x300) \
77 #define RDI_CFG0_BYTE_CNTR_EN 0
78 #define RDI_CFG0_FORMAT_MEASURE_EN 1
79 #define RDI_CFG0_TIMESTAMP_EN 2
80 #define RDI_CFG0_DROP_H_EN 3
81 #define RDI_CFG0_DROP_V_EN 4
82 #define RDI_CFG0_CROP_H_EN 5
83 #define RDI_CFG0_CROP_V_EN 6
84 #define RDI_CFG0_MISR_EN 7
85 #define RDI_CFG0_CGC_MODE 8
86 #define CGC_MODE_DYNAMIC 0
87 #define CGC_MODE_ALWAYS_ON 1
88 #define RDI_CFG0_PLAIN_ALIGNMENT 9
89 #define PLAIN_ALIGNMENT_LSB 0
90 #define PLAIN_ALIGNMENT_MSB 1
91 #define RDI_CFG0_PLAIN_FORMAT 10
92 #define RDI_CFG0_DECODE_FORMAT 12
93 #define RDI_CFG0_DATA_TYPE 16
94 #define RDI_CFG0_VIRTUAL_CHANNEL 22
95 #define RDI_CFG0_DT_ID 27
96 #define RDI_CFG0_EARLY_EOF_EN 29
97 #define RDI_CFG0_PACKING_FORMAT 30
98 #define RDI_CFG0_ENABLE 31
100 #define CSID_RDI_CFG1(rdi) ((csid_is_lite(csid) ? 0x204 : 0x304)\
102 #define RDI_CFG1_TIMESTAMP_STB_SEL 0
104 #define CSID_RDI_CTRL(rdi) ((csid_is_lite(csid) ? 0x208 : 0x308)\
106 #define RDI_CTRL_HALT_CMD 0
107 #define HALT_CMD_HALT_AT_FRAME_BOUNDARY 0
108 #define HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1
109 #define RDI_CTRL_HALT_MODE 2
111 #define CSID_RDI_FRM_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x20C : 0x30C)\
113 #define CSID_RDI_FRM_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x210 : 0x310)\
115 #define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((csid_is_lite(csid) ? 0x214 : 0x314)\
117 #define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((csid_is_lite(csid) ? 0x218 : 0x318)\
119 #define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x224 : 0x324)\
121 #define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x228 : 0x328)\
123 #define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x22C : 0x32C)\
125 #define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x230 : 0x330)\
128 #define CSID_TPG_CTRL 0x600
129 #define TPG_CTRL_TEST_EN 0
130 #define TPG_CTRL_FS_PKT_EN 1
131 #define TPG_CTRL_FE_PKT_EN 2
132 #define TPG_CTRL_NUM_ACTIVE_LANES 4
133 #define TPG_CTRL_CYCLES_BETWEEN_PKTS 8
134 #define TPG_CTRL_NUM_TRAIL_BYTES 20
136 #define CSID_TPG_VC_CFG0 0x604
137 #define TPG_VC_CFG0_VC_NUM 0
138 #define TPG_VC_CFG0_NUM_ACTIVE_SLOTS 8
139 #define NUM_ACTIVE_SLOTS_0_ENABLED 0
140 #define NUM_ACTIVE_SLOTS_0_1_ENABLED 1
141 #define NUM_ACTIVE_SLOTS_0_1_2_ENABLED 2
142 #define NUM_ACTIVE_SLOTS_0_1_3_ENABLED 3
143 #define TPG_VC_CFG0_LINE_INTERLEAVING_MODE 10
144 #define INTELEAVING_MODE_INTERLEAVED 0
145 #define INTELEAVING_MODE_ONE_SHOT 1
146 #define TPG_VC_CFG0_NUM_FRAMES 16
148 #define CSID_TPG_VC_CFG1 0x608
149 #define TPG_VC_CFG1_H_BLANKING_COUNT 0
150 #define TPG_VC_CFG1_V_BLANKING_COUNT 12
151 #define TPG_VC_CFG1_V_BLANK_FRAME_WIDTH_SEL 24
153 #define CSID_TPG_LFSR_SEED 0x60C
155 #define CSID_TPG_DT_n_CFG_0(n) (0x610 + (n) * 0xC)
156 #define TPG_DT_n_CFG_0_FRAME_HEIGHT 0
157 #define TPG_DT_n_CFG_0_FRAME_WIDTH 16
159 #define CSID_TPG_DT_n_CFG_1(n) (0x614 + (n) * 0xC)
160 #define TPG_DT_n_CFG_1_DATA_TYPE 0
161 #define TPG_DT_n_CFG_1_ECC_XOR_MASK 8
162 #define TPG_DT_n_CFG_1_CRC_XOR_MASK 16
164 #define CSID_TPG_DT_n_CFG_2(n) (0x618 + (n) * 0xC)
165 #define TPG_DT_n_CFG_2_PAYLOAD_MODE 0
166 #define TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD 4
167 #define TPG_DT_n_CFG_2_ENCODE_FORMAT 16
169 #define CSID_TPG_COLOR_BARS_CFG 0x640
170 #define TPG_COLOR_BARS_CFG_UNICOLOR_BAR_EN 0
171 #define TPG_COLOR_BARS_CFG_UNICOLOR_BAR_SEL 4
172 #define TPG_COLOR_BARS_CFG_SPLIT_EN 5
173 #define TPG_COLOR_BARS_CFG_ROTATE_PERIOD 8
175 #define CSID_TPG_COLOR_BOX_CFG 0x644
176 #define TPG_COLOR_BOX_CFG_MODE 0
177 #define TPG_COLOR_BOX_PATTERN_SEL 2
179 static void __csid_configure_rx(struct csid_device
*csid
,
180 struct csid_phy_config
*phy
, int vc
)
182 u8 lane_cnt
= csid
->phy
.lane_cnt
;
188 val
= (lane_cnt
- 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES
;
189 val
|= phy
->lane_assign
<< CSI2_RX_CFG0_DL0_INPUT_SEL
;
190 val
|= phy
->csiphy_id
<< CSI2_RX_CFG0_PHY_NUM_SEL
;
191 writel_relaxed(val
, csid
->base
+ CSID_CSI2_RX_CFG0
);
193 val
= 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN
;
195 val
|= 1 << CSI2_RX_CFG1_VC_MODE
;
196 val
|= 1 << CSI2_RX_CFG1_MISR_EN
;
197 writel_relaxed(val
, csid
->base
+ CSID_CSI2_RX_CFG1
);
200 static void __csid_ctrl_rdi(struct csid_device
*csid
, int enable
, u8 rdi
)
205 val
= HALT_CMD_RESUME_AT_FRAME_BOUNDARY
<< RDI_CTRL_HALT_CMD
;
207 val
= HALT_CMD_HALT_AT_FRAME_BOUNDARY
<< RDI_CTRL_HALT_CMD
;
208 writel_relaxed(val
, csid
->base
+ CSID_RDI_CTRL(rdi
));
211 static void __csid_configure_testgen(struct csid_device
*csid
, u8 enable
, u8 vc
)
213 struct csid_testgen_config
*tg
= &csid
->testgen
;
214 struct v4l2_mbus_framefmt
*input_format
= &csid
->fmt
[MSM_CSID_PAD_FIRST_SRC
+ vc
];
215 const struct csid_format_info
*format
= csid_get_fmt_entry(csid
->res
->formats
->formats
,
216 csid
->res
->formats
->nformats
,
218 u8 lane_cnt
= csid
->phy
.lane_cnt
;
224 /* configure one DT, infinite frames */
225 val
= vc
<< TPG_VC_CFG0_VC_NUM
;
226 val
|= INTELEAVING_MODE_ONE_SHOT
<< TPG_VC_CFG0_LINE_INTERLEAVING_MODE
;
227 val
|= 0 << TPG_VC_CFG0_NUM_FRAMES
;
228 writel_relaxed(val
, csid
->base
+ CSID_TPG_VC_CFG0
);
230 val
= 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT
;
231 val
|= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT
;
232 writel_relaxed(val
, csid
->base
+ CSID_TPG_VC_CFG1
);
234 writel_relaxed(0x12345678, csid
->base
+ CSID_TPG_LFSR_SEED
);
236 val
= (input_format
->height
& 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT
;
237 val
|= (input_format
->width
& 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH
;
238 writel_relaxed(val
, csid
->base
+ CSID_TPG_DT_n_CFG_0(0));
240 val
= format
->data_type
<< TPG_DT_n_CFG_1_DATA_TYPE
;
241 writel_relaxed(val
, csid
->base
+ CSID_TPG_DT_n_CFG_1(0));
243 val
= (tg
->mode
- 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE
;
244 val
|= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD
;
245 val
|= format
->decode_format
<< TPG_DT_n_CFG_2_ENCODE_FORMAT
;
246 writel_relaxed(val
, csid
->base
+ CSID_TPG_DT_n_CFG_2(0));
248 writel_relaxed(0, csid
->base
+ CSID_TPG_COLOR_BARS_CFG
);
250 writel_relaxed(0, csid
->base
+ CSID_TPG_COLOR_BOX_CFG
);
252 val
= enable
<< TPG_CTRL_TEST_EN
;
253 val
|= 1 << TPG_CTRL_FS_PKT_EN
;
254 val
|= 1 << TPG_CTRL_FE_PKT_EN
;
255 val
|= (lane_cnt
- 1) << TPG_CTRL_NUM_ACTIVE_LANES
;
256 val
|= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS
;
257 val
|= 0xA << TPG_CTRL_NUM_TRAIL_BYTES
;
258 writel_relaxed(val
, csid
->base
+ CSID_TPG_CTRL
);
261 static void __csid_configure_rdi_stream(struct csid_device
*csid
, u8 enable
, u8 vc
)
263 /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
264 struct v4l2_mbus_framefmt
*input_format
= &csid
->fmt
[MSM_CSID_PAD_FIRST_SRC
+ vc
];
265 const struct csid_format_info
*format
= csid_get_fmt_entry(csid
->res
->formats
->formats
,
266 csid
->res
->formats
->nformats
,
271 * DT_ID is a two bit bitfield that is concatenated with
272 * the four least significant bits of the five bit VC
273 * bitfield to generate an internal CID value.
280 * CID : VC 3:0 << 2 | DT_ID 1:0
282 u8 dt_id
= vc
& 0x03;
284 val
= 1 << RDI_CFG0_BYTE_CNTR_EN
;
285 val
|= 1 << RDI_CFG0_FORMAT_MEASURE_EN
;
286 val
|= 1 << RDI_CFG0_TIMESTAMP_EN
;
287 /* note: for non-RDI path, this should be format->decode_format */
288 val
|= DECODE_FORMAT_PAYLOAD_ONLY
<< RDI_CFG0_DECODE_FORMAT
;
289 val
|= format
->data_type
<< RDI_CFG0_DATA_TYPE
;
290 val
|= vc
<< RDI_CFG0_VIRTUAL_CHANNEL
;
291 val
|= dt_id
<< RDI_CFG0_DT_ID
;
292 writel_relaxed(val
, csid
->base
+ CSID_RDI_CFG0(vc
));
294 /* CSID_TIMESTAMP_STB_POST_IRQ */
295 val
= 2 << RDI_CFG1_TIMESTAMP_STB_SEL
;
296 writel_relaxed(val
, csid
->base
+ CSID_RDI_CFG1(vc
));
299 writel_relaxed(val
, csid
->base
+ CSID_RDI_FRM_DROP_PERIOD(vc
));
302 writel_relaxed(val
, csid
->base
+ CSID_RDI_FRM_DROP_PATTERN(vc
));
305 writel_relaxed(val
, csid
->base
+ CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc
));
308 writel_relaxed(val
, csid
->base
+ CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc
));
311 writel_relaxed(val
, csid
->base
+ CSID_RDI_RPP_PIX_DROP_PERIOD(vc
));
314 writel_relaxed(val
, csid
->base
+ CSID_RDI_RPP_PIX_DROP_PATTERN(vc
));
317 writel_relaxed(val
, csid
->base
+ CSID_RDI_RPP_LINE_DROP_PERIOD(vc
));
320 writel_relaxed(val
, csid
->base
+ CSID_RDI_RPP_LINE_DROP_PATTERN(vc
));
323 writel_relaxed(val
, csid
->base
+ CSID_RDI_CTRL(vc
));
325 val
= readl_relaxed(csid
->base
+ CSID_RDI_CFG0(vc
));
326 val
|= enable
<< RDI_CFG0_ENABLE
;
327 writel_relaxed(val
, csid
->base
+ CSID_RDI_CFG0(vc
));
330 static void csid_configure_stream(struct csid_device
*csid
, u8 enable
)
332 struct csid_testgen_config
*tg
= &csid
->testgen
;
334 /* Loop through all enabled VCs and configure stream for each */
335 for (i
= 0; i
< MSM_CSID_MAX_SRC_STREAMS
; i
++)
336 if (csid
->phy
.en_vc
& BIT(i
)) {
338 __csid_configure_testgen(csid
, enable
, i
);
340 __csid_configure_rdi_stream(csid
, enable
, i
);
341 __csid_configure_rx(csid
, &csid
->phy
, i
);
342 __csid_ctrl_rdi(csid
, enable
, i
);
346 static int csid_configure_testgen_pattern(struct csid_device
*csid
, s32 val
)
348 if (val
> 0 && val
<= csid
->testgen
.nmodes
)
349 csid
->testgen
.mode
= val
;
355 * csid_hw_version - CSID hardware version query
358 * Return HW version or error
360 static u32
csid_hw_version(struct csid_device
*csid
)
367 hw_version
= readl_relaxed(csid
->base
+ CSID_HW_VERSION
);
368 hw_gen
= (hw_version
>> HW_VERSION_GENERATION
) & 0xF;
369 hw_rev
= (hw_version
>> HW_VERSION_REVISION
) & 0xFFF;
370 hw_step
= (hw_version
>> HW_VERSION_STEPPING
) & 0xFFFF;
371 dev_dbg(csid
->camss
->dev
, "CSID HW Version = %u.%u.%u\n",
372 hw_gen
, hw_rev
, hw_step
);
378 * csid_isr - CSID module interrupt service routine
379 * @irq: Interrupt line
382 * Return IRQ_HANDLED on success
384 static irqreturn_t
csid_isr(int irq
, void *dev
)
386 struct csid_device
*csid
= dev
;
391 val
= readl_relaxed(csid
->base
+ CSID_TOP_IRQ_STATUS
);
392 writel_relaxed(val
, csid
->base
+ CSID_TOP_IRQ_CLEAR
);
393 reset_done
= val
& BIT(TOP_IRQ_STATUS_RESET_DONE
);
395 val
= readl_relaxed(csid
->base
+ CSID_CSI2_RX_IRQ_STATUS
);
396 writel_relaxed(val
, csid
->base
+ CSID_CSI2_RX_IRQ_CLEAR
);
398 /* Read and clear IRQ status for each enabled RDI channel */
399 for (i
= 0; i
< MSM_CSID_MAX_SRC_STREAMS
; i
++)
400 if (csid
->phy
.en_vc
& BIT(i
)) {
401 val
= readl_relaxed(csid
->base
+ CSID_CSI2_RDIN_IRQ_STATUS(i
));
402 writel_relaxed(val
, csid
->base
+ CSID_CSI2_RDIN_IRQ_CLEAR(i
));
405 val
= 1 << IRQ_CMD_CLEAR
;
406 writel_relaxed(val
, csid
->base
+ CSID_IRQ_CMD
);
409 complete(&csid
->reset_complete
);
415 * csid_reset - Trigger reset on CSID module and wait to complete
418 * Return 0 on success or a negative error code otherwise
420 static int csid_reset(struct csid_device
*csid
)
425 reinit_completion(&csid
->reset_complete
);
427 writel_relaxed(1, csid
->base
+ CSID_TOP_IRQ_CLEAR
);
428 writel_relaxed(1, csid
->base
+ CSID_IRQ_CMD
);
429 writel_relaxed(1, csid
->base
+ CSID_TOP_IRQ_MASK
);
430 writel_relaxed(1, csid
->base
+ CSID_IRQ_CMD
);
432 /* preserve registers */
433 val
= 0x1e << RST_STROBES
;
434 writel_relaxed(val
, csid
->base
+ CSID_RST_STROBES
);
436 time
= wait_for_completion_timeout(&csid
->reset_complete
,
437 msecs_to_jiffies(CSID_RESET_TIMEOUT_MS
));
439 dev_err(csid
->camss
->dev
, "CSID reset timeout\n");
446 static u32
csid_src_pad_code(struct csid_device
*csid
, u32 sink_code
,
447 unsigned int match_format_idx
, u32 match_code
)
450 case MEDIA_BUS_FMT_SBGGR10_1X10
:
453 MEDIA_BUS_FMT_SBGGR10_1X10
,
454 MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE
,
457 return csid_find_code(src_code
, ARRAY_SIZE(src_code
),
458 match_format_idx
, match_code
);
460 case MEDIA_BUS_FMT_Y10_1X10
:
463 MEDIA_BUS_FMT_Y10_1X10
,
464 MEDIA_BUS_FMT_Y10_2X8_PADHI_LE
,
467 return csid_find_code(src_code
, ARRAY_SIZE(src_code
),
468 match_format_idx
, match_code
);
471 if (match_format_idx
> 0)
478 static void csid_subdev_init(struct csid_device
*csid
)
480 csid
->testgen
.modes
= csid_testgen_modes
;
481 csid
->testgen
.nmodes
= CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2
;
484 const struct csid_hw_ops csid_ops_gen2
= {
485 .configure_stream
= csid_configure_stream
,
486 .configure_testgen_pattern
= csid_configure_testgen_pattern
,
487 .hw_version
= csid_hw_version
,
490 .src_pad_code
= csid_src_pad_code
,
491 .subdev_init
= csid_subdev_init
,