Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH] video/atmel_lcdfb: Fix build failure/typo for avr32
From: Wolfram Sang @ 2011-08-15 21:26 UTC (permalink / raw)
  To: Peter Hüwe
  Cc: Laurent Pinchart, Nicolas Ferre, Paul Mundt, linux-fbdev,
	linux-kernel, Stephen Rothwell
In-Reply-To: <201108151943.08347.PeterHuewe@gmx.de>

[-- Attachment #1: Type: text/plain, Size: 1012 bytes --]

On Mon, Aug 15, 2011 at 07:43:07PM +0200, Peter Hüwe wrote:
> Am Montag 15 August 2011, 19:31:27 schrieb Laurent Pinchart:
> > Thanks for the patch. I've already submitted the same patch
> > (https://patchwork.kernel.org/patch/990792/) nearly a month ago to the
> > linux- fbdev mailing list. Paul, can you please pick it up ?
> 
> Ah okay, didn't see it. I usually look on the lkml if the problem was already 
> fixed lately but somehow missed your patch.
> 
> Since you've done exactly what my patch did you get my 
> Reviewed-by: Peter Huewe <peterhuewe@gmx.de>

This bug was spotted during the review phase, too:

https://patchwork.kernel.org/patch/878382/

Dunno if the wrong patch was picked up or the follow up patch never came around.
Doesn't matter:

Acked-by: Wolfram Sang <w.sang@pengutronix.de>

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH] video/atmel_lcdfb: Fix build failure/typo for avr32 defconfig
From: Peter Hüwe @ 2011-08-15 17:43 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Nicolas Ferre, Paul Mundt, linux-fbdev, linux-kernel,
	Stephen Rothwell
In-Reply-To: <201108151931.27607.laurent.pinchart@ideasonboard.com>

Am Montag 15 August 2011, 19:31:27 schrieb Laurent Pinchart:
> Thanks for the patch. I've already submitted the same patch
> (https://patchwork.kernel.org/patch/990792/) nearly a month ago to the
> linux- fbdev mailing list. Paul, can you please pick it up ?

Ah okay, didn't see it. I usually look on the lkml if the problem was already 
fixed lately but somehow missed your patch.

Since you've done exactly what my patch did you get my 
Reviewed-by: Peter Huewe <peterhuewe@gmx.de>

Thanks,
Peter



^ permalink raw reply

* [RFC PATCH] Resurrect Intel740 driver: i740fb
From: Ondrej Zary @ 2011-08-15 17:34 UTC (permalink / raw)
  To: linux-fbdev; +Cc: Kernel development list, Paul Mundt

Hello,
this is an attempt to resurrect an old (like 2.4.19) out-of-tree driver for
Intel740 graphics cards and modify it for recent kernels. The old driver is
located at: http://sourceforge.net/projects/i740fbdev/files/

It was easier to create a new driver based on skeletonfb, using most of the
low level HW code from the old driver. The DDC code is completely new.

The driver works great for console (it's pretty fast, although only ypan is 
implemented, no blits). There are some bugs still left (colors are wrong in
fbtest with 16bpp 555 and 24bpp modes, 1280x1024-32 does not work).

The i740_calc_fifo() function formatting is nice but does not pass
checkpatch. Making it checkpatch-compliant makes the code look ugly. How to
make it both nice and compatible with Linux coding style?
(the remaining // comments mark things that need attention - missing xpan
and suspend/resume)

no signed-off-by yet

--- linux-2.6.39-rc2-orig/drivers/video/Kconfig	2011-04-06 03:30:43.000000000 +0200
+++ linux-2.6.39-rc2/drivers/video/Kconfig	2011-07-30 11:34:10.000000000 +0200
@@ -1117,6 +1117,17 @@ config FB_RIVA_BACKLIGHT
 	help
 	  Say Y here if you want to control the backlight of your display.
 
+config FB_I740
+	tristate "Intel740 support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select VGASTATE
+	help
+	  This driver supports graphics cards based on Intel740 chip.
+
 config FB_I810
 	tristate "Intel 810/815 support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
--- /dev/null	2011-08-15 18:11:24.797068032 +0200
+++ linux-2.6.39-rc2/drivers/video/i740fb.c	2011-08-14 22:51:31.000000000 +0200
@@ -0,0 +1,1262 @@
+/*
+ * i740fb - framebuffer driver for Intel740
+ * Copyright (c) 2011 Ondrej Zary
+ *
+ * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru> which was partially based on:
+ *  VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ *  i740fb by Patrick LERDA, v0.9
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "i740_reg.h"
+
+static char *mode_option __devinitdata;
+
+#ifdef CONFIG_MTRR
+static int mtrr __devinitdata = 1;
+#endif
+
+struct i740fb_par {
+	unsigned char __iomem *regs;
+	bool has_sgram;
+#ifdef CONFIG_MTRR
+	int mtrr_reg;
+#endif
+	bool ddc_registered;
+	struct i2c_adapter ddc_adapter;
+	struct i2c_algo_bit_data ddc_algo;
+	u32 pseudo_palette[16];
+
+	u8 crtc[VGA_CRT_C];
+	u8 atc[VGA_ATT_C];
+	u8 gdc[VGA_GFX_C];
+	u8 seq[VGA_SEQ_C];
+	u8 misc;
+	u8 vss;
+
+	/* i740 specific registers */
+	u8 display_cntl;
+	u8 pixelpipe_cfg0;
+	u8 pixelpipe_cfg1;
+	u8 pixelpipe_cfg2;
+	u8 video_clk2_m;
+	u8 video_clk2_n;
+	u8 video_clk2_mn_msbs;
+	u8 video_clk2_div_sel;
+	u8 pll_cntl;
+	u8 address_mapping;
+	u8 io_cntl;
+	u8 bitblt_cntl;
+	u8 ext_vert_total;
+	u8 ext_vert_disp_end;
+	u8 ext_vert_sync_start;
+	u8 ext_vert_blank_start;
+	u8 ext_horiz_total;
+	u8 ext_horiz_blank;
+	u8 ext_offset;
+	u8 interlace_cntl;
+	u32 lmi_fifo_watermark;
+	u8 ext_start_addr;
+	u8 ext_start_addr_hi;
+};
+
+#define DACSPEED8	203
+#define DACSPEED16	163
+#define DACSPEED24_SG	136
+#define DACSPEED24_SD	128
+#define DACSPEED32	86
+
+static struct fb_fix_screeninfo i740fb_fix __devinitdata = {
+	.id =		"i740fb",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+//	.xpanstep =	1,
+	.ypanstep =	1,
+	.accel =	FB_ACCEL_NONE,
+};
+
+static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
+{
+	vga_mm_w(par->regs, port, val);
+}
+static inline u8 i740inb(struct i740fb_par *par, u16 port)
+{
+	return vga_mm_r(par->regs, port);
+}
+static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
+{
+	vga_mm_w_fast(par->regs, port, reg, val);
+}
+static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
+{
+	vga_mm_w(par->regs, port, reg);
+	return vga_mm_r(par->regs, port+1);
+}
+static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg, u8 val, u8 mask)
+{
+	vga_mm_w_fast(par->regs, port, reg, (val & mask) | (i740inreg(par, port, reg) & ~mask));
+}
+static inline void i740outb_p(struct i740fb_par *par, u16 port, u8 val)
+{
+	vga_mm_w(par->regs, port, val);
+}
+static inline u8 i740inb_p(struct i740fb_par *par, unsigned short port)
+{
+	return vga_mm_r(par->regs, port);
+}
+
+#define REG_DDC_DRIVE	0x62
+#define REG_DDC_STATE	0x63
+#define DDC_SCL		(1 << 3)
+#define DDC_SDA		(1 << 2)
+
+static void i740fb_ddc_setscl(void *data, int val)
+{
+	struct i740fb_par *par = data;
+	unsigned char reg;
+
+	i740outreg(par, XRX, REG_DDC_DRIVE,
+		i740inreg(par, XRX, REG_DDC_DRIVE) | DDC_SCL);
+
+	reg = i740inreg(par, XRX, REG_DDC_STATE);
+	if (val)
+		reg |= DDC_SCL;
+	else
+		reg &= ~DDC_SCL;
+	i740outreg(par, XRX, REG_DDC_STATE, reg);
+}
+
+static void i740fb_ddc_setsda(void *data, int val)
+{
+	struct i740fb_par *par = data;
+	unsigned char reg;
+
+	i740outreg(par, XRX, REG_DDC_DRIVE,
+		i740inreg(par, XRX, REG_DDC_DRIVE) | DDC_SDA);
+
+	reg = i740inreg(par, XRX, REG_DDC_STATE);
+	if (val)
+		reg |= DDC_SDA;
+	else
+		reg &= ~DDC_SDA;
+	i740outreg(par, XRX, REG_DDC_STATE, reg);
+}
+
+static int i740fb_ddc_getscl(void *data)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg(par, XRX, REG_DDC_DRIVE,
+		i740inreg(par, XRX, REG_DDC_DRIVE) & ~DDC_SCL);
+
+	return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
+}
+
+static int i740fb_ddc_getsda(void *data)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg(par, XRX, REG_DDC_DRIVE,
+		i740inreg(par, XRX, REG_DDC_DRIVE) & ~DDC_SDA);
+
+	return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
+}
+
+static int __devinit i740fb_setup_ddc_bus(struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+
+	strlcpy(par->ddc_adapter.name, info->fix.id,
+		sizeof(par->ddc_adapter.name));
+	par->ddc_adapter.owner		= THIS_MODULE;
+	par->ddc_adapter.class		= I2C_CLASS_DDC;
+	par->ddc_adapter.algo_data	= &par->ddc_algo;
+	par->ddc_adapter.dev.parent	= info->device;
+	par->ddc_algo.setsda		= i740fb_ddc_setsda;
+	par->ddc_algo.setscl		= i740fb_ddc_setscl;
+	par->ddc_algo.getsda		= i740fb_ddc_getsda;
+	par->ddc_algo.getscl		= i740fb_ddc_getscl;
+	par->ddc_algo.udelay		= 10;
+	par->ddc_algo.timeout		= 20;
+	par->ddc_algo.data		= par;
+
+	i2c_set_adapdata(&par->ddc_adapter, par);
+
+	return i2c_bit_add_bus(&par->ddc_adapter);
+}
+
+/**
+ *	i740fb_open - Optional function. Called when the framebuffer is
+ *			 first accessed.
+ *	@info: frame buffer structure that represents a single frame buffer
+ *	@user: tell us if the userland (value=1) or the console is accessing
+ *		   the framebuffer.
+ *
+ *	This function is the first function called in the framebuffer api.
+ *	Usually you don't need to provide this function. The case where it
+ *	is used is to change from a text mode hardware state to a graphics
+ *	mode state.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int i740fb_open(struct fb_info *info, int user)
+{
+	return 0;
+}
+
+/**
+ *	i740fb_release - Optional function. Called when the framebuffer
+ *			device is closed.
+ *	@info: frame buffer structure that represents a single frame buffer
+ *	@user: tell us if the userland (value=1) or the console is accessing
+ *		   the framebuffer.
+ *
+ *	Thus function is called when we close /dev/fb or the framebuffer
+ *	console system is released. Usually you don't need this function.
+ *	The case where it is usually used is to go from a graphics state
+ *	to a text mode state.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int i740fb_release(struct fb_info *info, int user)
+{
+	return 0;
+}
+
+static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
+{
+	/*
+	 * Would like to calculate these values automatically, but a generic
+	 * algorithm does not seem possible.  Note: These FIFO water mark
+	 * values were tested on several cards and seem to eliminate the
+	 * all of the snow and vertical banding, but fine adjustments will
+	 * probably be required for other cards.
+	 */
+
+	u32 wm = 0x18120000;
+
+	switch (bpp) {
+	case 8:
+		if	(freq > 200) wm = 0x18120000;
+		else if (freq > 175) wm = 0x16110000;
+		else if (freq > 135) wm = 0x120E0000;
+		else		     wm = 0x100D0000;
+		break;
+	case 15:
+	case 16:
+		if (par->has_sgram) {
+			if	(freq > 140) wm = 0x2C1D0000;
+			else if (freq > 120) wm = 0x2C180000;
+			else if (freq > 100) wm = 0x24160000;
+			else if (freq >  90) wm = 0x18120000;
+			else if (freq >  50) wm = 0x16110000;
+			else if (freq >  32) wm = 0x13100000;
+			else		     wm = 0x120E0000;
+		} else {
+			if	(freq > 160) wm = 0x28200000;
+			else if (freq > 140) wm = 0x2A1E0000;
+			else if (freq > 130) wm = 0x2B1A0000;
+			else if (freq > 120) wm = 0x2C180000;
+			else if (freq > 100) wm = 0x24180000;
+			else if (freq >  90) wm = 0x18120000;
+			else if (freq >  50) wm = 0x16110000;
+			else if (freq >  32) wm = 0x13100000;
+			else		     wm = 0x120E0000;
+		}
+		break;
+	case 24:
+		if (par->has_sgram) {
+			if	(freq > 130) wm = 0x31200000;
+			else if (freq > 120) wm = 0x2E200000;
+			else if (freq > 100) wm = 0x2C1D0000;
+			else if (freq >  80) wm = 0x25180000;
+			else if (freq >  64) wm = 0x24160000;
+			else if (freq >  49) wm = 0x18120000;
+			else if (freq >  32) wm = 0x16110000;
+			else		     wm = 0x13100000;
+		} else {
+			if	(freq > 120) wm = 0x311F0000;
+			else if (freq > 100) wm = 0x2C1D0000;
+			else if (freq >  80) wm = 0x25180000;
+			else if (freq >  64) wm = 0x24160000;
+			else if (freq >  49) wm = 0x18120000;
+			else if (freq >  32) wm = 0x16110000;
+			else		     wm = 0x13100000;
+		}
+		break;
+	case 32:
+		if (par->has_sgram) {
+			if	(freq >  80) wm = 0x2A200000;
+			else if (freq >  60) wm = 0x281A0000;
+			else if (freq >  49) wm = 0x25180000;
+			else if (freq >  32) wm = 0x18120000;
+			else		     wm = 0x16110000;
+		} else {
+			if	(freq >  80) wm = 0x29200000;
+			else if (freq >  60) wm = 0x281A0000;
+			else if (freq >  49) wm = 0x25180000;
+			else if (freq >  32) wm = 0x18120000;
+			else		     wm = 0x16110000;
+		}
+		break;
+	}
+
+	return wm;
+}
+
+/* clock calculation from i740fb by Patrick LERDA */
+
+#define I740_RFREQ (1e6)
+#define TARGET_MAX_N 30
+
+#define I740_FFIX		8
+#define I740_REF_FREQ		(u32) (66.66666666667 * (1 << I740_FFIX) + 0.5)
+#define I740_MAX_VCO_FREQ	(u32)(450.00000000000 * (1 << I740_FFIX) + 0.5)
+
+#define I740_CALC_VCLKfix(m, n, p, d)   ((((((m) * I740_REF_FREQ * (4 << ((d) << 1)))) / (n)) + ((1 << (p)) / 2)) / (1 << (p)))
+
+static void i740_calc_vclk(u32 freq_hz, struct i740fb_par *par)
+{
+	u32 freq = freq_hz / (u32)(1e6 / I740_RFREQ);
+	const u32 err_max = freq / (u32)(I740_RFREQ / 0.005 / (1 << I740_FFIX) + 0.5);
+	const u32 err_target = freq / (u32)(I740_RFREQ / 0.001 / (1 << I740_FFIX) + 0.5);
+	u32 err_best = (u32)(512.0 * (1 << I740_FFIX));
+	u32 f_err, f_vco;
+	int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
+	int m, n, i;
+
+	/* find log2(MAX_VCO_FREQ/f_target) */
+	for (i = 0; i < 16; i++)
+		if ((I740_MAX_VCO_FREQ) / (1 << i) < freq / (u32)(I740_RFREQ / (1 << I740_FFIX)))
+			break;
+	i--;
+	p_best = i;
+
+	d_best = 0;
+	f_vco = (freq * (1 << p_best)) / (u32)(I740_RFREQ / (1 << I740_FFIX));
+	freq = freq / (u32)(I740_RFREQ / (1 << I740_FFIX));
+
+	n = 2;
+	do {
+		n++;
+		m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
+
+		if (m < 3)
+			m = 3;
+
+		{
+			u32 f_out = I740_CALC_VCLKfix(m, n, p_best, d_best);
+
+			f_err = (freq - f_out);
+
+			if (abs(f_err) < err_max) {
+				m_best = m;
+				n_best = n;
+				err_best = f_err;
+			}
+		}
+	} while ((abs(f_err) >= err_target) &&
+		 ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
+
+	if (abs(f_err) < err_target) {
+		m_best = m;
+		n_best = n;
+	}
+
+	par->video_clk2_m = (m_best-2) & 0xFF;
+	par->video_clk2_n = (n_best-2) & 0xFF;
+	par->video_clk2_mn_msbs = ((((n_best-2) >> 4) & VCO_N_MSBS) |
+				 (((m_best-2) >> 8) & VCO_M_MSBS));
+	par->video_clk2_div_sel = ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1);
+}
+
+static int i740fb_decode_var(const struct fb_var_screeninfo *var, struct i740fb_par *par, struct fb_info *info)
+{
+	/*
+	 *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+	 *  if it's too big, return -EINVAL.
+	 */
+
+	u32 xres, right, hslen, left, xtotal;
+	u32 yres, lower, vslen, upper, ytotal;
+	u32 vxres, xoffset, vyres, yoffset;
+	u32 bpp, base, dacspeed24;
+	u8 r7;
+	int i;
+
+	dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
+		  var->xres, var->yres, var->xres_virtual, var->xres_virtual);
+	dev_dbg(info->device, "	xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
+		  var->xoffset, var->yoffset, var->bits_per_pixel, var->grayscale);
+	dev_dbg(info->device, "	activate: %i, nonstd: %i, vmode: %i\n",
+		  var->activate, var->nonstd, var->vmode);
+	dev_dbg(info->device, "	pixclock: %i, hsynclen:%i, vsynclen:%i\n",
+		  var->pixclock, var->hsync_len, var->vsync_len);
+	dev_dbg(info->device, "	left: %i, right: %i, up:%i, lower:%i\n",
+		  var->left_margin, var->right_margin, var->upper_margin, var->lower_margin);
+
+
+	bpp = var->bits_per_pixel;
+	switch (bpp) {
+	case 1 ... 8:
+		bpp = 8;
+		if ((((u32)1e6) / var->pixclock) > DACSPEED8) {
+			dev_dbg(info->device, "var->pixclock: %i, DACSPEED8: %i\n", var->pixclock, DACSPEED8);
+			return -EINVAL;
+		}
+		break;
+	case 9 ... 15:
+		bpp = 15;
+	case 16:
+		if ((((u32)1e6) / var->pixclock) > DACSPEED16) {
+			dev_dbg(info->device, "var->pixclock: %i, DACSPEED16: %i\n", var->pixclock, DACSPEED16);
+			return -EINVAL;
+		}
+		break;
+	case 17 ... 24:
+		bpp = 24;
+		dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
+		if ((((u32)1e6) / var->pixclock) > dacspeed24) {
+			dev_dbg(info->device, "var->pixclock: %i, DACSPEED24: %i\n", var->pixclock, dacspeed24);
+			return -EINVAL;
+		}
+		break;
+	case 25 ... 32:
+		bpp = 32;
+		if ((((u32)1e6) / var->pixclock) > DACSPEED32) {
+			dev_dbg(info->device, "var->pixclock: %i, DACSPEED32: %i\n", var->pixclock, DACSPEED32);
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	xres = (var->xres + 7) & ~7;
+	vxres = (var->xres_virtual + 0xF) & ~0xF;
+	if (vxres < xres)
+		vxres = xres;
+
+	//xoffset = (var->xoffset + 7) & ~7;
+	xoffset = var->xoffset;
+	if (xres + xoffset > vxres)
+		xoffset = vxres - xres;
+
+	left = (var->left_margin + 7) & ~7;
+	right = (var->right_margin + 7) & ~7;
+	hslen = (var->hsync_len + 7) & ~7;
+
+	yres = var->yres;
+	vyres = var->yres_virtual;
+	if (yres > vyres)
+		vyres = yres;
+
+	yoffset = var->yoffset;
+	if (yres + yoffset > vyres)
+		yoffset = vyres - yres;
+
+	lower = var->lower_margin;
+	vslen = var->vsync_len;
+	upper = var->upper_margin;
+
+	if (vxres * vyres * ((bpp + 1) / 8) > info->screen_size || vyres = yres) {
+		vyres = info->screen_size / vxres / ((bpp + 1) / 8);
+		if (vyres < yres)
+			return -ENOMEM;
+	}
+
+	if (yoffset + yres > vyres)
+		yoffset = vyres - yres;
+
+	xtotal = xres + right + hslen + left;
+	ytotal = yres + lower + vslen + upper;
+
+	par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5;
+	par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1;
+	par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1;
+	par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3;
+	par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F)
+		| ((((xres + right + hslen) >> 3) & 0x20) << 2);
+	par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F) | 0x80;
+
+	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
+
+	r7 = 0x10;	/* disable linecompare */
+	if (ytotal & 0x100)
+		r7 |= 0x01;
+	if (ytotal & 0x200)
+		r7 |= 0x20;
+
+	par->crtc[VGA_CRTC_PRESET_ROW] = 0;
+	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */
+	if (var->vmode & FB_VMODE_DOUBLE)
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
+	par->crtc[VGA_CRTC_CURSOR_START] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
+	par->crtc[VGA_CRTC_V_DISP_END] = yres-1;
+	if ((yres-1) & 0x100)
+		r7 |= 0x02;
+	if ((yres-1) & 0x200)
+		r7 |= 0x40;
+
+	par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1;
+	par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1;
+	if ((yres + lower - 1) & 0x100)
+		r7 |= 0x0C;
+	if ((yres + lower - 1) & 0x200) {
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
+		r7 |= 0x80;
+	}
+
+	par->crtc[VGA_CRTC_V_SYNC_END] = ((yres + lower - 1 + vslen) & 0x0F) & ~0x10; /* disabled IRQ */
+	par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF; /* 0x7F for original VGA, but some SVGA chips requires all 8 bits to set */
+
+	par->crtc[VGA_CRTC_UNDERLINE] = 0x00;
+	par->crtc[VGA_CRTC_MODE] = 0xC3 ;
+	par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
+	par->crtc[VGA_CRTC_OVERFLOW] = r7;
+
+	par->vss = 0x00;	/* 3DA */
+
+	for (i = 0x00; i < 0x10; i++)
+		par->atc[i] = i;
+	par->atc[VGA_ATC_MODE] = 0x81;
+	par->atc[VGA_ATC_OVERSCAN] = 0x00;	/* 0 for EGA, 0xFF for VGA */
+	par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
+	par->atc[VGA_ATC_PEL] = xoffset & 7;
+	par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
+
+	par->misc = 0xC3;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		par->misc &= ~0x40;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		par->misc &= ~0x80;
+
+	par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
+	par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
+	par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
+	par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
+
+	par->gdc[VGA_GFX_SR_VALUE] = 0x00;
+	par->gdc[VGA_GFX_SR_ENABLE] = 0x00;
+	par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
+	par->gdc[VGA_GFX_DATA_ROTATE] = 0x00;
+	par->gdc[VGA_GFX_PLANE_READ] = 0;
+	par->gdc[VGA_GFX_MODE] = 0x02;
+	par->gdc[VGA_GFX_MISC] = 0x05;
+	par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
+	par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
+
+	base = (yoffset * vxres + (xoffset & ~7)) >> 2;
+	switch (bpp) {
+	case 8:
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 3;
+		par->ext_offset = vxres >> 11;
+		par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE;
+		par->bitblt_cntl = COLEXP_8BPP;
+		break;
+	case 15:
+		/* 0rrrrrgg gggbbbbb */
+		par->pixelpipe_cfg1 = DISPLAY_15BPP_MODE;
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
+		par->ext_offset = vxres >> 10;
+		par->bitblt_cntl = COLEXP_16BPP;
+		base *= 2;
+		break;
+	case 16:
+		/* rrrrrggg gggbbbbb */
+		par->pixelpipe_cfg1 = DISPLAY_16BPP_MODE;
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
+		par->ext_offset = vxres >> 10;
+		par->bitblt_cntl = COLEXP_16BPP;
+		base *= 2;
+		break;
+	case 24:
+		par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3;
+		par->ext_offset = (vxres * 3) >> 11;
+		par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE;
+		par->bitblt_cntl = COLEXP_24BPP;
+		base &= 0xFFFFFFFE; /* ...ignore the last bit. */
+		base *= 3;
+		break;
+	case 32:
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
+		par->ext_offset = vxres >> 9;
+		par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE;
+		par->bitblt_cntl = COLEXP_RESERVED; /* Not implemented on i740 */
+		base *= 4;
+		break;
+	}
+
+	par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
+	par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
+	par->ext_start_addr = ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
+	par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
+
+	par->pixelpipe_cfg0 = DAC_8_BIT;
+
+	par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE;
+	par->io_cntl = EXTENDED_CRTC_CNTL;
+	par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
+	par->display_cntl = HIRES_MODE;
+
+	/* Set the MCLK freq */
+	par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
+
+	/* Calculate the extended CRTC regs */
+	par->ext_vert_total = (ytotal - 2) >> 8;
+	par->ext_vert_disp_end = (yres - 1) >> 8;
+	par->ext_vert_sync_start = (yres + lower) >> 8;
+	par->ext_vert_blank_start = (yres + lower) >> 8;
+	par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8;
+	par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6;
+
+	par->interlace_cntl = INTERLACE_DISABLE;
+
+	/* Set the overscan color to 0. (NOTE: This only affects >8bpp mode.) */
+	par->atc[VGA_ATC_OVERSCAN] = 0;
+
+	/* Calculate VCLK that most closely matches the requested dot clock */
+	i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par);
+
+	/* Since we program the clocks ourselves, always use VCLK2. */
+	par->misc |= 0x0C;
+
+	/* Calculate the FIFO Watermark and Burst Length. */
+	par->lmi_fifo_watermark = i740_calc_fifo(par, ((int)1e6) / var->pixclock, bpp);
+
+	/*if (!fbmon_valid_timings(var->pixclock, ytotal, xtotal, info))
+	return -EINVAL;*/
+
+	return 0;
+}
+
+static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset	= var->green.offset = var->blue.offset = 0;
+		var->red.length	= var->green.length = var->blue.length = 8;
+//		var->xres_virtual = ((u32)par->ext_offset << 11)
+//			| ((u32)par->crtc[VGA_CRTC_OFFSET] << 3);
+		break;
+	case 16:
+		switch (var->green.length) {
+		default:
+		case 5:
+			var->red.offset = 10;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length	= var->green.length = var->blue.length = 5;
+//			startaddr /= 2;
+//			var->xres_virtual = ((u32)par->ext_offset << 10)
+//				| ((u32)par->crtc[VGA_CRTC_OFFSET] << 2);
+			break;
+		case 6:
+			var->red.offset = 11;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->green.length = 6;
+			var->red.length = var->blue.length = 5;
+//			startaddr /= 2;
+//			var->xres_virtual = ((u32)par->ext_offset << 10)
+//				| ((u32)par->crtc[VGA_CRTC_OFFSET] << 2);
+			break;
+		}
+		break;
+	case 24:
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length	= var->green.length = var->blue.length = 8;
+//		startaddr /= 3;
+//		startaddr &= 0xFFFFFFFE;
+//		var->xres_virtual = (((u32)par->ext_offset << 11)
+//			 | ((u32)par->crtc[VGA_CRTC_OFFSET] << 3))/3;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->transp.length = var->red.length = var->green.length = var->blue.length = 8;
+//		startaddr /= 4;
+//		var->xres_virtual = ((u32)par->ext_offset << 9)
+//			| ((u32)par->crtc[VGA_CRTC_OFFSET] << 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (var->xres != var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	var->yres_virtual = info->screen_size / var->xres_virtual / ((var->bits_per_pixel+1)/8);
+
+	if (info->monspecs.hfmax && info->monspecs.vfmax &&
+	    info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void vga_protect(struct i740fb_par *par)
+{
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, i740inreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE) | 0x20);	/* disable the display */
+
+	i740inb(par, 0x3DA);
+	i740outb(par, VGA_ATT_W, 0x00);	/* enable pallete access */
+}
+
+static void vga_unprotect(struct i740fb_par *par)
+{
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, i740inreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE) & 0xDF);	/* reenable display */
+
+	i740inb(par, 0x3DA);
+	i740outb(par, VGA_ATT_W, 0x20);	/* disable pallete access */
+}
+
+static int i740fb_set_par(struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+	u32 itemp;
+	int i;
+
+	memset(info->screen_base, 0, info->screen_size);
+
+	i740fb_decode_var(&info->var, par, info);
+
+	vga_protect(par);
+
+	i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
+
+	mdelay(1);
+
+	i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
+	i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
+	i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
+	i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
+
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
+
+	i740inb(par, 0x3DA);
+	i740outb(par, 0x3C0, 0x00);
+
+	/* update misc output register */
+	i740outb(par, VGA_MIS_W, par->misc | 0x01);
+
+	/* synchronous reset on */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
+	/* write sequencer registers */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, par->seq[1] | 0x20);
+	for (i = 2; i < VGA_SEQ_C; i++)
+		i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
+
+	/* synchronous reset off */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
+
+	/* deprotect CRT registers 0-7 */
+	i740outreg(par, VGA_CRT_IC, 0x11, par->crtc[0x11]);
+
+	/* write CRT registers */
+	for (i = 0; i < VGA_CRT_C; i++)
+		i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
+
+	/* write graphics controller registers */
+	for (i = 0; i < VGA_GFX_C; i++)
+		i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
+
+	/* write attribute controller registers */
+	for (i = 0; i < VGA_ATT_C; i++) {
+		i740inb_p(par, VGA_IS1_RC);		/* reset flip-flop */
+		i740outb_p(par, VGA_ATT_IW, i);
+		i740outb_p(par, VGA_ATT_IW, par->atc[i]);
+	}
+
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, par->seq[1]);
+
+	i740inb(par, VGA_IS1_RC);
+	i740outb(par, VGA_ATT_IW, 0x20);
+
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START, par->ext_vert_sync_start);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START, par->ext_vert_blank_start);
+	i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
+	i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
+	i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
+
+	i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL, par->interlace_cntl, INTERLACE_ENABLE);
+	i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
+	i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
+	i740outreg_mask(par, XRX, DISPLAY_CNTL, par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
+
+	i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
+
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1, par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
+
+	itemp = readl(par->regs + FWATER_BLC);
+	itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
+	itemp |= par->lmi_fifo_watermark;
+	writel(itemp, par->regs + FWATER_BLC);
+
+	i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
+
+	i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
+	i740outreg_mask(par, XRX, IO_CTNL, par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
+
+	if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
+		i740outb(par, VGA_PEL_MSK, 0xFF);
+		i740outb(par, VGA_PEL_IW, 0x00);
+		for (i = 0; i < 256; i++) {
+			i740outb_p(par, VGA_PEL_D, (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2);
+			i740outb_p(par, VGA_PEL_D, (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2);
+			i740outb_p(par, VGA_PEL_D, (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2);
+		}
+	}
+
+	/* Wait for screen to stabilize. */
+	mdelay(50);
+	vga_unprotect(par);
+
+	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
+	if (info->var.bits_per_pixel = 8)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	return 0;
+}
+
+static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n", regno, red, green, blue, transp, info->var.bits_per_pixel);
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		if (regno >= 256)
+			return 1;
+		i740outb(info->par, VGA_PEL_IW, regno);
+		i740outb(info->par, VGA_PEL_D, red >> 8);
+		i740outb(info->par, VGA_PEL_D, green >> 8);
+		i740outb(info->par, VGA_PEL_D, blue >> 8);
+		break;
+	case 15:
+	case 16:
+		if (regno >= 16)
+			return 0;
+		((u32 *)info->pseudo_palette)[regno] = (red & 0xF800) |
+			((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+		break;
+	case 24:
+	case 32:
+		if (regno >= 16)
+			return 0;
+		((u32 *)info->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+			(green & 0xFF00) | ((blue & 0xFF00) >> 8);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int i740fb_pan_display(struct fb_var_screeninfo *var,
+				 struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+	u32 base = (var->yoffset * var->xres_virtual + (var->xoffset & ~7)) >> 2;
+
+	dev_dbg(info->device, "pan_display: xoffset: %i, yoffset: %i base: %i\n", var->xoffset, var->yoffset, base);
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		break;
+	case 15:
+	case 16:
+		base *= 2;
+		break;
+	case 24:
+		/*
+		 * The last bit does not seem to have any effect on the start
+		 * address register in 24bpp mode, so...
+		 */
+		base &= 0xFFFFFFFE; /* ...ignore the last bit. */
+		base *= 3;
+		break;
+	case 32:
+		base *= 4;
+		break;
+	}
+
+	par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
+	par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
+	par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
+	par->ext_start_addr = ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
+	par->atc[VGA_ATC_PEL] = var->xoffset & 7;
+
+	i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO,  base & 0x000000FF);
+	i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI, (base & 0x0000FF00) >>  8);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, (base & 0x3FC00000) >> 22);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
+	//i740outreg(par, VGA_ATT_W, VGA_ATC_PEL, var->xoffset & 7);
+
+	return 0;
+}
+
+static int i740fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+
+	unsigned char SEQ01;
+	int DPMSSyncSelect;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		SEQ01 = 0x00;
+		DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
+		break;
+	case FB_BLANK_POWERDOWN:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Turn the screen on/off */
+	i740outb(par, SRX, 0x01);
+	SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
+	i740outb(par, SRX, 0x01);
+	i740outb(par, SRX + 1, SEQ01);
+
+	/* Set the DPMS mode */
+	i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
+
+	/* Let fbcon do a soft blank for us */
+	return (blank_mode = FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+static struct fb_ops i740fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= i740fb_open,
+	.fb_release	= i740fb_release,
+	.fb_check_var	= i740fb_check_var,
+	.fb_set_par	= i740fb_set_par,
+	.fb_setcolreg	= i740fb_setcolreg,
+	.fb_blank	= i740fb_blank,
+	.fb_pan_display	= i740fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit i740fb_probe(struct pci_dev *dev,
+				  const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct i740fb_par *par;
+	int ret;
+	bool found = false;
+	u8 *edid;
+
+	info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
+	if (!info) {
+		dev_err(&(dev->dev), "cannot allocate framebuffer\n");
+		return -ENOMEM;
+	}
+
+	par = info->par;
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.bits_per_pixel = 8;
+	info->fbops = &i740fb_ops;
+	info->pseudo_palette = par->pseudo_palette;
+
+	ret = pci_enable_device(dev);
+	if (ret) {
+		dev_err(info->device, "cannot enable PCI device\n");
+		goto err_enable_device;
+	}
+
+	ret = pci_request_regions(dev, info->fix.id);
+	if (ret) {
+		dev_err(info->device, "error requesting regions\n");
+		goto err_request_regions;
+	}
+
+	info->screen_base = pci_ioremap_bar(dev, 0);
+	if (!info->screen_base) {
+		dev_err(info->device, "error remapping base\n");
+		ret = -ENOMEM;
+		goto err_ioremap_1;
+	}
+
+	par->regs = pci_ioremap_bar(dev, 1);
+	if (!par->regs) {
+		dev_err(info->device, "error remapping MMIO\n");
+		ret = -ENOMEM;
+		goto err_ioremap_2;
+	}
+
+	/* detect memory size */
+	if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1) = DRAM_ROW_1_SDRAM)
+		i740outb(par, XRX, DRAM_ROW_BNDRY_1);
+	else
+		i740outb(par, XRX, DRAM_ROW_BNDRY_0);
+	info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
+	/* detect memory type */
+	par->has_sgram = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
+	par->has_sgram = !((par->has_sgram & DRAM_RAS_TIMING) ||
+			   (par->has_sgram & DRAM_RAS_PRECHARGE));
+
+	printk(KERN_INFO "fb%d: Intel740 on %s, %ld KB %s\n", info->node,
+		pci_name(dev), info->screen_size >> 10,
+		par->has_sgram ? "SGRAM" : "SDRAM");
+
+	info->fix = i740fb_fix;
+	info->fix.mmio_start = pci_resource_start(dev, 1);
+	info->fix.mmio_len = pci_resource_len(dev, 1);
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = info->screen_size;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	if (i740fb_setup_ddc_bus(info) = 0) {
+		par->ddc_registered = true;
+		edid = fb_ddc_read(&par->ddc_adapter);
+		if (edid) {
+			fb_edid_to_monspecs(edid, &info->monspecs);
+			kfree(edid);
+			if (!info->monspecs.modedb)
+				dev_err(info->device, "error getting mode database\n");
+			else {
+				const struct fb_videomode *m;
+
+				fb_videomode_to_modelist(info->monspecs.modedb,
+							 info->monspecs.modedb_len,
+							 &info->modelist);
+				m = fb_find_best_display(&info->monspecs, &info->modelist);
+				if (m) {
+					fb_videomode_to_var(&info->var, m);
+					/* fill all other info->var's fields */
+					if (i740fb_check_var(&info->var, info) = 0)
+						found = true;
+				}
+			}
+		}
+	}
+
+	if (!mode_option && !found)
+		mode_option = "640x480-8@60";
+
+	if (mode_option) {
+		ret = fb_find_mode(&info->var, info, mode_option,
+				   info->monspecs.modedb, info->monspecs.modedb_len,
+				   NULL, info->var.bits_per_pixel);
+		if (!ret || ret = 4) {
+			dev_err(info->device, "mode %s not found\n", mode_option);
+			ret = -EINVAL;
+		}
+	}
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	if (ret = -EINVAL)
+		goto err_find_mode;
+
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret) {
+		dev_err(info->device, "cannot allocate colormap\n");
+		goto err_alloc_cmap;
+	}
+
+	ret = register_framebuffer(info);
+	if (ret) {
+		dev_err(info->device, "error registering framebuffer\n");
+		goto err_reg_framebuffer;
+	}
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
+	pci_set_drvdata(dev, info);
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		par->mtrr_reg = -1;
+		par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+	}
+#endif
+	return 0;
+
+err_reg_framebuffer:
+	fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+	if (par->ddc_registered)
+		i2c_del_adapter(&par->ddc_adapter);
+	pci_iounmap(dev, par->regs);
+err_ioremap_2:
+	pci_iounmap(dev, info->screen_base);
+err_ioremap_1:
+	pci_release_regions(dev);
+err_request_regions:
+/*	pci_disable_device(dev); */
+err_enable_device:
+	framebuffer_release(info);
+	return ret;
+}
+
+static void __devexit i740fb_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+
+	if (info) {
+#ifdef CONFIG_MTRR
+		struct i740fb_par *par = info->par;
+
+		if (par->mtrr_reg >= 0) {
+			mtrr_del(par->mtrr_reg, 0, 0);
+			par->mtrr_reg = -1;
+		}
+#endif
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+		if (par->ddc_registered)
+			i2c_del_adapter(&par->ddc_adapter);
+		pci_iounmap(dev, par->regs);
+		pci_iounmap(dev, info->screen_base);
+		pci_release_regions(dev);
+/*		pci_disable_device(dev); */
+		pci_set_drvdata(dev, NULL);
+		framebuffer_release(info);
+	}
+}
+
+#ifdef CONFIG_PM
+static int i740fb_suspend(struct pci_dev *dev, pm_message_t msg)
+{
+	////////////////////////////////// TODO
+	return 0;
+}
+
+static int i740fb_resume(struct pci_dev *dev)
+{
+	////////////////////////////////// TODO
+	return 0;
+}
+#else
+#define i740fb_suspend NULL
+#define i740fb_resume NULL
+#endif /* CONFIG_PM */
+
+#define I740_ID_PCI 0x00d1
+#define I740_ID_AGP 0x7800
+
+static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, i740fb_id_table);
+
+static struct pci_driver i740fb_driver = {
+	.name		= "i740fb",
+	.id_table	= i740fb_id_table,
+	.probe		= i740fb_probe,
+	.remove		= __devexit_p(i740fb_remove),
+	.suspend	= i740fb_suspend,
+	.resume		= i740fb_resume,
+};
+
+#ifndef MODULE
+static int  __init i740fb_setup(char *options)
+{
+	char *opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
+#ifdef CONFIG_MTRR
+		else if (!strncmp(opt, "mtrr:", 5))
+			mtrr = simple_strtoul(opt + 5, NULL, 0);
+#endif
+		else
+			mode_option = opt;
+	}
+
+	return 0;
+}
+#endif
+
+int __init i740fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("i740fb", &option))
+		return -ENODEV;
+	i740fb_setup(option);
+#endif
+
+	return pci_register_driver(&i740fb_driver);
+}
+
+static void __exit i740fb_exit(void)
+{
+	pci_unregister_driver(&i740fb_driver);
+}
+
+module_init(i740fb_init);
+module_exit(i740fb_exit);
+
+MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for Intel740");
+
+module_param(mode_option, charp, 0444);
+MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
--- /dev/null	2011-08-15 18:11:24.797068032 +0200
+++ linux-2.6.39-rc2/drivers/video/i740_reg.h	2011-08-14 23:47:48.000000000 +0200
@@ -0,0 +1,309 @@
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Kevin E. Martin <kevin@precisioninsight.com>
+ */
+
+/* I/O register offsets */
+#define SRX VGA_SEQ_I
+#define GRX VGA_GFX_I
+#define ARX VGA_ATT_IW
+#define XRX 0x3D6
+#define MRX 0x3D2
+
+/* VGA Color Palette Registers */
+#define DACMASK		0x3C6
+#define DACSTATE	0x3C7
+#define DACRX		0x3C7
+#define DACWX		0x3C8
+#define DACDATA		0x3C9
+
+/* CRT Controller Registers (CRX) */
+#define START_ADDR_HI		0x0C
+#define START_ADDR_LO		0x0D
+#define VERT_SYNC_END		0x11
+#define EXT_VERT_TOTAL		0x30
+#define EXT_VERT_DISPLAY	0x31
+#define EXT_VERT_SYNC_START	0x32
+#define EXT_VERT_BLANK_START	0x33
+#define EXT_HORIZ_TOTAL		0x35
+#define EXT_HORIZ_BLANK		0x39
+#define EXT_START_ADDR		0x40
+#define EXT_START_ADDR_ENABLE	0x80
+#define EXT_OFFSET		0x41
+#define EXT_START_ADDR_HI	0x42
+#define INTERLACE_CNTL		0x70
+#define INTERLACE_ENABLE	0x80
+#define INTERLACE_DISABLE	0x00
+
+/* Miscellaneous Output Register */
+#define MSR_R		0x3CC
+#define MSR_W		0x3C2
+#define IO_ADDR_SELECT	0x01
+
+#define MDA_BASE	0x3B0
+#define CGA_BASE	0x3D0
+
+/* System Configuration Extension Registers (XRX) */
+#define IO_CTNL		0x09
+#define EXTENDED_ATTR_CNTL	0x02
+#define EXTENDED_CRTC_CNTL	0x01
+
+#define ADDRESS_MAPPING	0x0A
+#define PACKED_MODE_ENABLE	0x04
+#define LINEAR_MODE_ENABLE	0x02
+#define PAGE_MAPPING_ENABLE	0x01
+
+#define BITBLT_CNTL	0x20
+#define COLEXP_MODE		0x30
+#define COLEXP_8BPP		0x00
+#define COLEXP_16BPP		0x10
+#define COLEXP_24BPP		0x20
+#define COLEXP_RESERVED		0x30
+#define CHIP_RESET		0x02
+#define BITBLT_STATUS		0x01
+
+#define DISPLAY_CNTL	0x40
+#define VGA_WRAP_MODE		0x02
+#define VGA_WRAP_AT_256KB	0x00
+#define VGA_NO_WRAP		0x02
+#define GUI_MODE		0x01
+#define STANDARD_VGA_MODE	0x00
+#define HIRES_MODE		0x01
+
+#define DRAM_ROW_TYPE	0x50
+#define DRAM_ROW_0		0x07
+#define DRAM_ROW_0_SDRAM	0x00
+#define DRAM_ROW_0_EMPTY	0x07
+#define DRAM_ROW_1		0x38
+#define DRAM_ROW_1_SDRAM	0x00
+#define DRAM_ROW_1_EMPTY	0x38
+#define DRAM_ROW_CNTL_LO 0x51
+#define DRAM_CAS_LATENCY	0x10
+#define DRAM_RAS_TIMING		0x08
+#define DRAM_RAS_PRECHARGE	0x04
+#define DRAM_ROW_CNTL_HI 0x52
+#define DRAM_EXT_CNTL	0x53
+#define DRAM_REFRESH_RATE	0x03
+#define DRAM_REFRESH_DISABLE	0x00
+#define DRAM_REFRESH_60HZ	0x01
+#define DRAM_REFRESH_FAST_TEST	0x02
+#define DRAM_REFRESH_RESERVED	0x03
+#define DRAM_TIMING	0x54
+#define DRAM_ROW_BNDRY_0 0x55
+#define DRAM_ROW_BNDRY_1 0x56
+
+#define DPMS_SYNC_SELECT 0x61
+#define VSYNC_CNTL		0x08
+#define VSYNC_ON		0x00
+#define VSYNC_OFF		0x08
+#define HSYNC_CNTL		0x02
+#define HSYNC_ON		0x00
+#define HSYNC_OFF		0x02
+
+#define PIXPIPE_CONFIG_0 0x80
+#define DAC_8_BIT		0x80
+#define DAC_6_BIT		0x00
+#define HW_CURSOR_ENABLE	0x10
+#define EXTENDED_PALETTE	0x01
+
+#define PIXPIPE_CONFIG_1 0x81
+#define DISPLAY_COLOR_MODE	0x0F
+#define DISPLAY_VGA_MODE	0x00
+#define DISPLAY_8BPP_MODE	0x02
+#define DISPLAY_15BPP_MODE	0x04
+#define DISPLAY_16BPP_MODE	0x05
+#define DISPLAY_24BPP_MODE	0x06
+#define DISPLAY_32BPP_MODE	0x07
+
+#define PIXPIPE_CONFIG_2 0x82
+#define DISPLAY_GAMMA_ENABLE	0x08
+#define DISPLAY_GAMMA_DISABLE	0x00
+#define OVERLAY_GAMMA_ENABLE	0x04
+#define OVERLAY_GAMMA_DISABLE	0x00
+
+#define CURSOR_CONTROL	0xA0
+#define CURSOR_ORIGIN_SCREEN	0x00
+#define CURSOR_ORIGIN_DISPLAY	0x10
+#define CURSOR_MODE		0x07
+#define CURSOR_MODE_DISABLE	0x00
+#define CURSOR_MODE_32_4C_AX	0x01
+#define CURSOR_MODE_128_2C	0x02
+#define CURSOR_MODE_128_1C	0x03
+#define CURSOR_MODE_64_3C	0x04
+#define CURSOR_MODE_64_4C_AX	0x05
+#define CURSOR_MODE_64_4C	0x06
+#define CURSOR_MODE_RESERVED	0x07
+#define CURSOR_BASEADDR_LO 0xA2
+#define CURSOR_BASEADDR_HI 0xA3
+#define CURSOR_X_LO	0xA4
+#define CURSOR_X_HI	0xA5
+#define CURSOR_X_POS		0x00
+#define CURSOR_X_NEG		0x80
+#define CURSOR_Y_LO	0xA6
+#define CURSOR_Y_HI	0xA7
+#define CURSOR_Y_POS		0x00
+#define CURSOR_Y_NEG		0x80
+
+#define VCLK2_VCO_M	0xC8
+#define VCLK2_VCO_N	0xC9
+#define VCLK2_VCO_MN_MSBS 0xCA
+#define VCO_N_MSBS		0x30
+#define VCO_M_MSBS		0x03
+#define VCLK2_VCO_DIV_SEL 0xCB
+#define POST_DIV_SELECT		0x70
+#define POST_DIV_1		0x00
+#define POST_DIV_2		0x10
+#define POST_DIV_4		0x20
+#define POST_DIV_8		0x30
+#define POST_DIV_16		0x40
+#define POST_DIV_32		0x50
+#define VCO_LOOP_DIV_BY_4M	0x00
+#define VCO_LOOP_DIV_BY_16M	0x04
+#define REF_CLK_DIV_BY_5	0x02
+#define REF_DIV_4		0x00
+#define REF_DIV_1		0x01
+
+#define PLL_CNTL	0xCE
+#define PLL_MEMCLK_SEL		0x03
+#define PLL_MEMCLK__66667KHZ	0x00
+#define PLL_MEMCLK__75000KHZ	0x01
+#define PLL_MEMCLK__88889KHZ	0x02
+#define PLL_MEMCLK_100000KHZ	0x03
+
+/* Multimedia Extension Registers (MRX) */
+#define ACQ_CNTL_1	0x02
+#define ACQ_CNTL_2	0x03
+#define FRAME_CAP_MODE		0x01
+#define CONT_CAP_MODE		0x00
+#define SINGLE_CAP_MODE		0x01
+#define ACQ_CNTL_3	0x04
+#define COL_KEY_CNTL_1		0x3C
+#define BLANK_DISP_OVERLAY	0x20
+
+/* FIFOs */
+#define LP_FIFO		0x1000
+#define HP_FIFO		0x2000
+#define INSTPNT		0x3040
+#define LP_FIFO_COUNT	0x3040
+#define HP_FIFO_COUNT	0x3041
+
+/* FIFO Commands */
+#define CLIENT		0xE0000000
+#define CLIENT_2D	0x60000000
+
+/* Command Parser Mode Register */
+#define COMPARS		0x3038
+#define TWO_D_INST_DISABLE		0x08
+#define THREE_D_INST_DISABLE		0x04
+#define STATE_VAR_UPDATE_DISABLE	0x02
+#define PAL_STIP_DISABLE		0x01
+
+/* Interrupt Control Registers */
+#define IER		0x3030
+#define IIR		0x3032
+#define IMR		0x3034
+#define ISR		0x3036
+#define VMIINTB_EVENT		0x2000
+#define GPIO4_INT		0x1000
+#define DISP_FLIP_EVENT		0x0800
+#define DVD_PORT_DMA		0x0400
+#define DISP_VBLANK		0x0200
+#define FIFO_EMPTY_DMA_DONE	0x0100
+#define INST_PARSER_ERROR	0x0080
+#define USER_DEFINED		0x0040
+#define BREAKPOINT		0x0020
+#define DISP_HORIZ_COUNT	0x0010
+#define DISP_VSYNC		0x0008
+#define CAPTURE_HORIZ_COUNT	0x0004
+#define CAPTURE_VSYNC		0x0002
+#define THREE_D_PIPE_FLUSHED	0x0001
+
+/* FIFO Watermark and Burst Length Control Register */
+#define FWATER_BLC	0x00006000
+#define LMI_BURST_LENGTH	0x7F000000
+#define LMI_FIFO_WATERMARK	0x003F0000
+#define AGP_BURST_LENGTH	0x00007F00
+#define AGP_FIFO_WATERMARK	0x0000003F
+
+/* BitBLT Registers */
+#define SRC_DST_PITCH	0x00040000
+#define DST_PITCH		0x1FFF0000
+#define SRC_PITCH		0x00001FFF
+#define COLEXP_BG_COLOR	0x00040004
+#define COLEXP_FG_COLOR	0x00040008
+#define MONO_SRC_CNTL	0x0004000C
+#define MONO_USE_COLEXP		0x00000000
+#define MONO_USE_SRCEXP		0x08000000
+#define MONO_DATA_ALIGN		0x07000000
+#define MONO_BIT_ALIGN		0x01000000
+#define MONO_BYTE_ALIGN		0x02000000
+#define MONO_WORD_ALIGN		0x03000000
+#define MONO_DWORD_ALIGN	0x04000000
+#define MONO_QWORD_ALIGN	0x05000000
+#define MONO_SRC_INIT_DSCRD	0x003F0000
+#define MONO_SRC_RIGHT_CLIP	0x00003F00
+#define MONO_SRC_LEFT_CLIP	0x0000003F
+#define BITBLT_CONTROL	0x00040010
+#define BLTR_STATUS		0x80000000
+#define DYN_DEPTH		0x03000000
+#define DYN_DEPTH_8BPP		0x00000000
+#define DYN_DEPTH_16BPP		0x01000000
+#define DYN_DEPTH_24BPP		0x02000000
+#define DYN_DEPTH_32BPP		0x03000000	/* Not implemented on the i740 */
+#define DYN_DEPTH_ENABLE	0x00800000
+#define PAT_VERT_ALIGN		0x00700000
+#define SOLID_PAT_SELECT	0x00080000
+#define PAT_IS_IN_COLOR		0x00000000
+#define PAT_IS_MONO		0x00040000
+#define MONO_PAT_TRANSP		0x00020000
+#define COLOR_TRANSP_ROP	0x00000000
+#define COLOR_TRANSP_DST	0x00008000
+#define COLOR_TRANSP_EQ		0x00000000
+#define COLOR_TRANSP_NOT_EQ	0x00010000
+#define COLOR_TRANSP_ENABLE	0x00004000
+#define MONO_SRC_TRANSP		0x00002000
+#define SRC_IS_IN_COLOR		0x00000000
+#define SRC_IS_MONO		0x00001000
+#define SRC_USE_SRC_ADDR	0x00000000
+#define SRC_USE_BLTDATA		0x00000400
+#define BLT_TOP_TO_BOT		0x00000000
+#define BLT_BOT_TO_TOP		0x00000200
+#define BLT_LEFT_TO_RIGHT	0x00000000
+#define BLT_RIGHT_TO_LEFT	0x00000100
+#define BLT_ROP			0x000000FF
+#define BLT_PAT_ADDR	0x00040014
+#define BLT_SRC_ADDR	0x00040018
+#define BLT_DST_ADDR	0x0004001C
+#define BLT_DST_H_W	0x00040020
+#define BLT_DST_HEIGHT		0x1FFF0000
+#define BLT_DST_WIDTH		0x00001FFF
+#define SRCEXP_BG_COLOR	0x00040024
+#define SRCEXP_FG_COLOR	0x00040028
+#define BLTDATA		0x00050000


