Serdes(串行器/解串器)目前在车载摄像头上广泛应用,关于Serdes的具体解释在网上查到很多,不进行详述。
在我做的这个方案中,2路模组(thcv241+imx307,thcv241将imx307的mipi信号转换为串行信号)通过同轴线缆输入到thcv244;thcv244将串行信号解除串转换为mipi信号输出,thcv244支持mipi vc(虚拟通道)技术,最多能够支持4路模组转换;thcv244与rk3568通过2lane mipi连接。
一、thcv244驱动
第一次接触Serdes方案,有点懵,首先在于,thcv241和imx307肯定是需要进行参数配置的,而且imx307是i2c接口配置,但是imx307的i2c没有引到rk3568上面来,引到rk3568的只有thcv244的i2c,这咋弄呢?后面请教thcv244的厂家技术支持,原来是采用了一种i2c透传技术。
正常情况下,一个i2c设备只有一个设备地址(尽管可以配置,但必须要固定),但是支持i2c透传的i2c设备可以响应非自身设备地址的数据。当向thcv244特定寄存器写入需要透传的目标设备的设备地址后,它就可以响应i2c上给这个目标设备地址的消息,以此来进行配置imx307、thcv241。对于SOC,相当于在i2c总线上挂上了imx307、thcv241两个设备。
参考sdk中,gc2053(Sensor类驱动)或者nvp6188(转换芯片类驱动),编写thcv244驱动。因为rk3568使用的v4l2驱动框架,驱动写好后,可以直接使用v4l2-ctl工具进行测试。
主要是确保初始化寄存器参数的正确性,link_freq(mipi clock)、bus_fmt图像数据格式、bpp像素点数据位数、分辨率等。
其中,link_freq很容易弄混,是指的单lane上mipi的传输速度。比如imx307传输1920x1080@60fps传输速度是891Mbps,2lane传输时,link_freq应该设置为445.5M。
二、dts配置,vicap/isp
1、配置数据链路通道为vicap
1)dts配置如下
data-lanes需要看硬件上mipi lane接口使用。rk3568 mipi有4lane,可以分开1、2,3、4使用。我们硬件上使用的1、2两lane,因此设置data-lanes=<1 2>;
&csi2_dphy_hw {
status = "okay";
};&i2c2 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
clock-frequency = <100000>;thcv244: thcv244@b {
compatible = "thine,thcv244";
status = "okay";
reg = <0xb>;
//clocks = <&cru PCLK_MIPICSIPHY>;
//clock-names = "pclk";
//power-domains = <&power RK3568_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&thcv244_dphy_pwdn>;//, <&thcv244_dphy_errb>, <&thcv244_dphy_lock>;
//rockchip,grf = <&grf>;
//power-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;
// reset = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "thcv244";
rockchip,camera-module-lens-name = "thcv244";port {
thcv244_out: endpoint {
remote-endpoint = <&mipi_in_thcv244_rgb>;
data-lanes = <1 2>;
};
};
};
};&csi2_dphy1 {
status = "okay";ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_thcv244_rgb: endpoint@0 {
reg = <0>;
remote-endpoint = <&thcv244_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;csidphy1_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_csi2_input>;
};
};
};
};&mipi_csi2 {
status = "okay";ports {
#address-cells = <1>;
#size-cells = <0>;port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;mipi_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy1_out>;
data-lanes = <1 2>;
};
};port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;mipi_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in>;
data-lanes = <1 2>;
};
};
};
};&rkcif {
status = "okay";
};&rkcif_mmu {
status = "okay";
};&rkcif_mipi_lvds {
status = "okay";port {
cif_mipi_in: endpoint {
remote-endpoint = <&mipi_csi2_output>;
data-lanes = <1 2>;
};
};
};
2)media-ctl验证是否注册成功
启动系统后,执行media-ctl -p -d /dev/media0,如果有多个摄像头,可能并非是media0。
root@rk3568-buildroot:/# media-ctl -p -d /dev/media0
Media controller API version 5.10.160Media device information
------------------------
driver rkcif
model rkcif_mipi_lvds
serial
bus info
hw revision 0x0
driver version 5.10.160Device topology
- entity 1: stream_cif_mipi_id0 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video0
pad0: Sink
<- "rockchip-mipi-csi2":1 [ENABLED]
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 []- entity 5: stream_cif_mipi_id1 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video1
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 [ENABLED]
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 []- entity 9: stream_cif_mipi_id2 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video2
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 [ENABLED]
<- "rockchip-mipi-csi2":4 []- entity 13: stream_cif_mipi_id3 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video3
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 [ENABLED]- entity 17: rkcif_tools_id0 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video4
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 []- entity 21: rkcif_tools_id1 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video5
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 []- entity 25: rkcif_tools_id2 (1 pad, 4 links)
type Node subtype V4L flags 0
device node name /dev/video6
pad0: Sink
<- "rockchip-mipi-csi2":1 []
<- "rockchip-mipi-csi2":2 []
<- "rockchip-mipi-csi2":3 []
<- "rockchip-mipi-csi2":4 []- entity 29: rkcif-mipi-luma (0 pad, 0 link)
type Node subtype V4L flags 0
device node name /dev/video7- entity 32: rockchip-mipi-csi2 (5 pads, 29 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[fmt:SRGGB12_1X12/1920x1080 field:none
crop.bounds:(0,0)/1920x1080
crop:(0,0)/1920x1080]
<- "rockchip-csi2-dphy1":1 [ENABLED]
pad1: Source
-> "stream_cif_mipi_id0":0 [ENABLED]
-> "stream_cif_mipi_id1":0 []
-> "stream_cif_mipi_id2":0 []
-> "stream_cif_mipi_id3":0 []
-> "rkcif_tools_id0":0 []
-> "rkcif_tools_id1":0 []
-> "rkcif_tools_id2":0 []
pad2: Source
-> "stream_cif_mipi_id0":0 []
-> "stream_cif_mipi_id1":0 [ENABLED]
-> "stream_cif_mipi_id2":0 []
-> "stream_cif_mipi_id3":0 []
-> "rkcif_tools_id0":0 []
-> "rkcif_tools_id1":0 []
-> "rkcif_tools_id2":0 []
pad3: Source
-> "stream_cif_mipi_id0":0 []
-> "stream_cif_mipi_id1":0 []
-> "stream_cif_mipi_id2":0 [ENABLED]
-> "stream_cif_mipi_id3":0 []
-> "rkcif_tools_id0":0 []
-> "rkcif_tools_id1":0 []
-> "rkcif_tools_id2":0 []
pad4: Source
-> "stream_cif_mipi_id0":0 []
-> "stream_cif_mipi_id1":0 []
-> "stream_cif_mipi_id2":0 []
-> "stream_cif_mipi_id3":0 [ENABLED]
-> "rkcif_tools_id0":0 []
-> "rkcif_tools_id1":0 []
-> "rkcif_tools_id2":0 []- entity 38: rockchip-csi2-dphy1 (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[fmt:SRGGB12_1X12/1920x1080@10000/300000 field:none
crop.bounds:(0,0)/1920x1080]
<- "m00_b_thcv244 2-000b":0 [ENABLED]
pad1: Source
-> "rockchip-mipi-csi2":0 [ENABLED]- entity 43: m00_b_thcv244 2-000b (1 pad, 1 link)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev2
pad0: Source
[fmt:SRGGB12_1X12/1920x1080@10000/300000 field:none
crop.bounds:(0,0)/1920x1080]
-> "rockchip-csi2-dphy1":0 [ENABLED]
2、配置数据链路通道为isp
1)dts配置如下
&csi2_dphy_hw {
status = "okay";
};&csi2_dphy1 {
status = "okay";ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_thcv244_rgb: endpoint@1 {
reg = <1>;
remote-endpoint = <&thcv244_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;csidphy1_out: endpoint@1 {
reg = <1>;
remote-endpoint = <&isp_in1>;
};
};
};
};&i2c2 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
clock-frequency = <100000>;thcv244: thcv244@b {
compatible = "thine,thcv244";
status = "okay";
reg = <0xb>;
//clocks = <&cru PCLK_MIPICSIPHY>;
//clock-names = "pclk";
//power-domains = <&power RK3568_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&thcv244_dphy_pwdn>;//, <&thcv244_dphy_errb>, <&thcv244_dphy_lock>;
//rockchip,grf = <&grf>;
//power-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;
// reset = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "thcv244";
rockchip,camera-module-lens-name = "thcv244";port {
thcv244_out: endpoint {
remote-endpoint = <&mipi_in_thcv244_rgb>;
data-lanes = <1 2>;
};
};
};
};&rkisp {
status = "okay";
max-input = <1948 1097 60>;
};&rkisp_mmu {
status = "okay";
};&rkisp_vir0 {
status = "okay";
/* thcv244-rgb->dphy1->isp_vir0 */
port {
#address-cells = <1>;
#size-cells = <0>;isp_in1: endpoint@0 {
reg = <0>;
remote-endpoint = <&csidphy1_out>;
};
};
};
2)media-ctl验证是否注册成功
启动系统后,执行media-ctl -p -d /dev/media0,如果有多个摄像头,可能并非是media0。
root@rk3568-buildroot:~# media-ctl -p -d /dev/media0
Media controller API version 5.10.160Media device information
------------------------
driver rkisp-vir0
model rkisp0
serial
bus info
hw revision 0x0
driver version 5.10.160Device topology
- entity 1: rkisp-isp-subdev (4 pads, 8 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[fmt:SRGGB12_1X12/1948x1097 field:none
crop.bounds:(0,0)/1948x1097
crop:(0,0)/1948x1097]
<- "rkisp-csi-subdev":1 [ENABLED]
<- "rkisp_rawrd0_m":0 []
<- "rkisp_rawrd2_s":0 []
pad1: Sink
<- "rkisp-input-params":0 [ENABLED]
pad2: Source
[fmt:YUYV8_2X8/1948x1097 field:none colorspace:smpte170m quantization:full-range
crop.bounds:(0,0)/1948x1097
crop:(0,0)/1948x1097]
-> "rkisp_mainpath":0 [ENABLED]
-> "rkisp_selfpath":0 [ENABLED]
-> "rkisp_iqtool":0 [ENABLED]
pad3: Source
-> "rkisp-statistics":0 [ENABLED]- entity 6: rkisp-csi-subdev (6 pads, 5 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[fmt:SRGGB12_1X12/1948x1097 field:none]
<- "rockchip-csi2-dphy1":1 [ENABLED]
pad1: Source
[fmt:SRGGB12_1X12/1948x1097 field:none]
-> "rkisp-isp-subdev":0 [ENABLED]
pad2: Source
-> "rkisp_rawwr0":0 [ENABLED]
pad3: Source
pad4: Source
-> "rkisp_rawwr2":0 [ENABLED]
pad5: Source
-> "rkisp_rawwr3":0 [ENABLED]- entity 13: rkisp_mainpath (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video0
pad0: Sink
<- "rkisp-isp-subdev":2 [ENABLED]- entity 19: rkisp_selfpath (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video1
pad0: Sink
<- "rkisp-isp-subdev":2 [ENABLED]- entity 25: rkisp_rawwr0 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video2
pad0: Sink
<- "rkisp-csi-subdev":2 [ENABLED]- entity 31: rkisp_rawwr2 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video3
pad0: Sink
<- "rkisp-csi-subdev":4 [ENABLED]- entity 37: rkisp_rawwr3 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video4
pad0: Sink
<- "rkisp-csi-subdev":5 [ENABLED]- entity 43: rkisp_iqtool (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video5
pad0: Sink
<- "rkisp-isp-subdev":2 [ENABLED]- entity 49: rkisp_rawrd0_m (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video6
pad0: Source
-> "rkisp-isp-subdev":0 []- entity 55: rkisp_rawrd2_s (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video7
pad0: Source
-> "rkisp-isp-subdev":0 []- entity 61: rkisp-statistics (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video8
pad0: Sink
<- "rkisp-isp-subdev":3 [ENABLED]- entity 67: rkisp-input-params (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video9
pad0: Source
-> "rkisp-isp-subdev":1 [ENABLED]- entity 73: rockchip-csi2-dphy1 (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev2
pad0: Sink
[fmt:SRGGB12_1X12/1948x1097@10000/600000 field:none
crop.bounds:(0,0)/1948x1097]
<- "m00_b_thcv244 2-000b":0 [ENABLED]
pad1: Source
-> "rkisp-csi-subdev":0 [ENABLED]- entity 76: m00_b_thcv244 2-000b (1 pad, 1 link)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev3
pad0: Source
[fmt:SRGGB12_1X12/1948x1097@10000/600000 field:none
crop.bounds:(0,0)/1948x1097]
-> "rockchip-csi2-dphy1":0 [ENABLED]
三、问题
1)rk3568对于mipi虚拟通道的配置
通过查看sdk中全部nvp6188这种转换类芯片(支持mipi虚拟通道,即多路摄像头分时复用一个mipi dphy)的dts配置,发现全部是通过vicap通道,而且各类文档中也是vicap支持4路vc通道。但是问题在于,这些参考中,所有的sensor数据格式都是yuv格式或RGB格式,并没有Raw格式的,因此感觉不适用。
当然,通过v4l2-ctl抓拍Raw数据时,能够正常获取,但是Raw格式是并不能直接使用的,需要通过ISP处理成YUV/RGB格式系统才可以使用。
Raw格式抓拍命令如下,因为vicap是bypass通道,因此pixelformat的指定需要根据sensor的输出数据格式设置,可以参考Linux源码“include/uapi/linux/videodev2.h”、“include/uapi/linux/media-bus-format.h”查看。
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=RG12 --stream-mmap=4 --stream-count=1 --stream-to=/tmp/cap.raw --stream-skip=2 --stream-poll
2)rk3568 isp是否支持虚拟通道复用?
这个问题和rk的FAE在redmine上来来回回沟通好多次,一开始提出需求时,他们说不能链接isp,需要用vicap,让我参考nvp6188或者maxim的驱动,总是怀疑是我的驱动不对。我一直强调我们sensor是raw格式的,但是总是被忽略。后面一步一步把问题沟通清楚后,来一个isp并不支持,需要我们转换芯片输出的格式是yuv或rgb格式才行,无语。。。
3)抓图或者预览,MIPI报错
a、SOT错误:mipi-csi2-hw ERR1:0x2 (sot sync,lane: 1)
1、确认sensor配置在其他平台能够正常点亮
2、检查link_freq,必须与sensor匹配,且是单lane上的传输速度
b、Packet Error或CRC Error:rkisp-vir0: MIPI error: packet: 0x0000d080
1、一般情况下都是mipi信号质量问题,需要查看mipi走线,如果有连接板需要看连接排线是否太长或没有屏蔽;
2、mipi发射端芯片工作电压是否正常,因为可能会引起干扰或者mipi信号幅度不够
4)RKISP_Tuner Tools生成Sensor的IQ参数
链接rkisp,通过v4l2-ctl预览时,发现画面很暗且偏色,原因是没有Sensor对应的iqfile。运行rkaiq_3A_server,看报错缺失的iqfile,记住文件名,也可以通过dts中配置的Sensor Type、Module Name、Module Lens Name,将三者字符串通过‘_’连接确定对应的iq文件名。
通过RKISP_Tuner Tools生成IQ参数文件(操作方法工具中有),然后重新命名成rkaiq_3A_server能够识别的文件名,并且放到iqfile路径下。
重新运行rkaiq_3A_server,再启动预览,画面正常。