mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From ee3b2b581fa4a51535207fb45e7cd4253dbf9a43 Mon Sep 17 00:00:00 2001
 | |
| From: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | |
| Date: Fri, 29 Jul 2022 17:46:49 +0100
 | |
| Subject: [PATCH] media: video-mux: Read CSI2 config from FW, and pass to
 | |
|  receiver
 | |
| 
 | |
| There is no obligation for all source devices on a video-mux to
 | |
| require the same bus configuration, so read the configuration
 | |
| from the sink ports, and relay via get_mbus_config on the source
 | |
| port.
 | |
| If the sources support get_mbus_config, then call that first.
 | |
| 
 | |
| Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
 | |
| ---
 | |
|  drivers/media/platform/video-mux.c | 68 +++++++++++++++++++++++++++++-
 | |
|  1 file changed, 66 insertions(+), 2 deletions(-)
 | |
| 
 | |
| --- a/drivers/media/platform/video-mux.c
 | |
| +++ b/drivers/media/platform/video-mux.c
 | |
| @@ -20,11 +20,28 @@
 | |
|  #include <media/v4l2-mc.h>
 | |
|  #include <media/v4l2-subdev.h>
 | |
|  
 | |
| +struct video_mux_asd {
 | |
| +	struct v4l2_async_subdev base;
 | |
| +	unsigned int port;
 | |
| +};
 | |
| +
 | |
| +static inline struct video_mux_asd *to_video_mux_asd(struct v4l2_async_subdev *asd)
 | |
| +{
 | |
| +	return container_of(asd, struct video_mux_asd, base);
 | |
| +}
 | |
| +
 | |
| +struct video_mux_pad_cfg {
 | |
| +	unsigned int num_lanes;
 | |
| +	bool non_continuous;
 | |
| +	struct v4l2_subdev *source;
 | |
| +};
 | |
| +
 | |
|  struct video_mux {
 | |
|  	struct v4l2_subdev subdev;
 | |
|  	struct v4l2_async_notifier notifier;
 | |
|  	struct media_pad *pads;
 | |
|  	struct v4l2_mbus_framefmt *format_mbus;
 | |
| +	struct video_mux_pad_cfg *cfg;
 | |
|  	struct mux_control *mux;
 | |
|  	struct mutex lock;
 | |
|  	int active;
 | |
| @@ -330,10 +347,34 @@ static int video_mux_init_cfg(struct v4l
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static int video_mux_get_mbus_config(struct v4l2_subdev *sd,
 | |
| +				     unsigned int pad,
 | |
| +				     struct v4l2_mbus_config *cfg)
 | |
| +{
 | |
| +	struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
 | |
| +	int ret;
 | |
| +
 | |
| +	ret = v4l2_subdev_call(vmux->cfg[vmux->active].source, pad, get_mbus_config,
 | |
| +			       0, cfg);
 | |
| +
 | |
| +	if (ret != -ENOIOCTLCMD)
 | |
| +		return ret;
 | |
| +
 | |
| +	cfg->type = V4L2_MBUS_CSI2_DPHY;
 | |
| +	cfg->bus.mipi_csi2.num_data_lanes = vmux->cfg[vmux->active].num_lanes;
 | |
| +
 | |
| +	/* Support for non-continuous CSI-2 clock is missing in pdate mode */
 | |
| +	if (vmux->cfg[vmux->active].non_continuous)
 | |
| +		cfg->bus.mipi_csi2.flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
 | |
| +
 | |
| +	return 0;
 | |
| +};
 | |
| +
 | |
|  static const struct v4l2_subdev_pad_ops video_mux_pad_ops = {
 | |
|  	.init_cfg = video_mux_init_cfg,
 | |
|  	.get_fmt = video_mux_get_format,
 | |
|  	.set_fmt = video_mux_set_format,
 | |
| +	.get_mbus_config = video_mux_get_mbus_config,
 | |
|  };
 | |
|  
 | |
|  static const struct v4l2_subdev_ops video_mux_subdev_ops = {
 | |
| @@ -346,6 +387,9 @@ static int video_mux_notify_bound(struct
 | |
|  				  struct v4l2_async_subdev *asd)
 | |
|  {
 | |
|  	struct video_mux *vmux = notifier_to_video_mux(notifier);
 | |
| +	unsigned int port = to_video_mux_asd(asd)->port;
 | |
| +
 | |
| +	vmux->cfg[port].source = sd;
 | |
|  
 | |
|  	return v4l2_create_fwnode_links(sd, &vmux->subdev);
 | |
|  }
 | |
| @@ -363,7 +407,7 @@ static int video_mux_async_register(stru
 | |
|  	v4l2_async_nf_init(&vmux->notifier);
 | |
|  
 | |
|  	for (i = 0; i < num_input_pads; i++) {
 | |
| -		struct v4l2_async_subdev *asd;
 | |
| +		struct video_mux_asd *asd;
 | |
|  		struct fwnode_handle *ep, *remote_ep;
 | |
|  
 | |
|  		ep = fwnode_graph_get_endpoint_by_id(
 | |
| @@ -381,7 +425,8 @@ static int video_mux_async_register(stru
 | |
|  		fwnode_handle_put(remote_ep);
 | |
|  
 | |
|  		asd = v4l2_async_nf_add_fwnode_remote(&vmux->notifier, ep,
 | |
| -						      struct v4l2_async_subdev);
 | |
| +						      struct video_mux_asd);
 | |
| +		asd->port = i;
 | |
|  
 | |
|  		fwnode_handle_put(ep);
 | |
|  
 | |
| @@ -406,6 +451,9 @@ static int video_mux_probe(struct platfo
 | |
|  {
 | |
|  	struct device_node *np = pdev->dev.of_node;
 | |
|  	struct device *dev = &pdev->dev;
 | |
| +	struct v4l2_fwnode_endpoint fwnode_ep = {
 | |
| +		.bus_type = V4L2_MBUS_CSI2_DPHY
 | |
| +	};
 | |
|  	struct device_node *ep;
 | |
|  	struct video_mux *vmux;
 | |
|  	unsigned int num_pads = 0;
 | |
| @@ -458,10 +506,26 @@ static int video_mux_probe(struct platfo
 | |
|  	if (!vmux->format_mbus)
 | |
|  		return -ENOMEM;
 | |
|  
 | |
| +	vmux->cfg = devm_kcalloc(dev, num_pads, sizeof(*vmux->cfg), GFP_KERNEL);
 | |
| +	if (!vmux->cfg)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
|  	for (i = 0; i < num_pads; i++) {
 | |
|  		vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK
 | |
|  							 : MEDIA_PAD_FL_SOURCE;
 | |
|  		vmux->format_mbus[i] = video_mux_format_mbus_default;
 | |
| +
 | |
| +		ep = of_graph_get_endpoint_by_regs(pdev->dev.of_node, i, 0);
 | |
| +		if (ep) {
 | |
| +			ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fwnode_ep);
 | |
| +			if (!ret) {
 | |
| +				/* Get number of data lanes */
 | |
| +				vmux->cfg[i].num_lanes = fwnode_ep.bus.mipi_csi2.num_data_lanes;
 | |
| +				vmux->cfg[i].non_continuous = fwnode_ep.bus.mipi_csi2.flags &
 | |
| +							V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
 | |
| +			}
 | |
| +			of_node_put(ep);
 | |
| +		}
 | |
|  	}
 | |
|  
 | |
|  	vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX;
 |