【内核配置】六、修改内核自带的的LCD驱动源码并编译进内核 | 烧写到Mini2440__TD35 完整攻略

主   机:VMWare--Ubuntu-16.04.2-x64-100ask
开发板:Mini2440--256M NandFlash,   2M NorFlash,   64M SDRAM,   LCD-TD35;
    bootlorder:u-boot1.16,        Kernel:2.6.22.6;
编译器:arm-linux-gcc-3.4.5


 

目的:修改打补丁之后的Linus-2.6.22.6内核自带的的LCD驱动源码并编译进内核,用于Mini2440__TD35开发板LCD;
说明:   1.Mini2440__TD35的背光用的GPB1; JZ2440的LCD背光用的GPB0; 
    2.视频的LCD驱动实现的功能已实现;
    3.内核自带的LCD驱动源码分两部分:稳定的不长修改的代码linux-2.6.22.6\drivers\video\s3c2410fb.c,
       硬件相关的代码linux-2.6.22.6\arch\arm\plat-s3c24xx\devs.c和其下的各具体型号LCD,
       其中我们的LCD用的驱动是:linux-2.6.22.6\arch\arm\mach-s3c2440\mach-smdk2440.c。
步骤:
1.修改mach-smdk2440.c文件:static struct s3c2410fb_mach_info smdk2440_lcd_cfg结构体里面的参数;

 1 /* 240x320_Mini2440 */
 2 static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
 3     .regs   = {
 4         .lcdcon1 =  S3C2410_LCDCON1_TFT16BPP | \
 5                     S3C2410_LCDCON1_TFT | \
 6                     S3C2410_LCDCON1_CLKVAL(0x06),
 7 
 8         .lcdcon2 =  S3C2410_LCDCON2_VBPD(1) | \
 9                     S3C2410_LCDCON2_LINEVAL(319) | \
10                     S3C2410_LCDCON2_VFPD(8) | \
11                     S3C2410_LCDCON2_VSPW(1),
12 
13         .lcdcon3 =  S3C2410_LCDCON3_HBPD(34) | \
14                     S3C2410_LCDCON3_HOZVAL(239) | \
15                     S3C2410_LCDCON3_HFPD(39),
16 
17         .lcdcon4 =  S3C2410_LCDCON4_MVAL(13) | \
18                     S3C2410_LCDCON4_HSPW(4),
19 
20         .lcdcon5    = S3C2410_LCDCON5_FRM565 |
21                       S3C2410_LCDCON5_INVVLINE |
22                      S3C2410_LCDCON5_INVVFRAME |
23                       S3C2410_LCDCON5_PWREN |
24                       S3C2410_LCDCON5_HWSWP,
25     },
26 
27     .gpccon      = 0xaaaa56aa,        //原为0xaaaa56aa;
28     .gpccon_mask = 0xffffffff,
29     .gpcup       = 0xffffffff,
30     .gpcup_mask     = 0xffffffff,
31 
32     .gpdcon      = 0xaaaaaaaa,
33     .gpdcon_mask = 0xffffffff,
34     .gpdup       = 0xffffffff,
35     .gpdup_mask     = 0xffffffff,
36 
37     .fixed_syncs =  1,
38     .type        =  S3C2410_LCDCON1_TFT, 
39     .width        = 240,
40     .height        = 320,
41 
42     .xres        = {
43         .min    = 240,
44         .max    = 240,
45         .defval    = 240,
46     },
47 
48     .yres        = {
49         .max    =   320,
50         .min    =   320,
51         .defval =   320,
52     },
53 
54     .bpp    = {
55         .min    =   16,
56         .max    =   16,
57         .defval =   16,
58     },
59 };

 

2.修改s3c2410fb.c文件:所有背光引脚 S3C2410_GPB0 都改为了 S3C2410_GPB1,其他代码都不修改!(源码如下)

3.结束。


执行:make uImage之后的内核下载到30000000;

问题1:字符显示和打印均没有问题,也可以用开发板按键执行“ls”命令并成功,但是屏幕显示有横条;
问题2:蜂鸣器还是老响;

