基于RV1126 Video分析-----mipi dphy模块所代表的subdev子设备注册

工作:

								LIST_HEAD(notifier_list)----+                    LIST_HEAD(subdev_list)----+	
				                                            |                                              |
				                                            |                                              |
				                                            | 挂载                                         | 挂载
		                                                    |                                              |
struct techpoint 		                                    |                                              |
	struct v4l2_async_notifier *subdev_notifier; -----------+                                              |
		struct v4l2_subdev *sd; ---------+                                                                 |
			                             | bind                                                            |
	struct v4l2_subdev subdev;-----------+  ---------------------------------------------------------------+
		const struct v4l2_subdev_ops *ops(init!!!)		   
		struct v4l2_device *v4l2_dev; (NULL)        

	struct i2c_client *client;
		struct device dev;					
			struct device_node	*of_node; // A  			如节点	tp2855_1@44 
				struct	device_node *child;  //Aa           如节点 		ports 	
			+-------struct fwnode_handle *fwnode; 
			|	+---struct	device_node *child; // Aa-1     如节点    		ucam_out0
			|	|			
			|   |
			|   |
			|   |
			|   |
			|	|											LIST_HEAD(notifier_list)-----+         LIST_HEAD(subdev_list)-----+
			|	|																		 |                                    |
			|	|																		 |挂载                                |挂载
			|	|			struct mipidphy_priv                                         |                                    |
			|	|						                                                 |                                    |
			|	|		+-------struct v4l2_async_notifier notifier; --------------------+                                    |
			|	|		|			const struct v4l2_async_notifier_operations *ops; (init!!!)                               |
			|	|		|	+-------struct list_head waiting;//等待通知链表 												  |
			|	|		|	|		struct v4l2_async_subdev **subdevs;//数组 												  |
			|	|		|	+-----------|//subdevs[n] 将远端目标节点封装为 v4l2_async_subdev 结构 保存在该数组                |
			|	|		|				|enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE                      |
			|	|		|				|union match                                                                          |
			+---|-------|--------------------struct fwnode_handle *fwnode;													  |
				|		|			struct v4l2_subdev *sd ------------+                                                      |
				|		|						    				   |                                                      |
				|		|		struct v4l2_subdev sd;-----------------+ -----------------------------------------------------+
				|		|			const struct v4l2_subdev_ops *ops	
				|		|			struct v4l2_device *v4l2_dev; (NULL)
				|		+------------struct v4l2_async_notifier *subdev_notifier;
				|					
				|				struct device *dev;
				|					struct device_node	*of_node; //A associated device tree node           如 节点 csi_dphy0                        
				|						struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
				|							struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0 
				|								struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1  
				|------------------------------------remote-endpoint = <&ucam_out0> 设备树属性

//连接 0x44 前四通道 摄像头
&csi_dphy0 {                                     
	status = "okay";                 

  //mipi有两端一段连接Sensor,另一端连接 mipi_csi2_input
	 ports {                                         
		#address-cells = <1>;                         
		#size-cells = <0>;                            
          //连接到Sensor                                        
		port@0 {                                      
			reg = <0>;                                  
			#address-cells = <1>;                       
			#size-cells = <0>;                          
                                                 
			csi_dphy0_input: endpoint@1 {               
				reg = <1>;                                
				remote-endpoint = <&ucam_out0>;    // 连接到Sensor : ucam_out0       
				data-lanes = <1 2 3 4>;                   
			};                                          
		};                                            
         //连接到 mipi_csi2_input                             
		port@1 {                                      
			reg = <1>;                                  
			#address-cells = <1>;                       
			#size-cells = <0>;                          
                                                 
			csi_dphy0_output: endpoint@0 {              
				reg = <0>;                                
				remote-endpoint = <&mipi_csi2_input>;     // 连接到 mipi_csi2_input
				data-lanes = <1 2 3 4>;                   
			};                                          
		};                                            
	};                                             
};                                             

//连接 0x45 后四通道摄像头             
&csi_dphy1 {                                     
	status = "okay";

	 //连接到Sensor      
	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy1_input: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&ucam_out1>;// 连接到Sensor : ucam_out1 
				data-lanes = <1 2 3 4>;
			};
		};

		 //连接到ISP   
		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy1_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&isp_in>; // 连接到ISP : isp_in
				data-lanes = <1 2 3 4>;
			};
		};
	};     
};                                 

kernel\drivers\phy\rockchip\phy-rockchip-mipi-rx.c