-- 
Ondrej Zary

^ permalink raw reply

* Re: [PATCH] video/atmel_lcdfb: Fix build failure/typo for avr32 defconfig
From: Laurent Pinchart @ 2011-08-15 17:31 UTC (permalink / raw)
  To: Peter Huewe
  Cc: Nicolas Ferre, Paul Mundt, linux-fbdev, linux-kernel,
	Stephen Rothwell
In-Reply-To: <1313429190-29275-1-git-send-email-peterhuewe@gmx.de>

Hi Peter,

On Monday 15 August 2011 19:26:30 Peter Huewe wrote:
> This patch fixes a typo which causes this build failure for the
> avr32 defconfig:
> 
> drivers/video/atmel_lcdfb.c:63: error: request for member 'xres_virtual'
> in something not a structure or union
> make[3]: *** [drivers/video/atmel_lcdfb.o] Error 1
> 
> The typo was introduced by 895607ec
> "atmel_lcdfb: use display information in info not in var for panning"
> 
> KernelVersion: Linux-next 20110812
> The typo was introduced through the fbdev tree.

Thanks for the patch. I've already submitted the same patch 
(https://patchwork.kernel.org/patch/990792/) nearly a month ago to the linux-
fbdev mailing list. Paul, can you please pick it up ?

> Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
> ---
> So much for compile testing... ;)
> 
>  drivers/video/atmel_lcdfb.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index 77153c6..63409c1 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -60,7 +60,7 @@ static void atmel_lcdfb_update_dma2d(struct
> atmel_lcdfb_info *sinfo,
> 
>  	pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
> 
> -	dma2dcfg = (info-var.xres_virtual - info->var.xres)
> +	dma2dcfg = (info->var.xres_virtual - info->var.xres)
>  		 * info->var.bits_per_pixel / 8;
>  	dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
>  	lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH] video/atmel_lcdfb: Fix build failure/typo for avr32 defconfig
From: Peter Huewe @ 2011-08-15 17:26 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Nicolas Ferre, Paul Mundt, linux-fbdev, linux-kernel, peterhuewe,
	Stephen Rothwell

