smdkv210 uboot增加LCD顯示(二)

如果只是簡單的顯示圖片或字符,smdkv210 uboot增加LCD顯示(一)中的方法就可以了,但是要使用console的話

就有另一種方法,主要參考u-boot-2010.09 for mini6410 (add LCD support )

http://blog.chinaunix.net/uid-20543672-id-94391.html

還有u-boot-2009.08在mini2440上的移植(七)---增加LCD顯示功能 

http://blog.163.com/liuqiang_mail@126/blog/static/10996887520117622235857/

其實要在U-boot中添加LCD支持其實很簡單,只要你的CPU支持類似framebuffer的機制,就只要添加一個初始化LCD 控制器和一個GraphicDevice *pGD結構體的代碼就基本可以了。

下圖是LCD驅動軟件分層執行流程示意。可以看到LCD在執行時最終調用的是底層的board_video_init()函數,其主要作用是對LCD控制寄存器進行初始化。可由用戶根據實際LCD硬件編寫。

u-boot-2009.08在mini2440上的移植(七)---增加LCD顯示功能 - singleboy - singleboy的博客

(1)在/drivers/video/下添加一個驅動文件名爲s5pc110_fb.c,將下面內容粘貼進去:

#include <common.h>
 #if defined(CONFIG_VIDEO_S5PC110)
 #include <video_fb.h>
#include "videomodes.h"
#include <regs-fb.h>
#include <s5pc110.h>
/*
 * Export Graphic Device
 */
GraphicDevice smi;
 #define VIDEO_MEM_SIZE  0x200000        /*NEC 4.3 inches: 480x272x16bit = 0x3FC00 bytes  7 inches:800*480*4bytes = 0x177000 bytes*/
//CPU:     S5pc110@1000MHz
//         Fclk = 1000MHz, Hclk = 200MHz, Pclk = 100MHz (ASYNC Mode) 
 extern void board_video_init(GraphicDevice *pGD);
 /*******************************************************************************
 *
 * Init video chip with common Linux graphic modes (lilo)
 */
void *video_hw_init (void)
{
//   s3c64xx_fb * const fb = s3c64xx_get_base_fb();
    GraphicDevice *pGD = (GraphicDevice *)&smi;
    int videomode;
    unsigned long t1, hsynch, vsynch;
    char *penv;
    int tmp, i, bits_per_pixel;
    struct ctfb_res_modes *res_mode;
    struct ctfb_res_modes var_mode;
    int clkval;
//    unsigned char videoout;
     /* Search for video chip */
    printf("Video: ");
   tmp = 0;
          videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
         /* get video mode via environment */
         if ((penv = getenv ("videomode")) != NULL) {
                 /* deceide if it is a string */
                 if (penv[0] <= '9') {
                         videomode = (int) simple_strtoul (penv, NULL, 16);
                         tmp = 1;
                 }
         } else {
                 tmp = 1;
         }
         if (tmp) {
                 /* parameter are vesa modes */
                 /* search params */
                 for (i = 0; i < VESA_MODES_COUNT; i++) {
                         if (vesa_modes[i].vesanr == videomode)
                                 break;
                 }
                 if (i == VESA_MODES_COUNT) {
                         printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
                         i = 0;
                }
                 res_mode =
                         (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
                                                                  resindex];
                 bits_per_pixel = vesa_modes[i].bits_per_pixel;
         } else {
 
                res_mode = (struct ctfb_res_modes *) &var_mode;
                 bits_per_pixel = video_get_params (res_mode, penv);
         }
 
         /* calculate hsynch and vsynch freq (info only) */
         t1 = (res_mode->left_margin + res_mode->xres +
               res_mode->right_margin + res_mode->hsync_len) / 8;
         t1 *= 8;
         t1 *= res_mode->pixclock;
         t1 /= 1000;
         hsynch = 1000000000L / t1;
         t1 *=
                 (res_mode->upper_margin + res_mode->yres +
                  res_mode->lower_margin + res_mode->vsync_len);
         t1 /= 1000;
         vsynch = 1000000000L / t1;
 
         /* fill in Graphic device struct */
         sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
                  res_mode->yres, bits_per_pixel, (hsynch / 1000),
                  (vsynch / 1000));
         printf ("%s\n", pGD->modeIdent);
         pGD->winSizeX = res_mode->xres;
         pGD->winSizeY = res_mode->yres;
         pGD->plnSizeX = res_mode->xres;
         pGD->plnSizeY = res_mode->yres;
             
         switch (bits_per_pixel) {
         case 8:
                 pGD->gdfBytesPP = 1;
                 pGD->gdfIndex = GDF__8BIT_INDEX;
                 break;
         case 15:
                 pGD->gdfBytesPP = 2;
                 pGD->gdfIndex = GDF_15BIT_555RGB;
                 break;
         case 16:
                 pGD->gdfBytesPP = 2;
                 pGD->gdfIndex = GDF_16BIT_565RGB;
                 break;
         case 24:
                 pGD->gdfBytesPP = 3;
                 pGD->gdfIndex = GDF_24BIT_888RGB;
                 break;
case 32:
                 pGD->gdfBytesPP = 4;
                 pGD->gdfIndex = GDF_32BIT_X888RGB;
                 break;
         }
