因为有拍照、录制视频、直播等刚需,现在手机的摄像头基本都是高清,支持高清摄像头的SoC都支持MIPI-CSI。

不同SoC的MIPI-CSI在实现上有一定差别,即使同一厂家设计生产的芯片也都不尽相同。

本文基于瑞芯微rk3568平台evb1公板为例来详细讲解MIPI-CSI/DPHY驱动。

阅读本文之前,建议大家先仔细学习前面几篇文章。

一、rk3568硬件模块部分

驱动的研究往往要先从硬件着手,下面我首先看下rk3568公板电路。

1)电路图

由电路图可得摄像头与SoC的MIPI-CSI接口,可以是x4lane,也可以是x2lane,data和clk都是差分信号。

如果不了解,建议问下硬件工程师。

控制摄像头接口是I2C接口,并且位于I2C通道4下。

2)rk3568内部MIPI相关模块图

电路图只能查看SoC的MIPI控制器与摄像头的接口关系,下面我们来看下rk3568内部与mipi相关的模块。

吐槽一下瑞芯微的文档,一言难尽,我严重怀疑厂家压根就不想让其他人真正搞懂他们的SDK,这样好收每年的技术支持费用,高通这损招是让丫彻底学明白了。

由于官方给的手册要么有错误,要么就是有些图片错误,就不截图了。

下图是根据官方手册说明,整理的内部模块图。

  1. Sensor输出数据流通过MIPI的lanes传输给rk3568的DPHY控制器
  2. CSI控制器从硬件中提取出图像数据
  3. VICAP从MIPI接口读取数据
  4. 然后将数据传递给给ISP ,ISP 再输出经过一系列图像处理算法后得到图像。
  5. MP用于预览图像
  6. SP用于缩放
  • VICAP

    Video Capture通过DVP/MIPI接口从摄像头读取数据,并通过AXI总线将数据传输到主存中。

VICAP特性:

支持 BT601 YCbCr 422 8bit  、 RAW 8/10/12bit 输入
支持 BT656 YCbCr 422 8bit 输入
支持 BT1120 YCbCr 422 8bit 输入 , 单/双边 取样
支持 2/4 mixed BT656/BT1120 YCbCr 422 8bit input
支持 YUYV 序列的配置
支持 the polarity of pixel_clk, hsync and vsync configurable
支持接收 CSI2 协议的数据(最多4个IDs)
支持接收 DSI 协议的数据(Video mode/Command mode)
支持窗口裁剪
支持virtual stride when write to DDR
支持输出NV16/NV12格式的YUV数据
支持compact/non-compact output for RAW data
支持MMU
  • ISP(图像信号处理)

ISP是一个完整的视频和静止图像输入设备。

这个模块支持集成YCbCr处理图像传感器和简单CMOS传感器 ,提交没有任何综合图像处理Bayer RGB模式图像。

rk3568采用的是ISP21版本。

ISP21 包含了一系列的图像处理算法模块,主要包括:暗电流矫正、坏点矫正、3A、HDR、镜头阴影矫

正、镜头畸变矫正、3DLUT、去噪(包括RAW域去噪,多帧降噪,颜色去噪等)、锐化
等。

ISP21包括硬件算法实现及软件逻辑控制部分,RkAiq即为软件逻辑控制部分的实现。

RkAiq不断从ISP HW获取统计数据,并经过3A等算法生成新的参数反馈给各硬件模块。

RkAiq软件模块主要实现的功能为:从ISP驱动获取图像统计,结合IQ Tuning参数,使用一系列算法计

算出新的ISP、Sensor等硬件参数,不断迭代该过程,最终达到最优的图像效果。

3)CSI_RX、VICAP、ISP寄存器基地址

《Rockchip RK3568 TRM Part1 V1.1-20210301.pdf》

二、 瑞芯微MIPI-CSI设备树分析

在rk3568中主要包含4个设备:

  • isp-subdev:

    图像处理控制器,如3a处理,并将处理后的所得的参数反馈给sensor。
  • csi-subdev:

    mipi数据解析控制器。
  • cis2-dphy:

    mipi数据硬件接收控制器。
  • sensor:

    外接的sensor,支持mipi输出。

下面我看下瑞芯微MIPI-CSI是如何用设备树描述的。

1. 内核中相关MIPI设备树说明文档

瑞芯微MIPI-CSI设备树节点属性说明参考内核说明文档:

