為有拍照、錄制視頻、直播等剛需,現在手機的攝像頭基本都是高清,支持高清攝像頭的SoC都支持MIPI-CSI。
不同SoC的MIPI-CSI在實現上有一定差別,即使同一廠家設計生產的芯片也都不盡相同。
本文基于瑞芯微rk3568平臺evb1公板為例來詳細講解MIPI-CSI/DPHY驅動。
閱讀本文之前,建議大家先仔細學習前面幾篇文章。
驅動的研究往往要先從硬件著手,下面我首先看下rk3568公板電路。
由電路圖可得攝像頭與SoC的MIPI-CSI接口,可以是x4lane,也可以是x2lane,data和clk都是差分信號。
如果不了解,建議問下硬件工程師。
控制攝像頭接口是I2C接口,并且位于I2C通道4下。
電路圖只能查看SoC的MIPI控制器與攝像頭的接口關系,下面我們來看下rk3568內部與mipi相關的模塊。
吐槽一下瑞芯微的文檔,一言難盡,我嚴重懷疑廠家壓根就不想讓其他人真正搞懂他們的SDK,這樣好收每年的技術支持費用,高通這損招是讓丫徹底學明白了。
由于官方給的手冊要么有錯誤,要么就是有些圖片錯誤,就不截圖了。
下圖是根據官方手冊說明,整理的內部模塊圖。
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是一個完整的視頻和靜止圖像輸入設備。這個模塊支持集成YCbCr處理圖像傳感器和簡單CMOS傳感器 ,提交沒有任何綜合圖像處理Bayer RGB模式圖像。
rk3568采用的是ISP21版本。
ISP21 包含了一系列的圖像處理算法模塊,主要包括:暗電流矯正、壞點矯正、3A、HDR、鏡頭陰影矯 正、鏡頭畸變矯正、3DLUT、去噪(包括RAW域去噪,多幀降噪,顏色去噪等)、銳化等。
ISP21包括硬件算法實現及軟件邏輯控制部分,RkAiq即為軟件邏輯控制部分的實現。
RkAiq不斷從ISP HW獲取統計數據,并經過3A等算法生成新的參數反饋給各硬件模塊。
RkAiq軟件模塊主要實現的功能為:從ISP驅動獲取圖像統計,結合IQ Tuning參數,使用一系列算法計 算出新的ISP、Sensor等硬件參數,不斷迭代該過程,最終達到最優的圖像效果。
《Rockchip RK3568 TRM Part1 V1.1-20210301.pdf》
在rk3568中主要包含4個設備:
下面我看下瑞芯微MIPI-CSI是如何用設備樹描述的。
瑞芯微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系列的攝像設備樹說明
rk3568的MIPI-CSI用到的所有的設備樹節點:
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>;**中描述。
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,
};
以下是描述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開始分析。
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結尾的文件
該函數主要用于申請設備號:
主設備號 :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);
}
注意 為簡化起見,所有代碼只把最重要的部分列舉出來,后同。
該函數是最重要的一個初始化函數,除了rkisp_csi2_dphy(entity67)外,其他的功能部件都在該函數中初始化。
注冊rkisp-vir0父設備、isp-dubdev子設備、csi2-dev子設備等,由于rk3568支持多路sensor輸入,即isp支持多路處理,因此會虛擬多通道isp-virx。
該函數主要工作:
中注冊。
該函數主要初始化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 }
著游戲直播、視頻會議與網課功能的普及應用,越來越多的人群開始對筆記本電腦的攝像頭功能有了使用需求。不過由于使用設備與使用習慣上的不同,不少筆記本電腦用戶可能會遇到攝像頭功能無法正常使用的困擾。
今天《搞機作戰室》將給大家匯總一下常見的幾種攝像頭功能問題與解決方案,希望能幫到遇到此類型的電腦用戶。
情況一、相機設備的權限未正常開啟,應用無權訪問相機功能
解決方式:檢查并開啟系統設置中相機訪問權限
設置路徑:Windows設置>>隱私>>相機
情況二:“相機”應用異常,軟件無法正常打開
解決方式:重置或卸載重裝“相機”應用
設置路徑:Windows設置>>應用>>應用與功能>>相機>>高級選項
情況三:筆記本電腦未識別到“相機”設備,提示驅動錯誤
解決方式:檢查并更新修復攝像頭設備驅動程序
設置路徑:右擊Windows菜單圖標>>設備管理器>>照相機>>右擊選項“更新驅動程序”
情況四:設備管理器中無法找到“照相機”驅動選項,相機功能無法使用
解決方式:部分筆記本的鍵盤帶來有禁用相機功能的多媒體按鍵,需要檢查并重新啟動相機功能。
設置路徑:查看筆記本鍵盤上是否帶有相機圖標的多媒體功能按鍵,如存在該按鍵,通過FN組合鍵重新啟動功能。(例如機械師T58-V可以通過FN+F10開啟或禁用攝像頭功能)
如以上四種解決方案都沒有效果,有一定的幾率是攝像頭配件出現異常損壞問題,建議通過重裝/重置windows官網原生系統映像的方式排除是否硬件損壞。
如重裝/重置系統后依舊無法正常恢復攝像頭功能,建議聯系品牌售后咨詢檢測維修服務。筆記本相機配件一般保修期為1年,可聯系品牌官方售后處理。
inux下視頻捕捉具體的linux調用
v4l2采集視頻步驟
具體的詳見文章:
linux下通過V4L2驅動USB攝像頭_v4l2_cap_video_capture_mplane_simonXi-tech的博客-CSDN博客