#if 0
         /* statically configure settings for debug*/
        pGD->winSizeX = pGD->plnSizeX = 480;
         pGD->winSizeY = pGD->plnSizeY = 272;
         pGD->gdfBytesPP = 2;
         pGD->gdfIndex = GDF_16BIT_565RGB;
#endif 
         pGD->frameAdrs = LCD_VIDEO_ADDR; //in config file :include/configs/mini6410.h
         pGD->memSize = VIDEO_MEM_SIZE;
         /* Clear video memory */
         memset((void *)pGD->frameAdrs, 0x00, pGD->memSize);
 
         board_video_init(pGD); //in board init file :board/samsung/mini6410/mini6410.c  for gpio etc.

t1 = res_mode->pixclock;
        t1 /= 1000;
        t1 = 1000000000L / t1;
clkval = (CONFIG_SYS_VIDEO_VCLOCK_HZ / t1) - 1; 
// clkval = 1;  //for debug
VIDCON0 = ( VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB_P | 
VIDCON0_CLKVALUP_ALWAYS | VIDCON0_CLKVAL_F(clkval)| 
VIDCON0_CLKDIR_DIVIDED| VIDCON0_CLKSEL_HCLK   );
VIDCON1  = ( VIDCON1_IVSYNC_INVERT | VIDCON1_IHSYNC_INVERT);
VIDTCON0 = ( VIDTCON0_VBPD(res_mode->upper_margin) | 
VIDTCON0_VFPD(res_mode->lower_margin) | 
VIDTCON0_VSPW(res_mode->vsync_len));
VIDTCON1 = ( VIDTCON1_HBPD(res_mode->left_margin) | 
VIDTCON1_HFPD(res_mode->right_margin) |
VIDTCON1_HSPW(res_mode->hsync_len));
  VIDTCON2 = (VIDTCON2_LINEVAL(pGD->winSizeY - 1) | VIDTCON2_HOZVAL(pGD->winSizeX - 1));
#if defined(LCD_VIDEO_BACKGROUND)   
WINCON0  = (WINCON_BPPMODE_16BPP_565 | WINCON_ENWIN_ENABLE | WINCON_HAWSWP_ENABLE);
VIDOSD0A  = (VIDOSD_LEFT_X(0) | VIDOSD_TOP_Y(0));
VIDOSD0B  = (VIDOSD_RIGHT_X(pGD->winSizeX - 1) | VIDOSD_BOTTOM_Y(pGD->winSizeY - 1));
VIDOSD0C  = VIDOSD_SIZE(pGD->winSizeY * pGD->winSizeX);
#endif
WINCON1  = (WINCON_BPPMODE_16BPP_565 | WINCON_ENWIN_ENABLE | WINCON_HAWSWP_ENABLE);
VIDOSD1A  = (VIDOSD_LEFT_X(0) | VIDOSD_TOP_Y(0));
VIDOSD1B  = (VIDOSD_RIGHT_X(pGD->winSizeX - 1) | VIDOSD_BOTTOM_Y(pGD->winSizeY - 1));
#if defined(LCD_VIDEO_BACKGROUND) 
VIDOSD1C  = (VIDOSD_ALPHA0_R(LCD_VIDEO_BACKGROUND_ALPHA) |
VIDOSD_ALPHA0_G(LCD_VIDEO_BACKGROUND_ALPHA) | 
VIDOSD_ALPHA0_B(LCD_VIDEO_BACKGROUND_ALPHA) );
#endif
VIDOSD1D  = VIDOSD_SIZE(pGD->winSizeY * pGD->winSizeX);
WINSHMAP = WINSHMAP_CH_ENABLE(1);  //Enables Channel 1
#if defined(LCD_VIDEO_BACKGROUND)  
/* config  Display framebuffer addr for background*/
         VIDW00ADD0B0 = LCD_VIDEO_BACKGROUND_ADDR;
          /* This marks the end of the frame buffer. */
         VIDW00ADD1B0 = (VIDW00ADD0B0 &0xffffffff) + (pGD->winSizeX+0) * pGD->winSizeY * (pGD->gdfBytesPP);
         VIDW00ADD2= ((pGD->winSizeX * pGD->gdfBytesPP) & 0x1fff);
