From 4c2a54b09ba35a409afc34bd331a57a994921664 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 19 Sep 2007 14:50:22 +1000 Subject: [POWERPC] Fix platinumfb framebuffer Current kernels have a non-working platinumfb due to some resource management issues. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/video/platinumfb.c | 48 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 8503e733a172..cbe71a5338d0 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -17,6 +17,8 @@ * more details. */ +#undef DEBUG + #include #include #include @@ -535,33 +537,35 @@ static int __devinit platinumfb_probe(struct of_device* odev, volatile __u8 *fbuffer; int bank0, bank1, bank2, bank3, rc; - printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n"); + dev_info(&odev->dev, "Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); - if (info == NULL) + if (info == NULL) { + dev_err(&odev->dev, "Failed to allocate fbdev !\n"); return -ENOMEM; + } pinfo = info->par; if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) { - printk(KERN_ERR "platinumfb: Can't get resources\n"); - framebuffer_release(info); - return -ENXIO; - } - if (!request_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.start - - pinfo->rsrc_reg.end + 1, - "platinumfb registers")) { + dev_err(&odev->dev, "Can't get resources\n"); framebuffer_release(info); return -ENXIO; } + dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_reg.start, + (unsigned long long)pinfo->rsrc_reg.end); + dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_fb.start, + (unsigned long long)pinfo->rsrc_fb.end); + + /* Do not try to request register space, they overlap with the + * northbridge and that can fail. Only request framebuffer + */ if (!request_mem_region(pinfo->rsrc_fb.start, - pinfo->rsrc_fb.start - - pinfo->rsrc_fb.end + 1, + pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1, "platinumfb framebuffer")) { - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); + printk(KERN_ERR "platinumfb: Can't request framebuffer !\n"); framebuffer_release(info); return -ENXIO; } @@ -600,7 +604,8 @@ static int __devinit platinumfb_probe(struct of_device* odev, bank2 = fbuffer[0x200000] == 0x56; bank3 = fbuffer[0x300000] == 0x78; pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; - printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024), + printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", + (unsigned int) (pinfo->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0); /* @@ -644,16 +649,15 @@ static int __devexit platinumfb_remove(struct of_device* odev) unregister_framebuffer (info); /* Unmap frame buffer and registers */ + iounmap(pinfo->frame_buffer); + iounmap(pinfo->platinum_regs); + iounmap(pinfo->cmap_regs); + release_mem_region(pinfo->rsrc_fb.start, pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1); - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); - iounmap(pinfo->frame_buffer); - iounmap(pinfo->platinum_regs); + release_mem_region(pinfo->cmap_regs_phys, 0x1000); - iounmap(pinfo->cmap_regs); framebuffer_release(info); -- cgit v1.2.3-70-g09d2 From dc8afdc7ada82562231cbae867fe6dcdb7b677f5 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 07:47:00 +1000 Subject: [POWERPC] XilinxFB: Move xilinxfb_platform_data definition to a shared header file XilnixFB can be used by more than just arch/ppc. Move the data structure definition into include/linux/xilinxfb.h so it can be used by microblaze and arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.h | 8 +------- drivers/video/xilinxfb.c | 2 +- include/linux/xilinxfb.h | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 include/linux/xilinxfb.h (limited to 'drivers/video') diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h index 9f38d92ae536..6ebd9b4b8f1c 100644 --- a/arch/ppc/syslib/virtex_devices.h +++ b/arch/ppc/syslib/virtex_devices.h @@ -12,13 +12,7 @@ #define __ASM_VIRTEX_DEVICES_H__ #include - -/* ML300/403 reference design framebuffer driver platform data struct */ -struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; - u32 screen_width_mm; -}; +#include void __init virtex_early_serial_map(void); diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ef9733a18d4..4bc67ab56afa 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -30,7 +30,7 @@ #include #include -#include +#include #define DRIVER_NAME "xilinxfb" #define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h new file mode 100644 index 000000000000..9ad984d22c38 --- /dev/null +++ b/include/linux/xilinxfb.h @@ -0,0 +1,23 @@ +/* + * Platform device data for Xilinx Framebuffer device + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XILINXFB_H__ +#define __XILINXFB_H__ + +#include + +/* ML300/403 reference design framebuffer driver platform data struct */ +struct xilinxfb_platform_data { + u32 rotate_screen; + u32 screen_height_mm; + u32 screen_width_mm; +}; + +#endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2 From 258de4badd5b7b5d168307638f755bd4df16c18e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [POWERPC] XilinxFB: add banner output to probe routine when DEBUG is defined Debug support: when DEBUG is defined, output relevant details to the log about the framebuffer registration. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 4bc67ab56afa..1a5f1e429c4d 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -287,6 +287,11 @@ xilinxfb_drv_probe(struct device *dev) goto failed4; } + /* Put a banner in the log (for DEBUG) */ + dev_dbg(dev, "regs: phys=%x, virt=%p\n", + drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", + (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ failed4: -- cgit v1.2.3-70-g09d2 From 3cb3ec2c26473d8123a468abfaca1e926344b1c2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [POWERPC] XilinxFB: Replace calls to printk with dev_dbg, dev_err, etc. The dev_dbg, dev_err, etc functions provide more context that plain vanilla printk which is useful for debugging. Where appropriate, change printk calls to the appropriate dev_*() call. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 1a5f1e429c4d..e63cbd1acfd2 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -18,6 +18,7 @@ * Geert Uytterhoeven. */ +#include #include #include #include @@ -214,7 +215,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { - printk(KERN_ERR "Couldn't allocate device private record\n"); + dev_err(dev, "Couldn't allocate device private record\n"); return -ENOMEM; } dev_set_drvdata(dev, drvdata); @@ -222,14 +223,13 @@ xilinxfb_drv_probe(struct device *dev) /* Map the control registers in */ regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - printk(KERN_ERR "Couldn't get registers resource\n"); + dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; goto failed1; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - printk(KERN_ERR - "Couldn't lock memory region at 0x%08X\n", + dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; goto failed1; @@ -241,7 +241,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { - printk(KERN_ERR "Could not allocate frame buffer memory\n"); + dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; goto failed2; } @@ -267,7 +267,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.pseudo_palette = drvdata->pseudo_palette; if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { - printk(KERN_ERR "Fail to allocate colormap (%d entries)\n", + dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; goto failed3; @@ -282,7 +282,7 @@ xilinxfb_drv_probe(struct device *dev) /* Register new frame buffer */ if (register_framebuffer(&drvdata->info) < 0) { - printk(KERN_ERR "Could not register frame buffer\n"); + dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; goto failed4; } -- cgit v1.2.3-70-g09d2 From 3fb99ce4e2748dafe3f10dba2932f0d13f577623 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: rename failout labels to reflect failure Labels and gotos are used in xilinxfb_assign to unwind allocations on device registration failures. Rename the labels to reflect the error which occured. This change is being made to make it easier to add new failout paths (which occurs in a subsuquent patch) and to make reviewing the failout path easier. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e63cbd1acfd2..9aa754a25218 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -225,14 +225,14 @@ xilinxfb_drv_probe(struct device *dev) if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; - goto failed1; + goto err_region; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; - goto failed1; + goto err_region; } drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); drvdata->regs_phys = regs_res->start; @@ -243,7 +243,7 @@ xilinxfb_drv_probe(struct device *dev) if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; - goto failed2; + goto err_fbmem; } /* Clear (turn to black) the framebuffer */ @@ -270,7 +270,7 @@ xilinxfb_drv_probe(struct device *dev) dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; - goto failed3; + goto err_cmap; } drvdata->info.flags = FBINFO_DEFAULT; @@ -284,7 +284,7 @@ xilinxfb_drv_probe(struct device *dev) if (register_framebuffer(&drvdata->info) < 0) { dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; - goto failed4; + goto err_regfb; } /* Put a banner in the log (for DEBUG) */ @@ -294,10 +294,10 @@ xilinxfb_drv_probe(struct device *dev) (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ -failed4: +err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); -failed3: +err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); @@ -305,10 +305,10 @@ failed3: xilinx_fb_out_be32(drvdata, REG_CTRL, 0); iounmap(drvdata->regs); -failed2: +err_fbmem: release_mem_region(regs_res->start, 8); -failed1: +err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); -- cgit v1.2.3-70-g09d2 From 264776224d3bb0cd80bc0ec11a769e05a58f8c6b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: Split device setup from bus binding Split the device setup code away from the platform bus binding. This is in preparation for adding the of_platform bus binding to this driver and most of the setup code is common between the two busses. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 133 ++++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 53 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 9aa754a25218..12d91279996d 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -196,23 +196,17 @@ static struct fb_ops xilinxfb_ops = .fb_imageblit = cfb_imageblit, }; -/* === The device driver === */ +/* --------------------------------------------------------------------- + * Bus independent setup/teardown + */ -static int -xilinxfb_drv_probe(struct device *dev) +static int xilinxfb_assign(struct device *dev, unsigned long physaddr, + int width_mm, int height_mm, int rotate) { - struct platform_device *pdev; - struct xilinxfb_platform_data *pdata; struct xilinxfb_drvdata *drvdata; - struct resource *regs_res; - int retval; - - if (!dev) - return -EINVAL; - - pdev = to_platform_device(dev); - pdata = pdev->dev.platform_data; + int rc; + /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "Couldn't allocate device private record\n"); @@ -221,40 +215,39 @@ xilinxfb_drv_probe(struct device *dev) dev_set_drvdata(dev, drvdata); /* Map the control registers in */ - regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - dev_err(dev, "Couldn't get registers resource\n"); - retval = -EFAULT; + if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; goto err_region; } - - if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08X\n", - regs_res->start); - retval = -EBUSY; - goto err_region; + drvdata->regs_phys = physaddr; + drvdata->regs = ioremap(physaddr, 8); + if (!drvdata->regs) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; + goto err_map; } - drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); - drvdata->regs_phys = regs_res->start; /* Allocate the framebuffer memory */ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); - retval = -ENOMEM; + rc = -ENOMEM; goto err_fbmem; } /* Clear (turn to black) the framebuffer */ - memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); + memset_io(drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (pdata && pdata->rotate_screen) + if (rotate) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -265,31 +258,29 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; drvdata->info.pseudo_palette = drvdata->pseudo_palette; + drvdata->info.flags = FBINFO_DEFAULT; + drvdata->info.var = xilinx_fb_var; + + xilinx_fb_var.height = height_mm; + xilinx_fb_var.width = width_mm; - if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { + /* Allocate a colour map */ + rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); - retval = -EFAULT; goto err_cmap; } - drvdata->info.flags = FBINFO_DEFAULT; - if (pdata) { - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; - } - drvdata->info.var = xilinx_fb_var; - /* Register new frame buffer */ - if (register_framebuffer(&drvdata->info) < 0) { + rc = register_framebuffer(&drvdata->info); + if (rc) { dev_err(dev, "Could not register frame buffer\n"); - retval = -EINVAL; goto err_regfb; } /* Put a banner in the log (for DEBUG) */ - dev_dbg(dev, "regs: phys=%x, virt=%p\n", - drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ @@ -300,30 +291,25 @@ err_regfb: err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); - /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); - iounmap(drvdata->regs); err_fbmem: - release_mem_region(regs_res->start, 8); + iounmap(drvdata->regs); + +err_map: + release_mem_region(physaddr, 8); err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); - return retval; + return rc; } -static int -xilinxfb_drv_remove(struct device *dev) +static int xilinxfb_release(struct device *dev) { - struct xilinxfb_drvdata *drvdata; - - if (!dev) - return -ENODEV; - - drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev); + struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); @@ -348,6 +334,47 @@ xilinxfb_drv_remove(struct device *dev) return 0; } +/* --------------------------------------------------------------------- + * Platform bus binding + */ + +static int +xilinxfb_drv_probe(struct device *dev) +{ + struct platform_device *pdev; + struct xilinxfb_platform_data *pdata; + struct resource *res; + int width_mm; + int height_mm; + int rotate; + + pdev = to_platform_device(dev); + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(dev, "Missing pdata structure\n"); + return -ENODEV; + } + + /* Find the registers address */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, "Couldn't get registers resource\n"); + return -ENODEV; + } + + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + + return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); +} + +static int +xilinxfb_drv_remove(struct device *dev) +{ + return xilinxfb_release(dev); +} + static struct device_driver xilinxfb_driver = { .name = DRIVER_NAME, -- cgit v1.2.3-70-g09d2 From 47473e31585032e5c048eeec50e0f9165890230a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: cleanup platform_bus binding to use platform bus API. Change the platform bus binding to make use of the established platform_bus API. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 12d91279996d..e482bb519635 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -339,26 +339,24 @@ static int xilinxfb_release(struct device *dev) */ static int -xilinxfb_drv_probe(struct device *dev) +xilinxfb_platform_probe(struct platform_device *pdev) { - struct platform_device *pdev; struct xilinxfb_platform_data *pdata; struct resource *res; int width_mm; int height_mm; int rotate; - pdev = to_platform_device(dev); pdata = pdev->dev.platform_data; if (!pdata) { - dev_err(dev, "Missing pdata structure\n"); + dev_err(&pdev->dev, "Missing pdata structure\n"); return -ENODEV; } /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) { - dev_err(dev, "Couldn't get registers resource\n"); + dev_err(&pdev->dev, "Couldn't get registers resource\n"); return -ENODEV; } @@ -366,22 +364,24 @@ xilinxfb_drv_probe(struct device *dev) width_mm = pdata->screen_width_mm; rotate = pdata->rotate_screen ? 1 : 0; - return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); + return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, + rotate); } static int -xilinxfb_drv_remove(struct device *dev) +xilinxfb_platform_remove(struct platform_device *pdev) { - return xilinxfb_release(dev); + return xilinxfb_release(&pdev->dev); } -static struct device_driver xilinxfb_driver = { - .name = DRIVER_NAME, - .bus = &platform_bus_type, - - .probe = xilinxfb_drv_probe, - .remove = xilinxfb_drv_remove +static struct platform_driver xilinxfb_platform_driver = { + .probe = xilinxfb_platform_probe, + .remove = xilinxfb_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, }; static int __init @@ -391,13 +391,13 @@ xilinxfb_init(void) * No kernel boot options used, * so we just need to register the driver */ - return driver_register(&xilinxfb_driver); + return platform_driver_register(&xilinxfb_platform_driver); } static void __exit xilinxfb_cleanup(void) { - driver_unregister(&xilinxfb_driver); + platform_driver_unregister(&xilinxfb_platform_driver); } module_init(xilinxfb_init); -- cgit v1.2.3-70-g09d2 From 31e8d4603ecaeb02424c9669e252ab835354a36e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: add of_platform bus binding Adds the of_platform bus binding to the xilinxfb driver. Needed to use framebuffer devices described in the OF device tree (used by arch/powerpc). Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 107 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 9 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e482bb519635..dbb23a9fef7b 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -6,9 +6,12 @@ * Author: MontaVista Software, Inc. * source@mvista.com * - * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is licensed - * "as is" without any warranty of any kind, whether express or implied. + * 2002-2007 (c) MontaVista Software, Inc. + * 2007 (c) Secret Lab Technologies, Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. */ /* @@ -29,7 +32,10 @@ #include #include #include - +#if defined(CONFIG_OF) +#include +#include +#endif #include #include @@ -384,20 +390,103 @@ static struct platform_driver xilinxfb_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF bus binding + */ + +#if defined(CONFIG_OF) +static int __devinit +xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + const u32 *prop; + int width = 0, height = 0, rotate = 0; + int size, rc; + + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); + + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + + prop = of_get_property(op->node, "display-number", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + width = prop[0]; + height = prop[1]; + } + + if (of_find_property(op->node, "rotate-display", NULL)) + rotate = 1; + + return xilinxfb_assign(&op->dev, res.start, width, height, rotate); +} + +static int __devexit xilinxfb_of_remove(struct of_device *op) +{ + return xilinxfb_release(&op->dev); +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit xilinxfb_of_match[] = { + { .compatible = "xilinx,ml300-fb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xilinxfb_of_match); + +static struct of_platform_driver xilinxfb_of_driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .match_table = xilinxfb_of_match, + .probe = xilinxfb_of_probe, + .remove = __devexit_p(xilinxfb_of_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init xilinxfb_of_register(void) +{ + pr_debug("xilinxfb: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&xilinxfb_of_driver); +} + +static inline void __exit xilinxfb_of_unregister(void) +{ + of_unregister_platform_driver(&xilinxfb_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init xilinxfb_of_register(void) { return 0; } +static inline void __exit xilinxfb_of_unregister(void) { } +#endif /* CONFIG_OF */ + +/* --------------------------------------------------------------------- + * Module setup and teardown + */ + static int __init xilinxfb_init(void) { - /* - * No kernel boot options used, - * so we just need to register the driver - */ - return platform_driver_register(&xilinxfb_platform_driver); + int rc; + rc = xilinxfb_of_register(); + if (rc) + return rc; + + rc = platform_driver_register(&xilinxfb_platform_driver); + if (rc) + xilinxfb_of_unregister(); + + return rc; } static void __exit xilinxfb_cleanup(void) { platform_driver_unregister(&xilinxfb_platform_driver); + xilinxfb_of_unregister(); } module_init(xilinxfb_init); -- cgit v1.2.3-70-g09d2 From e3cec00366e9d60ff65c6f6f8fffdfcadea01056 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 15:44:52 -0600 Subject: [POWERPC] XilinxFB: Make missing pdata structure non-fatal Missing pdata structure is not a fatal error. The device can still be initialized without it. Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dbb23a9fef7b..e6e12be845a9 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -349,15 +349,9 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm; - int height_mm; - int rotate; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata structure\n"); - return -ENODEV; - } + int width_mm = 0; + int height_mm = 0; + int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -366,9 +360,13 @@ xilinxfb_platform_probe(struct platform_device *pdev) return -ENODEV; } - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; + /* If a pdata structure is provided, then extract the parameters */ + pdata = pdev->dev.platform_data; + if (pdata) { + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + } return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, rotate); -- cgit v1.2.3-70-g09d2 From b9a22794f2c186b5722eac94b6735e797d976027 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: sparse fixes Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e6e12be845a9..dec602c23075 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -118,7 +118,7 @@ struct xilinxfb_drvdata { u32 regs_phys; /* phys. address of the control registers */ u32 __iomem *regs; /* virt. address of the control registers */ - unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ + void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ u32 reg_ctrl_default; @@ -246,7 +246,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io(drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -259,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Fill struct fb_info */ drvdata->info.device = dev; - drvdata->info.screen_base = drvdata->fb_virt; + drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; -- cgit v1.2.3-70-g09d2 From 01ba1e9d26fcd29f3ad4f3a5bcf40c0fbc40ee81 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:46 +1000 Subject: [POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters The call to xilinxfb_assign is getting unwieldy when adding features to the Xilinx framebuffer driver. Change xilinxfb_assign() to accept a pointer to a xilinxfb_platform_data structure to prepare for adding additition configuration options. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dec602c23075..b3b57f4a35a2 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -83,6 +83,12 @@ #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ +/* + * Default xilinxfb configuration + */ +static struct xilinxfb_platform_data xilinx_fb_default_pdata = { +}; + /* * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures */ @@ -207,7 +213,7 @@ static struct fb_ops xilinxfb_ops = */ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, - int width_mm, int height_mm, int rotate) + struct xilinxfb_platform_data *pdata) { struct xilinxfb_drvdata *drvdata; int rc; @@ -253,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (rotate) + if (pdata->rotate_screen) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -267,8 +273,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - xilinx_fb_var.height = height_mm; - xilinx_fb_var.width = width_mm; + xilinx_fb_var.height = pdata->screen_height_mm; + xilinx_fb_var.width = pdata->screen_width_mm; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -349,9 +355,6 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm = 0; - int height_mm = 0; - int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -361,15 +364,12 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - pdata = pdev->dev.platform_data; - if (pdata) { - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; - } + if (pdev->dev.platform_data) + pdata = pdev->dev.platform_data; + else + pdata = &xilinx_fb_default_pdata; - return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, - rotate); + return xilinxfb_assign(&pdev->dev, res->start, pdata); } static int @@ -398,9 +398,12 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) { struct resource res; const u32 *prop; - int width = 0, height = 0, rotate = 0; + struct xilinxfb_platform_data pdata; int size, rc; + /* Copy with the default pdata (not a ptr reference!) */ + pdata = xilinx_fb_default_pdata; + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); rc = of_address_to_resource(op->node, 0, &res); @@ -411,14 +414,14 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) prop = of_get_property(op->node, "display-number", &size); if ((prop) && (size >= sizeof(u32)*2)) { - width = prop[0]; - height = prop[1]; + pdata.screen_width_mm = prop[0]; + pdata.screen_height_mm = prop[1]; } if (of_find_property(op->node, "rotate-display", NULL)) - rotate = 1; + pdata.rotate_screen = 1; - return xilinxfb_assign(&op->dev, res.start, width, height, rotate); + return xilinxfb_assign(&op->dev, res.start, &pdata); } static int __devexit xilinxfb_of_remove(struct of_device *op) -- cgit v1.2.3-70-g09d2 From b4d6a7268fc754eefb196cabc0ccfa2e97022af2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:51 +1000 Subject: [POWERPC] XilinxFB: Add support for custom screen resolution Some custom implementations of the xilinx fb can use resolutions other than 640x480. This patch allows the resolution to be specified in the device tree or the xilinx_platform_data structure. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 71 ++++++++++++++++++++++++++++++------------------ include/linux/xilinxfb.h | 6 ++-- 2 files changed, 49 insertions(+), 28 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index b3b57f4a35a2..c6174125f52b 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -70,12 +70,6 @@ */ #define BYTES_PER_PIXEL 4 #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) -#define XRES 640 -#define YRES 480 -#define XRES_VIRTUAL 1024 -#define YRES_VIRTUAL YRES -#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL) -#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH) #define RED_SHIFT 16 #define GREEN_SHIFT 8 @@ -87,6 +81,10 @@ * Default xilinxfb configuration */ static struct xilinxfb_platform_data xilinx_fb_default_pdata = { + .xres = 640, + .yres = 480, + .xvirt = 1024, + .yvirt = 480; }; /* @@ -96,17 +94,10 @@ static struct fb_fix_screeninfo xilinx_fb_fix = { .id = "Xilinx", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, - .smem_len = FB_SIZE, - .line_length = LINE_LENGTH, .accel = FB_ACCEL_NONE }; static struct fb_var_screeninfo xilinx_fb_var = { - .xres = XRES, - .yres = YRES, - .xres_virtual = XRES_VIRTUAL, - .yres_virtual = YRES_VIRTUAL, - .bits_per_pixel = BITS_PER_PIXEL, .red = { RED_SHIFT, 8, 0 }, @@ -217,6 +208,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, { struct xilinxfb_drvdata *drvdata; int rc; + int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); @@ -243,7 +235,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); @@ -252,7 +244,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -269,12 +261,18 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; + drvdata->info.fix.smem_len = fbsize; + drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL; + drvdata->info.pseudo_palette = drvdata->pseudo_palette; drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; + drvdata->info.var.height = pdata->screen_height_mm; + drvdata->info.var.width = pdata->screen_width_mm; + drvdata->info.var.xres = pdata->xres; + drvdata->info.var.yres = pdata->yres; + drvdata->info.var.xres_virtual = pdata->xvirt; + drvdata->info.var.yres_virtual = pdata->yvirt; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -294,14 +292,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Put a banner in the log (for DEBUG) */ dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", - (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); + (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize); + return 0; /* success */ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -331,8 +330,8 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, - drvdata->fb_phys); + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -364,10 +363,18 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - if (pdev->dev.platform_data) + pdata = &xilinx_fb_default_pdata; + if (pdev->dev.platform_data) { pdata = pdev->dev.platform_data; - else - pdata = &xilinx_fb_default_pdata; + if (!pdata->xres) + pdata->xres = xilinx_fb_default_pdata.xres; + if (!pdata->yres) + pdata->yres = xilinx_fb_default_pdata.yres; + if (!pdata->xvirt) + pdata->xvirt = xilinx_fb_default_pdata.xvirt; + if (!pdata->yvirt) + pdata->yvirt = xilinx_fb_default_pdata.yvirt; + } return xilinxfb_assign(&pdev->dev, res->start, pdata); } @@ -412,12 +419,24 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) return rc; } - prop = of_get_property(op->node, "display-number", &size); + prop = of_get_property(op->node, "phys-size", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.screen_width_mm = prop[0]; pdata.screen_height_mm = prop[1]; } + prop = of_get_property(op->node, "resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xres = prop[0]; + pdata.yres = prop[1]; + } + + prop = of_get_property(op->node, "virtual-resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xvirt = prop[0]; + pdata.yvirt = prop[1]; + } + if (of_find_property(op->node, "rotate-display", NULL)) pdata.rotate_screen = 1; diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 9ad984d22c38..199a1eedf223 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -15,9 +15,11 @@ /* ML300/403 reference design framebuffer driver platform data struct */ struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; + u32 rotate_screen; /* Flag to rotate display 180 degrees */ + u32 screen_height_mm; /* Physical dimentions of screen in mm */ u32 screen_width_mm; + u32 xres, yres; /* resolution of screen in pixels */ + u32 xvirt, yvirt; /* resolution of memory buffer */ }; #endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2 From 287e5d6fcccfa38b953cebe307e1ddfd32363355 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:56 +1000 Subject: [POWERPC] XilinxFB: Allow fixed framebuffer base address Allow a fixed framebuffer address to be assigned to the framebuffer device instead of allocating the framebuffer from the consistent memory pool. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 22 ++++++++++++++++------ include/linux/xilinxfb.h | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index c6174125f52b..6ef99b2d13ca 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -117,6 +117,7 @@ struct xilinxfb_drvdata { void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ + int fb_alloced; /* Flag, was the fb memory alloced? */ u32 reg_ctrl_default; @@ -235,8 +236,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), - &drvdata->fb_phys, GFP_KERNEL); + if (pdata->fb_phys) { + drvdata->fb_phys = pdata->fb_phys; + drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize); + } else { + drvdata->fb_alloced = 1; + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), + &drvdata->fb_phys, GFP_KERNEL); + } + if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); rc = -ENOMEM; @@ -300,8 +308,9 @@ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, - drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, + drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -330,8 +339,9 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), - drvdata->fb_virt, drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 199a1eedf223..f2463f559fb9 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -20,6 +20,11 @@ struct xilinxfb_platform_data { u32 screen_width_mm; u32 xres, yres; /* resolution of screen in pixels */ u32 xvirt, yvirt; /* resolution of memory buffer */ + + /* Physical address of framebuffer memory; If non-zero, driver + * will use provided memory address instead of allocating one from + * the consistent pool. */ + u32 fb_phys; }; #endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2