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

王银喜

7年用户 2419经验值
私信 关注
[问答]

新手求助怎样去编写mipi csi源码呢

新手求助怎样去编写mipi csi源码呢?

回帖(1)

张楠

2022-2-21 09:17:32
mipi csi源码
dts代码如下



csi_dphy0: csi-dphy@ff4b0000 {
    compatible = "rockchip,rv1126-csi-dphy";
    ...   
    status = "okay";
    ...
    ports {
        #address-cells = <1>;
        #size-cells = <0>;
        port@0 {
            reg = <0>;
            #address-cells = <1>;
            #size-cells = <0>;

            mipi_in_ucam0: endpoint@1 {
                 reg = <1>;
                 /* imx291 */
                 remote-endpoint = <&ucam_out2>;
                 data-lanes = <1 2 3 4>;
            };
        };
        port@1 {
            reg = <1>;
            #address-cells = <1>;
            #size-cells = <0>;

            csidphy0_out: endpoint@0 {
                  reg = <0>;
                  remote-endpoint = <&mipi_csi2_input>;
            };
        };
    };
};


其实这里可以看出来和imx291直接的联系,imx291注册中dts有这样一句话 remote-endpoint = <&mipi_in_ucam0>;


代码中对remote-enpoint的解析后面也会分析,所以这里也可以知道下一遍文章要分析的subdev是有mipi_csi2_input的port的节点


开始驱动分析


struct mipidphy_priv {
        struct device *dev;
        ...
        struct v4l2_async_notifier notifier;
        struct v4l2_subdev sd;
        ...
        struct mipidphy_sensor sensors[MAX_DPHY_SENSORS];
        int num_sensors;
        ...
        bool is_streaming;
        ...
        int (*stream_on)(struct mipidphy_priv *priv, struct v4l2_subdev *sd);
        int (*stream_off)(struct mipidphy_priv *priv, struct v4l2_subdev *sd);
};


static int rockchip_mipidphy_probe(struct platform_device *pdev)
{
        struct device *dev = &pdev->dev;
        struct v4l2_subdev *sd;
        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;
        ...

        priv->stream_on = csi_mipidphy_stream_on;
        priv->stream_off = csi_mipidphy_stream_off;
        ...

        sd = &priv->sd;


        /*
         * 同样的
         * sd->ops = &mipidphy_subdev_ops;
         * sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
         * sd->v4l2_dev = NULL
         */

        v4l2_subdev_init(sd, &mipidphy_subdev_ops);
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
        snprintf(sd->name, sizeof(sd->name), "rockchip-mipi-dphy-rx");
        sd->dev = dev;

        platform_set_drvdata(pdev, &sd->entity);

        ret = rockchip_mipidphy_media_init(priv);
        if (ret < 0)
                goto destroy_mutex;

        return 0;
        ...
}

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

        /*
         * 下面这几行代码,个人认为加个CONFIG_MEDIA_CONTROLLER控制比较好
         * 同样是media,暂时忽略
         */
//#if defined(CONFIG_MEDIA_CONTROLLER)+++++++++++++++++++++++++++++++++++++
        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;
        ret = media_entity_pads_init(&priv->sd.entity,
                                MIPI_DPHY_RX_PADS_NUM, priv->pads);
        if (ret < 0)
                return ret;
//#endif -----------------------------------------------------------------


        /*
         * 对于v4l2_async_notifier_parse_fwnode_endpoints_by_port
         * 看专题分析
         *
         * 回调函数rockchip_mipidphy_fwnode_parse
         * 这里也不再分析,太细节和v4l2关系不大
         */


        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;

        if (!priv->notifier.num_subdevs)
                return -ENODEV;        /* no endpoint */

        priv->sd.subdev_notifier = &priv->notifier;

        /* 注意notifier的ops不为NULL*/

        priv->notifier.ops = &rockchip_mipidphy_async_ops;


        /*
         * 具体的看v4l2_async_subdev_notifier_register 分析
         *
         * 这个执行后 mipi csi pht的notifier->wait上会挂载asd
         * 这个asd就是notifier->subdevs[0]
         * 也就是imx291在dts中的节点
         * 最后将mipi csi pht的notifier挂载到notifier_list上
         */

        ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier);
        if (ret) {
                dev_err(priv->dev,
                        "failed to register async notifier : %dn", ret);
                v4l2_async_notifier_cleanup(&priv->notifier);
                return ret;
        }

        /*
         * 这里会有v4l2_dev = NULL不执行
         * 只是将subdev挂载到subdev_list
         */

        return v4l2_async_register_subdev(&priv->sd);
}



这样mipi-csi-phy就注册完了


结合之前的imx291注册


可以知道


notifier_list上有2个notifier,分别是imx291的和mipi-csi-phy的
subdev_list上有2个subdev,分别是imx291的和mipi-csi-phy的
其中mipi-csi-phy的notifier->subdevs[0]中记录了imx291 dts节点的信息


这样就关联起来了


imx291 --> mipi csi phy
举报

更多回帖

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