// mipidphy 总线私有数据
struct mipidphy_priv {
	struct device *dev;
	struct regmap *regmap_grf;
	const struct dphy_reg *grf_regs;
	const struct txrx_reg *txrx_regs;
	const struct csiphy_reg *csiphy_regs;
	void __iomem *csihost_base_addr;
	struct clk *clks[MAX_DPHY_CLK];
	const struct dphy_drv_data *drv_data;
	u64 data_rate_mbps;
	struct v4l2_async_notifier notifier;
	struct v4l2_subdev sd;
	struct mutex mutex; /* lock for updating protection */
	struct media_pad pads[MIPI_DPHY_RX_PADS_NUM];
	struct mipidphy_sensor sensors[MAX_DPHY_SENSORS];
	int num_sensors;
	int phy_index;
	bool is_streaming;
	void __iomem *txrx_base_addr;
	int (*stream_on)(struct mipidphy_priv *priv, struct v4l2_subdev *sd);
	int (*stream_off)(struct mipidphy_priv *priv, struct v4l2_subdev *sd);
};



static const struct v4l2_subdev_pad_ops mipidphy_subdev_pad_ops = {
	.set_fmt = mipidphy_get_set_fmt,
	.get_fmt = mipidphy_get_set_fmt,
	.get_selection = mipidphy_get_selection,
};

static const struct v4l2_subdev_core_ops mipidphy_core_ops = {
	.s_power = mipidphy_s_power,
};

static const struct v4l2_subdev_video_ops mipidphy_video_ops = {
	.g_frame_interval = mipidphy_g_frame_interval,
	.g_mbus_config = mipidphy_g_mbus_config,
	.s_stream = mipidphy_s_stream,
};

static const struct v4l2_subdev_ops mipidphy_subdev_ops = {
	.core = &mipidphy_core_ops,
	.video = &mipidphy_video_ops,
	.pad = &mipidphy_subdev_pad_ops,
};


static const struct of_device_id rockchip_mipidphy_match_id[] = {
	{
		.compatible = "rockchip,rk1808-mipi-dphy-rx",
		.data = &rk1808_mipidphy_drv_data,
	},
	{
		.compatible = "rockchip,rk3288-mipi-dphy",
		.data = &rk3288_mipidphy_drv_data,
	},
	{
		.compatible = "rockchip,rk3326-mipi-dphy",
		.data = &rk3326_mipidphy_drv_data,
	},
	{
		.compatible = "rockchip,rk3368-mipi-dphy",
		.data = &rk3368_mipidphy_drv_data,
	},
	{
		.compatible = "rockchip,rk3399-mipi-dphy",
		.data = &rk3399_mipidphy_drv_data,
	},
	{
		.compatible = "rockchip,rv1126-csi-dphy",
		.data = &rv1126_mipidphy_drv_data,
	},
	{}
};


static const struct
v4l2_async_notifier_operations rockchip_mipidphy_async_ops = {
	.bound = rockchip_mipidphy_notifier_bound,
	.unbind = rockchip_mipidphy_notifier_unbind,
};


	/*
1 注册	 
		  sd = &priv->sd; 绑定 struct mipidphy_priv ---- v4l2_subdev
          sd->ops = &mipidphy_subdev_ops;
          sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
          sd->v4l2_dev = NULL
	
2 初始化 异步通知notifier 的ops操作集  mipidphy_priv-->v4l2_async_notifier-->ops

3 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
  将异步通知notifier挂载到 全局notifier_list链表上 
  
4 将当前subdev挂载到 全局链表subdev_list上           

*/
static int rockchip_mipidphy_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	
	// v4l2_subdev
	struct v4l2_subdev *sd;
	
	//MIPI 总线私有数据
	struct mipidphy_priv *priv;
	struct regmap *grf;
	struct resource *res;
	const struct of_device_id *of_id;
	const struct dphy_drv_data *drv_data;
	int i, ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
	priv->dev = dev;

	of_id = of_match_device(rockchip_mipidphy_match_id, dev);
	if (!of_id)
		return -EINVAL;

...
	
	//注册
	/*
	 * 同样的
	 * sd = &priv->sd; 绑定 struct mipidphy_priv ---- v4l2_subdev
	 * sd->ops = &mipidphy_subdev_ops;
	 * sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
	 * sd->v4l2_dev = NULL
	 */
	sd = &priv->sd;
	mutex_init(&priv->mutex);
	v4l2_subdev_init(sd, &mipidphy_subdev_ops);
	
...

	/*
		
	1 初始化 异步通知notifier 的ops操作集  mipidphy_priv-->v4l2_async_notifier-->ops
	
	2 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
	  将异步通知notifier挂载到 全局notifier_list链表上 
	  
	3 将当前subdev挂载到 全局链表subdev_list上  
	*/
	ret = rockchip_mipidphy_media_init(priv);
	if (ret < 0)
		goto destroy_mutex;

