0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #include <linux/clk.h>
0045 #include <linux/module.h>
0046 #include <linux/kernel.h>
0047 #include <linux/errno.h>
0048 #include <linux/string.h>
0049 #include <linux/mm.h>
0050 #include <linux/fb.h>
0051 #include <linux/init.h>
0052 #include <linux/interrupt.h>
0053 #include <linux/ctype.h>
0054 #include <linux/dma-mapping.h>
0055 #include <linux/platform_device.h>
0056 #include <linux/slab.h>
0057
0058 #include <asm/mach-au1x00/au1000.h>
0059
0060 #define DEBUG 0
0061
0062 #include "au1100fb.h"
0063
0064 #define DRIVER_NAME "au1100fb"
0065 #define DRIVER_DESC "LCD controller driver for AU1100 processors"
0066
0067 #define to_au1100fb_device(_info) \
0068 (_info ? container_of(_info, struct au1100fb_device, info) : NULL);
0069
0070
0071
0072
0073
0074 struct fb_bitfield rgb_bitfields[][4] =
0075 {
0076
0077 { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
0078 { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
0079 { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
0080 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
0081 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
0082
0083
0084 { { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } },
0085 };
0086
0087 static struct fb_fix_screeninfo au1100fb_fix = {
0088 .id = "AU1100 FB",
0089 .xpanstep = 1,
0090 .ypanstep = 1,
0091 .type = FB_TYPE_PACKED_PIXELS,
0092 .accel = FB_ACCEL_NONE,
0093 };
0094
0095 static struct fb_var_screeninfo au1100fb_var = {
0096 .activate = FB_ACTIVATE_NOW,
0097 .height = -1,
0098 .width = -1,
0099 .vmode = FB_VMODE_NONINTERLACED,
0100 };
0101
0102
0103
0104
0105
0106 static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
0107 {
0108 struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
0109
0110 print_dbg("fb_blank %d %p", blank_mode, fbi);
0111
0112 switch (blank_mode) {
0113
0114 case VESA_NO_BLANKING:
0115
0116 fbdev->regs->lcd_control |= LCD_CONTROL_GO;
0117 wmb();
0118 break;
0119
0120 case VESA_VSYNC_SUSPEND:
0121 case VESA_HSYNC_SUSPEND:
0122 case VESA_POWERDOWN:
0123
0124 fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
0125 wmb();
0126 break;
0127 default:
0128 break;
0129
0130 }
0131 return 0;
0132 }
0133
0134
0135
0136
0137
0138 int au1100fb_setmode(struct au1100fb_device *fbdev)
0139 {
0140 struct fb_info *info = &fbdev->info;
0141 u32 words;
0142 int index;
0143
0144 if (!fbdev)
0145 return -EINVAL;
0146
0147
0148 if (panel_is_active(fbdev->panel) || panel_is_color(fbdev->panel)) {
0149 if (info->var.bits_per_pixel <= 8) {
0150
0151 info->var.red.offset = 0;
0152 info->var.red.length = info->var.bits_per_pixel;
0153 info->var.red.msb_right = 0;
0154
0155 info->var.green.offset = 0;
0156 info->var.green.length = info->var.bits_per_pixel;
0157 info->var.green.msb_right = 0;
0158
0159 info->var.blue.offset = 0;
0160 info->var.blue.length = info->var.bits_per_pixel;
0161 info->var.blue.msb_right = 0;
0162
0163 info->var.transp.offset = 0;
0164 info->var.transp.length = 0;
0165 info->var.transp.msb_right = 0;
0166
0167 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0168 info->fix.line_length = info->var.xres_virtual /
0169 (8/info->var.bits_per_pixel);
0170 } else {
0171
0172 index = (fbdev->panel->control_base & LCD_CONTROL_SBPPF_MASK) >> LCD_CONTROL_SBPPF_BIT;
0173 info->var.red = rgb_bitfields[index][0];
0174 info->var.green = rgb_bitfields[index][1];
0175 info->var.blue = rgb_bitfields[index][2];
0176 info->var.transp = rgb_bitfields[index][3];
0177
0178 info->fix.visual = FB_VISUAL_TRUECOLOR;
0179 info->fix.line_length = info->var.xres_virtual << 1;
0180 }
0181 } else {
0182
0183 info->fix.visual = FB_VISUAL_MONO10;
0184 info->fix.line_length = info->var.xres_virtual / 8;
0185 }
0186
0187 info->screen_size = info->fix.line_length * info->var.yres_virtual;
0188 info->var.rotate = ((fbdev->panel->control_base&LCD_CONTROL_SM_MASK) \
0189 >> LCD_CONTROL_SM_BIT) * 90;
0190
0191
0192 fbdev->regs->lcd_control = fbdev->panel->control_base;
0193 fbdev->regs->lcd_horztiming = fbdev->panel->horztiming;
0194 fbdev->regs->lcd_verttiming = fbdev->panel->verttiming;
0195 fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base;
0196 fbdev->regs->lcd_intenable = 0;
0197 fbdev->regs->lcd_intstatus = 0;
0198 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys);
0199
0200 if (panel_is_dual(fbdev->panel)) {
0201
0202
0203 if (info->var.yres_virtual >= (info->var.yres << 1)) {
0204 fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys +
0205 (info->fix.line_length *
0206 (info->var.yres_virtual >> 1)));
0207 } else {
0208 fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys);
0209 }
0210 }
0211
0212 words = info->fix.line_length / sizeof(u32);
0213 if (!info->var.rotate || (info->var.rotate == 180)) {
0214 words *= info->var.yres_virtual;
0215 if (info->var.rotate ) {
0216 words -= (words % 8);
0217 }
0218 }
0219 fbdev->regs->lcd_words = LCD_WRD_WRDS_N(words);
0220
0221 fbdev->regs->lcd_pwmdiv = 0;
0222 fbdev->regs->lcd_pwmhi = 0;
0223
0224
0225 fbdev->regs->lcd_control |= LCD_CONTROL_GO;
0226 mdelay(10);
0227 au1100fb_fb_blank(VESA_NO_BLANKING, info);
0228
0229 return 0;
0230 }
0231
0232
0233
0234
0235 int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
0236 {
0237 struct au1100fb_device *fbdev;
0238 u32 *palette;
0239 u32 value;
0240
0241 fbdev = to_au1100fb_device(fbi);
0242 palette = fbdev->regs->lcd_palettebase;
0243
0244 if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1))
0245 return -EINVAL;
0246
0247 if (fbi->var.grayscale) {
0248
0249 red = green = blue =
0250 (19595 * red + 38470 * green + 7471 * blue) >> 16;
0251 }
0252
0253 if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
0254
0255 if (regno > 16)
0256 return -EINVAL;
0257
0258 palette = (u32*)fbi->pseudo_palette;
0259
0260 red >>= (16 - fbi->var.red.length);
0261 green >>= (16 - fbi->var.green.length);
0262 blue >>= (16 - fbi->var.blue.length);
0263
0264 value = (red << fbi->var.red.offset) |
0265 (green << fbi->var.green.offset)|
0266 (blue << fbi->var.blue.offset);
0267 value &= 0xFFFF;
0268
0269 } else if (panel_is_active(fbdev->panel)) {
0270
0271 value = (red & 0xF800)|((green >> 5) & 0x07E0)|((blue >> 11) & 0x001F);
0272 value &= 0xFFFF;
0273
0274 } else if (panel_is_color(fbdev->panel)) {
0275
0276 value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) |
0277 ((green >> 8) & 0x00F0) |
0278 (((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00);
0279 value &= 0xFFF;
0280 } else {
0281
0282 value = (green >> 12) & 0x000F;
0283 value &= 0xF;
0284 }
0285
0286 palette[regno] = value;
0287
0288 return 0;
0289 }
0290
0291
0292
0293
0294 int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
0295 {
0296 struct au1100fb_device *fbdev;
0297 int dy;
0298
0299 fbdev = to_au1100fb_device(fbi);
0300
0301 print_dbg("fb_pan_display %p %p", var, fbi);
0302
0303 if (!var || !fbdev) {
0304 return -EINVAL;
0305 }
0306
0307 if (var->xoffset - fbi->var.xoffset) {
0308
0309 return -EINVAL;
0310 }
0311
0312 print_dbg("fb_pan_display 2 %p %p", var, fbi);
0313 dy = var->yoffset - fbi->var.yoffset;
0314 if (dy) {
0315
0316 u32 dmaaddr;
0317
0318 print_dbg("Panning screen of %d lines", dy);
0319
0320 dmaaddr = fbdev->regs->lcd_dmaaddr0;
0321 dmaaddr += (fbi->fix.line_length * dy);
0322
0323
0324 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr);
0325
0326 if (panel_is_dual(fbdev->panel)) {
0327 dmaaddr = fbdev->regs->lcd_dmaaddr1;
0328 dmaaddr += (fbi->fix.line_length * dy);
0329 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr);
0330 }
0331 }
0332 print_dbg("fb_pan_display 3 %p %p", var, fbi);
0333
0334 return 0;
0335 }
0336
0337
0338
0339
0340
0341 int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
0342 {
0343 struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
0344
0345 pgprot_val(vma->vm_page_prot) |= (6 << 9);
0346
0347 return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys,
0348 fbdev->fb_len);
0349 }
0350
0351 static const struct fb_ops au1100fb_ops =
0352 {
0353 .owner = THIS_MODULE,
0354 .fb_setcolreg = au1100fb_fb_setcolreg,
0355 .fb_blank = au1100fb_fb_blank,
0356 .fb_pan_display = au1100fb_fb_pan_display,
0357 .fb_fillrect = cfb_fillrect,
0358 .fb_copyarea = cfb_copyarea,
0359 .fb_imageblit = cfb_imageblit,
0360 .fb_mmap = au1100fb_fb_mmap,
0361 };
0362
0363
0364
0365
0366 static int au1100fb_setup(struct au1100fb_device *fbdev)
0367 {
0368 char *this_opt, *options;
0369 int num_panels = ARRAY_SIZE(known_lcd_panels);
0370
0371 if (num_panels <= 0) {
0372 print_err("No LCD panels supported by driver!");
0373 return -ENODEV;
0374 }
0375
0376 if (fb_get_options(DRIVER_NAME, &options))
0377 return -ENODEV;
0378 if (!options)
0379 return -ENODEV;
0380
0381 while ((this_opt = strsep(&options, ",")) != NULL) {
0382
0383 if (!strncmp(this_opt, "panel:", 6)) {
0384 int i;
0385 this_opt += 6;
0386 for (i = 0; i < num_panels; i++) {
0387 if (!strncmp(this_opt, known_lcd_panels[i].name,
0388 strlen(this_opt))) {
0389 fbdev->panel = &known_lcd_panels[i];
0390 fbdev->panel_idx = i;
0391 break;
0392 }
0393 }
0394 if (i >= num_panels) {
0395 print_warn("Panel '%s' not supported!", this_opt);
0396 return -ENODEV;
0397 }
0398 }
0399
0400 else
0401 print_warn("Unsupported option \"%s\"", this_opt);
0402 }
0403
0404 print_info("Panel=%s", fbdev->panel->name);
0405
0406 return 0;
0407 }
0408
0409 static int au1100fb_drv_probe(struct platform_device *dev)
0410 {
0411 struct au1100fb_device *fbdev;
0412 struct resource *regs_res;
0413 struct clk *c;
0414
0415
0416 fbdev = devm_kzalloc(&dev->dev, sizeof(*fbdev), GFP_KERNEL);
0417 if (!fbdev)
0418 return -ENOMEM;
0419
0420 if (au1100fb_setup(fbdev))
0421 goto failed;
0422
0423 platform_set_drvdata(dev, (void *)fbdev);
0424 fbdev->dev = &dev->dev;
0425
0426
0427 regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
0428 if (!regs_res) {
0429 print_err("fail to retrieve registers resource");
0430 return -EFAULT;
0431 }
0432
0433 au1100fb_fix.mmio_start = regs_res->start;
0434 au1100fb_fix.mmio_len = resource_size(regs_res);
0435
0436 if (!devm_request_mem_region(&dev->dev,
0437 au1100fb_fix.mmio_start,
0438 au1100fb_fix.mmio_len,
0439 DRIVER_NAME)) {
0440 print_err("fail to lock memory region at 0x%08lx",
0441 au1100fb_fix.mmio_start);
0442 return -EBUSY;
0443 }
0444
0445 fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(au1100fb_fix.mmio_start);
0446
0447 print_dbg("Register memory map at %p", fbdev->regs);
0448 print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
0449
0450 c = clk_get(NULL, "lcd_intclk");
0451 if (!IS_ERR(c)) {
0452 fbdev->lcdclk = c;
0453 clk_set_rate(c, 48000000);
0454 clk_prepare_enable(c);
0455 }
0456
0457
0458 fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
0459 (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
0460
0461 fbdev->fb_mem = dmam_alloc_coherent(&dev->dev,
0462 PAGE_ALIGN(fbdev->fb_len),
0463 &fbdev->fb_phys, GFP_KERNEL);
0464 if (!fbdev->fb_mem) {
0465 print_err("fail to allocate framebuffer (size: %dK))",
0466 fbdev->fb_len / 1024);
0467 return -ENOMEM;
0468 }
0469
0470 au1100fb_fix.smem_start = fbdev->fb_phys;
0471 au1100fb_fix.smem_len = fbdev->fb_len;
0472
0473 print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
0474 print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
0475
0476
0477 au1100fb_var.bits_per_pixel = fbdev->panel->bpp;
0478 au1100fb_var.xres = fbdev->panel->xres;
0479 au1100fb_var.xres_virtual = au1100fb_var.xres;
0480 au1100fb_var.yres = fbdev->panel->yres;
0481 au1100fb_var.yres_virtual = au1100fb_var.yres;
0482
0483 fbdev->info.screen_base = fbdev->fb_mem;
0484 fbdev->info.fbops = &au1100fb_ops;
0485 fbdev->info.fix = au1100fb_fix;
0486
0487 fbdev->info.pseudo_palette =
0488 devm_kcalloc(&dev->dev, 16, sizeof(u32), GFP_KERNEL);
0489 if (!fbdev->info.pseudo_palette)
0490 return -ENOMEM;
0491
0492 if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
0493 print_err("Fail to allocate colormap (%d entries)",
0494 AU1100_LCD_NBR_PALETTE_ENTRIES);
0495 return -EFAULT;
0496 }
0497
0498 fbdev->info.var = au1100fb_var;
0499
0500
0501 au1100fb_setmode(fbdev);
0502
0503
0504 if (register_framebuffer(&fbdev->info) < 0) {
0505 print_err("cannot register new framebuffer");
0506 goto failed;
0507 }
0508
0509 return 0;
0510
0511 failed:
0512 if (fbdev->lcdclk) {
0513 clk_disable_unprepare(fbdev->lcdclk);
0514 clk_put(fbdev->lcdclk);
0515 }
0516 if (fbdev->info.cmap.len != 0) {
0517 fb_dealloc_cmap(&fbdev->info.cmap);
0518 }
0519
0520 return -ENODEV;
0521 }
0522
0523 int au1100fb_drv_remove(struct platform_device *dev)
0524 {
0525 struct au1100fb_device *fbdev = NULL;
0526
0527 if (!dev)
0528 return -ENODEV;
0529
0530 fbdev = platform_get_drvdata(dev);
0531
0532 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
0533 au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
0534 #endif
0535 fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
0536
0537
0538 unregister_framebuffer(&fbdev->info);
0539
0540 fb_dealloc_cmap(&fbdev->info.cmap);
0541
0542 if (fbdev->lcdclk) {
0543 clk_disable_unprepare(fbdev->lcdclk);
0544 clk_put(fbdev->lcdclk);
0545 }
0546
0547 return 0;
0548 }
0549
0550 #ifdef CONFIG_PM
0551 static struct au1100fb_regs fbregs;
0552
0553 int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state)
0554 {
0555 struct au1100fb_device *fbdev = platform_get_drvdata(dev);
0556
0557 if (!fbdev)
0558 return 0;
0559
0560
0561 au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
0562
0563 clk_disable(fbdev->lcdclk);
0564
0565 memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
0566
0567 return 0;
0568 }
0569
0570 int au1100fb_drv_resume(struct platform_device *dev)
0571 {
0572 struct au1100fb_device *fbdev = platform_get_drvdata(dev);
0573
0574 if (!fbdev)
0575 return 0;
0576
0577 memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
0578
0579 clk_enable(fbdev->lcdclk);
0580
0581
0582 au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
0583
0584 return 0;
0585 }
0586 #else
0587 #define au1100fb_drv_suspend NULL
0588 #define au1100fb_drv_resume NULL
0589 #endif
0590
0591 static struct platform_driver au1100fb_driver = {
0592 .driver = {
0593 .name = "au1100-lcd",
0594 },
0595 .probe = au1100fb_drv_probe,
0596 .remove = au1100fb_drv_remove,
0597 .suspend = au1100fb_drv_suspend,
0598 .resume = au1100fb_drv_resume,
0599 };
0600 module_platform_driver(au1100fb_driver);
0601
0602 MODULE_DESCRIPTION(DRIVER_DESC);
0603 MODULE_LICENSE("GPL");