0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/amba/bus.h>
0014 #include <linux/amba/clcd.h>
0015 #include <linux/backlight.h>
0016 #include <linux/clk.h>
0017 #include <linux/delay.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/fb.h>
0020 #include <linux/init.h>
0021 #include <linux/ioport.h>
0022 #include <linux/list.h>
0023 #include <linux/mm.h>
0024 #include <linux/module.h>
0025 #include <linux/of_address.h>
0026 #include <linux/of_graph.h>
0027 #include <linux/slab.h>
0028 #include <linux/string.h>
0029 #include <video/display_timing.h>
0030 #include <video/of_display_timing.h>
0031 #include <video/videomode.h>
0032
0033 #define to_clcd(info) container_of(info, struct clcd_fb, fb)
0034
0035
0036 static const char *clcd_name = "CLCD FB";
0037
0038 static inline void clcdfb_set_start(struct clcd_fb *fb)
0039 {
0040 unsigned long ustart = fb->fb.fix.smem_start;
0041 unsigned long lstart;
0042
0043 ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
0044 lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
0045
0046 writel(ustart, fb->regs + CLCD_UBAS);
0047 writel(lstart, fb->regs + CLCD_LBAS);
0048 }
0049
0050 static void clcdfb_disable(struct clcd_fb *fb)
0051 {
0052 u32 val;
0053
0054 if (fb->board->disable)
0055 fb->board->disable(fb);
0056
0057 if (fb->panel->backlight) {
0058 fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
0059 backlight_update_status(fb->panel->backlight);
0060 }
0061
0062 val = readl(fb->regs + fb->off_cntl);
0063 if (val & CNTL_LCDPWR) {
0064 val &= ~CNTL_LCDPWR;
0065 writel(val, fb->regs + fb->off_cntl);
0066
0067 msleep(20);
0068 }
0069 if (val & CNTL_LCDEN) {
0070 val &= ~CNTL_LCDEN;
0071 writel(val, fb->regs + fb->off_cntl);
0072 }
0073
0074
0075
0076
0077 if (fb->clk_enabled) {
0078 fb->clk_enabled = false;
0079 clk_disable(fb->clk);
0080 }
0081 }
0082
0083 static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
0084 {
0085
0086
0087
0088 if (!fb->clk_enabled) {
0089 fb->clk_enabled = true;
0090 clk_enable(fb->clk);
0091 }
0092
0093
0094
0095
0096 cntl |= CNTL_LCDEN;
0097 writel(cntl, fb->regs + fb->off_cntl);
0098
0099 msleep(20);
0100
0101
0102
0103
0104 cntl |= CNTL_LCDPWR;
0105 writel(cntl, fb->regs + fb->off_cntl);
0106
0107
0108
0109
0110 if (fb->panel->backlight) {
0111 fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
0112 backlight_update_status(fb->panel->backlight);
0113 }
0114
0115
0116
0117
0118 if (fb->board->enable)
0119 fb->board->enable(fb);
0120 }
0121
0122 static int
0123 clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
0124 {
0125 u32 caps;
0126 int ret = 0;
0127
0128 if (fb->panel->caps && fb->board->caps)
0129 caps = fb->panel->caps & fb->board->caps;
0130 else {
0131
0132 caps = fb->panel->cntl & CNTL_BGR ?
0133 CLCD_CAP_BGR : CLCD_CAP_RGB;
0134
0135 caps &= ~CLCD_CAP_444;
0136 }
0137
0138
0139 if (!(fb->panel->cntl & CNTL_LCDTFT))
0140 caps &= ~CLCD_CAP_888;
0141
0142 memset(&var->transp, 0, sizeof(var->transp));
0143
0144 var->red.msb_right = 0;
0145 var->green.msb_right = 0;
0146 var->blue.msb_right = 0;
0147
0148 switch (var->bits_per_pixel) {
0149 case 1:
0150 case 2:
0151 case 4:
0152 case 8:
0153
0154 caps &= CLCD_CAP_5551;
0155 if (!caps) {
0156 ret = -EINVAL;
0157 break;
0158 }
0159
0160 var->red.length = var->bits_per_pixel;
0161 var->red.offset = 0;
0162 var->green.length = var->bits_per_pixel;
0163 var->green.offset = 0;
0164 var->blue.length = var->bits_per_pixel;
0165 var->blue.offset = 0;
0166 break;
0167
0168 case 16:
0169
0170 if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
0171 ret = -EINVAL;
0172 break;
0173 }
0174
0175
0176
0177
0178
0179 if (var->green.length == 4 && caps & CLCD_CAP_444)
0180 caps &= CLCD_CAP_444;
0181 if (var->green.length == 5 && caps & CLCD_CAP_5551)
0182 caps &= CLCD_CAP_5551;
0183 else if (var->green.length == 6 && caps & CLCD_CAP_565)
0184 caps &= CLCD_CAP_565;
0185 else {
0186
0187
0188
0189
0190 if (caps & CLCD_CAP_565) {
0191 var->green.length = 6;
0192 caps &= CLCD_CAP_565;
0193 } else if (caps & CLCD_CAP_5551) {
0194 var->green.length = 5;
0195 caps &= CLCD_CAP_5551;
0196 } else {
0197 var->green.length = 4;
0198 caps &= CLCD_CAP_444;
0199 }
0200 }
0201
0202 if (var->green.length >= 5) {
0203 var->red.length = 5;
0204 var->blue.length = 5;
0205 } else {
0206 var->red.length = 4;
0207 var->blue.length = 4;
0208 }
0209 break;
0210 case 32:
0211
0212 caps &= CLCD_CAP_888;
0213 if (!caps) {
0214 ret = -EINVAL;
0215 break;
0216 }
0217
0218 var->red.length = 8;
0219 var->green.length = 8;
0220 var->blue.length = 8;
0221 break;
0222 default:
0223 ret = -EINVAL;
0224 break;
0225 }
0226
0227
0228
0229
0230
0231
0232 if (ret == 0 && var->bits_per_pixel >= 16) {
0233 bool bgr, rgb;
0234
0235 bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
0236 rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
0237
0238 if (!bgr && !rgb)
0239
0240
0241
0242
0243
0244 bgr = caps & CLCD_CAP_BGR;
0245
0246 if (bgr) {
0247 var->blue.offset = 0;
0248 var->green.offset = var->blue.offset + var->blue.length;
0249 var->red.offset = var->green.offset + var->green.length;
0250 } else {
0251 var->red.offset = 0;
0252 var->green.offset = var->red.offset + var->red.length;
0253 var->blue.offset = var->green.offset + var->green.length;
0254 }
0255 }
0256
0257 return ret;
0258 }
0259
0260 static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0261 {
0262 struct clcd_fb *fb = to_clcd(info);
0263 int ret = -EINVAL;
0264
0265 if (fb->board->check)
0266 ret = fb->board->check(fb, var);
0267
0268 if (ret == 0 &&
0269 var->xres_virtual * var->bits_per_pixel / 8 *
0270 var->yres_virtual > fb->fb.fix.smem_len)
0271 ret = -EINVAL;
0272
0273 if (ret == 0)
0274 ret = clcdfb_set_bitfields(fb, var);
0275
0276 return ret;
0277 }
0278
0279 static int clcdfb_set_par(struct fb_info *info)
0280 {
0281 struct clcd_fb *fb = to_clcd(info);
0282 struct clcd_regs regs;
0283
0284 fb->fb.fix.line_length = fb->fb.var.xres_virtual *
0285 fb->fb.var.bits_per_pixel / 8;
0286
0287 if (fb->fb.var.bits_per_pixel <= 8)
0288 fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
0289 else
0290 fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
0291
0292 fb->board->decode(fb, ®s);
0293
0294 clcdfb_disable(fb);
0295
0296 writel(regs.tim0, fb->regs + CLCD_TIM0);
0297 writel(regs.tim1, fb->regs + CLCD_TIM1);
0298 writel(regs.tim2, fb->regs + CLCD_TIM2);
0299 writel(regs.tim3, fb->regs + CLCD_TIM3);
0300
0301 clcdfb_set_start(fb);
0302
0303 clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
0304
0305 fb->clcd_cntl = regs.cntl;
0306
0307 clcdfb_enable(fb, regs.cntl);
0308
0309 #ifdef DEBUG
0310 printk(KERN_INFO
0311 "CLCD: Registers set to\n"
0312 " %08x %08x %08x %08x\n"
0313 " %08x %08x %08x %08x\n",
0314 readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
0315 readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
0316 readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
0317 readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
0318 #endif
0319
0320 return 0;
0321 }
0322
0323 static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
0324 {
0325 unsigned int mask = (1 << bf->length) - 1;
0326
0327 return (val >> (16 - bf->length) & mask) << bf->offset;
0328 }
0329
0330
0331
0332
0333
0334 static int
0335 clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
0336 unsigned int blue, unsigned int transp, struct fb_info *info)
0337 {
0338 struct clcd_fb *fb = to_clcd(info);
0339
0340 if (regno < 16)
0341 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
0342 convert_bitfield(blue, &fb->fb.var.blue) |
0343 convert_bitfield(green, &fb->fb.var.green) |
0344 convert_bitfield(red, &fb->fb.var.red);
0345
0346 if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
0347 int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
0348 u32 val, mask, newval;
0349
0350 newval = (red >> 11) & 0x001f;
0351 newval |= (green >> 6) & 0x03e0;
0352 newval |= (blue >> 1) & 0x7c00;
0353
0354
0355
0356
0357
0358 if (fb->clcd_cntl & CNTL_BEBO)
0359 regno ^= 1;
0360
0361 if (regno & 1) {
0362 newval <<= 16;
0363 mask = 0x0000ffff;
0364 } else {
0365 mask = 0xffff0000;
0366 }
0367
0368 val = readl(fb->regs + hw_reg) & mask;
0369 writel(val | newval, fb->regs + hw_reg);
0370 }
0371
0372 return regno > 255;
0373 }
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385 static int clcdfb_blank(int blank_mode, struct fb_info *info)
0386 {
0387 struct clcd_fb *fb = to_clcd(info);
0388
0389 if (blank_mode != 0) {
0390 clcdfb_disable(fb);
0391 } else {
0392 clcdfb_enable(fb, fb->clcd_cntl);
0393 }
0394 return 0;
0395 }
0396
0397 static int clcdfb_mmap(struct fb_info *info,
0398 struct vm_area_struct *vma)
0399 {
0400 struct clcd_fb *fb = to_clcd(info);
0401 unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
0402 int ret = -EINVAL;
0403
0404 len = info->fix.smem_len;
0405
0406 if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
0407 fb->board->mmap)
0408 ret = fb->board->mmap(fb, vma);
0409
0410 return ret;
0411 }
0412
0413 static const struct fb_ops clcdfb_ops = {
0414 .owner = THIS_MODULE,
0415 .fb_check_var = clcdfb_check_var,
0416 .fb_set_par = clcdfb_set_par,
0417 .fb_setcolreg = clcdfb_setcolreg,
0418 .fb_blank = clcdfb_blank,
0419 .fb_fillrect = cfb_fillrect,
0420 .fb_copyarea = cfb_copyarea,
0421 .fb_imageblit = cfb_imageblit,
0422 .fb_mmap = clcdfb_mmap,
0423 };
0424
0425 static int clcdfb_register(struct clcd_fb *fb)
0426 {
0427 int ret;
0428
0429
0430
0431
0432
0433 if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
0434 fb->off_ienb = CLCD_PL111_IENB;
0435 fb->off_cntl = CLCD_PL111_CNTL;
0436 } else {
0437 fb->off_ienb = CLCD_PL110_IENB;
0438 fb->off_cntl = CLCD_PL110_CNTL;
0439 }
0440
0441 fb->clk = clk_get(&fb->dev->dev, NULL);
0442 if (IS_ERR(fb->clk)) {
0443 ret = PTR_ERR(fb->clk);
0444 goto out;
0445 }
0446
0447 ret = clk_prepare(fb->clk);
0448 if (ret)
0449 goto free_clk;
0450
0451 fb->fb.device = &fb->dev->dev;
0452
0453 fb->fb.fix.mmio_start = fb->dev->res.start;
0454 fb->fb.fix.mmio_len = resource_size(&fb->dev->res);
0455
0456 fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
0457 if (!fb->regs) {
0458 printk(KERN_ERR "CLCD: unable to remap registers\n");
0459 ret = -ENOMEM;
0460 goto clk_unprep;
0461 }
0462
0463 fb->fb.fbops = &clcdfb_ops;
0464 fb->fb.flags = FBINFO_FLAG_DEFAULT;
0465 fb->fb.pseudo_palette = fb->cmap;
0466
0467 strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
0468 fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
0469 fb->fb.fix.type_aux = 0;
0470 fb->fb.fix.xpanstep = 0;
0471 fb->fb.fix.ypanstep = 0;
0472 fb->fb.fix.ywrapstep = 0;
0473 fb->fb.fix.accel = FB_ACCEL_NONE;
0474
0475 fb->fb.var.xres = fb->panel->mode.xres;
0476 fb->fb.var.yres = fb->panel->mode.yres;
0477 fb->fb.var.xres_virtual = fb->panel->mode.xres;
0478 fb->fb.var.yres_virtual = fb->panel->mode.yres;
0479 fb->fb.var.bits_per_pixel = fb->panel->bpp;
0480 fb->fb.var.grayscale = fb->panel->grayscale;
0481 fb->fb.var.pixclock = fb->panel->mode.pixclock;
0482 fb->fb.var.left_margin = fb->panel->mode.left_margin;
0483 fb->fb.var.right_margin = fb->panel->mode.right_margin;
0484 fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
0485 fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
0486 fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
0487 fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
0488 fb->fb.var.sync = fb->panel->mode.sync;
0489 fb->fb.var.vmode = fb->panel->mode.vmode;
0490 fb->fb.var.activate = FB_ACTIVATE_NOW;
0491 fb->fb.var.nonstd = 0;
0492 fb->fb.var.height = fb->panel->height;
0493 fb->fb.var.width = fb->panel->width;
0494 fb->fb.var.accel_flags = 0;
0495
0496 fb->fb.monspecs.hfmin = 0;
0497 fb->fb.monspecs.hfmax = 100000;
0498 fb->fb.monspecs.vfmin = 0;
0499 fb->fb.monspecs.vfmax = 400;
0500 fb->fb.monspecs.dclkmin = 1000000;
0501 fb->fb.monspecs.dclkmax = 100000000;
0502
0503
0504
0505
0506 clcdfb_set_bitfields(fb, &fb->fb.var);
0507
0508
0509
0510
0511 ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
0512 if (ret)
0513 goto unmap;
0514
0515
0516
0517
0518 writel(0, fb->regs + fb->off_ienb);
0519
0520 fb_set_var(&fb->fb, &fb->fb.var);
0521
0522 dev_info(&fb->dev->dev, "%s hardware, %s display\n",
0523 fb->board->name, fb->panel->mode.name);
0524
0525 ret = register_framebuffer(&fb->fb);
0526 if (ret == 0)
0527 goto out;
0528
0529 printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
0530
0531 fb_dealloc_cmap(&fb->fb.cmap);
0532 unmap:
0533 iounmap(fb->regs);
0534 clk_unprep:
0535 clk_unprepare(fb->clk);
0536 free_clk:
0537 clk_put(fb->clk);
0538 out:
0539 return ret;
0540 }
0541
0542 #ifdef CONFIG_OF
0543 static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
0544 struct clcd_panel *clcd_panel)
0545 {
0546 int err;
0547 struct display_timing timing;
0548 struct videomode video;
0549
0550 err = of_get_display_timing(node, "panel-timing", &timing);
0551 if (err) {
0552 pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
0553 return err;
0554 }
0555
0556 videomode_from_timing(&timing, &video);
0557
0558 err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
0559 if (err)
0560 return err;
0561
0562
0563 if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
0564 clcd_panel->tim2 |= TIM2_IPC;
0565 else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
0566
0567
0568
0569
0570
0571
0572 clcd_panel->tim2 |= TIM2_IPC;
0573
0574 if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
0575 clcd_panel->tim2 |= TIM2_IHS;
0576
0577 if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
0578 clcd_panel->tim2 |= TIM2_IVS;
0579
0580 if (timing.flags & DISPLAY_FLAGS_DE_LOW)
0581 clcd_panel->tim2 |= TIM2_IOE;
0582
0583 return 0;
0584 }
0585
0586 static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
0587 {
0588 return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
0589 mode->refresh);
0590 }
0591
0592 static int clcdfb_of_get_backlight(struct device *dev,
0593 struct clcd_panel *clcd_panel)
0594 {
0595 struct backlight_device *backlight;
0596
0597
0598 backlight = devm_of_find_backlight(dev);
0599 if (IS_ERR(backlight))
0600 return PTR_ERR(backlight);
0601
0602 clcd_panel->backlight = backlight;
0603 return 0;
0604 }
0605
0606 static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
0607 struct clcd_panel *clcd_panel)
0608 {
0609 int err;
0610 struct fb_videomode *mode;
0611 char *name;
0612 int len;
0613
0614
0615 if (of_device_is_compatible(panel, "panel-dpi"))
0616 err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
0617 else
0618 err = -ENOENT;
0619 if (err)
0620 return err;
0621 mode = &clcd_panel->mode;
0622
0623 len = clcdfb_snprintf_mode(NULL, 0, mode);
0624 name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
0625 if (!name)
0626 return -ENOMEM;
0627
0628 clcdfb_snprintf_mode(name, len + 1, mode);
0629 mode->name = name;
0630
0631 return 0;
0632 }
0633
0634 static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
0635 {
0636 static struct {
0637 unsigned int part;
0638 u32 r0, g0, b0;
0639 u32 caps;
0640 } panels[] = {
0641 { 0x110, 1, 7, 13, CLCD_CAP_5551 },
0642 { 0x110, 0, 8, 16, CLCD_CAP_888 },
0643 { 0x110, 16, 8, 0, CLCD_CAP_888 },
0644 { 0x111, 4, 14, 20, CLCD_CAP_444 },
0645 { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
0646 { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
0647 CLCD_CAP_565 },
0648 { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
0649 CLCD_CAP_565 | CLCD_CAP_888 },
0650 };
0651 int i;
0652
0653
0654 fb->panel->tim2 |= TIM2_BCD;
0655
0656
0657 fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
0658
0659 fb->panel->caps = 0;
0660
0661
0662 for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
0663 if (amba_part(fb->dev) != panels[i].part)
0664 continue;
0665 if (g0 != panels[i].g0)
0666 continue;
0667 if (r0 == panels[i].r0 && b0 == panels[i].b0)
0668 fb->panel->caps = panels[i].caps;
0669 }
0670
0671
0672
0673
0674
0675 if (r0 != 0 && b0 == 0)
0676 fb->panel->bgr_connection = true;
0677
0678 return fb->panel->caps ? 0 : -EINVAL;
0679 }
0680
0681 static int clcdfb_of_init_display(struct clcd_fb *fb)
0682 {
0683 struct device_node *endpoint, *panel;
0684 int err;
0685 unsigned int bpp;
0686 u32 max_bandwidth;
0687 u32 tft_r0b0g0[3];
0688
0689 fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
0690 if (!fb->panel)
0691 return -ENOMEM;
0692
0693
0694
0695
0696 endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
0697 if (!endpoint)
0698 return -ENODEV;
0699
0700 panel = of_graph_get_remote_port_parent(endpoint);
0701 if (!panel) {
0702 err = -ENODEV;
0703 goto out_endpoint_put;
0704 }
0705
0706 err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
0707 if (err)
0708 goto out_panel_put;
0709
0710 err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
0711 if (err)
0712 goto out_panel_put;
0713
0714 err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
0715 &max_bandwidth);
0716 if (!err) {
0717
0718
0719
0720
0721
0722
0723
0724 bpp = max_bandwidth / (1000 / 8)
0725 / PICOS2KHZ(fb->panel->mode.pixclock);
0726 bpp = rounddown_pow_of_two(bpp);
0727 if (bpp > 32)
0728 bpp = 32;
0729 } else
0730 bpp = 32;
0731 fb->panel->bpp = bpp;
0732
0733 #ifdef CONFIG_CPU_BIG_ENDIAN
0734 fb->panel->cntl |= CNTL_BEBO;
0735 #endif
0736 fb->panel->width = -1;
0737 fb->panel->height = -1;
0738
0739 if (of_property_read_u32_array(endpoint,
0740 "arm,pl11x,tft-r0g0b0-pads",
0741 tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0) {
0742 err = -ENOENT;
0743 goto out_panel_put;
0744 }
0745
0746 of_node_put(panel);
0747 of_node_put(endpoint);
0748
0749 return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
0750 tft_r0b0g0[1], tft_r0b0g0[2]);
0751 out_panel_put:
0752 of_node_put(panel);
0753 out_endpoint_put:
0754 of_node_put(endpoint);
0755 return err;
0756 }
0757
0758 static int clcdfb_of_vram_setup(struct clcd_fb *fb)
0759 {
0760 int err;
0761 struct device_node *memory;
0762 u64 size;
0763
0764 err = clcdfb_of_init_display(fb);
0765 if (err)
0766 return err;
0767
0768 memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
0769 if (!memory)
0770 return -ENODEV;
0771
0772 fb->fb.screen_base = of_iomap(memory, 0);
0773 if (!fb->fb.screen_base) {
0774 of_node_put(memory);
0775 return -ENOMEM;
0776 }
0777
0778 fb->fb.fix.smem_start = of_translate_address(memory,
0779 of_get_address(memory, 0, &size, NULL));
0780 fb->fb.fix.smem_len = size;
0781 of_node_put(memory);
0782
0783 return 0;
0784 }
0785
0786 static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
0787 {
0788 unsigned long off, user_size, kernel_size;
0789
0790
0791 off = vma->vm_pgoff << PAGE_SHIFT;
0792 user_size = vma->vm_end - vma->vm_start;
0793 kernel_size = fb->fb.fix.smem_len;
0794
0795 if (off >= kernel_size || user_size > (kernel_size - off))
0796 return -ENXIO;
0797
0798 return remap_pfn_range(vma, vma->vm_start,
0799 __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
0800 user_size,
0801 pgprot_writecombine(vma->vm_page_prot));
0802 }
0803
0804 static void clcdfb_of_vram_remove(struct clcd_fb *fb)
0805 {
0806 iounmap(fb->fb.screen_base);
0807 }
0808
0809 static int clcdfb_of_dma_setup(struct clcd_fb *fb)
0810 {
0811 unsigned long framesize;
0812 dma_addr_t dma;
0813 int err;
0814
0815 err = clcdfb_of_init_display(fb);
0816 if (err)
0817 return err;
0818
0819 framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
0820 fb->panel->bpp / 8);
0821 fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
0822 &dma, GFP_KERNEL);
0823 if (!fb->fb.screen_base)
0824 return -ENOMEM;
0825
0826 fb->fb.fix.smem_start = dma;
0827 fb->fb.fix.smem_len = framesize;
0828
0829 return 0;
0830 }
0831
0832 static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
0833 {
0834 return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
0835 fb->fb.fix.smem_start, fb->fb.fix.smem_len);
0836 }
0837
0838 static void clcdfb_of_dma_remove(struct clcd_fb *fb)
0839 {
0840 dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
0841 fb->fb.screen_base, fb->fb.fix.smem_start);
0842 }
0843
0844 static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
0845 {
0846 struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
0847 GFP_KERNEL);
0848 struct device_node *node = dev->dev.of_node;
0849
0850 if (!board)
0851 return NULL;
0852
0853 board->name = of_node_full_name(node);
0854 board->caps = CLCD_CAP_ALL;
0855 board->check = clcdfb_check;
0856 board->decode = clcdfb_decode;
0857 if (of_find_property(node, "memory-region", NULL)) {
0858 board->setup = clcdfb_of_vram_setup;
0859 board->mmap = clcdfb_of_vram_mmap;
0860 board->remove = clcdfb_of_vram_remove;
0861 } else {
0862 board->setup = clcdfb_of_dma_setup;
0863 board->mmap = clcdfb_of_dma_mmap;
0864 board->remove = clcdfb_of_dma_remove;
0865 }
0866
0867 return board;
0868 }
0869 #else
0870 static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
0871 {
0872 return NULL;
0873 }
0874 #endif
0875
0876 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
0877 {
0878 struct clcd_board *board = dev_get_platdata(&dev->dev);
0879 struct clcd_fb *fb;
0880 int ret;
0881
0882 if (!board)
0883 board = clcdfb_of_get_board(dev);
0884
0885 if (!board)
0886 return -EINVAL;
0887
0888 ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
0889 if (ret)
0890 goto out;
0891
0892 ret = amba_request_regions(dev, NULL);
0893 if (ret) {
0894 printk(KERN_ERR "CLCD: unable to reserve regs region\n");
0895 goto out;
0896 }
0897
0898 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
0899 if (!fb) {
0900 ret = -ENOMEM;
0901 goto free_region;
0902 }
0903
0904 fb->dev = dev;
0905 fb->board = board;
0906
0907 dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
0908 amba_part(dev), amba_manf(dev), amba_rev(dev),
0909 (unsigned long long)dev->res.start);
0910
0911 ret = fb->board->setup(fb);
0912 if (ret)
0913 goto free_fb;
0914
0915 ret = clcdfb_register(fb);
0916 if (ret == 0) {
0917 amba_set_drvdata(dev, fb);
0918 goto out;
0919 }
0920
0921 fb->board->remove(fb);
0922 free_fb:
0923 kfree(fb);
0924 free_region:
0925 amba_release_regions(dev);
0926 out:
0927 return ret;
0928 }
0929
0930 static void clcdfb_remove(struct amba_device *dev)
0931 {
0932 struct clcd_fb *fb = amba_get_drvdata(dev);
0933
0934 clcdfb_disable(fb);
0935 unregister_framebuffer(&fb->fb);
0936 if (fb->fb.cmap.len)
0937 fb_dealloc_cmap(&fb->fb.cmap);
0938 iounmap(fb->regs);
0939 clk_unprepare(fb->clk);
0940 clk_put(fb->clk);
0941
0942 fb->board->remove(fb);
0943
0944 kfree(fb);
0945
0946 amba_release_regions(dev);
0947 }
0948
0949 static const struct amba_id clcdfb_id_table[] = {
0950 {
0951 .id = 0x00041110,
0952 .mask = 0x000ffffe,
0953 },
0954 { 0, 0 },
0955 };
0956
0957 MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
0958
0959 static struct amba_driver clcd_driver = {
0960 .drv = {
0961 .name = "clcd-pl11x",
0962 },
0963 .probe = clcdfb_probe,
0964 .remove = clcdfb_remove,
0965 .id_table = clcdfb_id_table,
0966 };
0967
0968 static int __init amba_clcdfb_init(void)
0969 {
0970 if (fb_get_options("ambafb", NULL))
0971 return -ENODEV;
0972
0973 return amba_driver_register(&clcd_driver);
0974 }
0975
0976 module_init(amba_clcdfb_init);
0977
0978 static void __exit amba_clcdfb_exit(void)
0979 {
0980 amba_driver_unregister(&clcd_driver);
0981 }
0982
0983 module_exit(amba_clcdfb_exit);
0984
0985 MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
0986 MODULE_LICENSE("GPL");