注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

deisp的博客

 
 
 

日志

 
 

三星的LTV350QV-F05-LCD  

2008-02-14 12:24:34|  分类: 驱动移植 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 [这个贴子最后由seasea在 2007/01/30 07:47pm 第 1 次编辑]

lcd上可以看到小企鹅了.在这个论坛上受益颇多,在此分享自己的一点经验,希望对初学者有些帮助.
我的板子是自己做的,2410,lcd用的是三星的LTV350QV-F05.刚开始硬件出了一堆问题,一一解决后就开始移植驱动了.内核是2.6.14.
这款lcd的特点是驱动ic内置在lcd模块上,所以不用外接lpc3600等驱动ic.它提供一个60pin的软平线接口出来.这个接口和2410可以直接连接.接口内包含一个spi口,用来给lcd模块写寄存器,初始化lcd模块.因此,2.6.14的驱动内需要加上一些代码来完成这项工作.可能某些lcd是不需要这个初始化的,那样的话移植会更简单.
移植修改的地方如下:
1.在mach-smdk2410.c中添加平台信息.主要是设置一个结构体.
//-------------added by hjcai
static struct s3c2410fb_mach_info smdk2410_lcd_platdata = {
.width= 320,
.height= 240,
.xres = {
.defval= 320,
.min= 320,
.max= 320,
},
.yres = {
.defval= 240,
.min= 240,
.max= 240,
},
.bpp = {
.defval= 16,
.min= 16,
.max= 16,
},
.regs = {
.lcdcon1= S3C2410_LCDCON1_TFT16BPP | S3C2410_LCDCON1_TFT | S3C2410_LCDCON1_CLKVAL(4),
.lcdcon2= S3C2410_LCDCON2_LINEVAL(239) | S3C2410_LCDCON2_VBPD(5) | S3C2410_LCDCON2_VFPD(4) | S3C2410_LCDCON2_VSPW(3),
.lcdcon3= S3C2410_LCDCON3_HOZVAL(319) | S3C2410_LCDCON3_HBPD(22) | S3C2410_LCDCON3_HFPD(20),
.lcdcon4= S3C2410_LCDCON4_HSPW(19) | S3C2410_LCDCON4_MVAL(13),
.lcdcon5= S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_HWSWP | S3C2410_LCDCON5_INVVCLK|S3C2410_LCDCON5_INVVLINE|S3C2410_LCDCON5_INVVFRAME|S3C2410_LCDCON5_PWREN,
},
.gpcup= 0xFFFFFFFF,
.gpcup_mask= 0xFFFFFFFF,
.gpccon= 0xaaaaaaaa,
.gpccon_mask= 0xFFFFFFFF,
.gpdup= 0xFFFFFFFF,
.gpdup_mask= 0xFFFFFFFF,
.gpdcon= 0xaaaaaaaa,
.gpdcon_mask= 0xFFFFFFFF,
.lpcsel= 0x00,
};
这部分设置是关键,要针对自己的lcd修改.我开始一直不成功原因是用了24bpp格式,后来改成16bpp才看到企鹅.还不太清楚原因,2410和lcd都支持24bpp的,看来是内核不支持或者没配置好,高手请指点一下.
然后,在smdk2410_map_io(void)中添加
set_s3c2410fb_info(&smdk2410_lcd_platdata);

2.在s3c2410fb.c中增加初始化lcd代码.这里采用三个gpio口来模拟spi口
/*---------------added by hjcai*/
#define CLEAR_SCL    __raw_writel(__raw_readl(S3C2410_GPBDAT) &0xfffffffd, S3C2410_GPBDAT)             //SCL信号清零
#define SET_SCL        __raw_writel(__raw_readl(S3C2410_GPBDAT) |0x00000002, S3C2410_GPBDAT)
#define CLEAR_SDI    __raw_writel(__raw_readl(S3C2410_GPBDAT) &0xfffffffe, S3C2410_GPBDAT)              //清零SDI
#define SET_SDI        __raw_writel(__raw_readl(S3C2410_GPBDAT) |0x00000001, S3C2410_GPBDAT)
#define CLEAR_CS      __raw_writel(__raw_readl(S3C2410_GPBDAT) &0xffffffbf, S3C2410_GPBDAT)             //CS清零
#define SET_CS          __raw_writel(__raw_readl(S3C2410_GPBDAT) |0x00000040, S3C2410_GPBDAT)
/*---------------end add*/
/*---------------added by hjcai*/
//****************begin of set the index register **************//
void set_index_register(int ireg, int freq)         //ireq指定要写的寄存器,freq指定SCL半个周期
{

    int iindex=0x0074;        //指定是写寄存器的index,先传0x74,再传index
    int idata;
    int i;
    int gpbdat;

    SET_SCL;                  //先将SCL,SDI置高
    SET_SDI;
    udelay(20);

    CLEAR_CS;                  //CS有效
    udelay(1);

    CLEAR_SCL;               
    CLEAR_SDI;                //由于index和data都是要在开始传0x74和0x76,所以SDI第一个数据是0

   //printk("register\n");
  for(i=7;i>=0;i--)             //逐个将0x74送到GPB0上去
 { 
 
    gpbdat=__raw_readl(S3C2410_GPBDAT) ;

    idata=iindex>>i;
    //printk("idata=%x\n",idata);
    idata &=0x0001;
   // printk("bit=%x\n",idata);

gpbdat &=0xfffffff0;           //将要传递的位取出来,放到GPBDAT的第0位上
gpbdat |=idata;

    CLEAR_SCL;                       //SCL下降沿时,SDI数据更新
    __raw_writel(gpbdat, S3C2410_GPBDAT);
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
    SET_SCL;                         
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
 }

  //printk("command\n");
  for(i=15;i>=0;i--)                        //发送完0x74后发index
 { 
     gpbdat=__raw_readl(S3C2410_GPBDAT) ;
 
    idata=ireg>>i;                    
    idata &=0x00000001;

    gpbdat &=0xfffffff0;               //将ireq要传递的位逐个取出来,放到GPBDAT的第0位上
    gpbdat |=idata;

    CLEAR_SCL;
    __raw_writel(gpbdat, S3C2410_GPBDAT);
   // printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
    SET_SCL;
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
 }

     printk("\n");
 
SET_SDI;
udelay(1);
SET_CS;

}


