Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.1-rc8 537 lines 14 kB view raw
1/* 2 * Xilinx TFT frame buffer driver 3 * 4 * Author: MontaVista Software, Inc. 5 * source@mvista.com 6 * 7 * 2002-2007 (c) MontaVista Software, Inc. 8 * 2007 (c) Secret Lab Technologies, Ltd. 9 * 2009 (c) Xilinx Inc. 10 * 11 * This file is licensed under the terms of the GNU General Public License 12 * version 2. This program is licensed "as is" without any warranty of any 13 * kind, whether express or implied. 14 */ 15 16/* 17 * This driver was based on au1100fb.c by MontaVista rewritten for 2.6 18 * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn 19 * was based on skeletonfb.c, Skeleton for a frame buffer device by 20 * Geert Uytterhoeven. 21 */ 22 23#include <linux/device.h> 24#include <linux/module.h> 25#include <linux/kernel.h> 26#include <linux/version.h> 27#include <linux/errno.h> 28#include <linux/string.h> 29#include <linux/mm.h> 30#include <linux/fb.h> 31#include <linux/init.h> 32#include <linux/dma-mapping.h> 33#include <linux/of_device.h> 34#include <linux/of_platform.h> 35#include <linux/of_address.h> 36#include <linux/io.h> 37#include <linux/xilinxfb.h> 38#include <linux/slab.h> 39 40#ifdef CONFIG_PPC_DCR 41#include <asm/dcr.h> 42#endif 43 44#define DRIVER_NAME "xilinxfb" 45 46 47/* 48 * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for 49 * the VGA port on the Xilinx ML40x board. This is a hardware display 50 * controller for a 640x480 resolution TFT or VGA screen. 51 * 52 * The interface to the framebuffer is nice and simple. There are two 53 * control registers. The first tells the LCD interface where in memory 54 * the frame buffer is (only the 11 most significant bits are used, so 55 * don't start thinking about scrolling). The second allows the LCD to 56 * be turned on or off as well as rotated 180 degrees. 57 * 58 * In case of direct PLB access the second control register will be at 59 * an offset of 4 as compared to the DCR access where the offset is 1 60 * i.e. REG_CTRL. So this is taken care in the function 61 * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of 62 * direct PLB access. 63 */ 64#define NUM_REGS 2 65#define REG_FB_ADDR 0 66#define REG_CTRL 1 67#define REG_CTRL_ENABLE 0x0001 68#define REG_CTRL_ROTATE 0x0002 69 70/* 71 * The hardware only handles a single mode: 640x480 24 bit true 72 * color. Each pixel gets a word (32 bits) of memory. Within each word, 73 * the 8 most significant bits are ignored, the next 8 bits are the red 74 * level, the next 8 bits are the green level and the 8 least 75 * significant bits are the blue level. Each row of the LCD uses 1024 76 * words, but only the first 640 pixels are displayed with the other 384 77 * words being ignored. There are 480 rows. 78 */ 79#define BYTES_PER_PIXEL 4 80#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) 81 82#define RED_SHIFT 16 83#define GREEN_SHIFT 8 84#define BLUE_SHIFT 0 85 86#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ 87 88/* 89 * Default xilinxfb configuration 90 */ 91static struct xilinxfb_platform_data xilinx_fb_default_pdata = { 92 .xres = 640, 93 .yres = 480, 94 .xvirt = 1024, 95 .yvirt = 480, 96}; 97 98/* 99 * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures 100 */ 101static struct fb_fix_screeninfo xilinx_fb_fix = { 102 .id = "Xilinx", 103 .type = FB_TYPE_PACKED_PIXELS, 104 .visual = FB_VISUAL_TRUECOLOR, 105 .accel = FB_ACCEL_NONE 106}; 107 108static struct fb_var_screeninfo xilinx_fb_var = { 109 .bits_per_pixel = BITS_PER_PIXEL, 110 111 .red = { RED_SHIFT, 8, 0 }, 112 .green = { GREEN_SHIFT, 8, 0 }, 113 .blue = { BLUE_SHIFT, 8, 0 }, 114 .transp = { 0, 0, 0 }, 115 116 .activate = FB_ACTIVATE_NOW 117}; 118 119 120#define PLB_ACCESS_FLAG 0x1 /* 1 = PLB, 0 = DCR */ 121 122struct xilinxfb_drvdata { 123 124 struct fb_info info; /* FB driver info record */ 125 126 phys_addr_t regs_phys; /* phys. address of the control 127 registers */ 128 void __iomem *regs; /* virt. address of the control 129 registers */ 130#ifdef CONFIG_PPC_DCR 131 dcr_host_t dcr_host; 132 unsigned int dcr_len; 133#endif 134 void *fb_virt; /* virt. address of the frame buffer */ 135 dma_addr_t fb_phys; /* phys. address of the frame buffer */ 136 int fb_alloced; /* Flag, was the fb memory alloced? */ 137 138 u8 flags; /* features of the driver */ 139 140 u32 reg_ctrl_default; 141 142 u32 pseudo_palette[PALETTE_ENTRIES_NO]; 143 /* Fake palette of 16 colors */ 144}; 145 146#define to_xilinxfb_drvdata(_info) \ 147 container_of(_info, struct xilinxfb_drvdata, info) 148 149/* 150 * The XPS TFT Controller can be accessed through PLB or DCR interface. 151 * To perform the read/write on the registers we need to check on 152 * which bus its connected and call the appropriate write API. 153 */ 154static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset, 155 u32 val) 156{ 157 if (drvdata->flags & PLB_ACCESS_FLAG) 158 out_be32(drvdata->regs + (offset << 2), val); 159#ifdef CONFIG_PPC_DCR 160 else 161 dcr_write(drvdata->dcr_host, offset, val); 162#endif 163} 164 165static int 166xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, 167 unsigned transp, struct fb_info *fbi) 168{ 169 u32 *palette = fbi->pseudo_palette; 170 171 if (regno >= PALETTE_ENTRIES_NO) 172 return -EINVAL; 173 174 if (fbi->var.grayscale) { 175 /* Convert color to grayscale. 176 * grayscale = 0.30*R + 0.59*G + 0.11*B */ 177 red = green = blue = 178 (red * 77 + green * 151 + blue * 28 + 127) >> 8; 179 } 180 181 /* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */ 182 183 /* We only handle 8 bits of each color. */ 184 red >>= 8; 185 green >>= 8; 186 blue >>= 8; 187 palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) | 188 (blue << BLUE_SHIFT); 189 190 return 0; 191} 192 193static int 194xilinx_fb_blank(int blank_mode, struct fb_info *fbi) 195{ 196 struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi); 197 198 switch (blank_mode) { 199 case FB_BLANK_UNBLANK: 200 /* turn on panel */ 201 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); 202 break; 203 204 case FB_BLANK_NORMAL: 205 case FB_BLANK_VSYNC_SUSPEND: 206 case FB_BLANK_HSYNC_SUSPEND: 207 case FB_BLANK_POWERDOWN: 208 /* turn off panel */ 209 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 210 default: 211 break; 212 213 } 214 return 0; /* success */ 215} 216 217static struct fb_ops xilinxfb_ops = 218{ 219 .owner = THIS_MODULE, 220 .fb_setcolreg = xilinx_fb_setcolreg, 221 .fb_blank = xilinx_fb_blank, 222 .fb_fillrect = cfb_fillrect, 223 .fb_copyarea = cfb_copyarea, 224 .fb_imageblit = cfb_imageblit, 225}; 226 227/* --------------------------------------------------------------------- 228 * Bus independent setup/teardown 229 */ 230 231static int xilinxfb_assign(struct device *dev, 232 struct xilinxfb_drvdata *drvdata, 233 unsigned long physaddr, 234 struct xilinxfb_platform_data *pdata) 235{ 236 int rc; 237 int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; 238 239 if (drvdata->flags & PLB_ACCESS_FLAG) { 240 /* 241 * Map the control registers in if the controller 242 * is on direct PLB interface. 243 */ 244 if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { 245 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", 246 physaddr); 247 rc = -ENODEV; 248 goto err_region; 249 } 250 251 drvdata->regs_phys = physaddr; 252 drvdata->regs = ioremap(physaddr, 8); 253 if (!drvdata->regs) { 254 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", 255 physaddr); 256 rc = -ENODEV; 257 goto err_map; 258 } 259 } 260 261 /* Allocate the framebuffer memory */ 262 if (pdata->fb_phys) { 263 drvdata->fb_phys = pdata->fb_phys; 264 drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize); 265 } else { 266 drvdata->fb_alloced = 1; 267 drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), 268 &drvdata->fb_phys, GFP_KERNEL); 269 } 270 271 if (!drvdata->fb_virt) { 272 dev_err(dev, "Could not allocate frame buffer memory\n"); 273 rc = -ENOMEM; 274 if (drvdata->flags & PLB_ACCESS_FLAG) 275 goto err_fbmem; 276 else 277 goto err_region; 278 } 279 280 /* Clear (turn to black) the framebuffer */ 281 memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); 282 283 /* Tell the hardware where the frame buffer is */ 284 xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); 285 286 /* Turn on the display */ 287 drvdata->reg_ctrl_default = REG_CTRL_ENABLE; 288 if (pdata->rotate_screen) 289 drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; 290 xilinx_fb_out_be32(drvdata, REG_CTRL, 291 drvdata->reg_ctrl_default); 292 293 /* Fill struct fb_info */ 294 drvdata->info.device = dev; 295 drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; 296 drvdata->info.fbops = &xilinxfb_ops; 297 drvdata->info.fix = xilinx_fb_fix; 298 drvdata->info.fix.smem_start = drvdata->fb_phys; 299 drvdata->info.fix.smem_len = fbsize; 300 drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL; 301 302 drvdata->info.pseudo_palette = drvdata->pseudo_palette; 303 drvdata->info.flags = FBINFO_DEFAULT; 304 drvdata->info.var = xilinx_fb_var; 305 drvdata->info.var.height = pdata->screen_height_mm; 306 drvdata->info.var.width = pdata->screen_width_mm; 307 drvdata->info.var.xres = pdata->xres; 308 drvdata->info.var.yres = pdata->yres; 309 drvdata->info.var.xres_virtual = pdata->xvirt; 310 drvdata->info.var.yres_virtual = pdata->yvirt; 311 312 /* Allocate a colour map */ 313 rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); 314 if (rc) { 315 dev_err(dev, "Fail to allocate colormap (%d entries)\n", 316 PALETTE_ENTRIES_NO); 317 goto err_cmap; 318 } 319 320 /* Register new frame buffer */ 321 rc = register_framebuffer(&drvdata->info); 322 if (rc) { 323 dev_err(dev, "Could not register frame buffer\n"); 324 goto err_regfb; 325 } 326 327 if (drvdata->flags & PLB_ACCESS_FLAG) { 328 /* Put a banner in the log (for DEBUG) */ 329 dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, 330 drvdata->regs); 331 } 332 /* Put a banner in the log (for DEBUG) */ 333 dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n", 334 (unsigned long long)drvdata->fb_phys, drvdata->fb_virt, fbsize); 335 336 return 0; /* success */ 337 338err_regfb: 339 fb_dealloc_cmap(&drvdata->info.cmap); 340 341err_cmap: 342 if (drvdata->fb_alloced) 343 dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, 344 drvdata->fb_phys); 345 else 346 iounmap(drvdata->fb_virt); 347 348 /* Turn off the display */ 349 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 350 351err_fbmem: 352 if (drvdata->flags & PLB_ACCESS_FLAG) 353 iounmap(drvdata->regs); 354 355err_map: 356 if (drvdata->flags & PLB_ACCESS_FLAG) 357 release_mem_region(physaddr, 8); 358 359err_region: 360 kfree(drvdata); 361 dev_set_drvdata(dev, NULL); 362 363 return rc; 364} 365 366static int xilinxfb_release(struct device *dev) 367{ 368 struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); 369 370#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) 371 xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); 372#endif 373 374 unregister_framebuffer(&drvdata->info); 375 376 fb_dealloc_cmap(&drvdata->info.cmap); 377 378 if (drvdata->fb_alloced) 379 dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), 380 drvdata->fb_virt, drvdata->fb_phys); 381 else 382 iounmap(drvdata->fb_virt); 383 384 /* Turn off the display */ 385 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 386 387 /* Release the resources, as allocated based on interface */ 388 if (drvdata->flags & PLB_ACCESS_FLAG) { 389 iounmap(drvdata->regs); 390 release_mem_region(drvdata->regs_phys, 8); 391 } 392#ifdef CONFIG_PPC_DCR 393 else 394 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len); 395#endif 396 397 kfree(drvdata); 398 dev_set_drvdata(dev, NULL); 399 400 return 0; 401} 402 403/* --------------------------------------------------------------------- 404 * OF bus binding 405 */ 406 407static int __devinit xilinxfb_of_probe(struct platform_device *op) 408{ 409 const u32 *prop; 410 u32 *p; 411 u32 tft_access; 412 struct xilinxfb_platform_data pdata; 413 struct resource res; 414 int size, rc; 415 struct xilinxfb_drvdata *drvdata; 416 417 /* Copy with the default pdata (not a ptr reference!) */ 418 pdata = xilinx_fb_default_pdata; 419 420 /* Allocate the driver data region */ 421 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 422 if (!drvdata) { 423 dev_err(&op->dev, "Couldn't allocate device private record\n"); 424 return -ENOMEM; 425 } 426 427 /* 428 * To check whether the core is connected directly to DCR or PLB 429 * interface and initialize the tft_access accordingly. 430 */ 431 p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL); 432 tft_access = p ? *p : 0; 433 434 /* 435 * Fill the resource structure if its direct PLB interface 436 * otherwise fill the dcr_host structure. 437 */ 438 if (tft_access) { 439 drvdata->flags |= PLB_ACCESS_FLAG; 440 rc = of_address_to_resource(op->dev.of_node, 0, &res); 441 if (rc) { 442 dev_err(&op->dev, "invalid address\n"); 443 goto err; 444 } 445 } 446#ifdef CONFIG_PPC_DCR 447 else { 448 int start; 449 res.start = 0; 450 start = dcr_resource_start(op->dev.of_node, 0); 451 drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0); 452 drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len); 453 if (!DCR_MAP_OK(drvdata->dcr_host)) { 454 dev_err(&op->dev, "invalid DCR address\n"); 455 goto err; 456 } 457 } 458#endif 459 460 prop = of_get_property(op->dev.of_node, "phys-size", &size); 461 if ((prop) && (size >= sizeof(u32)*2)) { 462 pdata.screen_width_mm = prop[0]; 463 pdata.screen_height_mm = prop[1]; 464 } 465 466 prop = of_get_property(op->dev.of_node, "resolution", &size); 467 if ((prop) && (size >= sizeof(u32)*2)) { 468 pdata.xres = prop[0]; 469 pdata.yres = prop[1]; 470 } 471 472 prop = of_get_property(op->dev.of_node, "virtual-resolution", &size); 473 if ((prop) && (size >= sizeof(u32)*2)) { 474 pdata.xvirt = prop[0]; 475 pdata.yvirt = prop[1]; 476 } 477 478 if (of_find_property(op->dev.of_node, "rotate-display", NULL)) 479 pdata.rotate_screen = 1; 480 481 dev_set_drvdata(&op->dev, drvdata); 482 return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata); 483 484 err: 485 kfree(drvdata); 486 return -ENODEV; 487} 488 489static int __devexit xilinxfb_of_remove(struct platform_device *op) 490{ 491 return xilinxfb_release(&op->dev); 492} 493 494/* Match table for of_platform binding */ 495static struct of_device_id xilinxfb_of_match[] __devinitdata = { 496 { .compatible = "xlnx,xps-tft-1.00.a", }, 497 { .compatible = "xlnx,xps-tft-2.00.a", }, 498 { .compatible = "xlnx,xps-tft-2.01.a", }, 499 { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", }, 500 { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", }, 501 {}, 502}; 503MODULE_DEVICE_TABLE(of, xilinxfb_of_match); 504 505static struct platform_driver xilinxfb_of_driver = { 506 .probe = xilinxfb_of_probe, 507 .remove = __devexit_p(xilinxfb_of_remove), 508 .driver = { 509 .name = DRIVER_NAME, 510 .owner = THIS_MODULE, 511 .of_match_table = xilinxfb_of_match, 512 }, 513}; 514 515 516/* --------------------------------------------------------------------- 517 * Module setup and teardown 518 */ 519 520static int __init 521xilinxfb_init(void) 522{ 523 return platform_driver_register(&xilinxfb_of_driver); 524} 525 526static void __exit 527xilinxfb_cleanup(void) 528{ 529 platform_driver_unregister(&xilinxfb_of_driver); 530} 531 532module_init(xilinxfb_init); 533module_exit(xilinxfb_cleanup); 534 535MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); 536MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); 537MODULE_LICENSE("GPL");