Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1051103
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-04 15:45:16

lcd.c文件

点击(此处)折叠或打开

  1. /*内核的LCD驱动程序已经实现了,我们这里重新写一遍*/

  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/errno.h>
  5. #include <linux/string.h>
  6. #include <linux/mm.h>
  7. #include <linux/slab.h>
  8. #include <linux/delay.h>
  9. #include <linux/fb.h>
  10. #include <linux/init.h>
  11. #include <linux/dma-mapping.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/clk.h>
  15. #include <asm/io.h>
  16. #include <asm/div64.h>
  17. #include <asm/mach/map.h>
  18. #include <mach/regs-lcd.h>
  19. #include <mach/regs-gpio.h>
  20. #include <mach/fb.h>
  21. #include <linux/pm.h> //电源管理

  22. #ifdef CONFIG_PM
  23. #include <linux/pm.h>
  24. #endif

  25. static struct fb_info * s3c_lcd = NULL;

  26. /*****************************************************************************/
  27. volatile unsigned long * gpio_va = NULL;
  28. #define GPIO_OFT(x) ((x) - 0x56000000)

  29. /*gpio_va前面如果不加(char *),后面+0x20,则表示0x20*(volatile unsigned long *)lcdreg_va个长度=0x20*4
  30. *0x20*(char *)lcdreg_va个长度=0x20*1
  31. */
  32. #define    GPCCON (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000020))) //设置为:VD[7]到VD[0]功能引脚
  33. #define    GPCDAT (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000024)))
  34. #define    GPCUP (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000028)))

  35. #define    GPDCON (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000030))) //设置为:VD[23]到VD[8]功能引脚
  36. #define    GPDDAT (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000034)))
  37. #define    GPDUP (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000038)))

  38. #define    GPGCON (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000060))) //设置为:LCD_PWREN引脚
  39. #define    GPGDAT (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000064)))
  40. #define    GPGUP (*(volatile unsigned long *)((char *)gpio_va + GPIO_OFT(0x56000068)))

  41. /*****************************************************************************/
  42. volatile unsigned long * lcdreg_va = NULL;
  43. #define LCD_OFT(x) ((x) - 0x4D000000)

  44. #define    LCDCON1 (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000000)))
  45. #define    LCDCON2 (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000004)))
  46. #define    LCDCON3    (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000008)))
  47. #define    LCDCON4 (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D00000C)))
  48. #define    LCDCON5    (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000010)))

  49. #define    LCDSADDR1 (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000014)))
  50. #define    LCDSADDR2 (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000018)))
  51. #define    LCDSADDR3    (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D00001C)))

  52. #define    LCDINTPND (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000054))) //LCD中断挂起寄存器
  53. #define    LCDSRCPND (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D000058))) //LCD中断源寄存器
  54. #define    LCDINTMSK    (*(volatile unsigned long *)((char *)lcdreg_va + LCD_OFT(0x4D00005C))) //LCD中断屏蔽寄存器

  55. /*****************************************************************************/
  56. #define LCD_YSIZE_TFT_480272 (272) //实际LCD的高度
  57. #define LCD_XSIZE_TFT_480272 (480) //实际LCD的宽度

  58. #define CLKAVL_TFT ((0x04)&(0x3ff)) //用于设置LCDCON1中,像素时钟:低10位有效
  59. #define PNRMODE_LCDTYPE_TFT ((0x03)&(0x3)) //用于设置LCDCON1中,LCD类型:TFT:低2位有效
  60. #define BPPMODE_8BPP ((0xB)&(0xf)) //用于设置LCDCON1中,BPP类型:8BPP:低4位有效
  61. #define BPPMODE_16BPP (0xC) //用于设置LCDCON1中,BPP类型:16BPP
  62. #define BPPMODE_24BPP (0xD) //用于设置LCDCON1中,BPP类型:24BPP
  63. #define ENVID_DISABLE (0) //用于设置LCDCON1中,LCD信号禁止
  64. #define ENVID_ENABLE (1) //用于设置LCDCON1中,LCD信号使能

  65. //下面的取值,查看LCD控制器手册
  66. #define VBPD_480272 ((2)&(0xff)) //用于设置LCDCON2中,VBPD值:低8位有效
  67. #define LINEVAL_480272 ((LCD_YSIZE_TFT_480272-1)&(0x3ff)) //用于设置LCDCON2中,LINEVAL值:低10位有效,一旦实际LCD确定,这个值就确定下来了,不可以是其他任何值
  68. #define VFPD_480272 ((4)&(0xff)) //用于设置LCDCON2中,VFPD值:低8位有效
  69. #define VSPW_480272 ((8)&(0x3f)) //用于设置LCDCON2中,VSPW值:低8位有效

  70. #define HBPD_480272 ((10)&(0x7f)) //用于设置LCDCON3中,HBPD值:低7位有效
  71. #define HOZVAL_480272 ((LCD_XSIZE_TFT_480272-1)&(0x7ff)) //用于设置LCDCON3中,HOZVAL值:低11位有效,一旦实际LCD确定,这个值就确定下来了,不可以是其他任何值
  72. #define HFPD_480272 ((19)&(0xff)) //用于设置LCDCON3中,HFPD值:低8位有效
  73. #define HSPW_480272 ((30)&(0xff)) //用于设置LCDCON4中,HSPW值:低8位有效

  74. #define FORMAT_FRM565_565 (1) //用于设置LCDCON5中,FRM565值:TFT_LCD的显示模式为16BPP时:所使用的数据格式:565格式
  75. #define FORMAT_FRM565_5551 (0) //用于设置LCDCON5中,FRM565值:TFT_LCD的显示模式为16BPP时:所使用的数据格式:5551格式
  76. #define INVVLINE_HSYNC (1) //用于设置LCDCON5中,INVVLINE值:1:极性反转
  77. #define INVVFRAME_VSYNC (1) //用于设置LCDCON5中,INVVFRAME值:1:极性反转
  78. #define BSWP (0) //用于设置LCDCON5中,BSWP值:0
  79. #define HWSWP (1) //用于设置LCDCON5中,HWSWP值:1:0位和1位,共同决定内存中像素的排列格式

  80. #define LOWER21BITS(n) ((n) & 0x1fffff)

  81. //#define LCDFRAMEBUFFER (s3c_lcd->fix.smem_start) //帧内存起始地址

  82. #define DEB_PRINTK printk //测试完成,用这个,表示什么都不打印
  83. //#define DEB_PRINTK(x...) //测试时,用这个
  84. /*****************************************************************************/
  85. static unsigned int pseudo_buffer[16]; //本地调色板

  86. /* from pxafb.c TODO 函数功能 : 设置var中颜色的值*/
  87. static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
  88. {
  89.     chan &= 0xffff; //保留16位
  90.     chan >>= 16 - bf->length;
  91.     return chan << bf->offset;
  92. }

  93. /*
  94. *函数功能 : 设置调色板空间各个寄存器的值
  95. *函数参数 : regno : 调色板内存空间的编号,即索引值。类似于小时候画画的颜料碟子,共256个碟子。
  96. *注意 : 调色板中的数据,相当于是画图时,提前调试好的颜色,只不过,这个事先调试好的颜色只有256种,直接拿过来用就是了。
  97. */
  98. static int s3c_lcd_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
  99. {
  100.     unsigned int val;

  101.     switch (info->fix.visual) //本程序这里固定是真彩色
  102.     {
  103.     case FB_VISUAL_TRUECOLOR: //真彩色
  104.         /* true-colour, use pseudo-palette */
  105.         if(regno < 16)
  106.         {
  107.             /*用 red green blue 3原色构造出val*/
  108.             val = chan_to_field(red, &info->var.red);
  109.             val |= chan_to_field(green, &info->var.green);
  110.             val |= chan_to_field(blue, &info->var.blue);

  111.             //((U32 *)(info->pseudo_palette))[regno] = val;
  112.             pseudo_buffer[regno] = val;
  113.         }
  114.         break;

  115.     default:
  116.         return 1;    /* unknown type */
  117.     }

  118.     return 0;
  119. }

  120. static struct fb_ops mylcd_fb_ops =
  121. {
  122.     .owner        = THIS_MODULE,
  123.     .fb_setcolreg    = s3c_lcd_setcolreg, //本文件中实现,设置调色板
  124.     .fb_fillrect    = cfb_fillrect, //函数功能 : 填充一个矩形。下面这3个函数用内核已经定义好的函数,对显存的一些操作,是很通用的函数,几乎在所有的xxxfb.c文件中都有使用。
  125.     .fb_copyarea    = cfb_copyarea, //函数功能 : 拷贝一个区域
  126.     .fb_imageblit    = cfb_imageblit, //函数功能 :
  127. };


  128. static int __init lcd_int(void)
  129. {
  130.         int ret = 0;
  131.         dma_addr_t map_dma = 0;
  132.         printk("DEVICE:lcd_int() ok\n");

  133.         /* 1, 分配一个fb_info结构体
  134.         *在内核提供的驱动代码s3c2410fb.c中,需要额外的空间,我们这里简化了,不需要额外的空间,所以第1个参数size=0
  135.         */
  136.         printk("DEVICE:framebuffer_alloc()1 ok! s3c_lcd=[%p]\n", s3c_lcd);
  137.         s3c_lcd = framebuffer_alloc(0, NULL);
  138.         if(s3c_lcd == NULL)
  139.         {
  140.             printk("DEVICE:framebuffer_alloc() err!\n");
  141.             return -ENOMEM;
  142.         }
  143.         printk("DEVICE:framebuffer_alloc()2 ok! s3c_lcd=[%p]\n", s3c_lcd);

  144.         /* 2. 设置 */
  145.         //下面设置的值,在fbmem.c中调用read,write函数时,会使用到。
  146.         /* 2.1 设置固定的参数 struct fb_fix_screeninfo fix */
  147.         strcpy(s3c_lcd->fix.id, "mylcd");                        //这个名称可以随便取。
  148.         s3c_lcd->fix.smem_start = 0;                                //显存的起始地址,是物理地址,在分配了显存之后再赋值。
  149.         s3c_lcd->fix.smem_len = 480*272*16/8;                //显存的大小,单位是字节。需要查看LCD手册。16表示是使用16BPP
  150.         s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;    //类型,其实这里不设置也可以,framebuffer_alloc()时,会全部初始化为0。
  151.         /*类型用宏定义来表示,当不知道取什么值时,用默认的第1个值0,可以支持大部分的LCD。
  152.         #define FB_TYPE_PACKED_PIXELS        0         //Packed Pixels
  153.         #define FB_TYPE_PLANES            1         //Non interleaved planes
  154.         #define FB_TYPE_INTERLEAVED_PLANES    2        //Interleaved planes
  155.         #define FB_TYPE_TEXT            3         //Text/attributes
  156.         #define FB_TYPE_VGA_PLANES        4         //EGA/VGA planes
  157.         */
  158.         //s3c_lcd->fix.type_aux = 0;     //附加类型,这里可以不设置
  159.         s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; //我们使用的LCD是TFT屏,是真彩色的
  160.         /*
  161.         #define FB_VISUAL_MONO01        0                        //单色Monochr. 1=Black 0=White
  162.         #define FB_VISUAL_MONO10        1                        //单色Monochr. 1=White 0=Black
  163.         #define FB_VISUAL_TRUECOLOR        2                    //真彩色True color
  164.         #define FB_VISUAL_PSEUDOCOLOR        3                //伪彩色Pseudo color (like atari)
  165.         #define FB_VISUAL_DIRECTCOLOR        4                //Direct color
  166.         #define FB_VISUAL_STATIC_PSEUDOCOLOR    5    //Pseudo color readonly
  167.         */
  168.         //s3c_lcd->fix.xpanstep = 0;                            //这个不知道是什么玩意,设置为0,其实这里也可以不设置。
  169.         //s3c_lcd->fix.ypanstep = 0;
  170.         //s3c_lcd->fix.ywrapstep = 0;
  171.         s3c_lcd->fix.line_length = 480*2;                //我们采用的是16BPP,所以每1个像素是2个字节
  172.         printk("DEVICE:fix ok\n");
  173.         
  174.         /* 2.2 设置可变的参数 struct fb_var_screeninfo var */
  175.         s3c_lcd->var.xres = 480;                                //x轴方向上的分辨率,即一行有多少个像素点,是有效分辨率,即硬件分辨率吧,可见分辨率。
  176.         s3c_lcd->var.yres = 272;                                //y轴方向上的分辨率。
  177.         s3c_lcd->var.xres_virtual = 480;                //x轴方向上的虚拟分辨率,类似于我们在个人PC上设置的桌面分辨率,虚拟>=可见,才可以实现滚屏,但是我们这里搞最简单,所以也取可见分辨率。
  178.         s3c_lcd->var.yres_virtual = 272;                //y轴方向上的虚拟分辨率。
  179.         s3c_lcd->var.xoffset = 0;                                //虚拟到可见,x轴方向上的差值,初始值也是0,所以这里可以不设置了。
  180.         s3c_lcd->var.yoffset = 0;                                //虚拟到可见,y轴方向上的差值。
  181.         s3c_lcd->var.bits_per_pixel = 16;                //每个像素用多少位,我们这里采用16BPP的像素格式。
  182.         //s3c_lcd->var.grayscale = 0;                            //灰度值,取0时,指彩色,这里也可以不设置。
  183.         //下面设置位域,我们采用16BPP,RGB=565格式。
  184.         s3c_lcd->var.red.offset = 11; //红色从16位颜色的第11位开始
  185.         s3c_lcd->var.red.length = 5;                        //红色的长度是5位
  186.         //s3c_lcd->var.red.msb_right = 0;                    //红色的最高位在左边,这里也可以不设置
  187.         s3c_lcd->var.green.offset = 5;                    //绿色第5位开始
  188.         s3c_lcd->var.green.length = 6;                    //绿色的长度是6位
  189.         //s3c_lcd->var.green.msb_right = 0;                //绿色的最高位在左边
  190.         s3c_lcd->var.blue.offset = 0;                        //蓝色第0位开始
  191.         s3c_lcd->var.blue.length = 5;                        //蓝色的长度是5位
  192.         //s3c_lcd->var.blue.msb_right = 0;                //蓝色的最高位在左边
  193.         
  194.         s3c_lcd->var.nonstd = 0;                                //取0:标准像素格式,1:非标准像素格式,所以这里也可以不设置。
  195.         s3c_lcd->var.activate = FB_ACTIVATE_NOW;//看不懂,用默认值
  196.         /*
  197.         #define FB_ACTIVATE_NOW        0                            //set values immediately (or vbl)
  198.         #define FB_ACTIVATE_NXTOPEN    1                        //activate on next open
  199.         #define FB_ACTIVATE_TEST    2                            //don't set, round up impossible
  200.         #define FB_ACTIVATE_MASK 15                //values
  201.         #define FB_ACTIVATE_VBL     16                //activate values on next vbl
  202.         #define FB_CHANGE_CMAP_VBL 32                //change colormap on vbl
  203.         #define FB_ACTIVATE_ALL     64                //change all VCs on this fb
  204.         #define FB_ACTIVATE_FORCE 128                //force apply even when no change
  205.         #define FB_ACTIVATE_INV_MODE 256                //invalidate videomode
  206.         */
  207.         s3c_lcd->var.height = 0;                                //LCD的物理高度,可以不写,写了也没多大意义。
  208.         s3c_lcd->var.width = 0;                                    //LCD的物理宽度。
  209.         
  210.         //pixclock,left_margin 如果我们有真实的数据时,可以写进去,写进去了也没多大意义。
  211.         printk("DEVICE:var ok!\n");

  212.         /* 2.3 设置操作函数 */
  213.         s3c_lcd->fbops = &mylcd_fb_ops;    //这个是重点。

  214.         /* 2.4 其他的设置 */
  215.         //为了兼容以前的程序,还需要提供假的调色板。
  216.         s3c_lcd->pseudo_palette = (void *)pseudo_buffer;
  217.         s3c_lcd->screen_base = NULL;                        //显存的起始地址,是虚拟地址,在分配了显存之后再赋值。
  218.         s3c_lcd->screen_size = 480*272*16/8;        //显存的大小,单位是字节。

  219.         /* 3. 硬件相关的设置 */
  220.         /* 3.1 配置GPIO用于LCD */
  221.         /* 这里映射1M的内存空间,映射内存的最小单位就是1页 */
  222.         gpio_va = (volatile unsigned long *)ioremap(0x56000000, 0x100000); //GPIO的基址
  223.         if(gpio_va == NULL)
  224.         {
  225.             printk("DEVICE:ioremap() gpio_va err!\n");
  226.             return -1;
  227.         }
  228.         printk("DEVICE:ioremap() gpio_va ok! gpio_va=[%p]\n", gpio_va);
  229.         
  230.         printk("DEVICE:ioremap() gpio_va ok! &GPCCON=[%p]\n", &GPCCON);
  231.         printk("DEVICE:ioremap() gpio_va ok! &GPCDAT=[%p]\n", &GPCDAT);
  232.         printk("DEVICE:ioremap() gpio_va ok! &GPCUP=[%p]\n", &GPCUP);
  233.         
  234.         printk("DEVICE:ioremap() gpio_va ok! &GPDCON=[%p]\n", &GPDCON);
  235.         printk("DEVICE:ioremap() gpio_va ok! &GPDDAT=[%p]\n", &GPDDAT);
  236.         printk("DEVICE:ioremap() gpio_va ok! &GPDUP=[%p]\n", &GPDUP);
  237.         
  238.         printk("DEVICE:ioremap() gpio_va ok! &GPGCON=[%p]\n", &GPGCON);
  239.         printk("DEVICE:ioremap() gpio_va ok! &GPGDAT=[%p]\n", &GPGDAT);
  240.         printk("DEVICE:ioremap() gpio_va ok! &GPGUP=[%p]\n", &GPGUP);

  241.         GPCUP = 0x0;
  242.         /*GPCCON寄存器
  243.         [31:0]=1010,1010,1010,1010,高16位,设置为:VD[7]到VD[0]功能引脚
  244.          1010,1010,1010,1010,底16位,设置为:LCD_LPCREVB,LCD_LPCREV,LCD_LPCOE,VM,VFRAME,VLINE,VCLK,LEND功能引脚*/
  245.         GPCCON = 0xaaaaaaaa;
  246.         printk("DEVICE:GPCCON ok! GPCCON=[%x]\n", (unsigned int)GPCCON);
  247.         GPDUP = 0x0;
  248.         /*GPDCON寄存器 [31:0]=1010,1010,1010,1010,1010,1010,1010,1010, 设置为:VD[23]到VD[8]功能引脚*/
  249.         GPDCON = 0xaaaaaaaa;
  250.         GPGUP = 0x0;
  251.         /*GPG4:为LCD_PWREN电源使能引脚*/
  252.         GPGCON |= (3<<8);                                        //GPG4用作LCD_PWREN
  253.         GPGDAT &= ~(1<<4);                                    //输出低电平
  254.         
  255.         /* 3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等 */
  256.         lcdreg_va = (volatile unsigned long *)ioremap(0x4D000000, 0x100000); //LCD相关寄存器的基址
  257.         if(lcdreg_va == NULL)
  258.         {
  259.             printk("DEVICE:ioremap() lcdreg_va err!\n");
  260.             return -1;
  261.         }
  262.         printk("DEVICE:ioremap() lcdreg_va ok! lcdreg_va=[%p]\n", lcdreg_va);
  263.         
  264.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDCON1=[%p]\n", &LCDCON1);
  265.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDCON2=[%p]\n", &LCDCON2);
  266.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDCON3=[%p]\n", &LCDCON3);
  267.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDCON4=[%p]\n", &LCDCON4);
  268.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDCON5=[%p]\n", &LCDCON5);
  269.         
  270.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDSADDR1=[%p]\n", &LCDSADDR1);
  271.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDSADDR2=[%p]\n", &LCDSADDR2);
  272.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDSADDR3=[%p]\n", &LCDSADDR3);

  273.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDINTPND=[%p]\n", &LCDINTPND);
  274.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDSRCPND=[%p]\n", &LCDSRCPND);
  275.         printk("DEVICE:ioremap() lcdreg_va ok! &LCDINTMSK=[%p]\n", &LCDINTMSK);

  276.         /*LCD控制1寄存器:用于设置LCD类型,像素时钟,使能LCD信号的输出
  277.         [17:8]=CLKAVL_TFT=(100)b,像素时钟信号VCLK=高速时钟信号HCLK/((4+1)*2),本实验中HCLK=100MHZ,所以VCLK=10MHZ,周期是100ns。
  278.          注意 : 这个的取值范围是0~9。
  279.         [6:5]=PNRMODE_LCDTYPE_TFT=(11)b,4位双扫描显示模式(STN) 11:TFT面板 (为什么设置成00和11都行啊?)
  280.         [4:1]=BPPMODE_16BPP=(1100)b,TFT的16位每像素模式,即16bpp
  281.         [0]=ENVID_DISABLE=0,禁止LCD控制信号和视频输出
  282.         */
  283.         LCDCON1 = ((CLKAVL_TFT<<8)|(PNRMODE_LCDTYPE_TFT<<5)|(BPPMODE_16BPP<<1)|ENVID_DISABLE);

  284.         /*LCD控制2寄存器:用于设置垂直方向上信号的时间参数
  285.         [25:24]=VBPD_480272=(10)b,垂直后沿帧开始时,垂直同步周期后的无效行数为2
  286.         [23:14]=LINEVAL_480272=(272-1)十进制,决定LCD面板的垂直尺寸,272行
  287.         [13:6]=VFPD_480272=(100)b,垂直前沿帧结束时,垂直同步周期前的无效行数为4
  288.         [5:0]=VSPW_480272=(1000)b,VSYNC脉冲的高电平宽度8
  289.         */
  290.         LCDCON2 = ((VBPD_480272<<24)|(LINEVAL_480272<<14)|(VFPD_480272<<6)|(VSPW_480272));
  291.         
  292.         /*LCD控制3寄存器:用于设置水平方向各信号的时间参数
  293.         [22:19]=HBPD_480272=(1010)b,无效的像素点数,一个VCLK周期对应一个像素点。
  294.         [18:8]=HOZVAL_480272=(480-1)十进制,决定LCD面板的水平尺寸,480行
  295.         [7:0]=HFPD_480272=(10011)b,无效的像素点数
  296.         */
  297.         LCDCON3 = ((HBPD_480272<<19)|(HOZVAL_480272<<8|(HFPD_480272)));
  298.         
  299.         /*LCD控制4寄存器:LCDCON3位数不够用,补充用LCDCON4,来给出另外一个水平方向信号的时间参数
  300.         [7:0]=(30)十进制,无效的像素点数
  301.         */
  302.         LCDCON4 = (HSPW_480272);
  303.         
  304.         /*LCD控制5寄存器
  305.         [11]=1,16bpp输出数据视频的格式,为5:6:5,[11]=0,格式为5:5:5:1
  306.         [9]=1,本程序是TFT屏,所以只决定HSYNC脉冲极性,反转,[9]=0,极性正常
  307.         [8]=1,本程序是TFT屏,所以只决定VSYNC脉冲极性,反转,[8]=0,极性正常
  308.         [1]=0,字节交换控制位使能
  309.         [0]=1,半字节交换控制位使能,0位和1位,共同决定了16BPP显示模式时,内存中像素的排列格式:p1在低16位,p2在高16位
  310.         */
  311.         LCDCON5 = ((FORMAT_FRM565_565<<11)|(INVVLINE_HSYNC<<9)|(INVVFRAME_VSYNC<<8)|(BSWP<<1)|(HWSWP));

  312.         /* 3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 */
  313.         //这个函数执行完之后,显存的物理地址,虚拟地址都可以得到了。是可写的一块内存。物理地址是一块连续的空间
  314.         //kmalloc分配的虚拟地址是连续的,物理地址是不连续的。
  315.         printk("DEVICE:dma_alloc_writecombine() ok! smem_len=[%d]\n", s3c_lcd->fix.smem_len); //26112
  316.         s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, &map_dma, GFP_KERNEL);
  317.         if(s3c_lcd->screen_base == NULL)
  318.         {
  319.                 printk("DEVICE:dma_alloc_writecombine() err!\n");
  320.                 return -1;
  321.         }
  322.         printk("DEVICE:dma_alloc_writecombine() ok! map_dma=[%x]\n",(unsigned int)(map_dma));
  323.         printk("DEVICE:dma_alloc_writecombine() ok! screen_base=[%p]\n", s3c_lcd->screen_base);
  324.         s3c_lcd->fix.smem_start = (unsigned long)map_dma;
  325.         printk("DEVICE:dma_alloc_writecombine() ok! smem_start=[%x]\n", (unsigned int)(s3c_lcd->fix.smem_start));

  326.         //本实验设置:帧内存与视口(view point)完全吻合
  327.         //下面的 (LCD_XSIZE_TFT_480272 * LCD_YSIZE_TFT_480272 * 2) = s3c_lcd->fix.smem_len
  328.         //LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
  329.         //LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER + (s3c_lcd->fix.smem_len))>>1);
  330.         LCDSADDR1 = ((s3c_lcd->fix.smem_start>>22)<<21) | LOWER21BITS(s3c_lcd->fix.smem_start>>1);
  331.         printk("DEVICE:LCDSADDR1 ok! LCDSADDR1=[%x]\n", (unsigned int)LCDSADDR1);
  332.         LCDSADDR2 = LOWER21BITS((s3c_lcd->fix.smem_start + (s3c_lcd->fix.smem_len))>>1);
  333.         printk("DEVICE:LCDSADDR2 ok! LCDSADDR2=[%x]\n", (unsigned int)LCDSADDR2);
  334.         LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_480272/2);
  335.         printk("DEVICE:LCDSADDR3 ok! LCDSADDR3=[%x]\n", (unsigned int)LCDSADDR3);

  336.         /*LCD中断屏蔽寄存器:决定屏蔽哪个中断源,被屏蔽的中断源将不会被服务
  337.         [1]=1,LCD帧同步中断,屏蔽
  338.         [0]=1,LCD FIFO中断,屏蔽
  339.         */
  340.         LCDINTMSK |= 3;
  341.         printk("DEVICE:LCDINTMSK ok! LCDINTMSK=[%x]\n", (unsigned int)LCDINTMSK);

  342.         /* 启动LCD */
  343.         LCDCON1 |= 1;                                         //LCDCON1最低位为1:LCD输出使能
  344.         LCDCON5 |= (1<<3);                                 //LCDCON5第3位:使能LCD本身
  345.         printk("DEVICE:LCDCON1 ok! LCDCON1=[%x]\n", (unsigned int)LCDCON1);
  346.         GPGDAT |= (1<<4);                                        //输出高电平 LCD_PWR使能背光
  347.         printk("DEVICE:GPGDAT ok! GPGDAT=[%x]\n", (unsigned int)GPGDAT);

  348.         /* 4,注册 */
  349.         printk("[%s][%s][%d]:s3c_lcd=[%p]\n", __FILE__, __FUNCTION__, __LINE__, s3c_lcd);
  350.         ret = register_framebuffer(s3c_lcd);
  351.         if(ret < 0)
  352.         {
  353.             printk("DEVICE:register_framebuffer() ret=[%d]\n", ret);
  354.             return -1;
  355.         }
  356.         printk("[%s][%s][%d]:s3c_lcd=[%p]\n", __FILE__, __FUNCTION__, __LINE__, s3c_lcd);
  357.         return 0;
  358. }

  359. static void __exit lcd_exit(void)
  360. {
  361.         unregister_framebuffer(s3c_lcd);
  362.         
  363.         LCDCON1 &= (~1); /*LCDCON1最低位为0:LCD输出禁止*/

  364.         dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);

  365.         iounmap((void *)lcdreg_va);
  366.         iounmap((void *)gpio_va);
  367.         
  368.         /*释放fb_info结构体的空间*/
  369.         framebuffer_release(s3c_lcd);

  370.         return;
  371. }

  372. module_init(lcd_int);
  373. module_exit(lcd_exit);

  374. MODULE_AUTHOR("wangxiancai"); //代码的作者
  375. MODULE_DESCRIPTION("touchsc driver"); //代码的描述,功能
  376. MODULE_LICENSE("GPL"); //开源协议
  377. MODULE_ALIAS("lcd");

  378. /*
  379. 测试:在2.6.30内核上没有看见
  380. 1,make menuconfig 去掉原来的LCD驱动程序
  381.    Device Drivers --->
  382.            Graphics support --->
  383.                    <*> Support for frame buffer devices ---> //如果有关于2410 2440LCD support 的选项,则去掉。
  384.                            <M> S3C2410 LCD framebuffer support     //不是去掉*,是配置为M。原本是*号。
  385.    注意 : 编译成模块的原因是:我们要使用到 struct fb_ops 结构体中的3个函数,所以需要这3个函数的文件也编译.ko文件。
  386.    在文件 : kernel-2.6.13/drivers/video 中可以看见 cfbfillrect.ko + cfbcopyarea.ko + cfbimgblt.ko

  387. 2,插入自己编译生成的ko模块。
  388.     cd /wxc/driver/chardriver/ko
  389.   在serial下# insmod lcd.ko
  390.   lcd: Unknown symbol cfb_copyarea
  391.     lcd: Unknown symbol cfb_imageblit
  392.     lcd: Unknown symbol cfb_fillrect
  393.   //出来这个信息,表明模块插入失败。报错原因是 : 差了3个模块
  394.   拷贝3个ko文件(cfbfillrect.ko + cfbcopyarea.ko + cfbimgblt.ko)到 目录:/wxc/driver/chardriver/ko
  395. # cd /home/wangxc/linux/kernel/kerner-2.6.30/drivers/video
  396. # cp cfbcopyarea.ko /home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/chardriver/ko
  397. # cp cfbfillrect.ko /home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/chardriver/ko
  398. # cp cfbimgblt.ko /home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/chardriver/ko

  399. # ls -lrt /dev/fb* //没有fb0文件

  400. # insmod cfbfillrect.ko //只是提供一些函数,它们本身并不是驱动程序。
  401. # insmod cfbcopyarea.ko
  402. # insmod cfbimgblt.ko
  403. # insmod lcd.ko

  404. # ls -lrt /dev/fb* //有fb0文件
  405. crw-rw---- 1 root root 29, 0 Jan 1 00:00 /dev/fb0 //LCD可用,一定有这个文件
  406. */
