华天正smdkv210开发板的自带的uboot没有加入LCD显示功能,需要用串口进行交互,给烧写系统带来麻烦。
所以考虑修改uboot源码增加LCD显示和按键驱动,使得板子可以不用串口也能烧写系统。开发板用的是7寸
800*480电容屏。
在此过程中我主要参考了两篇文章,一篇文章是简单的LCD驱动,对应的配置是 CONFIG_LCD,核心源码是
/common/lcd.c ; 另一篇是带console的驱动,对应CONFIG_VIDEO,核心源码是/drivers/video/cfb_console.c。
这两个也是我移植过程中经历的两个阶段,先介绍简单的LCD驱动。主要参考文章
s3c6410 LCD 在uboot下的驱动http://hi.baidu.com/sundongxia2008/blog/item/8a43f9470f01399eb2b7dc97.html
由于没有LCD的datasheet,得不到时序参数,在仿照这篇文章移植后没有任何显示,后来在开发板自带的uboot
源码中找到了一个lcd驱动,/cpu/s5pc11x/fimd.c,调用里面的LCD初始化代码修改lcd.c,实现lcd刷蓝色背景,在
指定位置显示字符。lcd.c源码如下:
/*
* Common LCD routines for supported CPUs
*
*/
/************************************************************************/
/* ** HEADER FILES */
/************************************************************************/
/* #define DEBUG */
#include <config.h>
#include <common.h>
#include <command.h>
#include <version.h>
#include <stdarg.h>
#include <linux/types.h>
#include <devices.h>
#if defined(CONFIG_POST)
#include <post.h>
#endif
#include <lcd.h>
#include <watchdog.h>
#ifdef CONFIG_LCD
/************************************************************************/
/* ** FONT DATA */
/************************************************************************/
#include <fonts.h> /* Get font data, width and height*/
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_BGCOLOR 0x1428A0
#define LCD_SETCURSOR(Xpos,Ypos) (CFG_LCD_FBUFFER + Xpos*LCD_WIDTH*4 + Ypos*4)
static unsigned int TextColor = 0x0000;
static unsigned int BackColor = LCD_BGCOLOR;
void LCD_Initialize_NONAME1(void); //fimd.c中的LCD初始化函数
/*
* Frame buffer memory information
*/
//void *lcd_base; /* Start of framebuffer memory*/
static int lcd_init ();
void lcd_Enable (void);
/************************************************************************/
/* ** GENERIC Initialization Routines */
/************************************************************************/
int drv_lcd_init (void)
{
struct device_t lcddev;
int rc;
// lcd_base = (void*)CFG_LCD_FBUFFER;
lcd_init (); /* LCD initialization */
#ifdef CONFIG_NO_VIDEO_CONSOLE
return 0;
#endif
// Device initialization
memset (&lcddev, 0, sizeof (lcddev));
strcpy (lcddev.name, "lcd");
lcddev.ext = 0;
lcddev.flags = DEV_FLAGS_OUTPUT;
lcddev.putc = lcd_putc;
lcddev.puts = lcd_puts;
rc = device_register (&lcddev); //重定向输出信息
return (rc == 0) ? 1 : rc;
}
/*----------------------------------------------------------------------*/
static int lcd_init ()
{
/* Initialize the lcd controller */
printf("LCD Initializing......");
LCD_Initialize_NONAME1();
printf("complete\n");
LCD_clear(); //刷蓝色背景色
LCD_DisplayChar(0,0,'E'); //在(0,0)处写字母”E”
return 0;
}
void LCD_DrawChar(u16 Xpos, u16 Ypos, uc16 *c)
{
u32 index = 0, i = 0;
u16 Xaddress = 0;
Xaddress = Xpos;
u32* pBuffer = (u32*)LCD_SETCURSOR(Xaddress, Ypos);
for(index = 0; index < 24; index++)
{
for(i = 0; i < 16; i++)
{
if((c[index] & (1 << i)) == 0x00)
{
*pBuffer++ = BackColor;
}
else
{
*pBuffer++ = TextColor;
}
}
Xaddress++;
pBuffer = (u32*)LCD_SETCURSOR(Xaddress, Ypos);
}
}
void LCD_DisplayChar(u16 Line, u16 Column, u8 Ascii)
{
Ascii -= 32;
LCD_DrawChar(Line, Column, &ASCII_Table[Ascii * 24]);
}
void LCD_clear()
{
u16 i, j;
u32* pBuffer = (u32*)CFG_LCD_FBUFFER;
for (i=0; i < LCD_HEIGHT; i++)
{
for (j=0; j < LCD_WIDTH; j++)
{
*pBuffer++ = BackColor;
}
}
}
ulong calc_fbsize (void)
{
ulong size;
int line_length = (panel_info.vl_col * panel_info.vl_bpix) / 8;
size = line_length * panel_info.vl_row;
#ifdef CFG_LCD_FBUFFER
size = 1536000;
#endif
return size;
}
/************************************************************************/
/* ** ROM capable initialization part - needed to reserve FB memory*/
/************************************************************************/
/*
* This is called early in the system initialization to grab memory
* for the LCD controller.
* Returns new address for monitor, after reserving LCD buffer memory
*
* Note that this is running from ROM, so no write access to global data.
*/
ulong lcd_setmem (ulong addr)
{
ulong size;
int line_length = (panel_info.vl_col * panel_info.vl_bpix) / 8;
debug ("LCD panel info: %d x %d, %d bit/pix\n",
panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );
size = line_length * panel_info.vl_row;
#ifdef CFG_LCD_FBUFFER
size = 1536000; //800*480*4 bytes
#endif
/* Round up to nearest full page */
size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
/* Allocate pages for the frame buffer. */
addr -= size;
debug ("Reserving %ldk for LCD Framebuffer at: %08lx\n", size>>10, addr);
return (addr);
}
#endif /* CONFIG_LCD */
调用fimd.c中的初始化代码LCD有显示,但是不能在指定位置显示数据,是lcd配置的问题,原来它的配置是1366*768.
对照s5pc210处理器的datasheet,给LCD初始化过程做注释,代码如下:
void LCD_Initialize_NONAME1(void)
{
u32 uFbAddr = CFG_LCD_FBUFFER;
u32 i;
u32* pBuffer = (u32*)uFbAddr;
Outp32(0xe0200040, 0x10000000); //GPBCON [31:28]:output [27:0]:input
Outp32(0xe0200048, 0x1555); //GPBPUD GPBPUD[7]:Pull-up/ down disabled GPBPUD[6:0]:Pull-down enabled
Outp32(0xe020004c, 0xc000); //GPBDRV GPBDRV[7]:4x GPBDRV[6:0]:1x
Outp32(0xe0200040, 0x10010000); //GPBCON [31:28],[19:16]:output [27:20],[15:0]:input
Outp32(0xe0200048, 0x1455); //GPBPUD GPBPUD[7],[4]:Pull-up/ down disabled ,GPBPUD[6:5][3:0]:Pull-down enabled
Outp32(0xe020004c, 0xc300); //GPBDRV GPBDRV[7],[4]:4x GPBDRV[6:5][3:0]:1x
Outp32(0xe0200040, 0x10110000); //GPBCON [31:28],[23:20],[19:16]:output [27:24],[15:0]:input
Outp32(0xe0200048, 0x1055); //GPBPUD GPBPUD[7],[5][4]:Pull-up/ down disabled ,GPBPUD[6][3:0]:Pull-down enabled
Outp32(0xe020004c, 0xcf00); //GPBDRV GPBDRV[7],[5],[4]:4x GPBDRV[6][3:0]:1x
Outp32(0xe02000c0, 0x1); //GPD1CON [23:4]:input [3:0]:output
Outp32(0xe02000c8, 0x54); //GPD1PUD GPD1PUD[5:4],[0]:Pull-up/ down disabled ,GPBPUD[3:1]:Pull-down enabled
Outp32(0xe02000cc, 0x3); //GPD1DRV GPD1DRV[0]:4x GPBDRV[5:1]:1x
Outp32(0xe02000c0, 0x11); //GPD1CON [23:8]:input [7:0]:output
Outp32(0xe02000c8, 0x50); //GPD1PUD GPD1PUD[5:4],[1:0]:Pull-up/ down disabled ,GPBPUD[3:2]:Pull-down enabled
Outp32(0xe02000cc, 0xf); //GPD1DRV GPD1DRV[1:0]:4x GPBDRV[5:2]:1x
Outp32(0xe02000a0, 0x1001); //GPD0CON GPD0CON[3],[0]:output GPD0CON[2:1]:input
Outp32(0xe02000a8, 0x15); //GPD0PUD GPD0PUD[3]:Pull-up/ down disabled,GPD0PUD[2:0]:Pull-down enabled
Outp32(0xe02000ac, 0xc0); //GPD0DRV GPD0DRV[3]:4x,GPD0DRV[2:0]:1x
Outp32(0xe0200c00, 0x1000010); // GPH0CON GPH0CON[6],[1]:output,GPH0CON[7],[5:2],[0]:input
Outp32(0xe0200c08, 0x4455); // GPH0PUD GPH0PUD[6],[4]:Pull-up/ down disabled GPH0PUD[7],[5],[4:0]:Pull-down enabled
Outp32(0xe0200c0c, 0x3000); // GPH0DRV GPH0DRV[6]:4x GPH0DRV[7],[5:0]:1x
Outp32(0xe0200040, 0x11110000); //GPBCON [31:16]:output [15:0]:input
Outp32(0xe0200048, 0x55); //GPBPUD GPBPUD[7:4]:Pull-up/ down disabled GPBPUD[3:0]:Pull-down enabled
Outp32(0xe020004c, 0xff00); //GPBDRV GPBDRV[7:4]:4x GPBDRV[3:0]:1x
Outp32(0xe0200040, 0x11110100); //GPBCON [31:16],[11:8]:output [15:12],[7:0]:input
Outp32(0xe0200048, 0x55); //GPBPUD GPBPUD[7:4]:Pull-up/ down disabled GPBPUD[3:0]:Pull-down enabled
Outp32(0xe020004c, 0xff00); //GPBDRV GPBDRV[7:4]:4x GPBDRV[3:0]:1x
Outp32(0xe0200044, 0x80); //GPBDAT GPBDAT[7]=1,GPBDAT[6:0]=0
Outp32(0xe0200044, 0x98); //GPBDAT GPBDAT[7],[4:3]=1,GPBDAT[6:5],[2:0]=0
Outp32(0xe0200044, 0xb9); //GPBDAT GPBDAT[7],[5:3],[0]=1,GPBDAT[6],[2:1]=0
Outp32(0xe0200044, 0xbb); //GPBDAT GPBDAT[7],[5:3],[1:0]=1,GPBDAT[6],[2]=0
Outp32(0xe0200044, 0xbb); //GPBDAT GPBDAT[7],[5:3],[1:0]=1,GPBDAT[6],[2]=0
Outp32(0xe02000a4, 0xd); //GPD0DAT GPD0DAT[3:2],[0]=1,GPD0DAT[1]=0
Outp32(0xe0200c04, 0xd1); //GPH0DAT[7:6],[4],[0]=1,GPH0DAT[5],[3:1]=0
Outp32(0xe0200044, 0xfb); //GPBDAT GPBDAT[7:3],[1:0]=1,GPBDAT[2]=0
Outp32(0xe0200044, 0xff); //GPBDAT GPBDAT[7:0]=1
Outp32(0xe0200c04, 0x91); //GPH0DAT[7],[4],[0]=1,GPH0DAT[6:5],[3:1]=0
Outp32(0xe0200c04, 0xd1); //GPH0DAT[7:6],[4],[0]=1,GPH0DAT[5],[3:1]=0
Outp32(0xe0200c04, 0xd3); //GPH0DAT[7:6],[4],[1:0]=1,GPH0DAT[5],[3:2]=0
Outp32(0xe0200120, 0x22222222);//set GPF0[0:7] as HSYNC,VSYNC,VDEN,VCLK,VD[0:3]
Outp32(0xe0200128,0x0);//set pull-up,down disable
Outp32(0xe0200140, 0x22222222);//set GPF1CON[7:0] as VD[11:4]
Outp32(0xe0200148,0x0);//set pull-up,down disable
Outp32(0xe0200160, 0x22222222);//set GPF2CON[7:0] as VD[19:12]
Outp32(0xe0200168,0x0);//set pull-up,down disable
Outp32(0xe0200180, 0x00002222);//set GPF3CON[3:0] as VD[23:20]
Outp32(0xe0200188,0x0);//set pull-up,down disable
//--------- S5PC110 EVT0 needs MAX drive strength---------//
Outp32(0xe020012c,0xffffffff);//set GPF0 drive strength max by WJ.KIM(09.07.17)
Outp32(0xe020014c,0xffffffff);//set GPF1 drive strength max by WJ.KIM(09.07.17)
Outp32(0xe020016c,0xffffffff);//set GPF2 drive strength max by WJ.KIM(09.07.17)
Outp32(0xe020018c,0x3ff);//set GPF3 drive strength max by WJ.KIM(09.07.17)
Outp32(0xe0107008,0x2); //DISPLAY_CONTROL output path RGB=FIMD I80=FIMD ITU=FIMD
Outp32(0xe0100204,0x700000); //CLK_SRC1 fimdclk = EPLL
Outp32(0xf8000004, 0x60); //VIDCON1 HSYNC pulse Inverted,VSYNC pulse Inverted
// Outp32(0xf8000010, 0xe0e0305); //VIDTCON0 VBPDE=14,VBPD=14,VFPD=3,VSPW=5
Outp32(0xf8000010, 0x60400); //VIDTCON0 VBPDE=0,VBPD=6,VFPD=4,VSPW=0
Outp32(0xf8000014, 0x3103020); //VIDTCON1 VFPDE=3,HBPD=16,HFPD=48,HSPW=32
// Outp32(0xf8000170, 0x0); //DITHMODE Disables dithering
Outp32(0xf8000018, 0xefb1f); //VIDTCON2 0xefb1f:HOZVAL=799 LINEVAL=479,800*480; 0x17fd55:HOZVAL=1365 LINEVAL=767,1366*768;
// Outp32(0xf8000000, 0x0); //VIDCON0 RGB interface 0 + RGB parallel format + Normal: RGBORDER[2] @VIDCON3 + VCLK Free Run :Normal mode
//video clock source:HCLK
// Outp32(0xf8000000, 0x254); //VIDCON0
// Outp32(0xf8000130, 0x20); //VIDINTCON0 FIFO Interrupt Window 0 control = enables
/* Outp32(0xf8000020, 0x0); //WINCON0 Window 0 Buffer set 0
Outp32(0xf8000024, 0x0); //WINCON1 Window 1 Buffer set 0
Outp32(0xf8000028, 0x0); //WINCON2 Window 2 Buffer set 0
Outp32(0xf800002c, 0x0); //WINCON3 Window 3 Buffer set 0
Outp32(0xf8000030, 0x0); //WINCON4 Window 4 Buffer set 0
Outp32(0xf8000034, 0x0);
Outp32(0xf8000180, 0x0);
Outp32(0xf8000184, 0x0);
Outp32(0xf8000188, 0x0);
Outp32(0xf800018c, 0x0);
Outp32(0xf8000190, 0x0);
Outp32(0xf8000140, 0x0);
Outp32(0xf8000148, 0x0);
Outp32(0xf8000150, 0x0);
Outp32(0xf8000158, 0x0);
Outp32(0xf8000058, 0x0);
Outp32(0xf8000208, 0x0);
Outp32(0xf800020c, 0x0);
Outp32(0xf8000068, 0x0);
Outp32(0xf8000210, 0x0);
Outp32(0xf8000214, 0x0);
Outp32(0xf8000078, 0x0);
Outp32(0xf8000218, 0x0);
Outp32(0xf800021c, 0x0);
Outp32(0xf8000088, 0x0);
Outp32(0xf8000220, 0x0);
Outp32(0xf8000224, 0x0); */
// Outp32(0xf8000260, 0x1); //BLENDCON BLEND_NEW=8-bit alpha value
// Outp32(0xf8000200, 0xffffff); //VIDW0ALPHA0 Window 0 Alpha0
// Outp32(0xf8000204, 0xffffff); //VIDW0ALPHA1 Window 0 Alpha1
// Outp32(0xf8000034, 0x0);
// Outp32(0xf8000020, 0x802c);
Outp32(0xf80000a0, uFbAddr + 0x00000000);
Outp32(0xf80000d0, uFbAddr + 0x00177000); //buffer size 0x00177000:800*480*4 0x00400800:1366*768*4
// Outp32(0xf80000a4, uFbAddr + 0x00000000);
// Outp32(0xf80000d4, uFbAddr + 0x00400800);
// Outp32(0xf80020a0, uFbAddr + 0x00000000);
// Outp32(0xf80020d0, uFbAddr + 0x00400800);
Outp32(0xf8000100, 0xc80); //VIDW00ADD2 0xc80:PAGEWIDTH_F=800*4 0x1558:PAGEWIDTH_F=1366*4
Outp32(0xf8000040, 0x0); //VIDOSD0A 配置窗口位置寄存器A 和 B win0左上角的X、Y坐标(0,0)
Outp32(0xf8000044, 0x18f9df);//VIDOSD0B win0右下角角的X、Y坐标(799,479)
Outp32(0xf8000048, 0x5dc00); //VIDOSD0C 0x5dc00:OSDSIZE=800*480 0x100200:OSDSIZE=1366*768
// Outp32(0xf8000020, 0x802d);
// Outp32(0xf8000034, 0x1);
Outp32(0xf8000020, 0x802d); //WINCON0 ENWIN_F=1,ALPHA_SEL_F=0,BPPMODE_F=Unpacked 24 bpp,WSWP_F =1
Outp32(0xf8000034, 0x1); //VIDOSD0C C0_EN_F=Enables Channel 0
// Outp32(0xf8000000, 0x257);
// Outp32(0xf8000000, 0x57); //===> MPLL should be 667 !!!!
Outp32(0xf8000000, 0x53); //ENVID_F=1,ENVID=1,CLKDIR=Divided by CLKVAL_F ,CLKVAL_F=1
Outp32(0xf80001a4, 0x3); //TRIGCON
// LCD_setprogress(0);
}
原来代码中有些配置是重复的,已经注释掉了,可以正常显示。