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-gen1.h"
19 #define CAMSS_CSID_HW_VERSION 0x0
20 #define CAMSS_CSID_CORE_CTRL_0 0x004
21 #define CAMSS_CSID_CORE_CTRL_1 0x008
22 #define CAMSS_CSID_RST_CMD 0x010
23 #define CAMSS_CSID_CID_LUT_VC_n(n) (0x014 + 0x4 * (n))
24 #define CAMSS_CSID_CID_n_CFG(n) (0x024 + 0x4 * (n))
25 #define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0)
26 #define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1)
27 #define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4
28 #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8)
29 #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8)
30 #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9)
31 #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9)
32 #define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10)
33 #define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10)
34 #define CAMSS_CSID_IRQ_CLEAR_CMD 0x064
35 #define CAMSS_CSID_IRQ_MASK 0x068
36 #define CAMSS_CSID_IRQ_STATUS 0x06c
37 #define CAMSS_CSID_TG_CTRL 0x0a8
38 #define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436
39 #define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437
40 #define CAMSS_CSID_TG_VC_CFG 0x0ac
41 #define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff
42 #define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f
43 #define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0b4 + 0xc * (n))
44 #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n))
45 #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n))
47 static void csid_configure_stream(struct csid_device
*csid
, u8 enable
)
49 struct csid_testgen_config
*tg
= &csid
->testgen
;
50 u32 sink_code
= csid
->fmt
[MSM_CSID_PAD_SINK
].code
;
51 u32 src_code
= csid
->fmt
[MSM_CSID_PAD_SRC
].code
;
55 struct v4l2_mbus_framefmt
*input_format
;
56 const struct csid_format_info
*format
;
57 u8 vc
= 0; /* Virtual Channel 0 */
58 u8 cid
= vc
* 4; /* id of Virtual Channel and Data Type set */
62 /* Config Test Generator */
63 u32 num_bytes_per_line
, num_lines
;
65 input_format
= &csid
->fmt
[MSM_CSID_PAD_SRC
];
66 format
= csid_get_fmt_entry(csid
->res
->formats
->formats
,
67 csid
->res
->formats
->nformats
,
69 num_bytes_per_line
= input_format
->width
* format
->bpp
* format
->spp
/ 8;
70 num_lines
= input_format
->height
;
72 /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
74 val
= ((CAMSS_CSID_TG_VC_CFG_V_BLANKING
& 0xff) << 24) |
75 ((CAMSS_CSID_TG_VC_CFG_H_BLANKING
& 0x7ff) << 13);
76 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_VC_CFG
);
78 /* 28:16 bytes per lines, 12:0 num of lines */
79 val
= ((num_bytes_per_line
& 0x1fff) << 16) |
81 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_DT_n_CGG_0(0));
84 val
= format
->data_type
;
85 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_DT_n_CGG_1(0));
87 /* 2:0 output test pattern */
89 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_DT_n_CGG_2(0));
91 struct csid_phy_config
*phy
= &csid
->phy
;
93 input_format
= &csid
->fmt
[MSM_CSID_PAD_SINK
];
94 format
= csid_get_fmt_entry(csid
->res
->formats
->formats
,
95 csid
->res
->formats
->nformats
,
98 val
= phy
->lane_cnt
- 1;
99 val
|= phy
->lane_assign
<< 4;
101 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_CORE_CTRL_0
);
103 val
= phy
->csiphy_id
<< 17;
106 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_CORE_CTRL_1
);
111 dt_shift
= (cid
% 4) * 8;
113 val
= readl_relaxed(csid
->base
+ CAMSS_CSID_CID_LUT_VC_n(vc
));
114 val
&= ~(0xff << dt_shift
);
115 val
|= format
->data_type
<< dt_shift
;
116 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_CID_LUT_VC_n(vc
));
118 val
= CAMSS_CSID_CID_n_CFG_ISPIF_EN
;
119 val
|= CAMSS_CSID_CID_n_CFG_RDI_EN
;
120 val
|= format
->decode_format
<< CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT
;
121 val
|= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP
;
123 if ((sink_code
== MEDIA_BUS_FMT_SBGGR10_1X10
&&
124 src_code
== MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE
) ||
125 (sink_code
== MEDIA_BUS_FMT_Y10_1X10
&&
126 src_code
== MEDIA_BUS_FMT_Y10_2X8_PADHI_LE
)) {
127 val
|= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING
;
128 val
|= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16
;
129 val
|= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB
;
132 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_CID_n_CFG(cid
));
135 val
= CAMSS_CSID_TG_CTRL_ENABLE
;
136 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_CTRL
);
140 val
= CAMSS_CSID_TG_CTRL_DISABLE
;
141 writel_relaxed(val
, csid
->base
+ CAMSS_CSID_TG_CTRL
);
146 static int csid_configure_testgen_pattern(struct csid_device
*csid
, s32 val
)
148 if (val
> 0 && val
<= csid
->testgen
.nmodes
)
149 csid
->testgen
.mode
= val
;
154 static u32
csid_hw_version(struct csid_device
*csid
)
156 u32 hw_version
= readl_relaxed(csid
->base
+ CAMSS_CSID_HW_VERSION
);
158 dev_dbg(csid
->camss
->dev
, "CSID HW Version = 0x%08x\n", hw_version
);
164 * isr - CSID module interrupt service routine
165 * @irq: Interrupt line
168 * Return IRQ_HANDLED on success
170 static irqreturn_t
csid_isr(int irq
, void *dev
)
172 struct csid_device
*csid
= dev
;
175 value
= readl_relaxed(csid
->base
+ CAMSS_CSID_IRQ_STATUS
);
176 writel_relaxed(value
, csid
->base
+ CAMSS_CSID_IRQ_CLEAR_CMD
);
178 if ((value
>> 11) & 0x1)
179 complete(&csid
->reset_complete
);
185 * csid_reset - Trigger reset on CSID module and wait to complete
188 * Return 0 on success or a negative error code otherwise
190 static int csid_reset(struct csid_device
*csid
)
194 reinit_completion(&csid
->reset_complete
);
196 writel_relaxed(0x7fff, csid
->base
+ CAMSS_CSID_RST_CMD
);
198 time
= wait_for_completion_timeout(&csid
->reset_complete
,
199 msecs_to_jiffies(CSID_RESET_TIMEOUT_MS
));
201 dev_err(csid
->camss
->dev
, "CSID reset timeout\n");
208 static u32
csid_src_pad_code(struct csid_device
*csid
, u32 sink_code
,
209 unsigned int match_format_idx
, u32 match_code
)
212 case MEDIA_BUS_FMT_SBGGR10_1X10
:
215 MEDIA_BUS_FMT_SBGGR10_1X10
,
216 MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE
,
219 return csid_find_code(src_code
, ARRAY_SIZE(src_code
),
220 match_format_idx
, match_code
);
222 case MEDIA_BUS_FMT_Y10_1X10
:
225 MEDIA_BUS_FMT_Y10_1X10
,
226 MEDIA_BUS_FMT_Y10_2X8_PADHI_LE
,
229 return csid_find_code(src_code
, ARRAY_SIZE(src_code
),
230 match_format_idx
, match_code
);
233 if (match_format_idx
> 0)
240 static void csid_subdev_init(struct csid_device
*csid
)
242 csid
->testgen
.modes
= csid_testgen_modes
;
243 csid
->testgen
.nmodes
= CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1
;
246 const struct csid_hw_ops csid_ops_4_7
= {
247 .configure_stream
= csid_configure_stream
,
248 .configure_testgen_pattern
= csid_configure_testgen_pattern
,
249 .hw_version
= csid_hw_version
,
252 .src_pad_code
= csid_src_pad_code
,
253 .subdev_init
= csid_subdev_init
,