使用参数设置LCD控制器
根据芯片手册,一个一个设置寄存器:
- Framebuffer地址设置(基地址)
- Framebuffer中数据格式设置
- LCD时序参数设置
- LCD引脚极性设置
主要是根据imx6ull的芯片手册一个一个设置相关的寄存器,也没有什么取巧的办法。
static void lcd_controller_enable(struct imx6ull_lcdif *lcdif)
{
lcdif->CTRL |= (1<<0);
}
static int lcd_controller_init(struct imx6ull_lcdif *lcdif,
struct display_timing *dt, int lcd_bpp, int fb_bpp,
unsigned int fb_phy)
{
int lcd_data_bus_width;
int fb_width;
int vsync_pol = 0;
int hsync_pol = 0;
int dotclk_pol = 0;
int de_pol = 0;
switch(lcd_bpp) {
case 16:
lcd_data_bus_width = 0x0;
break;
case 8:
lcd_data_bus_width = 0x1;
break;
case 18:
lcd_data_bus_width = 0x2;
break;
case 24:
lcd_data_bus_width = 0x3;
break;
default:
lcd_data_bus_width = 0x0;
break;
}
switch(fb_bpp) {
case 16:
fb_width = 0x0;
break;
case 8:
fb_width = 0x1;
break;
case 18:
fb_width = 0x2;
break;
case 24:
case 32:
fb_width = 0x3;
break;
default:
fb_width = 0x0;
break;
}
/*
* 初始化LCD控制器的CTRL寄存器
* [19] : 1 : DOTCLK和DVI modes需要设置为1
* [17] : 1 : 设置为1工作在DOTCLK模式
* [15:14] : 00 : 输入数据不交换(小端模式)默认就为0,不需设置
* [13:12] : 00 : CSC数据不交换(小端模式)默认就为0,不需设置
* [11:10] : 11 : 数据总线为24bit
* [9:8] 根据显示屏资源文件bpp来设置:8位0x1 , 16位0x0 ,24位0x3
* [5] : 1 : 设置elcdif工作在主机模式
* [1] : 0 : 24位数据均是有效数据,默认就为0,不需设置
*/
lcdif->CTRL = (0<<30) | (0<<29) | (0<<28) | (1<<19) | (1<<17) | (lcd_data_bus_width << 10) |\
(fb_width << 8) | (1<<5);
/*
* 设置ELCDIF的寄存器CTRL1
* 根据bpp设置,bpp为24或32才设置
* [19:16] : 111 :表示ARGB传输格式模式下,传输24位无压缩数据,A通道不用传输)
*/
if(fb_bpp == 24 || fb_bpp == 32) {
lcdif->CTRL1 &= ~(0xf << 16);
lcdif->CTRL1 |= (0x7 << 16);
} else {
lcdif->CTRL1 |= (0xf << 16);
}
/*
* 设置ELCDIF的寄存器TRANSFER_COUNT寄存器
* [31:16] : 垂直方向上的像素个数
* [15:0] : 水平方向上的像素个数
*/
lcdif->TRANSFER_COUNT = (dt->vactive.typ << 16 )| (dt->hactive.typ<<0);
if(dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
hsync_pol = 1;
if(dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
vsync_pol = 1;
if(dt->flags & DISPLAY_FLAGS_DE_HIGH)
de_pol = 1;
if(dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
dotclk_pol = 1;
/*
* 设置ELCDIF的VDCTRL0寄存器
* [29] 0 : VSYNC输出 ,默认为0,无需设置
* [28] 1 : 在DOTCLK模式下,设置1硬件会产生使能ENABLE输出
* [27] 0 : VSYNC低电平有效 ,根据屏幕配置文件将其设置为0
* [26] 0 : HSYNC低电平有效 , 根据屏幕配置文件将其设置为0
* [25] 1 : DOTCLK下降沿有效 ,根据屏幕配置文件将其设置为1
* [24] 1 : ENABLE信号高电平有效,根据屏幕配置文件将其设置为1
* [21] 1 : 帧同步周期单位,DOTCLK mode设置为1
* [20] 1 : 帧同步脉冲宽度单位,DOTCLK mode设置为1
* [17:0] : vysnc脉冲宽度
*/
lcdif->VDCTRL0 = (1 << 28) | (vsync_pol << 27) | (hsync_pol << 26) | (dotclk_pol << 25) | (de_pol << 24) | (1<<21) |
(1<<20) | (dt->vsync_len.typ << 0);
/*
* 设置ELCDIF的VDCTRL1寄存器
* 设置垂直方向的总周期:上黑框tvb+垂直同步脉冲tvp+垂直有效高度yres+下黑框tvf
*/
lcdif->VDCTRL1 = dt->vback_porch.typ + dt->vsync_len.typ + dt->vactive.typ + dt->vfront_porch.typ;
/*
* 设置ELCDIF的VDCTRL2寄存器
* [18:31] : 水平同步信号脉冲宽度
* [17: 0] : 水平方向总周期
* 设置水平方向的总周期:左黑框thb+水平同步脉冲thp+水平有效高度xres+右黑框thf
*/
lcdif->VDCTRL2 = (dt->hsync_len.typ << 18)| (dt->hback_porch.typ + dt->hsync_len.typ + dt->hactive.typ + dt->hfront_porch.typ) << 0;
/*
* 设置ELCDIF的VDCTRL3寄存器
* [27:16] :水平方向上的等待时钟数 =thb + thp
* [15:0] : 垂直方向上的等待时钟数 = tvb + tvp
*/
lcdif->VDCTRL3 = (dt->hback_porch.typ + dt->hsync_len.typ) << 16 |
((dt->vback_porch.typ + dt->vsync_len.typ) << 0);
/*
* 设置ELCDIF的VDCTRL4寄存器
* [18] 使用VSHYNC、HSYNC、DOTCLK模式此为置1
* [17:0] : 水平方向的宽度
*/
lcdif->VDCTRL4 = (1 << 18) | (dt->hactive.typ);
/*
* 设置ELCDIF的CUR_BUF和NEXT_BUF寄存器
* CUR_BUF : 当前显存地址
* NEXT_BUF : 下一帧显存地址
* 方便运算,都设置为同一个显存地址
*/
lcdif->CUR_BUF = fb_phy;
lcdif->NEXT_BUF = fb_phy;
return 0;
}
使能LCD函数
static void lcd_controller_enable(struct imx6ull_lcdif *lcdif)
{
lcdif->CTRL |= (1<<0);
}
在probe函数调用函数
probe:
{
//...
lcd_controller_init(lcdif, dt, bits_per_pixel, 16, phy_addr);
lcd_controller_enable(lcdif);
//...
}