工作:
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);
}
W:\H3318C_ODM\H3318C\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(¬ifier->waiting);
INIT_LIST_HEAD(¬ifier->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, ¬ifier->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(¬ifier->list, ¬ifier_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;
}