This patch fixes a typo which causes this build failure for the
avr32 defconfig:

drivers/video/atmel_lcdfb.c:63: error: request for member 'xres_virtual'
in something not a structure or union
make[3]: *** [drivers/video/atmel_lcdfb.o] Error 1

The typo was introduced by 895607ec
"atmel_lcdfb: use display information in info not in var for panning"

KernelVersion: Linux-next 20110812
The typo was introduced through the fbdev tree.

Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
---
So much for compile testing... ;)

 drivers/video/atmel_lcdfb.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 77153c6..63409c1 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -60,7 +60,7 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
 
 	pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
 
-	dma2dcfg = (info-var.xres_virtual - info->var.xres)
+	dma2dcfg = (info->var.xres_virtual - info->var.xres)
 		 * info->var.bits_per_pixel / 8;
 	dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
 	lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH] backlight: Fix broken regulator API usage in l4f00242t03
From: Sascha Hauer @ 2011-08-15 15:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110815130619.GB3927@opensource.wolfsonmicro.com>

On Mon, Aug 15, 2011 at 10:06:22PM +0900, Mark Brown wrote:
> On Mon, Aug 15, 2011 at 08:42:42AM +0200, Sascha Hauer wrote:
> 
> > Maybe you could change these pr_err to dev_err on the way. The rest of
> > the driver already uses dev_*.
> 
> Minimal diff and all that...

It just came to my mind because you touch the lines anyway, but I'm fine
with the posted version aswell.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH] backlight: Fix broken regulator API usage in l4f00242t03
From: Mark Brown @ 2011-08-15 14:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1313372500-28017-1-git-send-email-broonie@opensource.wolfsonmicro.com>

The regulator support in the l4f00242t03 is very non-idiomatic, rather
than requesting the regulators based on the device name and the supply
names used by the device the driver requires boards to pass system
specific supply names around through platform data. The driver also
conditionally requests the regulators based on this platform data, adding
unneeded conditional code to the driver.

Fix this by removing the platform data and converting to the standard idiom,
also updating all in tree users of the driver. As no datasheet appears to
be available for the LCD I'm guessing the names for the supplies based on
the existing users and I've no ability to do anything more than compile
test.

