Thread (2 messages) flat view 2 messages, 2 authors, 2011-01-25

Re: [PATCH] unicore32: add framebuffer driver for unigfx engine in PKUnity SoC

From: Paul Mundt <hidden>
Date: 2011-01-25 09:02:16
Also in: lkml

On Sat, Jan 22, 2011 at 06:29:45PM +0800, Guan Xuetao wrote:
quoted hunk ↗ jump to hunk
diff --git a/drivers/video/puv3_fb.c b/drivers/video/puv3_fb.c
new file mode 100644
index 0000000..d938a73
--- /dev/null
+++ b/drivers/video/puv3_fb.c
[snip]
+static unsigned long unifb_regs[10];
+
This is probably something that you will want to move in to platform
data.
+#define VIDEOMEMSIZE	(SZ_4M)		/* 4 MB for 1024*768*32b */
+
+static void *videomemory;
+static u_long videomemorysize = VIDEOMEMSIZE;
+module_param(videomemorysize, ulong, 0);
+
Along with these, given that they're not dynamically acquired by the
driver.
+static int unifb_enable __initdata = 1;	/* enable by default */
+module_param(unifb_enable, bool, 0);
+
No need for this, you can use fb_get_options() and -ENODEV out in the
init path then simply use the generic "off" parsing done by the fbmem
code.
+#ifdef CONFIG_PUV3_UNIGFX_HWACCEL
+static void unifb_sync(void)
+{
+	/* TODO: may, this can be replaced by interrupt */
+	int cnt;
+
+	for (cnt = 0; cnt < 0x10000000; cnt++) {
+		if (UGE_COMMAND & 0x1000000)
+			return;
+	}
+
+	if (cnt > 0x8000000)
+		printk(KERN_WARNING "Warning: UniGFX GE time out ...\n");
+}
+
In addition to switching to platform data for the I/O offsets, you can
also use dev_warn() here on the device pointer (fb_info->device).
+static struct fb_ops unifb_ops = {
+	.fb_read        = fb_sys_read,
+	.fb_write       = fb_sys_write,
+	.fb_check_var	= unifb_check_var,
+	.fb_set_par	= unifb_set_par,
+	.fb_setcolreg	= unifb_setcolreg,
+	.fb_pan_display	= unifb_pan_display,
+#ifdef CONFIG_PUV3_UNIGFX_HWACCEL
+	.fb_fillrect	= unifb_fillrect,
+	.fb_copyarea	= unifb_copyarea,
+	.fb_imageblit   = unifb_imageblit,
+#else
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+	.fb_imageblit	= sys_imageblit,
+#endif
+	.fb_mmap	= unifb_mmap,
+};
+
There's no need for the ifdef here, all of your accel routines manually
check if acceleration is disabled or not and fall back on the sys_xxx()
paths, so it's safe to always reference them.
+static int unifb_set_par(struct fb_info *info)
+{
+	int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd;
+	int format;
+
+#ifdef CONFIG_PUV3_PM
+	struct clk *clk_vga;
+	u32 pixclk = 0;
+	int i;
+
+	for (i = 0; i <= 10; i++) {
+		if    (info->var.xres         = unifb_modes[i].xres
+		    && info->var.yres         = unifb_modes[i].yres
+		    && info->var.upper_margin = unifb_modes[i].upper_margin
+		    && info->var.lower_margin = unifb_modes[i].lower_margin
+		    && info->var.left_margin  = unifb_modes[i].left_margin
+		    && info->var.right_margin = unifb_modes[i].right_margin
+		    && info->var.hsync_len    = unifb_modes[i].hsync_len
+		    && info->var.vsync_len    = unifb_modes[i].vsync_len) {
+			pixclk = unifb_modes[i].pixclock;
+			break;
+		}
+	}
+
+	/* set clock rate */
+	clk_vga = clk_get(NULL, "VGA_CLK");
+	i = 0;
You can pass info->device to clk_get() instead of NULL. This will make it
easier to match specific clocks and lookups per device in the future.

You'll presumably also want to check if clk_get() returned an error and
handle that accordingly.
+	if (pixclk != 0) {
+		if (clk_set_rate(clk_vga, pixclk) = 0)
+			i = 1;
+	}
+
+	if (i = 0) {           /* set clock failed */
+		info->fix = unifb_fix;
+		info->var = unifb_default;
+		clk_set_rate(clk_vga, unifb_default.pixclock);
+	}
If clk_set_rate() can fail the first time, it can fail the second time
too. You'll want more error handling here.
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return 1;
+
+		v = (red << info->var.red.offset) |
+		    (green << info->var.green.offset) |
+		    (blue << info->var.blue.offset) |
+		    (transp << info->var.transp.offset);
+		switch (info->var.bits_per_pixel) {
+		case 8:
+			break;
+		case 16:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		case 24:
+		case 32:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		}
The 16 case is no different than the 24/32 case.

The default case should also return 1 to indicate an error.
+#ifndef MODULE
+/*
+ * The virtual framebuffer driver is only enabled if explicitly
+ * requested by passing 'video=unifb:' (or any actual options).
+ */
+static int __init unifb_setup(char *options)
+{
+	char *this_opt;
+
+	unifb_enable = 0;
+
+	if (!options)
+		return 1;
+
+	unifb_enable = 1;
+
+	if (!*options)
+		return 1;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		/* Test disable for backwards compatibility */
+		if (!strcmp(this_opt, "disable"))
+			unifb_enable = 0;
+	}
+	return 1;
+}
+#endif  /*  MODULE  */
+
Just kill all of this and use the generic "off" handling.
+static int unifb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int retval = -ENOMEM;
+
+	/*
+	 * For real video cards we use ioremap.
+	 */
+	videomemory = (void *)KUSER_UNIGFX_BASE;
+
+	/*
+	 * VFB could clear memory to prevent kernel info
+	 * leakage into userspace and set black screen
+	 * VGA-based drivers MUST NOT clear memory if
+	 * they want to be able to take over vgacon
+	 */
+	/* memset(videomemory, 0, videomemorysize); */
+
This is a remnant from a vmalloc acquired framebuffer base, so can be
killed off.
+	info = framebuffer_alloc(sizeof(u32)*256, &dev->dev);
+	if (!info)
+		goto err;
+
+	info->screen_base = (char __iomem *)videomemory;
+	unifb_fix.smem_start = PKUNITY_UNIGFX_MMAP_BASE;
+	unifb_fix.smem_len = videomemorysize;
+	unifb_fix.mmio_start = PKUNITY_UNIGFX_BASE;
All of these should be passed in via your platform device resources, with
necessary remapping.
+	info->fix = unifb_fix;
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+	info->flags = FBINFO_FLAG_DEFAULT;
+#ifdef CONFIG_PUV3_UNIGFX_HWACCEL
+	info->fix.accel = FB_ACCEL_PUV3_UNIGFX;
+	info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+#else
+	info->flags |= FBINFO_HWACCEL_DISABLED;
+#endif
+
The accel flag is deprecated, so just drop it completely.

