(六)正点原子4.3寸RGB屏幕驱动--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
正点原子ATK4384屏幕,分辨率800*480,支持RGB接口,RGB LCD接口信号线如下所示:
目录
一、RGB屏幕介绍
正点原子ATK4384显示屏,分辨率800*480,支持RGB接口,详细资料下载地址为:4.3寸RGBLCD电容触摸屏800*480。RGB LCD接口信号线如下所示:
信号线 | 描述 |
R[7:0] | 数据线 |
G[7:0] | 数据线 |
B[7:0] | 数据线 |
DE | 数据使能线 |
VSYNC | 垂直同步信号线 |
HSYNC | 水平同步信号线 |
PCLK | 像素钟信号线 |
屏幕的参数如下所示,其中各参数的含义详见这篇博客,解释的比较详细,我就不再重复造轮子了。
参数 | 值 | 单位 |
水平显示区域 | 800 | 每时钟 (tCLK) |
HSPW (thp) | 48 | 每时钟 (tCLK) |
HBP (thb) | 88 | 每时钟 (tCLK) |
HFP (thf) | 40 | 每时钟 (tCLK) |
垂直显示区域 | 480 | 每行 (th) |
VSPW (tvp) | 3个 | 每行 (th) |
VBP (tvb) | 32 | 每行 (th) |
VFP (tvf) | 13 | 每行 (th) |
我的板子上存在两个屏幕接口, 1.14寸ips屏幕、ATK4384的40pinrgb屏幕,由于1.14寸屏幕实在是太小了,因此,本系统使用的40PinRGB屏幕接口如图所示。由下面的硬件原理图可以看出我们采用的屏数据格式是RGB666,当然,I2C接口用作触摸屏数据传输,本文暂时用不到。
二、RGB屏幕驱动
linux内核已经配备了RGB模式下的LCD驱动(见drivers/gpu/drm/panel/panel-simple.c,也就是DRM驱动),而我们的F1C200s支持RGB模式的LCD,我们不需要从零写一个屏幕驱动,我们只需要简单几步即可驱动LCD屏幕。F1C200s虽然不像IMX6ULL那样配备eLCDIF接口,但只需要符合RGB接口的时序即可点亮。
注意:内核配置文件和之前相同!
1、设备树修改
.dtsi文件中做以下修改,代码修改处添加了modify by kashine的标注。其中,加入reset和clock两个文件夹下的suniv-ccu-f1c100s.h文件,是为了提供一些宏定义;设备树de结点是display engine驱动初始化结点,官方解释为:Allwinner A10 Display Engine DRM/KMS Driver,关于DRM驱动的知识,这里不在赘述;tcon0结点对应时序控制驱动,官方解释为:Allwinner A10 Timing Controller Driver;pio结点中加入RGB屏幕的管脚信息;fe0结点和be0结点为RGB显示的前后端驱动程序;pwm结点用于背光显示,亮度调节。
我们来详细分析一下代码中的各个部分。
-
display-engine:描述了显示引擎,这是 F1C100s 处理器中的一个重要组件,用于处理图像数据。它与显示前端(display-frontend)和显示后端(display-backend),相连接包含一条pipeline fe0。
-
tcon0:代表了时序控制器(Timing Controller,简称 TCON),它负责生成正确的时序信号,以驱动显示面板。这部分代码中,我们可以看到 TCON 的寄存器地址、中断号、时钟和复位信号等信息。此外,还定义了输入和输出端口,分别连接到显示后端和显示面板。
-
lcd_rgb666_pins:定义了与 RGB 屏幕连接的引脚,这里使用了 18 位的 RGB666 接口。
-
display-frontend 和 display-backend:显示前端和显示后端分别负责图像数据的预处理和后处理。显示前端接收原始图像数据,对其进行缩放、色彩空间转换等操作;显示后端则负责图像数据的合成、alpha 混合等功能。这两个部分通过端口和端点(endpoint)进行连接。
-
panel:描述了显示面板,定义了使用的LCD panel参数。这里使用了一个兼容于 "alientek,alientek_4p3_inch" 和 "simple-panel" 的面板。面板的输入端口与 TCON 的输出端口相连接。
-
reg_vcc3v3:描述了一个固定电压的电源,为面板提供 3.3V 电源。
最后,在设备树末尾,启用了 be0(显示后端)、de(显示引擎)和 tcon0(时序控制器)节点。
从这段代码中可以看出,该 RGB 屏幕驱动确实使用了 DRM 框架。其工作原理大致如下:
- 显示前端接收原始图像数据,进行预处理。
- 处理后的图像数据传递给显示后端,进行后处理和合成。
- 处理后的图像数据通过 TCON 生成正确的时序信号,驱动显示面板。
// SPDX-License-Identifier: (GPL-2.0+ OR X11)
/*
* Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
* Copyright 2018 Mesih Kilinc <mesihkilinc@gmail.com>
*/
// modify by kashine
#include <dt-bindings/clock/suniv-ccu-f1c100s.h>// 下面引用该文件中的一些宏定义
#include <dt-bindings/reset/suniv-ccu-f1c100s.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
clocks {
osc24M: clk-24M {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "osc24M";
};
osc32k: clk-32k {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
clock-output-names = "osc32k";
};
};
cpus {
cpu {
compatible = "arm,arm926ej-s";
device_type = "cpu";
};
};
// modify by kashine
de: display-engine {
compatible = "allwinner,suniv-f1c100s-display-engine";
allwinner,pipelines = <&fe0>;
status = "disabled";
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
sram-controller@1c00000 {
compatible = "allwinner,suniv-f1c100s-system-control",
"allwinner,sun4i-a10-system-control";
reg = <0x01c00000 0x30>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
sram_d: sram@10000 {
compatible = "mmio-sram";
reg = <0x00010000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x00010000 0x1000>;
otg_sram: sram-section@0 {
compatible = "allwinner,suniv-f1c100s-sram-d",
"allwinner,sun4i-a10-sram-d";
reg = <0x0000 0x1000>;
status = "disabled";
};
};
};
// modify by kashine
tcon0: lcd-controller@1c0c000 {
compatible = "allwinner,suniv-f1c100s-tcon";
reg = <0x01c0c000 0x1000>;
interrupts = <29>;
clocks = <&ccu CLK_BUS_LCD>,
<&ccu CLK_TCON>;
clock-names = "ahb",
"tcon-ch0";
clock-output-names = "tcon-pixel-clock";
resets = <&ccu RST_BUS_LCD>;
reset-names = "lcd";
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
tcon0_in: port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
tcon0_in_be0: endpoint@0 {
reg = <0>;
remote-endpoint = <&be0_out_tcon0>;
};
};
tcon0_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
};
};
};
ccu: clock@1c20000 {
compatible = "allwinner,suniv-f1c100s-ccu";
reg = <0x01c20000 0x400>;
clocks = <&osc24M>, <&osc32k>;
clock-names = "hosc", "losc";
#clock-cells = <1>;
#reset-cells = <1>;
};
intc: interrupt-controller@1c20400 {
compatible = "allwinner,suniv-f1c100s-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
};
pio: pinctrl@1c20800 {
compatible = "allwinner,suniv-f1c100s-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <38>, <39>, <40>;
clocks = <&ccu 37>, <&osc24M>, <&osc32k>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
#gpio-cells = <3>;
uart0_pe_pins: uart0-pe-pins {
pins = "PE0", "PE1";
function = "uart0";
};
// modify by kashine
lcd_rgb666_pins: lcd-rgb666-pins {
pins = "PD0", "PD1", "PD2", "PD3", "PD4",
"PD5", "PD6", "PD7", "PD8", "PD9",
"PD10", "PD11", "PD12", "PD13", "PD14",
"PD15", "PD16", "PD17", "PD18", "PD19",
"PD20", "PD21";
function = "lcd";
};
// modify by kashine
mmc0_pins: mmc0-pins {
pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
function = "mmc0";
};
};
timer@1c20c00 {
compatible = "allwinner,suniv-f1c100s-timer";
reg = <0x01c20c00 0x90>;
interrupts = <13>;
clocks = <&osc24M>;
};
wdt: watchdog@1c20ca0 {
compatible = "allwinner,suniv-f1c100s-wdt",
"allwinner,sun4i-a10-wdt";
reg = <0x01c20ca0 0x20>;
};
uart0: serial@1c25000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c25000 0x400>;
interrupts = <1>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu 38>;
resets = <&ccu 24>;
status = "disabled";
};
uart1: serial@1c25400 {
compatible = "snps,dw-apb-uart";
reg = <0x01c25400 0x400>;
interrupts = <2>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu 39>;
resets = <&ccu 25>;
status = "disabled";
};
uart2: serial@1c25800 {
compatible = "snps,dw-apb-uart";
reg = <0x01c25800 0x400>;
interrupts = <3>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu 40>;
resets = <&ccu 26>;
status = "disabled";
};
// modify by kashine
mmc0: mmc@1c0f000 {
compatible = "allwinner,suniv-f1c100s-mmc",
"allwinner,sun7i-a20-mmc";
reg = <0x01c0f000 0x1000>;
clocks = <&ccu CLK_BUS_MMC0>,
<&ccu CLK_MMC0>,
<&ccu CLK_MMC0_OUTPUT>,
<&ccu CLK_MMC0_SAMPLE>;
clock-names = "ahb",
"mmc",
"output",
"sample";
resets = <&ccu RST_BUS_MMC0>;
reset-names = "ahb";
interrupts = <23>;
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
// modify by kashine
fe0: display-frontend@1e00000 {
compatible = "allwinner,suniv-f1c100s-display-frontend";
reg = <0x01e00000 0x20000>;
interrupts = <30>;
clocks = <&ccu CLK_BUS_DE_FE>, <&ccu CLK_DE_FE>,
<&ccu CLK_DRAM_DE_FE>;
clock-names = "ahb", "mod",
"ram";
resets = <&ccu RST_BUS_DE_FE>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
fe0_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
fe0_out_be0: endpoint@0 {
reg = <0>;
remote-endpoint = <&be0_in_fe0>;
};
};
};
};
// modify by kashine
be0: display-backend@1e60000 {
compatible = "allwinner,suniv-f1c100s-display-backend";
reg = <0x01e60000 0x10000>;
reg-names = "be";
interrupts = <31>;
clocks = <&ccu CLK_BUS_DE_BE>, <&ccu CLK_DE_BE>,
<&ccu CLK_DRAM_DE_BE>;
clock-names = "ahb", "mod",
"ram";
resets = <&ccu RST_BUS_DE_BE>;
reset-names = "be";
assigned-clocks = <&ccu CLK_DE_BE>;
assigned-clock-rates = <300000000>;
ports {
#address-cells = <1>;
#size-cells = <0>;
be0_in: port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
be0_in_fe0: endpoint@0 {
reg = <0>;
remote-endpoint = <&fe0_out_be0>;
};
};
be0_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
be0_out_tcon0: endpoint@0 {
reg = <0>;
remote-endpoint = <&tcon0_in_be0>;
};
};
};
};
// modify by kashine
pwm: pwm@1c21000 {
compatible = "allwinner,sun4i-a10-pwm";
reg = <0x01C21000 0x08>;
clocks = <&osc24M>;
#pwm-cells = <3>;
status = "disabled";
};
};
};
.dts文件做以下修改,添加了一个panel面板设备结点,对应4.3寸RGB屏幕,其compatible属性对应指定的显示驱动,我们将在后面提到;添加了backlight背光调节结点,设置了不同的背光等级;然后打开或修改了.dtsi文件中结点的功能。
// SPDX-License-Identifier: (GPL-2.0+ OR X11)
/*
* Copyright 2018 Icenowy Zheng <icenowy@aosc.io>
*/
/dts-v1/;
#include "suniv-f1c100s.dtsi"
// modify by kashine
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "Lichee Pi Nano";
compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s";
aliases {
serial0 = &uart0;
};
chosen {
stdout-path = "serial0:115200n8";
};
// modify by kashine
panel: panel {//ampire_am800480r3tmqwa1h_mode
compatible = "alientek,alientek_4p3_inch", "simple-panel";
#address-cells = <1>;
#size-cells = <0>;
reset-gpios = <&pio 4 4 GPIO_ACTIVE_LOW>;
power-supply = <®_vcc3v3>;
//backlight = <&backlight>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
panel_input: endpoint@0 {
reg = <0>;
remote-endpoint = <&tcon0_out_lcd>;
};
};
};
// modify by kashine
reg_vcc3v3: vcc3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
// modify by kashine
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 1 500000 0>;
pwm-names = "backlight";
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
};
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pe_pins>;
status = "okay";
};
// modify by kashine all down
&mmc0 {
vmmc-supply = <®_vcc3v3>;
bus-width = <4>;
broken-cd;
status = "okay";
};
&be0 {
status = "okay";
};
&de {
status = "okay";
};
&tcon0 {
pinctrl-names = "default";
pinctrl-0 = <&lcd_rgb666_pins>;
status = "okay";
};
&tcon0_out {
tcon0_out_lcd: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_input>;
};
};
&pio {
pwm1_pin: pwm1_pin {
pins = "PE6";
function = "pwm1";
};
};
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm1_pin>;
status = "okay";
};
2、屏幕信息添加
本文使用正点原子40Pin RGB 屏幕,分辨率为800*480,根据正点原子提供的资料,在内核目录/drivers/gpu/drm/panel/panel_simple.c中,填写屏幕时序信息如下:
// modify by kashine
static const struct drm_display_mode alientek_4p3_inch_mode = {
.clock = 31000,
.hdisplay = 800,
.hsync_start = 800 + 40,
.hsync_end = 800 + 40 + 48,
.htotal = 800 + 40 + 48 + 88,
.vdisplay = 480,
.vsync_start = 480 + 13,
.vsync_end = 480 + 13 + 3,
.vtotal = 480 + 13 + 3 + 32,
.vrefresh = 60,
};
static const struct panel_desc alientek_4p3_inch = {
.modes = &alientek_4p3_inch_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 154,
.height = 85,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
};
首先来解释alientek_4p3_inch_mode结构体中的参数含义,主要为屏幕的时序信息,设置错误可能导致显示错位、不完整。
clock: RGB屏幕需要使用的时钟频率
hdisplay:有效显示区水平像素数量,800*480中的800,对应Active Width
hsync_start:水平同步开始,对应hdispay + HFP
hsync_end:水平同步结束,对应hdisplay + HFP + HSYNC width(HSPW)
htotal:水平总像素,对应hdisplay + HFP + HSYNC width + HBP
vdisplay:垂直显示像素,800*480中的480,对应Active Height
vsync_start:垂直同步开始,对应vdispay + VFP
vsync_end:垂直像素结束,对应vdisplay + VFP + VSYNC width(VSPW)
vtotal:垂直总像素,对应vdisplay + VFP + VSYNC width + VBP
vrefresh:刷新率
原文链接:https://blog.csdn.net/u012794472/article/details/124868025
alientek_4p3_inch结构体主要用来描述所用屏幕的信息,包括显示模式、像素格式等。其中MEDIA_BUS_FMT_RGB666_1X18的含义详见The Linux Kernel documentation。width、height为液晶的尺寸,需要根据屏幕的用户使用手册进行设置,如下图所示为本文使用的ATK4384屏幕尺寸图。
另一处需要修改的地方如下所示,添加设备树对应的设备驱动绑定信息。
.data = &vl050_8048nt_c01,
}, {
.compatible = "winstar,wf35ltiacd",
.data = &winstar_wf35ltiacd,
}, {// modify by kashine
.compatible = "alientek,alientek_4p3_inch",
.data = &alientek_4p3_inch,
},{
/* Must be the last entry */
.compatible = "panel-dpi",
.data = &panel_dpi,
}, {
/* sentinel */
}
3、内核驱动修改
以下为核心内容,本人尝试了坑网、CSDN、荔枝派、芒果派等的众多教程,历经多次内核修改与编译,最终整理出关于F1C200s在Linux5.7.1内核下的RGB驱动修改方法如下。主要修改文件为内核目录/drivers/gpu/drm/sun4i/文件夹下的三个文件,分别为sun4i_tcon.c、sun4i_drv.c、sun4i_backend.c。以下修改内容主要是为了使驱动适配F1C200s这款芯片。
可以根据代码中注释及前后内容,定位三个文件需要修改的地方。
// sun4i_backend.c文件修改
// modify by kashine
static const struct sun4i_backend_quirks suniv_backend_quirks = {
};
static const struct sun4i_backend_quirks sun4i_backend_quirks = {
.needs_output_muxing = true,
};
static const struct sun4i_backend_quirks sun5i_backend_quirks = {
};
static const struct sun4i_backend_quirks sun6i_backend_quirks = {
};
static const struct sun4i_backend_quirks sun7i_backend_quirks = {
.needs_output_muxing = true,
.supports_lowest_plane_alpha = true,
};
static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
.supports_lowest_plane_alpha = true,
};
static const struct sun4i_backend_quirks sun9i_backend_quirks = {
};
static const struct of_device_id sun4i_backend_of_table[] = {
{// modify by kashine
.compatible = "allwinner,suniv-f1c100s-display-backend",
.data = &suniv_backend_quirks,
},
{
.compatible = "allwinner,sun4i-a10-display-backend",
.data = &sun4i_backend_quirks,
},
{
.compatible = "allwinner,sun5i-a13-display-backend",
.data = &sun5i_backend_quirks,
},
{
.compatible = "allwinner,sun6i-a31-display-backend",
.data = &sun6i_backend_quirks,
},
{
.compatible = "allwinner,sun7i-a20-display-backend",
.data = &sun7i_backend_quirks,
},
{
.compatible = "allwinner,sun8i-a23-display-backend",
.data = &sun8i_a33_backend_quirks,
},
{
.compatible = "allwinner,sun8i-a33-display-backend",
.data = &sun8i_a33_backend_quirks,
},
{
.compatible = "allwinner,sun9i-a80-display-backend",
.data = &sun9i_backend_quirks,
},
{ }
};
// sun4i_drv.c文件修改
static bool sun4i_drv_node_is_frontend(struct device_node *node)
{
// modify by kashine
return of_device_is_compatible(node, "allwinner,suniv-f1c100s-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun4i-a10-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun8i-a23-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend");
}
static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,suniv-f1c100s-display-engine" },// modify by kashine
{ .compatible = "allwinner,sun4i-a10-display-engine" },
{ .compatible = "allwinner,sun5i-a10s-display-engine" },
{ .compatible = "allwinner,sun5i-a13-display-engine" },
{ .compatible = "allwinner,sun6i-a31-display-engine" },
{ .compatible = "allwinner,sun6i-a31s-display-engine" },
{ .compatible = "allwinner,sun7i-a20-display-engine" },
{ .compatible = "allwinner,sun8i-a23-display-engine" },
{ .compatible = "allwinner,sun8i-a33-display-engine" },
{ .compatible = "allwinner,sun8i-a83t-display-engine" },
{ .compatible = "allwinner,sun8i-h3-display-engine" },
{ .compatible = "allwinner,sun8i-r40-display-engine" },
{ .compatible = "allwinner,sun8i-v3s-display-engine" },
{ .compatible = "allwinner,sun9i-a80-display-engine" },
{ .compatible = "allwinner,sun50i-a64-display-engine" },
{ .compatible = "allwinner,sun50i-h6-display-engine" },
{ }
};
// sun4i_tcon.c文件修改
// modify by kashine
static const struct sun4i_tcon_quirks suniv_f1c100s_quirks = {
/*
* The F1C100s SoC has a second channel in TCON, but the clock input of
* it is not documented.
*/
.has_channel_0 = true,
//.has_channel_1 = true,
.dclk_min_div = 1,// Linux5.2不需要加,5.7.1不加该代码会白屏
};
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
.has_channel_0 = true,
.has_channel_1 = true,
.dclk_min_div = 4,
.set_mux = sun4i_a10_tcon_set_mux,
};
/* sun4i_drv uses this list to check if a device node is a TCON */
const struct of_device_id sun4i_tcon_of_table[] = {
{.compatible = "allwinner,suniv-f1c100s-tcon", .data = &suniv_f1c100s_quirks },// modify by kashine
{ .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
{ .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
{ .compatible = "allwinner,sun7i-a20-tcon0", .data = &sun7i_a20_tcon0_quirks },
{ .compatible = "allwinner,sun7i-a20-tcon1", .data = &sun7i_a20_quirks },
{ .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
{ .compatible = "allwinner,sun8i-r40-tcon-tv", .data = &sun8i_r40_tv_quirks },
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
{ }
};
4、开机logo显示
使用make menuconfig打开图形化配置界面,打开Bootup logo,其中的三个选项全部选中。
-> Device Drivers
-> Graphics support
-> Bootup logo (LOGO [=y])
-> Standard black and white Linux logo
-> Standard 16-color Linux logo
-> Standard 224-color Linux logo
背光选项记得勾上(其实不勾也可以)。
三、RGB屏幕显示功能测试
修改完上述内核文件后,重新编译,编译所需的时间相比于初次编译要短很多。在uboot的bootargs参数中添加如下内容可使内核输出更多drm相关信息,便于调试:
drm.debug=0x1f debug
如图所示为开发板上电启动过程中RGB屏幕显示的内容,启动时左上角显示Linux logo,符合我们的预期。
进入Debian文件系统后,可以使用如下命令查看日志的输出级别(在Linux中日志一共分为8个等级,数值越小,优先级越高)下面的四个数字是由kernel/printk.c文件中定义的一个数组决定的。
cat /proc/sys/kernel/printk
# 默认输出7 4 1 7
上面四个数字的含别如下:
控制台日志级别:优先级高于该值的消息将被打印至控制台
默认的消息日志级别:将用该优先级来打印没有优先级的消息
最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
默认的控制台日志级别:控制台日志级别的缺省值
如果觉得开机之后输出的日志信息太多,可以使用如下命令修改打印的日志信息级别,减少不必要的信息干扰。
# 屏蔽掉所有的内核printk打印
echo 0 4 1 7 > /proc/sys/kernel/printk
四、屏幕背光调节功能测试
通过PE6管脚输出PWM波,控制屏幕背光引脚,进而控制屏幕亮度,本文在设备树中设置了八个亮度等级,通过在脚本(.sh文件,并chomd权限)中输入以下代码可以控制亮度变化。(这里有个小问题,输入零的时候并没有熄屏,留个小坑吧)
while true
do
for i in {7..1}
do
sleep 0.2
echo $i > /sys/class/backlight/backlight/brightness
done
for j in {1..7}
do
echo $j > /sys/class/backlight/backlight/brightness
sleep 0.2
done
done
五、主要参考内容
2.Lctech Pi(F1C200S)4.3寸(480*272)16位RGB565LCD屏驱动适配 ;
3.解决f1c100s 主线Linux 升级到 4.19 之后的版本没有 framebuffer(fb0)设备问题(Linux5.2);
6.更换正点原子7寸RGB LCD(1024*600),启动失败
7.ttyS、ttySAC、tty、ttyn的区别_HeroKern的博客-CSDN博客_ttytcu0和ttyths0的区别。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)