SPI LCD 使用 DE 加速合成
在 1.0.7 版本驱动中,新增了 SPI LCD 通过 DE RTWB 回写实现 DE 加速合成的功能。
由于 SPI 屏是纯 CPU 软件屏,没有类似于 I8080,RGB 屏幕的 DE+TCON 硬件合成执行的功能,所以当执行一些 YUV 转 RGB 显示,多通道合成的时候会比较吃力,需要用 CPU 纯软件的合成转换,此时可以使用 DE 硬件的回写功能,使用 DE 的硬件合成加速,将输出的数据显示在 SPI 屏上。其流程如下:

整个框架包括四个流程:
- 应用层通过操作
/dev/disp节点,设置送显,送图层,绑定显示通道 - 应用层获取 SPI LCD 的显存 FD,将其传入 DISP 驱动
- 触发 DE 硬件执行合成和回写,将图像数据写道 SPI LCD 的显存中
- 执行 PANDISPLAY 操作,通知 SPI LCD 进行刷屏操作
危险
备注
加速方案的限制
备注
这套加速方案有一定的限制性,需要符合这些要求才可以使用
- DE 模块需要完全交给显示使用,不可以作为双屏显示,或者独立执 行其他缩放操作
- DE 模块仅能回写 RGB888,ARGB888 的数据,所以要求 SPI 屏幕需要支持 RGB888 或者支持 RGB666,若是 RGB666,其时序需要支持丢弃 BIT,使得送显数据 RGB888 但是实际屏幕显示 RGB666
- SPI 屏幕显示需要支持 TE
- 方案会占用较多内存,需要较多 buffer
- 目前仅支持 Video 通道送 YUV 显示,RGB + YUV 合成还不支持
备注
备注
为 什么屏幕配置RGB666,可以送RGB888的数据?
备注
这里以 DBI RGB666 时序为例,可以看到 RGB666 的送图格式中,每个颜色都需要发送两个 dummy clock,这两个数据会被屏幕自动丢弃,所以我们可以直接送显 RGB888 的数据,屏幕配置为 RGB666,屏幕自行丢弃低位两个不需要的 data,达到屏幕配置 RGB666,送显 RGB888 的功能。

参考 QSPI,也有类似的丢弃

:::
:::
:::
另外由于DE回写与屏幕送显是完全异步的操作,所以需要多块 buffer 轮转送显,一般 VI 送帧 20fps,需要配置 3 块 buffer。
配置功能
内核模块配置
需要配置这些模块
CONFIG_AW_DISP2=y
# CONFIG_AW_DISP2_PQ is not set
# CONFIG_AW_HDMI_TX_DISP2 is not set
CONFIG_LCD_FB=y
CONFIG_AW_LCD_FB_USE_ION=y
首先配置 LCD FB 显示驱动模块,配置路径如下所示:
Allwinner BSP --->
Device Drivers --->
Video Drivers --->
SPI LCD Panel Drivers --->
<*> LCD FB Driver Support (SPI LCD)

LCD 显示面板驱动位于
Allwinner BSP --->
Device Drivers --->
Video Drivers --->
SPI LCD Panel Drivers --->
LCD FB Panels select --->
[*] LCD support kld2844B panel
...

然后需要配置 LCD_FB 使用 ION 内存申请
Allwinner BSP --->
Device Drivers --->
Video Drivers --->
SPI LCD Panel Drivers --->
[*] LCD_FB use ION for framebuffer (Linux <= 5.4)

然后需要配置 DISP2 驱动,启用 DE 功能
Allwinner BSP --->
Device Drivers --->
Video Drivers --->
<*> DISP Driver Support(sunxi-disp2)

设备树配置
LCD FB 相关配置,配置 SPI 屏的一些细节
&pio {
dbi1_pins_default: dbi1@0 {
pins = "PD1", "PD2", "PD3"; /* dbi-cs, dbi-clk, dbi-sdo */
function = "spi1";
allwinner,drive = <3>;
};
dbi1_pins_dcx: dbi1@1 {
pins = "PD5"; /* dbi-dcx */
function = "spi1_hold";
allwinner,drive = <3>;
bias-pull-up;
};
dbi1_pins_te: dbi1@2 {
pins = "PD6"; /* dbi-te */
function = "spi1_wp";
allwinner,drive = <3>;
bias-pull-up;
};
dbi1_pins_sleep: dbi1@3 {
pins = "PD1", "PD2", "PD3", "PD5", "PD6";
function = "io_disabled";
};
};
&spi1 {
pinctrl-0 = <&dbi1_pins_default &dbi1_pins_dcx &dbi1_pins_te>;
pinctrl-1 = <&dbi1_pins_sleep>;
pinctrl-names = "default", "sleep";
/*Set SUNXI_SPI_BUS_DBI when using SPI LCD*/
sunxi,spi-bus-mode = <SUNXI_SPI_BUS_DBI>;
/*sunxi,spi-bus-mode = <SUNXI_SPI_BUS_MASTER>;*/
sunxi,spi-cs-mode = <SUNXI_SPI_CS_AUTO>;
status = "okay";
spi_panel_spi1: slave@0 {
device_type = "spi-panel";
compatible = "allwinner,spi-panel";
reg = <0x0>;
spi-max-frequency = <100000000>;
lcd_used = <1>;
lcd_driver_name = "kld2844b";
lcd_if = <1>;
lcd_dbi_if = <4>;
lcd_data_speed = <48>;
lcd_spi_bus_num = <1>;
lcd_x = <240>;
lcd_y = <320>;
lcd_pixel_fmt = <0>; /* 配置 fb 为 ARGB888 */
lcd_dbi_fmt = <3>; /* 屏幕为 RGB666 */
lcd_rgb_order = <0>;
lcd_width = <60>;
lcd_height = <95>;
lcd_pwm_used = <1>;
lcd_pwm_ch = <6>;
lcd_pwm_freq = <5000>;
lcd_pwm_pol = <1>;
lcd_frm = <1>;
lcd_gamma_en = <1>;
fb_buffer_num = <2>;
lcd_backlight = <100>;
lcd_fps = <60>;
lcd_dbi_te = <0>;
lcd_dbi_clk_mode = <0>;
lcd_gpio_0 = <&pio PD 4 GPIO_ACTIVE_LOW>; /* reset */
/*lcd_spi_dc_pin = <&pio PD 5 GPIO_ACTIVE_HIGH>;*/
status = "okay";
};
};
&lcd_fb {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
spi_panel0: endpoint@0 {
reg = <0>;
remote-endpoint = <&spi_panel_spi1>;
};
};
};
DISP DE 硬件设备树配置
&disp {
disp_init_enable = <1>;
disp_mode = <0>;
screen0_output_type = <7>; /* 配置为 RTWB 回写模式 */
screen0_output_mode = <4>;
screen0_to_lcd_index = <0>;
screen1_output_type = <3>;
screen1_output_mode = <10>;
screen1_to_lcd_index = <2>;
screen1_output_format = <0>;
screen1_output_bits = <0>;
screen1_output_eotf = <4>;
screen1_output_cs = <257>;
screen1_output_dvi_hdmi = <2>;
screen1_output_range = <2>;
screen1_output_scan = <0>;
screen1_output_aspect_ratio = <8>;
fb_format = <0>;
fb_num = <1>;
fb_debug = <0>;
/*<disp channel layer zorder>*/
fb0_map = <0 0 0 16>;
fb0_width = <240>; /* fb分辨率,需要与 SPI 屏幕一致 */
fb0_height = <320>; /* fb分辨率,需要与 SPI 屏幕一致 */
/*<disp channel layer zorder>*/
fb1_map = <0 2 0 16>;
fb1_width = <240>; /* fb分辨率,需要与 SPI 屏幕一致 */
fb1_height = <320>; /* fb分辨率,需要与 SPI 屏幕一致 */
/*<disp channel layer zorder>*/
fb2_map = <1 0 0 16>;
fb2_width = <240>; /* fb分辨率,需要与 SPI 屏幕一致 */
fb2_height = <320>; /* fb分辨率,需要与 SPI 屏幕一致 */
/*<disp channel layer zorder>*/
fb3_map = <1 1 0 16>;
fb3_width = <240>; /* fb分辨率,需要与 SPI 屏幕一致 */
fb3_height = <320>; /* fb分辨率,需要与 SPI 屏幕一致 */
chn_cfg_mode = <1>;
disp_para_zone = <1>;
};
&lcd0 {
lcd_used = <1>;
lcd_driver_name = "default_lcd";
lcd_if = <0>;
lcd_hv_if = <8>;
lcd_x = <240>; /* fb分辨率,需要与 SPI 屏幕一致 */
lcd_y = <320>; /* fb分辨率,需要与 SPI 屏幕一致 */
lcd_width = <108>;
lcd_height = <64>;
lcd_dclk_freq = <27>; /* 任意即可 */
lcd_hbp = <70>;
lcd_ht = <1716>;
lcd_hspw = <1>;
lcd_vbp = <21>;
lcd_vt = <263>;
lcd_vspw = <1>;
};
应用编写流程
应用流程如下所示:
