1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 Intel Corporation. All rights reserved.
4 * Intel Visual Sensing Controller CSI Linux driver
5 */
6
7 /*
8 * To set ownership of CSI-2 link and to configure CSI-2 link, there
9 * are specific commands, which are sent via MEI protocol. The send
10 * command function uses "completion" as a synchronization mechanism.
11 * The response for command is received via a mei callback which wakes
12 * up the caller. There can be only one outstanding command at a time.
13 */
14
15 #include <linux/completion.h>
16 #include <linux/delay.h>
17 #include <linux/kernel.h>
18 #include <linux/math64.h>
19 #include <linux/mei_cl_bus.h>
20 #include <linux/module.h>
21 #include <linux/mutex.h>
22 #include <linux/pci.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/slab.h>
25 #include <linux/units.h>
26 #include <linux/uuid.h>
27 #include <linux/workqueue.h>
28
29 #include <media/ipu-bridge.h>
30 #include <media/ipu6-pci-table.h>
31 #include <media/v4l2-async.h>
32 #include <media/v4l2-ctrls.h>
33 #include <media/v4l2-fwnode.h>
34 #include <media/v4l2-subdev.h>
35
36 #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI"
37
38 /* the 5s used here is based on experiment */
39 #define CSI_CMD_TIMEOUT (5 * HZ)
40 /* to setup CSI-2 link an extra delay needed and determined experimentally */
41 #define CSI_FW_READY_DELAY_MS 100
42 /* link frequency unit is 100kHz */
43 #define CSI_LINK_FREQ(x) ((u32)(div_u64(x, 100 * HZ_PER_KHZ)))
44
45 /*
46 * identify the command id supported by firmware
47 * IPC, as well as the privacy notification id
48 * used when processing privacy event.
49 */
50 enum csi_cmd_id {
51 /* used to set csi ownership */
52 CSI_SET_OWNER = 0,
53
54 /* used to configure CSI-2 link */
55 CSI_SET_CONF = 2,
56
57 /* privacy notification id used when privacy state changes */
58 CSI_PRIVACY_NOTIF = 6,
59 };
60
61 /* CSI-2 link ownership definition */
62 enum csi_link_owner {
63 CSI_LINK_IVSC,
64 CSI_LINK_HOST,
65 };
66
67 /* privacy status definition */
68 enum ivsc_privacy_status {
69 CSI_PRIVACY_OFF,
70 CSI_PRIVACY_ON,
71 CSI_PRIVACY_MAX,
72 };
73
74 enum csi_pads {
75 CSI_PAD_SINK,
76 CSI_PAD_SOURCE,
77 CSI_NUM_PADS
78 };
79
80 /* configuration of the CSI-2 link between host and IVSC */
81 struct csi_link_cfg {
82 /* number of data lanes used on the CSI-2 link */
83 u32 nr_of_lanes;
84
85 /* frequency of the CSI-2 link */
86 u32 link_freq;
87
88 /* for future use */
89 u32 rsvd[2];
90 } __packed;
91
92 /* CSI command structure */
93 struct csi_cmd {
94 u32 cmd_id;
95 union _cmd_param {
96 u32 param;
97 struct csi_link_cfg conf;
98 } param;
99 } __packed;
100
101 /* CSI notification structure */
102 struct csi_notif {
103 u32 cmd_id;
104 int status;
105 union _resp_cont {
106 u32 cont;
107 struct csi_link_cfg conf;
108 } cont;
109 } __packed;
110
111 struct mei_csi {
112 struct mei_cl_device *cldev;
113
114 /* command response */
115 struct csi_notif cmd_response;
116 /* used to wait for command response from firmware */
117 struct completion cmd_completion;
118 /* protect command download */
119 struct mutex lock;
120
121 struct v4l2_subdev subdev;
122 struct media_pad *remote;
123 struct v4l2_async_notifier notifier;
124 struct v4l2_ctrl_handler ctrl_handler;
125 struct v4l2_ctrl *freq_ctrl;
126 struct v4l2_ctrl *privacy_ctrl;
127 /* lock for v4l2 controls */
128 struct mutex ctrl_lock;
129 /* start streaming or not */
130 int streaming;
131
132 struct media_pad pads[CSI_NUM_PADS];
133
134 /* number of data lanes used on the CSI-2 link */
135 u32 nr_of_lanes;
136 /* frequency of the CSI-2 link */
137 u64 link_freq;
138 };
139
140 static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = {
141 .width = 1,
142 .height = 1,
143 .code = MEDIA_BUS_FMT_Y8_1X8,
144 .field = V4L2_FIELD_NONE,
145 };
146
notifier_to_csi(struct v4l2_async_notifier * n)147 static inline struct mei_csi *notifier_to_csi(struct v4l2_async_notifier *n)
148 {
149 return container_of(n, struct mei_csi, notifier);
150 }
151
sd_to_csi(struct v4l2_subdev * sd)152 static inline struct mei_csi *sd_to_csi(struct v4l2_subdev *sd)
153 {
154 return container_of(sd, struct mei_csi, subdev);
155 }
156
157 /* send a command to firmware and mutex must be held by caller */
mei_csi_send(struct mei_csi * csi,u8 * buf,size_t len)158 static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len)
159 {
160 struct csi_cmd *cmd = (struct csi_cmd *)buf;
161 int ret;
162
163 reinit_completion(&csi->cmd_completion);
164
165 ret = mei_cldev_send(csi->cldev, buf, len);
166 if (ret < 0)
167 goto out;
168
169 ret = wait_for_completion_killable_timeout(&csi->cmd_completion,
170 CSI_CMD_TIMEOUT);
171 if (ret < 0) {
172 goto out;
173 } else if (!ret) {
174 ret = -ETIMEDOUT;
175 goto out;
176 }
177
178 /* command response status */
179 ret = csi->cmd_response.status;
180 if (ret == -1) {
181 /* notify privacy on instead of reporting error */
182 ret = 0;
183 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
184 } else if (ret) {
185 ret = -EINVAL;
186 goto out;
187 }
188
189 if (csi->cmd_response.cmd_id != cmd->cmd_id)
190 ret = -EINVAL;
191
192 out:
193 return ret;
194 }
195
196 /* set CSI-2 link ownership */
csi_set_link_owner(struct mei_csi * csi,enum csi_link_owner owner)197 static int csi_set_link_owner(struct mei_csi *csi, enum csi_link_owner owner)
198 {
199 struct csi_cmd cmd = { 0 };
200 size_t cmd_size;
201 int ret;
202
203 cmd.cmd_id = CSI_SET_OWNER;
204 cmd.param.param = owner;
205 cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.param);
206
207 mutex_lock(&csi->lock);
208
209 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
210
211 mutex_unlock(&csi->lock);
212
213 return ret;
214 }
215
216 /* configure CSI-2 link between host and IVSC */
csi_set_link_cfg(struct mei_csi * csi)217 static int csi_set_link_cfg(struct mei_csi *csi)
218 {
219 struct csi_cmd cmd = { 0 };
220 size_t cmd_size;
221 int ret;
222
223 cmd.cmd_id = CSI_SET_CONF;
224 cmd.param.conf.nr_of_lanes = csi->nr_of_lanes;
225 cmd.param.conf.link_freq = CSI_LINK_FREQ(csi->link_freq);
226 cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf);
227
228 mutex_lock(&csi->lock);
229
230 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
231 /*
232 * wait configuration ready if download success. placing
233 * delay under mutex is to make sure current command flow
234 * completed before starting a possible new one.
235 */
236 if (!ret)
237 msleep(CSI_FW_READY_DELAY_MS);
238
239 mutex_unlock(&csi->lock);
240
241 return ret;
242 }
243
244 /* callback for receive */
mei_csi_rx(struct mei_cl_device * cldev)245 static void mei_csi_rx(struct mei_cl_device *cldev)
246 {
247 struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
248 struct csi_notif notif = { 0 };
249 int ret;
250
251 ret = mei_cldev_recv(cldev, (u8 *)¬if, sizeof(notif));
252 if (ret < 0) {
253 dev_err(&cldev->dev, "recv error: %d\n", ret);
254 return;
255 }
256
257 switch (notif.cmd_id) {
258 case CSI_PRIVACY_NOTIF:
259 if (notif.cont.cont < CSI_PRIVACY_MAX)
260 v4l2_ctrl_s_ctrl(csi->privacy_ctrl,
261 notif.cont.cont == CSI_PRIVACY_ON);
262 break;
263 case CSI_SET_OWNER:
264 case CSI_SET_CONF:
265 memcpy(&csi->cmd_response, ¬if, ret);
266
267 complete(&csi->cmd_completion);
268 break;
269 default:
270 break;
271 }
272 }
273
mei_csi_set_stream(struct v4l2_subdev * sd,int enable)274 static int mei_csi_set_stream(struct v4l2_subdev *sd, int enable)
275 {
276 struct mei_csi *csi = sd_to_csi(sd);
277 struct v4l2_subdev *remote_sd =
278 media_entity_to_v4l2_subdev(csi->remote->entity);
279 s64 freq;
280 int ret;
281
282 if (enable && csi->streaming == 0) {
283 freq = v4l2_get_link_freq(csi->remote, 0, 0);
284 if (freq < 0) {
285 dev_err(&csi->cldev->dev,
286 "error %lld, invalid link_freq\n", freq);
287 ret = freq;
288 goto err;
289 }
290 csi->link_freq = freq;
291
292 /* switch CSI-2 link to host */
293 ret = csi_set_link_owner(csi, CSI_LINK_HOST);
294 if (ret < 0)
295 goto err;
296
297 /* configure CSI-2 link */
298 ret = csi_set_link_cfg(csi);
299 if (ret < 0)
300 goto err_switch;
301
302 ret = v4l2_subdev_call(remote_sd, video, s_stream, 1);
303 if (ret)
304 goto err_switch;
305 } else if (!enable && csi->streaming == 1) {
306 v4l2_subdev_call(remote_sd, video, s_stream, 0);
307
308 /* switch CSI-2 link to IVSC */
309 ret = csi_set_link_owner(csi, CSI_LINK_IVSC);
310 if (ret < 0)
311 dev_warn(&csi->cldev->dev,
312 "failed to switch CSI2 link: %d\n", ret);
313 }
314
315 csi->streaming = enable;
316
317 return 0;
318
319 err_switch:
320 csi_set_link_owner(csi, CSI_LINK_IVSC);
321
322 err:
323 return ret;
324 }
325
mei_csi_init_state(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)326 static int mei_csi_init_state(struct v4l2_subdev *sd,
327 struct v4l2_subdev_state *sd_state)
328 {
329 struct v4l2_mbus_framefmt *mbusformat;
330 unsigned int i;
331
332 for (i = 0; i < sd->entity.num_pads; i++) {
333 mbusformat = v4l2_subdev_state_get_format(sd_state, i);
334 *mbusformat = mei_csi_format_mbus_default;
335 }
336
337 return 0;
338 }
339
mei_csi_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)340 static int mei_csi_set_fmt(struct v4l2_subdev *sd,
341 struct v4l2_subdev_state *sd_state,
342 struct v4l2_subdev_format *format)
343 {
344 struct v4l2_mbus_framefmt *source_fmt;
345 struct v4l2_mbus_framefmt *sink_fmt;
346
347 sink_fmt = v4l2_subdev_state_get_format(sd_state, CSI_PAD_SINK);
348 source_fmt = v4l2_subdev_state_get_format(sd_state, CSI_PAD_SOURCE);
349
350 if (format->pad) {
351 *source_fmt = *sink_fmt;
352
353 return 0;
354 }
355
356 v4l_bound_align_image(&format->format.width, 1, 65536, 0,
357 &format->format.height, 1, 65536, 0, 0);
358
359 switch (format->format.code) {
360 case MEDIA_BUS_FMT_RGB444_1X12:
361 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
362 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
363 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
364 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
365 case MEDIA_BUS_FMT_RGB565_1X16:
366 case MEDIA_BUS_FMT_BGR565_2X8_BE:
367 case MEDIA_BUS_FMT_BGR565_2X8_LE:
368 case MEDIA_BUS_FMT_RGB565_2X8_BE:
369 case MEDIA_BUS_FMT_RGB565_2X8_LE:
370 case MEDIA_BUS_FMT_RGB666_1X18:
371 case MEDIA_BUS_FMT_RBG888_1X24:
372 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
373 case MEDIA_BUS_FMT_BGR888_1X24:
374 case MEDIA_BUS_FMT_GBR888_1X24:
375 case MEDIA_BUS_FMT_RGB888_1X24:
376 case MEDIA_BUS_FMT_RGB888_2X12_BE:
377 case MEDIA_BUS_FMT_RGB888_2X12_LE:
378 case MEDIA_BUS_FMT_ARGB8888_1X32:
379 case MEDIA_BUS_FMT_RGB888_1X32_PADHI:
380 case MEDIA_BUS_FMT_RGB101010_1X30:
381 case MEDIA_BUS_FMT_RGB121212_1X36:
382 case MEDIA_BUS_FMT_RGB161616_1X48:
383 case MEDIA_BUS_FMT_Y8_1X8:
384 case MEDIA_BUS_FMT_UV8_1X8:
385 case MEDIA_BUS_FMT_UYVY8_1_5X8:
386 case MEDIA_BUS_FMT_VYUY8_1_5X8:
387 case MEDIA_BUS_FMT_YUYV8_1_5X8:
388 case MEDIA_BUS_FMT_YVYU8_1_5X8:
389 case MEDIA_BUS_FMT_UYVY8_2X8:
390 case MEDIA_BUS_FMT_VYUY8_2X8:
391 case MEDIA_BUS_FMT_YUYV8_2X8:
392 case MEDIA_BUS_FMT_YVYU8_2X8:
393 case MEDIA_BUS_FMT_Y10_1X10:
394 case MEDIA_BUS_FMT_UYVY10_2X10:
395 case MEDIA_BUS_FMT_VYUY10_2X10:
396 case MEDIA_BUS_FMT_YUYV10_2X10:
397 case MEDIA_BUS_FMT_YVYU10_2X10:
398 case MEDIA_BUS_FMT_Y12_1X12:
399 case MEDIA_BUS_FMT_UYVY12_2X12:
400 case MEDIA_BUS_FMT_VYUY12_2X12:
401 case MEDIA_BUS_FMT_YUYV12_2X12:
402 case MEDIA_BUS_FMT_YVYU12_2X12:
403 case MEDIA_BUS_FMT_UYVY8_1X16:
404 case MEDIA_BUS_FMT_VYUY8_1X16:
405 case MEDIA_BUS_FMT_YUYV8_1X16:
406 case MEDIA_BUS_FMT_YVYU8_1X16:
407 case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
408 case MEDIA_BUS_FMT_UYVY10_1X20:
409 case MEDIA_BUS_FMT_VYUY10_1X20:
410 case MEDIA_BUS_FMT_YUYV10_1X20:
411 case MEDIA_BUS_FMT_YVYU10_1X20:
412 case MEDIA_BUS_FMT_VUY8_1X24:
413 case MEDIA_BUS_FMT_YUV8_1X24:
414 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
415 case MEDIA_BUS_FMT_UYVY12_1X24:
416 case MEDIA_BUS_FMT_VYUY12_1X24:
417 case MEDIA_BUS_FMT_YUYV12_1X24:
418 case MEDIA_BUS_FMT_YVYU12_1X24:
419 case MEDIA_BUS_FMT_YUV10_1X30:
420 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
421 case MEDIA_BUS_FMT_AYUV8_1X32:
422 case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
423 case MEDIA_BUS_FMT_YUV12_1X36:
424 case MEDIA_BUS_FMT_YUV16_1X48:
425 case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
426 case MEDIA_BUS_FMT_JPEG_1X8:
427 case MEDIA_BUS_FMT_AHSV8888_1X32:
428 case MEDIA_BUS_FMT_SBGGR8_1X8:
429 case MEDIA_BUS_FMT_SGBRG8_1X8:
430 case MEDIA_BUS_FMT_SGRBG8_1X8:
431 case MEDIA_BUS_FMT_SRGGB8_1X8:
432 case MEDIA_BUS_FMT_SBGGR10_1X10:
433 case MEDIA_BUS_FMT_SGBRG10_1X10:
434 case MEDIA_BUS_FMT_SGRBG10_1X10:
435 case MEDIA_BUS_FMT_SRGGB10_1X10:
436 case MEDIA_BUS_FMT_SBGGR12_1X12:
437 case MEDIA_BUS_FMT_SGBRG12_1X12:
438 case MEDIA_BUS_FMT_SGRBG12_1X12:
439 case MEDIA_BUS_FMT_SRGGB12_1X12:
440 case MEDIA_BUS_FMT_SBGGR14_1X14:
441 case MEDIA_BUS_FMT_SGBRG14_1X14:
442 case MEDIA_BUS_FMT_SGRBG14_1X14:
443 case MEDIA_BUS_FMT_SRGGB14_1X14:
444 case MEDIA_BUS_FMT_SBGGR16_1X16:
445 case MEDIA_BUS_FMT_SGBRG16_1X16:
446 case MEDIA_BUS_FMT_SGRBG16_1X16:
447 case MEDIA_BUS_FMT_SRGGB16_1X16:
448 break;
449 default:
450 format->format.code = MEDIA_BUS_FMT_Y8_1X8;
451 break;
452 }
453
454 if (format->format.field == V4L2_FIELD_ANY)
455 format->format.field = V4L2_FIELD_NONE;
456
457 *sink_fmt = format->format;
458 *source_fmt = *sink_fmt;
459
460 return 0;
461 }
462
mei_csi_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * mbus_config)463 static int mei_csi_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
464 struct v4l2_mbus_config *mbus_config)
465 {
466 struct mei_csi *csi = sd_to_csi(sd);
467 unsigned int i;
468 s64 freq;
469
470 mbus_config->type = V4L2_MBUS_CSI2_DPHY;
471 for (i = 0; i < V4L2_MBUS_CSI2_MAX_DATA_LANES; i++)
472 mbus_config->bus.mipi_csi2.data_lanes[i] = i + 1;
473 mbus_config->bus.mipi_csi2.num_data_lanes = csi->nr_of_lanes;
474
475 freq = v4l2_get_link_freq(csi->remote, 0, 0);
476 if (freq < 0) {
477 dev_err(&csi->cldev->dev,
478 "error %lld, invalid link_freq\n", freq);
479 return -EINVAL;
480 }
481
482 csi->link_freq = freq;
483 mbus_config->link_freq = freq;
484
485 return 0;
486 }
487
488 static const struct v4l2_subdev_video_ops mei_csi_video_ops = {
489 .s_stream = mei_csi_set_stream,
490 };
491
492 static const struct v4l2_subdev_pad_ops mei_csi_pad_ops = {
493 .get_fmt = v4l2_subdev_get_fmt,
494 .set_fmt = mei_csi_set_fmt,
495 .get_mbus_config = mei_csi_get_mbus_config,
496 };
497
498 static const struct v4l2_subdev_ops mei_csi_subdev_ops = {
499 .video = &mei_csi_video_ops,
500 .pad = &mei_csi_pad_ops,
501 };
502
503 static const struct v4l2_subdev_internal_ops mei_csi_internal_ops = {
504 .init_state = mei_csi_init_state,
505 };
506
507 static const struct media_entity_operations mei_csi_entity_ops = {
508 .link_validate = v4l2_subdev_link_validate,
509 };
510
mei_csi_notify_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)511 static int mei_csi_notify_bound(struct v4l2_async_notifier *notifier,
512 struct v4l2_subdev *subdev,
513 struct v4l2_async_connection *asd)
514 {
515 struct mei_csi *csi = notifier_to_csi(notifier);
516 int pad;
517
518 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
519 MEDIA_PAD_FL_SOURCE);
520 if (pad < 0)
521 return pad;
522
523 csi->remote = &subdev->entity.pads[pad];
524
525 return media_create_pad_link(&subdev->entity, pad,
526 &csi->subdev.entity, CSI_PAD_SINK,
527 MEDIA_LNK_FL_ENABLED |
528 MEDIA_LNK_FL_IMMUTABLE);
529 }
530
mei_csi_notify_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)531 static void mei_csi_notify_unbind(struct v4l2_async_notifier *notifier,
532 struct v4l2_subdev *subdev,
533 struct v4l2_async_connection *asd)
534 {
535 struct mei_csi *csi = notifier_to_csi(notifier);
536
537 csi->remote = NULL;
538 }
539
540 static const struct v4l2_async_notifier_operations mei_csi_notify_ops = {
541 .bound = mei_csi_notify_bound,
542 .unbind = mei_csi_notify_unbind,
543 };
544
mei_csi_init_controls(struct mei_csi * csi)545 static int mei_csi_init_controls(struct mei_csi *csi)
546 {
547 int ret;
548
549 mutex_init(&csi->ctrl_lock);
550
551 ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 1);
552 if (ret)
553 return ret;
554
555 csi->ctrl_handler.lock = &csi->ctrl_lock;
556
557 csi->privacy_ctrl = v4l2_ctrl_new_std(&csi->ctrl_handler, NULL,
558 V4L2_CID_PRIVACY, 0, 1, 1, 0);
559 if (csi->privacy_ctrl)
560 csi->privacy_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
561
562 if (csi->ctrl_handler.error)
563 return csi->ctrl_handler.error;
564
565 csi->subdev.ctrl_handler = &csi->ctrl_handler;
566
567 return 0;
568 }
569
mei_csi_parse_firmware(struct mei_csi * csi)570 static int mei_csi_parse_firmware(struct mei_csi *csi)
571 {
572 struct v4l2_fwnode_endpoint v4l2_ep = {
573 .bus_type = V4L2_MBUS_CSI2_DPHY,
574 };
575 struct device *dev = &csi->cldev->dev;
576 struct v4l2_async_connection *asd;
577 struct fwnode_handle *sink_ep, *source_ep;
578 int ret;
579
580 sink_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
581 if (!sink_ep) {
582 dev_err(dev, "can't obtain sink endpoint\n");
583 return -EINVAL;
584 }
585
586 v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev);
587 csi->notifier.ops = &mei_csi_notify_ops;
588
589 ret = v4l2_fwnode_endpoint_parse(sink_ep, &v4l2_ep);
590 if (ret) {
591 dev_err(dev, "could not parse v4l2 sink endpoint\n");
592 goto out_nf_cleanup;
593 }
594
595 csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
596
597 source_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 1, 0, 0);
598 if (!source_ep) {
599 ret = -ENOTCONN;
600 dev_err(dev, "can't obtain source endpoint\n");
601 goto out_nf_cleanup;
602 }
603
604 ret = v4l2_fwnode_endpoint_parse(source_ep, &v4l2_ep);
605 fwnode_handle_put(source_ep);
606 if (ret) {
607 dev_err(dev, "could not parse v4l2 source endpoint\n");
608 goto out_nf_cleanup;
609 }
610
611 if (csi->nr_of_lanes != v4l2_ep.bus.mipi_csi2.num_data_lanes) {
612 ret = -EINVAL;
613 dev_err(dev,
614 "the number of lanes does not match (%u vs. %u)\n",
615 csi->nr_of_lanes, v4l2_ep.bus.mipi_csi2.num_data_lanes);
616 goto out_nf_cleanup;
617 }
618
619 asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, sink_ep,
620 struct v4l2_async_connection);
621 if (IS_ERR(asd)) {
622 ret = PTR_ERR(asd);
623 goto out_nf_cleanup;
624 }
625
626 ret = v4l2_async_nf_register(&csi->notifier);
627 if (ret)
628 goto out_nf_cleanup;
629
630 fwnode_handle_put(sink_ep);
631
632 return 0;
633
634 out_nf_cleanup:
635 v4l2_async_nf_cleanup(&csi->notifier);
636 fwnode_handle_put(sink_ep);
637
638 return ret;
639 }
640
mei_csi_probe(struct mei_cl_device * cldev,const struct mei_cl_device_id * id)641 static int mei_csi_probe(struct mei_cl_device *cldev,
642 const struct mei_cl_device_id *id)
643 {
644 struct device *dev = &cldev->dev;
645 struct pci_dev *ipu;
646 struct mei_csi *csi;
647 unsigned int i;
648 int ret;
649
650 for (i = 0, ipu = NULL; !ipu && ipu6_pci_tbl[i].vendor; i++)
651 ipu = pci_get_device(ipu6_pci_tbl[i].vendor,
652 ipu6_pci_tbl[i].device, NULL);
653
654 if (!ipu)
655 return -ENODEV;
656
657 ret = ipu_bridge_init(&ipu->dev, ipu_bridge_parse_ssdb);
658 put_device(&ipu->dev);
659 if (ret < 0)
660 return ret;
661 if (!dev_fwnode(dev)) {
662 dev_err(dev, "mei-csi probed without device fwnode!\n");
663 return -ENXIO;
664 }
665
666 csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL);
667 if (!csi)
668 return -ENOMEM;
669
670 csi->cldev = cldev;
671 mutex_init(&csi->lock);
672 init_completion(&csi->cmd_completion);
673
674 mei_cldev_set_drvdata(cldev, csi);
675
676 ret = mei_cldev_enable(cldev);
677 if (ret < 0) {
678 dev_err(dev, "mei_cldev_enable failed: %d\n", ret);
679 goto destroy_mutex;
680 }
681
682 ret = mei_cldev_register_rx_cb(cldev, mei_csi_rx);
683 if (ret) {
684 dev_err(dev, "event cb registration failed: %d\n", ret);
685 goto err_disable;
686 }
687
688 ret = mei_csi_parse_firmware(csi);
689 if (ret)
690 goto err_disable;
691
692 csi->subdev.dev = &cldev->dev;
693 csi->subdev.state_lock = &csi->lock;
694 v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops);
695 csi->subdev.internal_ops = &mei_csi_internal_ops;
696 v4l2_set_subdevdata(&csi->subdev, csi);
697 csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
698 V4L2_SUBDEV_FL_HAS_EVENTS;
699 csi->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
700 csi->subdev.entity.ops = &mei_csi_entity_ops;
701
702 snprintf(csi->subdev.name, sizeof(csi->subdev.name),
703 MEI_CSI_ENTITY_NAME);
704
705 ret = mei_csi_init_controls(csi);
706 if (ret)
707 goto err_ctrl_handler;
708
709 csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
710 csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
711 ret = media_entity_pads_init(&csi->subdev.entity, CSI_NUM_PADS,
712 csi->pads);
713 if (ret)
714 goto err_ctrl_handler;
715
716 ret = v4l2_subdev_init_finalize(&csi->subdev);
717 if (ret < 0)
718 goto err_entity;
719
720 ret = v4l2_async_register_subdev(&csi->subdev);
721 if (ret < 0)
722 goto err_subdev;
723
724 pm_runtime_enable(&cldev->dev);
725
726 return 0;
727
728 err_subdev:
729 v4l2_subdev_cleanup(&csi->subdev);
730
731 err_entity:
732 media_entity_cleanup(&csi->subdev.entity);
733
734 err_ctrl_handler:
735 v4l2_ctrl_handler_free(&csi->ctrl_handler);
736 mutex_destroy(&csi->ctrl_lock);
737 v4l2_async_nf_unregister(&csi->notifier);
738 v4l2_async_nf_cleanup(&csi->notifier);
739
740 err_disable:
741 mei_cldev_disable(cldev);
742
743 destroy_mutex:
744 mutex_destroy(&csi->lock);
745
746 return ret;
747 }
748
mei_csi_remove(struct mei_cl_device * cldev)749 static void mei_csi_remove(struct mei_cl_device *cldev)
750 {
751 struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
752
753 v4l2_async_nf_unregister(&csi->notifier);
754 v4l2_async_nf_cleanup(&csi->notifier);
755 v4l2_ctrl_handler_free(&csi->ctrl_handler);
756 mutex_destroy(&csi->ctrl_lock);
757 v4l2_async_unregister_subdev(&csi->subdev);
758 v4l2_subdev_cleanup(&csi->subdev);
759 media_entity_cleanup(&csi->subdev.entity);
760
761 pm_runtime_disable(&cldev->dev);
762
763 mutex_destroy(&csi->lock);
764 }
765
766 #define MEI_CSI_UUID UUID_LE(0x92335FCF, 0x3203, 0x4472, \
767 0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA)
768
769 static const struct mei_cl_device_id mei_csi_tbl[] = {
770 { .uuid = MEI_CSI_UUID, .version = MEI_CL_VERSION_ANY },
771 { /* sentinel */ }
772 };
773 MODULE_DEVICE_TABLE(mei, mei_csi_tbl);
774
775 static struct mei_cl_driver mei_csi_driver = {
776 .id_table = mei_csi_tbl,
777 .name = KBUILD_MODNAME,
778
779 .probe = mei_csi_probe,
780 .remove = mei_csi_remove,
781 };
782
783 module_mei_cl_driver(mei_csi_driver);
784
785 MODULE_IMPORT_NS("INTEL_IPU_BRIDGE");
786 MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
787 MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
788 MODULE_DESCRIPTION("Device driver for IVSC CSI");
789 MODULE_LICENSE("GPL");
790