* Re: [PATCH] video: Add GRVGA framebuffer device driver
From: Konrad Rzeszutek Wilk @ 2011-06-15 14:56 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308128180-14645-1-git-send-email-kristoffer@gaisler.com>
On Wed, Jun 15, 2011 at 10:56:20AM +0200, Kristoffer Glembo wrote:
> This patch adds support for the GRVGA framebuffer IP core from Aeroflex Gaisler.
> The device is used in LEON SPARCV8 based System on Chips. Documentation can
> be found here: www.gaisler.com/products/grlib/grip.pdf.
See comments below.
>
> Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
> ---
> drivers/video/Kconfig | 10 +
> drivers/video/Makefile | 1 +
> drivers/video/grvga.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 570 insertions(+), 0 deletions(-)
> create mode 100644 drivers/video/grvga.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 549b960..18ee201 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -259,6 +259,16 @@ config FB_TILEBLITTING
> comment "Frame buffer hardware drivers"
> depends on FB
>
> +config FB_GRVGA
> + tristate "Aeroflex Gaisler framebuffer support"
> + depends on FB && SPARC
> + select FB_CFB_FILLRECT
> + select FB_CFB_COPYAREA
> + select FB_CFB_IMAGEBLIT
> + ---help---
> + This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
> +
> +
> config FB_CIRRUS
> tristate "Cirrus Logic support"
> depends on FB && (ZORRO || PCI)
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 8b83129..4cff5ec 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
> obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
>
> # Hardware specific drivers go first
> +obj-$(CONFIG_FB_GRVGA) += grvga.o
> obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
> obj-$(CONFIG_FB_ARC) += arcfb.o
> obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
> diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
> new file mode 100644
> index 0000000..e1514f9
> --- /dev/null
> +++ b/drivers/video/grvga.c
> @@ -0,0 +1,559 @@
> +/*
> + * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
> + *
> + * 2011 (c) Aeroflex Gaisler AB
> + *
> + * Full documentation of the core can be found here:
> + * http://www.gaisler.com/products/grlib/grip.pdf
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
> + *
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_device.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/mm.h>
> +#include <linux/fb.h>
> +#include <linux/io.h>
> +
> +#define GRVGA_REGLOAD(a) (__raw_readl(&(a)))
> +#define GRVGA_REGSAVE(a, v) (__raw_writel(v, &(a)))
writel?
> +#define GRVGA_REGORIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) | (v))))
> +#define GRVGA_REGANDIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) & (v))))
> +
> +#define GRVGA_FBINFO_DEFAULT (FBINFO_DEFAULT \
> + | FBINFO_PARTIAL_PAN_OK \
> + | FBINFO_HWACCEL_YPAN)
> +
> +struct grvga_regs {
> + u32 status; /* 0x00 */
> + u32 video_length; /* 0x04 */
> + u32 front_porch; /* 0x08 */
> + u32 sync_length; /* 0x0C */
> + u32 line_length; /* 0x10 */
> + u32 fb_pos; /* 0x14 */
> + u32 clk_vector[4]; /* 0x18 */
> + u32 clut; /* 0x20 */
> +};
Would it make sense to add __packed__ here? It seems that you
really depend on this ordering.
> +
> +struct grvga_par {
> + struct grvga_regs *regs;
> + u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
> + int clk_sel;
> +};
> +
> +
> +static const struct fb_videomode grvga_modedb[] = {
> + {
> + /* 640x480 @ 60 Hz */
> + NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
> + 0, FB_VMODE_NONINTERLACED
> + }, {
> + /* 800x600 @ 60 Hz */
> + NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
> + 0, FB_VMODE_NONINTERLACED
> + }, {
> + /* 800x600 @ 72 Hz */
> + NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
> + 0, FB_VMODE_NONINTERLACED
> + }, {
> + /* 1024x768 @ 60 Hz */
> + NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
> + 0, FB_VMODE_NONINTERLACED
> + }
> + };
> +
> +static struct fb_fix_screeninfo grvga_fix __initdata = {
> + .id = "AG SVGACTRL",
> + .type = FB_TYPE_PACKED_PIXELS,
> + .visual = FB_VISUAL_PSEUDOCOLOR,
> + .xpanstep = 0,
> + .ypanstep = 1,
> + .ywrapstep = 0,
> + .accel = FB_ACCEL_NONE,
> +};
> +
> +
> +static int grvga_check_var(struct fb_var_screeninfo *var,
> + struct fb_info *info);
> +static int grvga_set_par(struct fb_info *info);
> +static int grvga_setcolreg(unsigned regno,
> + unsigned red, unsigned green, unsigned blue, unsigned transp,
> + struct fb_info *info);
> +static int grvga_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
> +
> +static struct fb_ops grvga_ops = {
> + .owner = THIS_MODULE,
> + .fb_check_var = grvga_check_var,
> + .fb_set_par = grvga_set_par,
> + .fb_setcolreg = grvga_setcolreg,
> + .fb_pan_display = grvga_pan_display,
> + .fb_fillrect = cfb_fillrect,
> + .fb_copyarea = cfb_copyarea,
> + .fb_imageblit = cfb_imageblit
> +};
Could you move this struct down and remove the declarations earlier?
> +
> +static int grvga_check_var(struct fb_var_screeninfo *var,
> + struct fb_info *info)
> +{
> + struct grvga_par *par = info->par;
> + int i;
> +
> + if (!var->xres)
> + var->xres = 1;
> + if (!var->yres)
> + var->yres = 1;
> + if (var->bits_per_pixel <= 8)
> + var->bits_per_pixel = 8;
> + else if (var->bits_per_pixel <= 16)
> + var->bits_per_pixel = 16;
> + else if (var->bits_per_pixel <= 24)
> + var->bits_per_pixel = 24;
> + else if (var->bits_per_pixel <= 32)
> + var->bits_per_pixel = 32;
> + else
> + return -EINVAL;
> +
> + var->xres_virtual = var->xres;
> + var->yres_virtual = 2*var->yres;
> +
> + if (info->fix.smem_len) {
> + if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
> + return -ENOMEM;
> + }
> +
> + /* Which clocks that are available can be read out in these registers */
> + for (i = 0; i <= 3 ; i++) {
> + if (var->pixclock = par->regs->clk_vector[i])
> + break;
> + }
> + if (i != -1)
> + par->clk_sel = i;
How would i possibly become -1?
> + else
> + return -EINVAL;
> +
> + switch (info->var.bits_per_pixel) {
> + case 8:
> + var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
> + var->green = (struct fb_bitfield) {0, 8, 0};
> + var->blue = (struct fb_bitfield) {0, 8, 0};
> + var->transp = (struct fb_bitfield) {0, 0, 0};
> + break;
> + case 16:
> + var->red = (struct fb_bitfield) {11, 5, 0};
> + var->green = (struct fb_bitfield) {5, 6, 0};
> + var->blue = (struct fb_bitfield) {0, 5, 0};
> + var->transp = (struct fb_bitfield) {0, 0, 0};
> + break;
> + case 24:
> + case 32:
> + var->red = (struct fb_bitfield) {16, 8, 0};
> + var->green = (struct fb_bitfield) {8, 8, 0};
> + var->blue = (struct fb_bitfield) {0, 8, 0};
> + var->transp = (struct fb_bitfield) {24, 8, 0};
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int grvga_set_par(struct fb_info *info)
> +{
> +
> + int func = 0;
You probably want that to be u32.
> + struct grvga_par *par = info->par;
> +
> + GRVGA_REGSAVE(par->regs->video_length,
> + ((info->var.yres - 1) << 16) | (info->var.xres - 1));
> + GRVGA_REGSAVE(par->regs->front_porch,
> + (info->var.lower_margin << 16) | (info->var.right_margin));
> + GRVGA_REGSAVE(par->regs->sync_length,
> + (info->var.vsync_len << 16) | (info->var.hsync_len));
> + GRVGA_REGSAVE(par->regs->line_length,
> + ((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
> + (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1));
> +
> + switch (info->var.bits_per_pixel) {
> + case 8:
> + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
> + func = 1;
> + break;
> + case 16:
> + info->fix.visual = FB_VISUAL_TRUECOLOR;
> + func = 2;
> + break;
> + case 24:
> + case 32:
> + info->fix.visual = FB_VISUAL_TRUECOLOR;
> + func = 3;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + GRVGA_REGSAVE(par->regs->status, ((par->clk_sel << 6) | (func << 4)) | 1);
Just in case in the future you modify the code and bitshift func more than you thought
and end up with a signed value in an unsigned register.
> +
> + info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
> + return 0;
> +}
> +
> +static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
> +{
> + struct grvga_par *par;
> + par = info->par;
> +
> + if (regno >= 256) /* Size of CLUT */
> + return -EINVAL;
> +
> + if (info->var.grayscale) {
> + /* grayscale = 0.30*R + 0.59*G + 0.11*B */
> + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
> + }
> +
> +
> +
> +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
> +
> + red = CNVT_TOHW(red, info->var.red.length);
> + green = CNVT_TOHW(green, info->var.green.length);
> + blue = CNVT_TOHW(blue, info->var.blue.length);
> + transp = CNVT_TOHW(transp, info->var.transp.length);
> +
> +#undef CNVT_TOHW
> +
> + /* In PSEUDOCOLOR we use the hardware CLUT */
> + if (info->fix.visual = FB_VISUAL_PSEUDOCOLOR)
> + GRVGA_REGSAVE(par->regs->clut,
> + (regno << 24) | (red << 16) | (green << 8) | blue);
> +
> + /* Truecolor uses the pseudo palette */
> + else if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
> + u32 v;
> + if (regno >= 16)
> + return -EINVAL;
> +
> +
> + v = (red << info->var.red.offset) |
> + (green << info->var.green.offset) |
> + (blue << info->var.blue.offset) |
> + (transp << info->var.transp.offset);
> +
> + ((u32 *) (info->pseudo_palette))[regno] = v;
> + }
> + return 0;
> +}
> +
> +static int grvga_pan_display(struct fb_var_screeninfo *var,
> + struct fb_info *info)
> +{
> + struct grvga_par *par = info->par;
> + struct fb_fix_screeninfo *fix = &info->fix;
> + u32 base_addr;
> +
> + if (var->xoffset != 0)
> + return -EINVAL;
> +
> + base_addr = fix->smem_start + (var->yoffset * fix->line_length);
> + base_addr &= ~3UL;
> +
> + /* Set framebuffer base address */
> + GRVGA_REGSAVE(par->regs->fb_pos, base_addr);
> +
> + return 0;
> +}
> +
> +static int __init grvga_parse_custom(char *options,
> + struct fb_var_screeninfo *screendata)
> +{
> + char *this_opt;
> + int count = 0;
> + if (!options || !*options)
> + return -1;
> +
> + while ((this_opt = strsep(&options, " ")) != NULL) {
> + if (!*this_opt)
> + continue;
> +
> + switch (count) {
> + case 0:
> + screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 1:
> + screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 2:
> + screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 3:
> + screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 4:
> + screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 5:
> + screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 6:
> + screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 7:
> + screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 8:
> + screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
> + case 9:
> + screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
> + count++;
> + break;
No default case?
> + }
> + }
> + screendata->activate = FB_ACTIVATE_NOW;
> + screendata->vmode = FB_VMODE_NONINTERLACED;
> + return 0;
> +}
> +
> +static int __devinit grvga_probe(struct platform_device *dev)
> +{
> + struct fb_info *info;
> + int retval = -ENOMEM;
> + unsigned long virtual_start;
> + unsigned long grvga_fix_addr = 0;
> + unsigned long physical_start = 0;
> + unsigned long grvga_mem_size = 0;
> + struct grvga_par *par;
> + char *options = NULL, *mode_opt = NULL;
> +
> + info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
> + if (!info) {
> + dev_err(&dev->dev, "framebuffer_alloc failed\n");
> + return -ENOMEM;
> + }
> +
> + /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
> + *
> + * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
> + * If address is left out, we allocate memory,
> + * if size is left out we only allocate enough to support the given mode.
> + */
> + if (fb_get_options("grvga", &options)) {
> + retval = -ENODEV;
> + goto err;
> + }
> +
> + if (!options || !*options)
> + options = "640x480-8@60";
> +
> + while (1) {
> + char *this_opt = strsep(&options, ",");
> +
> + if (!this_opt)
> + break;
> +
> + if (!strncmp(this_opt, "custom", 6))
> + grvga_parse_custom(this_opt, &info->var);
> + else if (!strncmp(this_opt, "addr:", 5))
> + grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
> + else if (!strncmp(this_opt, "size:", 5))
> + grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
> + else
> + mode_opt = this_opt;
> + }
> +
> + par = info->par;
> + info->fbops = &grvga_ops;
> + info->fix = grvga_fix;
> + info->pseudo_palette = par->color_palette;
> + info->flags = GRVGA_FBINFO_DEFAULT;
> + info->fix.smem_len = grvga_mem_size;
> +
> + par->regs = of_ioremap(&dev->resource[0], 0,
> + resource_size(&dev->resource[0]),
> + "grlib-svgactrl regs");
> +
> + retval = fb_alloc_cmap(&info->cmap, 256, 0);
> + if (retval < 0) {
> + dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
> + retval = -ENOMEM;
> + goto err1;
> + }
> +
> + if (mode_opt) {
> + retval = fb_find_mode(&info->var, info, mode_opt,
> + grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
> + if (!retval || retval = 4) {
> + retval = -EINVAL;
> + goto err2;
> + }
> + }
> +
> + if (!grvga_mem_size)
> + grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
Should you update the info->fix.smem_len ?
> +
> + if (grvga_fix_addr) {
> + /* Got framebuffer base address from argument list */
> +
> + physical_start = grvga_fix_addr;
> +
> + if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
> + dev_err(&dev->dev, "request mem region failed\n");
requested..
> + retval = -ENOMEM;
> + goto err2;
> + }
> +
> + virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
> +
> + if (!virtual_start) {
> + dev_err(&dev->dev, "error mapping memory\n");
> + retval = -ENOMEM;
> + goto err3;
> + }
> + } else { /* Allocate frambuffer memory */
> +
> + unsigned long page;
> +
> + virtual_start = (unsigned long) __get_free_pages(GFP_ATOMIC | GFP_DMA,
> + get_order(grvga_mem_size));
> + if (!virtual_start) {
> + dev_err(&dev->dev,
> + "unable to allocate framebuffer memory (%lu bytes)\n",
> + grvga_mem_size);
> + retval = -ENOMEM;
> + goto err2;
> + }
> +
> +
> + physical_start = __pa(virtual_start);
Yikes. That is one big assumption. You don't want to use the PCI/DMA API
to map it? I thought that on SPARCs the Bus addresses are different
from the physical addresses?
> +
> + /* Set page reserved so that mmap will work. This is necessary
> + * since we'll be remapping normal memory.
> + */
> + for (page = virtual_start;
> + page < PAGE_ALIGN(virtual_start + grvga_mem_size);
> + page += PAGE_SIZE) {
> + SetPageReserved(virt_to_page(page));
> + }
> + }
> +
> + memset((unsigned long *) virtual_start, 0, grvga_mem_size);
> +
> + info->screen_base = (char __iomem *) virtual_start;
> + info->fix.smem_start = physical_start;
> + info->fix.smem_len = grvga_mem_size;
Ah, you update it here. OK.
> +
> + dev_set_drvdata(&dev->dev, info);
> +
> + dev_info(&dev->dev,
> + "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ 0x%x\n",
> + info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
> + grvga_mem_size >> 10, (unsigned int) info->screen_base);
> +
> + retval = register_framebuffer(info);
> + if (retval < 0) {
> + dev_err(&dev->dev, "failed to register framebuffer\n");
> + if (grvga_fix_addr)
> + goto err3;
> + else {
> + kfree((void *)virtual_start);
> + goto err2;
> + }
> + }
> +
> + GRVGA_REGSAVE(par->regs->fb_pos, physical_start);
> + GRVGA_REGORIN(par->regs->status, 1); /* Enable framebuffer */
> +
> + return 0;
> +
> +err3:
> + release_mem_region(physical_start, grvga_mem_size);
> +err2:
> + fb_dealloc_cmap(&info->cmap);
> +err1:
> + of_iounmap(&dev->resource[0], par->regs,
> + resource_size(&dev->resource[0]));
> +err:
> + framebuffer_release(info);
> +
> + return retval;
> +}
> +
> +static int __devexit grvga_remove(struct platform_device *device)
> +{
> + struct fb_info *info = dev_get_drvdata(&device->dev);
> + struct grvga_par *par = info->par;
> +
> + if (info) {
> + unregister_framebuffer(info);
> + fb_dealloc_cmap(&info->cmap);
> + of_iounmap(&device->resource[0], par->regs,
> + resource_size(&device->resource[0]));
> + framebuffer_release(info);
> + dev_set_drvdata(&device->dev, NULL);
Shouldn't that be much earlier? Like right after unregister_framebuffer?
> + }
> +
> + return 0;
> +}
> +
> +static struct of_device_id svgactrl_of_match[] = {
> + {
> + .name = "GAISLER_SVGACTRL",
> + },
> + {
> + .name = "01_063",
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, svgactrl_of_match);
> +
> +static struct platform_driver grvga_driver = {
> + .driver = {
> + .name = "grlib-svgactrl",
> + .owner = THIS_MODULE,
> + .of_match_table = svgactrl_of_match,
> + },
> + .probe = grvga_probe,
> + .remove = __devexit_p(grvga_remove),
> +};
> +
> +
> +int __init grvga_init(void)
> +{
> + return platform_driver_register(&grvga_driver);
> +}
> +
> +static void __exit grvga_exit(void)
> +{
> + platform_driver_unregister(&grvga_driver);
> +}
> +
> +module_init(grvga_init);
> +module_exit(grvga_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Aeroflex Gaisler");
> +MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");
> --
> 1.6.4.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] video: Add GRVGA framebuffer device driver
From: Geert Uytterhoeven @ 2011-06-15 12:09 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308128180-14645-1-git-send-email-kristoffer@gaisler.com>
On Wed, Jun 15, 2011 at 13:52, Kristoffer Glembo <kristoffer@gaisler.com> wrote:
> Geert Uytterhoeven wrote:
>> At first sight, nothing in this driver seems to be SPARC-specific, so
>> perhaps this can be relaxed
>> to e.g. depends on OF_DEVICE?
>
> It uses of_ioremap/unmap which are SPARC-specific. I have been bitten by things like this before
> when thinking I was portable so this time I just depended on SPARC. The core is not used on any
> other platforms and is not very likely to be used either.
Ah, your're right. I just thought all OF-capable platforms had of_ioremap().
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH V2] video: Add GRVGA framebuffer device driver
From: Kristoffer Glembo @ 2011-06-15 12:04 UTC (permalink / raw)
To: linux-fbdev
This patch adds support for the GRVGA framebuffer IP core from Aeroflex Gaisler.
The device is used in LEON SPARCV8 based System on Chips. Documentation can
be found here: www.gaisler.com/products/grlib/grip.pdf.
Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
---
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/grvga.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 570 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/grvga.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 549b960..18ee201 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -259,6 +259,16 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers"
depends on FB
+config FB_GRVGA
+ tristate "Aeroflex Gaisler framebuffer support"
+ depends on FB && SPARC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
+
+
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8b83129..4cff5ec 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
# Hardware specific drivers go first
+obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
new file mode 100644
index 0000000..aa1f9ab
--- /dev/null
+++ b/drivers/video/grvga.c
@@ -0,0 +1,559 @@
+/*
+ * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
+ *
+ * 2011 (c) Aeroflex Gaisler AB
+ *
+ * Full documentation of the core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+#define GRVGA_REGLOAD(a) (__raw_readl(&(a)))
+#define GRVGA_REGSAVE(a, v) (__raw_writel(v, &(a)))
+#define GRVGA_REGORIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) | (v))))
+#define GRVGA_REGANDIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) & (v))))
+
+#define GRVGA_FBINFO_DEFAULT (FBINFO_DEFAULT \
+ | FBINFO_PARTIAL_PAN_OK \
+ | FBINFO_HWACCEL_YPAN)
+
+struct grvga_regs {
+ u32 status; /* 0x00 */
+ u32 video_length; /* 0x04 */
+ u32 front_porch; /* 0x08 */
+ u32 sync_length; /* 0x0C */
+ u32 line_length; /* 0x10 */
+ u32 fb_pos; /* 0x14 */
+ u32 clk_vector[4]; /* 0x18 */
+ u32 clut; /* 0x20 */
+};
+
+struct grvga_par {
+ struct grvga_regs *regs;
+ u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
+ int clk_sel;
+};
+
+
+static const struct fb_videomode grvga_modedb[] = {
+ {
+ /* 640x480 @ 60 Hz */
+ NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 60 Hz */
+ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 72 Hz */
+ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1024x768 @ 60 Hz */
+ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ };
+
+static struct fb_fix_screeninfo grvga_fix __initdata = {
+ .id = "AG SVGACTRL",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 0,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int grvga_set_par(struct fb_info *info);
+static int grvga_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue, unsigned transp,
+ struct fb_info *info);
+static int grvga_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+
+static struct fb_ops grvga_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = grvga_check_var,
+ .fb_set_par = grvga_set_par,
+ .fb_setcolreg = grvga_setcolreg,
+ .fb_pan_display = grvga_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit
+};
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ int i;
+
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel <= 24)
+ var->bits_per_pixel = 24;
+ else if (var->bits_per_pixel <= 32)
+ var->bits_per_pixel = 32;
+ else
+ return -EINVAL;
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = 2*var->yres;
+
+ if (info->fix.smem_len) {
+ if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
+ return -ENOMEM;
+ }
+
+ /* Which clocks that are available can be read out in these registers */
+ for (i = 0; i <= 3 ; i++) {
+ if (var->pixclock = par->regs->clk_vector[i])
+ break;
+ }
+ if (i != -1)
+ par->clk_sel = i;
+ else
+ return -EINVAL;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
+ var->green = (struct fb_bitfield) {0, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 16:
+ var->red = (struct fb_bitfield) {11, 5, 0};
+ var->green = (struct fb_bitfield) {5, 6, 0};
+ var->blue = (struct fb_bitfield) {0, 5, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 24:
+ case 32:
+ var->red = (struct fb_bitfield) {16, 8, 0};
+ var->green = (struct fb_bitfield) {8, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {24, 8, 0};
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int grvga_set_par(struct fb_info *info)
+{
+
+ int func = 0;
+ struct grvga_par *par = info->par;
+
+ GRVGA_REGSAVE(par->regs->video_length,
+ ((info->var.yres - 1) << 16) | (info->var.xres - 1));
+ GRVGA_REGSAVE(par->regs->front_porch,
+ (info->var.lower_margin << 16) | (info->var.right_margin));
+ GRVGA_REGSAVE(par->regs->sync_length,
+ (info->var.vsync_len << 16) | (info->var.hsync_len));
+ GRVGA_REGSAVE(par->regs->line_length,
+ ((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
+ (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1));
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ func = 1;
+ break;
+ case 16:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 2;
+ break;
+ case 24:
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ GRVGA_REGSAVE(par->regs->status, ((par->clk_sel << 6) | (func << 4)) | 1);
+
+ info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
+ return 0;
+}
+
+static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct grvga_par *par;
+ par = info->par;
+
+ if (regno >= 256) /* Size of CLUT */
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+#undef CNVT_TOHW
+
+ /* In PSEUDOCOLOR we use the hardware CLUT */
+ if (info->fix.visual = FB_VISUAL_PSEUDOCOLOR)
+ GRVGA_REGSAVE(par->regs->clut,
+ (regno << 24) | (red << 16) | (green << 8) | blue);
+
+ /* Truecolor uses the pseudo palette */
+ else if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
+ u32 v;
+ if (regno >= 16)
+ return -EINVAL;
+
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ }
+ return 0;
+}
+
+static int grvga_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ u32 base_addr;
+
+ if (var->xoffset != 0)
+ return -EINVAL;
+
+ base_addr = fix->smem_start + (var->yoffset * fix->line_length);
+ base_addr &= ~3UL;
+
+ /* Set framebuffer base address */
+ GRVGA_REGSAVE(par->regs->fb_pos, base_addr);
+
+ return 0;
+}
+
+static int __init grvga_parse_custom(char *options,
+ struct fb_var_screeninfo *screendata)
+{
+ char *this_opt;
+ int count = 0;
+ if (!options || !*options)
+ return -1;
+
+ while ((this_opt = strsep(&options, " ")) != NULL) {
+ if (!*this_opt)
+ continue;
+
+ switch (count) {
+ case 0:
+ screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 1:
+ screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 2:
+ screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 3:
+ screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 4:
+ screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 5:
+ screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 6:
+ screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 7:
+ screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 8:
+ screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 9:
+ screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ }
+ }
+ screendata->activate = FB_ACTIVATE_NOW;
+ screendata->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+}
+
+static int __devinit grvga_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ unsigned long virtual_start;
+ unsigned long grvga_fix_addr = 0;
+ unsigned long physical_start = 0;
+ unsigned long grvga_mem_size = 0;
+ struct grvga_par *par;
+ char *options = NULL, *mode_opt = NULL;
+
+ info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
+ if (!info) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
+ *
+ * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
+ * If address is left out, we allocate memory,
+ * if size is left out we only allocate enough to support the given mode.
+ */
+ if (fb_get_options("grvga", &options)) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ if (!options || !*options)
+ options = "640x480-8@60";
+
+ while (1) {
+ char *this_opt = strsep(&options, ",");
+
+ if (!this_opt)
+ break;
+
+ if (!strncmp(this_opt, "custom", 6))
+ grvga_parse_custom(this_opt, &info->var);
+ else if (!strncmp(this_opt, "addr:", 5))
+ grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
+ else if (!strncmp(this_opt, "size:", 5))
+ grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
+ else
+ mode_opt = this_opt;
+ }
+
+ par = info->par;
+ info->fbops = &grvga_ops;
+ info->fix = grvga_fix;
+ info->pseudo_palette = par->color_palette;
+ info->flags = GRVGA_FBINFO_DEFAULT;
+ info->fix.smem_len = grvga_mem_size;
+
+ par->regs = of_ioremap(&dev->resource[0], 0,
+ resource_size(&dev->resource[0]),
+ "grlib-svgactrl regs");
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ if (mode_opt) {
+ retval = fb_find_mode(&info->var, info, mode_opt,
+ grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
+ if (!retval || retval = 4) {
+ retval = -EINVAL;
+ goto err2;
+ }
+ }
+
+ if (!grvga_mem_size)
+ grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
+
+ if (grvga_fix_addr) {
+ /* Got framebuffer base address from argument list */
+
+ physical_start = grvga_fix_addr;
+
+ if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
+ dev_err(&dev->dev, "request mem region failed\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
+
+ if (!virtual_start) {
+ dev_err(&dev->dev, "error mapping memory\n");
+ retval = -ENOMEM;
+ goto err3;
+ }
+ } else { /* Allocate frambuffer memory */
+
+ unsigned long page;
+
+ virtual_start = (unsigned long) __get_free_pages(GFP_ATOMIC | GFP_DMA,
+ get_order(grvga_mem_size));
+ if (!virtual_start) {
+ dev_err(&dev->dev,
+ "unable to allocate framebuffer memory (%lu bytes)\n",
+ grvga_mem_size);
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+
+ physical_start = __pa(virtual_start);
+
+ /* Set page reserved so that mmap will work. This is necessary
+ * since we'll be remapping normal memory.
+ */
+ for (page = virtual_start;
+ page < PAGE_ALIGN(virtual_start + grvga_mem_size);
+ page += PAGE_SIZE) {
+ SetPageReserved(virt_to_page(page));
+ }
+ }
+
+ memset((unsigned long *) virtual_start, 0, grvga_mem_size);
+
+ info->screen_base = (char __iomem *) virtual_start;
+ info->fix.smem_start = physical_start;
+ info->fix.smem_len = grvga_mem_size;
+
+ dev_set_drvdata(&dev->dev, info);
+
+ dev_info(&dev->dev,
+ "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
+ info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
+ grvga_mem_size >> 10, info->screen_base);
+
+ retval = register_framebuffer(info);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to register framebuffer\n");
+ if (grvga_fix_addr)
+ goto err3;
+ else {
+ kfree((void *)virtual_start);
+ goto err2;
+ }
+ }
+
+ GRVGA_REGSAVE(par->regs->fb_pos, physical_start);
+ GRVGA_REGORIN(par->regs->status, 1); /* Enable framebuffer */
+
+ return 0;
+
+err3:
+ release_mem_region(physical_start, grvga_mem_size);
+err2:
+ fb_dealloc_cmap(&info->cmap);
+err1:
+ of_iounmap(&dev->resource[0], par->regs,
+ resource_size(&dev->resource[0]));
+err:
+ framebuffer_release(info);
+
+ return retval;
+}
+
+static int __devexit grvga_remove(struct platform_device *device)
+{
+ struct fb_info *info = dev_get_drvdata(&device->dev);
+ struct grvga_par *par = info->par;
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ of_iounmap(&device->resource[0], par->regs,
+ resource_size(&device->resource[0]));
+ framebuffer_release(info);
+ dev_set_drvdata(&device->dev, NULL);
+ }
+
+ return 0;
+}
+
+static struct of_device_id svgactrl_of_match[] = {
+ {
+ .name = "GAISLER_SVGACTRL",
+ },
+ {
+ .name = "01_063",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, svgactrl_of_match);
+
+static struct platform_driver grvga_driver = {
+ .driver = {
+ .name = "grlib-svgactrl",
+ .owner = THIS_MODULE,
+ .of_match_table = svgactrl_of_match,
+ },
+ .probe = grvga_probe,
+ .remove = __devexit_p(grvga_remove),
+};
+
+
+int __init grvga_init(void)
+{
+ return platform_driver_register(&grvga_driver);
+}
+
+static void __exit grvga_exit(void)
+{
+ platform_driver_unregister(&grvga_driver);
+}
+
+module_init(grvga_init);
+module_exit(grvga_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aeroflex Gaisler");
+MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");
--
1.6.4.1
^ permalink raw reply related
* Re: [PATCH] video: Add GRVGA framebuffer device driver
From: Kristoffer Glembo @ 2011-06-15 11:52 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308128180-14645-1-git-send-email-kristoffer@gaisler.com>
Hi,
Geert Uytterhoeven wrote:
> At first sight, nothing in this driver seems to be SPARC-specific, so
> perhaps this can be relaxed
> to e.g. depends on OF_DEVICE?
>
It uses of_ioremap/unmap which are SPARC-specific. I have been bitten by things like this before
when thinking I was portable so this time I just depended on SPARC. The core is not used on any
other platforms and is not very likely to be used either.
> Please remove the cast and use %p to format the address.
Will do.
Thanks,
Kristoffer Glembo
^ permalink raw reply
* Re: [PATCH] video: Add GRVGA framebuffer device driver
From: Geert Uytterhoeven @ 2011-06-15 11:32 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308128180-14645-1-git-send-email-kristoffer@gaisler.com>
On Wed, Jun 15, 2011 at 10:56, Kristoffer Glembo <kristoffer@gaisler.com> wrote:
> This patch adds support for the GRVGA framebuffer IP core from Aeroflex Gaisler.
> The device is used in LEON SPARCV8 based System on Chips. Documentation can
> be found here: www.gaisler.com/products/grlib/grip.pdf.
>
> Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
> ---
> drivers/video/Kconfig | 10 +
> drivers/video/Makefile | 1 +
> drivers/video/grvga.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 570 insertions(+), 0 deletions(-)
> create mode 100644 drivers/video/grvga.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 549b960..18ee201 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -259,6 +259,16 @@ config FB_TILEBLITTING
> comment "Frame buffer hardware drivers"
> depends on FB
>
> +config FB_GRVGA
> + tristate "Aeroflex Gaisler framebuffer support"
> + depends on FB && SPARC
At first sight, nothing in this driver seems to be SPARC-specific, so
perhaps this can be relaxed
to e.g. depends on OF_DEVICE?
> + select FB_CFB_FILLRECT
> + select FB_CFB_COPYAREA
> + select FB_CFB_IMAGEBLIT
> + ---help---
> + This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
> +
> +
> config FB_CIRRUS
> tristate "Cirrus Logic support"
> depends on FB && (ZORRO || PCI)
> --- /dev/null
> +++ b/drivers/video/grvga.c
> + dev_info(&dev->dev,
> + "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ 0x%x\n",
> + info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
> + grvga_mem_size >> 10, (unsigned int) info->screen_base);
^^^^^^^^^^^^^^
Please remove the cast and use %p to format the address.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCHv2 15/28] OMAP4: HWMOD: Modify DSS opt clocks
From: Tomi Valkeinen @ 2011-06-15 11:23 UTC (permalink / raw)
To: b-cousson; +Cc: linux-fbdev, paul, khilman, linux-omap mailing list
In-Reply-To: <1307627810-3768-16-git-send-email-tomi.valkeinen@ti.com>
On Thu, 2011-06-09 at 16:56 +0300, Tomi Valkeinen wrote:
> Add missing DSS optional clocks to HWMOD data for OMAP4xxx.
>
> Add HWMOD_CONTROL_OPT_CLKS_IN_RESET flag for dispc to fix dispc reset.
>
> Cc: Benoit Cousson <b-cousson@ti.com>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Benoit (and/or Paul/Kevin), can you ack this and the other HWMOD
patches, or give comments?
Tomi
^ permalink raw reply
* Re: Possible deadlock when suspending framebuffer
From: Bruno Prémont @ 2011-06-15 10:20 UTC (permalink / raw)
To: Francis Moreau
Cc: Wanlong Gao, Paul Mundt, linux-fbdev, Linux Kernel Mailing List,
Linus Torvalds
In-Reply-To: <BANLkTinE+EZ9nr1qGKC0VY0bVHuF8U-R0w@mail.gmail.com>
On Wed, 15 Jun 2011 09:12:46 Francis Moreau wrote:
> On Wed, Jun 15, 2011 at 7:58 AM, Bruno Prémont wrote:
> Well, sorry for the dumb question but the fb/fbcon code is pretty hard
> to follow for me.
Certainly not just for you
> Why does store_fbstate() and any fb driver's suspsend methods acquire
> the console lock at all ?
From my understanding, fbcon currently has very loose binding with
framebuffers in general instead of just with those few framebuffers
it is effectively mapped to (and active on!).
James Simmons started a complete rework of fbcon/tty code which is
expected to get things more fine-grained, until then console semaphore
(console_lock) remains a kind of big kernel lock in the
console/framebuffer area.
As such any state change of framebuffer may influence/race against
fbcon.
e.g. for the suspend state you want to avoid fbcon to fiddle with
your framebuffer while it is suspending (and have fbcon know about the
suspended state). This way fbcon can unsuspend framebuffer if needed
but also stop accessing it when it should not.
Bruno
^ permalink raw reply
* Re: [PATCHv2 01/28] OMAP: change get_context_loss_count ret value
From: Rajendra Nayak @ 2011-06-15 9:19 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Paul Walmsley, linux-fbdev, b-cousson, khilman,
linux-omap mailing list
In-Reply-To: <4DF76830.8070108@ti.com>
On 6/14/2011 7:24 PM, Rajendra Nayak wrote:
> On 6/14/2011 12:54 PM, Tomi Valkeinen wrote:
>> On Tue, 2011-06-14 at 01:13 -0600, Paul Walmsley wrote:
>>> Hi Tomi
>>>
>>> On Mon, 13 Jun 2011, Tomi Valkeinen wrote:
>>>
>>>> Paul, can you take this patch and queue it for an rc?
>>>
>>> Generally I only queue regressions or fixes for major problems (crashes,
>>> corruption, etc.) for -rc series. So probably this one should go in via
>>> the normal merge window, unless it's been causing major disruptions?
>>
>> No, only disruptions for me as the DSS pm_runtime patches depend on this
>> one to function correctly. So merge window is ok, I'll handle the DSS
>> side somehow.
>
> Hi Paul/Kevin,
>
> I had a query, not directly related to this patch, but to the way
> the omap_pm_get_dev_context_loss_count() api is implemented, which
> this patch is trying to fix in some ways.
> I see that the api relies on the pwrdm level state counters, which
> in-turn seem to be getting updated only in the cpuidle/suspend path.
> How are domains like DSS which can independently transition outside
> of the cpuidle path handled?
Thinking some more on this, maybe I now understand how this worked
on OMAP3. We always had the 'autodeps' on OMAP3 which made sure no
clkdm idle's while MPU is not in standby, and hence all transitions
would always happen between the pwrdm_pre_transition() and
pwrdm_post_transition() (where the pwrdm level state counters get
cleared/updated) callbacks. So there were really no domain
transitions outside of this on OMAP3.
My questions were popping out from the work I was trying to do to
support this on OMAP4, and with no 'autodeps' on OMAP4 there will
be transitions outside of cpuidle/suspend where counters need
to be updated/cleared which at this point I have no clue how to
handle :(
I will start a separate discussion/thread on this since
this is probably not the right place to discuss on how to do
this on OMAP4.
Thanks,
Rajendra
> What I mean is, if DSS on disabling its clocks transitions to OFF
> state (it being an independent powerdomain) and tries to use this api
> to know if it lost context the next time it is re-enabling clocks and
> all this happens while there was no cpuidle being scheduled, where do
> the pwrdm level state counters get updated, which tell DSS it did lose
> context?
>
> On another note, i was wondering if it even made any sense to drivers
> like DSS, which have an independent power domain of its own on OMAP to
> try and do a restore-only-if-needed kind of an implementation.
> Would'nt it always lose context the moment it run-time idle's?
>
> regards,
> Rajendra
>
>>
>> Tomi
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH] video: Add GRVGA framebuffer device driver
From: Kristoffer Glembo @ 2011-06-15 8:56 UTC (permalink / raw)
To: linux-fbdev
This patch adds support for the GRVGA framebuffer IP core from Aeroflex Gaisler.
The device is used in LEON SPARCV8 based System on Chips. Documentation can
be found here: www.gaisler.com/products/grlib/grip.pdf.
Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
---
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/grvga.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 570 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/grvga.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 549b960..18ee201 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -259,6 +259,16 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers"
depends on FB
+config FB_GRVGA
+ tristate "Aeroflex Gaisler framebuffer support"
+ depends on FB && SPARC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
+
+
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8b83129..4cff5ec 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
# Hardware specific drivers go first
+obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
new file mode 100644
index 0000000..e1514f9
--- /dev/null
+++ b/drivers/video/grvga.c
@@ -0,0 +1,559 @@
+/*
+ * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
+ *
+ * 2011 (c) Aeroflex Gaisler AB
+ *
+ * Full documentation of the core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+
+#define GRVGA_REGLOAD(a) (__raw_readl(&(a)))
+#define GRVGA_REGSAVE(a, v) (__raw_writel(v, &(a)))
+#define GRVGA_REGORIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) | (v))))
+#define GRVGA_REGANDIN(a, v) (GRVGA_REGSAVE(a, (GRVGA_REGLOAD(a) & (v))))
+
+#define GRVGA_FBINFO_DEFAULT (FBINFO_DEFAULT \
+ | FBINFO_PARTIAL_PAN_OK \
+ | FBINFO_HWACCEL_YPAN)
+
+struct grvga_regs {
+ u32 status; /* 0x00 */
+ u32 video_length; /* 0x04 */
+ u32 front_porch; /* 0x08 */
+ u32 sync_length; /* 0x0C */
+ u32 line_length; /* 0x10 */
+ u32 fb_pos; /* 0x14 */
+ u32 clk_vector[4]; /* 0x18 */
+ u32 clut; /* 0x20 */
+};
+
+struct grvga_par {
+ struct grvga_regs *regs;
+ u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
+ int clk_sel;
+};
+
+
+static const struct fb_videomode grvga_modedb[] = {
+ {
+ /* 640x480 @ 60 Hz */
+ NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 60 Hz */
+ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 800x600 @ 72 Hz */
+ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1024x768 @ 60 Hz */
+ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ };
+
+static struct fb_fix_screeninfo grvga_fix __initdata = {
+ .id = "AG SVGACTRL",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 0,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int grvga_set_par(struct fb_info *info);
+static int grvga_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue, unsigned transp,
+ struct fb_info *info);
+static int grvga_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+
+static struct fb_ops grvga_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = grvga_check_var,
+ .fb_set_par = grvga_set_par,
+ .fb_setcolreg = grvga_setcolreg,
+ .fb_pan_display = grvga_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit
+};
+
+static int grvga_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ int i;
+
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel <= 24)
+ var->bits_per_pixel = 24;
+ else if (var->bits_per_pixel <= 32)
+ var->bits_per_pixel = 32;
+ else
+ return -EINVAL;
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = 2*var->yres;
+
+ if (info->fix.smem_len) {
+ if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
+ return -ENOMEM;
+ }
+
+ /* Which clocks that are available can be read out in these registers */
+ for (i = 0; i <= 3 ; i++) {
+ if (var->pixclock = par->regs->clk_vector[i])
+ break;
+ }
+ if (i != -1)
+ par->clk_sel = i;
+ else
+ return -EINVAL;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
+ var->green = (struct fb_bitfield) {0, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 16:
+ var->red = (struct fb_bitfield) {11, 5, 0};
+ var->green = (struct fb_bitfield) {5, 6, 0};
+ var->blue = (struct fb_bitfield) {0, 5, 0};
+ var->transp = (struct fb_bitfield) {0, 0, 0};
+ break;
+ case 24:
+ case 32:
+ var->red = (struct fb_bitfield) {16, 8, 0};
+ var->green = (struct fb_bitfield) {8, 8, 0};
+ var->blue = (struct fb_bitfield) {0, 8, 0};
+ var->transp = (struct fb_bitfield) {24, 8, 0};
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int grvga_set_par(struct fb_info *info)
+{
+
+ int func = 0;
+ struct grvga_par *par = info->par;
+
+ GRVGA_REGSAVE(par->regs->video_length,
+ ((info->var.yres - 1) << 16) | (info->var.xres - 1));
+ GRVGA_REGSAVE(par->regs->front_porch,
+ (info->var.lower_margin << 16) | (info->var.right_margin));
+ GRVGA_REGSAVE(par->regs->sync_length,
+ (info->var.vsync_len << 16) | (info->var.hsync_len));
+ GRVGA_REGSAVE(par->regs->line_length,
+ ((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
+ (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1));
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ func = 1;
+ break;
+ case 16:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 2;
+ break;
+ case 24:
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ func = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ GRVGA_REGSAVE(par->regs->status, ((par->clk_sel << 6) | (func << 4)) | 1);
+
+ info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
+ return 0;
+}
+
+static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct grvga_par *par;
+ par = info->par;
+
+ if (regno >= 256) /* Size of CLUT */
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+#undef CNVT_TOHW
+
+ /* In PSEUDOCOLOR we use the hardware CLUT */
+ if (info->fix.visual = FB_VISUAL_PSEUDOCOLOR)
+ GRVGA_REGSAVE(par->regs->clut,
+ (regno << 24) | (red << 16) | (green << 8) | blue);
+
+ /* Truecolor uses the pseudo palette */
+ else if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
+ u32 v;
+ if (regno >= 16)
+ return -EINVAL;
+
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ }
+ return 0;
+}
+
+static int grvga_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct grvga_par *par = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ u32 base_addr;
+
+ if (var->xoffset != 0)
+ return -EINVAL;
+
+ base_addr = fix->smem_start + (var->yoffset * fix->line_length);
+ base_addr &= ~3UL;
+
+ /* Set framebuffer base address */
+ GRVGA_REGSAVE(par->regs->fb_pos, base_addr);
+
+ return 0;
+}
+
+static int __init grvga_parse_custom(char *options,
+ struct fb_var_screeninfo *screendata)
+{
+ char *this_opt;
+ int count = 0;
+ if (!options || !*options)
+ return -1;
+
+ while ((this_opt = strsep(&options, " ")) != NULL) {
+ if (!*this_opt)
+ continue;
+
+ switch (count) {
+ case 0:
+ screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 1:
+ screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 2:
+ screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 3:
+ screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 4:
+ screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 5:
+ screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 6:
+ screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 7:
+ screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 8:
+ screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ case 9:
+ screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
+ count++;
+ break;
+ }
+ }
+ screendata->activate = FB_ACTIVATE_NOW;
+ screendata->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+}
+
+static int __devinit grvga_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ unsigned long virtual_start;
+ unsigned long grvga_fix_addr = 0;
+ unsigned long physical_start = 0;
+ unsigned long grvga_mem_size = 0;
+ struct grvga_par *par;
+ char *options = NULL, *mode_opt = NULL;
+
+ info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
+ if (!info) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
+ *
+ * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
+ * If address is left out, we allocate memory,
+ * if size is left out we only allocate enough to support the given mode.
+ */
+ if (fb_get_options("grvga", &options)) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ if (!options || !*options)
+ options = "640x480-8@60";
+
+ while (1) {
+ char *this_opt = strsep(&options, ",");
+
+ if (!this_opt)
+ break;
+
+ if (!strncmp(this_opt, "custom", 6))
+ grvga_parse_custom(this_opt, &info->var);
+ else if (!strncmp(this_opt, "addr:", 5))
+ grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
+ else if (!strncmp(this_opt, "size:", 5))
+ grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
+ else
+ mode_opt = this_opt;
+ }
+
+ par = info->par;
+ info->fbops = &grvga_ops;
+ info->fix = grvga_fix;
+ info->pseudo_palette = par->color_palette;
+ info->flags = GRVGA_FBINFO_DEFAULT;
+ info->fix.smem_len = grvga_mem_size;
+
+ par->regs = of_ioremap(&dev->resource[0], 0,
+ resource_size(&dev->resource[0]),
+ "grlib-svgactrl regs");
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ if (mode_opt) {
+ retval = fb_find_mode(&info->var, info, mode_opt,
+ grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
+ if (!retval || retval = 4) {
+ retval = -EINVAL;
+ goto err2;
+ }
+ }
+
+ if (!grvga_mem_size)
+ grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
+
+ if (grvga_fix_addr) {
+ /* Got framebuffer base address from argument list */
+
+ physical_start = grvga_fix_addr;
+
+ if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
+ dev_err(&dev->dev, "request mem region failed\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
+
+ if (!virtual_start) {
+ dev_err(&dev->dev, "error mapping memory\n");
+ retval = -ENOMEM;
+ goto err3;
+ }
+ } else { /* Allocate frambuffer memory */
+
+ unsigned long page;
+
+ virtual_start = (unsigned long) __get_free_pages(GFP_ATOMIC | GFP_DMA,
+ get_order(grvga_mem_size));
+ if (!virtual_start) {
+ dev_err(&dev->dev,
+ "unable to allocate framebuffer memory (%lu bytes)\n",
+ grvga_mem_size);
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+
+ physical_start = __pa(virtual_start);
+
+ /* Set page reserved so that mmap will work. This is necessary
+ * since we'll be remapping normal memory.
+ */
+ for (page = virtual_start;
+ page < PAGE_ALIGN(virtual_start + grvga_mem_size);
+ page += PAGE_SIZE) {
+ SetPageReserved(virt_to_page(page));
+ }
+ }
+
+ memset((unsigned long *) virtual_start, 0, grvga_mem_size);
+
+ info->screen_base = (char __iomem *) virtual_start;
+ info->fix.smem_start = physical_start;
+ info->fix.smem_len = grvga_mem_size;
+
+ dev_set_drvdata(&dev->dev, info);
+
+ dev_info(&dev->dev,
+ "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ 0x%x\n",
+ info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
+ grvga_mem_size >> 10, (unsigned int) info->screen_base);
+
+ retval = register_framebuffer(info);
+ if (retval < 0) {
+ dev_err(&dev->dev, "failed to register framebuffer\n");
+ if (grvga_fix_addr)
+ goto err3;
+ else {
+ kfree((void *)virtual_start);
+ goto err2;
+ }
+ }
+
+ GRVGA_REGSAVE(par->regs->fb_pos, physical_start);
+ GRVGA_REGORIN(par->regs->status, 1); /* Enable framebuffer */
+
+ return 0;
+
+err3:
+ release_mem_region(physical_start, grvga_mem_size);
+err2:
+ fb_dealloc_cmap(&info->cmap);
+err1:
+ of_iounmap(&dev->resource[0], par->regs,
+ resource_size(&dev->resource[0]));
+err:
+ framebuffer_release(info);
+
+ return retval;
+}
+
+static int __devexit grvga_remove(struct platform_device *device)
+{
+ struct fb_info *info = dev_get_drvdata(&device->dev);
+ struct grvga_par *par = info->par;
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ of_iounmap(&device->resource[0], par->regs,
+ resource_size(&device->resource[0]));
+ framebuffer_release(info);
+ dev_set_drvdata(&device->dev, NULL);
+ }
+
+ return 0;
+}
+
+static struct of_device_id svgactrl_of_match[] = {
+ {
+ .name = "GAISLER_SVGACTRL",
+ },
+ {
+ .name = "01_063",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, svgactrl_of_match);
+
+static struct platform_driver grvga_driver = {
+ .driver = {
+ .name = "grlib-svgactrl",
+ .owner = THIS_MODULE,
+ .of_match_table = svgactrl_of_match,
+ },
+ .probe = grvga_probe,
+ .remove = __devexit_p(grvga_remove),
+};
+
+
+int __init grvga_init(void)
+{
+ return platform_driver_register(&grvga_driver);
+}
+
+static void __exit grvga_exit(void)
+{
+ platform_driver_unregister(&grvga_driver);
+}
+
+module_init(grvga_init);
+module_exit(grvga_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aeroflex Gaisler");
+MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");
--
1.6.4.1
^ permalink raw reply related
* Re: Possible deadlock when suspending framebuffer
From: Francis Moreau @ 2011-06-15 7:12 UTC (permalink / raw)
To: Bruno Prémont
Cc: Wanlong Gao, Paul Mundt, linux-fbdev, Linux Kernel Mailing List,
Linus Torvalds
In-Reply-To: <20110615075803.3348b4ec@pluto.restena.lu>
On Wed, Jun 15, 2011 at 7:58 AM, Bruno Prémont
<bonbons@linux-vserver.org> wrote:
> Hi,
>
> On Wed, 15 Jun 2011 09:09:24 Wanlong Gao <wanlong.gao@gmail.com> wrote:
>> <snip>
>> Hi Francis:
>> can you test this patch?
>
> Do you have a deadlock trace which you are trying to fix?
>
> It's either the caller of unregister_framebuffer() which must be
> changed to not call unregister_framebuffer with info's lock held or
> the code reacting on the notification that must not try to acquire the
> lock again.
>
> The interesting par is if console semaphore has some relation to this
> deadlock as the order for taking both varies... It could be
> lock_fb_info(); console_lock() versus console_lock(); lock_fb_info()
>
> Bruno
>
>
>> Thanks
>>
>> From fe026c42af4cbdce053460a428a445e99071586a Mon Sep 17 00:00:00 2001
>> From: Wanlong Gao <wanlong.gao@gmail.com>
>> Date: Wed, 15 Jun 2011 09:03:41 +0800
>> Subject: [PATCH] test
>>
>>
>>
>> Signed-off-by: Wanlong Gao <wanlong.gao@gmail.com>
>> ---
>> drivers/video/fbmem.c | 3 ---
>> 1 files changed, 0 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
>> index 5aac00e..6e6cef3 100644
>> --- a/drivers/video/fbmem.c
>> +++ b/drivers/video/fbmem.c
>> @@ -1642,11 +1642,8 @@ static int do_unregister_framebuffer(struct
>> fb_info *fb_info)
>> if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
>> return -EINVAL;
>>
>> - if (!lock_fb_info(fb_info))
>> - return -ENODEV;
>> event.info = fb_info;
>> ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
>> - unlock_fb_info(fb_info);
>
> Not a good idea to stop taking fb_lock here.
> Pretty all calls of fb_notifier_call_chain are protected by info's
> lock, except the one for FB_EVENT_FB_UNREGISTERED a few lines further.
>
> IMHO it wou make sense to add the lock around that last one so all
> notifier chain calls are handled the same.
>
>> if (ret)
>> return -EINVAL;
>
>
Well, sorry for the dumb question but the fb/fbcon code is pretty hard
to follow for me.
Why does store_fbstate() and any fb driver's suspsend methods acquire
the console lock at all ?
Thanks
--
Francis
^ permalink raw reply
* Re: Possible deadlock when suspending framebuffer
From: Américo Wang @ 2011-06-15 7:04 UTC (permalink / raw)
To: wanlong.gao
Cc: Bruno Prémont, Francis Moreau, Paul Mundt, linux-fbdev,
Linux Kernel Mailing List, Linus Torvalds
In-Reply-To: <BANLkTimiv5T6cgRjkDfPwjh-c5AivYzhmA@mail.gmail.com>
On Wed, Jun 15, 2011 at 2:22 PM, Wanlong Gao <wanlong.gao@gmail.com> wrote:
> On Wed, Jun 15, 2011 at 1:58 PM, Bruno Prémont
> <bonbons@linux-vserver.org> wrote:
>>
>> Hi,
>>
>> On Wed, 15 Jun 2011 09:09:24 Wanlong Gao <wanlong.gao@gmail.com> wrote:
>> > <snip>
>> > Hi Francis:
>> > can you test this patch?
>>
>> Do you have a deadlock trace which you are trying to fix?
> No, I just look at the code and try to fix this but I'm not sure.
> Can you teach me how to have a deadlock trace here?
CONFIG_LOCKDEP=y
^ permalink raw reply
* Re: Possible deadlock when suspending framebuffer
From: Wanlong Gao @ 2011-06-15 6:22 UTC (permalink / raw)
To: Bruno Prémont
Cc: Francis Moreau, Paul Mundt, linux-fbdev,
Linux Kernel Mailing List, Linus Torvalds
In-Reply-To: <20110615075803.3348b4ec@pluto.restena.lu>
On Wed, Jun 15, 2011 at 1:58 PM, Bruno Prémont
<bonbons@linux-vserver.org> wrote:
>
> Hi,
>
> On Wed, 15 Jun 2011 09:09:24 Wanlong Gao <wanlong.gao@gmail.com> wrote:
> > <snip>
> > Hi Francis:
> > can you test this patch?
>
> Do you have a deadlock trace which you are trying to fix?
No, I just look at the code and try to fix this but I'm not sure.
Can you teach me how to have a deadlock trace here?
Thanks
>
> It's either the caller of unregister_framebuffer() which must be
> changed to not call unregister_framebuffer with info's lock held or
> the code reacting on the notification that must not try to acquire the
> lock again.
>
> The interesting par is if console semaphore has some relation to this
> deadlock as the order for taking both varies... It could be
> lock_fb_info(); console_lock() versus console_lock(); lock_fb_info()
>
I see, thanks
> Bruno
>
>
> > Thanks
> >
><snip>
>
> Not a good idea to stop taking fb_lock here.
> Pretty all calls of fb_notifier_call_chain are protected by info's
> lock, except the one for FB_EVENT_FB_UNREGISTERED a few lines further.
Yup, thanks
>
> IMHO it wou make sense to add the lock around that last one so all
> notifier chain calls are handled the same.
>
> <snip>
>
--
Best regards
Wanlong Gao
^ permalink raw reply
* Re: [PATCH v2 00/29] Use display information in info not in var for panning
From: Paul Mundt @ 2011-06-15 6:14 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308043507-11083-1-git-send-email-laurent.pinchart@ideasonboard.com>
On Tue, Jun 14, 2011 at 11:24:38AM +0200, Laurent Pinchart wrote:
> I've split the fixes in one patch per driver for easier review and handling of
> potential problems. The patches can be squashed together if needed. I've tried
> to CC individual driver maintainers when possible, and Acked-by lines received
> in reply to the first version have been included.
>
> Compared to v1, I've fixed a couple of subject lines that mentioned the wrong
> driver name, and replaced var->bits_per_pixel in the mx3fb driver.
>
> Not all patches have been tested on real hardware and acked. Geert Uytterhoeven
> acked the overall idea, and I believe the patches are now ready to be applied.
>
This seems like a good direction in general, so it's certainly with
proceeding with. I've applied the series to the fbdev/panning-fixes topic
branch, which I will subsequently merge so it's possible to get wider
coverage via -next.
Individual driver authors have had a few weeks to ack/nack accordingly,
so it's fairly reasonable to expect that you're not likely to be
collecting much more feedback before the whole thing gets merged anyways.
If it ends up horribly breaking a number of drivers then it's still
trivial to revert the branch merge and convert drivers incrementally, but
I don't expect that to really be a problem.
^ permalink raw reply
* Re: Possible deadlock when suspending framebuffer
From: Bruno Prémont @ 2011-06-15 5:58 UTC (permalink / raw)
To: Wanlong Gao
Cc: Francis Moreau, Paul Mundt, linux-fbdev,
Linux Kernel Mailing List, Linus Torvalds
In-Reply-To: <1308100165.2113.4.camel@Tux>
Hi,
On Wed, 15 Jun 2011 09:09:24 Wanlong Gao <wanlong.gao@gmail.com> wrote:
> <snip>
> Hi Francis:
> can you test this patch?
Do you have a deadlock trace which you are trying to fix?
It's either the caller of unregister_framebuffer() which must be
changed to not call unregister_framebuffer with info's lock held or
the code reacting on the notification that must not try to acquire the
lock again.
The interesting par is if console semaphore has some relation to this
deadlock as the order for taking both varies... It could be
lock_fb_info(); console_lock() versus console_lock(); lock_fb_info()
Bruno
> Thanks
>
> From fe026c42af4cbdce053460a428a445e99071586a Mon Sep 17 00:00:00 2001
> From: Wanlong Gao <wanlong.gao@gmail.com>
> Date: Wed, 15 Jun 2011 09:03:41 +0800
> Subject: [PATCH] test
>
>
>
> Signed-off-by: Wanlong Gao <wanlong.gao@gmail.com>
> ---
> drivers/video/fbmem.c | 3 ---
> 1 files changed, 0 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> index 5aac00e..6e6cef3 100644
> --- a/drivers/video/fbmem.c
> +++ b/drivers/video/fbmem.c
> @@ -1642,11 +1642,8 @@ static int do_unregister_framebuffer(struct
> fb_info *fb_info)
> if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
> return -EINVAL;
>
> - if (!lock_fb_info(fb_info))
> - return -ENODEV;
> event.info = fb_info;
> ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
> - unlock_fb_info(fb_info);
Not a good idea to stop taking fb_lock here.
Pretty all calls of fb_notifier_call_chain are protected by info's
lock, except the one for FB_EVENT_FB_UNREGISTERED a few lines further.
IMHO it wou make sense to add the lock around that last one so all
notifier chain calls are handled the same.
> if (ret)
> return -EINVAL;
^ permalink raw reply
* Re: [PATCH] fbdev: sh_mobile_hdmi: fix regression: statically enable RTPM
From: Paul Mundt @ 2011-06-15 5:53 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <Pine.LNX.4.64.1106141610430.19402@axis700.grange>
On Tue, Jun 14, 2011 at 04:27:22PM +0200, Guennadi Liakhovetski wrote:
> A recent modification to the runtime PM code on mach-shmobile made a wrong
> RTPM implementation in the sh_mobile_hdmi driver apparent, which broke
> HDMI hotplug detection support on ap4evb. This patch does not implement a
> proper dynamic RTPM support for sh_mobile_hdmi, instead it restores the
> previous working state by statically enabling it. A more power-efficient
> solution should be implemented for the next kernel version.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH v2 08/29] fbdev: unicore32: use display information in
From: Guan Xuetao @ 2011-06-15 2:40 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1308043507-11083-9-git-send-email-laurent.pinchart@ideasonboard.com>
On Tue, 2011-06-14 at 11:24 +0200, Laurent Pinchart wrote:
> We must not use any information in the passed var besides xoffset,
> yoffset and vmode as otherwise applications might abuse it.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
> ---
> drivers/video/fb-puv3.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c
> index 27f2c57..60a787f 100644
> --- a/drivers/video/fb-puv3.c
> +++ b/drivers/video/fb-puv3.c
> @@ -624,8 +624,8 @@ static int unifb_pan_display(struct fb_var_screeninfo *var,
> || var->xoffset)
> return -EINVAL;
> } else {
> - if (var->xoffset + var->xres > info->var.xres_virtual ||
> - var->yoffset + var->yres > info->var.yres_virtual)
> + if (var->xoffset + info->var.xres > info->var.xres_virtual ||
> + var->yoffset + info->var.yres > info->var.yres_virtual)
> return -EINVAL;
> }
> info->var.xoffset = var->xoffset;
Tested-and-Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Thanks.
Guan Xuetao
^ permalink raw reply
* Re: [PATCH] EFIFB: Fix error handling
From: Paul Mundt @ 2011-06-15 2:37 UTC (permalink / raw)
To: David Howells; +Cc: pjones, akpm, linux-kernel, linux-fbdev, stable
In-Reply-To: <20110615003817.18883.41030.stgit@warthog.procyon.org.uk>
On Wed, Jun 15, 2011 at 01:38:17AM +0100, David Howells wrote:
> Fix the error handling in the EFIFB driver if platform_driver_probe() fails.
> In that case, the code will pass the driver struct to the _device_
> unregistration function. It presumably should pass a pointer to the device
> struct instead.
>
> The compiler gives the following warning to indicate this:
>
> drivers/video/efifb.c: In function 'efifb_init':
> drivers/video/efifb.c:544:3: warning: passing argument 1 of 'platform_device_unregister' from incompatible pointer type
> include/linux/platform_device.h:40:13: note: expected 'struct platform_device *' but argument is of type 'struct platform_driver *'
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Peter Jones <pjones@redhat.com>
> cc: linux-fbdev@vger.kernel.org
> cc: stable@kernel.org
Thanks, I've already queued a fix for this.
^ permalink raw reply
* re:Possible deadlock when suspending framebuffer
From: Wanlong Gao @ 2011-06-15 1:09 UTC (permalink / raw)
To: Francis Moreau
Cc: Paul Mundt, linux-fbdev, Linux Kernel Mailing List,
Linus Torvalds
In-Reply-To: <BANLkTimny9nzr23TufH1kMcsk57M3NXuaA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 884 bytes --]
<snip>
Hi Francis:
can you test this patch?
Thanks
From fe026c42af4cbdce053460a428a445e99071586a Mon Sep 17 00:00:00 2001
From: Wanlong Gao <wanlong.gao@gmail.com>
Date: Wed, 15 Jun 2011 09:03:41 +0800
Subject: [PATCH] test
Signed-off-by: Wanlong Gao <wanlong.gao@gmail.com>
---
drivers/video/fbmem.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 5aac00e..6e6cef3 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1642,11 +1642,8 @@ static int do_unregister_framebuffer(struct
fb_info *fb_info)
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
return -EINVAL;
- if (!lock_fb_info(fb_info))
- return -ENODEV;
event.info = fb_info;
ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
- unlock_fb_info(fb_info);
if (ret)
return -EINVAL;
--
1.7.4.1
[-- Attachment #2: 0001-test.patch --]
[-- Type: text/x-patch, Size: 835 bytes --]
From fe026c42af4cbdce053460a428a445e99071586a Mon Sep 17 00:00:00 2001
From: Wanlong Gao <wanlong.gao@gmail.com>
Date: Wed, 15 Jun 2011 09:03:41 +0800
Subject: [PATCH] test
test
Signed-off-by: Wanlong Gao <wanlong.gao@gmail.com>
---
drivers/video/fbmem.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 5aac00e..6e6cef3 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1642,11 +1642,8 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
return -EINVAL;
- if (!lock_fb_info(fb_info))
- return -ENODEV;
event.info = fb_info;
ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
- unlock_fb_info(fb_info);
if (ret)
return -EINVAL;
--
1.7.4.1
^ permalink raw reply related
* [PATCH] EFIFB: Fix error handling
From: David Howells @ 2011-06-15 0:38 UTC (permalink / raw)
To: pjones; +Cc: akpm, linux-kernel, David Howells, linux-fbdev, stable
Fix the error handling in the EFIFB driver if platform_driver_probe() fails.
In that case, the code will pass the driver struct to the _device_
unregistration function. It presumably should pass a pointer to the device
struct instead.
The compiler gives the following warning to indicate this:
drivers/video/efifb.c: In function 'efifb_init':
drivers/video/efifb.c:544:3: warning: passing argument 1 of 'platform_device_unregister' from incompatible pointer type
include/linux/platform_device.h:40:13: note: expected 'struct platform_device *' but argument is of type 'struct platform_driver *'
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Peter Jones <pjones@redhat.com>
cc: linux-fbdev@vger.kernel.org
cc: stable@kernel.org
---
drivers/video/efifb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 69c49df..784139a 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -541,7 +541,7 @@ static int __init efifb_init(void)
*/
ret = platform_driver_probe(&efifb_driver, efifb_probe);
if (ret) {
- platform_device_unregister(&efifb_driver);
+ platform_device_unregister(&efifb_device);
return ret;
}
^ permalink raw reply related
* Re: Possible deadlock when suspending framebuffer
From: Florian Tobias Schandinat @ 2011-06-14 19:04 UTC (permalink / raw)
To: Linus Torvalds
Cc: Paul Mundt, linux-fbdev, Linux Kernel Mailing List,
Francis Moreau
In-Reply-To: <BANLkTimny9nzr23TufH1kMcsk57M3NXuaA@mail.gmail.com>
Hi Linus,
On 06/14/2011 06:15 PM, Linus Torvalds wrote:
> Paul, fbdev people.. Comments? This was sent to me and lkml, the right
> people probably didn't see it.
Sounds very familiar. Indeed a quick glance at my archive revealed 2
approaches/patches dealing with similar issues
http://marc.info/?l=linux-fbdev&m\x129539210207429&w=2
http://marc.info/?l=linux-fbdev&m\x129700789632450&w=2
I did not have time to verify that those do actually get those things right
everywhere but the first one looks good and should also solve this issue I think.
Regards,
Florian Tobias Schandinat
>
> I doubt it's a big problem in practice, but..
>
> Linus
>
> On Tue, Jun 14, 2011 at 6:10 AM, Francis Moreau<francis.moro@gmail.com> wrote:
>> Hello,
>>
>> I noticed that a possible deadlock can happen when the current frame
>> buffering is being suspended and a new frambuffer device is being
>> registred at the same time.
>>
>> When suspending the current frambuffer by doing : echo 1
>>> /sys/class/graphics/fb0/state, the kernel actually takes the
>> following locks in that order: console_lock, lock_fb_info (see
>> store_fbstate()).
>>
>> However when a new framebuffer is coming in, the lock sequence is:
>> lock_fb_info (taken by do_remove_conflicting_framebuffer()),
>> console_lock() (taken by unbind_console).
>>
>> I don't know how this should be fixed though...
>>
>> Thanks
>> --
>> Francis
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: Possible deadlock when suspending framebuffer
From: Linus Torvalds @ 2011-06-14 18:15 UTC (permalink / raw)
To: Paul Mundt, linux-fbdev; +Cc: Linux Kernel Mailing List, Francis Moreau
In-Reply-To: <BANLkTiko+2AM8dq8jP5xjbTcCM63hBAK=A@mail.gmail.com>
Paul, fbdev people.. Comments? This was sent to me and lkml, the right
people probably didn't see it.
I doubt it's a big problem in practice, but..
Linus
On Tue, Jun 14, 2011 at 6:10 AM, Francis Moreau <francis.moro@gmail.com> wrote:
> Hello,
>
> I noticed that a possible deadlock can happen when the current frame
> buffering is being suspended and a new frambuffer device is being
> registred at the same time.
>
> When suspending the current frambuffer by doing : echo 1
>>/sys/class/graphics/fb0/state, the kernel actually takes the
> following locks in that order: console_lock, lock_fb_info (see
> store_fbstate()).
>
> However when a new framebuffer is coming in, the lock sequence is:
> lock_fb_info (taken by do_remove_conflicting_framebuffer()),
> console_lock() (taken by unbind_console).
>
> I don't know how this should be fixed though...
>
> Thanks
> --
> Francis
>
^ permalink raw reply
* [PATCH] fbdev: sh_mobile_hdmi: fix regression: statically enable
From: Guennadi Liakhovetski @ 2011-06-14 14:27 UTC (permalink / raw)
To: linux-fbdev
A recent modification to the runtime PM code on mach-shmobile made a wrong
RTPM implementation in the sh_mobile_hdmi driver apparent, which broke
HDMI hotplug detection support on ap4evb. This patch does not implement a
proper dynamic RTPM support for sh_mobile_hdmi, instead it restores the
previous working state by statically enabling it. A more power-efficient
solution should be implemented for the next kernel version.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/video/sh_mobile_hdmi.c | 18 +++++-------------
1 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 6ae40b6..7d54e2c 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1127,23 +1127,16 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
struct fb_info *info = hdmi->info;
unsigned long parent_rate = 0, hdmi_rate;
- /* A device has been plugged in */
- pm_runtime_get_sync(hdmi->dev);
-
ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
- if (ret < 0) {
- pm_runtime_put(hdmi->dev);
+ if (ret < 0)
goto out;
- }
hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
/* Reconfigure the clock */
ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
- if (ret < 0) {
- pm_runtime_put(hdmi->dev);
+ if (ret < 0)
goto out;
- }
msleep(10);
sh_hdmi_configure(hdmi);
@@ -1191,7 +1184,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
fb_set_suspend(hdmi->info, 1);
console_unlock();
- pm_runtime_put(hdmi->dev);
}
out:
@@ -1312,7 +1304,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn);
pm_runtime_enable(&pdev->dev);
- pm_runtime_resume(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
/* Product and revision IDs are 0 in sh-mobile version */
dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
@@ -1340,7 +1332,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
ecodec:
free_irq(irq, hdmi);
ereqirq:
- pm_runtime_suspend(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
iounmap(hdmi->base);
emap:
@@ -1377,7 +1369,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
free_irq(irq, hdmi);
/* Wait for already scheduled work */
cancel_delayed_work_sync(&hdmi->edid_work);
- pm_runtime_suspend(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
clk_disable(hdmi->hdmi_clk);
clk_put(hdmi->hdmi_clk);
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCHv2 01/28] OMAP: change get_context_loss_count ret value
From: Rajendra Nayak @ 2011-06-14 13:55 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Paul Walmsley, linux-fbdev, b-cousson, khilman,
linux-omap mailing list
In-Reply-To: <1308036257.1899.8.camel@deskari>
On 6/14/2011 12:54 PM, Tomi Valkeinen wrote:
> On Tue, 2011-06-14 at 01:13 -0600, Paul Walmsley wrote:
>> Hi Tomi
>>
>> On Mon, 13 Jun 2011, Tomi Valkeinen wrote:
>>
>>> Paul, can you take this patch and queue it for an rc?
>>
>> Generally I only queue regressions or fixes for major problems (crashes,
>> corruption, etc.) for -rc series. So probably this one should go in via
>> the normal merge window, unless it's been causing major disruptions?
>
> No, only disruptions for me as the DSS pm_runtime patches depend on this
> one to function correctly. So merge window is ok, I'll handle the DSS
> side somehow.
Hi Paul/Kevin,
I had a query, not directly related to this patch, but to the way
the omap_pm_get_dev_context_loss_count() api is implemented, which
this patch is trying to fix in some ways.
I see that the api relies on the pwrdm level state counters, which
in-turn seem to be getting updated only in the cpuidle/suspend path.
How are domains like DSS which can independently transition outside
of the cpuidle path handled?
What I mean is, if DSS on disabling its clocks transitions to OFF
state (it being an independent powerdomain) and tries to use this api
to know if it lost context the next time it is re-enabling clocks and
all this happens while there was no cpuidle being scheduled, where do
the pwrdm level state counters get updated, which tell DSS it did lose
context?
On another note, i was wondering if it even made any sense to drivers
like DSS, which have an independent power domain of its own on OMAP to
try and do a restore-only-if-needed kind of an implementation.
Would'nt it always lose context the moment it run-time idle's?
regards,
Rajendra
>
> Tomi
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 29/29] staging: xgifb: use display information in info not in var for panning
From: Laurent Pinchart @ 2011-06-14 9:25 UTC (permalink / raw)
To: linux-fbdev
We must not use any information in the passed var besides xoffset,
yoffset and vmode as otherwise applications might abuse it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Aaro Koskinen <aaro.koskinen@iki.fi>
Cc: Arnaud Patard <apatard@mandriva.com>
---
drivers/staging/xgifb/XGI_main_26.c | 22 ++++++----------------
1 files changed, 6 insertions(+), 16 deletions(-)
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index cadec2a..e92f6fa 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -1365,26 +1365,16 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
}
#ifdef XGIFB_PAN
-static int XGIfb_pan_var(struct fb_var_screeninfo *var)
+static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
unsigned int base;
/* printk("Inside pan_var"); */
- if (var->xoffset > (var->xres_virtual - var->xres)) {
- /* printk("Pan: xo: %d xv %d xr %d\n",
- var->xoffset, var->xres_virtual, var->xres); */
- return -EINVAL;
- }
- if (var->yoffset > (var->yres_virtual - var->yres)) {
- /* printk("Pan: yo: %d yv %d yr %d\n",
- var->yoffset, var->yres_virtual, var->yres); */
- return -EINVAL;
- }
- base = var->yoffset * var->xres_virtual + var->xoffset;
+ base = var->yoffset * info->var.xres_virtual + var->xoffset;
/* calculate base bpp dep. */
- switch (var->bits_per_pixel) {
+ switch (info->var.bits_per_pixel) {
case 16:
base >>= 1;
break;
@@ -1682,9 +1672,9 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
/* printk("\nInside pan_display:\n"); */
- if (var->xoffset > (var->xres_virtual - var->xres))
+ if (var->xoffset > (info->var.xres_virtual - info->var.xres))
return -EINVAL;
- if (var->yoffset > (var->yres_virtual - var->yres))
+ if (var->yoffset > (info->var.yres_virtual - info->var.yres))
return -EINVAL;
if (var->vmode & FB_VMODE_YWRAP) {
@@ -1697,7 +1687,7 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var,
> info->var.yres_virtual)
return -EINVAL;
}
- err = XGIfb_pan_var(var);
+ err = XGIfb_pan_var(var, info);
if (err < 0)
return err;
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 28/29] vt8623fb: use display information in info not in var for panning
From: Laurent Pinchart @ 2011-06-14 9:25 UTC (permalink / raw)
To: linux-fbdev
We must not use any information in the passed var besides xoffset,
yoffset and vmode as otherwise applications might abuse it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Ondrej Zajicek <santiago@crfreenet.org>
Cc: David S. Miller <davem@davemloft.net>
---
drivers/video/vt8623fb.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index f9b3e3d..4e74d26 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -620,13 +620,14 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i
unsigned int offset;
/* Calculate the offset */
- if (var->bits_per_pixel = 0) {
- offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+ if (info->var.bits_per_pixel = 0) {
+ offset = (var->yoffset / 16) * info->var.xres_virtual
+ + var->xoffset;
offset = offset >> 3;
} else {
offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * var->bits_per_pixel / 8);
- offset = offset >> ((var->bits_per_pixel = 4) ? 2 : 1);
+ (var->xoffset * info->var.bits_per_pixel / 8);
+ offset = offset >> ((info->var.bits_per_pixel = 4) ? 2 : 1);
}
/* Set the offset */
--
1.7.3.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox