这篇文章我们介绍一下在安卓9、10、11的版本上,rk平台的hdmi-in功能是如何实现的,下篇文章我们再介绍安卓12之后的版本有了什么变化。希望对在rk平台调试hdmi-in功能的朋友有一些帮助。
目录
(1)概述
安卓9/10/11等版本一般对应的都是rk比较旧的主控芯片,例如rk3399、rk3568/6等等,这里呢,我们又可以分为两类,一类是rk3399等较久的主控,一类是RK3566/8两个平台。rk3399之类的主控芯片没有VICAP的图像模块,都是通过ISP接收HDMI-IN的图像数据,RK3566/68的平台有VICAP(RKCIF)模块,也有RKISP模块,可以两种方式实现。
在RK的主控芯片中只有RK3588拥有独立的HDMIRX模块,其他主控芯片都没有HDMI-RX模块,想要实现HDMI-IN 的功能只能通过外挂转接芯片的方式实现。比较常用的转接芯片有RK628、LT6911系列等等,这篇文章我们就介绍一下这种方式的实现以及调试指南
(2)基本功能流程实现原理
1.系统功能框图
系统框图如下图所示,RK628D作为类camera设备使用,基于V4L2框架实现相关驱动,HDMI信号源通过RK628的HDMIRX接口输入,经过RK628的内部模块处理将接收的图像数据处理为MIPI-CSI信号作为数据输出,同时图像格式也统一转换为YUV422格式输出,经MIPI lane接入到主控的MIPI接口,由主控接收图像并对图像进行处理显示,从而实现HDMI-IN的功能。
2.系统功能流程
2.1 APK工作流程
APK预览工作流程如下图所示:
2.2 热拔插
热拔插中断处理流程如下图所示
2.3 切换分辨率
切换分辨率流程如下图所示:
(3)功能配置说明
1.驱动代码与配置
1.1 驱动代码
转接芯片驱动代码如下:
drivers/media/i2c/rk628/
drivers/media/i2c/lt6911uxe.c
drivers/media/i2c/lt6911uxc.c
drivers/media/i2c/tc35874x.c
1.2 config配置
kernel的config配置如下:
CONFIG_VIDEO_LT6911UXC=y
CONFIG_VIDEO_LT6911UXE=y
CONFIG_VIDEO_RK628_CSI=y
CONFIG_VIDEO_TC35874X=y
2.DTS配置
以下介绍调试的时候的dts配置。主要有设备配置,链路配置,链路配置中,由于rk3566/68平台有两种场景,因此,我们分别介绍两种场景的配置。
2.1 设备配置
转接芯片一般都是i2c设备,需要配置到i2c总线下,参考如下配置:
&i2c5 {
status = "okay";
rk628_csi: rk628_csi@50 {
reg = <0x50>;
compatible = "rockchip,rk628-csi-v4l2";
status = "okay";
power-domains = <&power RK3588_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&rk628_pin>;
interrupt-parent = <&gpio2>;
interrupts = <RK_PC4 IRQ_TYPE_EDGE_RISING>;
enable-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
plugin-det-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>;
continues-clk = <1>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "HDMI-MIPI";
rockchip,camera-module-lens-name = "RK628-CSI";
port {
hdmiin_out0: endpoint {
remote-endpoint = <&hdmi_mipi0_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
interrupt-parent/ interrupts:连接RK628中断的GPIO引脚;
enable-gpios:RK628供电控制GPIO引脚(若为常供电可不配置);
reset-gpios:RK628复位控制GPIO引脚
rockchip,camera-module相关的都是适配RK的camera框架平台私有配置,与camera类似。
2.2 图像链路配置
这里具体RK3399以及RK3568为例,RK3399代表的是RK旧的平台,RK3568代表的是引入VICAP之后的平台,在RK3568之后的芯片平台也没有基于安卓11的版本,都是基于安卓12以后得版本,我们后续在做详细的介绍。
2.2.1 RK3399
RK339平台只能使用ISP接收图像,链路我们可以描述为:转接芯片-->dphy_rx0 -->isp
其中dts配置可以参考如下配置。需要注意的是rk3399有两个isp,配置对应的是哪一路即可。
&i2c4 {
clock-frequency = <400000>;
status = "okay";
rk628_csi_v4l2: rk628_csi_v4l2@50 {
reg = <0x50>;
compatible = "rockchip,rk628-csi-v4l2";
interrupt-parent = <&gpio2>;
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
//enable-gpios = <&gpio5 RK_PC3 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_LOW>;
plugin-det-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_LOW>;
//power-gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "RK628-CSI";
rockchip,camera-module-lens-name = "NC";
port {
hdmiin_out0: endpoint {
remote-endpoint = <&mipi_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
&mipi_dphy_rx0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmiin_out0>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
dphy_rx_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&isp_mipi_in>;
};
};
};
};
&isp0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp_mipi_in: endpoint@0 {
reg = <0>;
remote-endpoint = <&dphy_rx_out>;
};
};
};
&isp0_mmu {
status = "okay";
};
2.2.2 RK3568
RK3568则有两种情况,一是使用isp接收,二是使用vicap模块接收图像,我们分别进行介绍。
rk3568使用isp的场景,对应的图像链路为:
对应的dts配置为:
&csi2_dphy_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmiin_out0>;
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>;
};
};
};
};
&i2c4 {
clock-frequency = <400000>;
status = "okay";
rk628_csi_v4l2: rk628_csi_v4l2@50 {
reg = <0x50>;
compatible = "rockchip,rk628-csi-v4l2";
interrupt-parent = <&gpio2>;
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
//enable-gpios = <&gpio5 RK_PC3 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_LOW>;
plugin-det-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_LOW>;
//power-gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "RK628-CSI";
rockchip,camera-module-lens-name = "NC";
port {
hdmiin_out0: endpoint {
remote-endpoint = <&mipi_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
&rkisp {
status = "okay";
};
&rkisp_mmu {
status = "okay";
};
&rkisp_vir0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_in: endpoint@0 {
reg = <0>;
remote-endpoint = <&csidphy_out>;
};
};
};
RK3568使用VICap的场景,图像链路为:
对应的dts配置参考为:
&csi2_dphy_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
hdmi_to_mipi_in: endpoint@1 {
reg = <1>;
remote-endpoint = <<6911uxc_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy_out: endpoint@1 {
reg = <1>;
remote-endpoint = <&mipi_csi2_input>;
data-lanes = <1 2 3 4>;
};
};
};
};
&i2c3 {
status = "okay";
lt6911uxc: lt6911uxc@2b {
status = "okay";
reg = <0x2b>;
compatible = "lontium,lt6911uxc";
clocks = <&ext_cam_clk>;
clock-names = "xvclk";
interrupt-parent = <&gpio4>;
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
power-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>;
plugin-det-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
hpd-ctl-gpios = <&gpio3 27 GPIO_ACTIVE_LOW>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "LT6911UXC";
rockchip,camera-module-lens-name = "NC";
port {
lt6911uxc_out: endpoint {
remote-endpoint = <&hdmi_to_mipi_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
&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 = <&csidphy_out>;
data-lanes = <1 2 3 4>;
};
};
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 3 4>;
};
};
};
};
&rkcif_mipi_lvds {
status = "okay";
port {
cif_mipi_in: endpoint {
remote-endpoint = <&mipi_csi2_output>;
data-lanes = <1 2 3 4>;
};
};
};
&rkcif_mmu {
status = "okay";
};
&rkcif {
status = "okay";
};
3.camera xml注册设备
camera3_profiles.xml文件对应SDK目录下具体芯片平台的文件:
hardware/rockchip/camera/etc/camera/camera3_profiles_rk3xxx.xml
在设备上的路径为:
/vendor/etc/camera/camera3_profiles.xml
若是临时调试,可以采用adb替换文件的形式,但需要注意文件路径与文件名的正确性。
xml增加配置的时候可以参考其他已有的sensor,后续仅介绍关键的几个修改点。
3.1 设备名称与ID
xml中name参数与moduleid参数取决定着能否成功注册安卓camera设备,若该两项属性配置异常,则会导致
name:需要与驱动名称一致,有大小写区别;
moduleId:需要与驱动dts中配置的index一致;
3.2 分辨率配置
scaler.availableStreamConfigurations/scaler.availableMinFrameDurations/ scaler.availableStallDurations:需要正确配置预预览支持的分辨率以及帧率,此处的分辨率不能大于驱动实际输出的分辨率大小,如下所示:
<scaler.availableStreamConfigurations value="
BLOB,1920x1080,OUTPUT,
BLOB,176x144,OUTPUT,
YCbCr_420_888,1920x1080,OUTPUT,
YCbCr_420_888,176x144,OUTPUT,
IMPLEMENTATION_DEFINED,1920x1080,OUTPUT,
IMPLEMENTATION_DEFINED,176x144,OUTPUT"/>
<scaler.availableMinFrameDurations value="
BLOB,1920x1080,33333333,
BLOB,176x144,33333333,
YCbCr_420_888,1920x1080,33333333,
YCbCr_420_888,176x144,33333333,
IMPLEMENTATION_DEFINED,1920x1080,33333333,
IMPLEMENTATION_DEFINED,176x144,33333333" />
<scaler.availableStallDurations value="
BLOB,1920x1080,33333333,
3.3 SOC模式
在<Sensor_info_RKISP1>中需要配置sensorType,一般SOC为YUVsensor,即不启动3A,RAW为RAW sensor,启动3A,HDMI-IN都是YUV的图像,因此需要设置为SOC模式。
<sensorType value="SENSOR_TYPE_SOC"/> <!-- SENSOR_TYPE_SOC or SENSOR_TYPE_RAW -->
3.4 旋转角配置
<sensor. Orientation value="0"/>
4.APK适配
4.1 获取APK
APK源码地址:
RKDocs/common/hdmi-in/apk/rkCamera2_based_on_CameraHal3_V1.3.tar.gz
4.2 APK 源码适配
rkCamera2/jni/native.cpp
获取连接状态和分辨率的位置:
5.EDID配置
(4)调试方法
1.查看设备是否注册camera
使用如下命令查看是否成功注册cameraID
dumpsys media.camera
2.查看拓扑结构
HDMI2MIPI驱动框架类似camera,需要保证pipeline的完整才可以正常工作,使用media-ctl查看pipeline,同时也可以查看转接芯片对应的subdev节点,以便于apk那边适配修改。
media-ctl -d /dev/mediaX -p //X=0123...
3.v4l2抓取数据流
v4l2-ctl --verbose -d /dev/video0 --set-fmt-video=width=3840,height=2160,pixelformat='NV12' --stream-mmap=4
4.v4l2抓图
v4l2-ctl --verbose -d /dev/video0 --set-fmt-video=width=3840,height=2160,pixelformat='NV12' --stream-mmap=3 --stream-skip=4 --stream-to=/data/3840x2160_nv12.yuv --stream-count=5 --stream-poll
5.不同芯片平台接收能力
由于各个芯片平台isp/vicap的性能不同,对图像的最大接收能力也不同。可参考下表
芯片平台 | 控制器 | 支持分辨率 |
RK3288/RK3326 | ISP | 1080P60 |
RK3399 | ISP | 4K30 超频 |
RK3568/6 | ISP/VICAP | ISP:1080P60 VICAP:4K30 |
6.配置使用ISP CMA内存
部分平台HDMI IN接收图像数据时,根据实际系统负载,可能会存在带宽不足导致丢帧或MIPI接收异常等问题。此时需要提高DDR频率,若仍无改善,可给ISP预留使用CMA内存,以改善解决此问题。
-
rockchip_defconfig 配置预留 CMA 内存 128MB
CONFIG_CMA=y
CONFIG_CMA_SIZE_MBYTES=128
- 在dts配置ISP关闭IOMMU,使用CMA内存
&rkisp_mmu {
status = "disabled";
};
7.配置RK3399 ISP超频
配置RK3399超频625M,实现接收4K30图像。
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
index 5ed8dac..e8f259d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-vop-clk-set.dtsi
@@ -148,7 +148,7 @@
<50000000>, <100000000>,
<75000000>, <75000000>,
<816000000>, <816000000>,
- <600000000>, <200000000>,
+ <625000000>, <200000000>,
<800000000>, <150000000>,
<75000000>, <37500000>,
<300000000>, <100000000>,
diff --git a/drivers/media/platform/rockchip/isp1/dev.c b/drivers/media/platform/rockchip/isp1/dev.c
index 4e548f0..5aa9e13 100644
--- a/drivers/media/platform/rockchip/isp1/dev.c
+++ b/drivers/media/platform/rockchip/isp1/dev.c
@@ -757,7 +757,7 @@ static const unsigned int rk3368_isp_clk_rate[] = {
/* isp clock adjustment table (MHz) */
static const unsigned int rk3399_isp_clk_rate[] = {
- 300, 400, 600
+ 300, 400, 625
};
static struct isp_irqs_data rk1808_isp_irqs[] = {
(5)总结
本文较长基本详细介绍了安卓9/10/11等平台hdmi-in功能的开发,可以看到hdmi-in与camera最大的不同在于增加了切换分辨率与热拔插的功能,而目前在安卓11的版本上面,都是使用apk轮询的方式实现的,而在安卓12之后的版本中,对这一方式有所优化,并且也增加了低延时送显示的应用框架,不再完全依赖于camera框架,后续我们在做介绍。