【正点原子MP157连载】第十八章 RGB LCD彩条显示实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7_正点原子的博客-CSDN博客
eLCDIF
是 I.MX6U
自带的液晶屏幕接口,用于连接 RGB LCD
接口的屏幕。
1、初始化 I.MX6U
的 eLCDIF
控制器,重点是 LCD
屏幕宽(width
)、高(height
)、 hspw
、hbp
、 hfp
、 vspw
、 vbp
和 vfp
等信息。
2、初始化 LCD
像素时钟。
3、设置 RGBLCD
显存。
4、应用程序直接通过操作显存来操作 LCD
,实现在 LCD
上显示字符、图片等信息。
Linux
内核中使用 Framebuffer
提供统一的标准接口显示设备。Framebuffer
翻译过来就是帧缓冲,简称 fb
。fb
是一种机制,将系统中所有跟显示有关的硬件以及软件集合起来,虚拟出一个 fb
设备,当我们编写好 LCD
驱动以后会生成一个名为 /dev/fbX(X=0~n)
的设备,应用程序通过访问 /dev/fbX
这个设备就可以访问 LCD
。
NXP
官方的 Linux
内核默认已经开启了 LCD
驱动,因此我们是可以看到 /dev/fb0
这样一个设备,如下所示:
# ls -l /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
文件中。
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
。
驱动分析待完成……。
struct fb_info {
atomic_t count;
int node;
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
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; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
/* we need the PCI or similar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[0];
} *apertures;
bool skip_vt_switch; /* no VT switch on suspend/resume required */
};
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; /* registers */
u32 sync; /* record display timing polarities */
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;
};
Linux 驱动开发 六十二:《mxsfb.txt》翻译_lqonlylove的博客-CSDN博客
Linux 驱动开发 六十三:《display-timing.txt》翻译_lqonlylove的博客-CSDN博客
在 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>; // 数据更新和数据采样有效电平
};
};
};
};
通过原理图确定背光使用的 PIN
引脚。LCD
使用引脚为 BLT_PWM
(GPIO1_IO08
)。LCD
背光使用 PWM
驱动。
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";
#pwm-cells = <2>;
};
&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";
};
Linux 驱动开发 六十四:《pwm-backlight.txt》翻译_lqonlylove的博客-CSDN博客
LCD
驱动 Linux
内核已经写好,我们只需要按照硬件参数配置设备树即可使用。
Linux
在 drivers/tty/vt/vt.c
源码中配置 LCD
熄屏时间,配置项 static int blankinterval = 10*60
配置 LCD
熄屏时间,将 blankinterva
l 设置为 0,表示 LCD
常亮。