aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/xilinxfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/xilinxfb.c')
-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");