makefile文件

点击(此处)折叠或打开

  1. # File: Makefile
  2. # wangxiancai

  3. MODEXT = ko
  4. # INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.13/wxc/driver/chardriver/ko
  5. INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/chardriver/ko
  6. # CROSS=/home/wangxc/linux/toolchain/crosstools_3.4.1_softfloat/arm-linux/gcc-3.4.1-glibc-2.3.3/bin/arm-linux-
  7. CROSS=/home/wangxc/linux/toolchain/crosstools_4.4.3_softfloat/bin/arm-linux-
  8. # KERNELDIR=/home/wangxc/linux/kernel/kernel-2.6.13
  9. KERNELDIR=/home/wangxc/linux/kernel/kerner-2.6.30

  10. CC= $(CROSS)gcc
  11. LD= $(CROSS)ld

  12. #############################################################################
  13. # Compiler Flags
  14. #############################################################################
  15. EXTRA_CFLAGS += -I$(KERNELDIR)/include
  16. #############################################################################
  17. # Make Targets
  18. #############################################################################
  19. obj-m := lcd.o lcd2.o
  20. default:
  21.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  22. # Otherwise we were called directly from the command line; invoke the kernel build system.

  23. install: default
  24.     rm -rf $(INSTALLDIR)/lcd.$(MODEXT)
  25.     cp -rf $(PWD)/lcd.$(MODEXT) $(INSTALLDIR)
  26.     rm -rf $(INSTALLDIR)/lcd2.$(MODEXT)
  27.     cp -rf $(PWD)/lcd2.$(MODEXT) $(INSTALLDIR)

  28. clean:
  29.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.bak modules.order Module.symvers



阅读(629) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~