...
	return 0;
}


static struct platform_driver rockchip_isp_mipidphy_driver = {
	.probe = rockchip_mipidphy_probe,
	.remove = rockchip_mipidphy_remove,
	.driver = {
			.name = "rockchip-mipi-dphy-rx",
			.pm = &rockchip_mipidphy_pm_ops,
			.of_match_table = rockchip_mipidphy_match_id,
	},
};






static int rockchip_mipidphy_media_init(struct mipidphy_priv *priv)
{
	int ret;

	priv->pads[MIPI_DPHY_RX_PAD_SOURCE].flags =
		MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
	priv->pads[MIPI_DPHY_RX_PAD_SINK].flags =
		MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
	priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
	
	...
	
	/* 设备树解析
	
	 参数1 mipidphy_priv->device
	 参数2 mipidphy_priv->v4l2_async_notifier
	 参数3 size_t asd_struct_size
	 参数4 0
	 参数5 函数指针 rockchip_mipidphy_fwnode_parse
	
	*/
	/*
	 工作
	 第一步 通过 csi_dphy0 节点 找到 最底层孙设备 endpoint@1 节点
			struct mipidphy_priv
				struct device *dev;
				(-->)struct device_node	*of_node; //A associated device tree node           如 节点 csi_dphy0                        传入参数节点 !!!!
						struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
							struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0 
								struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1  传输的参数节点 !!!!
								(<--)struct fwnode_handle fwnode;		

	 第二步 通过 最底层孙设备 endpoint@1 节点 的 "remote-endpoint" 属性  找到 远程关联节点ucam_out0 的 父节点port
	 
	 第三步 将 远程关联节点ucam_out0 的 父节点port 信息 组织成 struct v4l2_async_subdev 数据结构。作为子设备 添加到 struct mipidphy_priv 中 。
				这样 就将sensor信息与 mipidphy 信息 关联了起来
	 
		
		struct mipidphy_priv
			struct device *dev;
				struct device_node	*of_node; //A associated device tree node           如 节点 csi_dphy0                        
					struct	device_node *child;  //Aa                 第一个子节点      如 节点 	ports 				
						struct	device_node *child; // Aa-1           第一个子节点      如 节点 		port@0 
							struct	device_node *child; //Aa-1-1      第一个子节点      如 节点 			endpoint@1  
								struct fwnode_handle fwnode;
			struct v4l2_async_notifier notifier;	
				struct v4l2_async_subdev **subdevs;//subdevs数组
					enum v4l2_async_match_type match_type = V4L2_ASYNC_MATCH_FWNODE  设备树fwnode匹配方式 
					union match
						struct fwnode_handle *fwnode;-----------------------------------------------------相连接的远程节点ucam_out0 的 父节点port的 fwnode
	*/
	ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
		priv->dev, &priv->notifier,
		sizeof(struct sensor_async_subdev), 0,
		rockchip_mipidphy_fwnode_parse);
	if (ret < 0)
		return ret;
	
	//如果 priv->notifier.num_subdevs 为0  返回
	if (!priv->notifier.num_subdevs)
		return -ENODEV;	/* no endpoint */
	

	//统一 异步通知notifier 。注意此时 异步通知notifier 为空 还没有被初始化
	priv->sd.subdev_notifier = &priv->notifier;
	//初始化 异步通知notifier 的ops操作集,注意此时 异步通知notifier的ops不为NULL
	priv->notifier.ops = &rockchip_mipidphy_async_ops;
	
	
	/* 主要就是将异步通知notifier挂载到 全局notifier_list链表上 
		
		
		参数1 struct mipidphy_priv -> v4l2_subdev
		参数2 struct mipidphy_priv -> v4l2_async_notifier
		
		1 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
		2 将异步通知notifier挂载到 全局notifier_list链表上 
		3 对于mipi-csi-phy驱动 还有 将 远端关联节点的顶层父节点 挂载到  struct mipidphy_priv -> v4l2_async_notifier->waiting 等待链表上
		
		v4l2_subdev
		v4l2_async_notifier
	*/
	ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier);
	if (ret) {
		dev_err(priv->dev,
			"failed to register async notifier : %d\n", ret);
		v4l2_async_notifier_cleanup(&priv->notifier);
		return ret;
	}

	//将当前subdev挂载到 全局链表subdev_list上
	return v4l2_async_register_subdev(&priv->sd);
}

kernel\drivers\media\v4l2-core\v4l2-async.c

