zoukankan      html  css  js  c++  java
  • s3c2440液晶屏驱动 (非内核自带) linux-4.1.24

    对于,不想逐一检查内核自带驱动,想自己编写驱动。

    1,make menuconfig 去掉 编译到内核,改为 M 编译为 模块(因为要用到里面的3个.ko 驱动)

    Device Drivers --->
        Graphics support --->
            Support for frame buffer devices --->
                <M> S3C2410 LCD framebuffer support

    2,make uImage && make modules 生成新内核  和 模块文件

    烧写新内核或使用 nfs bootm 使用编译为 M 模块的内核启动。

    复制 3个 ko 文件到 文件系统,这里用的是 NFS 网络文件系统。

    cp drivers/video/fbdev/core/cfb*.ko /nfs_root/new_fs  (新的 4.1 内核是在这里,以前没有 这个 core 目录)

    3, 使用原来的 2.6.22 的内核下的驱动程序,修改头文件后,编译为 .ko 文件放到 NFS 文件系统里,启动,如图所示

    图忘拍了,有时是白屏,有时是竖的细彩线。

    比较内核自带驱动 s3c2410fb.c 发现有个 usleep_range(1000, 1100); 

    而原来的 2.6.22 的驱动里面,是没有启用 clk 的。添加上这部分后,重新编译,试机成功。

    最后是完整的驱动源码:

      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/errno.h>
      4 #include <linux/string.h>
      5 #include <linux/mm.h>
      6 #include <linux/slab.h>
      7 #include <linux/delay.h>
      8 #include <linux/fb.h>
      9 #include <linux/init.h>
     10 #include <linux/dma-mapping.h>
     11 #include <linux/interrupt.h>
     12 #include <linux/workqueue.h>
     13 #include <linux/wait.h>
     14 #include <linux/platform_device.h>
     15 #include <linux/clk.h>
     16 
     17 #include <asm/io.h>
     18 #include <asm/uaccess.h>
     19 #include <asm/div64.h>
     20 
     21 //#include <asm/mach/map.h>
     22 //#include <asm/arch/regs-lcd.h>
     23 //#include <asm/arch/regs-gpio.h>
     24 //#include <asm/arch/fb.h>
     25 
     26 
     27 #include <asm/mach/map.h>
     28 #include <mach/regs-lcd.h>
     29 #include <mach/regs-gpio.h>
     30 #include <mach/fb.h>
     31 
     32 
     33 //参数定义
     34 #define LCD_WIDTH 480
     35 #define LCD_HEIGHT 272
     36 #define LCD_BIT 16
     37 
     38 #define LCD_CLKVAL 4
     39 #define LCD_TFT    3
     40 #define LCD_24BBP  0xd
     41 #define LCD_16BBP  0xc
     42 #define LCD_EN_OFF 0
     43 #define LCD_EN_ON  1
     44 #define LCD_VBPD   1
     45 #define LCD_LINEVAL  (LCD_HEIGHT - 1)
     46 #define LCD_VFPD   1
     47 #define LCD_VSPW   9
     48 #define LCD_HBPD   1
     49 #define LCD_HOZVAL (LCD_WIDTH - 1)
     50 #define LCD_HFPD   1
     51 #define LCD_HSPW   40
     52 #define LCD_INVVLINE 1
     53 #define LCD_INVVFRAME 1
     54 //调色板 u32 = unsigned int
     55 static u32 pseudo_palette[16];
     56 
     57 /* from pxafb.c */
     58 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
     59 {
     60     //只取16bit 数据
     61     chan &= 0xffff;
     62     //如 r = 16-5 = 11 : 右移去掉不要的位
     63     chan >>= (16 - bf->length);
     64     //在移到高位去 就是右边补0
     65     return chan << bf->offset;
     66 }
     67 
     68 static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
     69                  unsigned int green, unsigned int blue,
     70                  unsigned int transp, struct fb_info *info)
     71 {
     72     
     73     if(16 > regno)
     74     {
     75         unsigned int val;
     76         val  = chan_to_field(red, &info->var.red);
     77         val |= chan_to_field(green, &info->var.green);
     78         val |= chan_to_field(blue, &info->var.blue);
     79         pseudo_palette[regno] = val;
     80         return 0;
     81     }
     82     return 1;
     83 }
     84 
     85 
     86 static struct fb_ops s3c_ops = {
     87     .owner        = THIS_MODULE,
     88     .fb_setcolreg    = s3c_lcdfb_setcolreg,
     89     .fb_fillrect    = cfb_fillrect,
     90     .fb_copyarea    = cfb_copyarea,
     91     .fb_imageblit    = cfb_imageblit,
     92 };
     93 
     94 //定义GPIO
     95 static volatile unsigned long *gpb_con;
     96 static volatile unsigned long *gpc_con;
     97 static volatile unsigned long *gpd_con;
     98 static volatile unsigned long *gpg_con;
     99 
    100 static volatile unsigned long *gpb_dat;
    101 static volatile unsigned long *gpc_dat;
    102 static volatile unsigned long *gpd_dat;
    103 static volatile unsigned long *gpg_dat;
    104 
    105 struct lcd_regs {
    106     unsigned long    lcdcon1;    
    107     unsigned long    lcdcon2;    
    108     unsigned long    lcdcon3;    
    109     unsigned long    lcdcon4;    
    110     unsigned long    lcdcon5;    
    111     unsigned long    lcdsaddr1;    
    112     unsigned long    lcdsaddr2;    
    113     unsigned long    lcdsaddr3;    
    114     unsigned long    redlut;    
    115     unsigned long    greenlut;    
    116     unsigned long    bluelut;    
    117     unsigned long    reserved[9];    
    118     unsigned long    dithmode;    
    119     unsigned long    tpal;    
    120     unsigned long    lcdintpnd;    
    121     unsigned long    lcdsrcpnd;    
    122     unsigned long    lcdintmsk;    
    123     unsigned long    lpcsel;
    124 };
    125 
    126 static volatile struct lcd_regs * lcd_reg;
    127 
    128 
    129 //定义fb_info
    130 static struct fb_info * s3c_lcd;
    131 static int lcd_init(void)
    132 {
    133     //1,分配一个fb_info
    134     s3c_lcd = framebuffer_alloc(0, NULL);
    135 
    136     struct clk *clk;    
    137     clk = clk_get(NULL, "lcd");
    138     if (IS_ERR(clk)) {
    139         printk("failed to get lcd clock source
    ");
    140     }
    141 
    142     clk_prepare_enable(clk);
    143     printk("got and enabled clock
    ");
    144 
    145     usleep_range(1000, 1100);
    146     
    147     //2,设置
    148     //2,1 设置固定的参数
    149     strcpy(s3c_lcd->fix.id, "mylcd");
    150     s3c_lcd->fix.smem_len  = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;
    151     s3c_lcd->fix.type        = FB_TYPE_PACKED_PIXELS;
    152     s3c_lcd->fix.visual      = FB_VISUAL_TRUECOLOR;
    153     s3c_lcd->fix.line_length = LCD_WIDTH * LCD_BIT / 8; //单位 bytes    
    154     //物理地址由 dma_alloc_writecombine 函数分配
    155     //s3c_lcd->fix.smem_start  = LCD_FRAMEBUFFER;
    156     //s3c_lcd->fix.mmio_len    = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;
    157     
    158     //2,2 设置可变的参数
    159     s3c_lcd->var.width  = LCD_WIDTH;
    160     s3c_lcd->var.height = LCD_HEIGHT;
    161     s3c_lcd->var.xres         = LCD_WIDTH;
    162     s3c_lcd->var.yres         = LCD_HEIGHT;
    163     s3c_lcd->var.xres_virtual = LCD_WIDTH;
    164     s3c_lcd->var.yres_virtual = LCD_HEIGHT;
    165     s3c_lcd->var.bits_per_pixel = LCD_BIT;
    166     //RGB 5 6 5
    167     s3c_lcd->var.red.length   = 5;
    168     s3c_lcd->var.red.offset   = 11;
    169     s3c_lcd->var.green.length = 6;
    170     s3c_lcd->var.green.offset = 5;
    171     s3c_lcd->var.blue.length  = 5;
    172     s3c_lcd->var.blue.offset  = 0;
    173     s3c_lcd->var.activate     = FB_ACTIVATE_NOW;
    174 
    175     s3c_lcd->var.pixclock = 100000;
    176 
    177     //2,3 设置操作函数
    178     s3c_lcd->fbops = &s3c_ops;
    179 
    180     //2.4 其它的设置
    181     s3c_lcd->screen_size = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;
    182     s3c_lcd->pseudo_palette = pseudo_palette;
    183     
    184     //3,硬件相关的操作
    185     //3,1 配置GPIO
    186     gpb_con = ioremap(0x56000010, 4);
    187     gpb_dat = gpb_con + 1;
    188 
    189     gpc_con = ioremap(0x56000020, 4);
    190     gpc_dat = gpc_con + 1;
    191 
    192     gpd_con = ioremap(0x56000030, 4);
    193     gpc_dat = gpd_con + 1;
    194 
    195     gpg_con = ioremap(0x56000060, 4);
    196     gpg_dat = gpg_con + 1;
    197 
    198     *gpc_con = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 
    199     *gpd_con = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]
    200 
    201     *gpb_con &= ~(3);        //配置背光引脚为输出
    202     *gpb_con |= 1;
    203     *gpb_dat &= 0;           //默认输出低电平
    204 
    205     *gpg_con &= ~(3<<2*4);   //GPGCON 4 配置为 LCD_POWER 
    206     *gpg_con |= (3<<2*4);
    207     
    208     //3,2 配置lcdcon1 ~ lcdcon5
    209     lcd_reg          = ioremap(0x4d000000, sizeof(struct lcd_regs));
    210     lcd_reg->lcdcon1 = LCD_CLKVAL<<8 | LCD_TFT<<5 | LCD_16BBP<<1 | LCD_EN_OFF;
    211     lcd_reg->lcdcon2 = LCD_VBPD<<24 | LCD_LINEVAL<<14 | LCD_VFPD<<6 | LCD_VSPW;
    212     lcd_reg->lcdcon3 = LCD_HBPD<<19 | LCD_HOZVAL<<8 | LCD_HFPD;
    213     lcd_reg->lcdcon4 = LCD_HSPW;
    214     lcd_reg->lcdcon5 = 1<<11 | LCD_INVVLINE<<9 | LCD_INVVFRAME<<8 | 1;
    215     //屏幕宽度 * 16bit 颜色值 / words : 1 words = 2 byte
    216     lcd_reg->lcdsaddr3 = LCD_WIDTH * 16 / 16;
    217     
    218     //3,3 设置显存 bramebuffer, 并把地址告诉lcd 控制器
    219     s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &s3c_lcd->fix.smem_start, GFP_KERNEL);
    220     
    221     lcd_reg->lcdsaddr1 = (s3c_lcd->fix.smem_start>>22)<<21 | ((s3c_lcd->fix.smem_start>>1) & 0x1fffff);
    222     lcd_reg->lcdsaddr2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len)>>1) & 0x1fffff;
    223     
    224     unsigned long saddr1,saddr2,saddr3;
    225     saddr1  = s3c_lcd->fix.smem_start >> 1;
    226     saddr2  = s3c_lcd->fix.smem_start;
    227     saddr2 += s3c_lcd->fix.line_length * s3c_lcd->var.yres;
    228     saddr2 >>= 1;
    229     saddr3 = S3C2410_OFFSIZE(0) |
    230      S3C2410_PAGEWIDTH((s3c_lcd->fix.line_length / 2) & 0x3ff);
    231 
    232     lcd_reg->lcdsaddr1 = saddr1;
    233     lcd_reg->lcdsaddr2 = saddr2;
    234     lcd_reg->lcdsaddr3 = saddr3;
    235 
    236     printk("fb %x 
    ", LCD_CLKVAL<<8 | LCD_TFT<<5 | LCD_16BBP<<1 | LCD_EN_OFF);
    237     printk("fb %x 
    ", LCD_VBPD<<24 | LCD_LINEVAL<<14 | LCD_VFPD<<6 | LCD_VSPW);
    238     printk("fb %x 
    ", LCD_HBPD<<19 | LCD_HOZVAL<<8 | LCD_HFPD);
    239     printk("fb %x 
    ", LCD_HSPW);
    240     printk("fb %x 
    ", 1<<11 | LCD_INVVLINE<<9 | LCD_INVVFRAME<<8 | 1);
    241 
    242     
    243     printk("fb %x 
    ", saddr1);
    244     printk("fb %x 
    ", saddr2);
    245     printk("fb %x 
    ", saddr3);
    246 
    247     //打开 LCD_POWER 背光
    248     lcd_reg->lcdcon1 |= LCD_EN_ON;
    249     *gpb_dat |= 1;
    250     lcd_reg->lcdcon5 &= ~(1<<3);
    251     lcd_reg->lcdcon5 |=  (1<<3);
    252     
    253     //4,注册
    254     register_framebuffer(s3c_lcd);
    255     return 0;
    256 }
    257 
    258 static void lcd_exit(void)
    259 {
    260     //关背光
    261     *gpb_dat &= 0;
    262     lcd_reg->lcdcon5 &= ~(1<<3);
    263     lcd_reg->lcdcon1 &= LCD_EN_OFF;
    264 
    265     //注销显存
    266     dma_free_writecombine(NULL,s3c_lcd->fix.smem_len,s3c_lcd->screen_base,s3c_lcd->fix.smem_start);
    267 
    268     //注销
    269     framebuffer_release(s3c_lcd);
    270 
    271     //注销framebuf
    272     unregister_framebuffer(s3c_lcd);
    273     
    274     //取消map
    275     iounmap(gpb_con);
    276     iounmap(gpc_con);
    277     iounmap(gpd_con);
    278     iounmap(gpg_con);
    279     iounmap(lcd_reg);
    280 }
    281 
    282 
    283 module_init(lcd_init);
    284 module_exit(lcd_exit);
    285 MODULE_LICENSE("GPL");

    试验的时候要先加载那3个 .ko

    insmod cfbcopyarea.ko
    insmod cfbfillrect.ko
    insmod cfbimgblt.ko
    insmod lcd.ko  编译出来的 lcd 驱动

  • 相关阅读:
    BOM弹窗 滚动条
    标签占位信息
    标签样式操作
    Keepalived入门学习
    史上最全Redis面试题(2020最新版)
    一文带你读懂zookeeper在大数据生态的应用
    详细解析虚拟化的起源和分类
    干货 | Nginx负载均衡原理及配置实例
    干货 | 一文彻底读懂nginx中的location指令
    史上最全Linux面试题(2020最新版)
  • 原文地址:https://www.cnblogs.com/ningci/p/5544043.html
Copyright © 2011-2022 走看看