#endif
/* config  Display framebuffer addr for console*/
         VIDW01ADD0B0 = pGD->frameAdrs;
          /* This marks the end of the frame buffer. */
         VIDW01ADD1B0 = (VIDW01ADD0B0 &0xffffffff) + (pGD->winSizeX+0) * pGD->winSizeY * (pGD->gdfBytesPP);
         VIDW01ADD2= ((pGD->winSizeX * pGD->gdfBytesPP) & 0x1fff);
         /* Enable  Display  */
         VIDCON0 |= (VIDCON0_ENVID_ENABLE | VIDCON0_ENVID_F_ENABLE);   /* ENVID = 1     ENVID_F = 1*/ 
TRIGCON = (TRGMODE_I80 | SWTRGCMD_I80);  //TRIGCON = 3
        /* clear background  
        u16 p,q;
        u32* pBuffer = (u32*)pGD->frameAdrs;
for (p=0; p < pGD->winSizeX; p++)
{
for (q=0; q < pGD->winSizeY; q++)
{
*pBuffer++ = 0x555555;
}
} */
printf("Video: video_hw_init complete \n");
         return ((void*)&smi);
 }
void
video_set_lut (unsigned int index,      /* color number */
                unsigned char r, /* red */
                unsigned char g, /* green */
                unsigned char b  /* blue */
)
{
}

#endif /* CONFIG_VIDEO_S5PC110 */

(2)打開/drivers/video/Makefile,定位到

COBJS-y += videomodes.o
COBJS-y +=s5pc110_fb.o

COBJS := $(COBJS-y)

(3)修改/drivers/video/cfb_console.c,我直接使用了tekkaman ninja的源碼

