因為有拍照、錄制視頻、直播等剛需,現(xiàn)在手機的攝像頭基本都是高清,支持高清攝像頭的SoC都支持MIPI-CSI。
不同SoC的MIPI-CSI在實現(xiàn)上有一定差別,即使同一廠家設計生產(chǎn)的芯片也都不盡相同。
本文基于瑞芯微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,這樣好收每年的技術支持費用,高通這損招是讓丫徹底學明白了。
由于官方給的手冊要么有錯誤,要么就是有些圖片錯誤,就不截圖了。
下圖是根據(jù)官方手冊說明,整理的內部模塊圖。
- Sensor輸出數(shù)據(jù)流通過MIPI的lanes傳輸給rk3568的DPHY控制器CSI控制器從硬件中提取出圖像數(shù)據(jù)VICAP從MIPI接口讀取數(shù)據(jù)然后將數(shù)據(jù)傳遞給給ISP ,ISP 再輸出經(jīng)過一系列圖像處理算法后得到圖像。MP用于預覽圖像SP用于縮放 VICAP
- Video Capture通過DVP/MIPI接口從攝像頭讀取數(shù)據(jù),并通過AXI總線將數(shù)據(jù)傳輸到主存中。
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?協(xié)議的數(shù)據(jù)(最多4個IDs)
支持接收?DSI?協(xié)議的數(shù)據(jù)(Video?mode/Command?mode)
支持窗口裁剪
支持virtual?stride?when?write?to?DDR
支持輸出NV16/NV12格式的YUV數(shù)據(jù)
支持compact/non-compact?output?for?RAW?data
支持MMU
- ISP(圖像信號處理)
ISP是一個完整的視頻和靜止圖像輸入設備。這個模塊支持集成YCbCr處理圖像傳感器和簡單CMOS傳感器 ,提交沒有任何綜合圖像處理Bayer RGB模式圖像。
rk3568采用的是ISP21版本。
ISP21 包含了一系列的圖像處理算法模塊,主要包括:暗電流矯正、壞點矯正、3A、HDR、鏡頭陰影矯正、鏡頭畸變矯正、3DLUT、去噪(包括RAW域去噪,多幀降噪,顏色去噪等)、銳化等。
ISP21包括硬件算法實現(xiàn)及軟件邏輯控制部分,RkAiq即為軟件邏輯控制部分的實現(xiàn)。
RkAiq不斷從ISP HW獲取統(tǒng)計數(shù)據(jù),并經(jīng)過3A等算法生成新的參數(shù)反饋給各硬件模塊。
RkAiq軟件模塊主要實現(xiàn)的功能為:從ISP驅動獲取圖像統(tǒng)計,結合IQ Tuning參數(shù),使用一系列算法計算出新的ISP、Sensor等硬件參數(shù),不斷迭代該過程,最終達到最優(yōu)的圖像效果。
3)CSI_RX、VICAP、ISP寄存器基地址
《Rockchip RK3568 TRM Part1 V1.1-20210301.pdf》
二、 瑞芯微MIPI-CSI設備樹分析
在rk3568中主要包含4個設備:
-
- isp-subdev:圖像處理控制器,如3a處理,并將處理后的所得的參數(shù)反饋給sensor。csi-subdev:mipi數(shù)據(jù)解析控制器。cis2-dphy:
-
- mipi數(shù)據(jù)硬件接收控制器。sensor:外接的sensor,支持mipi輸出。
下面我看下瑞芯微MIPI-CSI是如何用設備樹描述的。
1. 內核中相關MIPI設備樹說明文檔
瑞芯微MIPI-CSI設備樹節(jié)點屬性說明參考內核說明文檔:
[kernelDocumentationdevicetreebindingsmedia]
video-interfaces.txt?????????????關于sensor節(jié)點屬性的說明,接口類型,
rockchip-isp1.txt????????????????isp模塊屬性說明
rockchip-mipi-dphy.txt???????????dphy模塊的說明
kernelDocumentationdevicetreebindingsmediai2covxxxxxx.txt??ov系列的攝像設備樹說明
2. 設備樹節(jié)點說明
rk3568的MIPI-CSI用到的所有的設備樹節(jié)點:
a) rockchip,rkisp-vir
rkisp_vir0:?rkisp-vir0?{
????compatible?=?"rockchip,rkisp-vir";
????rockchip,hw?=?<&rkisp>;
????status?=?"disabled";
};????
該設備樹信息對應的初始化函數(shù)
[kerneldriversmediaplatformrockchipispdev.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,
};
該節(jié)點用于初始化isp相關的組件,
驅動程序會創(chuàng)建拓撲圖中的 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硬件相關的信息在父節(jié)點**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,觸發(fā)方式高電平觸發(fā)
????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>;
???};
};
該設備樹節(jié)點用于描述ISP硬件信息:基地址0xfdff0000 、中斷源、時鐘、reset引腳、iommus等。
驅動提取對應的硬件信息,填充到struct rkisp_hw_dev結構體變量中。
對應驅動入口:
[kerneldriversmediaplatformrockchipisphw.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協(xié)議相關設備樹
-
- 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>;
????????????};
????????};
????};
};
該節(jié)點描述內容:
-?父節(jié)點csi2_dphy0?
-?port@n??????????:?表示pad號為n
-?mipi_in_ucam0???:?Sink?Pad(in表示進入該entity,上游連接的設備由remote-endpoint給出,即攝像頭0v13850_out)
- data-lanes ?????: mipi通道數(shù)量: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 對應的驅動入口為:
[kerneldriversphyrockchipphy-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,
?},
};
在函數(shù)rockchip_csi2_dphy_hw_probe()中還會注冊結構體變量 rockchip_csi2_dphy_driver
630????platform_driver_register(&rockchip_csi2_dphy_driver);
rockchip_csi2_dphy_driver定義如下:
[kerneldriversphyrockchipphy-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,
?},
};
分析驅動就要從這些入口函數(shù)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?相關參數(shù)設置
???????│???????????????????├──?isp_stats_v21.c?3A?相關統(tǒng)計
???????│???????????????????├──?regs.c?寄存器相關的讀寫操作
???????│???????????????????└──??rkisp.c?對應?isp_sd?entity?節(jié)點,
???????│???????????????????????包含從?mipi?接收數(shù)據(jù),并有?crop?功能
???????├──?v4l2-core??v4l2核心代碼
???????└──?i2c/
????????????└──?ov13850.c?CIS(cmos?image?sensor)驅動
注:3568的isp版本是v21,只需要看v21結尾的文件
1. 字符設備號申請:videodev_init()
該函數(shù)主要用于申請設備號:
主設備號 :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()
該函數(shù)是最重要的一個初始化函數(shù),除了rkisp_csi2_dphy(entity67)外,其他的功能部件都在該函數(shù)中初始化。
注冊rkisp-vir0父設備、isp-dubdev子設備、csi2-dev子設備等,由于rk3568支持多路sensor輸入,即isp支持多路處理,因此會虛擬多通道isp-virx。
該函數(shù)主要工作:
-
-
- 給isp_dev申請內存并初始化,該結構體用于camera控制器所有的信息注冊v4l2_device結構體初始化media相關資源函數(shù)rkisp_register_platform_subdevs(),用于注冊拓撲結構中的各個模塊,對應的entity詳見圖entity1、7注冊為sub_device
-
- 初始化struct v4l2_subdev_ops、初始化media子模塊需要相關信息
-
- entity1還會設置默認的圖像格式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
其中對于研發(fā)人員最重要的就是這些回調函數(shù),應用層下發(fā)的各個命令最終都會通過架構調用到這些函數(shù)。
下面把重要的幾個模塊所注冊的回調函數(shù)做了個總結:
這些回調函數(shù)在架構中關系參考下圖:
其中entity67相關資源是在函數(shù)rockchip_csi2_dphy_probe()中注冊。
3. isp驅動初始化:rkisp_hw_probe()
該函數(shù)主要初始化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:?%dn",?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()
文中各種mipi技術文檔,后臺回復關鍵字:mipi
后面還會繼續(xù)更新幾篇Camera文章,
建議大家訂閱本專題!
也可以后臺留言,加一口君好友yikoupeng,
拉你進高質量技術交流群。
end