The use of regulator_set_voltage() in the driver is also problematic, since
fixed voltages are required the expectation would be that the voltages
would be fixed in the constraints set by the machines rather than manually
configured by the driver, but is less problematic.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 arch/arm/mach-imx/mach-mx27_3ds.c     |    6 +--
 arch/arm/mach-imx/mach-mx31_3ds.c     |    6 +--
 drivers/video/backlight/l4f00242t03.c |   57 +++++++++++---------------------
 include/linux/spi/l4f00242t03.h       |    2 -
 4 files changed, 24 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 6fa6934..08e5e20 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -241,7 +241,7 @@ static struct regulator_init_data gpo_init = {
 };
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
-	REGULATOR_SUPPLY("lcd_2v8", NULL),
+	REGULATOR_SUPPLY("vcore", "spi0.0"),
 };
 
 static struct regulator_init_data vmmc1_init = {
@@ -257,7 +257,7 @@ static struct regulator_init_data vmmc1_init = {
 };
 
 static struct regulator_consumer_supply vgen_consumers[] = {
-	REGULATOR_SUPPLY("vdd_lcdio", NULL),
+	REGULATOR_SUPPLY("vdd", "spi0.0"),
 };
 
 static struct regulator_init_data vgen_init = {
@@ -348,8 +348,6 @@ static const struct imx_fb_platform_data mx27_3ds_fb_data __initconst = {
 static struct l4f00242t03_pdata mx27_3ds_lcd_pdata = {
 	.reset_gpio		= LCD_RESET,
 	.data_enable_gpio	= LCD_ENABLE,
-	.core_supply		= "lcd_2v8",
-	.io_supply		= "vdd_lcdio",
 };
 
 static struct spi_board_info mx27_3ds_spi_devs[] __initdata = {
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index c20be75..154ed32 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -285,8 +285,6 @@ static struct mx3fb_platform_data mx3fb_pdata __initdata = {
 static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = {
 	.reset_gpio		= IOMUX_TO_GPIO(MX31_PIN_LCS1),
 	.data_enable_gpio	= IOMUX_TO_GPIO(MX31_PIN_SER_RS),
-	.core_supply		= "lcd_2v8",
-	.io_supply		= "vdd_lcdio",
 };
 
 /*
@@ -411,7 +409,7 @@ static struct regulator_init_data vmmc2_init = {
 };
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
-	REGULATOR_SUPPLY("lcd_2v8", NULL),
+	REGULATOR_SUPPLY("vcore", "spi0.0"),
 	REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
 };
 
@@ -428,7 +426,7 @@ static struct regulator_init_data vmmc1_init = {
 };
 
 static struct regulator_consumer_supply vgen_consumers[] = {
-	REGULATOR_SUPPLY("vdd_lcdio", NULL),
+	REGULATOR_SUPPLY("vdd", "spi0.0"),
 };
 
 static struct regulator_init_data vgen_init = {
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index 046c7aa..1ce32fd 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -53,15 +53,11 @@ static void l4f00242t03_lcd_init(struct spi_device *spi)
 
 	dev_dbg(&spi->dev, "initializing LCD\n");
 
-	if (priv->io_reg) {
-		regulator_set_voltage(priv->io_reg, 1800000, 1800000);
-		regulator_enable(priv->io_reg);
-	}
+	regulator_set_voltage(priv->io_reg, 1800000, 1800000);
+	regulator_enable(priv->io_reg);
 
-	if (priv->core_reg) {
-		regulator_set_voltage(priv->core_reg, 2800000, 2800000);
-		regulator_enable(priv->core_reg);
-	}
+	regulator_set_voltage(priv->core_reg, 2800000, 2800000);
+	regulator_enable(priv->core_reg);
 
 	l4f00242t03_reset(pdata->reset_gpio);
 
@@ -79,11 +75,8 @@ static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
 
 	gpio_set_value(pdata->data_enable_gpio, 0);
 
-	if (priv->io_reg)
-		regulator_disable(priv->io_reg);
-
-	if (priv->core_reg)
-		regulator_disable(priv->core_reg);
+	regulator_disable(priv->io_reg);
+	regulator_disable(priv->core_reg);
 }
 
 static int l4f00242t03_lcd_power_get(struct lcd_device *ld)
@@ -202,24 +195,18 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 	if (ret)
 		goto err3;
 
-	if (pdata->io_supply) {
-		priv->io_reg = regulator_get(NULL, pdata->io_supply);
-
-		if (IS_ERR(priv->io_reg)) {
-			pr_err("%s: Unable to get the IO regulator\n",
-								__func__);
-			goto err3;
-		}
+	priv->io_reg = regulator_get(&spi->dev, "vdd");
+	if (IS_ERR(priv->io_reg)) {
+		dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
+		       __func__);
+		goto err3;
 	}
 
-	if (pdata->core_supply) {
-		priv->core_reg = regulator_get(NULL, pdata->core_supply);
-
-		if (IS_ERR(priv->core_reg)) {
-			pr_err("%s: Unable to get the core regulator\n",
-								__func__);
-			goto err4;
-		}
+	priv->core_reg = regulator_get(&spi->dev, "vcore");
+	if (IS_ERR(priv->core_reg)) {
+		dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
+		       __func__);
+		goto err4;
 	}
 
 	priv->ld = lcd_device_register("l4f00242t03",
@@ -239,11 +226,9 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 	return 0;
 
 err5:
-	if (priv->core_reg)
-		regulator_put(priv->core_reg);
+	regulator_put(priv->core_reg);
 err4:
-	if (priv->io_reg)
-		regulator_put(priv->io_reg);
+	regulator_put(priv->io_reg);
 err3:
 	gpio_free(pdata->data_enable_gpio);
 err2:
@@ -267,10 +252,8 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
 	gpio_free(pdata->data_enable_gpio);
 	gpio_free(pdata->reset_gpio);
 
-	if (priv->io_reg)
-		regulator_put(priv->io_reg);
-	if (priv->core_reg)
-		regulator_put(priv->core_reg);
+	regulator_put(priv->io_reg);
+	regulator_put(priv->core_reg);
 
 	kfree(priv);
 
diff --git a/include/linux/spi/l4f00242t03.h b/include/linux/spi/l4f00242t03.h
index aee1dbd..bc8677c 100644
--- a/include/linux/spi/l4f00242t03.h
+++ b/include/linux/spi/l4f00242t03.h
@@ -24,8 +24,6 @@
 struct l4f00242t03_pdata {
 	unsigned int	reset_gpio;
 	unsigned int	data_enable_gpio;
-	const char 	*io_supply;	/* will be set to 1.8 V */
-	const char 	*core_supply;	/* will be set to 2.8 V */
 };
 
 #endif /* _INCLUDE_LINUX_SPI_L4F00242T03_H_ */
-- 
1.7.5.4


^ permalink raw reply related

* Re: [PATCH] backlight: Fix broken regulator API usage in l4f00242t03
From: Mark Brown @ 2011-08-15 13:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110815064242.GR31404@pengutronix.de>

On Mon, Aug 15, 2011 at 08:42:42AM +0200, Sascha Hauer wrote:

> Maybe you could change these pr_err to dev_err on the way. The rest of
> the driver already uses dev_*.

Minimal diff and all that...

^ permalink raw reply

* [PATCH] video: nuc900fb: remove include of mach/clkdev.h
From: Axel Lin @ 2011-08-15  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

Since commit aa3831cf9d29cfeaebd8c2169378b74111364487
"ARM: Consolidate the clkdev header files",
the header file arch/arm/mach-nuc93x/include/mach/clkdev.h is removed.

This patch fixes below build error:

drivers/video/nuc900fb.c:42:25: error: mach/clkdev.h: No such file or directory
make[2]: *** [drivers/video/nuc900fb.o] Error 1
make[1]: *** [drivers/video] Error 2
make: *** [drivers] Error 2

Signed-off-by: Axel Lin <axel.lin@gmail.com>
---
 drivers/video/nuc900fb.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 0fff5978..37dd850 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -39,7 +39,6 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-ldm.h>
 #include <mach/fb.h>
-#include <mach/clkdev.h>
 
 #include "nuc900fb.h"
 
-- 
1.7.4.1




^ permalink raw reply related

* Re: [PATCH] backlight: Fix broken regulator API usage in l4f00242t03
From: Sascha Hauer @ 2011-08-15  6:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1313372500-28017-1-git-send-email-broonie@opensource.wolfsonmicro.com>

On Mon, Aug 15, 2011 at 10:41:40AM +0900, Mark Brown wrote:
> The regulator support in the l4f00242t03 is very non-idiomatic, rather
> than requesting the regulators based on the device name and the supply
> names used by the device the driver requires boards to pass system
> specific supply names around through platform data. The driver also
> conditionally requests the regulators based on this platform data, adding
> unneeded conditional code to the driver.
> 
> Fix this by removing the platform data and converting to the standard idiom,
> also updating all in tree users of the driver. As no datasheet appears to
> be available for the LCD I'm guessing the names for the supplies based on
> the existing users and I've no ability to do anything more than compile
> test.
> 
> The use of regulator_set_voltage() in the driver is also problematic, since
> fixed voltages are required the expectation would be that the voltages
> would be fixed in the constraints set by the machines rather than manually
> configured by the driver, but is less problematic.
> 
>  static int l4f00242t03_lcd_power_get(struct lcd_device *ld)
> @@ -202,24 +195,18 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
>  	if (ret)
>  		goto err3;
>  
> -	if (pdata->io_supply) {
> -		priv->io_reg = regulator_get(NULL, pdata->io_supply);
> -
> -		if (IS_ERR(priv->io_reg)) {
> -			pr_err("%s: Unable to get the IO regulator\n",
> -								__func__);
> -			goto err3;
> -		}
> +	priv->io_reg = regulator_get(&spi->dev, "vdd");
> +	if (IS_ERR(priv->io_reg)) {
> +		pr_err("%s: Unable to get the IO regulator\n",
> +		       __func__);
> +		goto err3;
>  	}
>  
> -	if (pdata->core_supply) {
> -		priv->core_reg = regulator_get(NULL, pdata->core_supply);
> -
> -		if (IS_ERR(priv->core_reg)) {
> -			pr_err("%s: Unable to get the core regulator\n",
> -								__func__);
> -			goto err4;
> -		}
> +	priv->core_reg = regulator_get(&spi->dev, "vcore");
> +	if (IS_ERR(priv->core_reg)) {
> +		pr_err("%s: Unable to get the core regulator\n",
> +		       __func__);
> +		goto err4;
>  	}

Maybe you could change these pr_err to dev_err on the way. The rest of
the driver already uses dev_*.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH] backlight: Fix broken regulator API usage in l4f00242t03
From: Mark Brown @ 2011-08-15  1:41 UTC (permalink / raw)
  To: linux-arm-kernel

The regulator support in the l4f00242t03 is very non-idiomatic, rather
than requesting the regulators based on the device name and the supply
names used by the device the driver requires boards to pass system
specific supply names around through platform data. The driver also
conditionally requests the regulators based on this platform data, adding
unneeded conditional code to the driver.

Fix this by removing the platform data and converting to the standard idiom,
also updating all in tree users of the driver. As no datasheet appears to
be available for the LCD I'm guessing the names for the supplies based on
the existing users and I've no ability to do anything more than compile
test.

The use of regulator_set_voltage() in the driver is also problematic, since
fixed voltages are required the expectation would be that the voltages
would be fixed in the constraints set by the machines rather than manually
configured by the driver, but is less problematic.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 arch/arm/mach-imx/mach-mx27_3ds.c     |    6 +--
 arch/arm/mach-imx/mach-mx31_3ds.c     |    6 +--
 drivers/video/backlight/l4f00242t03.c |   57 +++++++++++---------------------
 include/linux/spi/l4f00242t03.h       |    2 -
 4 files changed, 24 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 6fa6934..08e5e20 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -241,7 +241,7 @@ static struct regulator_init_data gpo_init = {
 };
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
-	REGULATOR_SUPPLY("lcd_2v8", NULL),
+	REGULATOR_SUPPLY("vcore", "spi0.0"),
 };
 
 static struct regulator_init_data vmmc1_init = {
@@ -257,7 +257,7 @@ static struct regulator_init_data vmmc1_init = {
 };
 
 static struct regulator_consumer_supply vgen_consumers[] = {
-	REGULATOR_SUPPLY("vdd_lcdio", NULL),
+	REGULATOR_SUPPLY("vdd", "spi0.0"),
 };
 
 static struct regulator_init_data vgen_init = {
@@ -348,8 +348,6 @@ static const struct imx_fb_platform_data mx27_3ds_fb_data __initconst = {
 static struct l4f00242t03_pdata mx27_3ds_lcd_pdata = {
 	.reset_gpio		= LCD_RESET,
 	.data_enable_gpio	= LCD_ENABLE,
-	.core_supply		= "lcd_2v8",
-	.io_supply		= "vdd_lcdio",
 };
 
 static struct spi_board_info mx27_3ds_spi_devs[] __initdata = {
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index c20be75..154ed32 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -285,8 +285,6 @@ static struct mx3fb_platform_data mx3fb_pdata __initdata = {
 static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = {
 	.reset_gpio		= IOMUX_TO_GPIO(MX31_PIN_LCS1),
 	.data_enable_gpio	= IOMUX_TO_GPIO(MX31_PIN_SER_RS),
-	.core_supply		= "lcd_2v8",
-	.io_supply		= "vdd_lcdio",
 };
 
 /*
@@ -411,7 +409,7 @@ static struct regulator_init_data vmmc2_init = {
 };
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
-	REGULATOR_SUPPLY("lcd_2v8", NULL),
+	REGULATOR_SUPPLY("vcore", "spi0.0"),
 	REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
 };
 
@@ -428,7 +426,7 @@ static struct regulator_init_data vmmc1_init = {
 };
 
 static struct regulator_consumer_supply vgen_consumers[] = {
-	REGULATOR_SUPPLY("vdd_lcdio", NULL),
+	REGULATOR_SUPPLY("vdd", "spi0.0"),
 };
 
 static struct regulator_init_data vgen_init = {
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index 046c7aa..f7d1a59 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -53,15 +53,11 @@ static void l4f00242t03_lcd_init(struct spi_device *spi)
 
 	dev_dbg(&spi->dev, "initializing LCD\n");
 
-	if (priv->io_reg) {
-		regulator_set_voltage(priv->io_reg, 1800000, 1800000);
-		regulator_enable(priv->io_reg);
-	}
+	regulator_set_voltage(priv->io_reg, 1800000, 1800000);
+	regulator_enable(priv->io_reg);
 
-	if (priv->core_reg) {
-		regulator_set_voltage(priv->core_reg, 2800000, 2800000);
-		regulator_enable(priv->core_reg);
-	}
+	regulator_set_voltage(priv->core_reg, 2800000, 2800000);
+	regulator_enable(priv->core_reg);
 
 	l4f00242t03_reset(pdata->reset_gpio);
 
@@ -79,11 +75,8 @@ static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
 
 	gpio_set_value(pdata->data_enable_gpio, 0);
 
-	if (priv->io_reg)
-		regulator_disable(priv->io_reg);
-
-	if (priv->core_reg)
-		regulator_disable(priv->core_reg);
+	regulator_disable(priv->io_reg);
+	regulator_disable(priv->core_reg);
 }
 
 static int l4f00242t03_lcd_power_get(struct lcd_device *ld)
@@ -202,24 +195,18 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 	if (ret)
 		goto err3;
 
-	if (pdata->io_supply) {
-		priv->io_reg = regulator_get(NULL, pdata->io_supply);
-
-		if (IS_ERR(priv->io_reg)) {
-			pr_err("%s: Unable to get the IO regulator\n",
-								__func__);
-			goto err3;
-		}
+	priv->io_reg = regulator_get(&spi->dev, "vdd");
+	if (IS_ERR(priv->io_reg)) {
+		pr_err("%s: Unable to get the IO regulator\n",
+		       __func__);
+		goto err3;
 	}
 
-	if (pdata->core_supply) {
-		priv->core_reg = regulator_get(NULL, pdata->core_supply);
-
-		if (IS_ERR(priv->core_reg)) {
-			pr_err("%s: Unable to get the core regulator\n",
-								__func__);
-			goto err4;
-		}
+	priv->core_reg = regulator_get(&spi->dev, "vcore");
+	if (IS_ERR(priv->core_reg)) {
+		pr_err("%s: Unable to get the core regulator\n",
+		       __func__);
+		goto err4;
 	}
 
 	priv->ld = lcd_device_register("l4f00242t03",
@@ -239,11 +226,9 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 	return 0;
 
 err5:
-	if (priv->core_reg)
-		regulator_put(priv->core_reg);
+	regulator_put(priv->core_reg);
 err4:
-	if (priv->io_reg)
-		regulator_put(priv->io_reg);
+	regulator_put(priv->io_reg);
 err3:
 	gpio_free(pdata->data_enable_gpio);
 err2:
@@ -267,10 +252,8 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
 	gpio_free(pdata->data_enable_gpio);
 	gpio_free(pdata->reset_gpio);
 
-	if (priv->io_reg)
-		regulator_put(priv->io_reg);
-	if (priv->core_reg)
-		regulator_put(priv->core_reg);
+	regulator_put(priv->io_reg);
+	regulator_put(priv->core_reg);
 
 	kfree(priv);
 
diff --git a/include/linux/spi/l4f00242t03.h b/include/linux/spi/l4f00242t03.h
index aee1dbd..bc8677c 100644
--- a/include/linux/spi/l4f00242t03.h
+++ b/include/linux/spi/l4f00242t03.h
@@ -24,8 +24,6 @@
 struct l4f00242t03_pdata {
 	unsigned int	reset_gpio;
 	unsigned int	data_enable_gpio;
-	const char 	*io_supply;	/* will be set to 1.8 V */
-	const char 	*core_supply;	/* will be set to 2.8 V */
 };
 
 #endif /* _INCLUDE_LINUX_SPI_L4F00242T03_H_ */
-- 
1.7.5.4


^ permalink raw reply related

* Re: [PATCH/RFC] fbdev: Add FOURCC-based format configuration API
From: Geert Uytterhoeven @ 2011-08-13  9:42 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Florian Tobias Schandinat, Guennadi Liakhovetski, Paul Mundt,
	linux-fbdev, linux-media, dri-devel
In-Reply-To: <201108111919.54649.laurent.pinchart@ideasonboard.com>

Hi LAurent,

On Thu, Aug 11, 2011 at 19:19, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Monday 01 August 2011 11:49:46 Geert Uytterhoeven wrote:
>> As several of the FOURCC formats duplicate formats you can already specify
>> in some other way (e.g. the RGB and greyscale formats), and as FOURCC makes
>> life easier for the application writer, I'm wondering whether it makes sense
>> to add FOURCC support in the generic layer for drivers that don't support
>> it? I.e. the generic layer would fill in fb_var_screeninfo depending on the
>> requested FOURCC mode, if possible.
>
> That's a good idea, but I'd like to add that in a second step. I'm working on
> a proof-of-concept by porting a driver to the FOURCC-based API first.

Sure! I was just mentioning it, so we keep it in the back of our head and don't
make decisions now that would make it impossible to add that later.

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: [PATCH] Add support for SMSC UFX6000/7000 USB display adapters
From: Greg KH @ 2011-08-12 19:34 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1313150823-2527-1-git-send-email-steve.glendinning@smsc.com>

On Fri, Aug 12, 2011 at 12:06:55PM -0700, Bernie Thompson wrote:
> On Fri, Aug 12, 2011 at 8:56 AM, Greg KH <gregkh@suse.de> wrote:
> 
>     You can do the same for your calls to pr_debug() and other pr_* calls.
>     If you note in the header file for those functions, it suggests that
>     drivers should always call the dev_* versions instead of teh "raw" pr_*
>     functions, as you do have access to a struct device within your driver.
> 
> 
> A little background from udlfb: we weren't able to stick with dev_* calls 100%,
> because udlfb needed to survive USB device removal and the freeing of the
> USB-initiated device structure. This is because the framebuffer device needed
> to outlive it if a client was holding on to it.  In other words, it's born a
> two-headed beast (usb and fbdev), but the two faces of the device are killed
> off independently based on remaining ref counts.  So there are prints in there
> which will fault if converted to dev_* without this in mind.
> 
> Because of this, we had originally created our own dl_* wrapper around the pr_
> macros.
> 
> Then a later patch initiated by Paul (fbdev maintainer) changed those to
> uncustomized pr_ macros with a goal of uniformity with other drivers.  And that
> code is what SMSC started from.
> 
> So there's some complexity behind the choices here.  It might be good to keep
> common strategies between udlfb and smsc's driver, as the issues to consider
> are the same.

Ok, thanks for the background information, that makes sense.

But for stuff like the usb probe() call, that should always be dev_* as
you really do have a proper pointer.  So when you do have a valid struct
device, you should use it.

Although a lot of the pr_info() calls should be downgraded to pr_debug()
I imagine, to keep things from being so noisy.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] Add support for SMSC UFX6000/7000 USB display adapters
From: Greg KH @ 2011-08-12 15:56 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1313150823-2527-1-git-send-email-steve.glendinning@smsc.com>

On Fri, Aug 12, 2011 at 01:07:03PM +0100, Steve Glendinning wrote:
> This patch adds framebuffer suport for SMSC's UFX6000 (USB 2.0) and
> UFX7000 (USB 3.0) display adapters.
> 
> Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>

Very nice job, I only have one very minor suggestion for this code from
a USB/driver core standpoint (I can't verify that the framebuffer api is
being used properly as I don't know that at all.):

> +/* sets analog bit PLL configuration values */
> +static int ufx_config_pix_clk(struct ufx_data *dev, u32 pixclock)
> +{
> +	struct pll_values asic_pll = {0};
> +	u32 value, clk_pixel, clk_pixel_pll;
> +	int status;
> +
> +	/* convert pixclock (in ps) to frequency (in Hz) */
> +	clk_pixel = PICOS2KHZ(pixclock) * 1000;
> +	pr_info("pixclock %d ps = clk_pixel %d Hz", pixclock, clk_pixel);

Use call pr_info() a bunch, (especially in your probe() call chain)
which will get noisy in the kernel log.  How about using dev_dbg()
instead, which allows you to dynamically turn on/off messages like this,
and it provides the needed information so that the reader of the
messages can tell exactly which device is sending the messages (very
helpful when you attach more than one.)

You can do the same for your calls to pr_debug() and other pr_* calls.
If you note in the header file for those functions, it suggests that
drivers should always call the dev_* versions instead of teh "raw" pr_*
functions, as you do have access to a struct device within your driver.

thanks,

greg k-h

^ permalink raw reply

* [PATCH] Add support for SMSC UFX6000/7000 USB display adapters
From: Steve Glendinning @ 2011-08-12 12:07 UTC (permalink / raw)
  To: linux-fbdev

This patch adds framebuffer suport for SMSC's UFX6000 (USB 2.0) and
UFX7000 (USB 3.0) display adapters.

Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
---
 MAINTAINERS             |    6 +
 drivers/video/Kconfig   |   16 +
 drivers/video/Makefile  |    1 +
 drivers/video/smscufx.c | 2009 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2032 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/smscufx.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1e55e1e..80d5555 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5920,6 +5920,12 @@ L:	netdev@vger.kernel.org
 S:	Supported
 F:	drivers/net/smsc9420.*
 
+SMSC UFX6000 and UFX7000 USB to VGA DRIVER
+M:	Steve Glendinning <steve.glendinning@smsc.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Supported
+F:	drivers/video/smscufx.c
+
 SN-IA64 (Itanium) SUB-PLATFORM
 M:	Jes Sorensen <jes@sgi.com>
 L:	linux-altix@sgi.com
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 549b960..8bfb387 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2110,6 +2110,22 @@ config FB_SM501
 
 	  If unsure, say N.
 
+config FB_SMSCUFX
+	tristate "SMSC UFX6000/7000 USB Framebuffer support"
+	depends on FB && USB
+	select FB_MODE_HELPERS
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
+	---help---
+	  This is a kernel framebuffer driver for SMSC UFX USB devices.
+	  Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
+	  mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000
+	  (USB 3.0) devices.
+	  To compile as a module, choose M here: the module name is smscufx.
+
 config FB_UDL
 	tristate "Displaylink USB Framebuffer support"
 	depends on FB && USB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8b83129..f3546ec 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -127,6 +127,7 @@ obj-$(CONFIG_FB_IBM_GXT4500)	  += gxt4500.o
 obj-$(CONFIG_FB_PS3)		  += ps3fb.o
 obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_UDL)		  += udlfb.o
+obj-$(CONFIG_FB_SMSCUFX)	  += smscufx.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)	  += sh_mipi_dsi.o
 obj-$(CONFIG_FB_SH_MOBILE_HDMI)	  += sh_mobile_hdmi.o
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
new file mode 100644
index 0000000..2d1a7b2
--- /dev/null
+++ b/drivers/video/smscufx.c
@@ -0,0 +1,2009 @@
+/*
+ * smscufx.c -- Framebuffer driver for SMSC UFX USB controller
+ *
+ * Copyright (C) 2011 Steve Glendinning <steve.glendinning@smsc.com>
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Based on udlfb, with work from Florian Echtler, Henrik Bjerregaard Pedersen,
+ * and others.
+ *
+ * Works well with Bernie Thompson's X DAMAGE patch to xf86-video-fbdev
+ * available from http://git.plugable.com
+ *
+ * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
+ * usb-skeleton by GregKH.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "edid.h"
+
+#define check_warn(status, fmt, args...) \
+	({ if (status < 0) pr_warn(fmt, ##args); })
+
+#define check_warn_return(status, fmt, args...) \
+	({ if (status < 0) { pr_warn(fmt, ##args); return status; } })
+
+#define check_warn_goto_error(status, fmt, args...) \
+	({ if (status < 0) { pr_warn(fmt, ##args); goto error; } })
+
+#define all_bits_set(x, bits) (((x) & (bits)) = (bits))
+
+#define USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER	0xA1
+
+/*
+ * TODO: Propose standard fb.h ioctl for reporting damage,
+ * using _IOWR() and one of the existing area structs from fb.h
+ * Consider these ioctls deprecated, but they're still used by the
+ * DisplayLink X server as yet - need both to be modified in tandem
+ * when new ioctl(s) are ready.
+ */
+#define UFX_IOCTL_RETURN_EDID	(0xAD)
+#define UFX_IOCTL_REPORT_DAMAGE	(0xAA)
+
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE		(512)
+#define MAX_TRANSFER		(PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT	(4)
+
+#define GET_URB_TIMEOUT		(HZ)
+#define FREE_URB_TIMEOUT	(HZ*2)
+
+#define BPP			2
+
+#define UFX_DEFIO_WRITE_DELAY	5 /* fb_deferred_io.delay in jiffies */
+#define UFX_DEFIO_WRITE_DISABLE	(HZ*60) /* "disable" with long delay */
+
+struct dloarea {
+	int x, y;
+	int w, h;
+};
+
+struct urb_node {
+	struct list_head entry;
+	struct ufx_data *dev;
+	struct delayed_work release_urb_work;
+	struct urb *urb;
+};
+
+struct urb_list {
+	struct list_head list;
+	spinlock_t lock;
+	struct semaphore limit_sem;
+	int available;
+	int count;
+	size_t size;
+};
+
+struct ufx_data {
+	struct usb_device *udev;
+	struct device *gdev; /* &udev->dev */
+	struct fb_info *info;
+	struct urb_list urbs;
+	struct kref kref;
+	int fb_count;
+	bool virtualized; /* true when physical usb device not present */
+	struct delayed_work free_framebuffer_work;
+	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+	char *edid; /* null until we read edid from hw or get from sysfs */
+	size_t edid_size;
+	u32 pseudo_palette[256];
+};
+
+static struct fb_fix_screeninfo ufx_fix = {
+	.id =           "smscufx",
+	.type =         FB_TYPE_PACKED_PIXELS,
+	.visual =       FB_VISUAL_TRUECOLOR,
+	.xpanstep =     0,
+	.ypanstep =     0,
+	.ywrapstep =    0,
+	.accel =        FB_ACCEL_NONE,
+};
+
+static const u32 smscufx_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
+	FBINFO_VIRTFB |	FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
+	FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
+
+static struct usb_device_id id_table[] = {
+	{USB_DEVICE(0x0424, 0x9d00),},
+	{USB_DEVICE(0x0424, 0x9d01),},
+	{},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* module options */
+static int console;   /* Optionally allow fbcon to consume first framebuffer */
+static int fb_defio = true;  /* Optionally enable fb_defio mmap support */
+
+/* ufx keeps a list of urbs for efficient bulk transfers */
+static void ufx_urb_completion(struct urb *urb);
+static struct urb *ufx_get_urb(struct ufx_data *dev);
+static int ufx_submit_urb(struct ufx_data *dev, struct urb * urb, size_t len);
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size);
+static void ufx_free_urb_list(struct ufx_data *dev);
+
+/* reads a control register */
+static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data)
+{
+	u32 *buf = kmalloc(4, GFP_KERNEL);
+	int ret;
+
+	BUG_ON(!dev);
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+		USB_VENDOR_REQUEST_READ_REGISTER,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		00, index, buf, 4, USB_CTRL_GET_TIMEOUT);
+
+	le32_to_cpus(buf);
+	*data = *buf;
+	kfree(buf);
+
+	if (unlikely(ret < 0))
+		pr_warn("Failed to read register index 0x%08x\n", index);
+
+	return ret;
+}
+
+/* writes a control register */
+static int ufx_reg_write(struct ufx_data *dev, u32 index, u32 data)
+{
+	u32 *buf = kmalloc(4, GFP_KERNEL);
+	int ret;
+
+	BUG_ON(!dev);
+
+	if (!buf)
+		return -ENOMEM;
+
+	*buf = data;
+	cpu_to_le32s(buf);
+
+	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+		USB_VENDOR_REQUEST_WRITE_REGISTER,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		00, index, buf, 4, USB_CTRL_SET_TIMEOUT);
+
+	kfree(buf);
+
+	if (unlikely(ret < 0))
+		pr_warn("Failed to write register index 0x%08x with value "
+			"0x%08x\n", index, data);
+
+	return ret;
+}
+
+static int ufx_reg_clear_and_set_bits(struct ufx_data *dev, u32 index,
+	u32 bits_to_clear, u32 bits_to_set)
+{
+	u32 data;
+	int status = ufx_reg_read(dev, index, &data);
+	check_warn_return(status, "ufx_reg_clear_and_set_bits error reading "
+		"0x%x", index);
+
+	data &= (~bits_to_clear);
+	data |= bits_to_set;
+
+	status = ufx_reg_write(dev, index, data);
+	check_warn_return(status, "ufx_reg_clear_and_set_bits error writing "
+		"0x%x", index);
+
+	return 0;
+}
+
+static int ufx_reg_set_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+	return ufx_reg_clear_and_set_bits(dev, index, 0, bits);
+}
+
+static int ufx_reg_clear_bits(struct ufx_data *dev, u32 index, u32 bits)
+{
+	return ufx_reg_clear_and_set_bits(dev, index, bits, 0);
+}
+
+static int ufx_lite_reset(struct ufx_data *dev)
+{
+	int status;
+	u32 value;
+
+	status = ufx_reg_write(dev, 0x3008, 0x00000001);
+	check_warn_return(status, "ufx_lite_reset error writing 0x3008");
+
+	status = ufx_reg_read(dev, 0x3008, &value);
+	check_warn_return(status, "ufx_lite_reset error reading 0x3008");
+
+	return (value = 0) ? 0 : -EIO;
+}
+
+/* If display is unblanked, then blank it */
+static int ufx_blank(struct ufx_data *dev, bool wait)
+{
+	u32 dc_ctrl, dc_sts;
+	int i;
+
+	int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+	check_warn_return(status, "ufx_blank error reading 0x2004");
+
+	status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+	check_warn_return(status, "ufx_blank error reading 0x2000");
+
+	/* return success if display is already blanked */
+	if ((dc_sts & 0x00000100) || (dc_ctrl & 0x00000100))
+		return 0;
+
+	/* request the DC to blank the display */
+	dc_ctrl |= 0x00000100;
+	status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+	check_warn_return(status, "ufx_blank error writing 0x2000");
+
+	/* return success immediately if we don't have to wait */
+	if (!wait)
+		return 0;
+
+	for (i = 0; i < 250; i++) {
+		status = ufx_reg_read(dev, 0x2004, &dc_sts);
+		check_warn_return(status, "ufx_blank error reading 0x2004");
+
+		if (dc_sts & 0x00000100)
+			return 0;
+	}
+
+	/* timed out waiting for display to blank */
+	return -EIO;
+}
+
+/* If display is blanked, then unblank it */
+static int ufx_unblank(struct ufx_data *dev, bool wait)
+{
+	u32 dc_ctrl, dc_sts;
+	int i;
+
+	int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+	check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+	status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+	check_warn_return(status, "ufx_unblank error reading 0x2000");
+
+	/* return success if display is already unblanked */
+	if (((dc_sts & 0x00000100) = 0) || ((dc_ctrl & 0x00000100) = 0))
+		return 0;
+
+	/* request the DC to unblank the display */
+	dc_ctrl &= ~0x00000100;
+	status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+	check_warn_return(status, "ufx_unblank error writing 0x2000");
+
+	/* return success immediately if we don't have to wait */
+	if (!wait)
+		return 0;
+
+	for (i = 0; i < 250; i++) {
+		status = ufx_reg_read(dev, 0x2004, &dc_sts);
+		check_warn_return(status, "ufx_unblank error reading 0x2004");
+
+		if ((dc_sts & 0x00000100) = 0)
+			return 0;
+	}
+
+	/* timed out waiting for display to unblank */
+	return -EIO;
+}
+
+/* If display is enabled, then disable it */
+static int ufx_disable(struct ufx_data *dev, bool wait)
+{
+	u32 dc_ctrl, dc_sts;
+	int i;
+
+	int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+	check_warn_return(status, "ufx_disable error reading 0x2004");
+
+	status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+	check_warn_return(status, "ufx_disable error reading 0x2000");
+
+	/* return success if display is already disabled */
+	if (((dc_sts & 0x00000001) = 0) || ((dc_ctrl & 0x00000001) = 0))
+		return 0;
+
+	/* request the DC to disable the display */
+	dc_ctrl &= ~(0x00000001);
+	status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+	check_warn_return(status, "ufx_disable error writing 0x2000");
+
+	/* return success immediately if we don't have to wait */
+	if (!wait)
+		return 0;
+
+	for (i = 0; i < 250; i++) {
+		status = ufx_reg_read(dev, 0x2004, &dc_sts);
+		check_warn_return(status, "ufx_disable error reading 0x2004");
+
+		if ((dc_sts & 0x00000001) = 0)
+			return 0;
+	}
+
+	/* timed out waiting for display to disable */
+	return -EIO;
+}
+
+/* If display is disabled, then enable it */
+static int ufx_enable(struct ufx_data *dev, bool wait)
+{
+	u32 dc_ctrl, dc_sts;
+	int i;
+
+	int status = ufx_reg_read(dev, 0x2004, &dc_sts);
+	check_warn_return(status, "ufx_enable error reading 0x2004");
+
+	status = ufx_reg_read(dev, 0x2000, &dc_ctrl);
+	check_warn_return(status, "ufx_enable error reading 0x2000");
+
+	/* return success if display is already enabled */
+	if ((dc_sts & 0x00000001) || (dc_ctrl & 0x00000001))
+		return 0;
+
+	/* request the DC to enable the display */
+	dc_ctrl |= 0x00000001;
+	status = ufx_reg_write(dev, 0x2000, dc_ctrl);
+	check_warn_return(status, "ufx_enable error writing 0x2000");
+
+	/* return success immediately if we don't have to wait */
+	if (!wait)
+		return 0;
+
+	for (i = 0; i < 250; i++) {
+		status = ufx_reg_read(dev, 0x2004, &dc_sts);
+		check_warn_return(status, "ufx_enable error reading 0x2004");
+
+		if (dc_sts & 0x00000001)
+			return 0;
+	}
+
+	/* timed out waiting for display to enable */
+	return -EIO;
+}
+
+static int ufx_config_sys_clk(struct ufx_data *dev)
+{
+	int status = ufx_reg_write(dev, 0x700C, 0x8000000F);
+	check_warn_return(status, "error writing 0x700C");
+
+	status = ufx_reg_write(dev, 0x7014, 0x0010024F);
+	check_warn_return(status, "error writing 0x7014");
+
+	status = ufx_reg_write(dev, 0x7010, 0x00000000);
+	check_warn_return(status, "error writing 0x7010");
+
+	status = ufx_reg_clear_bits(dev, 0x700C, 0x0000000A);
+	check_warn_return(status, "error clearing PLL1 bypass in 0x700C");
+	msleep(1);
+
+	status = ufx_reg_clear_bits(dev, 0x700C, 0x80000000);
+	check_warn_return(status, "error clearing output gate in 0x700C");
+
+	return 0;
+}
+
+static int ufx_config_ddr2(struct ufx_data *dev)
+{
+	int status, i = 0;
+	u32 tmp;
+
+	status = ufx_reg_write(dev, 0x0004, 0x001F0F77);
+	check_warn_return(status, "error writing 0x0004");
+
+	status = ufx_reg_write(dev, 0x0008, 0xFFF00000);
+	check_warn_return(status, "error writing 0x0008");
+
+	status = ufx_reg_write(dev, 0x000C, 0x0FFF2222);
+	check_warn_return(status, "error writing 0x000C");
+
+	status = ufx_reg_write(dev, 0x0010, 0x00030814);
+	check_warn_return(status, "error writing 0x0010");
+
+	status = ufx_reg_write(dev, 0x0014, 0x00500019);
+	check_warn_return(status, "error writing 0x0014");
+
+	status = ufx_reg_write(dev, 0x0018, 0x020D0F15);
+	check_warn_return(status, "error writing 0x0018");
+
+	status = ufx_reg_write(dev, 0x001C, 0x02532305);
+	check_warn_return(status, "error writing 0x001C");
+
+	status = ufx_reg_write(dev, 0x0020, 0x0B030905);
+	check_warn_return(status, "error writing 0x0020");
+
+	status = ufx_reg_write(dev, 0x0024, 0x00000827);
+	check_warn_return(status, "error writing 0x0024");
+
+	status = ufx_reg_write(dev, 0x0028, 0x00000000);
+	check_warn_return(status, "error writing 0x0028");
+
+	status = ufx_reg_write(dev, 0x002C, 0x00000042);
+	check_warn_return(status, "error writing 0x002C");
+
+	status = ufx_reg_write(dev, 0x0030, 0x09520000);
+	check_warn_return(status, "error writing 0x0030");
+
+	status = ufx_reg_write(dev, 0x0034, 0x02223314);
+	check_warn_return(status, "error writing 0x0034");
+
+	status = ufx_reg_write(dev, 0x0038, 0x00430043);
+	check_warn_return(status, "error writing 0x0038");
+
+	status = ufx_reg_write(dev, 0x003C, 0xF00F000F);
+	check_warn_return(status, "error writing 0x003C");
+
+	status = ufx_reg_write(dev, 0x0040, 0xF380F00F);
+	check_warn_return(status, "error writing 0x0040");
+
+	status = ufx_reg_write(dev, 0x0044, 0xF00F0496);
+	check_warn_return(status, "error writing 0x0044");
+
+	status = ufx_reg_write(dev, 0x0048, 0x03080406);
+	check_warn_return(status, "error writing 0x0048");
+
+	status = ufx_reg_write(dev, 0x004C, 0x00001000);
+	check_warn_return(status, "error writing 0x004C");
+
+	status = ufx_reg_write(dev, 0x005C, 0x00000007);
+	check_warn_return(status, "error writing 0x005C");
+
+	status = ufx_reg_write(dev, 0x0100, 0x54F00012);
+	check_warn_return(status, "error writing 0x0100");
+
+	status = ufx_reg_write(dev, 0x0104, 0x00004012);
+	check_warn_return(status, "error writing 0x0104");
+
+	status = ufx_reg_write(dev, 0x0118, 0x40404040);
+	check_warn_return(status, "error writing 0x0118");
+
+	status = ufx_reg_write(dev, 0x0000, 0x00000001);
+	check_warn_return(status, "error writing 0x0000");
+
+	while (i++ < 500) {
+		status = ufx_reg_read(dev, 0x0000, &tmp);
+		check_warn_return(status, "error reading 0x0000");
+
+		if (all_bits_set(tmp, 0xC0000000))
+			return 0;
+	}
+
+	pr_err("DDR2 initialisation timed out, reg 0x0000=0x%08x", tmp);
+	return -ETIMEDOUT;
+}
+
+struct pll_values {
+	u32 div_r0;
+	u32 div_f0;
+	u32 div_q0;
+	u32 range0;
+	u32 div_r1;
+	u32 div_f1;
+	u32 div_q1;
+	u32 range1;
+};
+
+static u32 ufx_calc_range(u32 ref_freq)
+{
+	if (ref_freq >= 88000000)
+		return 7;
+
+	if (ref_freq >= 54000000)
+		return 6;
+
+	if (ref_freq >= 34000000)
+		return 5;
+
+	if (ref_freq >= 21000000)
+		return 4;
+
+	if (ref_freq >= 13000000)
+		return 3;
+
+	if (ref_freq >= 8000000)
+		return 2;
+
+	return 1;
+}
+
+/* calculates PLL divider settings for a desired target frequency */
+static void ufx_calc_pll_values(const u32 clk_pixel_pll, struct pll_values *asic_pll)
+{
+	const u32 ref_clk = 25000000;
+	u32 div_r0, div_f0, div_q0, div_r1, div_f1, div_q1;
+	u32 min_error = clk_pixel_pll;
+
+	for (div_r0 = 1; div_r0 <= 32; div_r0++) {
+		u32 ref_freq0 = ref_clk / div_r0;
+		if (ref_freq0 < 5000000)
+			break;
+
+		if (ref_freq0 > 200000000)
+			continue;
+
+		for (div_f0 = 1; div_f0 <= 256; div_f0++) {
+			u32 vco_freq0 = ref_freq0 * div_f0;
+
+			if (vco_freq0 < 350000000)
+				continue;
+
+			if (vco_freq0 > 700000000)
+				break;
+
+			for (div_q0 = 0; div_q0 < 7; div_q0++) {
+				u32 pllout_freq0 = vco_freq0 / (1 << div_q0);
+
+				if (pllout_freq0 < 5000000)
+					break;
+
+				if (pllout_freq0 > 200000000)
+					continue;
+
+				for (div_r1 = 1; div_r1 <= 32; div_r1++) {
+					u32 ref_freq1 = pllout_freq0 / div_r1;
+
+					if (ref_freq1 < 5000000)
+						break;
+
+					for (div_f1 = 1; div_f1 <= 256; div_f1++) {
+						u32 vco_freq1 = ref_freq1 * div_f1;
+
+						if (vco_freq1 < 350000000)
+							continue;
+
+						if (vco_freq1 > 700000000)
+							break;
+
+						for (div_q1 = 0; div_q1 < 7; div_q1++) {
+							u32 pllout_freq1 = vco_freq1 / (1 << div_q1);
+							int error = abs(pllout_freq1 - clk_pixel_pll);
+
+							if (pllout_freq1 < 5000000)
+								break;
+
+							if (pllout_freq1 > 700000000)
+								continue;
+
+							if (error < min_error) {
+								min_error = error;
+
+								/* final returned value is equal to calculated value - 1
+								 * because a value of 0 = divide by 1 */
+								asic_pll->div_r0 = div_r0 - 1;
+								asic_pll->div_f0 = div_f0 - 1;
+								asic_pll->div_q0 = div_q0;
+								asic_pll->div_r1 = div_r1 - 1;
+								asic_pll->div_f1 = div_f1 - 1;
+								asic_pll->div_q1 = div_q1;
+
+								asic_pll->range0 = ufx_calc_range(ref_freq0);
+								asic_pll->range1 = ufx_calc_range(ref_freq1);
+
+								if (min_error = 0)
+									return;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+/* sets analog bit PLL configuration values */
+static int ufx_config_pix_clk(struct ufx_data *dev, u32 pixclock)
+{
+	struct pll_values asic_pll = {0};
+	u32 value, clk_pixel, clk_pixel_pll;
+	int status;
+
+	/* convert pixclock (in ps) to frequency (in Hz) */
+	clk_pixel = PICOS2KHZ(pixclock) * 1000;
+	pr_info("pixclock %d ps = clk_pixel %d Hz", pixclock, clk_pixel);
+
+	/* clk_pixel = 1/2 clk_pixel_pll */
+	clk_pixel_pll = clk_pixel * 2;
+
+	ufx_calc_pll_values(clk_pixel_pll, &asic_pll);
+
+	/* Keep BYPASS and RESET signals asserted until configured */
+	status = ufx_reg_write(dev, 0x7000, 0x8000000F);
+	check_warn_return(status, "error writing 0x7000");
+
+	value = (asic_pll.div_f1 | (asic_pll.div_r1 << 8) |
+		(asic_pll.div_q1 << 16) | (asic_pll.range1 << 20));
+	status = ufx_reg_write(dev, 0x7008, value);
+	check_warn_return(status, "error writing 0x7008");
+
+	value = (asic_pll.div_f0 | (asic_pll.div_r0 << 8) |
+		(asic_pll.div_q0 << 16) | (asic_pll.range0 << 20));
+	status = ufx_reg_write(dev, 0x7004, value);
+	check_warn_return(status, "error writing 0x7004");
+
+	status = ufx_reg_clear_bits(dev, 0x7000, 0x00000005);
+	check_warn_return(status,
+		"error clearing PLL0 bypass bits in 0x7000");
+	msleep(1);
+
+	status = ufx_reg_clear_bits(dev, 0x7000, 0x0000000A);
+	check_warn_return(status,
+		"error clearing PLL1 bypass bits in 0x7000");
+	msleep(1);
+
+	status = ufx_reg_clear_bits(dev, 0x7000, 0x80000000);
+	check_warn_return(status, "error clearing gate bits in 0x7000");
+
+	return 0;
+}
+
+static int ufx_set_vid_mode(struct ufx_data *dev, struct fb_var_screeninfo *var)
+{
+	u32 temp;
+	u16 h_total, h_active, h_blank_start, h_blank_end, h_sync_start, h_sync_end;
+	u16 v_total, v_active, v_blank_start, v_blank_end, v_sync_start, v_sync_end;
+
+	int status = ufx_reg_write(dev, 0x8028, 0);
+	check_warn_return(status, "ufx_set_vid_mode error disabling RGB pad");
+
+	status = ufx_reg_write(dev, 0x8024, 0);
+	check_warn_return(status, "ufx_set_vid_mode error disabling VDAC");
+
+	/* shut everything down before changing timing */
+	status = ufx_blank(dev, true);
+	check_warn_return(status, "ufx_set_vid_mode error blanking display");
+
+	status = ufx_disable(dev, true);
+	check_warn_return(status, "ufx_set_vid_mode error disabling display");
+
+	status = ufx_config_pix_clk(dev, var->pixclock);
+	check_warn_return(status, "ufx_set_vid_mode error configuring pixclock");
+
+	status = ufx_reg_write(dev, 0x2000, 0x00000104);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2000");
+
+	/* set horizontal timings */
+	h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	h_active = var->xres;
+	h_blank_start = var->xres + var->right_margin;
+	h_blank_end = var->xres + var->right_margin + var->hsync_len;
+	h_sync_start = var->xres + var->right_margin;
+	h_sync_end = var->xres + var->right_margin + var->hsync_len;
+
+	temp = ((h_total - 1) << 16) | (h_active - 1);
+	status = ufx_reg_write(dev, 0x2008, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2008");
+
+	temp = ((h_blank_start - 1) << 16) | (h_blank_end - 1);
+	status = ufx_reg_write(dev, 0x200C, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x200C");
+
+	temp = ((h_sync_start - 1) << 16) | (h_sync_end - 1);
+	status = ufx_reg_write(dev, 0x2010, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2010");
+
+	/* set vertical timings */
+	v_total = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;
+	v_active = var->yres;
+	v_blank_start = var->yres + var->lower_margin;
+	v_blank_end = var->yres + var->lower_margin + var->vsync_len;
+	v_sync_start = var->yres + var->lower_margin;
+	v_sync_end = var->yres + var->lower_margin + var->vsync_len;
+
+	temp = ((v_total - 1) << 16) | (v_active - 1);
+	status = ufx_reg_write(dev, 0x2014, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2014");
+
+	temp = ((v_blank_start - 1) << 16) | (v_blank_end - 1);
+	status = ufx_reg_write(dev, 0x2018, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2018");
+
+	temp = ((v_sync_start - 1) << 16) | (v_sync_end - 1);
+	status = ufx_reg_write(dev, 0x201C, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x201C");
+
+	status = ufx_reg_write(dev, 0x2020, 0x00000000);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2020");
+
+	status = ufx_reg_write(dev, 0x2024, 0x00000000);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2024");
+
+	/* Set the frame length register (#pix * 2 bytes/pixel) */
+	temp = var->xres * var->yres * 2;
+	temp = (temp + 7) & (~0x7);
+	status = ufx_reg_write(dev, 0x2028, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2028");
+
+	/* enable desired output interface & disable others */
+	status = ufx_reg_write(dev, 0x2040, 0);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+	status = ufx_reg_write(dev, 0x2044, 0);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2044");
+
+	status = ufx_reg_write(dev, 0x2048, 0);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2048");
+
+	/* set the sync polarities & enable bit */
+	temp = 0x00000001;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		temp |= 0x00000010;
+
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		temp |= 0x00000008;
+
+	status = ufx_reg_write(dev, 0x2040, temp);
+	check_warn_return(status, "ufx_set_vid_mode error writing 0x2040");
+
+	/* start everything back up */
+	status = ufx_enable(dev, true);
+	check_warn_return(status, "ufx_set_vid_mode error enabling display");
+
+	/* Unblank the display */
+	status = ufx_unblank(dev, true);
+	check_warn_return(status, "ufx_set_vid_mode error unblanking display");
+
+	/* enable RGB pad */
+	status = ufx_reg_write(dev, 0x8028, 0x00000003);
+	check_warn_return(status, "ufx_set_vid_mode error enabling RGB pad");
+
+	/* enable VDAC */
+	status = ufx_reg_write(dev, 0x8024, 0x00000007);
+	check_warn_return(status, "ufx_set_vid_mode error enabling VDAC");
+
+	return 0;
+}
+
+static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long page, pos;
+
+	if (offset + size > info->fix.smem_len)
+		return -EINVAL;
+
+	pos = (unsigned long)info->fix.smem_start + offset;
+
+	pr_notice("mmap() framebuffer addr:%lu size:%lu\n",
+		  pos, size);
+
+	while (size > 0) {
+		page = vmalloc_to_pfn((void *)pos);
+		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
+	return 0;
+}
+
+static char *ufx_raw_rect(struct ufx_data *dev, char *cmd, int x, int y,
+	int width, int height)
+{
+	size_t packed_line_len = ALIGN((width * 2), 4);
+	size_t packed_rect_len = packed_line_len * height;
+	int i;
+
+	BUG_ON(!dev);
+	BUG_ON(!dev->info);
+
+	/* command word */
+	*cmd = 0x01;
+	cmd += 4;
+
+	/* length word */
+	*((u32 *)cmd) = cpu_to_le32(packed_rect_len + 16);
+	cmd += 4;
+
+	*((u16 *)cmd) = cpu_to_le16(x);
+	cmd += 2;
+
+	*((u16 *)cmd) = cpu_to_le16(y);
+	cmd += 2;
+
+	*((u16 *)cmd) = cpu_to_le16(width);
+	cmd += 2;
+
+	*((u16 *)cmd) = cpu_to_le16(height);
+	cmd += 2;
+
+	/* frame base address */
+	*((u32 *)cmd) = cpu_to_le32(0 & 0xffffff80);
+	cmd += 4;
+
+	/* color mode and horizontal resolution */
+	*((u16 *)cmd) = cpu_to_le16(0x4000 | dev->info->var.xres);
+	cmd += 2;
+
+	/* vertical resolution */
+	*((u16 *)cmd) = cpu_to_le16(dev->info->var.yres);
+	cmd += 2;
+
+	/* packed data */
+	for (i = y; i < y + height ; i++) {
+		const int line_offset = dev->info->fix.line_length * i;
+		const int byte_offset = line_offset + (x * BPP);
+		memcpy(cmd, (char *) dev->info->fix.smem_start + byte_offset, (width * BPP));
+
+		/* include line padding */
+		cmd += packed_line_len;
+	}
+
+	return cmd;
+}
+
+int ufx_handle_damage(struct ufx_data *dev, int x, int y,
+	int width, int height)
+{
+	size_t packed_line_len = ALIGN((width * 2), 4);
+	int len, status, urb_lines, start_line = 0;
+	char *cmd;
+
+	if ((width <= 0) || (height <= 0) ||
+	    (x + width > dev->info->var.xres) ||
+	    (y + height > dev->info->var.yres))
+		return -EINVAL;
+
+	if (!atomic_read(&dev->usb_active))
+		return 0;
+
+	while (start_line < height) {
+		struct urb *urb = ufx_get_urb(dev);
+		if (!urb) {
+			pr_warn("ufx_handle_damage unable to get urb");
+			return 0;
+		}
+
+		/* assume we have enough space to transfer at least one line */
+		BUG_ON(urb->transfer_buffer_length < (24 + (width * 2)));
+
+		/* calculate the maximum number of lines we could fit in */
+		urb_lines = (urb->transfer_buffer_length - 24) / packed_line_len;
+
+		/* but we might not need this many */
+		urb_lines = min(urb_lines, (height - start_line));
+
+		memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+
+		cmd = ufx_raw_rect(dev, urb->transfer_buffer, x, (y + start_line), width, urb_lines);
+
+		len = cmd - (char *) urb->transfer_buffer;
+		BUG_ON(len != (24 + (packed_line_len * urb_lines)));
+
+		status = ufx_submit_urb(dev, urb, len);
+		check_warn_return(status, "Error submitting URB");
+
+		start_line += urb_lines;
+	}
+
+	return 0;
+}
+
+/* Path triggered by usermode clients who write to filesystem
+ * e.g. cat filename > /dev/fb1
+ * Not used by X Windows or text-mode console. But useful for testing.
+ * Slow because of extra copy and we must assume all pixels dirty. */
+static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	ssize_t result;
+	struct ufx_data *dev = info->par;
+	u32 offset = (u32) *ppos;
+
+	result = fb_sys_write(info, buf, count, ppos);
+
+	if (result > 0) {
+		int start = max((int)(offset / info->fix.line_length) - 1, 0);
+		int lines = min((u32)((result / info->fix.line_length) + 1),
+				(u32)info->var.yres);
+
+		ufx_handle_damage(dev, 0, start, info->var.xres, lines);
+	}
+
+	return result;
+}
+
+static void ufx_ops_copyarea(struct fb_info *info,
+				const struct fb_copyarea *area)
+{
+
+	struct ufx_data *dev = info->par;
+
+	sys_copyarea(info, area);
+
+	ufx_handle_damage(dev, area->dx, area->dy,
+			area->width, area->height);
+}
+
+static void ufx_ops_imageblit(struct fb_info *info,
+				const struct fb_image *image)
+{
+	struct ufx_data *dev = info->par;
+
+	sys_imageblit(info, image);
+
+	ufx_handle_damage(dev, image->dx, image->dy,
+			image->width, image->height);
+}
+
+static void ufx_ops_fillrect(struct fb_info *info,
+			  const struct fb_fillrect *rect)
+{
+	struct ufx_data *dev = info->par;
+
+	sys_fillrect(info, rect);
+
+	ufx_handle_damage(dev, rect->dx, rect->dy, rect->width,
+			      rect->height);
+}
+
+/* NOTE: fb_defio.c is holding info->fbdefio.mutex
+ *   Touching ANY framebuffer memory that triggers a page fault
+ *   in fb_defio will cause a deadlock, when it also tries to
+ *   grab the same mutex. */
+static void ufx_dpy_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+{
+	struct page *cur;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+	struct ufx_data *dev = info->par;
+
+	if (!fb_defio)
+		return;
+
+	if (!atomic_read(&dev->usb_active))
+		return;
+
+	/* walk the written page list and render each to device */
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+		/* create a rectangle of full screen width that encloses the
+		 * entire dirty framebuffer page */
+		const int x = 0;
+		const int width = dev->info->var.xres;
+		const int y = (cur->index << PAGE_SHIFT) / (width * 2);
+		int height = (PAGE_SIZE / (width * 2)) + 1;
+		height = min(height, (int)(dev->info->var.yres - y));
+
+		BUG_ON(y >= dev->info->var.yres);
+		BUG_ON((y + height) > dev->info->var.yres);
+
+		ufx_handle_damage(dev, x, y, width, height);
+	}
+}
+
+static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg)
+{
+	struct ufx_data *dev = info->par;
+	struct dloarea *area = NULL;
+
+	if (!atomic_read(&dev->usb_active))
+		return 0;
+
+	/* TODO: Update X server to get this from sysfs instead */
+	if (cmd = UFX_IOCTL_RETURN_EDID) {
+		char *edid = (char *)arg;
+		if (copy_to_user(edid, dev->edid, dev->edid_size))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* TODO: Help propose a standard fb.h ioctl to report mmap damage */
+	if (cmd = UFX_IOCTL_REPORT_DAMAGE) {
+		/* If we have a damage-aware client, turn fb_defio "off"
+		 * To avoid perf imact of unecessary page fault handling.
+		 * Done by resetting the delay for this fb_info to a very
+		 * long period. Pages will become writable and stay that way.
+		 * Reset to normal value when all clients have closed this fb.
+		 */
+		if (info->fbdefio)
+			info->fbdefio->delay = UFX_DEFIO_WRITE_DISABLE;
+
+		area = (struct dloarea *)arg;
+
+		if (area->x < 0)
+			area->x = 0;
+
+		if (area->x > info->var.xres)
+			area->x = info->var.xres;
+
+		if (area->y < 0)
+			area->y = 0;
+
+		if (area->y > info->var.yres)
+			area->y = info->var.yres;
+
+		ufx_handle_damage(dev, area->x, area->y, area->w, area->h);
+	}
+
+	return 0;
+}
+
+/* taken from vesafb */
+static int
+ufx_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+	       unsigned blue, unsigned transp, struct fb_info *info)
+{
+	int err = 0;
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16) {
+		if (info->var.red.offset = 10) {
+			/* 1:5:5:5 */
+			((u32 *) (info->pseudo_palette))[regno] +			    ((red & 0xf800) >> 1) |
+			    ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+		} else {
+			/* 0:5:6:5 */
+			((u32 *) (info->pseudo_palette))[regno] +			    ((red & 0xf800)) |
+			    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		}
+	}
+
+	return err;
+}
+
+/* It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ * Assumes caller is holding info->lock (for open and release at least) */
+static int ufx_ops_open(struct fb_info *info, int user)
+{
+	struct ufx_data *dev = info->par;
+
+	/* fbcon aggressively connects to first framebuffer it finds,
+	 * preventing other clients (X) from working properly. Usually
+	 * not what the user wants. Fail by default with option to enable. */
+	if ((user = 0) & (!console))
+		return -EBUSY;
+
+	/* If the USB device is gone, we don't accept new opens */
+	if (dev->virtualized)
+		return -ENODEV;
+
+	dev->fb_count++;
+
+	kref_get(&dev->kref);
+
+	if (fb_defio && (info->fbdefio = NULL)) {
+		/* enable defio at last moment if not disabled by client */
+
+		struct fb_deferred_io *fbdefio;
+
+		fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+
+		if (fbdefio) {
+			fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
+			fbdefio->deferred_io = ufx_dpy_deferred_io;
+		}
+
+		info->fbdefio = fbdefio;
+		fb_deferred_io_init(info);
+	}
+
+	pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d",
+		info->node, user, info, dev->fb_count);
+
+	return 0;
+}
+
+/*
+ * Called when all client interfaces to start transactions have been disabled,
+ * and all references to our device instance (ufx_data) are released.
+ * Every transaction must have a reference, so we know are fully spun down
+ */
+static void ufx_free(struct kref *kref)
+{
+	struct ufx_data *dev = container_of(kref, struct ufx_data, kref);
+
+	/* this function will wait for all in-flight urbs to complete */
+	if (dev->urbs.count > 0)
+		ufx_free_urb_list(dev);
+
+	pr_warn("freeing ufx_data %p", dev);
+
+	kfree(dev);
+}
+
+static void ufx_release_urb_work(struct work_struct *work)
+{
+	struct urb_node *unode = container_of(work, struct urb_node,
+					      release_urb_work.work);
+
+	up(&unode->dev->urbs.limit_sem);
+}
+
+static void ufx_free_framebuffer_work(struct work_struct *work)
+{
+	struct ufx_data *dev = container_of(work, struct ufx_data,
+					    free_framebuffer_work.work);
+	struct fb_info *info = dev->info;
+	int node = info->node;
+
+	unregister_framebuffer(info);
+
+	if (info->cmap.len != 0)
+		fb_dealloc_cmap(&info->cmap);
+	if (info->monspecs.modedb)
+		fb_destroy_modedb(info->monspecs.modedb);
+	if (info->screen_base)
+		vfree(info->screen_base);
+
+	fb_destroy_modelist(&info->modelist);
+
+	dev->info = 0;
+
+	/* Assume info structure is freed after this point */
+	framebuffer_release(info);
+
+	pr_warn("fb_info for /dev/fb%d has been freed", node);
+
+	/* ref taken in probe() as part of registering framebfufer */
+	kref_put(&dev->kref, ufx_free);
+}
+
+/*
+ * Assumes caller is holding info->lock mutex (for open and release at least)
+ */
+static int ufx_ops_release(struct fb_info *info, int user)
+{
+	struct ufx_data *dev = info->par;
+
+	dev->fb_count--;
+
+	/* We can't free fb_info here - fbmem will touch it when we return */
+	if (dev->virtualized && (dev->fb_count = 0))
+		schedule_delayed_work(&dev->free_framebuffer_work, HZ);
+
+	if ((dev->fb_count = 0) && (info->fbdefio)) {
+		fb_deferred_io_cleanup(info);
+		kfree(info->fbdefio);
+		info->fbdefio = NULL;
+		info->fbops->fb_mmap = ufx_ops_mmap;
+	}
+
+	pr_warn("released /dev/fb%d user=%d count=%d",
+		  info->node, user, dev->fb_count);
+
+	kref_put(&dev->kref, ufx_free);
+
+	return 0;
+}
+
+/* Check whether a video mode is supported by the chip
+ * We start from monitor's modes, so don't need to filter that here */
+static int ufx_is_valid_mode(struct fb_videomode *mode,
+		struct fb_info *info)
+{
+	if ((mode->xres * mode->yres) > (2048 * 1152)) {
+		pr_warn("%dx%d too many pixels",
+		       mode->xres, mode->yres);
+		return 0;
+	}
+
+	if (mode->pixclock < 5000) {
+		pr_warn("%dx%d %dps pixel clock too fast",
+		       mode->xres, mode->yres, mode->pixclock);
+		return 0;
+	}
+
+	pr_info("%dx%d (pixclk %dps %dMHz) valid mode", mode->xres, mode->yres,
+		mode->pixclock, (1000000 / mode->pixclock));
+	return 1;
+}
+
+static void ufx_var_color_format(struct fb_var_screeninfo *var)
+{
+	const struct fb_bitfield red = { 11, 5, 0 };
+	const struct fb_bitfield green = { 5, 6, 0 };
+	const struct fb_bitfield blue = { 0, 5, 0 };
+
+	var->bits_per_pixel = 16;
+	var->red = red;
+	var->green = green;
+	var->blue = blue;
+}
+
+static int ufx_ops_check_var(struct fb_var_screeninfo *var,
+				struct fb_info *info)
+{
+	struct fb_videomode mode;
+
+	/* TODO: support dynamically changing framebuffer size */
+	if ((var->xres * var->yres * 2) > info->fix.smem_len)
+		return -EINVAL;
+
+	/* set device-specific elements of var unrelated to mode */
+	ufx_var_color_format(var);
+
+	fb_var_to_videomode(&mode, var);
+
+	if (!ufx_is_valid_mode(&mode, info))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ufx_ops_set_par(struct fb_info *info)
+{
+	struct ufx_data *dev = info->par;
+	int result;
+	u16 *pix_framebuffer;
+	int i;
+
+	pr_notice("set_par mode %dx%d", info->var.xres, info->var.yres);
+	result = ufx_set_vid_mode(dev, &info->var);
+
+	if ((result = 0) && (dev->fb_count = 0)) {
+		/* paint greenscreen */
+		pix_framebuffer = (u16 *) info->screen_base;
+		for (i = 0; i < info->fix.smem_len / 2; i++)
+			pix_framebuffer[i] = 0x37e6;
+
+		ufx_handle_damage(dev, 0, 0, info->var.xres, info->var.yres);
+	}
+
+	return result;
+}
+
+/* In order to come back from full DPMS off, we need to set the mode again */
+static int ufx_ops_blank(int blank_mode, struct fb_info *info)
+{
+	struct ufx_data *dev = info->par;
+	ufx_set_vid_mode(dev, &info->var);
+	return 0;
+}
+
+static struct fb_ops ufx_ops = {
+	.owner = THIS_MODULE,
+	.fb_read = fb_sys_read,
+	.fb_write = ufx_ops_write,
+	.fb_setcolreg = ufx_ops_setcolreg,
+	.fb_fillrect = ufx_ops_fillrect,
+	.fb_copyarea = ufx_ops_copyarea,
+	.fb_imageblit = ufx_ops_imageblit,
+	.fb_mmap = ufx_ops_mmap,
+	.fb_ioctl = ufx_ops_ioctl,
+	.fb_open = ufx_ops_open,
+	.fb_release = ufx_ops_release,
+	.fb_blank = ufx_ops_blank,
+	.fb_check_var = ufx_ops_check_var,
+	.fb_set_par = ufx_ops_set_par,
+};
+
+/* Assumes &info->lock held by caller
+ * Assumes no active clients have framebuffer open */
+static int ufx_realloc_framebuffer(struct ufx_data *dev, struct fb_info *info)
+{
+	int retval = -ENOMEM;
+	int old_len = info->fix.smem_len;
+	int new_len;
+	unsigned char *old_fb = info->screen_base;
+	unsigned char *new_fb;
+
+	pr_warn("Reallocating framebuffer. Addresses will change!");
+
+	new_len = info->fix.line_length * info->var.yres;
+
+	if (PAGE_ALIGN(new_len) > old_len) {
+		/*
+		 * Alloc system memory for virtual framebuffer
+		 */
+		new_fb = vmalloc(new_len);
+		if (!new_fb) {
+			pr_err("Virtual framebuffer alloc failed");
+			goto error;
+		}
+
+		if (info->screen_base) {
+			memcpy(new_fb, old_fb, old_len);
+			vfree(info->screen_base);
+		}
+
+		info->screen_base = new_fb;
+		info->fix.smem_len = PAGE_ALIGN(new_len);
+		info->fix.smem_start = (unsigned long) new_fb;
+		info->flags = smscufx_info_flags;
+	}
+
+	retval = 0;
+
+error:
+	return retval;
+}
+
+/* sets up I2C Controller for 100 Kbps, std. speed, 7-bit addr, master,
+ * restart enabled, but no start byte, enable controller */
+static int ufx_i2c_init(struct ufx_data *dev)
+{
+	u32 tmp;
+
+	/* disable the controller before it can be reprogrammed */
+	int status = ufx_reg_write(dev, 0x106C, 0x00);
+	check_warn_return(status, "failed to disable I2C");
+
+	/* Setup the clock count registers
+	 * (12+1) = 13 clks @ 2.5 MHz = 5.2 uS */
+	status = ufx_reg_write(dev, 0x1018, 12);
+	check_warn_return(status, "error writing 0x1018");
+
+	/* (6+8) = 14 clks @ 2.5 MHz = 5.6 uS */
+	status = ufx_reg_write(dev, 0x1014, 6);
+	check_warn_return(status, "error writing 0x1014");
+
+	status = ufx_reg_read(dev, 0x1000, &tmp);
+	check_warn_return(status, "error reading 0x1000");
+
+	/* set speed to std mode */
+	tmp &= ~(0x06);
+	tmp |= 0x02;
+
+	/* 7-bit (not 10-bit) addressing */
+	tmp &= ~(0x10);
+
+	/* enable restart conditions and master mode */
+	tmp |= 0x21;
+
+	status = ufx_reg_write(dev, 0x1000, tmp);
+	check_warn_return(status, "error writing 0x1000");
+
+	/* Set normal tx using target address 0 */
+	status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0xC00, 0x000);
+	check_warn_return(status, "error setting TX mode bits in 0x1004");
+
+	/* Enable the controller */
+	status = ufx_reg_write(dev, 0x106C, 0x01);
+	check_warn_return(status, "failed to enable I2C");
+
+	return 0;
+}
+
+/* sets the I2C port mux and target address */
+static int ufx_i2c_configure(struct ufx_data *dev)
+{
+	int status = ufx_reg_write(dev, 0x106C, 0x00);
+	check_warn_return(status, "failed to disable I2C");
+
+	status = ufx_reg_write(dev, 0x3010, 0x00000000);
+	check_warn_return(status, "failed to write 0x3010");
+
+	/* A0h is std for any EDID, right shifted by one */
+	status = ufx_reg_clear_and_set_bits(dev, 0x1004, 0x3FF,	(0xA0 >> 1));
+	check_warn_return(status, "failed to set TAR bits in 0x1004");
+
+	status = ufx_reg_write(dev, 0x106C, 0x01);
+	check_warn_return(status, "failed to enable I2C");
+
+	return 0;
+}
+
+/* wait for BUSY to clear, with a timeout of 50ms with 10ms sleeps. if no
+ * monitor is connected, there is no error except for timeout */
+static int ufx_i2c_wait_busy(struct ufx_data *dev)
+{
+	u32 tmp;
+	int i, status;
+
+	for (i = 0; i < 15; i++) {
+		status = ufx_reg_read(dev, 0x1100, &tmp);
+		check_warn_return(status, "0x1100 read failed");
+
+		/* if BUSY is clear, check for error */
+		if ((tmp & 0x80000000) = 0) {
+			if (tmp & 0x20000000) {
+				pr_warn("I2C read failed, 0x1100=0x%08x", tmp);
+				return -EIO;
+			}
+
+			return 0;
+		}
+
+		/* perform the first 10 retries without delay */
+		if (i >= 10)
+			msleep(10);
+	}
+
+	pr_warn("I2C access timed out, resetting I2C hardware");
+	status =  ufx_reg_write(dev, 0x1100, 0x40000000);
+	check_warn_return(status, "0x1100 write failed");
+
+	return -ETIMEDOUT;
+}
+
+/* reads a 128-byte EDID block from the currently selected port and TAR */
+static int ufx_read_edid(struct ufx_data *dev, char *edid, int edid_len)
+{
+	int i, j, status;
+	u32 *edid_u32 = (u32 *)edid;
+
+	BUG_ON(edid_len != EDID_LENGTH);
+
+	status = ufx_i2c_configure(dev);
+	if (status < 0) {
+		pr_err("ufx_i2c_configure failed");
+		return status;
+	}
+
+	memset(edid, 0xff, EDID_LENGTH);
+
+	/* Read the 128-byte EDID as 2 bursts of 64 bytes */
+	for (i = 0; i < 2; i++) {
+		u32 temp = 0x28070000 | (63 << 20) | (((u32)(i * 64)) << 8);
+		status = ufx_reg_write(dev, 0x1100, temp);
+		check_warn_return(status, "Failed to write 0x1100");
+
+		temp |= 0x80000000;
+		status = ufx_reg_write(dev, 0x1100, temp);
+		check_warn_return(status, "Failed to write 0x1100");
+
+		status = ufx_i2c_wait_busy(dev);
+		check_warn_return(status, "Timeout waiting for I2C BUSY to clear");
+
+		for (j = 0; j < 16; j++) {
+			u32 data_reg_addr = 0x1110 + (j * 4);
+			status = ufx_reg_read(dev, data_reg_addr, edid_u32++);
+			check_warn_return(status, "Error reading i2c data");
+		}
+	}
+
+	/* all FF's in the first 16 bytes indicates nothing is connected */
+	for (i = 0; i < 16; i++) {
+		if (edid[i] != 0xFF) {
+			pr_info("edid data read succesfully");
+			return EDID_LENGTH;
+		}
+	}
+
+	pr_warn("edid data contains all 0xff");
+	return -ETIMEDOUT;
+}
+
+/* 1) use sw default
+ * 2) Parse into various fb_info structs
+ * 3) Allocate virtual framebuffer memory to back highest res mode
+ *
+ * Parses EDID into three places used by various parts of fbdev:
+ * fb_var_screeninfo contains the timing of the monitor's preferred mode
+ * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+ * fb_info.modelist is a linked list of all monitor & VESA modes which work
+ *
+ * If EDID is not readable/valid, then modelist is all VESA modes,
+ * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+ * Returns 0 if successful */
+static int ufx_setup_modes(struct ufx_data *dev, struct fb_info *info,
+	char *default_edid, size_t default_edid_size)
+{
+	const struct fb_videomode *default_vmode = NULL;
+	char *edid;
+	int i, result = 0, tries = 3;
+
+	if (info->dev) /* only use mutex if info has been registered */
+		mutex_lock(&info->lock);
+
+	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!edid) {
+		result = -ENOMEM;
+		goto error;
+	}
+
+	fb_destroy_modelist(&info->modelist);
+	memset(&info->monspecs, 0, sizeof(info->monspecs));
+
+	/* Try to (re)read EDID from hardware first
+	 * EDID data may return, but not parse as valid
+	 * Try again a few times, in case of e.g. analog cable noise */
+	while (tries--) {
+		i = ufx_read_edid(dev, edid, EDID_LENGTH);
+
+		if (i >= EDID_LENGTH)
+			fb_edid_to_monspecs(edid, &info->monspecs);
+
+		if (info->monspecs.modedb_len > 0) {
+			dev->edid = edid;
+			dev->edid_size = i;
+			break;
+		}
+	}
+
+	/* If that fails, use a previously returned EDID if available */
+	if (info->monspecs.modedb_len = 0) {
+
+		pr_err("Unable to get valid EDID from device/display\n");
+
+		if (dev->edid) {
+			fb_edid_to_monspecs(dev->edid, &info->monspecs);
+			if (info->monspecs.modedb_len > 0)
+				pr_err("Using previously queried EDID\n");
+		}
+	}
+
+	/* If that fails, use the default EDID we were handed */
+	if (info->monspecs.modedb_len = 0) {
+		if (default_edid_size >= EDID_LENGTH) {
+			fb_edid_to_monspecs(default_edid, &info->monspecs);
+			if (info->monspecs.modedb_len > 0) {
+				memcpy(edid, default_edid, default_edid_size);
+				dev->edid = edid;
+				dev->edid_size = default_edid_size;
+				pr_err("Using default/backup EDID\n");
+			}
+		}
+	}
+
+	/* If we've got modes, let's pick a best default mode */
+	if (info->monspecs.modedb_len > 0) {
+
+		for (i = 0; i < info->monspecs.modedb_len; i++) {
+			if (ufx_is_valid_mode(&info->monspecs.modedb[i], info))
+				fb_add_videomode(&info->monspecs.modedb[i],
+					&info->modelist);
+			else /* if we've removed top/best mode */
+				info->monspecs.misc &= ~FB_MISC_1ST_DETAIL;
+		}
+
+		default_vmode = fb_find_best_display(&info->monspecs,
+						     &info->modelist);
+	}
+
+	/* If everything else has failed, fall back to safe default mode */
+	if (default_vmode = NULL) {
+
+		struct fb_videomode fb_vmode = {0};
+
+		/* Add the standard VESA modes to our modelist
+		 * Since we don't have EDID, there may be modes that
+		 * overspec monitor and/or are incorrect aspect ratio, etc.
+		 * But at least the user has a chance to choose
+		 */
+		for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+			if (ufx_is_valid_mode((struct fb_videomode *)
+						&vesa_modes[i], info))
+				fb_add_videomode(&vesa_modes[i],
+						 &info->modelist);
+		}
+
+		/* default to resolution safe for projectors
+		 * (since they are most common case without EDID)
+		 */
+		fb_vmode.xres = 800;
+		fb_vmode.yres = 600;
+		fb_vmode.refresh = 60;
+		default_vmode = fb_find_nearest_mode(&fb_vmode,
+						     &info->modelist);
+	}
+
+	/* If we have good mode and no active clients */
+	if ((default_vmode != NULL) && (dev->fb_count = 0)) {
+
+		fb_videomode_to_var(&info->var, default_vmode);
+		ufx_var_color_format(&info->var);
+
+		/* with mode size info, we can now alloc our framebuffer */
+		memcpy(&info->fix, &ufx_fix, sizeof(ufx_fix));
+		info->fix.line_length = info->var.xres *
+			(info->var.bits_per_pixel / 8);
+
+		result = ufx_realloc_framebuffer(dev, info);
+
+	} else
+		result = -EINVAL;
+
+error:
+	if (edid && (dev->edid != edid))
+		kfree(edid);
+
+	if (info->dev)
+		mutex_unlock(&info->lock);
+
+	return result;
+}
+
+static int ufx_usb_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
+{
+	struct usb_device *usbdev;
+	struct ufx_data *dev = 0;
+	struct fb_info *info = 0;
+	int retval = -ENOMEM;
+	u32 id_rev, fpga_rev;
+
+	/* usb initialization */
+	usbdev = interface_to_usbdev(interface);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev = NULL) {
+		err("ufx_usb_probe: failed alloc of dev struct\n");
+		goto error;
+	}
+
+	/* we need to wait for both usb and fbdev to spin down on disconnect */
+	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
+
+	dev->udev = usbdev;
+	dev->gdev = &usbdev->dev; /* our generic struct device * */
+	usb_set_intfdata(interface, dev);
+
+	pr_info("%s %s - serial #%s\n",
+		usbdev->manufacturer, usbdev->product, usbdev->serial);
+	pr_info("vid_%04x&pid_%04x&rev_%04x driver's ufx_data struct at %p\n",
+		usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+		usbdev->descriptor.bcdDevice, dev);
+	pr_info("console enable=%d\n", console);
+	pr_info("fb_defio enable=%d\n", fb_defio);
+
+	if (!ufx_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+		retval = -ENOMEM;
+		pr_err("ufx_alloc_urb_list failed\n");
+		goto error;
+	}
+
+	/* We don't register a new USB class. Our client interface is fbdev */
+
+	/* allocates framebuffer driver structure, not framebuffer memory */
+	info = framebuffer_alloc(0, &usbdev->dev);
+	if (!info) {
+		retval = -ENOMEM;
+		pr_err("framebuffer_alloc failed\n");
+		goto error;
+	}
+
+	dev->info = info;
+	info->par = dev;
+	info->pseudo_palette = dev->pseudo_palette;
+	info->fbops = &ufx_ops;
+
+	retval = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (retval < 0) {
+		pr_err("fb_alloc_cmap failed %x\n", retval);
+		goto error;
+	}
+
+	INIT_DELAYED_WORK(&dev->free_framebuffer_work,
+			  ufx_free_framebuffer_work);
+
+	INIT_LIST_HEAD(&info->modelist);
+
+	retval = ufx_reg_read(dev, 0x3000, &id_rev);
+	check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval);
+	pr_info("ID_REV register value 0x%08x", id_rev);
+
+	retval = ufx_reg_read(dev, 0x3004, &fpga_rev);
+	check_warn_goto_error(retval, "error %d reading 0x3004 register from device", retval);
+	pr_info("FPGA_REV register value 0x%08x", fpga_rev);
+
+	pr_info("resetting device");
+	retval = ufx_lite_reset(dev);
+	check_warn_goto_error(retval, "error %d resetting device", retval);
+
+	pr_info("configuring system clock");
+	retval = ufx_config_sys_clk(dev);
+	check_warn_goto_error(retval, "error %d configuring system clock", retval);
+
+	pr_info("configuring DDR2 controller");
+	retval = ufx_config_ddr2(dev);
+	check_warn_goto_error(retval, "error %d initialising DDR2 controller", retval);
+
+	pr_info("configuring I2C controller");
+	retval = ufx_i2c_init(dev);
+	check_warn_goto_error(retval, "error %d initialising I2C controller", retval);
+
+	pr_info("selecting display mode");
+	retval = ufx_setup_modes(dev, info, NULL, 0);
+	check_warn_goto_error(retval, "unable to find common mode for display and adapter");
+
+	retval = ufx_reg_set_bits(dev, 0x4000, 0x00000001);
+	check_warn_goto_error(retval, "error %d enabling graphics engine", retval);
+
+	/* ready to begin using device */
+	atomic_set(&dev->usb_active, 1);
+
+	pr_info("checking var");
+	retval = ufx_ops_check_var(&info->var, info);
+	check_warn_goto_error(retval, "error %d ufx_ops_check_var", retval);
+
+	pr_info("setting par");
+	retval = ufx_ops_set_par(info);
+	check_warn_goto_error(retval, "error %d ufx_ops_set_par", retval);
+
+	pr_info("registering framebuffer");
+	retval = register_framebuffer(info);
+	check_warn_goto_error(retval, "error %d register_framebuffer", retval);
+
+	pr_info("SMSC UDX USB device /dev/fb%d attached. %dx%d resolution."
+		" Using %dK framebuffer memory\n", info->node,
+		info->var.xres, info->var.yres, info->fix.smem_len >> 10);
+
+	return 0;
+
+error:
+	if (dev) {
+		if (info) {
+			if (info->cmap.len != 0)
+				fb_dealloc_cmap(&info->cmap);
+			if (info->monspecs.modedb)
+				fb_destroy_modedb(info->monspecs.modedb);
+			if (info->screen_base)
+				vfree(info->screen_base);
+
+			fb_destroy_modelist(&info->modelist);
+
+			framebuffer_release(info);
+		}
+
+		kref_put(&dev->kref, ufx_free); /* ref for framebuffer */
+		kref_put(&dev->kref, ufx_free); /* last ref from kref_init */
+
+		/* dev has been deallocated. Do not dereference */
+	}
+
+	return retval;
+}
+
+static void ufx_usb_disconnect(struct usb_interface *interface)
+{
+	struct ufx_data *dev;
+	struct fb_info *info;
+
+	dev = usb_get_intfdata(interface);
+	info = dev->info;
+
+	pr_info("USB disconnect starting\n");
+
+	/* we virtualize until all fb clients release. Then we free */
+	dev->virtualized = true;
+
+	/* When non-active we'll update virtual framebuffer, but no new urbs */
+	atomic_set(&dev->usb_active, 0);
+
+	usb_set_intfdata(interface, NULL);
+
+	/* if clients still have us open, will be freed on last close */
+	if (dev->fb_count = 0)
+		schedule_delayed_work(&dev->free_framebuffer_work, 0);
+
+	/* release reference taken by kref_init in probe() */
+	kref_put(&dev->kref, ufx_free);
+
+	/* consider ufx_data freed */
+}
+
+static struct usb_driver ufx_driver = {
+	.name = "smscufx",
+	.probe = ufx_usb_probe,
+	.disconnect = ufx_usb_disconnect,
+	.id_table = id_table,
+};
+
+static int __init ufx_module_init(void)
+{
+	int res;
+
+	res = usb_register(&ufx_driver);
+	if (res)
+		err("usb_register failed. Error number %d", res);
+
+	return res;
+}
+
+static void __exit ufx_module_exit(void)
+{
+	usb_deregister(&ufx_driver);
+}
+
+module_init(ufx_module_init);
+module_exit(ufx_module_exit);
+
+static void ufx_urb_completion(struct urb *urb)
+{
+	struct urb_node *unode = urb->context;
+	struct ufx_data *dev = unode->dev;
+	unsigned long flags;
+
+	/* sync/async unlink faults aren't errors */
+	if (urb->status) {
+		if (!(urb->status = -ENOENT ||
+		    urb->status = -ECONNRESET ||
+		    urb->status = -ESHUTDOWN)) {
+			pr_err("%s - nonzero write bulk status received: %d\n",
+				__func__, urb->status);
+			atomic_set(&dev->lost_pixels, 1);
+		}
+	}
+
+	urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
+
+	spin_lock_irqsave(&dev->urbs.lock, flags);
+	list_add_tail(&unode->entry, &dev->urbs.list);
+	dev->urbs.available++;
+	spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+	/* When using fb_defio, we deadlock if up() is called
+	 * while another is waiting. So queue to another process */
+	if (fb_defio)
+		schedule_delayed_work(&unode->release_urb_work, 0);
+	else
+		up(&dev->urbs.limit_sem);
+}
+
+static void ufx_free_urb_list(struct ufx_data *dev)
+{
+	int count = dev->urbs.count;
+	struct list_head *node;
+	struct urb_node *unode;
+	struct urb *urb;
+	int ret;
+	unsigned long flags;
+
+	pr_notice("Waiting for completes and freeing all render urbs\n");
+
+	/* keep waiting and freeing, until we've got 'em all */
+	while (count--) {
+		/* Getting interrupted means a leak, but ok at shutdown*/
+		ret = down_interruptible(&dev->urbs.limit_sem);
+		if (ret)
+			break;
+
+		spin_lock_irqsave(&dev->urbs.lock, flags);
+
+		node = dev->urbs.list.next; /* have reserved one with sem */
+		list_del_init(node);
+
+		spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+		unode = list_entry(node, struct urb_node, entry);
+		urb = unode->urb;
+
+		/* Free each separately allocated piece */
+		usb_free_coherent(urb->dev, dev->urbs.size,
+				  urb->transfer_buffer, urb->transfer_dma);
+		usb_free_urb(urb);
+		kfree(node);
+	}
+}
+
+static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size)
+{
+	int i = 0;
+	struct urb *urb;
+	struct urb_node *unode;
+	char *buf;
+
+	spin_lock_init(&dev->urbs.lock);
+
+	dev->urbs.size = size;
+	INIT_LIST_HEAD(&dev->urbs.list);
+
+	while (i < count) {
+		unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+		if (!unode)
+			break;
+		unode->dev = dev;
+
+		INIT_DELAYED_WORK(&unode->release_urb_work,
+			  ufx_release_urb_work);
+
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			kfree(unode);
+			break;
+		}
+		unode->urb = urb;
+
+		buf = usb_alloc_coherent(dev->udev, size, GFP_KERNEL,
+					 &urb->transfer_dma);
+		if (!buf) {
+			kfree(unode);
+			usb_free_urb(urb);
+			break;
+		}
+
+		/* urb->transfer_buffer_length set to actual before submit */
+		usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
+			buf, size, ufx_urb_completion, unode);
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+		list_add_tail(&unode->entry, &dev->urbs.list);
+
+		i++;
+	}
+
+	sema_init(&dev->urbs.limit_sem, i);
+	dev->urbs.count = i;
+	dev->urbs.available = i;
+
+	pr_notice("allocated %d %d byte urbs\n", i, (int) size);
+
+	return i;
+}
+
+static struct urb *ufx_get_urb(struct ufx_data *dev)
+{
+	int ret = 0;
+	struct list_head *entry;
+	struct urb_node *unode;
+	struct urb *urb = NULL;
+	unsigned long flags;
+
+	/* Wait for an in-flight buffer to complete and get re-queued */
+	ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
+	if (ret) {
+		atomic_set(&dev->lost_pixels, 1);
+		pr_warn("wait for urb interrupted: %x available: %d\n",
+		       ret, dev->urbs.available);
+		goto error;
+	}
+
+	spin_lock_irqsave(&dev->urbs.lock, flags);
+
+	BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
+	entry = dev->urbs.list.next;
+	list_del_init(entry);
+	dev->urbs.available--;
+
+	spin_unlock_irqrestore(&dev->urbs.lock, flags);
+
+	unode = list_entry(entry, struct urb_node, entry);
+	urb = unode->urb;
+
+error:
+	return urb;
+}
+
+static int ufx_submit_urb(struct ufx_data *dev, struct urb *urb, size_t len)
+{
+	int ret;
+
+	BUG_ON(len > dev->urbs.size);
+
+	urb->transfer_buffer_length = len; /* set to actual payload len */
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		ufx_urb_completion(urb); /* because no one else will */
+		atomic_set(&dev->lost_pixels, 1);
+		pr_err("usb_submit_urb error %x\n", ret);
+	}
+	return ret;
+}
+
+module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found");
+
+module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support");
+
+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
+MODULE_DESCRIPTION("SMSC UFX kernel framebuffer driver");
+MODULE_LICENSE("GPL");
-- 
1.7.4.1


^ permalink raw reply related

* Re: How should .fb_check_var adjust parameters ?
From: Florian Tobias Schandinat @ 2011-08-12 12:06 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <201108121308.59532.laurent.pinchart@ideasonboard.com>

Hi Laurent,

On 08/12/2011 11:08 AM, Laurent Pinchart wrote:
> Hi everybody,
>
> I'm implementing support for fb_set_par() in a driver, and came to think about
> how fb_check_var should behave.
>
> The purpose of that operation is to let drivers verify and adjust a given set
> of fb_var_screeninfo parameters. Looking at various fbdev drivers, the
> function behaviour is clearly left to the author's preferences. Some drivers
> return an error when the parameters don't match the hardware capabilities
> exactly, other drivers adjust them in pretty much non-standardized ways, and
> some other drivers mix both behaviours.
>
> Is anyone aware of guidelines regarding how .fb_char_var should be implemented
> ? Under which conditions should it return an error, and under which conditions
> should it adjust parameters ? When adjusting parameters, how should it do so ?
> For instance, if xres>  xres_virtual, should xres be lowered or xres_virtual
> raised ?

I try to stick to
drivers/video/skeletonfb.c

  *	If the var passed in is slightly
  *	off by what the hardware can support then we alter the var PASSED in
  *	to what we can do.
  *
  *      For values that are off, this function must round them _up_ to the
  *      next value that is supported by the hardware.  If the value is
  *      greater than the highest value supported by the hardware, then this
  *      function must return -EINVAL.

Sure that still allows a lot of differences in implementation.


Best regards,

Florian Tobias Schandinat

^ permalink raw reply

* How should .fb_check_var adjust parameters ?
From: Laurent Pinchart @ 2011-08-12 11:08 UTC (permalink / raw)
  To: linux-fbdev

Hi everybody,

I'm implementing support for fb_set_par() in a driver, and came to think about 
how fb_check_var should behave.

The purpose of that operation is to let drivers verify and adjust a given set 
of fb_var_screeninfo parameters. Looking at various fbdev drivers, the 
function behaviour is clearly left to the author's preferences. Some drivers 
return an error when the parameters don't match the hardware capabilities 
exactly, other drivers adjust them in pretty much non-standardized ways, and 
some other drivers mix both behaviours.

Is anyone aware of guidelines regarding how .fb_char_var should be implemented 
? Under which conditions should it return an error, and under which conditions 
should it adjust parameters ? When adjusting parameters, how should it do so ? 
For instance, if xres > xres_virtual, should xres be lowered or xres_virtual 
raised ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH/RFC] fbdev: Add FOURCC-based format configuration API
From: Laurent Pinchart @ 2011-08-11 17:19 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Florian Tobias Schandinat, Guennadi Liakhovetski, Paul Mundt,
	linux-fbdev, linux-media, dri-devel
In-Reply-To: <CAMuHMdUMW3QC_43aKvw2KQqEmzmeXXois8+zFg+S+DG785GwjA@mail.gmail.com>

Hi Geert,

On Monday 01 August 2011 11:49:46 Geert Uytterhoeven wrote:
> On Mon, Aug 1, 2011 at 00:54, Florian Tobias Schandinat wrote:
> > On 07/31/2011 08:32 PM, Geert Uytterhoeven wrote:
> >> On Thu, Jul 28, 2011 at 12:51, Laurent Pinchart wrote:
> >>>> As for struct fb_var_screeninfo fields to support switching to a
> >>>> FOURCC mode, I also prefer an explicit dedicated flag to specify
> >>>> switching to it.
> >>>> Even though using FOURCC doesn't fit under the notion of a videomode,
> >>>> using
> >>>> one of .vmode bits is too tempting, so, I would actually take the
> >>>> plunge and
> >>>> use FB_VMODE_FOURCC.
> >>> 
> >>> Another option would be to consider any grayscale>  1 value as a
> >>> FOURCC. I've
> >>> briefly checked the in-tree drivers: they only assign grayscale with 0
> >>> or 1,
> >>> and check whether grayscale is 0 or different than 0. If a userspace
> >>> application only sets grayscale>  1 when talking to a driver that
> >>> supports the
> >>> FOURCC-based API, we could get rid of the flag.
> >>> 
> >>> What can't be easily found out is whether existing applications set
> >>> grayscale
> >>> to a>  1 value. They would break when used with FOURCC-aware drivers if
> >>> we
> >>> consider any grayscale>  1 value as a FOURCC. Is that a risk we can
> >>> take ?
> >> 
> >> I think we can. I'd expect applications to use either 1 or -1 (i.e.
> >> all ones), both are
> >> invalid FOURCC values.
> >> 
> >> Still, I prefer the nonstd way.
> >> And limiting traditional nonstd values to the lowest 24 bits (there
> >> are no in-tree
> >> drivers using the highest 8 bits, right?).
> > 
> > Okay, it would be okay for me to
> > - write raw FOURCC values in nonstd, enable FOURCC mode if upper byte !> > 0 - not having an explicit flag to enable FOURCC
> > - in FOURCC mode drivers must set visual to FB_VISUAL_FOURCC
> > - making support of FOURCC visible to userspace by capabilites |> > FB_CAP_FOURCC
> > 
> > The capabilities is not strictly necessary but I think it's very useful
> > as - it allows applications to make sure the extension is supported (for
> > example to adjust the UI)
> > - it allows applications to distinguish whether a particular format is
> > not supported or FOURCC at all
> > - it allows signaling further extensions of the API
> > - it does not hurt, one line per driver and still some bytes in fixinfo
> > free
> > 
> > 
> > So using it would look like this:
> > - the driver must have capabilities |= FB_CAP_FOURCC
> > - the application may check capabilities to know whether FOURCC is
> > supported - the application may write a raw FOURCC value in nonstd to
> > request changing to FOURCC mode with this format
> > - when the driver switches to a FOURCC mode it must have visual > > FB_VISUAL_FOURCC and the current FOURCC format in nonstd
> > - the application should check visual and nonstd to make sure it gets
> > what it wanted
> 
> As several of the FOURCC formats duplicate formats you can already specify
> in some other way (e.g. the RGB and greyscale formats), and as FOURCC makes
> life easier for the application writer, I'm wondering whether it makes sense
> to add FOURCC support in the generic layer for drivers that don't support
> it? I.e. the generic layer would fill in fb_var_screeninfo depending on the
> requested FOURCC mode, if possible.

That's a good idea, but I'd like to add that in a second step. I'm working on 
a proof-of-concept by porting a driver to the FOURCC-based API first.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [RFC] fbdev: allow multiple concurrent visible consoles
From: Martin Decky @ 2011-08-11 10:57 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1312799864-3468-1-git-send-email-FlorianSchandinat@gmx.de>

Hello Florian,

> This patch allows having multiple visible consoles that receive
> display updates. For example one can have running "top" to monitor
> the system on fb0 and at the same time work on a shell on fb1.

I hate to report this, because I would really appreciate this feature, 
but your patch (applied against kernel 3.0) breaks my machine.

I have an x86-64 machine with a dual-GPU ATI Radeon HD 4850 X2 (which 
acts essentially as two discrete R700s) driven by the "radeon" KMS driver.

If I use the "fbcon=map:01" boot option to map the even-numbered VCs to 
the first GPU and the odd-numbered VCs to the second GPU, the kernel 
patched with your patch encounters some sort of soft-lockup when 
initializing the second GPU (i.e. creating the fb1) while booting. The 
is no panic or oops message and I can reset the machine by hitting 
ctrl+alt+del, but there is no further progress. I can provide further 
observations if you would like to.


Best regards

Martin Decky

^ permalink raw reply

* Re: [PATCH v3 00/29] Use display information in info not in var for panning
From: Laurent Pinchart @ 2011-08-11  0:25 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1310123683-8064-1-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Florian,

On Wednesday 10 August 2011 23:01:59 Florian Tobias Schandinat wrote:
> On 08/09/2011 12:35 PM, Laurent Pinchart wrote:
> > On Wednesday 13 July 2011 10:24:24 Paul Mundt wrote:
> >> On Fri, Jul 08, 2011 at 01:14:14PM +0200, Laurent Pinchart wrote:
> >>> Hi everybody,
> >>> 
> >>> Here's the third version of the FBIOPAN_DISPLAY fixes patch series.
> >>> 
> >>> As a reminder, while playing with the FBIOPAN_DISPLAY ioctl I noticed
> >>> that many drivers use information from the ioctl argument such as the
> >>> display resolution when they should use the current settings from the
> >>> fb_info structure.
> >>> 
> >>> These 29 patches fix most of those drivers. Missing drivers are ivtv
> >>> (for which a patch has Andy Walls has already pushed a patch),
> >>> sh_mobile_lcdcfb (for which the fix is a bit more complex, I will work
> >>> on it later) and viafb (for which Florian Tobias Schandinat has already
> >>> sent a patch).
> >>> 
> >>> The patches have been compile-tested on architectures for which I have
> >>> a working compiler (x86 and ARM) with allyesconfig. I don't own any
> >>> hardware supported by these drivers so I haven't been able to perform
> >>> additional tests.
> >>> 
> >>> 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 v2, I've fixed a compile issue in the atmel_lcdfb driver
> >>> and added a couple of SoB lines.
> >>> 
> >>> Paul, is it time to push this for 3.1 ?
> >> 
> >> I have the v2 series queued up already, so it would be nice to simply
> >> have the v2->v3 differences as incremental changes that can be piled on.
> >> The signed-off-by lines are not that critical in this case since it's a
> >> largely mechanical change all over the place, so it's primarily the
> >> build fix(es?) that would be nice to have.
> > 
> > I've sent you a fix on top of your v2 series a while ago, and none of
> > these patches made it to v3.1-rc1.
> > 
> > Is fbdev maintained at all ?
> 
> Yes, it is :)

Great :-)

> Well I already wrote to Paul because of this and got a response. Basically
> he had to do other stuff/trees and felt that everything could go in after
> rc1 as well.

I know how being overwhelmed with work feels, so I'm not blaming Paul at all. 
As the last couple of e-mails I've sent him got no reply, and as the patches 
haven't been pushed to v3.1-rc1, I wanted to check if he was still alive :-) 
(or if a technical issue was preventing his replies for reaching me).

> But if the situation persists that he has too much other stuff to do and no
> time left for fbdev I'd be willing to take over maintaining the fbdev stuff.
> So you may rest assured that your work will not be lost and at worst be
> merged in the next merge window.

A delay of one merge window is OK in this case. I'm quite new to fbdev 
development, and still trying to find out how this subsystem is maintained 
(including how fast patches should be pushed, and how to submit urgent fixes 
when required).

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH v3 00/29] Use display information in info not in var for
From: Florian Tobias Schandinat @ 2011-08-10 21:01 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1310123683-8064-1-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Laurent, Paul,