(4)打開/drivers/video/videomodes.c,修改如下:

  {0x31A, RES_MODE_1280x1024, 16},
 {0x31B, RES_MODE_1280x1024, 24},
{0x211, RES_MODE_240x320, 16},
 {0x212, RES_MODE_800x480, 16},
};
const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
 /* x  y pixclk   le ri  up lo   hs vs  s  vmode */
 {640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
 {800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
 {1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
 {960, 720, 13100, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
 {1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
 {1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
 {240, 320, 90000, 1, 4, 1, 1, 30, 4, 0, FB_VMODE_NONINTERLACED},
 {800, 480, 15151, 16, 48, 6, 4, 32, 0, 0, FB_VMODE_NONINTERLACED},
};

(5)打開/drivers/video/videomodes.h,修改如下:

//#ifndef CONFIG_SYS_DEFAULT_VIDEO_MODE
//#define CONFIG_SYS_DEFAULT_VIDEO_MODE 0x301
#ifndef CFG_SYS_DEFAULT_VIDEO_MODE
#define CFG_SYS_DEFAULT_VIDEO_MODE 0x212
#endif

#define RES_MODE_1280x1024 5
#define RES_MODE_240x320  6
#define RES_MODE_800x480        7
#define RES_MODES_COUNT     8
//#define VESA_MODES_COUNT 19
#define VESA_MODES_COUNT 21

extern const struct ctfb_vesa_modes vesa_modes[];

(6)打開board/samsung/smdkc110/smdkc110.c,修改如下

 int board_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
// S5PC11X_GPIO * const gpio = S5PC11X_GetBase_GPIO();
//init gpio func for LCD
writel(0x10000000, GPBCON);     //GPBCON [31:28]:output [27:0]:input
writel(0x1555,GPBPUD);//GPBPUD GPBPUD[7]:Pull-up/ down disabled GPBPUD[6:0]:Pull-down enabled
writel(0xc000,GPBDRV_SR);//GPBDRV GPBDRV[7]:4x  GPBDRV[6:0]:1x
writel(0x10010000,GPBCON);//GPBCON [31:28],[19:16]:output [27:20],[15:0]:input
writel(0x1455,GPBPUD);//GPBPUD GPBPUD[7],[4]:Pull-up/ down disabled ,GPBPUD[6:5][3:0]:Pull-down enabled
writel(0xc300,GPBDRV_SR);//GPBDRV GPBDRV[7],[4]:4x  GPBDRV[6:5][3:0]:1x
writel(0x10110000,GPBCON);//GPBCON [31:28],[23:20],[19:16]:output [27:24],[15:0]:input
writel(0x1055,GPBPUD);//GPBPUD GPBPUD[7],[5][4]:Pull-up/ down disabled ,GPBPUD[6][3:0]:Pull-down enabled
writel(0xcf00,GPBDRV_SR);//GPBDRV GPBDRV[7],[5],[4]:4x  GPBDRV[6][3:0]:1x
writel(0x1,GPD1CON);//GPD1CON [23:4]:input [3:0]:output
writel(0x54,GPD1PUD);//GPD1PUD GPD1PUD[5:4],[0]:Pull-up/ down disabled ,GPBPUD[3:1]:Pull-down enabled
writel(0x3,GPD1DRV);//GPD1DRV GPD1DRV[0]:4x  GPBDRV[5:1]:1x
writel(0x11,GPD1CON);//GPD1CON [23:8]:input [7:0]:output
writel(0x50,GPD1PUD);//GPD1PUD GPD1PUD[5:4],[1:0]:Pull-up/ down disabled ,GPBPUD[3:2]:Pull-down enabled
writel(0xf,GPD1DRV);//GPD1DRV GPD1DRV[1:0]:4x  GPBDRV[5:2]:1x
writel(0x1001,GPD0CON);//GPD0CON GPD0CON[3],[0]:output GPD0CON[2:1]:input  
writel(0x15,GPD0PUD);//GPD0PUD GPD0PUD[3]:Pull-up/ down disabled,GPD0PUD[2:0]:Pull-down enabled
writel(0xc0,GPD0DRV);//GPD0DRV GPD0DRV[3]:4x,GPD0DRV[2:0]:1x
writel(0x1000010,GPH0CON);// GPH0CON GPH0CON[6],[1]:output,GPH0CON[7],[5:2],[0]:input  
writel(0x4455,GPH0PUD);// GPH0PUD GPH0PUD[6],[4]:Pull-up/ down disabled GPH0PUD[7],[5],[4:0]:Pull-down enabled
writel(0x3000,GPH0DRV);// GPH0DRV GPH0DRV[6]:4x GPH0DRV[7],[5:0]:1x
writel(0x11110000,GPBCON);//GPBCON [31:16]:output [15:0]:input
writel(0x55,GPBPUD);//GPBPUD GPBPUD[7:4]:Pull-up/ down disabled GPBPUD[3:0]:Pull-down enabled
writel(0xff00,GPBDRV_SR);//GPBDRV GPBDRV[7:4]:4x  GPBDRV[3:0]:1x
writel(0x11110100,GPBCON);//GPBCON [31:16],[11:8]:output [15:12],[7:0]:input
writel(0x55,GPBPUD);//GPBPUD GPBPUD[7:4]:Pull-up/ down disabled GPBPUD[3:0]:Pull-down enabled
writel(0xff00,GPBDRV_SR);//GPBDRV GPBDRV[7:4]:4x  GPBDRV[3:0]:1x
writel(0x80,GPBDAT);//GPBDAT GPBDAT[7]=1,GPBDAT[6:0]=0  
writel(0x98,GPBDAT);//GPBDAT GPBDAT[7],[4:3]=1,GPBDAT[6:5],[2:0]=0
writel(0xb9,GPBDAT);//GPBDAT GPBDAT[7],[5:3],[0]=1,GPBDAT[6],[2:1]=0
writel(0xbb,GPBDAT);//GPBDAT GPBDAT[7],[5:3],[1:0]=1,GPBDAT[6],[2]=0
writel(0xbb,GPBDAT);//GPBDAT GPBDAT[7],[5:3],[1:0]=1,GPBDAT[6],[2]=0
writel(0xd,GPD0DAT);//GPD0DAT GPD0DAT[3:2],[0]=1,GPD0DAT[1]=0  
writel(0xd1,GPH0DAT);//GPH0DAT[7:6],[4],[0]=1,GPH0DAT[5],[3:1]=0  
writel(0xfb,GPBDAT);//GPBDAT GPBDAT[7:3],[1:0]=1,GPBDAT[2]=0
writel(0xff,GPBDAT);//GPBDAT GPBDAT[7:0]=1
writel(0x91,GPH0DAT);//GPH0DAT[7],[4],[0]=1,GPH0DAT[6:5],[3:1]=0
writel(0xd1,GPH0DAT);//GPH0DAT[7:6],[4],[0]=1,GPH0DAT[5],[3:1]=0
writel(0xd3,GPH0DAT);//GPH0DAT[7:6],[4],[1:0]=1,GPH0DAT[5],[3:2]=0
writel(0x22222222,GPF0CON);//GPF0CON set GPF0[0:7] as HSYNC,VSYNC,VDEN,VCLK,VD[0:3]
writel(0x0,GPF0PUD);//GPF0PUD set pull-up,down disable
writel(0x22222222,GPF1CON);//set GPF1CON[7:0]  as VD[11:4]
writel(0x0,GPF1PUD);//GPF1PUD set pull-up,down disable
writel(0x22222222,GPF2CON);//set GPF2CON[7:0] as VD[19:12]
writel(0x0,GPF2PUD);//GPF2PUD set pull-up,down disable
writel(0x00002222,GPF3CON);//set GPF3CON[3:0]  as VD[23:20]
writel(0x0,GPF3PUD);//GPF3PUD set pull-up,down disable
//--------- S5PC110 EVT0 needs MAX drive strength---------//
writel(0xffffffff,GPF0DRV);//set GPF0DRV drive strength max by WJ.KIM(09.07.17)
writel(0xffffffff,GPF1DRV);//set GPF1DRV drive strength max by WJ.KIM(09.07.17)
writel(0xffffffff,GPF2DRV);//set GPF2DRV drive strength max by WJ.KIM(09.07.17)
writel(0x3ff,GPF3DRV);//set GPF3DRV drive strength max by WJ.KIM(09.07.17)

//init gpio func for MMC

......

}

//just init some reg for enable LCD 
void board_video_init(GraphicDevice *pGD) 

DISPLAY_CONTROL_REG = 0x2;//DISPLAY_CONTROL output path RGB=FIMD I80=FIMD ITU=FIMD
CLK_SRC1_REG = 0x700000; //CLK_SRC1 fimdclk = EPLL 


(7)修改配置文件/include/configs/smdkv210.h如下:

#if 1
//enable LCD display
#define CONFIG_CMD_BMP 
#define CONFIG_VIDEO 
#define CONFIG_VIDEO_S5PC110  
#define CONFIG_VIDEO_LOGO 
#define VIDEO_FB_16BPP_WORD_SWAP    //for BMP logo 
#define CONFIG_VIDEO_SW_CURSOR 
#define CONFIG_VIDEO_BMP_LOGO
//#define CONFIG_CONSOLE_EXTRA_INFO
//#define CONFIG_CONSOLE_CURSOR
//#define CONFIG_CONSOLE_TIME
#define CONFIG_CFB_CONSOLE
#define CONFIG_SYS_CONSOLE_IS_IN_ENV
//#define CFG_CONSOLE_INFO_QUIET 
//#define VIDEO_FB_LITTLE_ENDIAN 
#define CONFIG_SPLASH_SCREEN 
#define CFG_VIDEO_LOGO_MAX_SIZE         (1024*768+1024+100) /* 100 = slack */ 
#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE  (1024*768+1024+100) /* 100 = slack */
#define CONFIG_VIDEO_BMP_GZIP 
#define CONFIG_CMD_UNZIP   
#define LCD_VIDEO_ADDR         (0x48000000)//0x57a00000 
//#define LCD_VIDEO_BACKGROUND
#define CONFIG_VGA_AS_SINGLE_DEVICE
#define DEBUG_CFB_CONSOLE
#if defined(LCD_VIDEO_BACKGROUND)  
#define LCD_VIDEO_BACKGROUND_ADDR         (0x57900000)
#define LCD_VIDEO_BACKGROUND_LOADADDR         (0x57700000) 
#define LCD_VIDEO_BACKGROUND_LOADSIZE         (0x40000) 
#define LCD_VIDEO_BACKGROUND_ALPHA         (0xa)
#define LCD_VIDEO_BACKGROUND_IN_NAND
#define LCD_VIDEO_BACKGROUND_FLASH_ADDR (0xa0000)
#endif
#define CONFIG_SYS_VIDEO_VCLOCK_HZ (133000000)
//RAM_TEXT = 0x57e00000
#endif  /*enable LCD display*/ 

還有寄存器聲明文件s5pc110.h的修改和lcd寄存器配置的文件reg-fb.h代碼就不列出來了。

reg-fb.h是從內核代碼中拷過來的linux/arch/arm/plat-s5p/include/plat/regs-fb.h。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章