aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorJohn Linn <john.linn@xilinx.com>2009-06-06 12:43:16 -0400
committerGrant Likely <grant.likely@secretlab.ca>2009-06-06 12:43:16 -0400
commitdac4ccfb64bcdd5b4c248ccc22903d67486573cd (patch)
tree9a577b802632f829f8ac74533e6defa1d04f00e9 /drivers/video
parentb907abc9f2bad3111269c53d0f951ee76e376b44 (diff)
fbdev: Add PLB support and cleanup DCR in xilinxfb driver.
Added support for the new xps tft controller. The new core has PLB interface support in addition to existing DCR interface. Removed platform device support as both MicroBlaze and PowerPC use device tree. Previously, the dcr interface was assumed to be used in mmio mode, and the register space of the dcr interface was precomputed and stuffed into the device tree. This driver now makes use of the new dcr infrastructure to represent the dcr interface. This enables the dcr interface to be connected directly to a native dcr interface in a clean way. Added compatibility for ml507 dvi core. Signed-off-by: Suneel <suneelg@xilinx.com> Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> Signed-off-by: John Linn <john.linn@xilinx.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/xilinxfb.c290
1 files changed, 151 insertions, 139 deletions
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 40a3a2afbfe7..7a868bd16e0e 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -1,13 +1,12 @@
1/* 1/*
2 * xilinxfb.c 2 * Xilinx TFT frame buffer driver
3 *
4 * Xilinx TFT LCD frame buffer driver
5 * 3 *
6 * Author: MontaVista Software, Inc. 4 * Author: MontaVista Software, Inc.
7 * source@mvista.com 5 * source@mvista.com
8 * 6 *
9 * 2002-2007 (c) MontaVista Software, Inc. 7 * 2002-2007 (c) MontaVista Software, Inc.
10 * 2007 (c) Secret Lab Technologies, Ltd. 8 * 2007 (c) Secret Lab Technologies, Ltd.
9 * 2009 (c) Xilinx Inc.
11 * 10 *
12 * This file is licensed under the terms of the GNU General Public License 11 * 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 12 * version 2. This program is licensed "as is" without any warranty of any
@@ -24,33 +23,38 @@
24#include <linux/device.h> 23#include <linux/device.h>
25#include <linux/module.h> 24#include <linux/module.h>
26#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/version.h>
27#include <linux/errno.h> 27#include <linux/errno.h>
28#include <linux/string.h> 28#include <linux/string.h>
29#include <linux/mm.h> 29#include <linux/mm.h>
30#include <linux/fb.h> 30#include <linux/fb.h>
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/dma-mapping.h> 32#include <linux/dma-mapping.h>
33#include <linux/platform_device.h>
34#if defined(CONFIG_OF)
35#include <linux/of_device.h> 33#include <linux/of_device.h>
36#include <linux/of_platform.h> 34#include <linux/of_platform.h>
37#endif 35#include <linux/io.h>
38#include <asm/io.h>
39#include <linux/xilinxfb.h> 36#include <linux/xilinxfb.h>
37#include <asm/dcr.h>
40 38
41#define DRIVER_NAME "xilinxfb" 39#define DRIVER_NAME "xilinxfb"
42#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" 40
43 41
44/* 42/*
45 * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for 43 * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
46 * the VGA port on the Xilinx ML40x board. This is a hardware display controller 44 * the VGA port on the Xilinx ML40x board. This is a hardware display
47 * for a 640x480 resolution TFT or VGA screen. 45 * controller for a 640x480 resolution TFT or VGA screen.
48 * 46 *
49 * The interface to the framebuffer is nice and simple. There are two 47 * The interface to the framebuffer is nice and simple. There are two
50 * control registers. The first tells the LCD interface where in memory 48 * control registers. The first tells the LCD interface where in memory
51 * the frame buffer is (only the 11 most significant bits are used, so 49 * the frame buffer is (only the 11 most significant bits are used, so
52 * don't start thinking about scrolling). The second allows the LCD to 50 * don't start thinking about scrolling). The second allows the LCD to
53 * be turned on or off as well as rotated 180 degrees. 51 * be turned on or off as well as rotated 180 degrees.
52 *
53 * In case of direct PLB access the second control register will be at
54 * an offset of 4 as compared to the DCR access where the offset is 1
55 * i.e. REG_CTRL. So this is taken care in the function
56 * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of
57 * direct PLB access.
54 */ 58 */
55#define NUM_REGS 2 59#define NUM_REGS 2
56#define REG_FB_ADDR 0 60#define REG_FB_ADDR 0
@@ -107,17 +111,28 @@ static struct fb_var_screeninfo xilinx_fb_var = {
107 .activate = FB_ACTIVATE_NOW 111 .activate = FB_ACTIVATE_NOW
108}; 112};
109 113
114
115#define PLB_ACCESS_FLAG 0x1 /* 1 = PLB, 0 = DCR */
116
110struct xilinxfb_drvdata { 117struct xilinxfb_drvdata {
111 118
112 struct fb_info info; /* FB driver info record */ 119 struct fb_info info; /* FB driver info record */
113 120
114 u32 regs_phys; /* phys. address of the control registers */ 121 phys_addr_t regs_phys; /* phys. address of the control
115 u32 __iomem *regs; /* virt. address of the control registers */ 122 registers */
123 void __iomem *regs; /* virt. address of the control
124 registers */
125
126 dcr_host_t dcr_host;
127 unsigned int dcr_start;
128 unsigned int dcr_len;
116 129
117 void *fb_virt; /* virt. address of the frame buffer */ 130 void *fb_virt; /* virt. address of the frame buffer */
118 dma_addr_t fb_phys; /* phys. address of the frame buffer */ 131 dma_addr_t fb_phys; /* phys. address of the frame buffer */
119 int fb_alloced; /* Flag, was the fb memory alloced? */ 132 int fb_alloced; /* Flag, was the fb memory alloced? */
120 133
134 u8 flags; /* features of the driver */
135
121 u32 reg_ctrl_default; 136 u32 reg_ctrl_default;
122 137
123 u32 pseudo_palette[PALETTE_ENTRIES_NO]; 138 u32 pseudo_palette[PALETTE_ENTRIES_NO];
@@ -128,14 +143,19 @@ struct xilinxfb_drvdata {
128 container_of(_info, struct xilinxfb_drvdata, info) 143 container_of(_info, struct xilinxfb_drvdata, info)
129 144
130/* 145/*
131 * The LCD controller has DCR interface to its registers, but all 146 * The XPS TFT Controller can be accessed through PLB or DCR interface.
132 * the boards and configurations the driver has been tested with 147 * To perform the read/write on the registers we need to check on
133 * use opb2dcr bridge. So the registers are seen as memory mapped. 148 * which bus its connected and call the appropriate write API.
134 * This macro is to make it simple to add the direct DCR access
135 * when it's needed.
136 */ 149 */
137#define xilinx_fb_out_be32(driverdata, offset, val) \ 150static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
138 out_be32(driverdata->regs + offset, val) 151 u32 val)
152{
153 if (drvdata->flags & PLB_ACCESS_FLAG)
154 out_be32(drvdata->regs + (offset << 2), val);
155 else
156 dcr_write(drvdata->dcr_host, offset, val);
157
158}
139 159
140static int 160static int
141xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, 161xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
@@ -203,35 +223,34 @@ static struct fb_ops xilinxfb_ops =
203 * Bus independent setup/teardown 223 * Bus independent setup/teardown
204 */ 224 */
205 225
206static int xilinxfb_assign(struct device *dev, unsigned long physaddr, 226static int xilinxfb_assign(struct device *dev,
227 struct xilinxfb_drvdata *drvdata,
228 unsigned long physaddr,
207 struct xilinxfb_platform_data *pdata) 229 struct xilinxfb_platform_data *pdata)
208{ 230{
209 struct xilinxfb_drvdata *drvdata;
210 int rc; 231 int rc;
211 int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; 232 int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
212 233
213 /* Allocate the driver data region */ 234 if (drvdata->flags & PLB_ACCESS_FLAG) {
214 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 235 /*
215 if (!drvdata) { 236 * Map the control registers in if the controller
216 dev_err(dev, "Couldn't allocate device private record\n"); 237 * is on direct PLB interface.
217 return -ENOMEM; 238 */
218 } 239 if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
219 dev_set_drvdata(dev, drvdata); 240 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
220 241 physaddr);
221 /* Map the control registers in */ 242 rc = -ENODEV;
222 if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { 243 goto err_region;
223 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", 244 }
224 physaddr); 245
225 rc = -ENODEV; 246 drvdata->regs_phys = physaddr;
226 goto err_region; 247 drvdata->regs = ioremap(physaddr, 8);
227 } 248 if (!drvdata->regs) {
228 drvdata->regs_phys = physaddr; 249 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
229 drvdata->regs = ioremap(physaddr, 8); 250 physaddr);
230 if (!drvdata->regs) { 251 rc = -ENODEV;
231 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", 252 goto err_map;
232 physaddr); 253 }
233 rc = -ENODEV;
234 goto err_map;
235 } 254 }
236 255
237 /* Allocate the framebuffer memory */ 256 /* Allocate the framebuffer memory */
@@ -247,7 +266,10 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
247 if (!drvdata->fb_virt) { 266 if (!drvdata->fb_virt) {
248 dev_err(dev, "Could not allocate frame buffer memory\n"); 267 dev_err(dev, "Could not allocate frame buffer memory\n");
249 rc = -ENOMEM; 268 rc = -ENOMEM;
250 goto err_fbmem; 269 if (drvdata->flags & PLB_ACCESS_FLAG)
270 goto err_fbmem;
271 else
272 goto err_region;
251 } 273 }
252 274
253 /* Clear (turn to black) the framebuffer */ 275 /* Clear (turn to black) the framebuffer */
@@ -260,7 +282,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
260 drvdata->reg_ctrl_default = REG_CTRL_ENABLE; 282 drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
261 if (pdata->rotate_screen) 283 if (pdata->rotate_screen)
262 drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; 284 drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
263 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); 285 xilinx_fb_out_be32(drvdata, REG_CTRL,
286 drvdata->reg_ctrl_default);
264 287
265 /* Fill struct fb_info */ 288 /* Fill struct fb_info */
266 drvdata->info.device = dev; 289 drvdata->info.device = dev;
@@ -296,11 +319,14 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
296 goto err_regfb; 319 goto err_regfb;
297 } 320 }
298 321
322 if (drvdata->flags & PLB_ACCESS_FLAG) {
323 /* Put a banner in the log (for DEBUG) */
324 dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr,
325 drvdata->regs);
326 }
299 /* Put a banner in the log (for DEBUG) */ 327 /* Put a banner in the log (for DEBUG) */
300 dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); 328 dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n",
301 dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n", 329 (void *)drvdata->fb_phys, drvdata->fb_virt, fbsize);
302 (unsigned long long) drvdata->fb_phys, drvdata->fb_virt,
303 fbsize);
304 330
305 return 0; /* success */ 331 return 0; /* success */
306 332
@@ -311,14 +337,19 @@ err_cmap:
311 if (drvdata->fb_alloced) 337 if (drvdata->fb_alloced)
312 dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, 338 dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
313 drvdata->fb_phys); 339 drvdata->fb_phys);
340 else
341 iounmap(drvdata->fb_virt);
342
314 /* Turn off the display */ 343 /* Turn off the display */
315 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 344 xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
316 345
317err_fbmem: 346err_fbmem:
318 iounmap(drvdata->regs); 347 if (drvdata->flags & PLB_ACCESS_FLAG)
348 iounmap(drvdata->regs);
319 349
320err_map: 350err_map:
321 release_mem_region(physaddr, 8); 351 if (drvdata->flags & PLB_ACCESS_FLAG)
352 release_mem_region(physaddr, 8);
322 353
323err_region: 354err_region:
324 kfree(drvdata); 355 kfree(drvdata);
@@ -342,12 +373,18 @@ static int xilinxfb_release(struct device *dev)
342 if (drvdata->fb_alloced) 373 if (drvdata->fb_alloced)
343 dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), 374 dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
344 drvdata->fb_virt, drvdata->fb_phys); 375 drvdata->fb_virt, drvdata->fb_phys);
376 else
377 iounmap(drvdata->fb_virt);
345 378
346 /* Turn off the display */ 379 /* Turn off the display */
347 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 380 xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
348 iounmap(drvdata->regs);
349 381
350 release_mem_region(drvdata->regs_phys, 8); 382 /* Release the resources, as allocated based on interface */
383 if (drvdata->flags & PLB_ACCESS_FLAG) {
384 iounmap(drvdata->regs);
385 release_mem_region(drvdata->regs_phys, 8);
386 } else
387 dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
351 388
352 kfree(drvdata); 389 kfree(drvdata);
353 dev_set_drvdata(dev, NULL); 390 dev_set_drvdata(dev, NULL);
@@ -356,77 +393,57 @@ static int xilinxfb_release(struct device *dev)
356} 393}
357 394
358/* --------------------------------------------------------------------- 395/* ---------------------------------------------------------------------
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 396 * OF bus binding
410 */ 397 */
411 398
412#if defined(CONFIG_OF)
413static int __devinit 399static int __devinit
414xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) 400xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
415{ 401{
416 struct resource res;
417 const u32 *prop; 402 const u32 *prop;
403 u32 *p;
404 u32 tft_access;
418 struct xilinxfb_platform_data pdata; 405 struct xilinxfb_platform_data pdata;
406 struct resource res;
419 int size, rc; 407 int size, rc;
408 int start = 0, len = 0;
409 dcr_host_t dcr_host;
410 struct xilinxfb_drvdata *drvdata;
420 411
421 /* Copy with the default pdata (not a ptr reference!) */ 412 /* Copy with the default pdata (not a ptr reference!) */
422 pdata = xilinx_fb_default_pdata; 413 pdata = xilinx_fb_default_pdata;
423 414
424 dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); 415 dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
425 416
426 rc = of_address_to_resource(op->node, 0, &res); 417 /*
427 if (rc) { 418 * To check whether the core is connected directly to DCR or PLB
428 dev_err(&op->dev, "invalid address\n"); 419 * interface and initialize the tft_access accordingly.
429 return rc; 420 */
421 p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL);
422
423 if (p)
424 tft_access = *p;
425 else
426 tft_access = 0; /* For backward compatibility */
427
428 /*
429 * Fill the resource structure if its direct PLB interface
430 * otherwise fill the dcr_host structure.
431 */
432 if (tft_access) {
433 rc = of_address_to_resource(op->node, 0, &res);
434 if (rc) {
435 dev_err(&op->dev, "invalid address\n");
436 return -ENODEV;
437 }
438
439 } else {
440 start = dcr_resource_start(op->node, 0);
441 len = dcr_resource_len(op->node, 0);
442 dcr_host = dcr_map(op->node, start, len);
443 if (!DCR_MAP_OK(dcr_host)) {
444 dev_err(&op->dev, "invalid address\n");
445 return -ENODEV;
446 }
430 } 447 }
431 448
432 prop = of_get_property(op->node, "phys-size", &size); 449 prop = of_get_property(op->node, "phys-size", &size);
@@ -450,7 +467,26 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
450 if (of_find_property(op->node, "rotate-display", NULL)) 467 if (of_find_property(op->node, "rotate-display", NULL))
451 pdata.rotate_screen = 1; 468 pdata.rotate_screen = 1;
452 469
453 return xilinxfb_assign(&op->dev, res.start, &pdata); 470 /* Allocate the driver data region */
471 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
472 if (!drvdata) {
473 dev_err(&op->dev, "Couldn't allocate device private record\n");
474 return -ENOMEM;
475 }
476 dev_set_drvdata(&op->dev, drvdata);
477
478 if (tft_access)
479 drvdata->flags |= PLB_ACCESS_FLAG;
480
481 /* Arguments are passed based on the interface */
482 if (drvdata->flags & PLB_ACCESS_FLAG) {
483 return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata);
484 } else {
485 drvdata->dcr_start = start;
486 drvdata->dcr_len = len;
487 drvdata->dcr_host = dcr_host;
488 return xilinxfb_assign(&op->dev, drvdata, 0, &pdata);
489 }
454} 490}
455 491
456static int __devexit xilinxfb_of_remove(struct of_device *op) 492static int __devexit xilinxfb_of_remove(struct of_device *op)
@@ -460,7 +496,9 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
460 496
461/* Match table for of_platform binding */ 497/* Match table for of_platform binding */
462static struct of_device_id xilinxfb_of_match[] __devinitdata = { 498static struct of_device_id xilinxfb_of_match[] __devinitdata = {
499 { .compatible = "xlnx,xps-tft-1.00.a", },
463 { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", }, 500 { .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
501 { .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
464 {}, 502 {},
465}; 503};
466MODULE_DEVICE_TABLE(of, xilinxfb_of_match); 504MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
@@ -476,22 +514,6 @@ static struct of_platform_driver xilinxfb_of_driver = {
476 }, 514 },
477}; 515};
478 516
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 517
496/* --------------------------------------------------------------------- 518/* ---------------------------------------------------------------------
497 * Module setup and teardown 519 * Module setup and teardown
@@ -500,28 +522,18 @@ static inline void __exit xilinxfb_of_unregister(void) { }
500static int __init 522static int __init
501xilinxfb_init(void) 523xilinxfb_init(void)
502{ 524{
503 int rc; 525 return of_register_platform_driver(&xilinxfb_of_driver);
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} 526}
514 527
515static void __exit 528static void __exit
516xilinxfb_cleanup(void) 529xilinxfb_cleanup(void)
517{ 530{
518 platform_driver_unregister(&xilinxfb_platform_driver); 531 of_unregister_platform_driver(&xilinxfb_of_driver);
519 xilinxfb_of_unregister();
520} 532}
521 533
522module_init(xilinxfb_init); 534module_init(xilinxfb_init);
523module_exit(xilinxfb_cleanup); 535module_exit(xilinxfb_cleanup);
524 536
525MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); 537MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
526MODULE_DESCRIPTION(DRIVER_DESCRIPTION); 538MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
527MODULE_LICENSE("GPL"); 539MODULE_LICENSE("GPL");