OrangePi-3B 系列笔记:
- OrangePi-3B 折腾笔记 —— 认识开发板
- OrangePi-3B 折腾笔记 —— 准备构建环境
- OrangePi-3B 折腾笔记 —— 构建 U-Boot
- OrangePi-3B 折腾笔记 —— 构建 Kernel
- OrangePi-3B 折腾笔记 —— 点亮 LCD 屏幕
- OrangePi-3B 折腾笔记 —— 移植 WiFi & BT 驱动
- OrangePi-3B 折腾笔记 —— 构建文件系统镜像
温馨提示:
- OrangePi-3B 硬件版本 V1.1.1 的板子出现过有线网卡“无故”失灵的故障, 所以在进行操作前请确认开发板工作良好(修复这个问题需要更换 RK3566 芯片).
https://www.bilibili.com/read/cv33224126- 香橙派目前已经推出了硬件版本为 V2.1 的 OrangePi-3B, 有线网卡供应商更换为 RTL. 本系列文章没有针对 V2.1 的板子做过适配, 请根据实际情况操作(同时强烈谴责此种不负责任的行为, 如考虑购买此型号板子商用, 建议换个型号避坑).
- 本系列文章最后更新时间: 2024年7月20日.
编译环境
- 主板: OrangePi-3b_V1.1.1
- 芯片: RK3566
- 环境: Debian:12_x86_64(Docker)
内容说明
买了这个 OrangePi 3b
之后,顺手给它配一个5寸的屏幕。
淘宝里面找到一款设计给树莓派使用的屏幕,刚好 OrangePi 3b
的打孔位置和这个屏幕完全匹配,所有果断入手。
但是,这块屏实测默认只有香橙派的 Android
固件能够点亮它,其他的都不能直接点亮(LCD 屏通常需要特殊适配),不过至少也证明硬件是可以兼容的。
这就来适配一下。
移植
咨询网店老板屏幕相关参数信息,得知使用 raspberrypi,7inch-touchscreen-panel
就能驱动。香橙派的内核中包含这个驱动。
本来是想直接去香橙派的内核仓库抄作业的,但是发现香橙派只有 5.10
的内核适配了这块屏幕,直接拷过来到 6.6
的设备树中很多节点是无法识别的。
只能硬着头皮琢磨了。
不过香橙派的设备树倒是给了大致的思路。
使用 Device Tree Overlays
定义增量 DT
由于驱动是现成的,那么主要工作就是编辑设备树。按照主线内核的设备树架构,我这个设备并不是属于开发板,而是一个外设,那么我不应该直接修改通用的 rk3566-orangepo-3b.dts
文件,而应该使用 Device Tree Overlays
的方式定义。
Device Tree Overlays
是一种 DT
的增量扩展方案。一个母体 DT
可以通过融合很多 dtbo
文件进行动态扩展,达到一种解耦的效果。
首先来建立 Device Tree Overlays
的基本编译结构:
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 88ed4077425b..1405fe6ecdf0 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -106,3 +106,6 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-rock-5b.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-indiedroid-nova.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-khadas-edge2.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb
+
+rk3566-orangepi-3b-custom-dtbs := rk3566-orangepi-3b.dtb rk356x-raspi-7inch-touchscreen.dtbo
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-orangepi-3b-custom.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk356x-raspi-7inch-touchscreen.dtso b/arch/arm64/boot/dts/rockchip/rk356x-raspi-7inch-touchscreen.dtso
new file mode 100644
index 000000000000..0e5000a4d9d8
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk356x-raspi-7inch-touchscreen.dtso
@@ -0,0 +1,75 @@
+/dts-v1/;
+/plugin/;
+
+&{/} {
+
+};
kernel
的6.x
和5.x
关联dtbo
规则是不一样的,这里演示的是6.x
的版本;dtso
文件的写法有两种,其中一种新式写法和普通的dts
很类似,下面就都采用的这种写法;Makefile
中的两句的意思是通过rk3566-orangepi-3b.dts
和rk356x-raspi-7inch-touchscreen.dtso
构建出rk3566-orangepi-3b-custom.dtb
:
rk3566-orangepi-3b.dts
是构建kernel
时增对OrangePi-3B
加入的DT
,是一个比较通用的DT
;rk356x-raspi-7inch-touchscreen.dtso
是这次针对屏幕新增加的DT
;他有/plugin/
标志,表示是一个插件DT
;rk3566-orangepi-3b-custom.dtb
是rk3566-orangepi-3b.dts
和rk356x-raspi-7inch-touchscreen.dtso
合并构建出的产物,它还可以融合更多的dtso
文件;- 产物会构建出
rk3566-orangepi-3b-custom.dtb
和rk356x-raspi-7inch-touchscreen.dtbo
;前者可以用在u-boot
不支持fdt
命令的场景,后者可以使用u-boot
通过fdt
命令进行融合;- 上面
dts/dtb
、dtso/dtbo
变来变去没有问题,**s*
是源文件后缀,编译后的产物就是**b*
后缀;
使能 DSI
协议接口
首先,这是一块 LCD
屏幕,物理尺寸为 5inch
,物理分辨率为 800x480
,带电容触摸屏,接口为 MIPI
,使用 15p
排线和 OrangePi 3B
连接。查看 OrangePi 3B
的原理图得知,连接屏幕的 MIPI
口在 RK3566
中为 MIPI1
(图纸中标签为 LCD1
)。
进一步查阅资料:在 MIPI
规范中,MIPI-DSI
协议接口用于图像输出,MIPI-CSI
协议接口用于图像输入(比如摄像头)。
所以参照原理图:先将对应的 dsi1
节点使能;在 rk356x.dtsi
文件中发现 dts1
节点对应的 phys
关联到了 dsi_dphy1
节点, 那也一起使能:
&dsi1 {
status = "okay";
};
&dsi_dphy1 {
status = "okay";
};
rk356x.dtsi
是rk3566
、rk3568
等设备树的爸爸,里面定义的设备默认都是disable
的,要是需要使用那就得手动使能。
配置 MIPI-DSI
协议接口输入
然后,既然 MIPI-DSI
只是一种协议接口,那么它就需要有需要输入和输出信号。
在 rk356x.dtsi
文件中,已经给 dsi1
定义了两个端口 dsi1_in
和 dsi1_out
,接下来就需要给这两个接口通过设备树联结对端。
端口 dsi1_in
是 dsi1
的输入,它的数据来源应该是系统的显卡什么的。在瑞芯微的设备树中,这个设备叫做 display_subsystem
,它自己的端口又指向了 vop_out
。
瑞芯微给 vop_out
定义了 vp0
、vp1
、vp2
三路子端口,估计是支持三路视频输出。
其中 vp0
在 rk3566-orangepi-3b.dts
中配置为连接 HDMI
的端口。
那么我这就使用 vp1
把:
#include <dt-bindings/soc/rockchip,vop2.h>
&vp1 {
vp1_out_dsi1: endpoint@ROCKCHIP_VOP2_EP_MIPI1 {
reg = <ROCKCHIP_VOP2_EP_MIPI1>;
remote-endpoint = <&dsi1_in_vp2>;
};
};
&dsi1_in {
dsi1_in_vp2: endpoint {
remote-endpoint = <&vp1_out_dsi1>;
};
};
但是这样写编译 dtbs
的时候会抛警告,大致意思是 vp1
、dsi1_in
这些节点应该是一个 port
,但没有指定。
强迫症果断受不了。
那就换种写法,其实就是声明包含 port
的节点路径,这些路径可以在 rk356x.dtsi
里面找到:
#include <dt-bindings/soc/rockchip,vop2.h>
&vop_out {
#address-cells = <1>;
#size-cells = <0>;
vp1: port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
vp1_out_dsi1: endpoint@ROCKCHIP_VOP2_EP_MIPI1 {
reg = <ROCKCHIP_VOP2_EP_MIPI1>;
remote-endpoint = <&dsi1_in_vp2>;
};
};
};
&dsi1 {
ports {
#address-cells = <1>;
#size-cells = <0>;
dsi1_in: port@0 {
reg = <0>;
dsi1_in_vp2: endpoint {
remote-endpoint = <&vp1_out_dsi1>;
};
};
};
};
- 实测
RK3566
支持至少两路视频,并且可以双屏异显;不过可能和分辨率有关,我的显示屏分辨率都不高。- 设备树真的很神奇,就这样简单的配一下,就实现了两个不同设备的联结。
配置屏幕设备树
现在 MIPI-DSI
的输入部分已经好了,现在来看输出部分。在正式配置 MIPI-DSI
输出链路之前先把屏幕给挂到设备树上面。
上面说道,我用的屏幕是 MIPI
接口的,但 OrangePi-3B
和这块屏设计接口里面有一路 i2c
,它用来和屏幕控制芯片进行信令交互。
参考香橙派官方的设备树修改,在 kernel 6.6
版本里面最终配置长这样:
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
raspits_panel: raspits-panel@45 {
compatible = "raspberrypi,7inch-touchscreen-panel";
reg = <0x45>;
port {
panel_in_dsi1: endpoint {
remote-endpoint = <&dsi1_out_panel>;
};
};
};
raspits_touch_ft5426: raspits-touch-ft5426@38 {
compatible = "raspits_ft5426";
reg = <0x38>;
};
};
i2c1
是根据香橙派的原理图得到的。- 屏幕在设备树里面都叫面板,
raspits_panel
定义了一个port
叫panel_in_dsi1
, 这是它的信号输入端口(看着很牛逼,但这些规则都是驱动程序里面的逻辑)。- 因为这块屏还有一个触摸屏的能力,有现成的就一起抄过来了。但是这个驱动主线
kernel
中并没有,移植驱动的部分放后面。
配置 DSI
协议接口输出
屏幕好了之后来看 DSI
的输出端口,有了上面两个例子,其实已经很简单了,只需要和屏幕暴露的端口绑定起来就可以了:
&dsi1 {
ports {
#address-cells = <1>;
#size-cells = <0>;
dsi1_out: port@1 {
reg = <1>;
dsi1_out_panel: endpoint {
remote-endpoint = <&panel_in_dsi1>;
};
};
};
};
至此,设备树部分就写(其实是抄)完了,接下来为了让内核开机就能加载驱动,需要把上面设备树里面设备的驱动和内核一起编译。
修改编译配置
涉及到的驱动有:
#
# Touchscreen Support
#
CONFIG_INPUT=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_RASPITS_FT5426=y
#
# Display Panels
#
CONFIG_DRM=y
CONFIG_DRM_PANEL=y
CONFIG_DRM_ROCKCHIP=y
CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=y
#
# PHY Subsystem
#
CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=y
配置有不少,但这不是开启显示功能的所有配置。因为有不少配置在 defconfig
里面默认是 y
,我这只有那些不是 y
的部分。因为需要屏幕在没加载文件系统之前就能点亮。
这些配置还是挺复杂的,我自己其实是摸索了两三天才把屏幕点亮,至于为什么要有某个配置我说不好就不说了,我是根据设备树反向推导出来的。
举个例子,CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY
这个配置,是因为上面的 dts1
的 compatible
是 rockchip,rk3568-mipi-dsi
,这个 compatible
字段是驱动的识别,如果驱动要生效那么对应的字段值一定存在于驱动文件中。
于是我全局搜索 rockchip,rk3568-mipi-dsi
, 发现在一个叫 dw-mipi-dsi-rockchip.c
的文件里面包含。
那想让驱动生效就等于得编译进入内核,所以就看这个文件的编译选项,有什么条件才能加入编译队列。一般就先看同级目录下的 Makefile
文件。
果然,在同级目录下的 Makefile
文件中发现他需要 CONFIG_ROCKCHIP_DW_MIPI_DSI
选项才能加入队列。
所有我得确保这个文件是被编译的,把它放到 .config
搜索发现已经是 y
了说明是会编译到内核不用等待文件系统加载的。
然后,除了它自己,还需要关注他的父级。一般是上级目录,看看是否会参与编译。打开上一级文件夹下面的 Makefile
,查到当前文件夹 rockchip
,发现果然有一个 CONFIG_DRM_ROCKCHIP
控制这个目录是否参与编译。
所有需要确认 CONFIG_DRM_ROCKCHIP
是否是 y
。经检查它是 m
,那就强制 y
一下。
其他的驱动配置过程类似,反正各种排查踩坑就对了。
也可以使用 menuconfig
来搜索配置,比如已经知道需要 CONFIG_ROCKCHIP_DW_MIPI_DSI
,在 menuconfig
中搜索这个配置可以快速查看到他的依赖和对于的配置情况。
屏幕参数修改
经过长时间的摸爬滚打,屏幕终于是亮了。但是却出现了偏移的情况?回想起之前做项目的时候 LVDS
有个屏参的概念,一查果然 DSI
也有。
通过网上的文章学习了一下屏幕参数的概念以及计算方法,再从淘宝店小二那得到的信息,发现是驱动内的默认数据和屏幕没有对其。
老板给的信息虽然少,但是很有用,记录一下:
#define PIXEL_CLOCK ((2000000000 / 3) / 24)
#define VREFRESH 60
#define VTOTAL (480 + 7 + 2 + 21)
#define HACT 800
#define HSW 2
#define HBP 46
#define HFP ((PIXEL_CLOCK / (VTOTAL * VREFRESH))) - (HACT + HSW + HBP)
- 第一行频率和驱动里面的不一样,驱动里面得再除以
1000
;- 让我恍然大悟的是最后一条
HFP
的计算,实际画面异常的原因也就是自带驱动的HFP
是错误的;
网上的文章见最后,总之试了几次之后就正常显示了:
diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
index 4618c892cdd6..56e52206c9a8 100644
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -203,7 +203,7 @@ static const struct drm_display_mode rpi_touchscreen_modes[] = {
.hdisplay = 800,
.hsync_start = 800 + 1,
.hsync_end = 800 + 1 + 2,
- .htotal = 800 + 1 + 2 + 46,
+ .htotal = 800 + 1 + 2 + 1,
.vdisplay = 480,
.vsync_start = 480 + 7,
.vsync_end = 480 + 7 + 2,
双屏异显
刚开始弄的使用我以为 RK3566
不支持双路视频输出,调试的时候一直是吧 HDMI
的设备树禁用的。
后面发现 RK3566
是支持 MIPI
和 HDMI
同时输出的,并且是双屏异显。
有个前提,就是两路信号得启用不同的 vp
端口。
触摸屏驱动
这块屏幕用的触摸芯片是 ft5426
,内核中默认倒是有这个芯片的驱动,但是需要配置中断引脚,板子和屏幕都没有预留这个 IO
引脚,所有用不了。
那就只能将香橙派内核里面的驱动程序移植了过来。
移植倒是没多大难度,拷贝 drivers/input/touchscreen/raspits_ft5426.h
和 drivers/input/touchscreen/raspits_ft5426.c
两个源文件,同时把 drivers/input/touchscreen/Kconfig
文件中相关的部分也拷过来便于能够使用 menuconfig
进行配置,最后改一下 drivers/input/touchscreen/Makefile
文件,在里面增加 raspits_ft5426.c
作为编译输入。
需要注意的是 5.10
的驱动到 6.6
里面时,驱动的 probe
和 remove
两个函数需要调整一下签名:
diff --git a/drivers/input/touchscreen/raspits_ft5426.c b/drivers/input/touchscreen/raspits_ft5426.c
index fa2edcb2995b..0899a7052454 100644
--- a/drivers/input/touchscreen/raspits_ft5426.c
+++ b/drivers/input/touchscreen/raspits_ft5426.c
@@ -217,8 +217,7 @@ static void raspits_ft5426_work(struct work_struct *work)
}
}
-static int raspits_ft5426_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int raspits_ft5426_probe(struct i2c_client *client)
{
struct raspits_ft5426_data *ts_data;
struct input_dev *input_dev;
@@ -276,7 +275,7 @@ static int raspits_ft5426_probe(struct i2c_client *client,
return ret;
}
-static int raspits_ft5426_remove(struct i2c_client *client)
+static void raspits_ft5426_remove(struct i2c_client *client)
{
struct raspits_ft5426_data *ts_data = i2c_get_clientdata(client);
@@ -286,7 +285,6 @@ static int raspits_ft5426_remove(struct i2c_client *client)
input_free_device(ts_data->input_dev);
}
kfree(ts_data);
- return 0;
}
static const struct i2c_device_id raspits_ft5426_id[] = {
打完收工
走到这一步,这块屏就是完全驱动起来了,重新编译内核体验一下吧。
刚开始触摸屏不能用我以为是 Debian
系统不支持。还好没有放弃继续研究驱动搞定了。
下一个目标就是 OrangePi 3B
板载的蓝牙和无线网卡了~~~下篇博客再见!
针对 OrangePi 3B
的改动记录
https://github.com/lx0758/linux/commits/orangepi-3b/
调试
搞了这么久,发现验证内核最快的方式还是 U-Boot
通过 NFS
直接加载来的快。
快速应用修改
为了快速验证修改,我设置了 U-Boot
从远程通过 NFS
加载 Kernel
和 dtb
,每次重启时自动应用。
setenv ipaddr "192.168.8.21"
setenv load_kernel "nfs 0x4000000 192.168.8.13:/home/liux/projects/kernel/out/arch/arm64/boot/Image.gz"
setenv load_initramfs "load mmc 0:1 0x2000000 /boot/initramfs.img"
setenv load_dtb "nfs 0x1000000 192.168.8.13:/home/liux/projects/kernel/out/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b-custom.dtb"
setenv boot "booti 0x4000000 - 0x1000000"
setenv bootcmd "${load_kernel};${load_initramfs};${load_dtb};${boot};"
setenv bootargs "earlycon console=tty1 console=ttyS2,1500000n8 consoleblank=0 root=/dev/mmcblk0p1 rw rootfstype=ext4 rootwait"
saveenv
- 设置
u-boot
从NFS
加载kernel
和dts
;- 设置
kernel
从MMC
加载ROOTFS
;- 设置
kernel
不使用initramfs
,避免驱动重复加载;- 增加
kernel
启动参数console=tty1
使能屏幕输出;- 除了直接使用
rk3566-orangepi-3b-custom.dtb
设备树,也可以是使用Device Tree Overlays
技术加载差异设备数文件rk356x-raspi-7inch-touchscreen.dtbo
,具体可以查看构建文件系统的笔记。