[kernel\Documentation\devicetree\bindings\media]
video-interfaces.txt 关于sensor节点属性的说明,接口类型,
rockchip-isp1.txt isp模块属性说明
rockchip-mipi-dphy.txt dphy模块的说明
kernel\Documentation\devicetree\bindings\media\i2c\ovxxxxxx.txt ov系列的摄像设备树说明

2. 设备树节点说明

rk3568的MIPI-CSI用到的所有的设备树节点:

a) rockchip,rkisp-vir

rkisp_vir0: rkisp-vir0 {
compatible = "rockchip,rkisp-vir";
rockchip,hw = <&rkisp>;
status = "disabled";
};

该设备树信息对应的初始化函数

[kernel\drivers\media\platform\rockchip\isp\dev.c]
struct platform_driver rkisp_plat_drv = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(rkisp_plat_of_match),
.pm = &rkisp_plat_pm_ops,
},
.probe = rkisp_plat_probe,
.remove = rkisp_plat_remove,
};

该节点用于初始化isp相关的组件,

驱动程序会创建拓扑图中的 rkisp-isp-subdev、rkisp-csi-subdev、rkisp_mainpath、rkisp_selfpath、rkisp_rawwr0、rkisp_rawwr2、rkisp_rawwr3、rkisp_rawrd0_m、rkisp_rawrd2_s、rkisp-statistics、、rkisp-input-params 组件

isp硬件相关的信息在父节点rockchip,hw = <&rkisp>;中描述。

b) rkisp

rkisp: rkisp@fdff0000 {
compatible = "rockchip,rk3568-rkisp";
reg = <0x0 0xfdff0000 0x0 0x10000>;
interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; //中断使用的gpio,触发方式高电平触发
interrupt-names = "mipi_irq", "mi_irq", "isp_irq"; //中断名称
clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>, <&cru CLK_ISP>; //时钟
clock-names = "aclk_isp", "hclk_isp", "clk_isp"; //时钟名称
resets = <&cru SRST_ISP>, <&cru SRST_H_ISP>;
reset-names = "isp", "isp-h";
rockchip,grf = <&grf>;
power-domains = <&power RK3568_PD_VI>; //isp vicap电源和时钟
iommus = <&rkisp_mmu>; //mmu属性
rockchip,iq-feature = /bits/ 64 <0x3FBFFFE67FF>;
status = "disabled";
};
rkisp_mmu: iommu@fdff1a00 {
compatible = "rockchip,iommu-v2";
reg = <0x0 0xfdff1a00 0x0 0x100>;
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "isp_mmu";
clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>;
clock-names = "aclk", "iface";
power-domains = <&power RK3568_PD_VI>;
#iommu-cells = <0>;
rockchip,disable-mmu-reset;
status = "disabled";
};
pmu: power-management@fdd90000 {
pd_vi@RK3568_PD_VI {
reg = <RK3568_PD_VI>;
clocks = <&cru HCLK_VI>,
<&cru PCLK_VI>;
pm_qos = <&qos_isp>,
<&qos_vicap0>,
<&qos_vicap1>;
};
};

该设备树节点用于描述ISP硬件信息:

基地址0xfdff0000 、中断源、时钟、reset引脚、iommus等。

驱动提取对应的硬件信息,填充到struct rkisp_hw_dev结构体变量中。

对应驱动入口:

[kernel\drivers\media\platform\rockchip\isp\hw.c]
static struct platform_driver rkisp_hw_drv = {
.driver = {
.name = "rkisp_hw",
.of_match_table = of_match_ptr(rkisp_hw_of_match),
.pm = &rkisp_hw_pm_ops,
},
.probe = rkisp_hw_probe,
.remove = rkisp_hw_remove,
.shutdown = rkisp_hw_shutdown,
};

c) CSI2协议相关设备树

  • csi2_dphy0

    拓扑结构相关信息
  • csi2_dphy_hw

    csi2驱动相关硬件信息

以下是描述csi2_dphy0拓扑信息,实际摄像头信息需要用户自己填写:

[rk3568-evb1-ddr4-v10.dtsi]
&csi2_dphy0 {
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>;
remote-endpoint = <&0v13850_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>; csidphy_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&isp0_in>;
};
};
};
};

该节点描述内容:

- 父节点csi2_dphy0
- port@n : 表示pad号为n
- mipi_in_ucam0 : Sink Pad(in表示进入该entity,上游连接的设备由remote-endpoint给出,即摄像头0v13850_out)
- data-lanes : mipi通道数量:4
- csidphy_out : Source Pad,下游连接的设备由remote-endpoint给出,即isp0_in

以下是csi2_dphy控制器相关硬件信息,位于瑞芯微3568平台设备树文件rk3568.dtsi中

