Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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