Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only
2 : /*
3 : * Copyright (C) 2013--2024 Intel Corporation
4 : */
5 :
6 : #include <linux/atomic.h>
7 : #include <linux/bitfield.h>
8 : #include <linux/bits.h>
9 : #include <linux/delay.h>
10 : #include <linux/device.h>
11 : #include <linux/err.h>
12 : #include <linux/io.h>
13 : #include <linux/minmax.h>
14 : #include <linux/sprintf.h>
15 :
16 : #include <media/media-entity.h>
17 : #include <media/v4l2-ctrls.h>
18 : #include <media/v4l2-device.h>
19 : #include <media/v4l2-event.h>
20 : #include <media/v4l2-subdev.h>
21 :
22 : #include "ipu6-bus.h"
23 : #include "ipu6-isys.h"
24 : #include "ipu6-isys-csi2.h"
25 : #include "ipu6-isys-subdev.h"
26 : #include "ipu6-platform-isys-csi2-reg.h"
27 :
28 : #include "ipu4-compat.h"
29 :
30 : static int csi2_log_first_sof = 2;
31 : module_param(csi2_log_first_sof, int, 0644);
32 : MODULE_PARM_DESC(csi2_log_first_sof, "How many frames SOF should be logged during stream start");
33 :
34 :
35 : static const u32 csi2_supported_codes[] = {
36 : MEDIA_BUS_FMT_RGB565_1X16,
37 : MEDIA_BUS_FMT_RGB888_1X24,
38 : MEDIA_BUS_FMT_UYVY8_1X16,
39 : MEDIA_BUS_FMT_YUYV8_1X16,
40 : MEDIA_BUS_FMT_SBGGR10_1X10,
41 : MEDIA_BUS_FMT_SGBRG10_1X10,
42 : MEDIA_BUS_FMT_SGRBG10_1X10,
43 : MEDIA_BUS_FMT_SRGGB10_1X10,
44 : MEDIA_BUS_FMT_SBGGR12_1X12,
45 : MEDIA_BUS_FMT_SGBRG12_1X12,
46 : MEDIA_BUS_FMT_SGRBG12_1X12,
47 : MEDIA_BUS_FMT_SRGGB12_1X12,
48 : MEDIA_BUS_FMT_SBGGR8_1X8,
49 : MEDIA_BUS_FMT_SGBRG8_1X8,
50 : MEDIA_BUS_FMT_SGRBG8_1X8,
51 : MEDIA_BUS_FMT_SRGGB8_1X8,
52 : MEDIA_BUS_FMT_Y8_1X8,
53 : MEDIA_BUS_FMT_Y10_1X10,
54 : MEDIA_BUS_FMT_Y12_1X12,
55 : MEDIA_BUS_FMT_Y16_1X16,
56 : MEDIA_BUS_FMT_META_8,
57 : MEDIA_BUS_FMT_META_10,
58 : MEDIA_BUS_FMT_META_12,
59 : MEDIA_BUS_FMT_META_16,
60 : MEDIA_BUS_FMT_META_24,
61 : 0
62 : };
63 :
64 : /*
65 : * Strings corresponding to CSI-2 receiver errors are here.
66 : * Corresponding macros are defined in the header file.
67 : */
68 : static const struct ipu6_csi2_error dphy_rx_errors[] = {
69 : { "Single packet header error corrected", true },
70 : { "Multiple packet header errors detected", true },
71 : { "Payload checksum (CRC) error", true },
72 : { "Transfer FIFO overflow", false },
73 : { "Reserved short packet data type detected", true },
74 : { "Reserved long packet data type detected", true },
75 : { "Incomplete long packet detected", false },
76 : { "Frame sync error", false },
77 : { "Line sync error", false },
78 : { "DPHY recoverable synchronization error", true },
79 : { "DPHY fatal error", false },
80 : { "DPHY elastic FIFO overflow", false },
81 : { "Inter-frame short packet discarded", true },
82 : { "Inter-frame long packet discarded", true },
83 : { "MIPI pktgen overflow", false },
84 : { "MIPI pktgen data loss", false },
85 : { "FIFO overflow", false },
86 : { "Lane deskew", false },
87 : { "SOT sync error", false },
88 : { "HSIDLE detected", false }
89 : };
90 :
91 1 : s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2)
92 : {
93 : struct media_pad *src_pad;
94 :
95 1 : if (!csi2)
96 : return -EINVAL;
97 :
98 1 : src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
99 1 : if (IS_ERR(src_pad)) {
100 0 : dev_err(&csi2->isys->adev->auxdev.dev,
101 : "can't get source pad of %s (%pe)\n",
102 : csi2->asd.sd.name, src_pad);
103 0 : return PTR_ERR(src_pad);
104 : }
105 :
106 1 : return v4l2_get_link_freq(src_pad, 0, 0);
107 : }
108 :
109 0 : static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
110 : struct v4l2_event_subscription *sub)
111 : {
112 : struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
113 : struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
114 0 : struct device *dev = &csi2->isys->adev->auxdev.dev;
115 :
116 0 : dev_dbg(dev, "csi2 subscribe event(type %u id %u)\n",
117 : sub->type, sub->id);
118 :
119 0 : switch (sub->type) {
120 0 : case V4L2_EVENT_FRAME_SYNC:
121 0 : return v4l2_event_subscribe(fh, sub, 10, NULL);
122 0 : case V4L2_EVENT_CTRL:
123 0 : return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
124 : default:
125 : return -EINVAL;
126 : }
127 : }
128 :
129 : static const struct v4l2_subdev_core_ops csi2_sd_core_ops = {
130 : .subscribe_event = csi2_subscribe_event,
131 : .unsubscribe_event = v4l2_event_subdev_unsubscribe,
132 : };
133 :
134 : /*
135 : * The input system CSI2+ receiver has several
136 : * parameters affecting the receiver timings. These depend
137 : * on the MIPI bus frequency F in Hz (sensor transmitter rate)
138 : * as follows:
139 : * register value = (A/1e9 + B * UI) / COUNT_ACC
140 : * where
141 : * UI = 1 / (2 * F) in seconds
142 : * COUNT_ACC = counter accuracy in seconds
143 : * COUNT_ACC = 0.125 ns = 1 / 8 ns, ACCINV = 8.
144 : *
145 : * A and B are coefficients from the table below,
146 : * depending whether the register minimum or maximum value is
147 : * calculated.
148 : * Minimum Maximum
149 : * Clock lane A B A B
150 : * reg_rx_csi_dly_cnt_termen_clane 0 0 38 0
151 : * reg_rx_csi_dly_cnt_settle_clane 95 -8 300 -16
152 : * Data lanes
153 : * reg_rx_csi_dly_cnt_termen_dlane0 0 0 35 4
154 : * reg_rx_csi_dly_cnt_settle_dlane0 85 -2 145 -6
155 : * reg_rx_csi_dly_cnt_termen_dlane1 0 0 35 4
156 : * reg_rx_csi_dly_cnt_settle_dlane1 85 -2 145 -6
157 : * reg_rx_csi_dly_cnt_termen_dlane2 0 0 35 4
158 : * reg_rx_csi_dly_cnt_settle_dlane2 85 -2 145 -6
159 : * reg_rx_csi_dly_cnt_termen_dlane3 0 0 35 4
160 : * reg_rx_csi_dly_cnt_settle_dlane3 85 -2 145 -6
161 : *
162 : * We use the minimum values of both A and B.
163 : */
164 :
165 : #define DIV_SHIFT 8
166 : #define CSI2_ACCINV 8
167 :
168 : static u32 calc_timing(s32 a, s32 b, s64 link_freq, s32 accinv)
169 : {
170 1 : return accinv * a + (accinv * b * (500000000 >> DIV_SHIFT)
171 1 : / (s32)(link_freq >> DIV_SHIFT));
172 : }
173 :
174 : static int
175 1 : ipu6_isys_csi2_calc_timing(struct ipu6_isys_csi2 *csi2,
176 : struct ipu6_isys_csi2_timing *timing, s32 accinv)
177 : {
178 1 : struct device *dev = &csi2->isys->adev->auxdev.dev;
179 : s64 link_freq;
180 :
181 1 : link_freq = ipu6_isys_csi2_get_link_freq(csi2);
182 1 : if (link_freq < 0)
183 0 : return link_freq;
184 :
185 1 : timing->ctermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A,
186 : CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B,
187 : link_freq, accinv);
188 1 : timing->csettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A,
189 : CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_B,
190 : link_freq, accinv);
191 1 : timing->dtermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A,
192 : CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_B,
193 : link_freq, accinv);
194 1 : timing->dsettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A,
195 : CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_B,
196 : link_freq, accinv);
197 :
198 1 : dev_dbg(dev, "ctermen %u csettle %u dtermen %u dsettle %u\n",
199 : timing->ctermen, timing->csettle,
200 : timing->dtermen, timing->dsettle);
201 :
202 : return 0;
203 : }
204 :
205 : #ifdef IPU6
206 : void ipu6_isys_register_errors(struct ipu6_isys_csi2 *csi2)
207 : {
208 : u32 irq = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
209 : CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
210 : struct ipu6_isys *isys = csi2->isys;
211 : u32 mask;
212 :
213 : mask = isys->pdata->ipdata->csi2.irq_mask;
214 : writel(irq & mask, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
215 : CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
216 : csi2->receiver_errors |= irq & mask;
217 : }
218 :
219 : void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
220 : {
221 : struct device *dev = &csi2->isys->adev->auxdev.dev;
222 : const struct ipu6_csi2_error *errors;
223 : u32 status;
224 : u32 i;
225 :
226 : /* register errors once more in case of interrupts are disabled */
227 : ipu6_isys_register_errors(csi2);
228 : status = csi2->receiver_errors;
229 : csi2->receiver_errors = 0;
230 : errors = dphy_rx_errors;
231 :
232 : for (i = 0; i < CSI_RX_NUM_ERRORS_IN_IRQ; i++) {
233 : if (status & BIT(i))
234 : dev_err_ratelimited(dev, "csi2-%i error: %s\n",
235 : csi2->port, errors[i].error_string);
236 : }
237 : }
238 : #else
239 0 : void ipu4_isys_register_errors(struct ipu6_isys_csi2 *csi2)
240 : {
241 0 : u32 status = readl(csi2->base + CSI2_REG_CSIRX_IRQ_STATUS);
242 :
243 3 : writel(status, csi2->base + CSI2_REG_CSIRX_IRQ_CLEAR);
244 3 : csi2->receiver_errors |= status;
245 0 : }
246 :
247 3 : void ipu4_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
248 : {
249 3 : struct device *dev = &csi2->isys->adev->auxdev.dev;
250 : /*
251 : * Strings corresponding to CSI-2 receiver errors are here.
252 : * Corresponding macros are defined in the header file.
253 : */
254 : static const struct ipu_isys_csi2_error {
255 : const char *error_string;
256 : bool is_info_only;
257 : } errors[] = {
258 : {"Single packet header error corrected", true},
259 : {"Multiple packet header errors detected", true},
260 : {"Payload checksum (CRC) error", true},
261 : {"FIFO overflow", false},
262 : {"Reserved short packet data type detected", true},
263 : {"Reserved long packet data type detected", true},
264 : {"Incomplete long packet detected", false},
265 : {"Frame sync error", false},
266 : {"Line sync error", false},
267 : {"DPHY recoverable synchronization error", true},
268 : {"DPHY non-recoverable synchronization error", false},
269 : {"Escape mode error", true},
270 : {"Escape mode trigger event", true},
271 : {"Escape mode ultra-low power state for data lane(s)", true},
272 : {"Escape mode ultra-low power state exit for clock lane", true},
273 : {"Inter-frame short packet discarded", true},
274 : {"Inter-frame long packet discarded", true},
275 : };
276 : u32 status;
277 : unsigned int i;
278 :
279 : /* Register errors once more in case of error interrupts are disabled */
280 : ipu4_isys_register_errors(csi2);
281 : status = csi2->receiver_errors;
282 3 : csi2->receiver_errors = 0;
283 :
284 54 : for (i = 0; i < ARRAY_SIZE(errors); i++) {
285 51 : if (!(status & BIT(i)))
286 51 : continue;
287 :
288 0 : if (errors[i].is_info_only)
289 0 : dev_dbg(dev,
290 : "csi2-%i info: %s\n",
291 : csi2->port, errors[i].error_string);
292 : else
293 0 : dev_err_ratelimited(dev,
294 : "csi2-%i error: %s\n",
295 : csi2->port,
296 : errors[i].error_string);
297 : }
298 3 : }
299 : #endif
300 :
301 2 : static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
302 : const struct ipu6_isys_csi2_timing *timing,
303 : unsigned int nlanes, int enable)
304 : {
305 : struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
306 : struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
307 2 : struct ipu6_isys *isys = csi2->isys;
308 2 : struct device *dev = &isys->adev->auxdev.dev;
309 : #ifdef IPU6
310 : struct ipu6_isys_csi2_config cfg;
311 : unsigned int nports;
312 : int ret = 0;
313 : u32 mask = 0;
314 : u32 i;
315 :
316 : dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
317 : csi2->port, nlanes);
318 :
319 : cfg.port = csi2->port;
320 : cfg.nlanes = nlanes;
321 :
322 : mask = isys->pdata->ipdata->csi2.irq_mask;
323 : nports = isys->pdata->ipdata->csi2.nports;
324 :
325 : if (!enable) {
326 : writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
327 : writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
328 :
329 : writel(0,
330 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
331 : CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
332 : writel(mask,
333 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
334 : CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
335 : writel(0,
336 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
337 : CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
338 : writel(0xffffffff,
339 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
340 : CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
341 :
342 : isys->phy_set_power(isys, &cfg, timing, false);
343 :
344 : writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
345 : (isys->pdata->ipdata->csi2.fw_access_port_ofs,
346 : csi2->port));
347 : writel(0, isys->pdata->base +
348 : CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
349 :
350 : return ret;
351 : }
352 :
353 : /* reset port reset */
354 : writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
355 : usleep_range(100, 200);
356 : writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
357 :
358 : /* enable port clock */
359 : for (i = 0; i < nports; i++) {
360 : writel(1, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(i));
361 : writel(1, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
362 : (isys->pdata->ipdata->csi2.fw_access_port_ofs, i));
363 : }
364 :
365 : /* enable all error related irq */
366 : writel(mask,
367 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
368 : CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
369 : writel(mask,
370 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
371 : CSI_PORT_REG_BASE_IRQ_MASK_OFFSET);
372 : writel(mask,
373 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
374 : CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
375 : writel(mask,
376 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
377 : CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET);
378 : writel(mask,
379 : csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
380 : CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
381 :
382 : /*
383 : * Using event from firmware instead of irq to handle CSI2 sync event
384 : * which can reduce system wakeups. If CSI2 sync irq enabled, we need
385 : * disable the firmware CSI2 sync event to avoid duplicate handling.
386 : */
387 : writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
388 : CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
389 : writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
390 : CSI_PORT_REG_BASE_IRQ_MASK_OFFSET);
391 : writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
392 : CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
393 : writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
394 : CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET);
395 : writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
396 : CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
397 :
398 : /* configure to enable FE and PPI2CSI */
399 : writel(0, csi2->base + CSI_REG_CSI_FE_MODE);
400 : writel(CSI_SENSOR_INPUT, csi2->base + CSI_REG_CSI_FE_MUX_CTRL);
401 : writel(CSI_CNTR_SENSOR_LINE_ID | CSI_CNTR_SENSOR_FRAME_ID,
402 : csi2->base + CSI_REG_CSI_FE_SYNC_CNTR_SEL);
403 : writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK, nlanes - 1),
404 : csi2->base + CSI_REG_PPI2CSI_CONFIG_PPI_INTF);
405 :
406 : writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
407 : writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
408 :
409 : ret = isys->phy_set_power(isys, &cfg, timing, true);
410 : if (ret)
411 : dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port,
412 : ret);
413 :
414 : return ret;
415 : #else
416 : u32 i = 0;
417 : u32 val = 0;
418 : u32 csi2part = 0;
419 : u32 csi2csirx = 0;
420 :
421 3 : dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
422 : csi2->port, nlanes);
423 :
424 2 : if (!enable) {
425 1 : ipu4_isys_csi2_error(csi2);
426 :
427 1 : val = readl(csi2->base + CSI2_REG_CSI_RX_CONFIG);
428 1 : val &= ~(CSI2_CSI_RX_CONFIG_DISABLE_BYTE_CLK_GATING |
429 : CSI2_CSI_RX_CONFIG_RELEASE_LP11);
430 1 : writel(val, csi2->base + CSI2_REG_CSI_RX_CONFIG);
431 :
432 1 : writel(0, csi2->base + CSI2_REG_CSI_RX_ENABLE);
433 :
434 : /* Disable interrupts */
435 1 : writel(0, csi2->base + CSI2_REG_CSI2S2M_IRQ_MASK);
436 1 : writel(0, csi2->base + CSI2_REG_CSI2S2M_IRQ_ENABLE);
437 1 : writel(0, csi2->base + CSI2_REG_CSI2PART_IRQ_MASK);
438 1 : writel(0, csi2->base + CSI2_REG_CSI2PART_IRQ_ENABLE);
439 1 : return 0;
440 : }
441 :
442 1 : writel(timing->ctermen,
443 1 : csi2->base + CSI2_REG_CSI_RX_DLY_CNT_TERMEN_CLANE);
444 1 : writel(timing->csettle,
445 1 : csi2->base + CSI2_REG_CSI_RX_DLY_CNT_SETTLE_CLANE);
446 :
447 5 : for (i = 0; i < nlanes; i++) {
448 4 : writel(timing->dtermen,
449 4 : csi2->base +
450 4 : CSI2_REG_CSI_RX_DLY_CNT_TERMEN_DLANE(i));
451 4 : writel(timing->dsettle,
452 4 : csi2->base +
453 4 : CSI2_REG_CSI_RX_DLY_CNT_SETTLE_DLANE(i));
454 : }
455 :
456 1 : val = readl(csi2->base + CSI2_REG_CSI_RX_CONFIG);
457 1 : val |= CSI2_CSI_RX_CONFIG_DISABLE_BYTE_CLK_GATING |
458 : CSI2_CSI_RX_CONFIG_RELEASE_LP11;
459 1 : writel(val, csi2->base + CSI2_REG_CSI_RX_CONFIG);
460 :
461 1 : writel(nlanes, csi2->base + CSI2_REG_CSI_RX_NOF_ENABLED_LANES);
462 : writel(CSI2_CSI_RX_ENABLE_ENABLE,
463 1 : csi2->base + CSI2_REG_CSI_RX_ENABLE);
464 :
465 : /* SOF/EOF of VC0-VC3 enabled from CSI2PART register in B0 */
466 5 : for (i = 0; i < NR_OF_CSI2_VC; i++)
467 4 : csi2part |= IPU_CSI_RX_IRQ_FS_VC(i) | IPU_CSI_RX_IRQ_FE_VC(i);
468 :
469 : /* Enable csi2 receiver error interrupts */
470 : csi2csirx = BIT(CSI2_CSIRX_NUM_ERRORS) - 1;
471 1 : writel(csi2csirx, csi2->base + CSI2_REG_CSIRX_IRQ_EDGE);
472 1 : writel(0, csi2->base + CSI2_REG_CSIRX_IRQ_LEVEL_NOT_PULSE);
473 1 : writel(csi2csirx, csi2->base + CSI2_REG_CSIRX_IRQ_CLEAR);
474 1 : writel(csi2csirx, csi2->base + CSI2_REG_CSIRX_IRQ_MASK);
475 1 : writel(csi2csirx, csi2->base + CSI2_REG_CSIRX_IRQ_ENABLE);
476 :
477 : /* Enable csi2 error and SOF-related irqs */
478 1 : writel(csi2part, csi2->base + CSI2_REG_CSI2PART_IRQ_EDGE);
479 1 : writel(0, csi2->base + CSI2_REG_CSI2PART_IRQ_LEVEL_NOT_PULSE);
480 1 : writel(csi2part, csi2->base + CSI2_REG_CSI2PART_IRQ_CLEAR);
481 1 : writel(csi2part, csi2->base + CSI2_REG_CSI2PART_IRQ_MASK);
482 1 : writel(csi2part, csi2->base + CSI2_REG_CSI2PART_IRQ_ENABLE);
483 1 : return 0;
484 : #endif
485 : }
486 :
487 1 : static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
488 : struct v4l2_subdev_state *state,
489 : u32 pad, u64 streams_mask)
490 : {
491 : struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
492 : struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
493 1 : struct ipu6_isys_csi2_timing timing = { };
494 : struct v4l2_subdev *remote_sd;
495 : struct media_pad *remote_pad;
496 : u64 sink_streams;
497 : int ret;
498 :
499 1 : remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
500 1 : remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
501 :
502 : sink_streams =
503 1 : v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
504 : &streams_mask);
505 :
506 1 : ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
507 1 : if (ret)
508 : return ret;
509 :
510 1 : ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
511 1 : if (ret)
512 : return ret;
513 :
514 1 : ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
515 : sink_streams);
516 1 : if (ret) {
517 0 : ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
518 0 : return ret;
519 : }
520 :
521 : return 0;
522 : }
523 :
524 1 : static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
525 : struct v4l2_subdev_state *state,
526 : u32 pad, u64 streams_mask)
527 : {
528 : struct v4l2_subdev *remote_sd;
529 : struct media_pad *remote_pad;
530 : u64 sink_streams;
531 :
532 : sink_streams =
533 1 : v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
534 : &streams_mask);
535 :
536 1 : remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
537 1 : remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
538 :
539 1 : ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
540 :
541 1 : v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
542 :
543 1 : return 0;
544 : }
545 :
546 0 : static int ipu6_isys_csi2_set_sel(struct v4l2_subdev *sd,
547 : struct v4l2_subdev_state *state,
548 : struct v4l2_subdev_selection *sel)
549 : {
550 : struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
551 0 : struct device *dev = &asd->isys->adev->auxdev.dev;
552 : struct v4l2_mbus_framefmt *sink_ffmt;
553 : struct v4l2_mbus_framefmt *src_ffmt;
554 : struct v4l2_rect *crop;
555 :
556 0 : if (sel->pad == CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
557 : return -EINVAL;
558 :
559 0 : sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
560 : sel->pad,
561 : sel->stream);
562 0 : if (!sink_ffmt)
563 : return -EINVAL;
564 :
565 0 : src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream);
566 0 : if (!src_ffmt)
567 : return -EINVAL;
568 :
569 0 : crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
570 0 : if (!crop)
571 : return -EINVAL;
572 :
573 : /* Only vertical cropping is supported */
574 0 : sel->r.left = 0;
575 0 : sel->r.width = sink_ffmt->width;
576 : /* Non-bayer formats can't be single line cropped */
577 0 : if (!ipu6_isys_is_bayer_format(sink_ffmt->code))
578 0 : sel->r.top &= ~1;
579 0 : sel->r.height = clamp(sel->r.height & ~1, IPU6_ISYS_MIN_HEIGHT,
580 : sink_ffmt->height - sel->r.top);
581 0 : *crop = sel->r;
582 :
583 : /* update source pad format */
584 0 : src_ffmt->width = sel->r.width;
585 0 : src_ffmt->height = sel->r.height;
586 0 : if (ipu6_isys_is_bayer_format(sink_ffmt->code))
587 0 : src_ffmt->code = ipu6_isys_convert_bayer_order(sink_ffmt->code,
588 : sel->r.left,
589 : sel->r.top);
590 0 : dev_dbg(dev, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n",
591 : sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height,
592 : src_ffmt->code);
593 :
594 : return 0;
595 : }
596 :
597 0 : static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
598 : struct v4l2_subdev_state *state,
599 : struct v4l2_subdev_selection *sel)
600 : {
601 : struct v4l2_mbus_framefmt *sink_ffmt;
602 : struct v4l2_rect *crop;
603 : int ret = 0;
604 :
605 0 : if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK)
606 : return -EINVAL;
607 :
608 0 : sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
609 : sel->pad,
610 : sel->stream);
611 0 : if (!sink_ffmt)
612 : return -EINVAL;
613 :
614 0 : crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
615 0 : if (!crop)
616 : return -EINVAL;
617 :
618 0 : switch (sel->target) {
619 0 : case V4L2_SEL_TGT_CROP_DEFAULT:
620 : case V4L2_SEL_TGT_CROP_BOUNDS:
621 0 : sel->r.left = 0;
622 0 : sel->r.top = 0;
623 0 : sel->r.width = sink_ffmt->width;
624 0 : sel->r.height = sink_ffmt->height;
625 0 : break;
626 0 : case V4L2_SEL_TGT_CROP:
627 0 : sel->r = *crop;
628 0 : break;
629 : default:
630 : ret = -EINVAL;
631 : }
632 :
633 : return ret;
634 : }
635 :
636 : static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
637 : #if KERNEL_VERSION(6, 10, 0) > LINUX_VERSION_CODE
638 : .init_cfg = ipu6_isys_subdev_init_cfg,
639 : #endif
640 : .get_fmt = v4l2_subdev_get_fmt,
641 : .set_fmt = ipu6_isys_subdev_set_fmt,
642 : .get_selection = ipu6_isys_csi2_get_sel,
643 : .set_selection = ipu6_isys_csi2_set_sel,
644 : .enum_mbus_code = ipu6_isys_subdev_enum_mbus_code,
645 : .set_routing = ipu6_isys_subdev_set_routing,
646 : .enable_streams = ipu6_isys_csi2_enable_streams,
647 : .disable_streams = ipu6_isys_csi2_disable_streams,
648 : };
649 :
650 : static const struct v4l2_subdev_ops csi2_sd_ops = {
651 : .core = &csi2_sd_core_ops,
652 : .pad = &csi2_sd_pad_ops,
653 : };
654 :
655 : static const struct media_entity_operations csi2_entity_ops = {
656 : .link_validate = v4l2_subdev_link_validate,
657 : .has_pad_interdep = v4l2_subdev_has_pad_interdep,
658 : };
659 :
660 0 : void ipu6_isys_csi2_cleanup(struct ipu6_isys_csi2 *csi2)
661 : {
662 0 : if (!csi2->isys)
663 : return;
664 :
665 0 : v4l2_device_unregister_subdev(&csi2->asd.sd);
666 0 : v4l2_subdev_cleanup(&csi2->asd.sd);
667 0 : ipu6_isys_subdev_cleanup(&csi2->asd);
668 0 : csi2->isys = NULL;
669 : }
670 :
671 6 : int ipu6_isys_csi2_init(struct ipu6_isys_csi2 *csi2,
672 : struct ipu6_isys *isys,
673 : void __iomem *base, unsigned int index)
674 : {
675 6 : struct device *dev = &isys->adev->auxdev.dev;
676 : int ret;
677 :
678 6 : csi2->isys = isys;
679 6 : csi2->base = base;
680 6 : csi2->port = index;
681 :
682 6 : csi2->asd.sd.entity.ops = &csi2_entity_ops;
683 6 : csi2->asd.isys = isys;
684 6 : ret = ipu6_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0,
685 : NR_OF_CSI2_SINK_PADS, NR_OF_CSI2_SRC_PADS);
686 6 : if (ret)
687 0 : goto fail;
688 :
689 6 : csi2->asd.source = IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0 + index;
690 6 : csi2->asd.supported_codes = csi2_supported_codes;
691 6 : snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name),
692 : IPU6_ISYS_ENTITY_PREFIX " CSI2 %u", index);
693 : v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd);
694 6 : ret = v4l2_subdev_init_finalize(&csi2->asd.sd);
695 6 : if (ret) {
696 0 : dev_err(dev, "failed to init v4l2 subdev\n");
697 0 : goto fail;
698 : }
699 :
700 6 : ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd);
701 6 : if (ret) {
702 0 : dev_err(dev, "failed to register v4l2 subdev\n");
703 0 : goto fail;
704 : }
705 :
706 : return 0;
707 :
708 0 : fail:
709 0 : ipu6_isys_csi2_cleanup(csi2);
710 :
711 0 : return ret;
712 : }
713 :
714 2 : void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream *stream)
715 : {
716 2 : struct video_device *vdev = stream->asd->sd.devnode;
717 2 : struct device *dev = &stream->isys->adev->auxdev.dev;
718 : struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
719 2 : struct v4l2_event ev = {
720 : .type = V4L2_EVENT_FRAME_SYNC,
721 : };
722 :
723 2 : ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence);
724 2 : v4l2_event_queue(vdev, &ev);
725 :
726 2 : dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n",
727 : csi2->port, ev.u.frame_sync.frame_sequence, stream->vc);
728 :
729 : // Ambu-specific logging to see if we receive the first few frames from the FPGA
730 2 : if (ev.u.frame_sync.frame_sequence <= csi2_log_first_sof)
731 2 : dev_info(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n",
732 : csi2->port,
733 : ev.u.frame_sync.frame_sequence,
734 : stream->vc);
735 2 : }
736 :
737 0 : void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream)
738 : {
739 0 : struct device *dev = &stream->isys->adev->auxdev.dev;
740 0 : struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
741 0 : u32 frame_sequence = atomic_read(&stream->sequence);
742 :
743 0 : dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n",
744 : csi2->port, frame_sequence);
745 0 : }
746 :
747 1 : int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
748 : struct ipu6_isys_csi2 *csi2,
749 : struct media_entity *source_entity,
750 : struct v4l2_mbus_frame_desc_entry *entry)
751 : {
752 : struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
753 1 : struct device *dev = &csi2->isys->adev->auxdev.dev;
754 1 : struct v4l2_mbus_frame_desc desc;
755 : struct v4l2_subdev *source;
756 : struct media_pad *pad;
757 : unsigned int i;
758 : int ret;
759 :
760 1 : source = media_entity_to_v4l2_subdev(source_entity);
761 : if (!source)
762 : return -EPIPE;
763 :
764 1 : pad = media_pad_remote_pad_first(&csi2->asd.pad[CSI2_PAD_SINK]);
765 1 : if (!pad)
766 : return -EPIPE;
767 :
768 1 : ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc);
769 0 : if (ret)
770 1 : return ret;
771 :
772 0 : if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
773 0 : dev_err(dev, "Unsupported frame descriptor type\n");
774 0 : return -EINVAL;
775 : }
776 :
777 0 : for (i = 0; i < desc.num_entries; i++) {
778 0 : if (source_stream == desc.entry[i].stream) {
779 0 : desc_entry = &desc.entry[i];
780 : break;
781 : }
782 : }
783 :
784 : if (!desc_entry) {
785 0 : dev_err(dev, "Failed to find stream %u from remote subdev\n",
786 : source_stream);
787 0 : return -EINVAL;
788 : }
789 :
790 0 : if (desc_entry->bus.csi2.vc >= NR_OF_CSI2_VC) {
791 0 : dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc);
792 0 : return -EINVAL;
793 : }
794 :
795 0 : *entry = *desc_entry;
796 :
797 0 : return 0;
798 : }
|