[rk3568.dtsi]
aliases {
csi2dphy0 = &csi2_dphy0;
……
}
csi2_dphy0: csi2-dphy0 {
compatible = "rockchip,rk3568-csi2-dphy";
rockchip,hw = <&csi2_dphy_hw>;
status = "disabled";
}; csi2_dphy_hw: csi2-dphy-hw@fe870000 {
compatible = "rockchip,rk3568-csi2-dphy-hw";
reg = <0x0 0xfe870000 0x0 0x1000>;
clocks = <&cru PCLK_MIPICSIPHY>;
clock-names = "pclk";
rockchip,grf = <&grf>;
status = "disabled";
};

csi2dphy0 对应的驱动入口为:

[kernel\drivers\phy\rockchip\phy-rockchip-csi2-dphy-hw.c]
static struct platform_driver rockchip_csi2_dphy_hw_driver = {
.probe = rockchip_csi2_dphy_hw_probe,
.remove = rockchip_csi2_dphy_hw_remove,
.driver = {
.name = "rockchip-csi2-dphy-hw",
.of_match_table = rockchip_csi2_dphy_hw_match_id,
},
};

在函数rockchip_csi2_dphy_hw_probe()中还会注册结构体变量 rockchip_csi2_dphy_driver

630    platform_driver_register(&rockchip_csi2_dphy_driver);

rockchip_csi2_dphy_driver定义如下:


[kernel\drivers\phy\rockchip\phy-rockchip-csi2-dphy-hw.c]
struct platform_driver rockchip_csi2_dphy_driver = {
.probe = rockchip_csi2_dphy_probe,
.remove = rockchip_csi2_dphy_remove,
.driver = {
.name = "rockchip-csi2-dphy",
.pm = &rockchip_csi2_dphy_pm_ops,
.of_match_table = rockchip_csi2_dphy_match_id,
},
};

分析驱动就要从这些入口函数probe开始分析。

三、驱动初始化

1. 驱动文件目录

kernel
├── arch/arm64/boot/dts/rockchip DTS 配置文件
├── drivers/phy/rockchip/
├── phy-rockchip-csi2-dphy.c
└── phy-rockchip-csi2-dphy-hw.c mipi dphy 驱动
├── drivers/media|
├── platform/rockchip/isp rkisp isp 驱动
│ ├── capture_v21.c 包含 mp/sp 的配置及 vb2,帧中断处理
│ ├── dev.c 包含 probe、异步注册、 clock、 pipeline、iommu 及
media/v4l2 framework
│ ├── isp_params_v21.c 3A 相关参数设置
│ ├── isp_stats_v21.c 3A 相关统计
│ ├── regs.c 寄存器相关的读写操作
│ └── rkisp.c 对应 isp_sd entity 节点,
│ 包含从 mipi 接收数据,并有 crop 功能
├── v4l2-core v4l2核心代码
└── i2c/
└── ov13850.c CIS(cmos image sensor)驱动

注:

3568的isp版本是v21,只需要看v21结尾的文件

1. 字符设备号申请:videodev_init()

该函数主要用于申请设备号:

主设备号 :81

设备名 :video4linux

申请class:video4linux

#define VIDEO_MAJOR	81
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux" static struct class video_class = {
.name = VIDEO_NAME,
.dev_groups = video_device_groups,
};
static int __init videodev_init(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
ret = class_register(&video_class);
}
static void __exit videodev_exit(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0); class_unregister(&video_class);
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
}

注意

为简化起见,所有代码只把最重要的部分列举出来,后同。

2. isp架构初始化:rkisp_plat_probe()

该函数是最重要的一个初始化函数,除了rkisp_csi2_dphy(entity67)外,其他的功能部件都在该函数中初始化。

注册rkisp-vir0父设备、isp-dubdev子设备、csi2-dev子设备等,由于rk3568支持多路sensor输入,即isp支持多路处理,因此会虚拟多通道isp-virx。

该函数主要工作:

  1. 给isp_dev申请内存并初始化,该结构体用于camera控制器所有的信息
  2. 注册v4l2_device结构体
  3. 初始化media相关资源
  4. 函数rkisp_register_platform_subdevs(),用于注册拓扑结构中的各个模块,对应的entity详见图
  5. entity1、7注册为sub_device

    初始化struct v4l2_subdev_ops、初始化media子模块需要相关信息

    entity1还会设置默认的图像格式
  6. entity13、19、25、31、37、43、49、55、61注册为video_device

    填充struct v4l2_file_operations(struct video_device->fops)、struct v4l2_ioctl_ops(struct video_device->ioctl_ops),struct vb2_ops(struct video_device->vb2_queue->ops)

