mipi csi与mipi csi phy部件之间如何连接?
回帖(1)
2022-3-10 09:41:53
二,mipi csi 与mipi csi phy
这里直接贴出来bount函数
static const struct
v4l2_async_notifier_operations csi2_async_ops = {
.bound = csi2_notifier_bound,
.unbind = csi2_notifier_unbind,
};
static int
csi2_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
struct csi2_sensor *sensor;
struct media_link *link;
unsigned int pad, ret;
if (csi2->num_sensors == ARRAY_SIZE(csi2->sensors))
return -EBUSY;
sensor = &csi2->sensors[csi2->num_sensors++];
/*
* 这里的sd是mipi csi phy的subdev
*/
sensor->sd = sd;
/*
* mipi csi phy 的entity有2个pad
* 1个sink pad,1个source pad
* 这里是要找到source pad
* 为什么要找source呢?
* 因为source才是下一级需要的
* 可以看到这里只考虑了一个pad
* 因为写驱动的人知道source media 及 sink media的pad的个数
*/
for (pad = 0; pad < sd->entity.num_pads; pad++)
if (sensor->sd->entity.pads[pad].flags
& MEDIA_PAD_FL_SOURCE)
break;
/*
* 这里表示没有找到source pad
* 返回-ENXIO
*/
if (pad == sensor->sd->entity.num_pads) {
dev_err(csi2->dev,
"failed to find src pad for %sn",
sd->name);
return -ENXIO;
}
/*
* 这里重点分析
*/
ret = media_create_pad_link(&sensor->sd->entity, pad,
&csi2->sd.entity, RK_CSI2_PAD_SINK,
0/* csi2->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED */);
if (ret) {
dev_err(csi2->dev,
"failed to create link for %sn",
sd->name);
return ret;
}
/*
* 从entity的links链表上,找到第一个link
* 主意这个entity是mipi-csi的,不是mipi-csi-phy的
*/
link = list_first_entry(&csi2->sd.entity.links, struct media_link, list);
ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
if (ret) {
dev_err(csi2->dev,
"failed to create link for %sn",
sensor->sd->name);
return ret;
}
return 0;
}
csi2_notifier_bound() -> media_create_pad_link()
int
media_create_pad_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags)
{
struct media_link *link;
struct media_link *backlink;
BUG_ON(source == NULL || sink == NULL);
BUG_ON(source_pad >= source->num_pads);
BUG_ON(sink_pad >= sink->num_pads);
/*
* 创建一个link
* 这个link连接到source的links链表
*/
link = media_add_link(&source->links);
if (link == NULL)
return -ENOMEM;
/*
* link的source指向source的source pad
* link的sink指向sink的sink pad
*/
link->source = &source->pads[source_pad];
link->sink = &sink->pads[sink_pad];
link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
/* Initialize graph object embedded at the new link */
/*
* 之前分析imx291 mipi-csi-phy mipi-csi的时候
* 都是因为这个graph_obj.mdev为NULL
* 而无法深入分析
* 那么现在的source其mdev是怎么得到的呢?
* 在函数 v4l2_device_register_subdev中
* 调用 media_device_register_entity 设置的
* 这里建议去看
* v4l2_async_subdev_notifier_register 分析
* https://blog.csdn.net/ldl617/article/details/115548594
* 另外主意这里的所有点entity都已经链接到了media的entities链表
*
* media_gobj_create已经分析了很多次了
* 将link通过greph_obj链接到media的links链表
*/
media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
&link->graph_obj);
/* Create the backlink. Backlinks are used to help graph traversal and
* are not reported to userspace.
*/
/*
* 创建一个backlink,链接到sink底links
* 虽说是反向link
* 但是source和sink指向还是没有改变的
* 最后is_backlink = true 用于表示这是个反向link
*/
backlink = media_add_link(&sink->links);
if (backlink == NULL) {
__media_entity_remove_link(source, link);
return -ENOMEM;
}
backlink->source = &source->pads[source_pad];
backlink->sink = &sink->pads[sink_pad];
backlink->flags = flags;
backlink->is_backlink = true;
/* Initialize graph object embedded at the new link */
/*
* 将backlink通过graph_obj链接到media的links
*/
media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
&backlink->graph_obj);
/*
* link和backlink关联起来
*/
link->reverse = backlink;
backlink->reverse = link;
/*
* 更新sink的links和backlinks数量
* 更新source的links数量
*/
sink->num_backlinks++;
sink->num_links++;
source->num_links++;
return 0;
}
csi2_notifier_bound() -> media_entity_setup_link()
media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
int media_entity_setup_link(struct media_link *link, u32 flags)
{
int ret;
mutex_lock(&link->graph_obj.mdev->graph_mutex);
ret = __media_entity_setup_link(link, flags);
mutex_unlock(&link->graph_obj.mdev->graph_mutex);
return ret;
}
int __media_entity_setup_link(struct media_link *link, u32 flags)
{
const u32 mask = MEDIA_LNK_FL_ENABLED;
struct media_device *mdev;
struct media_entity *source, *sink;
int ret = -EBUSY;
if (link == NULL)
return -EINVAL;
/* The non-modifiable link flags must not be modified. */
/*
* link->flags 这里是0
* flag = MEDIA_LNK_FL_ENABLE
* 所以if不满足
*/
if ((link->flags & ~mask) != (flags & ~mask))
return -EINVAL;
if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
return link->flags == flags ? 0 : -EINVAL;
if (link->flags == flags)
return 0;
/*
* 分别找到source entity
* 和sink entity
*/
source = link->source->entity;
sink = link->sink->entity;
/*
* stream_count值大于0,可以认为启动了数据流传输
* 这里没有,所以为0
*/
if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
(source->stream_count || sink->stream_count))
return -EBUSY;
/*
* 找到所属的media
*/
mdev = source->graph_obj.mdev;
/*
* 调用media->ops->link_notify
* 基于RV1126平台imx291分析 --- media注册
* https://blog.csdn.net/ldl617/article/details/115677554
* 可以看上面的分析,medv没有ops,所以这里不分析
*/
if (mdev->ops && mdev->ops->link_notify) {
ret = mdev->ops->link_notify(link, flags,
MEDIA_DEV_NOTIFY_PRE_LINK_CH);
if (ret < 0)
return ret;
}
ret = __media_entity_setup_link_notify(link, flags);
if (mdev->ops && mdev->ops->link_notify)
mdev->ops->link_notify(link, flags,
MEDIA_DEV_NOTIFY_POST_LINK_CH);
return ret;
}
csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify()
static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
{
int ret;
/* Notify both entities. */
/*
* source entity 是mipi-csi-phy
* sink entity 是mipi csi
* mipi csi entity有ops = csi_entity_ops
*/
/* source entity没有ops */
ret = media_entity_call(link->source->entity, link_setup,
link->source, link->sink, flags);
if (ret < 0 && ret != -ENOIOCTLCMD)
return ret;
/*
* 调用 csi_entity_ops.link_setup
* 对应 csi2_link_setup
*/
ret = media_entity_call(link->sink->entity, link_setup,
link->sink, link->source, flags);
if (ret < 0 && ret != -ENOIOCTLCMD) {
media_entity_call(link->source->entity, link_setup,
link->source, link->sink, link->flags);
return ret;
}
/*
* 更新link->flags为ENABLE
* 同时backlink的也更新一下
*/
link->flags = flags;
link->reverse->flags = link->flags;
return 0;
}
csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify() -> csi2_link_setup()
static int csi2_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags)
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct csi2_dev *csi2 = sd_to_dev(sd);
struct v4l2_subdev *remote_sd;
int ret = 0;
/*
* 根据上下文分析
* entity是sink entity
* local 是sink pad
* remote 是source pad
* remote->entity是 source mentity
* flags 是 MEDIA_LNK_FL_ENABLED
*/
/*
* sd.entity == remote->entity
* 根据entity找到subdev
* 这里的remote_sd就是mipi-csi-phy的subdev
*/
remote_sd = media_entity_to_v4l2_subdev(remote->entity);
mutex_lock(&csi2->lock);
/*
* local->flags = 0
*/
if (local->flags & MEDIA_PAD_FL_SOURCE) {
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->sink_linked[local->index - 1]) {
ret = -EBUSY;
goto out;
}
csi2->sink_linked[local->index - 1] = true;
} else {
csi2->sink_linked[local->index - 1] = false;
}
} else {
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->src_sd) {
ret = -EBUSY;
goto out;
}
/*
* csi2通过src_sd直接关联到mipi-csi-phy的subdev
*/
csi2->src_sd = remote_sd;
} else {
csi2->src_sd = NULL;
}
}
out:
mutex_unlock(&csi2->lock);
return ret;
}
最后链接情况如下
二,mipi csi 与mipi csi phy
这里直接贴出来bount函数
static const struct
v4l2_async_notifier_operations csi2_async_ops = {
.bound = csi2_notifier_bound,
.unbind = csi2_notifier_unbind,
};
static int
csi2_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct csi2_dev *csi2 = container_of(notifier,
struct csi2_dev,
notifier);
struct csi2_sensor *sensor;
struct media_link *link;
unsigned int pad, ret;
if (csi2->num_sensors == ARRAY_SIZE(csi2->sensors))
return -EBUSY;
sensor = &csi2->sensors[csi2->num_sensors++];
/*
* 这里的sd是mipi csi phy的subdev
*/
sensor->sd = sd;
/*
* mipi csi phy 的entity有2个pad
* 1个sink pad,1个source pad
* 这里是要找到source pad
* 为什么要找source呢?
* 因为source才是下一级需要的
* 可以看到这里只考虑了一个pad
* 因为写驱动的人知道source media 及 sink media的pad的个数
*/
for (pad = 0; pad < sd->entity.num_pads; pad++)
if (sensor->sd->entity.pads[pad].flags
& MEDIA_PAD_FL_SOURCE)
break;
/*
* 这里表示没有找到source pad
* 返回-ENXIO
*/
if (pad == sensor->sd->entity.num_pads) {
dev_err(csi2->dev,
"failed to find src pad for %sn",
sd->name);
return -ENXIO;
}
/*
* 这里重点分析
*/
ret = media_create_pad_link(&sensor->sd->entity, pad,
&csi2->sd.entity, RK_CSI2_PAD_SINK,
0/* csi2->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED */);
if (ret) {
dev_err(csi2->dev,
"failed to create link for %sn",
sd->name);
return ret;
}
/*
* 从entity的links链表上,找到第一个link
* 主意这个entity是mipi-csi的,不是mipi-csi-phy的
*/
link = list_first_entry(&csi2->sd.entity.links, struct media_link, list);
ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
if (ret) {
dev_err(csi2->dev,
"failed to create link for %sn",
sensor->sd->name);
return ret;
}
return 0;
}
csi2_notifier_bound() -> media_create_pad_link()
int
media_create_pad_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags)
{
struct media_link *link;
struct media_link *backlink;
BUG_ON(source == NULL || sink == NULL);
BUG_ON(source_pad >= source->num_pads);
BUG_ON(sink_pad >= sink->num_pads);
/*
* 创建一个link
* 这个link连接到source的links链表
*/
link = media_add_link(&source->links);
if (link == NULL)
return -ENOMEM;
/*
* link的source指向source的source pad
* link的sink指向sink的sink pad
*/
link->source = &source->pads[source_pad];
link->sink = &sink->pads[sink_pad];
link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
/* Initialize graph object embedded at the new link */
/*
* 之前分析imx291 mipi-csi-phy mipi-csi的时候
* 都是因为这个graph_obj.mdev为NULL
* 而无法深入分析
* 那么现在的source其mdev是怎么得到的呢?
* 在函数 v4l2_device_register_subdev中
* 调用 media_device_register_entity 设置的
* 这里建议去看
* v4l2_async_subdev_notifier_register 分析
* https://blog.csdn.net/ldl617/article/details/115548594
* 另外主意这里的所有点entity都已经链接到了media的entities链表
*
* media_gobj_create已经分析了很多次了
* 将link通过greph_obj链接到media的links链表
*/
media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
&link->graph_obj);
/* Create the backlink. Backlinks are used to help graph traversal and
* are not reported to userspace.
*/
/*
* 创建一个backlink,链接到sink底links
* 虽说是反向link
* 但是source和sink指向还是没有改变的
* 最后is_backlink = true 用于表示这是个反向link
*/
backlink = media_add_link(&sink->links);
if (backlink == NULL) {
__media_entity_remove_link(source, link);
return -ENOMEM;
}
backlink->source = &source->pads[source_pad];
backlink->sink = &sink->pads[sink_pad];
backlink->flags = flags;
backlink->is_backlink = true;
/* Initialize graph object embedded at the new link */
/*
* 将backlink通过graph_obj链接到media的links
*/
media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
&backlink->graph_obj);
/*
* link和backlink关联起来
*/
link->reverse = backlink;
backlink->reverse = link;
/*
* 更新sink的links和backlinks数量
* 更新source的links数量
*/
sink->num_backlinks++;
sink->num_links++;
source->num_links++;
return 0;
}
csi2_notifier_bound() -> media_entity_setup_link()
media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
int media_entity_setup_link(struct media_link *link, u32 flags)
{
int ret;
mutex_lock(&link->graph_obj.mdev->graph_mutex);
ret = __media_entity_setup_link(link, flags);
mutex_unlock(&link->graph_obj.mdev->graph_mutex);
return ret;
}
int __media_entity_setup_link(struct media_link *link, u32 flags)
{
const u32 mask = MEDIA_LNK_FL_ENABLED;
struct media_device *mdev;
struct media_entity *source, *sink;
int ret = -EBUSY;
if (link == NULL)
return -EINVAL;
/* The non-modifiable link flags must not be modified. */
/*
* link->flags 这里是0
* flag = MEDIA_LNK_FL_ENABLE
* 所以if不满足
*/
if ((link->flags & ~mask) != (flags & ~mask))
return -EINVAL;
if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
return link->flags == flags ? 0 : -EINVAL;
if (link->flags == flags)
return 0;
/*
* 分别找到source entity
* 和sink entity
*/
source = link->source->entity;
sink = link->sink->entity;
/*
* stream_count值大于0,可以认为启动了数据流传输
* 这里没有,所以为0
*/
if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
(source->stream_count || sink->stream_count))
return -EBUSY;
/*
* 找到所属的media
*/
mdev = source->graph_obj.mdev;
/*
* 调用media->ops->link_notify
* 基于RV1126平台imx291分析 --- media注册
* https://blog.csdn.net/ldl617/article/details/115677554
* 可以看上面的分析,medv没有ops,所以这里不分析
*/
if (mdev->ops && mdev->ops->link_notify) {
ret = mdev->ops->link_notify(link, flags,
MEDIA_DEV_NOTIFY_PRE_LINK_CH);
if (ret < 0)
return ret;
}
ret = __media_entity_setup_link_notify(link, flags);
if (mdev->ops && mdev->ops->link_notify)
mdev->ops->link_notify(link, flags,
MEDIA_DEV_NOTIFY_POST_LINK_CH);
return ret;
}
csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify()
static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
{
int ret;
/* Notify both entities. */
/*
* source entity 是mipi-csi-phy
* sink entity 是mipi csi
* mipi csi entity有ops = csi_entity_ops
*/
/* source entity没有ops */
ret = media_entity_call(link->source->entity, link_setup,
link->source, link->sink, flags);
if (ret < 0 && ret != -ENOIOCTLCMD)
return ret;
/*
* 调用 csi_entity_ops.link_setup
* 对应 csi2_link_setup
*/
ret = media_entity_call(link->sink->entity, link_setup,
link->sink, link->source, flags);
if (ret < 0 && ret != -ENOIOCTLCMD) {
media_entity_call(link->source->entity, link_setup,
link->source, link->sink, link->flags);
return ret;
}
/*
* 更新link->flags为ENABLE
* 同时backlink的也更新一下
*/
link->flags = flags;
link->reverse->flags = link->flags;
return 0;
}
csi2_notifier_bound() -> media_entity_setup_link() -> __media_entity_setup_link_notify() -> csi2_link_setup()
static int csi2_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags)
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct csi2_dev *csi2 = sd_to_dev(sd);
struct v4l2_subdev *remote_sd;
int ret = 0;
/*
* 根据上下文分析
* entity是sink entity
* local 是sink pad
* remote 是source pad
* remote->entity是 source mentity
* flags 是 MEDIA_LNK_FL_ENABLED
*/
/*
* sd.entity == remote->entity
* 根据entity找到subdev
* 这里的remote_sd就是mipi-csi-phy的subdev
*/
remote_sd = media_entity_to_v4l2_subdev(remote->entity);
mutex_lock(&csi2->lock);
/*
* local->flags = 0
*/
if (local->flags & MEDIA_PAD_FL_SOURCE) {
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->sink_linked[local->index - 1]) {
ret = -EBUSY;
goto out;
}
csi2->sink_linked[local->index - 1] = true;
} else {
csi2->sink_linked[local->index - 1] = false;
}
} else {
if (flags & MEDIA_LNK_FL_ENABLED) {
if (csi2->src_sd) {
ret = -EBUSY;
goto out;
}
/*
* csi2通过src_sd直接关联到mipi-csi-phy的subdev
*/
csi2->src_sd = remote_sd;
} else {
csi2->src_sd = NULL;
}
}
out:
mutex_unlock(&csi2->lock);
return ret;
}
最后链接情况如下
举报