What happened to FBINFO_HWACCEL_IMAGEBLIT?
+#ifdef CONFIG_PM
+static int unifb_resume(struct platform_device *dev)
+{
+	int rc = 0;
+
+	if (dev->dev.power.power_state.event = PM_EVENT_ON)
+		return 0;
+
+	acquire_console_sem();
+
+	if (dev->dev.power.power_state.event = PM_EVENT_SUSPEND) {
+		UDE_FSA = unifb_regs[0];
+		UDE_LS  = unifb_regs[1];
+		UDE_PS  = unifb_regs[2];
+		UDE_HAT = unifb_regs[3];
+		UDE_HBT = unifb_regs[4];
+		UDE_HST = unifb_regs[5];
+		UDE_VAT = unifb_regs[6];
+		UDE_VBT = unifb_regs[7];
+		UDE_VST = unifb_regs[8];
+		UDE_CFG = unifb_regs[9];
+	}
This is probably worth abstracting through platform data.
+
+static int __init unifb_init(void)
+{
+	int ret = 0;
+
+#ifndef MODULE
+	if (fb_get_options("unifb", &unifb_option))
+		return -ENODEV;
+	unifb_setup(unifb_option);
+#endif
+
+	if (!unifb_enable)
+		return -ENXIO;
+
All of this can just be replaced with:

	if (fb_get_options("unifb", NULL))
		return -ENODEV;
+	ret = platform_driver_register(&unifb_driver);
+
+	if (!ret) {
+		unifb_device = platform_device_alloc("unifb", 0);
+
+		if (unifb_device)
+			ret = platform_device_add(unifb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(unifb_device);
+			platform_driver_unregister(&unifb_driver);
+		}
+	}
+
+	return ret;
+}
+
And if your architecture will then register a platform device with the
platform data filled out, all of this can be turned in to just a simple
platform_driver_register().
+module_init(unifb_init);
+
+#ifdef MODULE
+static void __exit unifb_exit(void)
+{
+	platform_device_unregister(unifb_device);
+	platform_driver_unregister(&unifb_driver);
+}
+
+module_exit(unifb_exit);
+
+MODULE_LICENSE("GPL v2");
+#endif
No need for the ifdef here, either.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help