void set_instruction(int iinstruct, int freq)   //iinstruct是要向寄存器写的数据,freq是SCL时钟间隔
{

    int iindex=0x0076;                //0x76指定要传递数据了
    int idata;
    int i;
    int gpbdat;

    SET_SCL;                 
    SET_SDI;
    udelay(20);

    CLEAR_CS;
    udelay(1);

    CLEAR_SCL;
    CLEAR_SDI;

  //printk("register\n");
  for(i=7;i>=0;i--)                            //发送0x76
 { 
    gpbdat=__raw_readl(S3C2410_GPBDAT) ;
 
    idata=iindex>>i;
    idata &=0x00000001;

    gpbdat &=0xfffffff0;
    gpbdat |=idata;

    CLEAR_SCL;
     __raw_writel(gpbdat, S3C2410_GPBDAT);
   // printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
    SET_SCL;
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
 }

  //printk("command\n");
  for(i=15;i>=0;i--)                                 //发送数据
 { 
    gpbdat=__raw_readl(S3C2410_GPBDAT) ;
    idata=iinstruct>>i;
    idata &=0x00000001;

    gpbdat &=0xfffffff0;
    gpbdat |=idata;

    CLEAR_SCL;
    __raw_writel(gpbdat, S3C2410_GPBDAT);
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
    SET_SCL;
    //printk("GPBDAT=%x\n",GPBDAT);
    udelay(freq);
 }

   //printk(" \n");
SET_SDI;
udelay(1);
SET_CS;
}

void set_index_instruct(int ireg, int iinstruct)     //将iistruct传到ireg寄存器中
{
   set_index_register (ireg,1);          //先传递index
   set_instruction (iinstruct,1);        //后传递data
}


void initial_LTV350QV(void)
{
//printk("LTV350QV initialize!\n");
__raw_writel(__raw_readl(S3C2410_GPBCON) &0xffffcff0, S3C2410_GPBCON);
__raw_writel(__raw_readl(S3C2410_GPBCON) |0x00001005, S3C2410_GPBCON);                //设定GPB0、GPB1、GPB6为output

SET_CS;                               //置CS,SDI,SCL无效
SET_SDI;
SET_SCL;


      mdelay(15);                            //延迟15ms
      set_index_instruct(0x0009,0x0000);     //将0000h传到R09寄存器


      mdelay(15); 
      set_index_instruct(0x0009,0x4000);
      set_index_instruct(0x000a,0x2000);
      set_index_instruct(0x0009,0x4055);

mdelay(60);
set_index_instruct(0x0001,0x409d);

      set_index_instruct(0x0002,0x0204);
 
      set_index_instruct(0x0003,0x0100);
 
      set_index_instruct(0x0004,0x3000);
 
      set_index_instruct(0x0005,0x4003);
 
      set_index_instruct(0x0006,0x000a);
 
      set_index_instruct(0x0007,0x0021);
 
      set_index_instruct(0x0008,0x0c00);
 
      set_index_instruct(0x0010,0x0103);
 
      set_index_instruct(0x0011,0x0301);
 
      set_index_instruct(0x0012,0x1f0f);
 
      set_index_instruct(0x0013,0x1f0f);
 
      set_index_instruct(0x0014,0x0707);
 
      set_index_instruct(0x0015,0x0307);
 
      set_index_instruct(0x0016,0x0707);
 
      set_index_instruct(0x0017,0x0000);
 
      set_index_instruct(0x0018,0x0004);
 
      set_index_instruct(0x0019,0x0000);
 

}
//**************** end of set the index register **************//
/*---------------end add*/
然后,在s3c2410fb_init(void)中添加
initial_LTV350QV();
在probe函数中添加几句代码:
device_create_file(dev, &dev_attr_debug);

printk(KERN_INFO "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
//------------added by hjcai
mdelay(35);
set_index_instruct(0x0009,0x4a55);  
       set_index_instruct(0x0005,0x5003);
//-------------add end
return 0;
这部分代码只针对ltv350qv,放置的位置可以改变,保证在驱动注册结束前被执行.

3.按论坛里seigpao大侠的做法,注释掉drivers\char\vt.c的blank_screen_t(unsigned long dummy)的函数内容,否则,lcd会在10分钟左右关掉显示.

4.配置内核,增加device driver/graphic support支持,我的全部选了,除了vga console选项(该选项好象需要pci支持).

基本就是这些.
另外,我在启动参数里若增加console=tty0,结果串口显示到
freeint init memory就没了.
而lcd上可以显示信息,但是不能滚屏,信息会覆盖,而且不能自动换行,某些行显示到屏幕右端就没了.
望高手指点.

 
 

  评论这张
 
阅读(465)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018