static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表


/*

		参数1 struct mipidphy_priv -> v4l2_subdev
		参数2 struct mipidphy_priv -> v4l2_async_notifier
*/
int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
					struct v4l2_async_notifier *notifier)
{
	int ret;

	if (WARN_ON(!sd || notifier->v4l2_dev))
		return -EINVAL;

	/*
         * 记录subdev
         */

	notifier->sd = sd;

	/*
	参数 struct mipidphy_priv -> v4l2_async_notifier
	
	异步通知注册 主要就是操作notifier 
	*/
	ret = __v4l2_async_notifier_register(notifier);
	if (ret)
		notifier->sd = NULL;

	return ret;
}



static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
	struct device *dev =
		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
	struct v4l2_async_subdev *asd;
	int ret;
	int i;

	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
		return -EINVAL;

	INIT_LIST_HEAD(&notifier->waiting);
	INIT_LIST_HEAD(&notifier->done);

	mutex_lock(&list_lock);
		 /*
		对于mipi-csi-phy驱动
			mipi-csi-phy驱动。在此之前已经  保存提取到的 节点endpoint 对应的远端关联节点的顶层父节点(如 tp2855_1@44) 到 mipidphy_priv->v4l2_async_notifier->subdevs[]数组
		
		对于mipi-cis 驱动
			mipi-cis 驱动。在此之前已经  保存提取到的 节点endpoint 对应的远端关联节点的顶层父节点(如 csi_dphy0) 到 csi2_dev->v4l2_async_notifier->subdevs[]数组
			
		对于 rkcif_mipi驱动 
			rkcif_mipi驱动。在此之前已经  保存提取到的 节点endpoint 对应的远端关联节点的顶层父节点(如 mipi_csi2) 到 rkcif_device->v4l2_async_notifier->subdevs[]数组
		
		
		1 对于mipi-csi-phy驱动  将 远端关联节点的顶层父节点 挂载到  struct mipidphy_priv -> v4l2_async_notifier->waiting 等待链表上 ((子设备描述v4l2_async_subdev 链表 waiting) )
		2 对于mipi-csi 驱动 将 远端关联节点的顶层父节点 挂载到  struct csi2_dev -> v4l2_async_notifier->waiting 等待链表上  (子设备描述v4l2_async_subdev 链表 waiting) 
		3 对于rkcif_mipi驱动 将 远端关联节点的顶层父节点 挂载到  struct rkcif_device -> v4l2_async_notifier->waiting 等待链表上 (子设备描述v4l2_async_subdev 链表 waiting) 
		
		
		对于 sensor驱动 无,跳过
	  */
for (i = 0; i < notifier->num_subdevs; i++) {
		
	//获取  对应的远端关联节点的父节点
	asd = notifier->subdevs[i];
		...
	//将 远端关联节点的顶层父节点 挂载到  struct mipidphy_priv -> v4l2_async_notifier->waiting 等待链表上 (子设备描述v4l2_async_subdev 链表 waiting) 
	/*
	参数1 远端关联节点的顶层父节点的 链表节点
	参数2 struct mipidphy_priv -> v4l2_async_notifier->waiting 等待链表
	*/
	list_add_tail(&asd->list, &notifier->waiting);

	}

	//该函数只能从V4L2顶层设备:rkcif_mipi设备 开始执行。因为其他三个subdev设备自己刚开始是没有初始化 自己的 父通知器 以及 自己的通知器所管理的 v4l2_device设备的
	ret = v4l2_async_notifier_try_all_subdevs(notifier);


	 /*  	参数1  当前设备异步通知器				
         * 条件不满足,暂时不进入分析,不满足原因如下
         * 1. notifier->parent == NULL
         * 2. notifier->v4l2_dev == NULL
		 
		 所以其他三个subdev设备 独自初始化时 不满足该函数运行条件
		 
		 只有 rkcif_mipi 能执行该函数
         */

	ret = v4l2_async_notifier_try_complete(notifier);

	  /*
         * 以上2个函数可以看出来,v4l2_dev为空时都不会执行
         * 将这个notifer挂载到链表notifier_list上
         */
	list_add(&notifier->list, &notifier_list);

...
}


int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *subdev_notifier;
	struct v4l2_async_notifier *notifier;
	int ret;

...

	mutex_lock(&list_lock);

	INIT_LIST_HEAD(&sd->async_list);

...

	/* None matched, wait for hot-plugging */
	 /*
         * 没有匹配到相关的信息
         * 将当前subdev挂载到 全局链表subdev_list上
         */
		 
	list_add(&sd->async_list, &subdev_list);

...

	return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值