On 08/09/2011 12:35 PM, Laurent Pinchart wrote:
> On Wednesday 13 July 2011 10:24:24 Paul Mundt wrote:
>> On Fri, Jul 08, 2011 at 01:14:14PM +0200, Laurent Pinchart wrote:
>>> Hi everybody,
>>>
>>> Here's the third version of the FBIOPAN_DISPLAY fixes patch series.
>>>
>>> As a reminder, while playing with the FBIOPAN_DISPLAY ioctl I noticed
>>> that many drivers use information from the ioctl argument such as the
>>> display resolution when they should use the current settings from the
>>> fb_info structure.
>>>
>>> These 29 patches fix most of those drivers. Missing drivers are ivtv (for
>>> which a patch has Andy Walls has already pushed a patch),
>>> sh_mobile_lcdcfb (for which the fix is a bit more complex, I will work
>>> on it later) and viafb (for which Florian Tobias Schandinat has already
>>> sent a patch).
>>>
>>> The patches have been compile-tested on architectures for which I have a
>>> working compiler (x86 and ARM) with allyesconfig. I don't own any
>>> hardware supported by these drivers so I haven't been able to perform
>>> additional tests.
>>>
>>> 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 v2, I've fixed a compile issue in the atmel_lcdfb driver and
>>> added a couple of SoB lines.
>>>
>>> Paul, is it time to push this for 3.1 ?
>>
>> I have the v2 series queued up already, so it would be nice to simply
>> have the v2->v3 differences as incremental changes that can be piled on.
>> The signed-off-by lines are not that critical in this case since it's a
>> largely mechanical change all over the place, so it's primarily the build
>> fix(es?) that would be nice to have.
>
> I've sent you a fix on top of your v2 series a while ago, and none of these
> patches made it to v3.1-rc1.
>
> Is fbdev maintained at all ?

