对于,不想逐一检查内核自带驱动,想自己编写驱动。
1,make menuconfig 去掉 编译到内核,改为 M 编译为 模块(因为要用到里面的3个.ko 驱动)
Device Drivers ---> 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 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 #include 15 #include 16 17 #include 18 #include 19 #include 20 21 //#include 22 //#include 23 //#include 24 //#include 25 26 27 #include 28 #include 29 #include 30 #include 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 sourcen"); 140 } 141 142 clk_prepare_enable(clk); 143 printk("got and enabled clockn"); 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); //配置背光引脚为输出
Graphics support --->
Support for frame buffer devices --->