Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Xilinx TFT frame buffer driver
0003  *
0004  * Author: MontaVista Software, Inc.
0005  *         source@mvista.com
0006  *
0007  * 2002-2007 (c) MontaVista Software, Inc.
0008  * 2007 (c) Secret Lab Technologies, Ltd.
0009  * 2009 (c) Xilinx Inc.
0010  *
0011  * This file is licensed under the terms of the GNU General Public License
0012  * version 2.  This program is licensed "as is" without any warranty of any
0013  * kind, whether express or implied.
0014  */
0015 
0016 /*
0017  * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
0018  * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
0019  * was based on skeletonfb.c, Skeleton for a frame buffer device by
0020  * Geert Uytterhoeven.
0021  */
0022 
0023 #include <linux/device.h>
0024 #include <linux/module.h>
0025 #include <linux/kernel.h>
0026 #include <linux/errno.h>
0027 #include <linux/string.h>
0028 #include <linux/mm.h>
0029 #include <linux/fb.h>
0030 #include <linux/init.h>
0031 #include <linux/dma-mapping.h>
0032 #include <linux/of_device.h>
0033 #include <linux/of_platform.h>
0034 #include <linux/of_address.h>
0035 #include <linux/io.h>
0036 #include <linux/slab.h>
0037 
0038 #ifdef CONFIG_PPC_DCR
0039 #include <asm/dcr.h>
0040 #endif
0041 
0042 #define DRIVER_NAME     "xilinxfb"
0043 
0044 /*
0045  * Xilinx calls it "TFT LCD Controller" though it can also be used for
0046  * the VGA port on the Xilinx ML40x board. This is a hardware display
0047  * controller for a 640x480 resolution TFT or VGA screen.
0048  *
0049  * The interface to the framebuffer is nice and simple.  There are two
0050  * control registers.  The first tells the LCD interface where in memory
0051  * the frame buffer is (only the 11 most significant bits are used, so
0052  * don't start thinking about scrolling).  The second allows the LCD to
0053  * be turned on or off as well as rotated 180 degrees.
0054  *
0055  * In case of direct BUS access the second control register will be at
0056  * an offset of 4 as compared to the DCR access where the offset is 1
0057  * i.e. REG_CTRL. So this is taken care in the function
0058  * xilinx_fb_out32 where it left shifts the offset 2 times in case of
0059  * direct BUS access.
0060  */
0061 #define NUM_REGS    2
0062 #define REG_FB_ADDR 0
0063 #define REG_CTRL    1
0064 #define REG_CTRL_ENABLE  0x0001
0065 #define REG_CTRL_ROTATE  0x0002
0066 
0067 /*
0068  * The hardware only handles a single mode: 640x480 24 bit true
0069  * color. Each pixel gets a word (32 bits) of memory.  Within each word,
0070  * the 8 most significant bits are ignored, the next 8 bits are the red
0071  * level, the next 8 bits are the green level and the 8 least
0072  * significant bits are the blue level.  Each row of the LCD uses 1024
0073  * words, but only the first 640 pixels are displayed with the other 384
0074  * words being ignored.  There are 480 rows.
0075  */
0076 #define BYTES_PER_PIXEL 4
0077 #define BITS_PER_PIXEL  (BYTES_PER_PIXEL * 8)
0078 
0079 #define RED_SHIFT   16
0080 #define GREEN_SHIFT 8
0081 #define BLUE_SHIFT  0
0082 
0083 #define PALETTE_ENTRIES_NO  16  /* passed to fb_alloc_cmap() */
0084 
0085 /* ML300/403 reference design framebuffer driver platform data struct */
0086 struct xilinxfb_platform_data {
0087     u32 rotate_screen;      /* Flag to rotate display 180 degrees */
0088     u32 screen_height_mm;   /* Physical dimensions of screen in mm */
0089     u32 screen_width_mm;
0090     u32 xres, yres;         /* resolution of screen in pixels */
0091     u32 xvirt, yvirt;       /* resolution of memory buffer */
0092 
0093     /* Physical address of framebuffer memory; If non-zero, driver
0094      * will use provided memory address instead of allocating one from
0095      * the consistent pool.
0096      */
0097     u32 fb_phys;
0098 };
0099 
0100 /*
0101  * Default xilinxfb configuration
0102  */
0103 static const struct xilinxfb_platform_data xilinx_fb_default_pdata = {
0104     .xres = 640,
0105     .yres = 480,
0106     .xvirt = 1024,
0107     .yvirt = 480,
0108 };
0109 
0110 /*
0111  * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
0112  */
0113 static const struct fb_fix_screeninfo xilinx_fb_fix = {
0114     .id =       "Xilinx",
0115     .type =     FB_TYPE_PACKED_PIXELS,
0116     .visual =   FB_VISUAL_TRUECOLOR,
0117     .accel =    FB_ACCEL_NONE
0118 };
0119 
0120 static const struct fb_var_screeninfo xilinx_fb_var = {
0121     .bits_per_pixel =   BITS_PER_PIXEL,
0122 
0123     .red =      { RED_SHIFT, 8, 0 },
0124     .green =    { GREEN_SHIFT, 8, 0 },
0125     .blue =     { BLUE_SHIFT, 8, 0 },
0126     .transp =   { 0, 0, 0 },
0127 
0128     .activate = FB_ACTIVATE_NOW
0129 };
0130 
0131 #define BUS_ACCESS_FLAG     0x1 /* 1 = BUS, 0 = DCR */
0132 #define LITTLE_ENDIAN_ACCESS    0x2 /* LITTLE ENDIAN IO functions */
0133 
0134 struct xilinxfb_drvdata {
0135     struct fb_info  info;       /* FB driver info record */
0136 
0137     phys_addr_t regs_phys;  /* phys. address of the control
0138                      * registers
0139                      */
0140     void __iomem    *regs;      /* virt. address of the control
0141                      * registers
0142                      */
0143 #ifdef CONFIG_PPC_DCR
0144     dcr_host_t      dcr_host;
0145     unsigned int    dcr_len;
0146 #endif
0147     void        *fb_virt;   /* virt. address of the frame buffer */
0148     dma_addr_t  fb_phys;    /* phys. address of the frame buffer */
0149     int     fb_alloced; /* Flag, was the fb memory alloced? */
0150 
0151     u8      flags;      /* features of the driver */
0152 
0153     u32     reg_ctrl_default;
0154 
0155     u32     pseudo_palette[PALETTE_ENTRIES_NO];
0156                     /* Fake palette of 16 colors */
0157 };
0158 
0159 #define to_xilinxfb_drvdata(_info) \
0160     container_of(_info, struct xilinxfb_drvdata, info)
0161 
0162 /*
0163  * The XPS TFT Controller can be accessed through BUS or DCR interface.
0164  * To perform the read/write on the registers we need to check on
0165  * which bus its connected and call the appropriate write API.
0166  */
0167 static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,
0168                 u32 val)
0169 {
0170     if (drvdata->flags & BUS_ACCESS_FLAG) {
0171         if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
0172             iowrite32(val, drvdata->regs + (offset << 2));
0173         else
0174             iowrite32be(val, drvdata->regs + (offset << 2));
0175     }
0176 #ifdef CONFIG_PPC_DCR
0177     else
0178         dcr_write(drvdata->dcr_host, offset, val);
0179 #endif
0180 }
0181 
0182 static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)
0183 {
0184     if (drvdata->flags & BUS_ACCESS_FLAG) {
0185         if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
0186             return ioread32(drvdata->regs + (offset << 2));
0187         else
0188             return ioread32be(drvdata->regs + (offset << 2));
0189     }
0190 #ifdef CONFIG_PPC_DCR
0191     else
0192         return dcr_read(drvdata->dcr_host, offset);
0193 #endif
0194     return 0;
0195 }
0196 
0197 static int
0198 xilinx_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
0199             unsigned int blue, unsigned int transp, struct fb_info *fbi)
0200 {
0201     u32 *palette = fbi->pseudo_palette;
0202 
0203     if (regno >= PALETTE_ENTRIES_NO)
0204         return -EINVAL;
0205 
0206     if (fbi->var.grayscale) {
0207         /* Convert color to grayscale.
0208          * grayscale = 0.30*R + 0.59*G + 0.11*B
0209          */
0210         blue = (red * 77 + green * 151 + blue * 28 + 127) >> 8;
0211         green = blue;
0212         red = green;
0213     }
0214 
0215     /* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
0216 
0217     /* We only handle 8 bits of each color. */
0218     red >>= 8;
0219     green >>= 8;
0220     blue >>= 8;
0221     palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
0222              (blue << BLUE_SHIFT);
0223 
0224     return 0;
0225 }
0226 
0227 static int
0228 xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
0229 {
0230     struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
0231 
0232     switch (blank_mode) {
0233     case FB_BLANK_UNBLANK:
0234         /* turn on panel */
0235         xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
0236         break;
0237 
0238     case FB_BLANK_NORMAL:
0239     case FB_BLANK_VSYNC_SUSPEND:
0240     case FB_BLANK_HSYNC_SUSPEND:
0241     case FB_BLANK_POWERDOWN:
0242         /* turn off panel */
0243         xilinx_fb_out32(drvdata, REG_CTRL, 0);
0244         break;
0245 
0246     default:
0247         break;
0248     }
0249     return 0; /* success */
0250 }
0251 
0252 static const struct fb_ops xilinxfb_ops = {
0253     .owner          = THIS_MODULE,
0254     .fb_setcolreg       = xilinx_fb_setcolreg,
0255     .fb_blank       = xilinx_fb_blank,
0256     .fb_fillrect        = cfb_fillrect,
0257     .fb_copyarea        = cfb_copyarea,
0258     .fb_imageblit       = cfb_imageblit,
0259 };
0260 
0261 /* ---------------------------------------------------------------------
0262  * Bus independent setup/teardown
0263  */
0264 
0265 static int xilinxfb_assign(struct platform_device *pdev,
0266                struct xilinxfb_drvdata *drvdata,
0267                struct xilinxfb_platform_data *pdata)
0268 {
0269     int rc;
0270     struct device *dev = &pdev->dev;
0271     int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
0272 
0273     if (drvdata->flags & BUS_ACCESS_FLAG) {
0274         struct resource *res;
0275 
0276         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0277         drvdata->regs = devm_ioremap_resource(&pdev->dev, res);
0278         if (IS_ERR(drvdata->regs))
0279             return PTR_ERR(drvdata->regs);
0280 
0281         drvdata->regs_phys = res->start;
0282     }
0283 
0284     /* Allocate the framebuffer memory */
0285     if (pdata->fb_phys) {
0286         drvdata->fb_phys = pdata->fb_phys;
0287         drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
0288     } else {
0289         drvdata->fb_alloced = 1;
0290         drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
0291                               &drvdata->fb_phys,
0292                               GFP_KERNEL);
0293     }
0294 
0295     if (!drvdata->fb_virt) {
0296         dev_err(dev, "Could not allocate frame buffer memory\n");
0297         return -ENOMEM;
0298     }
0299 
0300     /* Clear (turn to black) the framebuffer */
0301     memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
0302 
0303     /* Tell the hardware where the frame buffer is */
0304     xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
0305     rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
0306     /* Endianness detection */
0307     if (rc != drvdata->fb_phys) {
0308         drvdata->flags |= LITTLE_ENDIAN_ACCESS;
0309         xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
0310     }
0311 
0312     /* Turn on the display */
0313     drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
0314     if (pdata->rotate_screen)
0315         drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
0316     xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
0317 
0318     /* Fill struct fb_info */
0319     drvdata->info.device = dev;
0320     drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
0321     drvdata->info.fbops = &xilinxfb_ops;
0322     drvdata->info.fix = xilinx_fb_fix;
0323     drvdata->info.fix.smem_start = drvdata->fb_phys;
0324     drvdata->info.fix.smem_len = fbsize;
0325     drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
0326 
0327     drvdata->info.pseudo_palette = drvdata->pseudo_palette;
0328     drvdata->info.flags = FBINFO_DEFAULT;
0329     drvdata->info.var = xilinx_fb_var;
0330     drvdata->info.var.height = pdata->screen_height_mm;
0331     drvdata->info.var.width = pdata->screen_width_mm;
0332     drvdata->info.var.xres = pdata->xres;
0333     drvdata->info.var.yres = pdata->yres;
0334     drvdata->info.var.xres_virtual = pdata->xvirt;
0335     drvdata->info.var.yres_virtual = pdata->yvirt;
0336 
0337     /* Allocate a colour map */
0338     rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
0339     if (rc) {
0340         dev_err(dev, "Fail to allocate colormap (%d entries)\n",
0341             PALETTE_ENTRIES_NO);
0342         goto err_cmap;
0343     }
0344 
0345     /* Register new frame buffer */
0346     rc = register_framebuffer(&drvdata->info);
0347     if (rc) {
0348         dev_err(dev, "Could not register frame buffer\n");
0349         goto err_regfb;
0350     }
0351 
0352     if (drvdata->flags & BUS_ACCESS_FLAG) {
0353         /* Put a banner in the log (for DEBUG) */
0354         dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
0355             &drvdata->regs_phys, drvdata->regs);
0356     }
0357     /* Put a banner in the log (for DEBUG) */
0358     dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
0359         (unsigned long long)drvdata->fb_phys, drvdata->fb_virt, fbsize);
0360 
0361     return 0;   /* success */
0362 
0363 err_regfb:
0364     fb_dealloc_cmap(&drvdata->info.cmap);
0365 
0366 err_cmap:
0367     if (drvdata->fb_alloced)
0368         dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
0369                   drvdata->fb_phys);
0370     else
0371         iounmap(drvdata->fb_virt);
0372 
0373     /* Turn off the display */
0374     xilinx_fb_out32(drvdata, REG_CTRL, 0);
0375 
0376     return rc;
0377 }
0378 
0379 static int xilinxfb_release(struct device *dev)
0380 {
0381     struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
0382 
0383 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
0384     xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
0385 #endif
0386 
0387     unregister_framebuffer(&drvdata->info);
0388 
0389     fb_dealloc_cmap(&drvdata->info.cmap);
0390 
0391     if (drvdata->fb_alloced)
0392         dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
0393                   drvdata->fb_virt, drvdata->fb_phys);
0394     else
0395         iounmap(drvdata->fb_virt);
0396 
0397     /* Turn off the display */
0398     xilinx_fb_out32(drvdata, REG_CTRL, 0);
0399 
0400 #ifdef CONFIG_PPC_DCR
0401     /* Release the resources, as allocated based on interface */
0402     if (!(drvdata->flags & BUS_ACCESS_FLAG))
0403         dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
0404 #endif
0405 
0406     return 0;
0407 }
0408 
0409 /* ---------------------------------------------------------------------
0410  * OF bus binding
0411  */
0412 
0413 static int xilinxfb_of_probe(struct platform_device *pdev)
0414 {
0415     const u32 *prop;
0416     u32 tft_access = 0;
0417     struct xilinxfb_platform_data pdata;
0418     int size;
0419     struct xilinxfb_drvdata *drvdata;
0420 
0421     /* Copy with the default pdata (not a ptr reference!) */
0422     pdata = xilinx_fb_default_pdata;
0423 
0424     /* Allocate the driver data region */
0425     drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
0426     if (!drvdata)
0427         return -ENOMEM;
0428 
0429     /*
0430      * To check whether the core is connected directly to DCR or BUS
0431      * interface and initialize the tft_access accordingly.
0432      */
0433     of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
0434                  &tft_access);
0435 
0436     /*
0437      * Fill the resource structure if its direct BUS interface
0438      * otherwise fill the dcr_host structure.
0439      */
0440     if (tft_access)
0441         drvdata->flags |= BUS_ACCESS_FLAG;
0442 #ifdef CONFIG_PPC_DCR
0443     else {
0444         int start;
0445 
0446         start = dcr_resource_start(pdev->dev.of_node, 0);
0447         drvdata->dcr_len = dcr_resource_len(pdev->dev.of_node, 0);
0448         drvdata->dcr_host = dcr_map(pdev->dev.of_node, start, drvdata->dcr_len);
0449         if (!DCR_MAP_OK(drvdata->dcr_host)) {
0450             dev_err(&pdev->dev, "invalid DCR address\n");
0451             return -ENODEV;
0452         }
0453     }
0454 #endif
0455 
0456     prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
0457     if ((prop) && (size >= sizeof(u32) * 2)) {
0458         pdata.screen_width_mm = prop[0];
0459         pdata.screen_height_mm = prop[1];
0460     }
0461 
0462     prop = of_get_property(pdev->dev.of_node, "resolution", &size);
0463     if ((prop) && (size >= sizeof(u32) * 2)) {
0464         pdata.xres = prop[0];
0465         pdata.yres = prop[1];
0466     }
0467 
0468     prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
0469     if ((prop) && (size >= sizeof(u32) * 2)) {
0470         pdata.xvirt = prop[0];
0471         pdata.yvirt = prop[1];
0472     }
0473 
0474     if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
0475         pdata.rotate_screen = 1;
0476 
0477     platform_set_drvdata(pdev, drvdata);
0478     return xilinxfb_assign(pdev, drvdata, &pdata);
0479 }
0480 
0481 static int xilinxfb_of_remove(struct platform_device *op)
0482 {
0483     return xilinxfb_release(&op->dev);
0484 }
0485 
0486 /* Match table for of_platform binding */
0487 static const struct of_device_id xilinxfb_of_match[] = {
0488     { .compatible = "xlnx,xps-tft-1.00.a", },
0489     { .compatible = "xlnx,xps-tft-2.00.a", },
0490     { .compatible = "xlnx,xps-tft-2.01.a", },
0491     { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
0492     { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
0493     {},
0494 };
0495 MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
0496 
0497 static struct platform_driver xilinxfb_of_driver = {
0498     .probe = xilinxfb_of_probe,
0499     .remove = xilinxfb_of_remove,
0500     .driver = {
0501         .name = DRIVER_NAME,
0502         .of_match_table = xilinxfb_of_match,
0503     },
0504 };
0505 
0506 module_platform_driver(xilinxfb_of_driver);
0507 
0508 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
0509 MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
0510 MODULE_LICENSE("GPL");