Yes, it is :)

Well I already wrote to Paul because of this and got a response. Basically he 
had to do other stuff/trees and felt that everything could go in after rc1 as well.
But if the situation persists that he has too much other stuff to do and no time 
left for fbdev I'd be willing to take over maintaining the fbdev stuff.
So you may rest assured that your work will not be lost and at worst be merged 
in the next merge window.


Best regards,

Florian Tobias Schandinat

^ permalink raw reply

* Re: [PATCH v3 00/29] Use display information in info not in var for panning
From: Laurent Pinchart @ 2011-08-09 12:35 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1310123683-8064-1-git-send-email-laurent.pinchart@ideasonboard.com>

On Wednesday 13 July 2011 10:24:24 Paul Mundt wrote:
> On Fri, Jul 08, 2011 at 01:14:14PM +0200, Laurent Pinchart wrote:
> > Hi everybody,
> > 
> > Here's the third version of the FBIOPAN_DISPLAY fixes patch series.
> > 
> > As a reminder, while playing with the FBIOPAN_DISPLAY ioctl I noticed
> > that many drivers use information from the ioctl argument such as the
> > display resolution when they should use the current settings from the
> > fb_info structure.
> > 
> > These 29 patches fix most of those drivers. Missing drivers are ivtv (for
> > which a patch has Andy Walls has already pushed a patch),
> > sh_mobile_lcdcfb (for which the fix is a bit more complex, I will work
> > on it later) and viafb (for which Florian Tobias Schandinat has already
> > sent a patch).
> > 
> > The patches have been compile-tested on architectures for which I have a
> > working compiler (x86 and ARM) with allyesconfig. I don't own any
> > hardware supported by these drivers so I haven't been able to perform
> > additional tests.
> > 
> > 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 v2, I've fixed a compile issue in the atmel_lcdfb driver and
> > added a couple of SoB lines.
> > 
> > Paul, is it time to push this for 3.1 ?
> 
> I have the v2 series queued up already, so it would be nice to simply
> have the v2->v3 differences as incremental changes that can be piled on.
> The signed-off-by lines are not that critical in this case since it's a
> largely mechanical change all over the place, so it's primarily the build
> fix(es?) that would be nice to have.

