0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/sched.h>
0018 #include <linux/string.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/slab.h>
0021 #include <linux/fb.h>
0022 #include <linux/delay.h>
0023 #include <linux/init.h>
0024 #include <linux/io.h>
0025 #include <linux/ioport.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/dma-mapping.h>
0028 #include <linux/clk.h>
0029 #include <linux/err.h>
0030 #include <linux/uaccess.h>
0031 #include <video/pxa168fb.h>
0032
0033 #include "pxa168fb.h"
0034
0035 #define DEFAULT_REFRESH 60
0036
0037 static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
0038 {
0039
0040
0041
0042 if (var->bits_per_pixel == 8)
0043 return PIX_FMT_PSEUDOCOLOR;
0044
0045
0046
0047
0048 if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
0049 var->green.length <= 6 && var->blue.length <= 5) {
0050 if (var->transp.length == 0) {
0051 if (var->red.offset >= var->blue.offset)
0052 return PIX_FMT_RGB565;
0053 else
0054 return PIX_FMT_BGR565;
0055 }
0056
0057 if (var->transp.length == 1 && var->green.length <= 5) {
0058 if (var->red.offset >= var->blue.offset)
0059 return PIX_FMT_RGB1555;
0060 else
0061 return PIX_FMT_BGR1555;
0062 }
0063 }
0064
0065
0066
0067
0068 if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
0069 var->green.length <= 8 && var->blue.length <= 8) {
0070 if (var->bits_per_pixel == 24 && var->transp.length == 0) {
0071 if (var->red.offset >= var->blue.offset)
0072 return PIX_FMT_RGB888PACK;
0073 else
0074 return PIX_FMT_BGR888PACK;
0075 }
0076
0077 if (var->bits_per_pixel == 32 && var->transp.length == 8) {
0078 if (var->red.offset >= var->blue.offset)
0079 return PIX_FMT_RGBA888;
0080 else
0081 return PIX_FMT_BGRA888;
0082 } else {
0083 if (var->red.offset >= var->blue.offset)
0084 return PIX_FMT_RGB888UNPACK;
0085 else
0086 return PIX_FMT_BGR888UNPACK;
0087 }
0088 }
0089
0090 return -EINVAL;
0091 }
0092
0093 static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
0094 {
0095 switch (pix_fmt) {
0096 case PIX_FMT_RGB565:
0097 var->bits_per_pixel = 16;
0098 var->red.offset = 11; var->red.length = 5;
0099 var->green.offset = 5; var->green.length = 6;
0100 var->blue.offset = 0; var->blue.length = 5;
0101 var->transp.offset = 0; var->transp.length = 0;
0102 break;
0103 case PIX_FMT_BGR565:
0104 var->bits_per_pixel = 16;
0105 var->red.offset = 0; var->red.length = 5;
0106 var->green.offset = 5; var->green.length = 6;
0107 var->blue.offset = 11; var->blue.length = 5;
0108 var->transp.offset = 0; var->transp.length = 0;
0109 break;
0110 case PIX_FMT_RGB1555:
0111 var->bits_per_pixel = 16;
0112 var->red.offset = 10; var->red.length = 5;
0113 var->green.offset = 5; var->green.length = 5;
0114 var->blue.offset = 0; var->blue.length = 5;
0115 var->transp.offset = 15; var->transp.length = 1;
0116 break;
0117 case PIX_FMT_BGR1555:
0118 var->bits_per_pixel = 16;
0119 var->red.offset = 0; var->red.length = 5;
0120 var->green.offset = 5; var->green.length = 5;
0121 var->blue.offset = 10; var->blue.length = 5;
0122 var->transp.offset = 15; var->transp.length = 1;
0123 break;
0124 case PIX_FMT_RGB888PACK:
0125 var->bits_per_pixel = 24;
0126 var->red.offset = 16; var->red.length = 8;
0127 var->green.offset = 8; var->green.length = 8;
0128 var->blue.offset = 0; var->blue.length = 8;
0129 var->transp.offset = 0; var->transp.length = 0;
0130 break;
0131 case PIX_FMT_BGR888PACK:
0132 var->bits_per_pixel = 24;
0133 var->red.offset = 0; var->red.length = 8;
0134 var->green.offset = 8; var->green.length = 8;
0135 var->blue.offset = 16; var->blue.length = 8;
0136 var->transp.offset = 0; var->transp.length = 0;
0137 break;
0138 case PIX_FMT_RGBA888:
0139 var->bits_per_pixel = 32;
0140 var->red.offset = 16; var->red.length = 8;
0141 var->green.offset = 8; var->green.length = 8;
0142 var->blue.offset = 0; var->blue.length = 8;
0143 var->transp.offset = 24; var->transp.length = 8;
0144 break;
0145 case PIX_FMT_BGRA888:
0146 var->bits_per_pixel = 32;
0147 var->red.offset = 0; var->red.length = 8;
0148 var->green.offset = 8; var->green.length = 8;
0149 var->blue.offset = 16; var->blue.length = 8;
0150 var->transp.offset = 24; var->transp.length = 8;
0151 break;
0152 case PIX_FMT_PSEUDOCOLOR:
0153 var->bits_per_pixel = 8;
0154 var->red.offset = 0; var->red.length = 8;
0155 var->green.offset = 0; var->green.length = 8;
0156 var->blue.offset = 0; var->blue.length = 8;
0157 var->transp.offset = 0; var->transp.length = 0;
0158 break;
0159 }
0160 }
0161
0162 static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
0163 struct fb_videomode *mode, int pix_fmt, int ystretch)
0164 {
0165 struct fb_info *info = fbi->info;
0166
0167 set_pix_fmt(var, pix_fmt);
0168
0169 var->xres = mode->xres;
0170 var->yres = mode->yres;
0171 var->xres_virtual = max(var->xres, var->xres_virtual);
0172 if (ystretch)
0173 var->yres_virtual = info->fix.smem_len /
0174 (var->xres_virtual * (var->bits_per_pixel >> 3));
0175 else
0176 var->yres_virtual = max(var->yres, var->yres_virtual);
0177 var->grayscale = 0;
0178 var->accel_flags = FB_ACCEL_NONE;
0179 var->pixclock = mode->pixclock;
0180 var->left_margin = mode->left_margin;
0181 var->right_margin = mode->right_margin;
0182 var->upper_margin = mode->upper_margin;
0183 var->lower_margin = mode->lower_margin;
0184 var->hsync_len = mode->hsync_len;
0185 var->vsync_len = mode->vsync_len;
0186 var->sync = mode->sync;
0187 var->vmode = FB_VMODE_NONINTERLACED;
0188 var->rotate = FB_ROTATE_UR;
0189 }
0190
0191 static int pxa168fb_check_var(struct fb_var_screeninfo *var,
0192 struct fb_info *info)
0193 {
0194 struct pxa168fb_info *fbi = info->par;
0195 int pix_fmt;
0196
0197
0198
0199
0200 pix_fmt = determine_best_pix_fmt(var);
0201 if (pix_fmt < 0)
0202 return pix_fmt;
0203 set_pix_fmt(var, pix_fmt);
0204 fbi->pix_fmt = pix_fmt;
0205
0206
0207
0208
0209 if (var->xoffset + var->xres > var->xres_virtual)
0210 return -EINVAL;
0211 if (var->yoffset + var->yres > var->yres_virtual)
0212 return -EINVAL;
0213 if (var->xres + var->right_margin +
0214 var->hsync_len + var->left_margin > 2048)
0215 return -EINVAL;
0216 if (var->yres + var->lower_margin +
0217 var->vsync_len + var->upper_margin > 2048)
0218 return -EINVAL;
0219
0220
0221
0222
0223 if (var->xres_virtual * var->yres_virtual *
0224 (var->bits_per_pixel >> 3) > info->fix.smem_len)
0225 return -EINVAL;
0226
0227 return 0;
0228 }
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 static void set_clock_divider(struct pxa168fb_info *fbi,
0241 const struct fb_videomode *m)
0242 {
0243 int divider_int;
0244 int needed_pixclk;
0245 u64 div_result;
0246 u32 x = 0;
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 if (!m || !m->pixclock || !m->refresh) {
0258 dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
0259 return;
0260 }
0261
0262
0263
0264
0265 x = 0x80000000;
0266
0267
0268
0269
0270 div_result = 1000000000000ll;
0271 do_div(div_result, m->pixclock);
0272 needed_pixclk = (u32)div_result;
0273
0274 divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
0275
0276
0277 if (divider_int < 2) {
0278 dev_warn(fbi->dev, "Warning: clock source is too slow. "
0279 "Try smaller resolution\n");
0280 divider_int = 2;
0281 }
0282
0283
0284
0285
0286 x |= divider_int;
0287 writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
0288 }
0289
0290 static void set_dma_control0(struct pxa168fb_info *fbi)
0291 {
0292 u32 x;
0293
0294
0295
0296
0297 x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
0298 x &= ~CFG_GRA_ENA_MASK;
0299 x |= fbi->active ? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
0300
0301
0302
0303
0304
0305 if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
0306 x |= 0x10000000;
0307
0308
0309
0310
0311 x &= ~(0xF << 16);
0312 x |= (fbi->pix_fmt >> 1) << 16;
0313
0314
0315
0316
0317
0318
0319 x &= ~(1 << 12);
0320 x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
0321
0322 writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
0323 }
0324
0325 static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
0326 {
0327 u32 x;
0328
0329
0330
0331
0332
0333
0334 x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
0335 x |= 0x2032ff81;
0336
0337
0338
0339
0340
0341 if (!(sync & FB_SYNC_VERT_HIGH_ACT))
0342 x |= 0x08000000;
0343
0344 writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
0345 }
0346
0347 static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
0348 {
0349 struct pxa168fb_info *fbi = info->par;
0350 struct fb_var_screeninfo *var = &info->var;
0351 int pixel_offset;
0352 unsigned long addr;
0353
0354 pixel_offset = (yoffset * var->xres_virtual) + xoffset;
0355
0356 addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
0357 writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
0358 }
0359
0360 static void set_dumb_panel_control(struct fb_info *info)
0361 {
0362 struct pxa168fb_info *fbi = info->par;
0363 struct pxa168fb_mach_info *mi = dev_get_platdata(fbi->dev);
0364 u32 x;
0365
0366
0367
0368
0369 x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
0370
0371 x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
0372 x |= mi->gpio_output_data << 20;
0373 x |= mi->gpio_output_mask << 12;
0374 x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
0375 x |= mi->invert_composite_blank ? 0x00000040 : 0;
0376 x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
0377 x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
0378 x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
0379 x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
0380 x |= mi->invert_pixclock ? 0x00000002 : 0;
0381
0382 writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
0383 }
0384
0385 static void set_dumb_screen_dimensions(struct fb_info *info)
0386 {
0387 struct pxa168fb_info *fbi = info->par;
0388 struct fb_var_screeninfo *v = &info->var;
0389 int x;
0390 int y;
0391
0392 x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
0393 y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
0394
0395 writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
0396 }
0397
0398 static int pxa168fb_set_par(struct fb_info *info)
0399 {
0400 struct pxa168fb_info *fbi = info->par;
0401 struct fb_var_screeninfo *var = &info->var;
0402 struct fb_videomode mode;
0403 u32 x;
0404
0405
0406
0407
0408 if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
0409 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0410 else
0411 info->fix.visual = FB_VISUAL_TRUECOLOR;
0412 info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
0413 info->fix.ypanstep = var->yres;
0414
0415
0416
0417
0418 x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
0419 writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
0420
0421
0422
0423
0424 writel((var->yres << 16) | var->xres,
0425 fbi->reg_base + LCD_SPU_V_H_ACTIVE);
0426
0427
0428
0429
0430 fb_var_to_videomode(&mode, &info->var);
0431
0432
0433 set_clock_divider(fbi, &mode);
0434
0435
0436 set_dma_control0(fbi);
0437 set_dma_control1(fbi, info->var.sync);
0438
0439
0440
0441
0442 x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
0443 x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
0444 writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
0445 writel((var->yres << 16) | var->xres,
0446 fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
0447 writel((var->yres << 16) | var->xres,
0448 fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
0449
0450
0451
0452
0453 set_dumb_panel_control(info);
0454 set_dumb_screen_dimensions(info);
0455
0456 writel((var->left_margin << 16) | var->right_margin,
0457 fbi->reg_base + LCD_SPU_H_PORCH);
0458 writel((var->upper_margin << 16) | var->lower_margin,
0459 fbi->reg_base + LCD_SPU_V_PORCH);
0460
0461
0462
0463
0464 x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
0465 writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
0466
0467 return 0;
0468 }
0469
0470 static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
0471 {
0472 return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
0473 }
0474
0475 static u32 to_rgb(u16 red, u16 green, u16 blue)
0476 {
0477 red >>= 8;
0478 green >>= 8;
0479 blue >>= 8;
0480
0481 return (red << 16) | (green << 8) | blue;
0482 }
0483
0484 static int
0485 pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
0486 unsigned int blue, unsigned int trans, struct fb_info *info)
0487 {
0488 struct pxa168fb_info *fbi = info->par;
0489 u32 val;
0490
0491 if (info->var.grayscale)
0492 red = green = blue = (19595 * red + 38470 * green +
0493 7471 * blue) >> 16;
0494
0495 if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
0496 val = chan_to_field(red, &info->var.red);
0497 val |= chan_to_field(green, &info->var.green);
0498 val |= chan_to_field(blue , &info->var.blue);
0499 fbi->pseudo_palette[regno] = val;
0500 }
0501
0502 if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
0503 val = to_rgb(red, green, blue);
0504 writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
0505 writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
0506 }
0507
0508 return 0;
0509 }
0510
0511 static int pxa168fb_blank(int blank, struct fb_info *info)
0512 {
0513 struct pxa168fb_info *fbi = info->par;
0514
0515 fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
0516 set_dumb_panel_control(info);
0517
0518 return 0;
0519 }
0520
0521 static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
0522 struct fb_info *info)
0523 {
0524 set_graphics_start(info, var->xoffset, var->yoffset);
0525
0526 return 0;
0527 }
0528
0529 static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
0530 {
0531 struct pxa168fb_info *fbi = dev_id;
0532 u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
0533
0534 if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
0535
0536 writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
0537 fbi->reg_base + SPU_IRQ_ISR);
0538
0539 return IRQ_HANDLED;
0540 }
0541 return IRQ_NONE;
0542 }
0543
0544 static const struct fb_ops pxa168fb_ops = {
0545 .owner = THIS_MODULE,
0546 .fb_check_var = pxa168fb_check_var,
0547 .fb_set_par = pxa168fb_set_par,
0548 .fb_setcolreg = pxa168fb_setcolreg,
0549 .fb_blank = pxa168fb_blank,
0550 .fb_pan_display = pxa168fb_pan_display,
0551 .fb_fillrect = cfb_fillrect,
0552 .fb_copyarea = cfb_copyarea,
0553 .fb_imageblit = cfb_imageblit,
0554 };
0555
0556 static void pxa168fb_init_mode(struct fb_info *info,
0557 struct pxa168fb_mach_info *mi)
0558 {
0559 struct pxa168fb_info *fbi = info->par;
0560 struct fb_var_screeninfo *var = &info->var;
0561 u32 total_w, total_h, refresh;
0562 u64 div_result;
0563 const struct fb_videomode *m;
0564
0565
0566
0567
0568 refresh = DEFAULT_REFRESH;
0569
0570
0571 m = fb_find_best_mode(&info->var, &info->modelist);
0572 if (m)
0573 fb_videomode_to_var(&info->var, m);
0574
0575
0576 var->xres_virtual = var->xres;
0577 var->yres_virtual = info->fix.smem_len /
0578 (var->xres_virtual * (var->bits_per_pixel >> 3));
0579 dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
0580 var->xres, var->yres);
0581
0582
0583 total_w = var->xres + var->left_margin + var->right_margin +
0584 var->hsync_len;
0585 total_h = var->yres + var->upper_margin + var->lower_margin +
0586 var->vsync_len;
0587
0588 div_result = 1000000000000ll;
0589 do_div(div_result, total_w * total_h * refresh);
0590 var->pixclock = (u32)div_result;
0591 }
0592
0593 static int pxa168fb_probe(struct platform_device *pdev)
0594 {
0595 struct pxa168fb_mach_info *mi;
0596 struct fb_info *info = NULL;
0597 struct pxa168fb_info *fbi = NULL;
0598 struct resource *res;
0599 struct clk *clk;
0600 int irq, ret;
0601
0602 mi = dev_get_platdata(&pdev->dev);
0603 if (mi == NULL) {
0604 dev_err(&pdev->dev, "no platform data defined\n");
0605 return -EINVAL;
0606 }
0607
0608 clk = devm_clk_get(&pdev->dev, "LCDCLK");
0609 if (IS_ERR(clk))
0610 return dev_err_probe(&pdev->dev, PTR_ERR(clk),
0611 "unable to get LCDCLK");
0612
0613 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0614 if (res == NULL) {
0615 dev_err(&pdev->dev, "no IO memory defined\n");
0616 return -ENOENT;
0617 }
0618
0619 irq = platform_get_irq(pdev, 0);
0620 if (irq < 0)
0621 return -ENOENT;
0622
0623 info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
0624 if (info == NULL) {
0625 return -ENOMEM;
0626 }
0627
0628
0629 fbi = info->par;
0630 fbi->info = info;
0631 fbi->clk = clk;
0632 fbi->dev = info->dev = &pdev->dev;
0633 fbi->panel_rbswap = mi->panel_rbswap;
0634 fbi->is_blanked = 0;
0635 fbi->active = mi->active;
0636
0637
0638
0639
0640 info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
0641 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
0642 info->node = -1;
0643 strscpy(info->fix.id, mi->id, 16);
0644 info->fix.type = FB_TYPE_PACKED_PIXELS;
0645 info->fix.type_aux = 0;
0646 info->fix.xpanstep = 0;
0647 info->fix.ypanstep = 0;
0648 info->fix.ywrapstep = 0;
0649 info->fix.mmio_start = res->start;
0650 info->fix.mmio_len = resource_size(res);
0651 info->fix.accel = FB_ACCEL_NONE;
0652 info->fbops = &pxa168fb_ops;
0653 info->pseudo_palette = fbi->pseudo_palette;
0654
0655
0656
0657
0658 fbi->reg_base = devm_ioremap(&pdev->dev, res->start,
0659 resource_size(res));
0660 if (fbi->reg_base == NULL) {
0661 ret = -ENOMEM;
0662 goto failed_free_info;
0663 }
0664
0665
0666
0667
0668 info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
0669
0670 info->screen_base = dma_alloc_wc(fbi->dev, info->fix.smem_len,
0671 &fbi->fb_start_dma, GFP_KERNEL);
0672 if (info->screen_base == NULL) {
0673 ret = -ENOMEM;
0674 goto failed_free_info;
0675 }
0676
0677 info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
0678 set_graphics_start(info, 0, 0);
0679
0680
0681
0682
0683 set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
0684
0685 fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
0686
0687
0688
0689
0690 pxa168fb_init_mode(info, mi);
0691
0692
0693
0694
0695 ret = pxa168fb_check_var(&info->var, info);
0696 if (ret)
0697 goto failed_free_fbmem;
0698
0699
0700
0701
0702 clk_prepare_enable(fbi->clk);
0703
0704 pxa168fb_set_par(info);
0705
0706
0707
0708
0709 writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
0710 writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
0711 writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
0712 writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
0713 writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
0714 writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
0715 fbi->reg_base + LCD_SPU_SRAM_PARA1);
0716
0717
0718
0719
0720 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
0721 ret = -ENOMEM;
0722 goto failed_free_clk;
0723 }
0724
0725
0726
0727
0728 ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
0729 IRQF_SHARED, info->fix.id, fbi);
0730 if (ret < 0) {
0731 dev_err(&pdev->dev, "unable to request IRQ\n");
0732 ret = -ENXIO;
0733 goto failed_free_cmap;
0734 }
0735
0736
0737
0738
0739 writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
0740
0741
0742
0743
0744 ret = register_framebuffer(info);
0745 if (ret < 0) {
0746 dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
0747 ret = -ENXIO;
0748 goto failed_free_cmap;
0749 }
0750
0751 platform_set_drvdata(pdev, fbi);
0752 return 0;
0753
0754 failed_free_cmap:
0755 fb_dealloc_cmap(&info->cmap);
0756 failed_free_clk:
0757 clk_disable_unprepare(fbi->clk);
0758 failed_free_fbmem:
0759 dma_free_wc(fbi->dev, info->fix.smem_len,
0760 info->screen_base, fbi->fb_start_dma);
0761 failed_free_info:
0762 framebuffer_release(info);
0763
0764 dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
0765 return ret;
0766 }
0767
0768 static int pxa168fb_remove(struct platform_device *pdev)
0769 {
0770 struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
0771 struct fb_info *info;
0772 unsigned int data;
0773
0774 if (!fbi)
0775 return 0;
0776
0777
0778 data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
0779 data &= ~CFG_GRA_ENA_MASK;
0780 writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0);
0781
0782 info = fbi->info;
0783
0784 unregister_framebuffer(info);
0785
0786 writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
0787
0788 if (info->cmap.len)
0789 fb_dealloc_cmap(&info->cmap);
0790
0791 dma_free_wc(fbi->dev, info->fix.smem_len,
0792 info->screen_base, info->fix.smem_start);
0793
0794 clk_disable_unprepare(fbi->clk);
0795
0796 framebuffer_release(info);
0797
0798 return 0;
0799 }
0800
0801 static struct platform_driver pxa168fb_driver = {
0802 .driver = {
0803 .name = "pxa168-fb",
0804 },
0805 .probe = pxa168fb_probe,
0806 .remove = pxa168fb_remove,
0807 };
0808
0809 module_platform_driver(pxa168fb_driver);
0810
0811 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
0812 "Green Wan <gwan@marvell.com>");
0813 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
0814 MODULE_LICENSE("GPL");