一、RGBLCD 硬件原理
【正点原子MP157连载】第十八章 RGB LCD彩条显示实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7_正点原子的博客-CSDN博客
ATK7016 时序参数:
二、eLCDIF 接口
eLCDIF 是 I.MX6U 自带的液晶屏幕接口,用于连接 RGB LCD 接口的屏幕。
三、Linux 下 LCD 驱动分析
1、LCD 操作流程
1、初始化 I.MX6U 的 eLCDIF 控制器,重点是 LCD 屏幕宽(width )、高(height )、 hspw 、hbp 、 hfp 、 vspw 、 vbp 和 vfp 等信息。
2、初始化 LCD 像素时钟。
3、设置 RGBLCD 显存。
4、应用程序直接通过操作显存来操作 LCD ,实现在 LCD 上显示字符、图片等信息。
2、Framebuffer 设备
Linux 内核中使用 Framebuffer 提供统一的标准接口显示设备。Framebuffer 翻译过来就是帧缓冲,简称 fb 。fb 是一种机制,将系统中所有跟显示有关的硬件以及软件集合起来,虚拟出一个 fb 设备,当我们编写好 LCD 驱动以后会生成一个名为 /dev/fbX(X=0~n) 的设备,应用程序通过访问 /dev/fbX 这个设备就可以访问 LCD 。
NXP 官方的 Linux 内核默认已经开启了 LCD 驱动,因此我们是可以看到 /dev/fb0 这样一个设备,如下所示:
crw-rw---- 1 root root 29, 0 Jan 1 00:00 /dev/fb0
/dev/fb0 就是 LCD 对应的设备文件, /dev/fb0 是个字符设备,fb 的 file_operations 操作集定义在 drivers/video/fbdev/core/fbmem.c 文件中。
3、驱动分析
1、通过设备树确定驱动文件
设备树信息如下:
// 文件路径:linux-imx-4.1.15\arch\arm\boot\dts\imx6ull.dtsi
lcdif: lcdif@021c8000 {
compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
reg = <0x021c8000 0x4000>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
<&clks IMX6UL_CLK_LCDIF_APB>,
<&clks IMX6UL_CLK_DUMMY>;
clock-names = "pix", "axi", "disp_axi";
status = "disabled";
};
通过 fsl,imx6ul-lcdif 或 fsl,imx28-lcdif 查找驱动文件,驱动文件路径:linux-imx-4.1.15\drivers\video\fbdev\mxsfb.c 。
驱动分析待完成……。
四、重要结构体
1、fb_info
struct fb_info {
atomic_t count;
int node;
int flags;
struct mutex lock;
struct mutex mm_lock;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_monspecs monspecs;
struct work_struct queue;
struct fb_pixmap pixmap;
struct fb_pixmap sprite;
struct fb_cmap cmap;
struct list_head modelist;
struct fb_videomode *mode;
#ifdef CONFIG_FB_BACKLIGHT
struct backlight_device *bl_dev;
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io *fbdefio;
#endif
struct fb_ops *fbops;
struct device *device;
struct device *dev;
int class_flag;
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops;
#endif
char __iomem *screen_base;
unsigned long screen_size;
void *pseudo_palette;
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state;
void *fbcon_par;
void *par;
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[0];
} *apertures;
bool skip_vt_switch;
};
2、mxsfb_info
struct mxsfb_info {
struct fb_info *fb_info;
struct platform_device *pdev;
struct clk *clk_pix;
struct clk *clk_axi;
struct clk *clk_disp_axi;
bool clk_pix_enabled;
bool clk_axi_enabled;
bool clk_disp_axi_enabled;
void __iomem *base;
u32 sync;
unsigned allocated_size;
int enabled;
unsigned ld_intf_width;
unsigned dotclk_delay;
const struct mxsfb_devdata *devdata;
struct regulator *reg_lcd;
bool wait4vsync;
struct completion vsync_complete;
struct completion flip_complete;
int cur_blank;
int restore_blank;
char disp_dev[32];
struct mxc_dispdrv_handle *dispdrv;
int id;
struct fb_var_screeninfo var;
};
五、设备树添加
1、设备树添加说明
Linux 驱动开发 六十二:《mxsfb.txt》翻译_lqonlylove的博客-CSDN博客
Linux 驱动开发 六十三:《display-timing.txt》翻译_lqonlylove的博客-CSDN博客
2、添加设备树
在 lcdif 节点中追加或修改 LCD 时序相关参数,如题内容如下:
lcdif: lcdif@021c8000 {
compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
reg = <0x021c8000 0x4000>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
<&clks IMX6UL_CLK_LCDIF_APB>,
<&clks IMX6UL_CLK_DUMMY>;
clock-names = "pix", "axi", "disp_axi";
status = "disabled";
};
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
display = <&display0>;
status = "okay";
/* 7寸1024*600 */
display0: display {
bits-per-pixel = <32>; // RGB值(RGB888/666)
bus-width = <24>; // 数据线数量
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <51200000>; // 时钟配置
hactive = <1024>; // 水平像素点
vactive = <600>; // 垂直像素点
hfront-porch = <160>; // HFP 配置
hback-porch = <140>; // HBP 配置
hsync-len = <20>; // HSPW 配置
vback-porch = <20>; // VBP 配置
vfront-porch = <12>; // VFP 配置
vsync-len = <3>; // VSPW 配置
hsync-active = <0>; // HSYNC 信号有效电平
vsync-active = <0>; // VSYNC 信号有效电平
de-active = <1>; // DE 信号有效电平
pixelclk-active = <0>; // 数据更新和数据采样有效电平
};
};
};
};
六、LCD 背光配置
1、确定LCD背光使用的 PIN 引脚
通过原理图确定背光使用的 PIN 引脚。LCD 使用引脚为 BLT_PWM (GPIO1_IO08 )。LCD 背光使用 PWM 驱动。
2、设备树配置
pinctrl_pwm1: pwm1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0
>;
};
pwm1: pwm@02080000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02080000 0x4000>;
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM1>,
<&clks IMX6UL_CLK_PWM1>;
clock-names = "ipg", "per";
};
&pwm1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm1>;
status = "okay";
};
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
3、Linux 中相关说明
Linux 驱动开发 六十四:《pwm-backlight.txt》翻译_lqonlylove的博客-CSDN博客
七、特别说明
LCD 驱动 Linux 内核已经写好,我们只需要按照硬件参数配置设备树即可使用。
八、LCD 熄屏关闭
Linux 在 drivers/tty/vt/vt.c 源码中配置 LCD 熄屏时间,配置项 static int blankinterval = 10*60 配置 LCD 熄屏时间,将 blankinterva l 设置为 0,表示 LCD 常亮。
|