I've sent you a fix on top of your v2 series a while ago, and none of these 
patches made it to v3.1-rc1.

Is fbdev maintained at all ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* RE: [PATCH] video: Add a callback 'notify_after' for backlight control
From: JinGoo Han @ 2011-08-09  8:32 UTC (permalink / raw)
  To: dilee-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org,
	lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org
  Cc: jnien-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1312855525-21464-1-git-send-email-dilee@nvidia.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 994 bytes --]

> -----Original Message-----
> From: linux-fbdev-owner@vger.kernel.org [mailto:linux-fbdev-
> owner@vger.kernel.org] On Behalf Of dilee@nvidia.com
> Sent: Tuesday, August 09, 2011 11:30 AM
> To: rpurdie@rpsys.net; lethal@linux-sh.org; akpm@linux-foundation.org;
> arun.murthy@stericsson.com; rmorell@nvidia.com;
> linus.walleij@stericsson.com
> Cc: jnien@nvidia.com; swarren@nvidia.com; linux-fbdev@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-tegra@vger.kernel.org; Dilan Lee
> Subject: [PATCH] video: Add a callback 'notify_after' for backlight
> control
> 
> From: Dilan Lee <dilee@nvidia.com>
> 
> We need a callback to do some things after pwm_enable, pwm_disable
> and pwm_config.
> 
> Signed-off-by: Dilan Lee <dilee@nvidia.com>

