diff options
author | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2007-10-11 08:45:20 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2007-10-11 08:45:20 -0400 |
commit | 0a2cdd88f0b8ea98bcaf9712446cc46a240313f5 (patch) | |
tree | 05f2ac8731a0b24bba1552458839b1c7d032ff63 /drivers | |
parent | cdec12aebe1b10aa58bebaa05bb697843154f7f9 (diff) | |
parent | 17c5c2093624e81acda16fb737e4679750addd7a (diff) |
Merge branch 'virtex-for-2.6.24' of git://git.secretlab.ca/git/linux-2.6-virtex into for-2.6.24-4xx
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/xilinxfb.c | 279 |
1 files changed, 199 insertions, 80 deletions
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 4bc67ab56afa..dec602c23075 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,7 +32,10 @@ | |||
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 <linux/xilinxfb.h> | 40 | #include <linux/xilinxfb.h> |
34 | 41 | ||
@@ -111,7 +118,7 @@ struct xilinxfb_drvdata { | |||
111 | u32 regs_phys; /* phys. address of the control registers */ | 118 | u32 regs_phys; /* phys. address of the control registers */ |
112 | u32 __iomem *regs; /* virt. address of the control registers */ | 119 | u32 __iomem *regs; /* virt. address of the control registers */ |
113 | 120 | ||
114 | unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ | 121 | void *fb_virt; /* virt. address of the frame buffer */ |
115 | dma_addr_t fb_phys; /* phys. address of the frame buffer */ | 122 | dma_addr_t fb_phys; /* phys. address of the frame buffer */ |
116 | 123 | ||
117 | u32 reg_ctrl_default; | 124 | u32 reg_ctrl_default; |
@@ -195,130 +202,120 @@ static struct fb_ops xilinxfb_ops = | |||
195 | .fb_imageblit = cfb_imageblit, | 202 | .fb_imageblit = cfb_imageblit, |
196 | }; | 203 | }; |
197 | 204 | ||
198 | /* === The device driver === */ | 205 | /* --------------------------------------------------------------------- |
206 | * Bus independent setup/teardown | ||
207 | */ | ||
199 | 208 | ||
200 | static int | 209 | static int xilinxfb_assign(struct device *dev, unsigned long physaddr, |
201 | xilinxfb_drv_probe(struct device *dev) | 210 | int width_mm, int height_mm, int rotate) |
202 | { | 211 | { |
203 | struct platform_device *pdev; | ||
204 | struct xilinxfb_platform_data *pdata; | ||
205 | struct xilinxfb_drvdata *drvdata; | 212 | struct xilinxfb_drvdata *drvdata; |
206 | struct resource *regs_res; | 213 | int rc; |
207 | int retval; | ||
208 | |||
209 | if (!dev) | ||
210 | return -EINVAL; | ||
211 | |||
212 | pdev = to_platform_device(dev); | ||
213 | pdata = pdev->dev.platform_data; | ||
214 | 214 | ||
215 | /* Allocate the driver data region */ | ||
215 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); | 216 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); |
216 | if (!drvdata) { | 217 | if (!drvdata) { |
217 | printk(KERN_ERR "Couldn't allocate device private record\n"); | 218 | dev_err(dev, "Couldn't allocate device private record\n"); |
218 | return -ENOMEM; | 219 | return -ENOMEM; |
219 | } | 220 | } |
220 | dev_set_drvdata(dev, drvdata); | 221 | dev_set_drvdata(dev, drvdata); |
221 | 222 | ||
222 | /* Map the control registers in */ | 223 | /* Map the control registers in */ |
223 | regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 224 | if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { |
224 | if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { | 225 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", |
225 | printk(KERN_ERR "Couldn't get registers resource\n"); | 226 | physaddr); |
226 | retval = -EFAULT; | 227 | rc = -ENODEV; |
227 | goto failed1; | 228 | goto err_region; |
228 | } | 229 | } |
229 | 230 | drvdata->regs_phys = physaddr; | |
230 | if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { | 231 | drvdata->regs = ioremap(physaddr, 8); |
231 | printk(KERN_ERR | 232 | if (!drvdata->regs) { |
232 | "Couldn't lock memory region at 0x%08X\n", | 233 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", |
233 | regs_res->start); | 234 | physaddr); |
234 | retval = -EBUSY; | 235 | rc = -ENODEV; |
235 | goto failed1; | 236 | goto err_map; |
236 | } | 237 | } |
237 | drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); | ||
238 | drvdata->regs_phys = regs_res->start; | ||
239 | 238 | ||
240 | /* Allocate the framebuffer memory */ | 239 | /* Allocate the framebuffer memory */ |
241 | drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), | 240 | drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), |
242 | &drvdata->fb_phys, GFP_KERNEL); | 241 | &drvdata->fb_phys, GFP_KERNEL); |
243 | if (!drvdata->fb_virt) { | 242 | if (!drvdata->fb_virt) { |
244 | printk(KERN_ERR "Could not allocate frame buffer memory\n"); | 243 | dev_err(dev, "Could not allocate frame buffer memory\n"); |
245 | retval = -ENOMEM; | 244 | rc = -ENOMEM; |
246 | goto failed2; | 245 | goto err_fbmem; |
247 | } | 246 | } |
248 | 247 | ||
249 | /* Clear (turn to black) the framebuffer */ | 248 | /* Clear (turn to black) the framebuffer */ |
250 | memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); | 249 | memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); |
251 | 250 | ||
252 | /* Tell the hardware where the frame buffer is */ | 251 | /* Tell the hardware where the frame buffer is */ |
253 | xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); | 252 | xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); |
254 | 253 | ||
255 | /* Turn on the display */ | 254 | /* Turn on the display */ |
256 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; | 255 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; |
257 | if (pdata && pdata->rotate_screen) | 256 | if (rotate) |
258 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; | 257 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; |
259 | xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); | 258 | xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); |
260 | 259 | ||
261 | /* Fill struct fb_info */ | 260 | /* Fill struct fb_info */ |
262 | drvdata->info.device = dev; | 261 | drvdata->info.device = dev; |
263 | drvdata->info.screen_base = drvdata->fb_virt; | 262 | drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; |
264 | drvdata->info.fbops = &xilinxfb_ops; | 263 | drvdata->info.fbops = &xilinxfb_ops; |
265 | drvdata->info.fix = xilinx_fb_fix; | 264 | drvdata->info.fix = xilinx_fb_fix; |
266 | drvdata->info.fix.smem_start = drvdata->fb_phys; | 265 | drvdata->info.fix.smem_start = drvdata->fb_phys; |
267 | drvdata->info.pseudo_palette = drvdata->pseudo_palette; | 266 | drvdata->info.pseudo_palette = drvdata->pseudo_palette; |
267 | drvdata->info.flags = FBINFO_DEFAULT; | ||
268 | drvdata->info.var = xilinx_fb_var; | ||
269 | |||
270 | xilinx_fb_var.height = height_mm; | ||
271 | xilinx_fb_var.width = width_mm; | ||
268 | 272 | ||
269 | if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { | 273 | /* Allocate a colour map */ |
270 | printk(KERN_ERR "Fail to allocate colormap (%d entries)\n", | 274 | rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); |
275 | if (rc) { | ||
276 | dev_err(dev, "Fail to allocate colormap (%d entries)\n", | ||
271 | PALETTE_ENTRIES_NO); | 277 | PALETTE_ENTRIES_NO); |
272 | retval = -EFAULT; | 278 | goto err_cmap; |
273 | goto failed3; | ||
274 | } | 279 | } |
275 | 280 | ||
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; | ||
282 | |||
283 | /* Register new frame buffer */ | 281 | /* Register new frame buffer */ |
284 | if (register_framebuffer(&drvdata->info) < 0) { | 282 | rc = register_framebuffer(&drvdata->info); |
285 | printk(KERN_ERR "Could not register frame buffer\n"); | 283 | if (rc) { |
286 | retval = -EINVAL; | 284 | dev_err(dev, "Could not register frame buffer\n"); |
287 | goto failed4; | 285 | goto err_regfb; |
288 | } | 286 | } |
289 | 287 | ||
288 | /* Put a banner in the log (for DEBUG) */ | ||
289 | dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); | ||
290 | dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", | ||
291 | (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); | ||
290 | return 0; /* success */ | 292 | return 0; /* success */ |
291 | 293 | ||
292 | failed4: | 294 | err_regfb: |
293 | fb_dealloc_cmap(&drvdata->info.cmap); | 295 | fb_dealloc_cmap(&drvdata->info.cmap); |
294 | 296 | ||
295 | failed3: | 297 | err_cmap: |
296 | dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, | 298 | dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, |
297 | drvdata->fb_phys); | 299 | drvdata->fb_phys); |
298 | |||
299 | /* Turn off the display */ | 300 | /* Turn off the display */ |
300 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 301 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); |
302 | |||
303 | err_fbmem: | ||
301 | iounmap(drvdata->regs); | 304 | iounmap(drvdata->regs); |
302 | 305 | ||
303 | failed2: | 306 | err_map: |
304 | release_mem_region(regs_res->start, 8); | 307 | release_mem_region(physaddr, 8); |
305 | 308 | ||
306 | failed1: | 309 | err_region: |
307 | kfree(drvdata); | 310 | kfree(drvdata); |
308 | dev_set_drvdata(dev, NULL); | 311 | dev_set_drvdata(dev, NULL); |
309 | 312 | ||
310 | return retval; | 313 | return rc; |
311 | } | 314 | } |
312 | 315 | ||
313 | static int | 316 | static int xilinxfb_release(struct device *dev) |
314 | xilinxfb_drv_remove(struct device *dev) | ||
315 | { | 317 | { |
316 | struct xilinxfb_drvdata *drvdata; | 318 | 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 | 319 | ||
323 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) | 320 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) |
324 | xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); | 321 | xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); |
@@ -343,29 +340,151 @@ xilinxfb_drv_remove(struct device *dev) | |||
343 | return 0; | 340 | return 0; |
344 | } | 341 | } |
345 | 342 | ||
343 | /* --------------------------------------------------------------------- | ||
344 | * Platform bus binding | ||
345 | */ | ||
346 | |||
347 | static int | ||
348 | xilinxfb_platform_probe(struct platform_device *pdev) | ||
349 | { | ||
350 | struct xilinxfb_platform_data *pdata; | ||
351 | struct resource *res; | ||
352 | int width_mm = 0; | ||
353 | int height_mm = 0; | ||
354 | int rotate = 0; | ||
355 | |||
356 | /* Find the registers address */ | ||
357 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
358 | if (!res) { | ||
359 | dev_err(&pdev->dev, "Couldn't get registers resource\n"); | ||
360 | return -ENODEV; | ||
361 | } | ||
362 | |||
363 | /* If a pdata structure is provided, then extract the parameters */ | ||
364 | pdata = pdev->dev.platform_data; | ||
365 | if (pdata) { | ||
366 | height_mm = pdata->screen_height_mm; | ||
367 | width_mm = pdata->screen_width_mm; | ||
368 | rotate = pdata->rotate_screen ? 1 : 0; | ||
369 | } | ||
370 | |||
371 | return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, | ||
372 | rotate); | ||
373 | } | ||
374 | |||
375 | static int | ||
376 | xilinxfb_platform_remove(struct platform_device *pdev) | ||
377 | { | ||
378 | return xilinxfb_release(&pdev->dev); | ||
379 | } | ||
346 | 380 | ||
347 | static struct device_driver xilinxfb_driver = { | ||
348 | .name = DRIVER_NAME, | ||
349 | .bus = &platform_bus_type, | ||
350 | 381 | ||
351 | .probe = xilinxfb_drv_probe, | 382 | static struct platform_driver xilinxfb_platform_driver = { |
352 | .remove = xilinxfb_drv_remove | 383 | .probe = xilinxfb_platform_probe, |
384 | .remove = xilinxfb_platform_remove, | ||
385 | .driver = { | ||
386 | .owner = THIS_MODULE, | ||
387 | .name = DRIVER_NAME, | ||
388 | }, | ||
353 | }; | 389 | }; |
354 | 390 | ||
391 | /* --------------------------------------------------------------------- | ||
392 | * OF bus binding | ||
393 | */ | ||
394 | |||
395 | #if defined(CONFIG_OF) | ||
396 | static int __devinit | ||
397 | xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) | ||
398 | { | ||
399 | struct resource res; | ||
400 | const u32 *prop; | ||
401 | int width = 0, height = 0, rotate = 0; | ||
402 | int size, rc; | ||
403 | |||
404 | dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); | ||
405 | |||
406 | rc = of_address_to_resource(op->node, 0, &res); | ||
407 | if (rc) { | ||
408 | dev_err(&op->dev, "invalid address\n"); | ||
409 | return rc; | ||
410 | } | ||
411 | |||
412 | prop = of_get_property(op->node, "display-number", &size); | ||
413 | if ((prop) && (size >= sizeof(u32)*2)) { | ||
414 | width = prop[0]; | ||
415 | height = prop[1]; | ||
416 | } | ||
417 | |||
418 | if (of_find_property(op->node, "rotate-display", NULL)) | ||
419 | rotate = 1; | ||
420 | |||
421 | return xilinxfb_assign(&op->dev, res.start, width, height, rotate); | ||
422 | } | ||
423 | |||
424 | static int __devexit xilinxfb_of_remove(struct of_device *op) | ||
425 | { | ||
426 | return xilinxfb_release(&op->dev); | ||
427 | } | ||
428 | |||
429 | /* Match table for of_platform binding */ | ||
430 | static struct of_device_id __devinit xilinxfb_of_match[] = { | ||
431 | { .compatible = "xilinx,ml300-fb", }, | ||
432 | {}, | ||
433 | }; | ||
434 | MODULE_DEVICE_TABLE(of, xilinxfb_of_match); | ||
435 | |||
436 | static struct of_platform_driver xilinxfb_of_driver = { | ||
437 | .owner = THIS_MODULE, | ||
438 | .name = DRIVER_NAME, | ||
439 | .match_table = xilinxfb_of_match, | ||
440 | .probe = xilinxfb_of_probe, | ||
441 | .remove = __devexit_p(xilinxfb_of_remove), | ||
442 | .driver = { | ||
443 | .name = DRIVER_NAME, | ||
444 | }, | ||
445 | }; | ||
446 | |||
447 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
448 | static inline int __init xilinxfb_of_register(void) | ||
449 | { | ||
450 | pr_debug("xilinxfb: calling of_register_platform_driver()\n"); | ||
451 | return of_register_platform_driver(&xilinxfb_of_driver); | ||
452 | } | ||
453 | |||
454 | static inline void __exit xilinxfb_of_unregister(void) | ||
455 | { | ||
456 | of_unregister_platform_driver(&xilinxfb_of_driver); | ||
457 | } | ||
458 | #else /* CONFIG_OF */ | ||
459 | /* CONFIG_OF not enabled; do nothing helpers */ | ||
460 | static inline int __init xilinxfb_of_register(void) { return 0; } | ||
461 | static inline void __exit xilinxfb_of_unregister(void) { } | ||
462 | #endif /* CONFIG_OF */ | ||
463 | |||
464 | /* --------------------------------------------------------------------- | ||
465 | * Module setup and teardown | ||
466 | */ | ||
467 | |||
355 | static int __init | 468 | static int __init |
356 | xilinxfb_init(void) | 469 | xilinxfb_init(void) |
357 | { | 470 | { |
358 | /* | 471 | int rc; |
359 | * No kernel boot options used, | 472 | rc = xilinxfb_of_register(); |
360 | * so we just need to register the driver | 473 | if (rc) |
361 | */ | 474 | return rc; |
362 | return driver_register(&xilinxfb_driver); | 475 | |
476 | rc = platform_driver_register(&xilinxfb_platform_driver); | ||
477 | if (rc) | ||
478 | xilinxfb_of_unregister(); | ||
479 | |||
480 | return rc; | ||
363 | } | 481 | } |
364 | 482 | ||
365 | static void __exit | 483 | static void __exit |
366 | xilinxfb_cleanup(void) | 484 | xilinxfb_cleanup(void) |
367 | { | 485 | { |
368 | driver_unregister(&xilinxfb_driver); | 486 | platform_driver_unregister(&xilinxfb_platform_driver); |
487 | xilinxfb_of_unregister(); | ||
369 | } | 488 | } |
370 | 489 | ||
371 | module_init(xilinxfb_init); | 490 | module_init(xilinxfb_init); |