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.c353
1 files changed, 252 insertions, 101 deletions
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 6ef9733a18d4..6ef99b2d13ca 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -6,9 +6,12 @@
6 * Author: MontaVista Software, Inc. 6 * Author: MontaVista Software, Inc.
7 * source@mvista.com 7 * source@mvista.com
8 * 8 *
9 * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the 9 * 2002-2007 (c) MontaVista Software, Inc.
10 * terms of the GNU General Public License version 2. This program is licensed 10 * 2007 (c) Secret Lab Technologies, Ltd.
11 * "as is" without any warranty of any kind, whether express or implied. 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.
12 */ 15 */
13 16
14/* 17/*
@@ -18,6 +21,7 @@
18 * Geert Uytterhoeven. 21 * Geert Uytterhoeven.
19 */ 22 */
20 23
24#include <linux/device.h>
21#include <linux/module.h> 25#include <linux/module.h>
22#include <linux/kernel.h> 26#include <linux/kernel.h>
23#include <linux/version.h> 27#include <linux/version.h>
@@ -28,9 +32,12 @@
28#include <linux/init.h> 32#include <linux/init.h>
29#include <linux/dma-mapping.h> 33#include <linux/dma-mapping.h>
30#include <linux/platform_device.h> 34#include <linux/platform_device.h>
31 35#if defined(CONFIG_OF)
36#include <linux/of_device.h>
37#include <linux/of_platform.h>
38#endif
32#include <asm/io.h> 39#include <asm/io.h>
33#include <syslib/virtex_devices.h> 40#include <linux/xilinxfb.h>
34 41
35#define DRIVER_NAME "xilinxfb" 42#define DRIVER_NAME "xilinxfb"
36#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" 43#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver"
@@ -63,12 +70,6 @@
63 */ 70 */
64#define BYTES_PER_PIXEL 4 71#define BYTES_PER_PIXEL 4
65#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) 72#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8)
66#define XRES 640
67#define YRES 480
68#define XRES_VIRTUAL 1024
69#define YRES_VIRTUAL YRES
70#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL)
71#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH)
72 73
73#define RED_SHIFT 16 74#define RED_SHIFT 16
74#define GREEN_SHIFT 8 75#define GREEN_SHIFT 8
@@ -77,23 +78,26 @@
77#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ 78#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */
78 79
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/*
80 * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures 91 * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
81 */ 92 */
82static struct fb_fix_screeninfo xilinx_fb_fix = { 93static struct fb_fix_screeninfo xilinx_fb_fix = {
83 .id = "Xilinx", 94 .id = "Xilinx",
84 .type = FB_TYPE_PACKED_PIXELS, 95 .type = FB_TYPE_PACKED_PIXELS,
85 .visual = FB_VISUAL_TRUECOLOR, 96 .visual = FB_VISUAL_TRUECOLOR,
86 .smem_len = FB_SIZE,
87 .line_length = LINE_LENGTH,
88 .accel = FB_ACCEL_NONE 97 .accel = FB_ACCEL_NONE
89}; 98};
90 99
91static struct fb_var_screeninfo xilinx_fb_var = { 100static struct fb_var_screeninfo xilinx_fb_var = {
92 .xres = XRES,
93 .yres = YRES,
94 .xres_virtual = XRES_VIRTUAL,
95 .yres_virtual = YRES_VIRTUAL,
96
97 .bits_per_pixel = BITS_PER_PIXEL, 101 .bits_per_pixel = BITS_PER_PIXEL,
98 102
99 .red = { RED_SHIFT, 8, 0 }, 103 .red = { RED_SHIFT, 8, 0 },
@@ -111,8 +115,9 @@ struct xilinxfb_drvdata {
111 u32 regs_phys; /* phys. address of the control registers */ 115 u32 regs_phys; /* phys. address of the control registers */
112 u32 __iomem *regs; /* virt. address of the control registers */ 116 u32 __iomem *regs; /* virt. address of the control registers */
113 117
114 unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ 118 void *fb_virt; /* virt. address of the frame buffer */
115 dma_addr_t fb_phys; /* phys. 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? */
116 121
117 u32 reg_ctrl_default; 122 u32 reg_ctrl_default;
118 123
@@ -195,130 +200,136 @@ static struct fb_ops xilinxfb_ops =
195 .fb_imageblit = cfb_imageblit, 200 .fb_imageblit = cfb_imageblit,
196}; 201};
197 202
198/* === The device driver === */ 203/* ---------------------------------------------------------------------
204 * Bus independent setup/teardown
205 */
199 206
200static int 207static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
201xilinxfb_drv_probe(struct device *dev) 208 struct xilinxfb_platform_data *pdata)
202{ 209{
203 struct platform_device *pdev;
204 struct xilinxfb_platform_data *pdata;
205 struct xilinxfb_drvdata *drvdata; 210 struct xilinxfb_drvdata *drvdata;
206 struct resource *regs_res; 211 int rc;
207 int retval; 212 int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
208
209 if (!dev)
210 return -EINVAL;
211
212 pdev = to_platform_device(dev);
213 pdata = pdev->dev.platform_data;
214 213
214 /* Allocate the driver data region */
215 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 215 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
216 if (!drvdata) { 216 if (!drvdata) {
217 printk(KERN_ERR "Couldn't allocate device private record\n"); 217 dev_err(dev, "Couldn't allocate device private record\n");
218 return -ENOMEM; 218 return -ENOMEM;
219 } 219 }
220 dev_set_drvdata(dev, drvdata); 220 dev_set_drvdata(dev, drvdata);
221 221
222 /* Map the control registers in */ 222 /* Map the control registers in */
223 regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); 223 if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
224 if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { 224 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
225 printk(KERN_ERR "Couldn't get registers resource\n"); 225 physaddr);
226 retval = -EFAULT; 226 rc = -ENODEV;
227 goto failed1; 227 goto err_region;
228 } 228 }
229 229 drvdata->regs_phys = physaddr;
230 if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { 230 drvdata->regs = ioremap(physaddr, 8);
231 printk(KERN_ERR 231 if (!drvdata->regs) {
232 "Couldn't lock memory region at 0x%08X\n", 232 dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
233 regs_res->start); 233 physaddr);
234 retval = -EBUSY; 234 rc = -ENODEV;
235 goto failed1; 235 goto err_map;
236 } 236 }
237 drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
238 drvdata->regs_phys = regs_res->start;
239 237
240 /* Allocate the framebuffer memory */ 238 /* Allocate the framebuffer memory */
241 drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), 239 if (pdata->fb_phys) {
242 &drvdata->fb_phys, GFP_KERNEL); 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
243 if (!drvdata->fb_virt) { 248 if (!drvdata->fb_virt) {
244 printk(KERN_ERR "Could not allocate frame buffer memory\n"); 249 dev_err(dev, "Could not allocate frame buffer memory\n");
245 retval = -ENOMEM; 250 rc = -ENOMEM;
246 goto failed2; 251 goto err_fbmem;
247 } 252 }
248 253
249 /* Clear (turn to black) the framebuffer */ 254 /* Clear (turn to black) the framebuffer */
250 memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); 255 memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
251 256
252 /* Tell the hardware where the frame buffer is */ 257 /* Tell the hardware where the frame buffer is */
253 xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); 258 xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
254 259
255 /* Turn on the display */ 260 /* Turn on the display */
256 drvdata->reg_ctrl_default = REG_CTRL_ENABLE; 261 drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
257 if (pdata && pdata->rotate_screen) 262 if (pdata->rotate_screen)
258 drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; 263 drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
259 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); 264 xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
260 265
261 /* Fill struct fb_info */ 266 /* Fill struct fb_info */
262 drvdata->info.device = dev; 267 drvdata->info.device = dev;
263 drvdata->info.screen_base = drvdata->fb_virt; 268 drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
264 drvdata->info.fbops = &xilinxfb_ops; 269 drvdata->info.fbops = &xilinxfb_ops;
265 drvdata->info.fix = xilinx_fb_fix; 270 drvdata->info.fix = xilinx_fb_fix;
266 drvdata->info.fix.smem_start = drvdata->fb_phys; 271 drvdata->info.fix.smem_start = drvdata->fb_phys;
267 drvdata->info.pseudo_palette = drvdata->pseudo_palette; 272 drvdata->info.fix.smem_len = fbsize;
268 273 drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
269 if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
270 printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
271 PALETTE_ENTRIES_NO);
272 retval = -EFAULT;
273 goto failed3;
274 }
275 274
275 drvdata->info.pseudo_palette = drvdata->pseudo_palette;
276 drvdata->info.flags = FBINFO_DEFAULT; 276 drvdata->info.flags = FBINFO_DEFAULT;
277 if (pdata) {
278 xilinx_fb_var.height = pdata->screen_height_mm;
279 xilinx_fb_var.width = pdata->screen_width_mm;
280 }
281 drvdata->info.var = xilinx_fb_var; 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 }
282 292
283 /* Register new frame buffer */ 293 /* Register new frame buffer */
284 if (register_framebuffer(&drvdata->info) < 0) { 294 rc = register_framebuffer(&drvdata->info);
285 printk(KERN_ERR "Could not register frame buffer\n"); 295 if (rc) {
286 retval = -EINVAL; 296 dev_err(dev, "Could not register frame buffer\n");
287 goto failed4; 297 goto err_regfb;
288 } 298 }
289 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
290 return 0; /* success */ 305 return 0; /* success */
291 306
292failed4: 307err_regfb:
293 fb_dealloc_cmap(&drvdata->info.cmap); 308 fb_dealloc_cmap(&drvdata->info.cmap);
294 309
295failed3: 310err_cmap:
296 dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, 311 if (drvdata->fb_alloced)
297 drvdata->fb_phys); 312 dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
298 313 drvdata->fb_phys);
299 /* Turn off the display */ 314 /* Turn off the display */
300 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 315 xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
316
317err_fbmem:
301 iounmap(drvdata->regs); 318 iounmap(drvdata->regs);
302 319
303failed2: 320err_map:
304 release_mem_region(regs_res->start, 8); 321 release_mem_region(physaddr, 8);
305 322
306failed1: 323err_region:
307 kfree(drvdata); 324 kfree(drvdata);
308 dev_set_drvdata(dev, NULL); 325 dev_set_drvdata(dev, NULL);
309 326
310 return retval; 327 return rc;
311} 328}
312 329
313static int 330static int xilinxfb_release(struct device *dev)
314xilinxfb_drv_remove(struct device *dev)
315{ 331{
316 struct xilinxfb_drvdata *drvdata; 332 struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
317
318 if (!dev)
319 return -ENODEV;
320
321 drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
322 333
323#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) 334#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
324 xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); 335 xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
@@ -328,8 +339,9 @@ xilinxfb_drv_remove(struct device *dev)
328 339
329 fb_dealloc_cmap(&drvdata->info.cmap); 340 fb_dealloc_cmap(&drvdata->info.cmap);
330 341
331 dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, 342 if (drvdata->fb_alloced)
332 drvdata->fb_phys); 343 dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
344 drvdata->fb_virt, drvdata->fb_phys);
333 345
334 /* Turn off the display */ 346 /* Turn off the display */
335 xilinx_fb_out_be32(drvdata, REG_CTRL, 0); 347 xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
@@ -343,29 +355,168 @@ xilinxfb_drv_remove(struct device *dev)
343 return 0; 355 return 0;
344} 356}
345 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;
346 367
347static struct device_driver xilinxfb_driver = { 368 /* Find the registers address */
348 .name = DRIVER_NAME, 369 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
349 .bus = &platform_bus_type, 370 if (!res) {
371 dev_err(&pdev->dev, "Couldn't get registers resource\n");
372 return -ENODEV;
373 }
350 374
351 .probe = xilinxfb_drv_probe, 375 /* If a pdata structure is provided, then extract the parameters */
352 .remove = xilinxfb_drv_remove 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 {},
353}; 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 */
354 499
355static int __init 500static int __init
356xilinxfb_init(void) 501xilinxfb_init(void)
357{ 502{
358 /* 503 int rc;
359 * No kernel boot options used, 504 rc = xilinxfb_of_register();
360 * so we just need to register the driver 505 if (rc)
361 */ 506 return rc;
362 return driver_register(&xilinxfb_driver); 507
508 rc = platform_driver_register(&xilinxfb_platform_driver);
509 if (rc)
510 xilinxfb_of_unregister();
511
512 return rc;
363} 513}
364 514
365static void __exit 515static void __exit
366xilinxfb_cleanup(void) 516xilinxfb_cleanup(void)
367{ 517{
368 driver_unregister(&xilinxfb_driver); 518 platform_driver_unregister(&xilinxfb_platform_driver);
519 xilinxfb_of_unregister();
369} 520}
370 521
371module_init(xilinxfb_init); 522module_init(xilinxfb_init);