Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/video/amba-clcd.c
0003  *
0004  * Copyright (C) 2001 ARM Limited, by David A Rusling
0005  * Updated to 2.5, Deep Blue Solutions Ltd.
0006  *
0007  * This file is subject to the terms and conditions of the GNU General Public
0008  * License.  See the file COPYING in the main directory of this archive
0009  * for more details.
0010  *
0011  *  ARM PrimeCell PL110 Color LCD Controller
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 /* This is limited to 16 characters when displayed by X startup */
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      * Disable CLCD clock source.
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      * Enable the CLCD clock source.
0087      */
0088     if (!fb->clk_enabled) {
0089         fb->clk_enabled = true;
0090         clk_enable(fb->clk);
0091     }
0092 
0093     /*
0094      * Bring up by first enabling..
0095      */
0096     cntl |= CNTL_LCDEN;
0097     writel(cntl, fb->regs + fb->off_cntl);
0098 
0099     msleep(20);
0100 
0101     /*
0102      * and now apply power.
0103      */
0104     cntl |= CNTL_LCDPWR;
0105     writel(cntl, fb->regs + fb->off_cntl);
0106 
0107     /*
0108      * Turn on backlight
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      * finally, enable the interface.
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         /* Old way of specifying what can be used */
0132         caps = fb->panel->cntl & CNTL_BGR ?
0133             CLCD_CAP_BGR : CLCD_CAP_RGB;
0134         /* But mask out 444 modes as they weren't supported */
0135         caps &= ~CLCD_CAP_444;
0136     }
0137 
0138     /* Only TFT panels can do RGB888/BGR888 */
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         /* If we can't do 5551, reject */
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         /* If we can't do 444, 5551 or 565, reject */
0170         if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
0171             ret = -EINVAL;
0172             break;
0173         }
0174 
0175         /*
0176          * Green length can be 4, 5 or 6 depending whether
0177          * we're operating in 444, 5551 or 565 mode.
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              * PL110 officially only supports RGB555,
0188              * but may be wired up to allow RGB565.
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         /* If we can't do 888, reject */
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      * >= 16bpp displays have separate colour component bitfields
0229      * encoded in the pixel data.  Calculate their position from
0230      * the bitfield length defined above.
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              * The requested format was not possible, try just
0241              * our capabilities.  One of BGR or RGB must be
0242              * supported.
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, &regs);
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  *  Set a single color register. The values supplied have a 16 bit
0332  *  magnitude.  Return != 0 for invalid regno.
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          * 3.2.11: if we're configured for big endian
0356          * byte order, the palette entries are swapped.
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  *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
0377  *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
0378  *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
0379  *  to e.g. a video mode which doesn't support it. Implements VESA suspend
0380  *  and powerdown modes on hardware that supports disabling hsync/vsync:
0381  *    blank_mode == 2: suspend vsync
0382  *    blank_mode == 3: suspend hsync
0383  *    blank_mode == 4: powerdown
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      * ARM PL111 always has IENB at 0x1c; it's only PL110
0431      * which is reversed on some platforms.
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      * Make sure that the bitfields are set appropriately.
0505      */
0506     clcdfb_set_bitfields(fb, &fb->fb.var);
0507 
0508     /*
0509      * Allocate colourmap.
0510      */
0511     ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
0512     if (ret)
0513         goto unmap;
0514 
0515     /*
0516      * Ensure interrupts are disabled.
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     /* Set up some inversion flags */
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          * To preserve backwards compatibility, the IPC (inverted
0568          * pixel clock) flag needs to be set on any display that
0569          * doesn't explicitly specify that the pixel clock is
0570          * active on the negative or positive edge.
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     /* Look up the optional backlight device */
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     /* Only directly connected DPI panels supported for now */
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     /* Bypass pixel clock divider */
0654     fb->panel->tim2 |= TIM2_BCD;
0655 
0656     /* TFT display, vert. comp. interrupt at the start of the back porch */
0657     fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
0658 
0659     fb->panel->caps = 0;
0660 
0661     /* Match the setup with known variants */
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      * If we actually physically connected the R lines to B and
0673      * vice versa
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      * Fetch the panel endpoint.
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          * max_bandwidth is in bytes per second and pixclock in
0719          * pico-seconds, so the maximum allowed bits per pixel is
0720          *   8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
0721          * Rearrange this calculation to avoid overflow and then ensure
0722          * result is a valid format.
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");