xref: /openbmc/linux/drivers/media/pci/intel/ivsc/mei_csi.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
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/pm_runtime.h>
23  #include <linux/slab.h>
24  #include <linux/units.h>
25  #include <linux/uuid.h>
26  #include <linux/workqueue.h>
27  
28  #include <media/v4l2-async.h>
29  #include <media/v4l2-ctrls.h>
30  #include <media/v4l2-fwnode.h>
31  #include <media/v4l2-subdev.h>
32  
33  #define MEI_CSI_DRIVER_NAME "ivsc_csi"
34  #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI"
35  
36  #define MEI_CSI_LINK_FREQ_400MHZ 400000000ULL
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 v4l2_subdev *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  	unsigned int remote_pad;
130  	/* start streaming or not */
131  	int streaming;
132  
133  	struct media_pad pads[CSI_NUM_PADS];
134  	struct v4l2_mbus_framefmt format_mbus[CSI_NUM_PADS];
135  
136  	/* number of data lanes used on the CSI-2 link */
137  	u32 nr_of_lanes;
138  	/* frequency of the CSI-2 link */
139  	u64 link_freq;
140  
141  	/* privacy status */
142  	enum ivsc_privacy_status status;
143  };
144  
145  static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = {
146  	.width = 1,
147  	.height = 1,
148  	.code = MEDIA_BUS_FMT_Y8_1X8,
149  	.field = V4L2_FIELD_NONE,
150  };
151  
152  static s64 link_freq_menu_items[] = {
153  	MEI_CSI_LINK_FREQ_400MHZ
154  };
155  
notifier_to_csi(struct v4l2_async_notifier * n)156  static inline struct mei_csi *notifier_to_csi(struct v4l2_async_notifier *n)
157  {
158  	return container_of(n, struct mei_csi, notifier);
159  }
160  
sd_to_csi(struct v4l2_subdev * sd)161  static inline struct mei_csi *sd_to_csi(struct v4l2_subdev *sd)
162  {
163  	return container_of(sd, struct mei_csi, subdev);
164  }
165  
ctrl_to_csi(struct v4l2_ctrl * ctrl)166  static inline struct mei_csi *ctrl_to_csi(struct v4l2_ctrl *ctrl)
167  {
168  	return container_of(ctrl->handler, struct mei_csi, ctrl_handler);
169  }
170  
171  /* send a command to firmware and mutex must be held by caller */
mei_csi_send(struct mei_csi * csi,u8 * buf,size_t len)172  static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len)
173  {
174  	struct csi_cmd *cmd = (struct csi_cmd *)buf;
175  	int ret;
176  
177  	reinit_completion(&csi->cmd_completion);
178  
179  	ret = mei_cldev_send(csi->cldev, buf, len);
180  	if (ret < 0)
181  		goto out;
182  
183  	ret = wait_for_completion_killable_timeout(&csi->cmd_completion,
184  						   CSI_CMD_TIMEOUT);
185  	if (ret < 0) {
186  		goto out;
187  	} else if (!ret) {
188  		ret = -ETIMEDOUT;
189  		goto out;
190  	}
191  
192  	/* command response status */
193  	ret = csi->cmd_response.status;
194  	if (ret == -1) {
195  		/* notify privacy on instead of reporting error */
196  		ret = 0;
197  		v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
198  	} else if (ret) {
199  		ret = -EINVAL;
200  		goto out;
201  	}
202  
203  	if (csi->cmd_response.cmd_id != cmd->cmd_id)
204  		ret = -EINVAL;
205  
206  out:
207  	return ret;
208  }
209  
210  /* set CSI-2 link ownership */
csi_set_link_owner(struct mei_csi * csi,enum csi_link_owner owner)211  static int csi_set_link_owner(struct mei_csi *csi, enum csi_link_owner owner)
212  {
213  	struct csi_cmd cmd = { 0 };
214  	size_t cmd_size;
215  	int ret;
216  
217  	cmd.cmd_id = CSI_SET_OWNER;
218  	cmd.param.param = owner;
219  	cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.param);
220  
221  	mutex_lock(&csi->lock);
222  
223  	ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
224  
225  	mutex_unlock(&csi->lock);
226  
227  	return ret;
228  }
229  
230  /* configure CSI-2 link between host and IVSC */
csi_set_link_cfg(struct mei_csi * csi)231  static int csi_set_link_cfg(struct mei_csi *csi)
232  {
233  	struct csi_cmd cmd = { 0 };
234  	size_t cmd_size;
235  	int ret;
236  
237  	cmd.cmd_id = CSI_SET_CONF;
238  	cmd.param.conf.nr_of_lanes = csi->nr_of_lanes;
239  	cmd.param.conf.link_freq = CSI_LINK_FREQ(csi->link_freq);
240  	cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf);
241  
242  	mutex_lock(&csi->lock);
243  
244  	ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
245  	/*
246  	 * wait configuration ready if download success. placing
247  	 * delay under mutex is to make sure current command flow
248  	 * completed before starting a possible new one.
249  	 */
250  	if (!ret)
251  		msleep(CSI_FW_READY_DELAY_MS);
252  
253  	mutex_unlock(&csi->lock);
254  
255  	return ret;
256  }
257  
258  /* callback for receive */
mei_csi_rx(struct mei_cl_device * cldev)259  static void mei_csi_rx(struct mei_cl_device *cldev)
260  {
261  	struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
262  	struct csi_notif notif = { 0 };
263  	int ret;
264  
265  	ret = mei_cldev_recv(cldev, (u8 *)&notif, sizeof(notif));
266  	if (ret < 0) {
267  		dev_err(&cldev->dev, "recv error: %d\n", ret);
268  		return;
269  	}
270  
271  	switch (notif.cmd_id) {
272  	case CSI_PRIVACY_NOTIF:
273  		if (notif.cont.cont < CSI_PRIVACY_MAX) {
274  			csi->status = notif.cont.cont;
275  			v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status);
276  		}
277  		break;
278  	case CSI_SET_OWNER:
279  	case CSI_SET_CONF:
280  		memcpy(&csi->cmd_response, &notif, ret);
281  
282  		complete(&csi->cmd_completion);
283  		break;
284  	default:
285  		break;
286  	}
287  }
288  
mei_csi_set_stream(struct v4l2_subdev * sd,int enable)289  static int mei_csi_set_stream(struct v4l2_subdev *sd, int enable)
290  {
291  	struct mei_csi *csi = sd_to_csi(sd);
292  	s64 freq;
293  	int ret;
294  
295  	if (enable && csi->streaming == 0) {
296  		freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0);
297  		if (freq < 0) {
298  			dev_err(&csi->cldev->dev,
299  				"error %lld, invalid link_freq\n", freq);
300  			ret = freq;
301  			goto err;
302  		}
303  		csi->link_freq = freq;
304  
305  		/* switch CSI-2 link to host */
306  		ret = csi_set_link_owner(csi, CSI_LINK_HOST);
307  		if (ret < 0)
308  			goto err;
309  
310  		/* configure CSI-2 link */
311  		ret = csi_set_link_cfg(csi);
312  		if (ret < 0)
313  			goto err_switch;
314  
315  		ret = v4l2_subdev_call(csi->remote, video, s_stream, 1);
316  		if (ret)
317  			goto err_switch;
318  	} else if (!enable && csi->streaming == 1) {
319  		v4l2_subdev_call(csi->remote, video, s_stream, 0);
320  
321  		/* switch CSI-2 link to IVSC */
322  		ret = csi_set_link_owner(csi, CSI_LINK_IVSC);
323  		if (ret < 0)
324  			dev_warn(&csi->cldev->dev,
325  				 "failed to switch CSI2 link: %d\n", ret);
326  	}
327  
328  	csi->streaming = enable;
329  
330  	return 0;
331  
332  err_switch:
333  	csi_set_link_owner(csi, CSI_LINK_IVSC);
334  
335  err:
336  	return ret;
337  }
338  
339  static struct v4l2_mbus_framefmt *
mei_csi_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,unsigned int pad,u32 which)340  mei_csi_get_pad_format(struct v4l2_subdev *sd,
341  		       struct v4l2_subdev_state *sd_state,
342  		       unsigned int pad, u32 which)
343  {
344  	struct mei_csi *csi = sd_to_csi(sd);
345  
346  	switch (which) {
347  	case V4L2_SUBDEV_FORMAT_TRY:
348  		return v4l2_subdev_get_try_format(sd, sd_state, pad);
349  	case V4L2_SUBDEV_FORMAT_ACTIVE:
350  		return &csi->format_mbus[pad];
351  	default:
352  		return NULL;
353  	}
354  }
355  
mei_csi_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)356  static int mei_csi_init_cfg(struct v4l2_subdev *sd,
357  			    struct v4l2_subdev_state *sd_state)
358  {
359  	struct v4l2_mbus_framefmt *mbusformat;
360  	struct mei_csi *csi = sd_to_csi(sd);
361  	unsigned int i;
362  
363  	mutex_lock(&csi->lock);
364  
365  	for (i = 0; i < sd->entity.num_pads; i++) {
366  		mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i);
367  		*mbusformat = mei_csi_format_mbus_default;
368  	}
369  
370  	mutex_unlock(&csi->lock);
371  
372  	return 0;
373  }
374  
mei_csi_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)375  static int mei_csi_get_fmt(struct v4l2_subdev *sd,
376  			   struct v4l2_subdev_state *sd_state,
377  			   struct v4l2_subdev_format *format)
378  {
379  	struct v4l2_mbus_framefmt *mbusformat;
380  	struct mei_csi *csi = sd_to_csi(sd);
381  
382  	mutex_lock(&csi->lock);
383  
384  	mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad,
385  					    format->which);
386  	if (mbusformat)
387  		format->format = *mbusformat;
388  
389  	mutex_unlock(&csi->lock);
390  
391  	return 0;
392  }
393  
mei_csi_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)394  static int mei_csi_set_fmt(struct v4l2_subdev *sd,
395  			   struct v4l2_subdev_state *sd_state,
396  			   struct v4l2_subdev_format *format)
397  {
398  	struct v4l2_mbus_framefmt *source_mbusformat;
399  	struct v4l2_mbus_framefmt *mbusformat;
400  	struct mei_csi *csi = sd_to_csi(sd);
401  	struct media_pad *pad;
402  
403  	mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad,
404  					    format->which);
405  	if (!mbusformat)
406  		return -EINVAL;
407  
408  	source_mbusformat = mei_csi_get_pad_format(sd, sd_state, CSI_PAD_SOURCE,
409  						   format->which);
410  	if (!source_mbusformat)
411  		return -EINVAL;
412  
413  	v4l_bound_align_image(&format->format.width, 1, 65536, 0,
414  			      &format->format.height, 1, 65536, 0, 0);
415  
416  	switch (format->format.code) {
417  	case MEDIA_BUS_FMT_RGB444_1X12:
418  	case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
419  	case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
420  	case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
421  	case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
422  	case MEDIA_BUS_FMT_RGB565_1X16:
423  	case MEDIA_BUS_FMT_BGR565_2X8_BE:
424  	case MEDIA_BUS_FMT_BGR565_2X8_LE:
425  	case MEDIA_BUS_FMT_RGB565_2X8_BE:
426  	case MEDIA_BUS_FMT_RGB565_2X8_LE:
427  	case MEDIA_BUS_FMT_RGB666_1X18:
428  	case MEDIA_BUS_FMT_RBG888_1X24:
429  	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
430  	case MEDIA_BUS_FMT_BGR888_1X24:
431  	case MEDIA_BUS_FMT_GBR888_1X24:
432  	case MEDIA_BUS_FMT_RGB888_1X24:
433  	case MEDIA_BUS_FMT_RGB888_2X12_BE:
434  	case MEDIA_BUS_FMT_RGB888_2X12_LE:
435  	case MEDIA_BUS_FMT_ARGB8888_1X32:
436  	case MEDIA_BUS_FMT_RGB888_1X32_PADHI:
437  	case MEDIA_BUS_FMT_RGB101010_1X30:
438  	case MEDIA_BUS_FMT_RGB121212_1X36:
439  	case MEDIA_BUS_FMT_RGB161616_1X48:
440  	case MEDIA_BUS_FMT_Y8_1X8:
441  	case MEDIA_BUS_FMT_UV8_1X8:
442  	case MEDIA_BUS_FMT_UYVY8_1_5X8:
443  	case MEDIA_BUS_FMT_VYUY8_1_5X8:
444  	case MEDIA_BUS_FMT_YUYV8_1_5X8:
445  	case MEDIA_BUS_FMT_YVYU8_1_5X8:
446  	case MEDIA_BUS_FMT_UYVY8_2X8:
447  	case MEDIA_BUS_FMT_VYUY8_2X8:
448  	case MEDIA_BUS_FMT_YUYV8_2X8:
449  	case MEDIA_BUS_FMT_YVYU8_2X8:
450  	case MEDIA_BUS_FMT_Y10_1X10:
451  	case MEDIA_BUS_FMT_UYVY10_2X10:
452  	case MEDIA_BUS_FMT_VYUY10_2X10:
453  	case MEDIA_BUS_FMT_YUYV10_2X10:
454  	case MEDIA_BUS_FMT_YVYU10_2X10:
455  	case MEDIA_BUS_FMT_Y12_1X12:
456  	case MEDIA_BUS_FMT_UYVY12_2X12:
457  	case MEDIA_BUS_FMT_VYUY12_2X12:
458  	case MEDIA_BUS_FMT_YUYV12_2X12:
459  	case MEDIA_BUS_FMT_YVYU12_2X12:
460  	case MEDIA_BUS_FMT_UYVY8_1X16:
461  	case MEDIA_BUS_FMT_VYUY8_1X16:
462  	case MEDIA_BUS_FMT_YUYV8_1X16:
463  	case MEDIA_BUS_FMT_YVYU8_1X16:
464  	case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
465  	case MEDIA_BUS_FMT_UYVY10_1X20:
466  	case MEDIA_BUS_FMT_VYUY10_1X20:
467  	case MEDIA_BUS_FMT_YUYV10_1X20:
468  	case MEDIA_BUS_FMT_YVYU10_1X20:
469  	case MEDIA_BUS_FMT_VUY8_1X24:
470  	case MEDIA_BUS_FMT_YUV8_1X24:
471  	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
472  	case MEDIA_BUS_FMT_UYVY12_1X24:
473  	case MEDIA_BUS_FMT_VYUY12_1X24:
474  	case MEDIA_BUS_FMT_YUYV12_1X24:
475  	case MEDIA_BUS_FMT_YVYU12_1X24:
476  	case MEDIA_BUS_FMT_YUV10_1X30:
477  	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
478  	case MEDIA_BUS_FMT_AYUV8_1X32:
479  	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
480  	case MEDIA_BUS_FMT_YUV12_1X36:
481  	case MEDIA_BUS_FMT_YUV16_1X48:
482  	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
483  	case MEDIA_BUS_FMT_JPEG_1X8:
484  	case MEDIA_BUS_FMT_AHSV8888_1X32:
485  	case MEDIA_BUS_FMT_SBGGR8_1X8:
486  	case MEDIA_BUS_FMT_SGBRG8_1X8:
487  	case MEDIA_BUS_FMT_SGRBG8_1X8:
488  	case MEDIA_BUS_FMT_SRGGB8_1X8:
489  	case MEDIA_BUS_FMT_SBGGR10_1X10:
490  	case MEDIA_BUS_FMT_SGBRG10_1X10:
491  	case MEDIA_BUS_FMT_SGRBG10_1X10:
492  	case MEDIA_BUS_FMT_SRGGB10_1X10:
493  	case MEDIA_BUS_FMT_SBGGR12_1X12:
494  	case MEDIA_BUS_FMT_SGBRG12_1X12:
495  	case MEDIA_BUS_FMT_SGRBG12_1X12:
496  	case MEDIA_BUS_FMT_SRGGB12_1X12:
497  	case MEDIA_BUS_FMT_SBGGR14_1X14:
498  	case MEDIA_BUS_FMT_SGBRG14_1X14:
499  	case MEDIA_BUS_FMT_SGRBG14_1X14:
500  	case MEDIA_BUS_FMT_SRGGB14_1X14:
501  	case MEDIA_BUS_FMT_SBGGR16_1X16:
502  	case MEDIA_BUS_FMT_SGBRG16_1X16:
503  	case MEDIA_BUS_FMT_SGRBG16_1X16:
504  	case MEDIA_BUS_FMT_SRGGB16_1X16:
505  		break;
506  	default:
507  		format->format.code = MEDIA_BUS_FMT_Y8_1X8;
508  		break;
509  	}
510  
511  	if (format->format.field == V4L2_FIELD_ANY)
512  		format->format.field = V4L2_FIELD_NONE;
513  
514  	mutex_lock(&csi->lock);
515  
516  	pad = &csi->pads[format->pad];
517  	if (pad->flags & MEDIA_PAD_FL_SOURCE)
518  		format->format = csi->format_mbus[CSI_PAD_SINK];
519  
520  	*mbusformat = format->format;
521  
522  	if (pad->flags & MEDIA_PAD_FL_SINK)
523  		*source_mbusformat = format->format;
524  
525  	mutex_unlock(&csi->lock);
526  
527  	return 0;
528  }
529  
mei_csi_g_volatile_ctrl(struct v4l2_ctrl * ctrl)530  static int mei_csi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
531  {
532  	struct mei_csi *csi = ctrl_to_csi(ctrl);
533  	s64 freq;
534  
535  	if (ctrl->id == V4L2_CID_LINK_FREQ) {
536  		if (!csi->remote)
537  			return -EINVAL;
538  
539  		freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0);
540  		if (freq < 0) {
541  			dev_err(&csi->cldev->dev,
542  				"error %lld, invalid link_freq\n", freq);
543  			return -EINVAL;
544  		}
545  
546  		link_freq_menu_items[0] = freq;
547  		ctrl->val = 0;
548  
549  		return 0;
550  	}
551  
552  	return -EINVAL;
553  }
554  
555  static const struct v4l2_ctrl_ops mei_csi_ctrl_ops = {
556  	.g_volatile_ctrl = mei_csi_g_volatile_ctrl,
557  };
558  
559  static const struct v4l2_subdev_video_ops mei_csi_video_ops = {
560  	.s_stream = mei_csi_set_stream,
561  };
562  
563  static const struct v4l2_subdev_pad_ops mei_csi_pad_ops = {
564  	.init_cfg = mei_csi_init_cfg,
565  	.get_fmt = mei_csi_get_fmt,
566  	.set_fmt = mei_csi_set_fmt,
567  };
568  
569  static const struct v4l2_subdev_ops mei_csi_subdev_ops = {
570  	.video = &mei_csi_video_ops,
571  	.pad = &mei_csi_pad_ops,
572  };
573  
574  static const struct media_entity_operations mei_csi_entity_ops = {
575  	.link_validate = v4l2_subdev_link_validate,
576  };
577  
mei_csi_notify_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)578  static int mei_csi_notify_bound(struct v4l2_async_notifier *notifier,
579  				struct v4l2_subdev *subdev,
580  				struct v4l2_async_connection *asd)
581  {
582  	struct mei_csi *csi = notifier_to_csi(notifier);
583  	int pad;
584  
585  	pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
586  					  MEDIA_PAD_FL_SOURCE);
587  	if (pad < 0)
588  		return pad;
589  
590  	csi->remote = subdev;
591  	csi->remote_pad = pad;
592  
593  	return media_create_pad_link(&subdev->entity, pad,
594  				     &csi->subdev.entity, CSI_PAD_SINK,
595  				     MEDIA_LNK_FL_ENABLED |
596  				     MEDIA_LNK_FL_IMMUTABLE);
597  }
598  
mei_csi_notify_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)599  static void mei_csi_notify_unbind(struct v4l2_async_notifier *notifier,
600  				  struct v4l2_subdev *subdev,
601  				  struct v4l2_async_connection *asd)
602  {
603  	struct mei_csi *csi = notifier_to_csi(notifier);
604  
605  	csi->remote = NULL;
606  }
607  
608  static const struct v4l2_async_notifier_operations mei_csi_notify_ops = {
609  	.bound = mei_csi_notify_bound,
610  	.unbind = mei_csi_notify_unbind,
611  };
612  
mei_csi_init_controls(struct mei_csi * csi)613  static int mei_csi_init_controls(struct mei_csi *csi)
614  {
615  	u32 max;
616  	int ret;
617  
618  	mutex_init(&csi->ctrl_lock);
619  
620  	ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2);
621  	if (ret)
622  		return ret;
623  
624  	csi->ctrl_handler.lock = &csi->ctrl_lock;
625  
626  	max = ARRAY_SIZE(link_freq_menu_items) - 1;
627  	csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler,
628  						&mei_csi_ctrl_ops,
629  						V4L2_CID_LINK_FREQ,
630  						max,
631  						0,
632  						link_freq_menu_items);
633  	if (csi->freq_ctrl)
634  		csi->freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY |
635  					 V4L2_CTRL_FLAG_VOLATILE;
636  
637  	csi->privacy_ctrl = v4l2_ctrl_new_std(&csi->ctrl_handler, NULL,
638  					      V4L2_CID_PRIVACY, 0, 1, 1, 0);
639  	if (csi->privacy_ctrl)
640  		csi->privacy_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
641  
642  	if (csi->ctrl_handler.error)
643  		return csi->ctrl_handler.error;
644  
645  	csi->subdev.ctrl_handler = &csi->ctrl_handler;
646  
647  	return 0;
648  }
649  
mei_csi_parse_firmware(struct mei_csi * csi)650  static int mei_csi_parse_firmware(struct mei_csi *csi)
651  {
652  	struct v4l2_fwnode_endpoint v4l2_ep = {
653  		.bus_type = V4L2_MBUS_CSI2_DPHY,
654  	};
655  	struct device *dev = &csi->cldev->dev;
656  	struct v4l2_async_connection *asd;
657  	struct fwnode_handle *fwnode;
658  	struct fwnode_handle *ep;
659  	int ret;
660  
661  	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
662  	if (!ep) {
663  		dev_err(dev, "not connected to subdevice\n");
664  		return -EINVAL;
665  	}
666  
667  	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
668  	if (ret) {
669  		dev_err(dev, "could not parse v4l2 endpoint\n");
670  		fwnode_handle_put(ep);
671  		return -EINVAL;
672  	}
673  
674  	fwnode = fwnode_graph_get_remote_endpoint(ep);
675  	fwnode_handle_put(ep);
676  
677  	v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev);
678  	csi->notifier.ops = &mei_csi_notify_ops;
679  
680  	asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode,
681  				       struct v4l2_async_connection);
682  	if (IS_ERR(asd)) {
683  		fwnode_handle_put(fwnode);
684  		return PTR_ERR(asd);
685  	}
686  
687  	ret = v4l2_fwnode_endpoint_alloc_parse(fwnode, &v4l2_ep);
688  	fwnode_handle_put(fwnode);
689  	if (ret)
690  		return ret;
691  	csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
692  
693  	ret = v4l2_async_nf_register(&csi->notifier);
694  	if (ret)
695  		v4l2_async_nf_cleanup(&csi->notifier);
696  
697  	v4l2_fwnode_endpoint_free(&v4l2_ep);
698  
699  	return ret;
700  }
701  
mei_csi_probe(struct mei_cl_device * cldev,const struct mei_cl_device_id * id)702  static int mei_csi_probe(struct mei_cl_device *cldev,
703  			 const struct mei_cl_device_id *id)
704  {
705  	struct device *dev = &cldev->dev;
706  	struct mei_csi *csi;
707  	int ret;
708  
709  	if (!dev_fwnode(dev))
710  		return -EPROBE_DEFER;
711  
712  	csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL);
713  	if (!csi)
714  		return -ENOMEM;
715  
716  	csi->cldev = cldev;
717  	mutex_init(&csi->lock);
718  	init_completion(&csi->cmd_completion);
719  
720  	mei_cldev_set_drvdata(cldev, csi);
721  
722  	ret = mei_cldev_enable(cldev);
723  	if (ret < 0) {
724  		dev_err(dev, "mei_cldev_enable failed: %d\n", ret);
725  		goto destroy_mutex;
726  	}
727  
728  	ret = mei_cldev_register_rx_cb(cldev, mei_csi_rx);
729  	if (ret) {
730  		dev_err(dev, "event cb registration failed: %d\n", ret);
731  		goto err_disable;
732  	}
733  
734  	ret = mei_csi_parse_firmware(csi);
735  	if (ret)
736  		goto err_disable;
737  
738  	csi->subdev.dev = &cldev->dev;
739  	v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops);
740  	v4l2_set_subdevdata(&csi->subdev, csi);
741  	csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
742  			    V4L2_SUBDEV_FL_HAS_EVENTS;
743  	csi->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
744  	csi->subdev.entity.ops = &mei_csi_entity_ops;
745  
746  	snprintf(csi->subdev.name, sizeof(csi->subdev.name),
747  		 MEI_CSI_ENTITY_NAME);
748  
749  	ret = mei_csi_init_controls(csi);
750  	if (ret)
751  		goto err_ctrl_handler;
752  
753  	csi->format_mbus[CSI_PAD_SOURCE] = mei_csi_format_mbus_default;
754  	csi->format_mbus[CSI_PAD_SINK] = mei_csi_format_mbus_default;
755  
756  	csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
757  	csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
758  	ret = media_entity_pads_init(&csi->subdev.entity, CSI_NUM_PADS,
759  				     csi->pads);
760  	if (ret)
761  		goto err_ctrl_handler;
762  
763  	ret = v4l2_subdev_init_finalize(&csi->subdev);
764  	if (ret < 0)
765  		goto err_entity;
766  
767  	ret = v4l2_async_register_subdev(&csi->subdev);
768  	if (ret < 0)
769  		goto err_subdev;
770  
771  	pm_runtime_enable(&cldev->dev);
772  
773  	return 0;
774  
775  err_subdev:
776  	v4l2_subdev_cleanup(&csi->subdev);
777  
778  err_entity:
779  	media_entity_cleanup(&csi->subdev.entity);
780  
781  err_ctrl_handler:
782  	v4l2_ctrl_handler_free(&csi->ctrl_handler);
783  	mutex_destroy(&csi->ctrl_lock);
784  	v4l2_async_nf_unregister(&csi->notifier);
785  	v4l2_async_nf_cleanup(&csi->notifier);
786  
787  err_disable:
788  	mei_cldev_disable(cldev);
789  
790  destroy_mutex:
791  	mutex_destroy(&csi->lock);
792  
793  	return ret;
794  }
795  
mei_csi_remove(struct mei_cl_device * cldev)796  static void mei_csi_remove(struct mei_cl_device *cldev)
797  {
798  	struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
799  
800  	v4l2_async_nf_unregister(&csi->notifier);
801  	v4l2_async_nf_cleanup(&csi->notifier);
802  	v4l2_ctrl_handler_free(&csi->ctrl_handler);
803  	mutex_destroy(&csi->ctrl_lock);
804  	v4l2_async_unregister_subdev(&csi->subdev);
805  	v4l2_subdev_cleanup(&csi->subdev);
806  	media_entity_cleanup(&csi->subdev.entity);
807  
808  	pm_runtime_disable(&cldev->dev);
809  
810  	mutex_destroy(&csi->lock);
811  }
812  
813  #define MEI_CSI_UUID UUID_LE(0x92335FCF, 0x3203, 0x4472, \
814  			     0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA)
815  
816  static const struct mei_cl_device_id mei_csi_tbl[] = {
817  	{ MEI_CSI_DRIVER_NAME, MEI_CSI_UUID, MEI_CL_VERSION_ANY },
818  	{ /* sentinel */ }
819  };
820  MODULE_DEVICE_TABLE(mei, mei_csi_tbl);
821  
822  static struct mei_cl_driver mei_csi_driver = {
823  	.id_table = mei_csi_tbl,
824  	.name = MEI_CSI_DRIVER_NAME,
825  
826  	.probe = mei_csi_probe,
827  	.remove = mei_csi_remove,
828  };
829  
830  module_mei_cl_driver(mei_csi_driver);
831  
832  MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
833  MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
834  MODULE_DESCRIPTION("Device driver for IVSC CSI");
835  MODULE_LICENSE("GPL");
836