瑞芯微Rockchip开发者社区
直播中

LL-LING宁

8年用户 1279经验值
擅长:电源/新能源
私信 关注
[问答]

mipi csi与mipi csi phy部件之间如何连接?

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;
}
最后链接情况如下

举报

更多回帖

发帖
×
20
完善资料,
赚取积分