1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * camss-csid-4-1.c |
4 | * |
5 | * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module |
6 | * |
7 | * Copyright (C) 2020 Linaro Ltd. |
8 | */ |
9 | |
10 | #include <linux/completion.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/io.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/of.h> |
15 | |
16 | #include "camss-csid.h" |
17 | #include "camss-csid-gen1.h" |
18 | #include "camss.h" |
19 | |
20 | #define CAMSS_CSID_HW_VERSION 0x0 |
21 | #define CAMSS_CSID_CORE_CTRL_0 0x004 |
22 | #define CAMSS_CSID_CORE_CTRL_1 0x008 |
23 | #define CAMSS_CSID_RST_CMD 0x00c |
24 | #define CAMSS_CSID_CID_LUT_VC_n(n) (0x010 + 0x4 * (n)) |
25 | #define CAMSS_CSID_CID_n_CFG(n) (0x020 + 0x4 * (n)) |
26 | #define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) |
27 | #define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) |
28 | #define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 |
29 | #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8) |
30 | #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8) |
31 | #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) |
32 | #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) |
33 | #define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) |
34 | #define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) |
35 | #define CAMSS_CSID_IRQ_CLEAR_CMD 0x060 |
36 | #define CAMSS_CSID_IRQ_MASK 0x064 |
37 | #define CAMSS_CSID_IRQ_STATUS 0x068 |
38 | #define CAMSS_CSID_TG_CTRL 0x0a0 |
39 | #define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 |
40 | #define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 |
41 | #define CAMSS_CSID_TG_VC_CFG 0x0a4 |
42 | #define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff |
43 | #define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f |
44 | #define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0ac + 0xc * (n)) |
45 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) |
46 | #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n)) |
47 | |
48 | static const struct csid_format csid_formats[] = { |
49 | { |
50 | MEDIA_BUS_FMT_UYVY8_1X16, |
51 | DATA_TYPE_YUV422_8BIT, |
52 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
53 | 8, |
54 | 2, |
55 | }, |
56 | { |
57 | MEDIA_BUS_FMT_VYUY8_1X16, |
58 | DATA_TYPE_YUV422_8BIT, |
59 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
60 | 8, |
61 | 2, |
62 | }, |
63 | { |
64 | MEDIA_BUS_FMT_YUYV8_1X16, |
65 | DATA_TYPE_YUV422_8BIT, |
66 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
67 | 8, |
68 | 2, |
69 | }, |
70 | { |
71 | MEDIA_BUS_FMT_YVYU8_1X16, |
72 | DATA_TYPE_YUV422_8BIT, |
73 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
74 | 8, |
75 | 2, |
76 | }, |
77 | { |
78 | MEDIA_BUS_FMT_SBGGR8_1X8, |
79 | DATA_TYPE_RAW_8BIT, |
80 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
81 | 8, |
82 | 1, |
83 | }, |
84 | { |
85 | MEDIA_BUS_FMT_SGBRG8_1X8, |
86 | DATA_TYPE_RAW_8BIT, |
87 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
88 | 8, |
89 | 1, |
90 | }, |
91 | { |
92 | MEDIA_BUS_FMT_SGRBG8_1X8, |
93 | DATA_TYPE_RAW_8BIT, |
94 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
95 | 8, |
96 | 1, |
97 | }, |
98 | { |
99 | MEDIA_BUS_FMT_SRGGB8_1X8, |
100 | DATA_TYPE_RAW_8BIT, |
101 | DECODE_FORMAT_UNCOMPRESSED_8_BIT, |
102 | 8, |
103 | 1, |
104 | }, |
105 | { |
106 | MEDIA_BUS_FMT_SBGGR10_1X10, |
107 | DATA_TYPE_RAW_10BIT, |
108 | DECODE_FORMAT_UNCOMPRESSED_10_BIT, |
109 | 10, |
110 | 1, |
111 | }, |
112 | { |
113 | MEDIA_BUS_FMT_SGBRG10_1X10, |
114 | DATA_TYPE_RAW_10BIT, |
115 | DECODE_FORMAT_UNCOMPRESSED_10_BIT, |
116 | 10, |
117 | 1, |
118 | }, |
119 | { |
120 | MEDIA_BUS_FMT_SGRBG10_1X10, |
121 | DATA_TYPE_RAW_10BIT, |
122 | DECODE_FORMAT_UNCOMPRESSED_10_BIT, |
123 | 10, |
124 | 1, |
125 | }, |
126 | { |
127 | MEDIA_BUS_FMT_SRGGB10_1X10, |
128 | DATA_TYPE_RAW_10BIT, |
129 | DECODE_FORMAT_UNCOMPRESSED_10_BIT, |
130 | 10, |
131 | 1, |
132 | }, |
133 | { |
134 | MEDIA_BUS_FMT_SBGGR12_1X12, |
135 | DATA_TYPE_RAW_12BIT, |
136 | DECODE_FORMAT_UNCOMPRESSED_12_BIT, |
137 | 12, |
138 | 1, |
139 | }, |
140 | { |
141 | MEDIA_BUS_FMT_SGBRG12_1X12, |
142 | DATA_TYPE_RAW_12BIT, |
143 | DECODE_FORMAT_UNCOMPRESSED_12_BIT, |
144 | 12, |
145 | 1, |
146 | }, |
147 | { |
148 | MEDIA_BUS_FMT_SGRBG12_1X12, |
149 | DATA_TYPE_RAW_12BIT, |
150 | DECODE_FORMAT_UNCOMPRESSED_12_BIT, |
151 | 12, |
152 | 1, |
153 | }, |
154 | { |
155 | MEDIA_BUS_FMT_SRGGB12_1X12, |
156 | DATA_TYPE_RAW_12BIT, |
157 | DECODE_FORMAT_UNCOMPRESSED_12_BIT, |
158 | 12, |
159 | 1, |
160 | }, |
161 | { |
162 | MEDIA_BUS_FMT_Y10_1X10, |
163 | DATA_TYPE_RAW_10BIT, |
164 | DECODE_FORMAT_UNCOMPRESSED_10_BIT, |
165 | 10, |
166 | 1, |
167 | }, |
168 | }; |
169 | |
170 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
171 | { |
172 | struct csid_testgen_config *tg = &csid->testgen; |
173 | u32 val; |
174 | |
175 | if (enable) { |
176 | struct v4l2_mbus_framefmt *input_format; |
177 | const struct csid_format *format; |
178 | u8 vc = 0; /* Virtual Channel 0 */ |
179 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ |
180 | u8 dt_shift; |
181 | |
182 | if (tg->enabled) { |
183 | /* Config Test Generator */ |
184 | u32 num_lines, num_bytes_per_line; |
185 | |
186 | input_format = &csid->fmt[MSM_CSID_PAD_SRC]; |
187 | format = csid_get_fmt_entry(formats: csid->formats, nformats: csid->nformats, |
188 | code: input_format->code); |
189 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; |
190 | num_lines = input_format->height; |
191 | |
192 | /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ |
193 | /* 1:0 VC */ |
194 | val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | |
195 | ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); |
196 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG); |
197 | |
198 | /* 28:16 bytes per lines, 12:0 num of lines */ |
199 | val = ((num_bytes_per_line & 0x1fff) << 16) | |
200 | (num_lines & 0x1fff); |
201 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0)); |
202 | |
203 | /* 5:0 data type */ |
204 | val = format->data_type; |
205 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0)); |
206 | |
207 | /* 2:0 output test pattern */ |
208 | val = tg->mode - 1; |
209 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0)); |
210 | } else { |
211 | struct csid_phy_config *phy = &csid->phy; |
212 | |
213 | input_format = &csid->fmt[MSM_CSID_PAD_SINK]; |
214 | format = csid_get_fmt_entry(formats: csid->formats, nformats: csid->nformats, |
215 | code: input_format->code); |
216 | |
217 | val = phy->lane_cnt - 1; |
218 | val |= phy->lane_assign << 4; |
219 | |
220 | writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0); |
221 | |
222 | val = phy->csiphy_id << 17; |
223 | val |= 0x9; |
224 | |
225 | writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1); |
226 | } |
227 | |
228 | /* Config LUT */ |
229 | |
230 | dt_shift = (cid % 4) * 8; |
231 | val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); |
232 | val &= ~(0xff << dt_shift); |
233 | val |= format->data_type << dt_shift; |
234 | writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); |
235 | |
236 | val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; |
237 | val |= CAMSS_CSID_CID_n_CFG_RDI_EN; |
238 | val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; |
239 | val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; |
240 | writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid)); |
241 | |
242 | if (tg->enabled) { |
243 | val = CAMSS_CSID_TG_CTRL_ENABLE; |
244 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); |
245 | } |
246 | } else { |
247 | if (tg->enabled) { |
248 | val = CAMSS_CSID_TG_CTRL_DISABLE; |
249 | writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); |
250 | } |
251 | } |
252 | } |
253 | |
254 | static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) |
255 | { |
256 | if (val > 0 && val <= csid->testgen.nmodes) |
257 | csid->testgen.mode = val; |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static u32 csid_hw_version(struct csid_device *csid) |
263 | { |
264 | u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); |
265 | |
266 | dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n" , hw_version); |
267 | |
268 | return hw_version; |
269 | } |
270 | |
271 | static irqreturn_t csid_isr(int irq, void *dev) |
272 | { |
273 | struct csid_device *csid = dev; |
274 | u32 value; |
275 | |
276 | value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS); |
277 | writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD); |
278 | |
279 | if ((value >> 11) & 0x1) |
280 | complete(&csid->reset_complete); |
281 | |
282 | return IRQ_HANDLED; |
283 | } |
284 | |
285 | static int csid_reset(struct csid_device *csid) |
286 | { |
287 | unsigned long time; |
288 | |
289 | reinit_completion(x: &csid->reset_complete); |
290 | |
291 | writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD); |
292 | |
293 | time = wait_for_completion_timeout(x: &csid->reset_complete, |
294 | timeout: msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); |
295 | if (!time) { |
296 | dev_err(csid->camss->dev, "CSID reset timeout\n" ); |
297 | return -EIO; |
298 | } |
299 | |
300 | return 0; |
301 | } |
302 | |
303 | static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, |
304 | unsigned int match_format_idx, u32 match_code) |
305 | { |
306 | if (match_format_idx > 0) |
307 | return 0; |
308 | |
309 | return sink_code; |
310 | } |
311 | |
312 | static void csid_subdev_init(struct csid_device *csid) |
313 | { |
314 | csid->formats = csid_formats; |
315 | csid->nformats = ARRAY_SIZE(csid_formats); |
316 | csid->testgen.modes = csid_testgen_modes; |
317 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; |
318 | } |
319 | |
320 | const struct csid_hw_ops csid_ops_4_1 = { |
321 | .configure_stream = csid_configure_stream, |
322 | .configure_testgen_pattern = csid_configure_testgen_pattern, |
323 | .hw_version = csid_hw_version, |
324 | .isr = csid_isr, |
325 | .reset = csid_reset, |
326 | .src_pad_code = csid_src_pad_code, |
327 | .subdev_init = csid_subdev_init, |
328 | }; |
329 | |