Reviewed-by: Jingoo Han <jg1.han@samsung.com>

I reviewed and tested the patch.
It works properly.

Thanks,
Jingoo Han

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±ýöÝzÿâžØ^n‡r¡ö¦zË\x1aëh™¨è­Ú&£ûàz¿äz¹Þ—ú+€Ê+zf£¢·hšˆ§~†­†Ûiÿÿïêÿ‘êçz_è®\x0fæj:+v‰¨þ)ߣøm

^ permalink raw reply

* RE: [PATCH] video: Add a callback 'notify_after' for backlight
From: Arun MURTHY @ 2011-08-09  3:43 UTC (permalink / raw)
  To: dilee-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org,
	lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org
  Cc: jnien-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1312856996-22452-1-git-send-email-dilee-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

> -----Original Message-----
> From: dilee@nvidia.com [mailto:dilee@nvidia.com]
> Sent: Tuesday, August 09, 2011 8:00 AM
> To: rpurdie@rpsys.net; lethal@linux-sh.org; akpm@linux-foundation.org;
> Arun MURTHY; rmorell@nvidia.com; Linus WALLEIJ
> Cc: jnien@nvidia.com; swarren@nvidia.com; linux-fbdev@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-tegra@vger.kernel.org; Dilan Lee
> Subject: [PATCH] video: Add a callback 'notify_after' for backlight
> control
> 
> From: Dilan Lee <dilee@nvidia.com>
> 
> We need a callback to do some things after pwm_enable, pwm_disable
> and pwm_config.
> 
> Signed-off-by: Dilan Lee <dilee@nvidia.com>

Reviewed-by: Arun Murthy <arun.murthy@stericsson.com>


^ permalink raw reply

* Re: [PATCH] video: Add a callback 'notify_after' for backlight
From: Robert Morell @ 2011-08-09  2:34 UTC (permalink / raw)
  To: Dilan Lee
  Cc: rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org,
	lethal-M7jkjyW5wf5g9hUCZPvPmw@public.gmane.org,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org,
	arun.murthy-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org,
	linus.walleij-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org,
	Jordan Nien, Stephen Warren,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1312856996-22452-1-git-send-email-dilee-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On Mon, Aug 08, 2011 at 07:29:56PM -0700, Dilan Lee wrote:
> From: Dilan Lee <dilee@nvidia.com>
> 
> We need a callback to do some things after pwm_enable, pwm_disable
> and pwm_config.
> 
> Signed-off-by: Dilan Lee <dilee@nvidia.com>

Reviewed-by: Robert Morell <rmorell@nvidia.com>

Thanks,
Robert

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox