0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
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
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
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
0069
0070
0071
0072
0073
0074
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
0084
0085
0086 struct xilinxfb_platform_data {
0087 u32 rotate_screen;
0088 u32 screen_height_mm;
0089 u32 screen_width_mm;
0090 u32 xres, yres;
0091 u32 xvirt, yvirt;
0092
0093
0094
0095
0096
0097 u32 fb_phys;
0098 };
0099
0100
0101
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
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
0132 #define LITTLE_ENDIAN_ACCESS 0x2
0133
0134 struct xilinxfb_drvdata {
0135 struct fb_info info;
0136
0137 phys_addr_t regs_phys;
0138
0139
0140 void __iomem *regs;
0141
0142
0143 #ifdef CONFIG_PPC_DCR
0144 dcr_host_t dcr_host;
0145 unsigned int dcr_len;
0146 #endif
0147 void *fb_virt;
0148 dma_addr_t fb_phys;
0149 int fb_alloced;
0150
0151 u8 flags;
0152
0153 u32 reg_ctrl_default;
0154
0155 u32 pseudo_palette[PALETTE_ENTRIES_NO];
0156
0157 };
0158
0159 #define to_xilinxfb_drvdata(_info) \
0160 container_of(_info, struct xilinxfb_drvdata, info)
0161
0162
0163
0164
0165
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
0208
0209
0210 blue = (red * 77 + green * 151 + blue * 28 + 127) >> 8;
0211 green = blue;
0212 red = green;
0213 }
0214
0215
0216
0217
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
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
0243 xilinx_fb_out32(drvdata, REG_CTRL, 0);
0244 break;
0245
0246 default:
0247 break;
0248 }
0249 return 0;
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
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
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
0301 memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
0302
0303
0304 xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
0305 rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
0306
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
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
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
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
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
0354 dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
0355 &drvdata->regs_phys, drvdata->regs);
0356 }
0357
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;
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
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
0398 xilinx_fb_out32(drvdata, REG_CTRL, 0);
0399
0400 #ifdef CONFIG_PPC_DCR
0401
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
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
0422 pdata = xilinx_fb_default_pdata;
0423
0424
0425 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
0426 if (!drvdata)
0427 return -ENOMEM;
0428
0429
0430
0431
0432
0433 of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
0434 &tft_access);
0435
0436
0437
0438
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
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");