问题发现及解决:上传的mach-smdk2440.c和s3c2410fb.c文件反被内核原文件覆盖了,没有修改成功,我也是醉了!重新上传
到一个新建的文件夹,然后用$ sudo cp ...命令覆盖内核原文件,执行则运行成功!

问题3:问什么上传的文件会被反覆盖?



s3c2410fb.c
  1 /* 修改s3c2410fb.c文件:所有背光引脚 S3C2410_GPB0 都改为了 S3C2410_GPB1;*/

  #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 #ifdef CONFIG_PM 27 #include <linux/pm.h> 28 #endif 29 30 #include "s3c2410fb.h" 31 32 33 static struct s3c2410fb_mach_info *mach_info; 34 35 /* Debugging stuff */ 36 #ifdef CONFIG_FB_S3C2410_DEBUG 37 static int debug = 1; 38 #else 39 static int debug = 0; 40 #endif 41 42 #define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } 43 44 /* useful functions */ 45 46 /* s3c2410fb_set_lcdaddr 47 * 48 * initialise lcd controller address pointers 49 */ 50 51 static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi) 52 { 53 struct fb_var_screeninfo *var = &fbi->fb->var; 54 unsigned long saddr1, saddr2, saddr3; 55 56 saddr1 = fbi->fb->fix.smem_start >> 1; 57 saddr2 = fbi->fb->fix.smem_start; 58 saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; 59 saddr2>>= 1; 60 61 saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x7ff); 62 63 dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); 64 dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); 65 dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); 66 67 writel(saddr1, S3C2410_LCDSADDR1); 68 writel(saddr2, S3C2410_LCDSADDR2); 69 writel(saddr3, S3C2410_LCDSADDR3); 70 } 71 72 /* s3c2410fb_calc_pixclk() 73 * 74 * calculate divisor for clk->pixclk 75 */ 76 77 static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, 78 unsigned long pixclk) 79 { 80 unsigned long clk = clk_get_rate(fbi->clk); // hclk get 81 unsigned long long div; 82 83 div = (unsigned long long)clk / pixclk; 84 return div; 85 } 86 87 /* 88 * s3c2410fb_check_var(): 89 * Get the video params out of 'var'. If a value doesn't fit, round it up, 90 * if it's too big, return -EINVAL. 91 * 92 */ 93 static int s3c2410fb_check_var(struct fb_var_screeninfo *var, 94 struct fb_info *info) 95 { 96 struct s3c2410fb_info *fbi = info->par; 97 98 dprintk("check_var(var=%p, info=%p)\n", var, info); 99 100 /* validate x/y resolution */ 101 102 if (var->yres > fbi->mach_info->yres.max) 103 var->yres = fbi->mach_info->yres.max; 104 else if (var->yres < fbi->mach_info->yres.min) 105 var->yres = fbi->mach_info->yres.min; 106 107 if (var->xres > fbi->mach_info->xres.max) 108 var->yres = fbi->mach_info->xres.max; 109 else if (var->xres < fbi->mach_info->xres.min) 110 var->xres = fbi->mach_info->xres.min; 111 112 /* validate bpp */ 113 114 if (var->bits_per_pixel > fbi->mach_info->bpp.max) 115 var->bits_per_pixel = fbi->mach_info->bpp.max; 116 else if (var->bits_per_pixel < fbi->mach_info->bpp.min) 117 var->bits_per_pixel = fbi->mach_info->bpp.min; 118 119 /* set r/g/b positions */ 120 switch (var->bits_per_pixel) { 121 case 1: 122 case 2: 123 case 4: 124 var->red.offset = 0; 125 var->red.length = var->bits_per_pixel; 126 var->green = var->red; 127 var->blue = var->red; 128 var->transp.offset = 0; 129 var->transp.length = 0; 130 break; 131 case 8: 132 if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) { 133 /* 8 bpp 332 */ 134 var->red.length = 3; 135 var->red.offset = 5; 136 var->green.length = 3; 137 var->green.offset = 2; 138 var->blue.length = 2; 139 var->blue.offset = 0; 140 var->transp.length = 0; 141 } else { 142 var->red.offset = 0; 143 var->red.length = var->bits_per_pixel; 144 var->green = var->red; 145 var->blue = var->red; 146 var->transp.offset = 0; 147 var->transp.length = 0; 148 } 149 break; 150 case 12: 151 /* 12 bpp 444 */ 152 var->red.length = 4; 153 var->red.offset = 8; 154 var->green.length = 4; 155 var->green.offset = 4; 156 var->blue.length = 4; 157 var->blue.offset = 0; 158 var->transp.length = 0; 159 break; 160 161 default: 162 case 16: 163 if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) { 164 /* 16 bpp, 565 format */ 165 var->red.offset = 11; 166 var->green.offset = 5; 167 var->blue.offset = 0; 168 var->red.length = 5; 169 var->green.length = 6; 170 var->blue.length = 5; 171 var->transp.length = 0; 172 } else { 173 /* 16 bpp, 5551 format */ 174 var->red.offset = 11; 175 var->green.offset = 6; 176 var->blue.offset = 1; 177 var->red.length = 5; 178 var->green.length = 5; 179 var->blue.length = 5; 180 var->transp.length = 0; 181 } 182 break; 183 case 24: 184 /* 24 bpp 888 */ 185 var->red.length = 8; 186 var->red.offset = 16; 187 var->green.length = 8; 188 var->green.offset = 8; 189 var->blue.length = 8; 190 var->blue.offset = 0; 191 var->transp.length = 0; 192 break; 193 194 195 } 196 return 0; 197 } 198 199 200 /* s3c2410fb_activate_var 201 * 202 * activate (set) the controller from the given framebuffer 203 * information 204 */ 205 206 static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, 207 struct fb_var_screeninfo *var) 208 { 209 int hs; 210 211 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; 212 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT; 213 214 dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); 215 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); 216 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); 217 218 fbi->regs.lcdcon1 |= fbi->mach_info->type; 219 220 if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) 221 switch (var->bits_per_pixel) { 222 case 1: 223 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; 224 break; 225 case 2: 226 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; 227 break; 228 case 4: 229 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; 230 break; 231 case 8: 232 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; 233 break; 234 case 16: 235 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; 236 break; 237 238 default: 239 /* invalid pixel depth */ 240 dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); 241 } 242 else 243 switch (var->bits_per_pixel) { 244 case 1: 245 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP; 246 break; 247 case 2: 248 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY; 249 break; 250 case 4: 251 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY; 252 break; 253 case 8: 254 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP; 255 break; 256 case 12: 257 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP; 258 break; 259 260 default: 261 /* invalid pixel depth */ 262 dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); 263 } 264 265 /* check to see if we need to update sync/borders */ 266 267 if (!fbi->mach_info->fixed_syncs) { 268 dprintk("setting vert: up=%d, low=%d, sync=%d\n", 269 var->upper_margin, var->lower_margin, 270 var->vsync_len); 271 272 dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", 273 var->left_margin, var->right_margin, 274 var->hsync_len); 275 276 fbi->regs.lcdcon2 = 277 S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | 278 S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | 279 S3C2410_LCDCON2_VSPW(var->vsync_len - 1); 280 281 fbi->regs.lcdcon3 = 282 S3C2410_LCDCON3_HBPD(var->right_margin - 1) | 283 S3C2410_LCDCON3_HFPD(var->left_margin - 1); 284 285 fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff); 286 fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1); 287 } 288 289 /* update X/Y info */ 290 291 fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); 292 fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); 293 294 switch(fbi->mach_info->type) { 295 case S3C2410_LCDCON1_DSCAN4: 296 case S3C2410_LCDCON1_STN8: 297 hs = var->xres / 8; 298 break; 299 case S3C2410_LCDCON1_STN4: 300 hs = var->xres / 4; 301 break; 302 default: 303 case S3C2410_LCDCON1_TFT: 304 hs = var->xres; 305 break; 306 307 } 308 309 /* Special cases : STN color displays */ 310 if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \ 311 || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) { 312 hs = hs * 3; 313 } 314 315 316 fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); 317 fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1); 318 319 if (var->pixclock > 0) { 320 int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); 321 322 if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) { 323 clkdiv = (clkdiv / 2) -1; 324 if (clkdiv < 0) 325 clkdiv = 0; 326 } 327 else { 328 clkdiv = (clkdiv / 2); 329 if (clkdiv < 2) 330 clkdiv = 2; 331 } 332 333 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); 334 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); 335 } 336 337 /* write new registers */ 338 339 dprintk("new register set:\n"); 340 dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1); 341 dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2); 342 dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3); 343 dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); 344 dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); 345 346 writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); 347 writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); 348 writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); 349 writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); 350 writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); 351 352 /* set lcd address pointers */ 353 s3c2410fb_set_lcdaddr(fbi); 354 355 writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); 356 } 357 358 359 /* 360 * s3c2410fb_set_par - Optional function. Alters the hardware state. 361 * @info: frame buffer structure that represents a single frame buffer 362 * 363 */ 364 static int s3c2410fb_set_par(struct fb_info *info) 365 { 366 struct s3c2410fb_info *fbi = info->par; 367 struct fb_var_screeninfo *var = &info->var; 368 369 switch (var->bits_per_pixel) 370 { 371 case 16: 372 fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; 373 break; 374 case 1: 375 fbi->fb->fix.visual = FB_VISUAL_MONO01; 376 break; 377 default: 378 fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; 379 break; 380 } 381 382 fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; 383 384 /* activate this new configuration */ 385 386 s3c2410fb_activate_var(fbi, var); 387 return 0; 388 } 389 390 static void schedule_palette_update(struct s3c2410fb_info *fbi, 391 unsigned int regno, unsigned int val) 392 { 393 unsigned long flags; 394 unsigned long irqen; 395 396 local_irq_save(flags); 397 398 fbi->palette_buffer[regno] = val; 399 400 if (!fbi->palette_ready) { 401 fbi->palette_ready = 1; 402 403 /* enable IRQ */ 404 irqen = readl(S3C2410_LCDINTMSK); 405 irqen &= ~S3C2410_LCDINT_FRSYNC; 406 writel(irqen, S3C2410_LCDINTMSK); 407 } 408 409 local_irq_restore(flags); 410 } 411 412 /* from pxafb.c */ 413 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) 414 { 415 chan &= 0xffff; 416 chan >>= 16 - bf->length; 417 return chan << bf->offset; 418 } 419 420 static int s3c2410fb_setcolreg(unsigned regno, 421 unsigned red, unsigned green, unsigned blue, 422 unsigned transp, struct fb_info *info) 423 { 424 struct s3c2410fb_info *fbi = info->par; 425 unsigned int val; 426 427 /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */ 428 429 switch (fbi->fb->fix.visual) { 430 case FB_VISUAL_TRUECOLOR: 431 /* true-colour, use pseuo-palette */ 432 433 if (regno < 16) { 434 u32 *pal = fbi->fb->pseudo_palette; 435 436 val = chan_to_field(red, &fbi->fb->var.red); 437 val |= chan_to_field(green, &fbi->fb->var.green); 438 val |= chan_to_field(blue, &fbi->fb->var.blue); 439 440 pal[regno] = val; 441 } 442 break; 443 444 case FB_VISUAL_PSEUDOCOLOR: 445 if (regno < 256) { 446 /* currently assume RGB 5-6-5 mode */ 447 448 val = ((red >> 0) & 0xf800); 449 val |= ((green >> 5) & 0x07e0); 450 val |= ((blue >> 11) & 0x001f); 451 452 writel(val, S3C2410_TFTPAL(regno)); 453 schedule_palette_update(fbi, regno, val); 454 } 455 456 break; 457 458 default: 459 return 1; /* unknown type */ 460 } 461 462 return 0; 463 } 464 465 466 /** 467 * s3c2410fb_blank 468 * @blank_mode: the blank mode we want. 469 * @info: frame buffer structure that represents a single frame buffer 470 * 471 * Blank the screen if blank_mode != 0, else unblank. Return 0 if 472 * blanking succeeded, != 0 if un-/blanking failed due to e.g. a 473 * video mode which doesn't support it. Implements VESA suspend 474 * and powerdown modes on hardware that supports disabling hsync/vsync: 475 * blank_mode == 2: suspend vsync 476 * blank_mode == 3: suspend hsync 477 * blank_mode == 4: powerdown 478 * 479 * Returns negative errno on error, or zero on success. 480 * 481 */ 482 static int s3c2410fb_blank(int blank_mode, struct fb_info *info) 483 { 484 dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); 485 486 if (mach_info == NULL) 487 return -EINVAL; 488 489 if (blank_mode == FB_BLANK_UNBLANK) 490 writel(0x0, S3C2410_TPAL); 491 else { 492 dprintk("setting TPAL to output 0x000000\n"); 493 writel(S3C2410_TPAL_EN, S3C2410_TPAL); 494 } 495 496 return 0; 497 } 498 499 static int s3c2410fb_debug_show(struct device *dev, struct device_attribute *attr, char *buf) 500 { 501 return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); 502 } 503 static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *attr, 504 const char *buf, size_t len) 505 { 506 if (mach_info == NULL) 507 return -EINVAL; 508 509 if (len < 1) 510 return -EINVAL; 511 512 if (strnicmp(buf, "on", 2) == 0 || 513 strnicmp(buf, "1", 1) == 0) { 514 debug = 1; 515 printk(KERN_DEBUG "s3c2410fb: Debug On"); 516 } else if (strnicmp(buf, "off", 3) == 0 || 517 strnicmp(buf, "0", 1) == 0) { 518 debug = 0; 519 printk(KERN_DEBUG "s3c2410fb: Debug Off"); 520 } else { 521 return -EINVAL; 522 } 523 524 return len; 525 } 526 527 528 static DEVICE_ATTR(debug, 0666, 529 s3c2410fb_debug_show, 530 s3c2410fb_debug_store); 531 532 static struct fb_ops s3c2410fb_ops = { 533 .owner = THIS_MODULE, 534 .fb_check_var = s3c2410fb_check_var, 535 .fb_set_par = s3c2410fb_set_par, 536 .fb_blank = s3c2410fb_blank, 537 .fb_setcolreg = s3c2410fb_setcolreg, 538 .fb_fillrect = cfb_fillrect, 539 .fb_copyarea = cfb_copyarea, 540 .fb_imageblit = cfb_imageblit, 541 }; 542 543 544 /* 545 * s3c2410fb_map_video_memory(): 546 * Allocates the DRAM memory for the frame buffer. This buffer is 547 * remapped into a non-cached, non-buffered, memory region to 548 * allow palette and pixel writes to occur without flushing the 549 * cache. Once this area is remapped, all virtual memory 550 * access to the video memory should occur at the new region. 551 */ 552 static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi) 553 { 554 dprintk("map_video_memory(fbi=%p)\n", fbi); 555 556 fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE); 557 fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, 558 &fbi->map_dma, GFP_KERNEL); 559 560 fbi->map_size = fbi->fb->fix.smem_len; 561 562 if (fbi->map_cpu) { 563 /* prevent initial garbage on screen */ 564 dprintk("map_video_memory: clear %p:%08x\n", 565 fbi->map_cpu, fbi->map_size); 566 memset(fbi->map_cpu, 0xf0, fbi->map_size); 567 568 fbi->screen_dma = fbi->map_dma; 569 fbi->fb->screen_base = fbi->map_cpu; 570 fbi->fb->fix.smem_start = fbi->screen_dma; 571 572 dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n", 573 fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len); 574 } 575 576 return fbi->map_cpu ? 0 : -ENOMEM; 577 } 578 579 static inline void s3c2410fb_unmap_video_memory(struct s3c2410fb_info *fbi) 580 { 581 dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); 582 } 583 584 static inline void modify_gpio(void __iomem *reg, 585 unsigned long set, unsigned long mask) 586 { 587 unsigned long tmp; 588 589 tmp = readl(reg) & ~mask; 590 writel(tmp | set, reg); 591 } 592 593 594 /* 595 * s3c2410fb_init_registers - Initialise all LCD-related registers 596 */ 597 598 static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) 599 { 600 unsigned long flags; 601 602 /* Initialise LCD with values from haret */ 603 604 local_irq_save(flags); 605 606 /* modify the gpio(s) with interrupts set (bjd) */ 607 608 modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask); 609 modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask); 610 modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask); 611 modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask); 612 613 local_irq_restore(flags); 614 615 writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); 616 writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); 617 writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); 618 writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); 619 writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); 620 621 s3c2410fb_set_lcdaddr(fbi); 622 623 dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); 624 writel(mach_info->lpcsel, S3C2410_LPCSEL); 625 626 dprintk("replacing TPAL %08x\n", readl(S3C2410_TPAL)); 627 628 /* ensure temporary palette disabled */ 629 writel(0x00, S3C2410_TPAL); 630 631 632 #if 0 633 /* ghcstop modified */ 634 s3c2410_gpio_cfgpin(S3C2410_GPC5, S3C2410_GPC5_OUTP); // lcd display enable/disable 635 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP); // back light control 636 s3c2410_gpio_cfgpin(S3C2410_GPH6, S3C2410_GPH6_OUTP); 637 638 s3c2410_gpio_pullup(S3C2410_GPC5, 0); 639 s3c2410_gpio_pullup(S3C2410_GPB1, 0); 640 s3c2410_gpio_pullup(S3C2410_GPH6, 0); 641 642 s3c2410_gpio_setpin(S3C2410_GPC5, 1); 643 s3c2410_gpio_setpin(S3C2410_GPH6, 1); 644 s3c2410_gpio_setpin(S3C2410_GPB1, 1); 645 #else 646 /* thisway.diy@163.com modify again, for eBlocks */ 647 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP); // back light control 648 649 s3c2410_gpio_pullup(S3C2410_GPB1, 0); 650 651 s3c2410_gpio_setpin(S3C2410_GPB1, 1); // back light control, enable 652 #endif 653 654 /* probably not required */ 655 msleep(10); 656 657 /* Enable video by setting the ENVID bit to 1 */ 658 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; 659 writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); 660 661 // add by thisway.diy@163.com, for eBlocks 662 s3c2410_gpio_setpin(S3C2410_GPB1, 1); // back light control 663 664 return 0; 665 } 666 667 static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) 668 { 669 unsigned int i; 670 unsigned long ent; 671 672 fbi->palette_ready = 0; 673 674 for (i = 0; i < 256; i++) { 675 if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR) 676 continue; 677 678 writel(ent, S3C2410_TFTPAL(i)); 679 680 /* it seems the only way to know exactly 681 * if the palette wrote ok, is to check 682 * to see if the value verifies ok 683 */ 684 685 if (readw(S3C2410_TFTPAL(i)) == ent) 686 fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR; 687 else 688 fbi->palette_ready = 1; /* retry */ 689 } 690 } 691 692 static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) 693 { 694 struct s3c2410fb_info *fbi = dev_id; 695 unsigned long lcdirq = readl(S3C2410_LCDINTPND); 696 697 if (lcdirq & S3C2410_LCDINT_FRSYNC) { 698 if (fbi->palette_ready) 699 s3c2410fb_write_palette(fbi); 700 701 writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDINTPND); 702 writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDSRCPND); 703 } 704 705 return IRQ_HANDLED; 706 } 707 708 static char driver_name[]="s3c2410fb"; 709 710 static int __init s3c2410fb_probe(struct platform_device *pdev) 711 { 712 struct s3c2410fb_info *info; 713 struct fb_info *fbinfo; 714 struct s3c2410fb_hw *mregs; 715 int ret; 716 int irq; 717 int i; 718 u32 lcdcon1; 719 720 mach_info = pdev->dev.platform_data; 721 if (mach_info == NULL) { 722 dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n"); 723 return -EINVAL; 724 } 725 726 mregs = &mach_info->regs; 727 728 irq = platform_get_irq(pdev, 0); 729 if (irq < 0) { 730 dev_err(&pdev->dev, "no irq for device\n"); 731 return -ENOENT; 732 } 733 734 fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); 735 if (!fbinfo) { 736 return -ENOMEM; 737 } 738 739 740 info = fbinfo->par; 741 info->fb = fbinfo; 742 info->dev = &pdev->dev; 743 744 platform_set_drvdata(pdev, fbinfo); 745 746 dprintk("devinit\n"); 747 748 strcpy(fbinfo->fix.id, driver_name); 749 750 memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); 751 752 /* Stop the video and unset ENVID if set */ 753 info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; 754 lcdcon1 = readl(S3C2410_LCDCON1); 755 writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); 756 757 // add by thisway.diy@163.com, for eBlocks 758 s3c2410_gpio_setpin(S3C2410_GPB1, 0); // back light control 759 760 info->mach_info = pdev->dev.platform_data; 761 762 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; 763 fbinfo->fix.type_aux = 0; 764 fbinfo->fix.xpanstep = 0; 765 fbinfo->fix.ypanstep = 0; 766 fbinfo->fix.ywrapstep = 0; 767 fbinfo->fix.accel = FB_ACCEL_NONE; 768 769 fbinfo->var.nonstd = 0; 770 fbinfo->var.activate = FB_ACTIVATE_NOW; 771 fbinfo->var.height = mach_info->height; 772 fbinfo->var.width = mach_info->width; 773 fbinfo->var.accel_flags = 0; 774 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; 775 776 fbinfo->fbops = &s3c2410fb_ops; 777 fbinfo->flags = FBINFO_FLAG_DEFAULT; 778 fbinfo->pseudo_palette = &info->pseudo_pal; 779 780 fbinfo->var.xres = mach_info->xres.defval; 781 fbinfo->var.xres_virtual = mach_info->xres.defval; 782 fbinfo->var.yres = mach_info->yres.defval; 783 fbinfo->var.yres_virtual = mach_info->yres.defval; 784 fbinfo->var.bits_per_pixel = mach_info->bpp.defval; 785 786 fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1; 787 fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) + 1; 788 fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1; 789 790 fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1; 791 fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1; 792 fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1; 793 794 fbinfo->var.red.offset = 11; 795 fbinfo->var.green.offset = 5; 796 fbinfo->var.blue.offset = 0; 797 fbinfo->var.transp.offset = 0; 798 fbinfo->var.red.length = 5; 799 fbinfo->var.green.length = 6; 800 fbinfo->var.blue.length = 5; 801 fbinfo->var.transp.length = 0; 802 fbinfo->fix.smem_len = mach_info->xres.max * 803 mach_info->yres.max * 804 mach_info->bpp.max / 8; 805 806 for (i = 0; i < 256; i++) 807 info->palette_buffer[i] = PALETTE_BUFF_CLEAR; 808 809 if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c2410-lcd")) { 810 ret = -EBUSY; 811 goto dealloc_fb; 812 } 813 814 815 dprintk("got LCD region\n"); 816 817 ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info); 818 if (ret) { 819 dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); 820 ret = -EBUSY; 821 goto release_mem; 822 } 823 824 info->clk = clk_get(NULL, "lcd"); 825 if (!info->clk || IS_ERR(info->clk)) { 826 printk(KERN_ERR "failed to get lcd clock source\n"); 827 ret = -ENOENT; 828 goto release_irq; 829 } 830 831 clk_enable(info->clk); 832 dprintk("got and enabled clock\n"); 833 834 msleep(1); 835 836 /* Initialize video memory */ 837 ret = s3c2410fb_map_video_memory(info); 838 if (ret) { 839 printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret); 840 ret = -ENOMEM; 841 goto release_clock; 842 } 843 dprintk("got video memory\n"); 844 845 ret = s3c2410fb_init_registers(info); 846 847 ret = s3c2410fb_check_var(&fbinfo->var, fbinfo); 848 849 ret = register_framebuffer(fbinfo); 850 if (ret < 0) { 851 printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret); 852 goto free_video_memory; 853 } 854 855 /* create device files */ 856 device_create_file(&pdev->dev, &dev_attr_debug); 857 858 printk(KERN_INFO "fb%d: %s frame buffer device\n", 859 fbinfo->node, fbinfo->fix.id); 860 861 return 0; 862 863 free_video_memory: 864 s3c2410fb_unmap_video_memory(info); 865 release_clock: 866 clk_disable(info->clk); 867 clk_put(info->clk); 868 release_irq: 869 free_irq(irq,info); 870 release_mem: 871 release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD); 872 dealloc_fb: 873 framebuffer_release(fbinfo); 874 return ret; 875 } 876 877 /* s3c2410fb_stop_lcd 878 * 879 * shutdown the lcd controller 880 */ 881 882 static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) 883 { 884 unsigned long flags; 885 886 local_irq_save(flags); 887 888 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; 889 writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); 890 891 // add by thisway.diy@163.com, for eBlocks 892 s3c2410_gpio_setpin(S3C2410_GPB1, 0); // back light control 893 894 local_irq_restore(flags); 895 } 896 897 /* 898 * Cleanup 899 */ 900 static int s3c2410fb_remove(struct platform_device *pdev) 901 { 902 struct fb_info *fbinfo = platform_get_drvdata(pdev); 903 struct s3c2410fb_info *info = fbinfo->par; 904 int irq; 905 906 s3c2410fb_stop_lcd(info); 907 msleep(1); 908 909 s3c2410fb_unmap_video_memory(info); 910 911 if (info->clk) { 912 clk_disable(info->clk); 913 clk_put(info->clk); 914 info->clk = NULL; 915 } 916 917 irq = platform_get_irq(pdev, 0); 918 free_irq(irq,info); 919 release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD); 920 unregister_framebuffer(fbinfo); 921 922 return 0; 923 } 924 925 #ifdef CONFIG_PM 926 927 /* suspend and resume support for the lcd controller */ 928 929 static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) 930 { 931 struct fb_info *fbinfo = platform_get_drvdata(dev); 932 struct s3c2410fb_info *info = fbinfo->par; 933 printk("100ask suspend\n"); 934 s3c2410fb_stop_lcd(info); 935 936 /* sleep before disabling the clock, we need to ensure 937 * the LCD DMA engine is not going to get back on the bus 938 * before the clock goes off again (bjd) */ 939 940 msleep(1); 941 clk_disable(info->clk); 942 943 return 0; 944 } 945 946 static int s3c2410fb_resume(struct platform_device *dev) 947 { 948 struct fb_info *fbinfo = platform_get_drvdata(dev); 949 struct s3c2410fb_info *info = fbinfo->par; 950 951 printk("100ask resume\n"); 952 clk_enable(info->clk); 953 msleep(1); 954 955 s3c2410fb_init_registers(info); 956 957 return 0; 958 } 959 960 #else 961 #define s3c2410fb_suspend NULL 962 #define s3c2410fb_resume NULL 963 #endif 964 965 static struct platform_driver s3c2410fb_driver = { 966 .probe = s3c2410fb_probe, 967 .remove = s3c2410fb_remove, 968 .suspend = s3c2410fb_suspend, 969 .resume = s3c2410fb_resume, 970 .driver = { 971 .name = "s3c2410-lcd", 972 .owner = THIS_MODULE, 973 }, 974 }; 975 976 int __devinit s3c2410fb_init(void) 977 { 978 return platform_driver_register(&s3c2410fb_driver); 979 } 980 981 static void __exit s3c2410fb_cleanup(void) 982 { 983 platform_driver_unregister(&s3c2410fb_driver); 984 } 985 986 987 module_init(s3c2410fb_init); 988 module_exit(s3c2410fb_cleanup); 989 990 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, Ben Dooks <ben-linux@fluff.org>"); 991 MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); 992 MODULE_LICENSE("GPL");

 


 

posted @ 2018-12-25 19:12  大秦长剑  阅读(990)  评论(0编辑  收藏  举报