uboot下有现成的LCD驱动模板,原来是用于MPC823和PXA250的,我们需要在s3c6410这个ARM11的uboot中增加LCD的驱动,可以在这个基础上修改。具体分以下几步:        1.  修改配置头文件,是整个工程支持LCD。         在修改include/configs/smdk6410.h 增加一行        #define CONFIG_LCD       这行会把common/lcd.c加入编译,同时影响lib_arm/board.c,lib_arm/armlinux.c。在文件cpu/s3c64xx/cpu.c中,还有进入linux内核前的关于lcd控制的准备工作lcd_disable(),lcd_panel_disable()。        2. 修改common/lcd.c       在lcd.c中准备函数calc_fbsize(),这个函数会在armlinux.c中调用,用于计算lcd显示缓冲需要的内存。注意,如果我们使用的现实缓冲比较大,就不能使用这个方法来分配。uboot中malloc函数最大分配的内存,不可能超过uboot使用的总内存512K。如果显示分辨率只有320x240,这个占用内存只有153K,这个方法还是可行的。        先定义一个LCD的显示控制结构,用于各种函数的计算。        typedef struct vidinfo {            ushort    vl_col;        /*每行点数,如320*/            ushort    vl_row;        /*整屏行数,如340 */            ushort    vl_width;    /* 虚拟屏宽度,我们简化,不用虚拟屏*/            ushort    vl_height;    /* 虚拟屏高度*/            u_char    vl_bpix;    /*每点位数,如16*/        } vidinfo_t;        我们使用宏结构定义各种参数:        //1376 //1178#define S3CFB_HFP        52//40    /*前沿点数*/#define S3CFB_HSW        50//48    /* hsync脉冲宽度 */#define S3CFB_HBP        200//240//40    /* 后沿点数 *///805 //807#define S3CFB_VFP        13//13    /* 前沿行数 */#define S3CFB_VSW        1//3    /* vsync脉冲宽度 */#define S3CFB_VBP        25//29    /* 后沿行数 */#define S3CFB_HRES        1024    /* x方向分辨率*/#define S3CFB_VRES        768    /* y方向分辨率*/#define S3CFB_VFRAME_FREQ         60    /* 帧频率*/#define PIXELBITS               16    /*每点使用位数*/#define S3CFB_IVCLK             CFG_LOW  /*VCLK极性控制*/#define S3CFB_IHSYNC            CFG_HIGH /*HSYNC极性控制*/#define S3CFB_IVSYNC            CFG_HIGH /*VSYNC极性控制*/#define S3CFB_IVDEN             CFG_LOW  /*DE 数据有效极性控制*/#define S3CFB_PIXEL_CLOCK    (S3CFB_VFRAME_FREQ * (S3CFB_HFP +S3CFB_HSW + S3CFB_HBP + S3CFB_HRES) * (S3CFB_VFP + S3CFB_VSW + S3CFB_VBP + S3CFB_VRES))        我们使用的LCD比较大,我们直接指定显示缓冲区。#define LCD_FRAMEBUFFER         (TEXT_BASE - 0x300000)            准备参数结构vidinfo_t panel_info = {  S3CFB_HRES,    S3CFB_VRES,             0,             0,     PIXELBITS, };        需要在uboot中,通过计算分配显示缓冲,需要加入下面的宏:DECLARE_GLOBAL_DATA_PTR;        现在我们完成calc_fbsize函数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 LCD_FRAMEBUFFER  size = 4096;  //直接给一个固定值#endif  return size;}        3.  继续修改lcd.c,准备函数lcd_setmem,给board.c调用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 LCD_FRAMEBUFFER        size = 4096;  //直接给一个固定值#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);}        4.  为了简化我们的工作,我们使用linux内核中的头文件,来替换我们重新定义寄存器。        从linux2.6.28文件包中,提取arch/arm/plat-s3c/include/plat/regs-lcd.h       开头部分用下面替换#include #include /***************************************************************************//* LCD Registers for S3C2443/2450/S3C6400/6410 */#define S3C_LCDREG(x)        __REG((x) + ELFIN_LCD_BASE)/* LCD control registers */#define S3C_VIDCON0        S3C_LCDREG(0x00)      /* Video control 0 register */#define S3C_VIDCON1        S3C_LCDREG(0x04)      /* Video control 1 register */    增加MIFPCON_REG 和SPCON_REG寄存器的定义#define MIFPCON_REG                    __REG(0x7410800C)    #define  SEL_BYPASS_MASK             0x00000008       #define SPCON_REG                      __REG(ELFIN_GPIO_BASE + SPCON_OFFSET)   #define LCD_SEL_MASK                 0x00000003            #define RGB_IF_STYLE_MASK            0x00000001     5.  增加函数lcd_disable,lcd_panel_disable用于进入linux内核的准备工作void lcd_disable (void){  S3C_VIDCON0 &= (~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE));}void lcd_Enable (void){  S3C_VIDCON0 |= (S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);}void lcd_panel_disable(void){  MIFPCON_REG |= SEL_BYPASS_MASK;}    6.  准备驱动函数/************************************************************************//* ** GENERIC Initialization Routines                    *//************************************************************************/int drv_lcd_init (void){    device_t lcddev;    int rc;    lcd_base = (void *)(gd->fb_base);#ifdef LCD_FRAMEBUFFER        lcd_base = (void*)LCD_FRAMEBUFFER;#endif    lcd_line_length = (panel_info.vl_col * panel_info.vl_bpix) / 8;        lcd_color_fg = 0xffff;        lcd_color_bg = 0x0000;    lcd_init (lcd_base);        /* LCD initialization */        //画线,测试一下显示效果        lcd_vline(0,0,S3CFB_HRES,0x001f);        lcd_vline(0,S3CFB_VRES-1,S3CFB_HRES,0x07e0);        lcd_hline(0,0,S3CFB_VRES,0xf800);        lcd_hline(S3CFB_HRES-1,0,S3CFB_VRES,0xffff);#ifdef    CONFIG_NO_VIDEO_CONSOLE            return 0;#endif    /* Device initialization */    memset (&lcddev, 0, sizeof (lcddev));    strcpy (lcddev.name, "lcd");    lcddev.ext   = 0;            /* No extensions */    lcddev.flags = DEV_FLAGS_OUTPUT;    /* Output only */    lcddev.putc  = lcd_putc;        /* 'putc' function */    lcddev.puts  = lcd_puts;        /* 'puts' function */    rc = device_register (&lcddev); //如果需要uboot的打印信息使用LCD,需要登记设备。    return (rc == 0) ? 1 : rc;}    7.  准备lcd_init 初始化屏显位置信息,图片等(为简化略过显示图片)static int lcd_init (void *lcdbase){    /* Initialize the lcd controller */    debug ("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);    lcd_ctrl_init (lcdbase);            //lcd_clear (NULL, 1, 1, NULL);    /* dummy args */    //lcd_enable ();    /* Initialize the console */    console_col = 0;#ifdef CONFIG_LCD_INFO_BELOW_LOGO    console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;#else    console_row = 1;    /* leave 1 blank line below logo */#endif    lcd_is_enabled = 1;    return 0;}        8 . 寄存器相关的初始化static int lcd_ctrl_init(void *lcdbase){  ulong freq_lcdclk;  ulong freq_Hclk;  ulong fb_size;  unsigned char nn;  unsigned short *pp;  int i;  //初始化管脚分配  GPICON_REG = 0xaaaaaaaa;  GPIPUD_REG = 0xaaaaaaaa;  GPJCON_REG = 0xaaaaaaaa;  GPJPUD_REG = 0xaaaaaaaa;  lcd_disable();  S3C_WINCON0 &= (~(S3C_WINCONx_ENWIN_F_ENABLE));    按照手册初始化寄存器  // (1)MOFPCON:SEL_BYPASS[3] value@0x7410800C  必须设置为0  MIFPCON_REG &= (~SEL_BYPASS_MASK);  //(2)SPCON:LCD_SEL[1:0]value@0x74F0081A0 选择RGB I/F类型  SPCON_REG &= (~LCD_SEL_MASK);  SPCON_REG |= (RGB_IF_STYLE_MASK);  //(3)VIDCON0:配置视频输出格式  freq_lcdclk = S3CFB_PIXEL_CLOCK;  freq_Hclk = get_HCLK();  nn = (unsigned char)(freq_Hclk / freq_lcdclk) - 1;  if(freq_lcdclk   {    S3C_VIDCON0 = S3C_VIDCON0_INTERLACE_F_PROGRESSIVE + S3C_VIDCON0_VIDOUT_RGB_IF + \            S3C_VIDCON0_PNRMODE_RGB_P + S3C_VIDCON0_CLKVALUP_ST_FRM + S3C_VIDCON0_CLKVAL_F(nn) + \            S3C_VIDCON0_CLKDIR_DIVIDED + S3C_VIDCON0_CLKSEL_F_HCLK;   }else  {    S3C_VIDCON0 = S3C_VIDCON0_INTERLACE_F_PROGRESSIVE + S3C_VIDCON0_VIDOUT_RGB_IF + \            S3C_VIDCON0_PNRMODE_RGB_P + S3C_VIDCON0_CLKVALUP_ST_FRM + S3C_VIDCON0_CLKVAL_F(0) + \            S3C_VIDCON0_CLKDIR_DIRECTED  + S3C_VIDCON0_CLKSEL_F_HCLK;   }  //(4)VIDCON1:RGB I/F 控制信号  nn = 0;  if(S3CFB_IVCLK)  {    nn += S3C_VIDCON1_IVCLK_RISE_EDGE;  }  if(S3CFB_IHSYNC)  {    nn += S3C_VIDCON1_IHSYNC_INVERT;  }  if(S3CFB_IVSYNC)  {    nn += S3C_VIDCON1_IVSYNC_INVERT;  }  if(S3CFB_IVDEN)  {    nn += S3C_VIDCON1_IVDEN_INVERT;  }  S3C_VIDCON1 = (unsigned int)nn;  S3C_VIDCON2 = 0;  //(5)I80IFCONx:i80系统I/F信号控制  //(6)ITUIFCON0:ITU(BT.601)接口控制  //(7)VIDTCONx:视频输出时序和显示尺寸  S3C_VIDTCON0 = S3C_VIDTCON0_VBPD(S3CFB_VBP - 1) | S3C_VIDTCON0_VFPD(S3CFB_VFP - 1) | S3C_VIDTCON0_VSPW(S3CFB_VSW - 1);  S3C_VIDTCON1 = S3C_VIDTCON1_HBPD(S3CFB_HBP - 1) | S3C_VIDTCON1_HFPD(S3CFB_HFP -1) | S3C_VIDTCON1_HSPW(S3CFB_HSW - 1);  S3C_VIDTCON2 = S3C_VIDTCON2_LINEVAL(S3CFB_VRES - 1) | S3C_VIDTCON2_HOZVAL(S3CFB_HRES - 1);  //(8)WINCONx:窗口格式控制,为简化只使用窗口0,不使用双缓冲  S3C_WINCON0 = S3C_WINCONx_BPPMODE_F_16BPP_565;  S3C_WINCON1 = 0;  S3C_WINCON2 = 0;  S3C_WINCON3 = 0;  S3C_WINCON4 = 0;  //(9)VIDOSDxA ,VIDOSDxB:窗口位置控制  S3C_VIDOSD0A = S3C_VIDOSDxA_OSD_LTX_F(0) + S3C_VIDOSDxA_OSD_LTY_F(0);  S3C_VIDOSD0B = S3C_VIDOSDxB_OSD_RBX_F(S3CFB_HRES - 1) | S3C_VIDOSDxB_OSD_RBY_F(S3CFB_VRES - 1);  S3C_VIDOSD0C = S3C_VIDOSD0C_OSDSIZE(S3CFB_HRES*S3CFB_VRES);    S3C_VIDOSD1A = 0;  S3C_VIDOSD1B = 0;  S3C_VIDOSD1C = 0;  S3C_VIDOSD1D = 0;  S3C_VIDOSD2A = 0;  S3C_VIDOSD2B = 0;  S3C_VIDOSD2C = 0;  S3C_VIDOSD2D = 0;  S3C_VIDOSD3A = 0;  S3C_VIDOSD3B = 0;  S3C_VIDOSD3C = 0;  S3C_VIDOSD4A = 0;  S3C_VIDOSD4B = 0;  S3C_VIDOSD4C = 0;  //(10)VIDOSDxC:alpha 值设置  //(11)VIDWxxADDx:源图像地址设置  fb_size = calc_fbsize();#ifdef LCD_FRAMEBUFFER  fb_size =   (panel_info.vl_col * panel_info.vl_bpix) / 8 * panel_info.vl_row;#endif // S3C_VIDW00ADD0B0 = (unsigned int)(lcdbase) | S3C_VIDWxxADD0_VBANK_F((unsigned int)lcdbase);  S3C_VIDW00ADD0B0 = virt_to_phys(lcdbase);  S3C_VIDW00ADD0B1 = 0;  S3C_VIDW01ADD0B0 = 0;  S3C_VIDW01ADD0B1 = 0;  S3C_VIDW02ADD0 = 0;  S3C_VIDW03ADD0 = 0;  S3C_VIDW04ADD0 = 0; // S3C_VIDW00ADD1B0 = S3C_VIDWxxADD1_VBASEL_F((unsigned int)(lcdbase) + fb_size);  S3C_VIDW00ADD1B0 = virt_to_phys((unsigned int)(lcdbase) + fb_size);  S3C_VIDW00ADD1B1 = 0;  S3C_VIDW01ADD1B0 = 0;  S3C_VIDW01ADD1B1 = 0;  S3C_VIDW02ADD1 = 0;  S3C_VIDW03ADD1 = 0;  S3C_VIDW04ADD1 = 0;    S3C_VIDW00ADD2 = S3C_VIDWxxADD2_OFFSIZE_F(0) | (S3C_VIDWxxADD2_PAGEWIDTH_F(panel_info.vl_col*panel_info.vl_bpix/8));  S3C_VIDW01ADD2 = 0;  S3C_VIDW02ADD2 = 0;  S3C_VIDW03ADD2 = 0;  S3C_VIDW04ADD2 = 0;  //(12)WxKEYCONx:色键寄存器  //(13)WINxMAP:窗口颜色控制  //(14)WPALCON:调色板控制  //(15)WxPDATAxx:调色板数据#if 1  memset(lcdbase,0x55,fb_size);//增加一个底色#else  pp = lcdbase;  for(i=0;i  {    *pp = 0xf100;    pp++;   }#endif  lcd_Enable();  S3C_WINCON0 |= S3C_WINCONx_ENWIN_F_ENABLE;  return (0);}    这样屏上应该有显示了,下面仔细根据屏的类型调整宏机构就可以了。
10-25 13:23
查看更多