動(dòng)代碼解析:從sensor出圖到/dev/video節(jié)點(diǎn))
簡介這份資源是瑞芯微RK平臺(tái)ISP子系統(tǒng)的Linux內(nèi)核驅(qū)動(dòng)源碼面向從事嵌入式Linux、攝像頭圖像處理與V4L2框架開發(fā)的工程師及驅(qū)動(dòng)學(xué)習(xí)者。代碼圍繞設(shè)備樹匹配機(jī)制展開從of_device_id的匹配方式入手完整呈現(xiàn)了CIF與ISP模塊的驅(qū)動(dòng)實(shí)現(xiàn)適合用于理解RK平臺(tái)圖像采集鏈路的注冊(cè)流程、平臺(tái)設(shè)備與V4L2子設(shè)備的對(duì)接方式。壓縮包共17個(gè)文件包含8個(gè).h頭文件、7個(gè).c源文件以及Makefile和Kconfig各1個(gè)頭文件定義寄存器、圖像源與平臺(tái)接口源文件實(shí)現(xiàn)V4L2設(shè)備、ISP控制與圖像源操作Kconfig與Makefile則負(fù)責(zé)內(nèi)核編譯配置整體約96KB結(jié)構(gòu)緊湊便于逐文件研讀。目前已有1750人學(xué)習(xí)下載可作為RK ISP驅(qū)動(dòng)移植、調(diào)試與二次開發(fā)的參考素材幫助讀者快速定位關(guān)鍵數(shù)據(jù)結(jié)構(gòu)與驅(qū)動(dòng)入口。1. rkisp 驅(qū)動(dòng)代碼到底能拿來干什么從 sensor 出圖到 /dev/video 節(jié)點(diǎn)如果你手上有塊 RK3588 或 RK3568 的板子接了個(gè) MIPI sensordmesg里能看到rkisp字樣但/dev/video*死活不出圖或者出了圖顏色發(fā)綠、幀率對(duì)不上——那你需要的不是再翻一遍《Rockchip ISP 開發(fā)指南》而是把 rkisp 的驅(qū)動(dòng)代碼拉下來從probe一路讀到streamon。rkisp 是 Rockchip 平臺(tái) ISP 硬件模塊的 Linux 內(nèi)核驅(qū)動(dòng)位于內(nèi)核源碼drivers/media/platform/rockchip/isp/目錄下負(fù)責(zé) sensor 數(shù)據(jù)接入、ISP pipeline 配置、DMA 輸出到內(nèi)存最終暴露成 V4L2 的 video 節(jié)點(diǎn)。它解決的是「sensor 有數(shù)據(jù)、ISP 有硬件、但用戶態(tài)拿不到幀」這條鏈路上的所有粘合問題。適合誰做 RK 平臺(tái)相機(jī) bring-up 的 BSP 工程師、調(diào) ISP tuning 時(shí)想搞清楚參數(shù)從哪進(jìn)內(nèi)核的算法工程師以及被rkisp日志繞暈、想直接讀源碼定位問題的驅(qū)動(dòng)開發(fā)者。這份代碼不是獨(dú)立倉庫而是內(nèi)核樹的一部分所以「下載」的本質(zhì)是拿到對(duì)應(yīng)內(nèi)核版本、確認(rèn) rkisp 目錄完整、能編譯進(jìn) Image。2. rkisp 驅(qū)動(dòng)代碼的目錄結(jié)構(gòu)與核心數(shù)據(jù)流先看懂再動(dòng)手2.1 代碼從哪來、放在哪、依賴什么rkisp 驅(qū)動(dòng)不在獨(dú)立 Git 倉庫里它隨 Rockchip 官方內(nèi)核發(fā)布。常見做法是從 Rockchip 的 kernel 倉庫拉對(duì)應(yīng)分支比如develop-5.10或develop-6.1然后確認(rèn)drivers/media/platform/rockchip/isp/存在。這個(gè)目錄下通常有這些文件文件作用dev.c設(shè)備 probe、時(shí)鐘/復(fù)位/中斷申請(qǐng)、media device 注冊(cè)capture.cvideo 節(jié)點(diǎn)注冊(cè)、vb2 隊(duì)列、DMA buffer 管理rkisp.cISP 硬件抽象層寄存器讀寫、pipeline 使能hw.cISP 各模塊DPCC、BLC、LSC、AWB、CCM 等寄存器配置params.c3A 參數(shù)從用戶態(tài)到內(nèi)核的傳遞通道stats.c統(tǒng)計(jì)信息回傳tuning 工具依賴csi.cMIPI CSI-2 接收端配置bridge.cISP 與 sensor 之間的 media bus 連接依賴的內(nèi)核配置項(xiàng)一般是CONFIG_VIDEO_ROCKCHIP_ISP它又依賴CONFIG_MEDIA_SUPPORT、CONFIG_V4L2_SUBDEV_API、CONFIG_VIDEOBUF2_DMA_CONTIG等。如果你在menuconfig里找不到這個(gè)選項(xiàng)先確認(rèn)內(nèi)核版本和 Rockchip 補(bǔ)丁是否打全。2.2 一條幀從 sensor 到用戶態(tài)要過幾道手理解 rkisp 驅(qū)動(dòng)關(guān)鍵是理解 media pipeline。典型鏈路是sensor subdev → csi2 subdev → rkisp subdev → rkisp capture video nodesensor 通過 I2C 配置輸出 MIPI CSI-2 數(shù)據(jù)csi2 接收后交給 rkisprkisp 內(nèi)部做 ISP 處理然后通過 DMA 寫到內(nèi)存capture 節(jié)點(diǎn)用 vb2 管理 buffer用戶態(tài)VIDIOC_DQBUF拿到幀。驅(qū)動(dòng)代碼里dev.c的rkisp_probe會(huì)做幾件事申請(qǐng)rkisp的寄存器基地址、使能aclk/hclk/sclk等時(shí)鐘、復(fù)位 ISP、申請(qǐng)中斷、調(diào)用rkisp_register_platform_subdevs注冊(cè)子設(shè)備、最后rkisp_create_media_dev建立 media graph。如果 probe 失敗dmesg里通常能看到failed to get xxx clock或failed to request irq這就是你排查的起點(diǎn)。2.3 編譯進(jìn)內(nèi)核并確認(rèn)節(jié)點(diǎn)出現(xiàn)假設(shè)你已經(jīng)拿到 Rockchip 內(nèi)核源碼交叉編譯工具鏈就緒操作步驟如下。第一步確認(rèn)配置# 進(jìn)入內(nèi)核源碼目錄 cd ~/rk3588/kernel # 檢查 rkisp 配置是否開啟 grep -E ROCKCHIP_ISP|VIDEO_ROCKCHIP .config如果輸出里沒有CONFIG_VIDEO_ROCKCHIP_ISPy或m需要手動(dòng)開make ARCHarm64 menuconfig # 路徑Device Drivers → Multimedia support → Rockchip ISP # 選中 Rockchip ISP1 Driver第二步編譯make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc) Image make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- dtbs第三步燒錄后確認(rèn)驅(qū)動(dòng)加載# 查看內(nèi)核日志里 rkisp 的 probe 信息 dmesg | grep -i rkisp # 查看 media 設(shè)備 ls /dev/media* # 用 media-ctl 打印 pipeline media-ctl -d /dev/media0 -pmedia-ctl -p的輸出會(huì)列出所有 entity 和 pad 連接。如果 sensor、csi2、rkisp 都在且 link 是ENABLED說明驅(qū)動(dòng)層 pipeline 已經(jīng)通了。如果某個(gè) entity 缺失回到dts里檢查對(duì)應(yīng)節(jié)點(diǎn)是否status okay。提示不同內(nèi)核版本 rkisp 目錄名可能略有差異5.10 常見為isp/6.1 可能拆成isp1/和isp2/以實(shí)際源碼為準(zhǔn)。3. 把 rkisp 跑起來dts 配置、media pipeline 與出圖驗(yàn)證3.1 dts 里 rkisp 節(jié)點(diǎn)怎么寫才不翻車rkisp 驅(qū)動(dòng)能不能 probe七成看 dts。以 RK3588 為例rkisp節(jié)點(diǎn)通常在arch/arm64/boot/dts/rockchip/rk3588s.dtsi里定義板級(jí) dts 里要覆蓋status和ports。關(guān)鍵點(diǎn)rkisp0 { status okay; }; mipi_dcphy0 { status okay; }; csi2_dcphy0 { status okay; ports { #address-cells 1; #size-cells 0; port0 { reg 0; #address-cells 1; #size-cells 0; csi_dcphy0_in: endpoint0 { reg 0; remote-endpoint sensor_out; >media-ctl -d /dev/media0 -p | grep -i sensor假設(shè)輸出里 sensor entity 是m00_b_ov13850 1-0036接下來設(shè)置格式# 設(shè)置 sensor 輸出格式 media-ctl -d /dev/media0 \ --set-v4l2 m00_b_ov13850 1-0036:0[fmt:SBGGR10_1X10/2112x1568] # 設(shè)置 rkisp 輸入格式 media-ctl -d /dev/media0 \ --set-v4l2 rkisp-isp-subdev:0[fmt:SBGGR10_1X10/2112x1568] # 設(shè)置 rkisp 輸出格式 media-ctl -d /dev/media0 \ --set-v4l2 rkisp-isp-subdev:2[fmt:YUYV8_2X8/2112x1568]第二步找到 capture video 節(jié)點(diǎn)ls /dev/video* v4l2-ctl --list-devices通常 rkisp 會(huì)注冊(cè)多個(gè) video 節(jié)點(diǎn)比如rkisp_mainpath、rkisp_selfpath。選 mainpath 對(duì)應(yīng)的節(jié)點(diǎn)比如/dev/video0。第三步抓幀# 設(shè)置格式 v4l2-ctl -d /dev/video0 \ --set-fmt-videowidth2112,height1568,pixelformatYUYV # 抓 10 幀存成文件 v4l2-ctl -d /dev/video0 \ --stream-mmap4 \ --stream-count10 \ --stream-toframe.raw如果frame.raw大小等于2112*1568*2*10說明幀確實(shí)出來了。用ffmpeg或raw2rgb轉(zhuǎn)一下就能看圖像。如果stream-to卡住不動(dòng)先看dmesg有沒有rkisp的 timeout 或vb2報(bào)錯(cuò)。3.3 參數(shù)怎么改分辨率、格式與 buffer 數(shù)量rkisp 驅(qū)動(dòng)里分辨率不是隨便設(shè)的它受 sensor 輸出能力和 ISP 內(nèi)部限制約束。常見做法是sensor 端設(shè)一個(gè)它支持的模式比如2112x156830fpsrkisp 輸入 pad 格式必須和 sensor 輸出一致rkisp 輸出 pad 可以縮放但縮放比例有限制一般不超過 8 倍。buffer 數(shù)量通過--stream-mmap4指定4 表示 4 個(gè) buffer 輪轉(zhuǎn)。太少會(huì)丟幀太多占內(nèi)存。調(diào)試階段用 4 比較穩(wěn)。如果你要改驅(qū)動(dòng)里的默認(rèn)行為比如默認(rèn)輸出格式可以看capture.c里rkisp_video_set_fmt函數(shù)它決定了用戶態(tài)沒設(shè)格式時(shí)用什么。但一般不建議改驅(qū)動(dòng)默認(rèn)值優(yōu)先在用戶態(tài)用v4l2-ctl或應(yīng)用層設(shè)置。注意media-ctl設(shè)置格式時(shí)sensor 的 format code 必須和驅(qū)動(dòng)里sensor-fmt.code匹配寫錯(cuò)會(huì)返回Invalid argument。4. rkisp 驅(qū)動(dòng)調(diào)試避坑五個(gè)血淚現(xiàn)場4.1 probe 失敗dmesg 只報(bào) clock 錯(cuò)誤現(xiàn)象dmesg | grep rkisp顯示failed to get aclk或failed to get hclk。原因dts 里 rkisp 節(jié)點(diǎn)的clocks和clock-names不匹配或者時(shí)鐘控制器節(jié)點(diǎn)沒使能。解決對(duì)照rk3588s.dtsi里 rkisp 的clocks定義確認(rèn)板級(jí) dts 沒有覆蓋錯(cuò)。常見的是clock-names里少了sclk或者assigned-clocks沒配。4.2 media pipeline 建不起來entity 缺失現(xiàn)象media-ctl -p只看到 rkisp看不到 sensor 或 csi2。原因sensor 驅(qū)動(dòng)沒 probe或者 csi2 節(jié)點(diǎn)status不是okay或者remote-endpoint寫錯(cuò)。解決先dmesg | grep -i sensor確認(rèn) sensor 是否 probe再檢查 csi2 的ports里 endpoint 是否和 sensor 的 endpoint 成對(duì)最后確認(rèn)># 找到 stats 節(jié)點(diǎn) v4l2-ctl --list-devices | grep -A2 rkisp # 假設(shè) stats 節(jié)點(diǎn)是 /dev/video1 v4l2-ctl -d /dev/video1 --stream-mmap1 --stream-count1 --stream-tostats.binstats.bin里就是 ISP 硬件統(tǒng)計(jì)結(jié)果格式由rkisp_stat結(jié)構(gòu)體定義在stats.c里能看到具體字段。如果你要自己解析可以對(duì)照include/uapi/linux/rkisp1-config.h里的定義。另一個(gè)進(jìn)階技巧是直接讀寄存器。rkisp 的寄存器基地址在 dts 里probe 后可以通過devm_ioremap映射。調(diào)試時(shí)可以在hw.c里加dev_dbg打印關(guān)鍵寄存器值比如RKISP_ISP_CTRL、RKISP_ISP_INT_EN確認(rèn) pipeline 是否真的使能。但注意改驅(qū)動(dòng)加打印要重新編譯內(nèi)核比較耗時(shí)優(yōu)先用devmem在用戶態(tài)讀# 假設(shè) rkisp 寄存器基地址是 0xfdcc0000 devmem 0xfdcc0000 32不過devmem讀之前要確認(rèn)時(shí)鐘已使能否則讀出來全是 0 或總線報(bào)錯(cuò)。我自己的習(xí)慣是每次改完 dts 或驅(qū)動(dòng)先dmesg | grep -i rkisp看 probe 有沒有報(bào)錯(cuò)再用media-ctl -p確認(rèn) pipeline最后v4l2-ctl --stream-mmap抓一幀。這三步走完基本能定位八成問題。從那以后我每次 bring-up 新板子都強(qiáng)制走一遍這個(gè)流程省得后面調(diào)圖像時(shí)才發(fā)現(xiàn)底層就沒通。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取