![ ](https://img-blog.csdnimg.cn/796972bedb2046e89d3e3772fec31a9b.png

其中对于研发人员最重要的就是这些回调函数,应用层下发的各个命令最终都会通过架构调用到这些函数。

下面把重要的几个模块所注册的回调函数做了个总结:

这些回调函数在架构中关系参考下图:



其中entity67相关资源是在函数rockchip_csi2_dphy_probe()中注册。

3. isp驱动初始化:rkisp_hw_probe()

该函数主要初始化isp驱动

static const struct of_device_id rkisp_hw_of_match[] = {
……
{
.compatible = "rockchip,rk3568-rkisp",
.data = &rk3568_isp_match_data,
},
{},
}; 640 static int rkisp_hw_probe(struct platform_device *pdev)
641 {
646 struct rkisp_hw_dev *hw_dev;
……
/*匹配设备树compatible属性*/
651 match = of_match_node(rkisp_hw_of_match, node);
654 /*为hw_dev 分配内存*/
655 hw_dev = devm_kzalloc(dev, sizeof(*hw_dev), GFP_KERNEL);
659 dev_set_drvdata(dev, hw_dev);//dev->driver_data
660 hw_dev->dev = dev;
661 hw_dev->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
662 dev_info(dev, "is_thunderboot: %d\n", hw_dev->is_thunderboot);
663 hw_dev->max_in.w = 0;
664 hw_dev->max_in.h = 0;
665 hw_dev->max_in.fps = 0;
//获得grf句柄*/
669 hw_dev->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
672 /*获取控制器物理地址
673 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/*将物理地址映射为基地址*/
679 hw_dev->base_addr = devm_ioremap_resource(dev, res); 694 match_data = match->data;
695 hw_dev->mipi_irq = -1;
696
697 hw_dev->pdev = pdev;
698 hw_dev->match_data = match_data;
699 if (!hw_dev->is_thunderboot)
700 rkisp_register_irq(hw_dev); //注册中断
701 /*从设备树中提取时钟*/
702 for (i = 0; i < match_data->num_clks; i++) {
703 struct clk *clk = devm_clk_get(dev, match_data->clks[i]);
704
707 hw_dev->clks[i] = clk;
708 }
709 hw_dev->num_clks = match_data->num_clks;
710 hw_dev->clk_rate_tbl = match_data->clk_rate_tbl;
711 hw_dev->num_clk_rate_tbl = match_data->num_clk_rate_tbl;
712 /*提取reset属性*/
713 hw_dev->reset = devm_reset_control_array_get(dev, false, false);
718
719 ret = of_property_read_u64(node, "rockchip,iq-feature", &hw_dev->iq_feature);
720 if (!ret)
721 hw_dev->is_feature_on = true;
722 else
723 hw_dev->is_feature_on = false;
724 /*初始化其他的一些变量*/
725 hw_dev->dev_num = 0;
…………
743 hw_dev->is_shutdown = false;
744 hw_dev->is_mmu = is_iommu_enable(dev);
745 ret = of_reserved_mem_device_init(dev);
…………
770 }

4. mipi接口dphy驱动初始化:rockchip_csi2_dphy_probe()、rockchip_csi2_dphy_hw_probe()

学习更多嵌入式、Linux相关知识,后台留言加我好友!

Camera | 7.瑞芯微rk3568平台摄像头控制器MIPI-CSI驱动架构梳理的更多相关文章

  1. 瑞芯微RK3399宣布系统开源,进入百余种行业市场!

    集微网消息,2月24日瑞芯微官方突然宣布, Rockchip RK3399Linux系统开源!作为Rockchip旗舰级芯片,RK3399具有高性能.高扩展.全能型应用特性. 这一重磅消息立马刷爆朋友 ...

  2. Linux下更新瑞芯微固件

    有这样的需求,是因为提供的BSP中是在windows下烧写的系统.我直接在linux下开发,每次编译后代码都要在windows下烧写,是一个很麻烦的事情.为了解决这个问题我尝试着用VirtualBox ...

  3. 9.7寸RK3188瑞芯微四核爱立顺M33平板电脑 - 深圳吉祥星晨科技有限公司 - 华强商情网

    9.7寸RK3188瑞芯微四核爱立顺M33平板电脑 - 深圳吉祥星晨科技有限公司 - 华强商情网 欢迎加入 2000人超级QQ群,平板电脑行业交流群:221371451,平板电脑产品及报价群:5765 ...

  4. 瑞芯微发布最新旗舰应用处理器-RK3588

    在瑞芯微电子第四届“开发者之春”大会上,瑞芯微推出了新一代8nm旗舰处理器-RK3588 这个芯片将采用8nm 制程工艺.基于A76+A55 内核组合,具备4K UI性能.8K VPU,拥有NPU2. ...

  5. 瑞芯微ROCK960 RK3399固件烧录总结

    1 下载固件 进入瑞芯微ROCK960下载主页 https://www.96boards.org/documentation/consumer/rock/downloads/ 选择os固件, Debi ...

  6. 瑞芯微RK3399六核-迅为3399开发板介绍

    迅为3399开发板基于瑞芯微的RK3399处理器设计,Rockchip RK3399是瑞芯微推出的一款低功耗.高性能的应用处理器芯片,该芯片基于Big.Little架构,即具有独立的NEON协同处理器 ...

  7. 瑞芯微RK3188如何配置USB摄像头支持

  8. 瑞芯微RK3188摄像头相关参数的配置

  9. 瑞芯微RKnanC芯片处理器介绍

    RKnanC是一种低成本.低功耗.高效率的数字多媒体芯片,它是基于ARM的低功耗处理器结构和硬件加速器.它是专为便携式音频产品应用,如MP3播放器等. RKnanC可以支持各种音频标准的解码,如MP3 ...

  10. 瑞芯微ROCK960 RK3399烧录image后扩容rootfs

    问题描述: RK3399开发板烧录官网提供的ubuntu镜像: Ubuntu 16.04 Server arm64(下载地址:https://www.96boards.org/documentatio ...

随机推荐

  1. dotnet 融合 Avalonia 和 UNO 框架

    现在在 .NET 系列里面,势头比较猛的 UI 框架中,就包括了 Avalonia 和 UNO 框架.本文将告诉大家如何尝试在一个解决方案里面融合 Avalonia 和 UNO 两个框架,即在一个进程 ...

  2. 高通lk阶段mipi 代码解析以及新屏幕添加

    参考:https://www.cnblogs.com/linhaostudy/p/9237526.html 背景 前段时间做了这块的工作,但总结完以后领导说我的认识还是过于肤浅,因此重新再看了一下. ...

  3. 【论文阅读】ICML2020: Can Autonomous Vehicles Identify, Recover From, and Adapt to Distribution Shifts?

    Column: January 6, 2022 7:18 PM Last edited time: January 30, 2022 12:14 AM Sensor/组织: Oxford Status ...

  4. Vue 处理异步加载顺序问题:在Konva中确保文本在图片之上显示

    Vue 处理异步加载顺序问题:在Konva中确保文本在Konva之上显示 在使用Konva开发应用时,我们经常会遇到需要将文本绘制在图片之上的情况.一个常见的问题是,由于图像加载是异步的,文本有时会显 ...

  5. 解决方案 | Windows 验证账号出现 0x80190001错误解决

    一.问题描述 点击windows开始→账户→更改账户设置→验证,出现下面的错误. 二.解决方法 网上流行的是这个方法,https://blog.csdn.net/qq_36393978/article ...

  6. 统计里面PV 和 UV代表什么意思

    1.网站流量bai统计中"PV"它所代表的意思是访问量了,具体指的du就是网站zhi的页面点击量或是浏览量,亦或是页面的刷新量dao了,网站的页面每刷新一次,就统计一个" ...

  7. [oeasy]python0081_[趣味拓展]ESC键进化历史_键盘演化过程_ANSI_控制序列_转义序列_CSI

    光标位置 回忆上次内容 上次了解了 新的转义模式 \033 逃逸控制字符 escape 这个字符 让字符串 退出标准输出流 进行控制信息的设置 可以设置 光标输出的位置       ​   添加图片注 ...

  8. oeasy教您玩转vim - 38 - # 配合移动

    ​ 快速删除 回忆上节课内容 以前知道可以在插入状态下使用 del.退格 进行删除 现在知道了默认状态下使用通过 x 删除字符 可以在 x 前面使用[count]进行翻倍 如 10x 删除的字符存储在 ...

  9. vscode取消json文件注释下划线

    使用 vscode 打开一个json文件,如果有单行或多行注释,则会显示红色下划线,解决办法如下: 方法1 点击底部的JSON,选择 JSON with Comments 即可,然后红色下划线消失,底 ...

  10. C# 泛型单例工厂

    核心代码,线程安全 class SingletonFactory<T> where T : new() { private static T uniqueInstance; private ...