Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* fb_setcolreg(), CNVT_TOHW() and chan_to_field()
From: Rabin Vincent @ 2011-10-25  7:46 UTC (permalink / raw)
  To: linux-fbdev

I'm trying to figure out the best way to implement fb_setcolreg() for
FB_VISUAL_TRUECOLOR.

14 or so drivers copy/paste the CNVT_TOHW from skeletonfb.c:

 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
 ...
 red = CNVT_TOHW(red, info->var.red.length);

Another 18 or so drivers copy/paste a chan_to_field() function which has
a straightforward shift:

 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
 {
 	chan &= 0xffff;
 	chan >>= 16 - bf->length;
 	return chan << bf->offset;
 }
 ...
 val = chan_to_field(red, &info->var.red);

Both methods return similar values, except that with CNVT_TOHW() the
extreme values seem to have a smaller range than the other values, while
with the chan_to_field() shift all the values have an equal range.

What's the reason behind choosing one over the other?  Could/should a
common function be provided for all the drivers to use?

^ permalink raw reply

* Re: fb_setcolreg(), CNVT_TOHW() and chan_to_field()
From: Geert Uytterhoeven @ 2011-10-25 11:15 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <20111025073349.GB6027@debian>

On Tue, Oct 25, 2011 at 09:34, Rabin Vincent <rabin@rab.in> wrote:
> I'm trying to figure out the best way to implement fb_setcolreg() for
> FB_VISUAL_TRUECOLOR.

FB_VISUAL_TRUECOLOR implies the colormap is read-only.
Perhaps you meant FB_VISUAL_DIRECTCOLOR?

> 14 or so drivers copy/paste the CNVT_TOHW from skeletonfb.c:
>
>  #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
>  ...
>  red = CNVT_TOHW(red, info->var.red.length);
>
> Another 18 or so drivers copy/paste a chan_to_field() function which has
> a straightforward shift:
>
>  static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
>  {
>        chan &= 0xffff;
>        chan >>= 16 - bf->length;
>        return chan << bf->offset;
>  }
>  ...
>  val = chan_to_field(red, &info->var.red);
>
> Both methods return similar values, except that with CNVT_TOHW() the
> extreme values seem to have a smaller range than the other values, while
> with the chan_to_field() shift all the values have an equal range.
>
> What's the reason behind choosing one over the other?  Could/should a
> common function be provided for all the drivers to use?

The idea is to use the full dynamic range of the 16-bit values. I.e. 'all ones'
in the hardware-specific value should map to 'all ones' in the 16-bit expanded
value. So the macros are preferred.

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: fb_setcolreg(), CNVT_TOHW() and chan_to_field()
From: Rabin Vincent @ 2011-10-25 15:25 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <20111025073349.GB6027@debian>

On Tue, Oct 25, 2011 at 01:15:41PM +0200, Geert Uytterhoeven wrote:
> On Tue, Oct 25, 2011 at 09:34, Rabin Vincent <rabin@rab.in> wrote:
> > I'm trying to figure out the best way to implement fb_setcolreg() for
> > FB_VISUAL_TRUECOLOR.
> 
> FB_VISUAL_TRUECOLOR implies the colormap is read-only.
> Perhaps you meant FB_VISUAL_DIRECTCOLOR?

I was referring to the pseudo palette usage for FB_VISUAL_TRUECOLOR, which is
where most of the drivers use chan_to_field(), for example in s3c2410fb.c:

	switch (info->fix.visual) {
	case FB_VISUAL_TRUECOLOR:
		/* true-colour, use pseudo-palette */

		if (regno < 16) {
			u32 *pal = info->pseudo_palette;

			val  = chan_to_field(red,   &info->var.red);

> 
> > 14 or so drivers copy/paste the CNVT_TOHW from skeletonfb.c:
> >
> >  #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
> >  ...
> >  red = CNVT_TOHW(red, info->var.red.length);
> >
> > Another 18 or so drivers copy/paste a chan_to_field() function which has
> > a straightforward shift:
> >
> >  static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
> >  {
> >        chan &= 0xffff;
> >        chan >>= 16 - bf->length;
> >        return chan << bf->offset;
> >  }
> >  ...
> >  val = chan_to_field(red, &info->var.red);
> >
> > Both methods return similar values, except that with CNVT_TOHW() the
> > extreme values seem to have a smaller range than the other values, while
> > with the chan_to_field() shift all the values have an equal range.
> >
> > What's the reason behind choosing one over the other?  Could/should a
> > common function be provided for all the drivers to use?
> 
> The idea is to use the full dynamic range of the 16-bit values. I.e. 'all ones'
> in the hardware-specific value should map to 'all ones' in the 16-bit expanded
> value. So the macros are preferred.

I'm not sure I follow.  In the pseudo palette, where the bf->length is less
than 16, both CNVT_TOHW() and the plain shift return the same values for the
all-ones case.

^ permalink raw reply

* [PATCH] fbtest: fix test011 with xpanstep or ypanstep greater than 1
From: Ondrej Zary @ 2011-10-27 20:31 UTC (permalink / raw)
  To: linux-fbdev

Hello,
this patch fixes test011 in fbtest if framebuffer driver requires xpanstep or
ypanstep to be greater than 1. Without this, test011 fails on savagefb:

ioctl FBIOPAN_DISPLAY: Invalid argument

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>

--- fbtest-orig/tests/test011.c	2011-10-27 22:20:47.000000000 +0200
+++ fbtest/tests/test011.c	2011-10-27 22:22:16.000000000 +0200
@@ -93,16 +93,25 @@ static int linegen_next(struct linegen *
     return 1;
 }
 
-static void move(u32 cx, u32 cy, u32 x1, u32 y1, u32 x2, u32 y2)
+static void move(u32 cx, u32 cy, u32 x1, u32 y1, u32 x2, u32 y2, u32 xpanstep, u32 ypanstep)
 {
     struct linegen gen;
     u32 x, y;
     static int cnt = 0;
 
+    if (xpanstep = 0)
+    	xpanstep = 1;
+    if (ypanstep = 0)
+        ypanstep = 1;
+    x1 /= xpanstep;
+    x2 /= xpanstep;
+    y1 /= ypanstep;
+    y2 /= ypanstep;
+
     linegen_init(&gen, x1, y1, x2, y2);
     while (linegen_next(&gen, &x, &y)) {
 	fill_circle(cx+x, cy+y, 2, cnt & 4 ? black_pixel : white_pixel);
-	fb_pan(x, y);
+	fb_pan(x * xpanstep, y * ypanstep);
 	wait_ms(SLEEP_MS);
 	cnt++;
     }
@@ -137,29 +146,29 @@ static enum test_res test011_func(void)
     dy = fb_fix.ypanstep ? fb_var.yres_virtual-fb_var.yres : 0;
 
     /* move right */
-    move(cx, cy, 0, 0, dx, 0);
+    move(cx, cy, 0, 0, dx, 0, fb_fix.xpanstep, fb_fix.ypanstep);
 
     /* move down */
-    move(cx, cy, dx, 0, dx, dy);
+    move(cx, cy, dx, 0, dx, dy, fb_fix.xpanstep, fb_fix.ypanstep);
 
     /* move left */
-    move(cx, cy, dx, dy, 0, dy);
+    move(cx, cy, dx, dy, 0, dy, fb_fix.xpanstep, fb_fix.ypanstep);
 
     if (dx >= 2 && dy >= 2) {
 	/* move up and right */
-	move(cx, cy, 0, dy, dx/2, 0);
+	move(cx, cy, 0, dy, dx/2, 0, fb_fix.xpanstep, fb_fix.ypanstep);
 
 	/* move right and down */
-	move(cx, cy, dx/2, 0, dx, dy/2);
+	move(cx, cy, dx/2, 0, dx, dy/2, fb_fix.xpanstep, fb_fix.ypanstep);
 
 	/* move left and down */
-	move(cx, cy, dx, dy/2, dx/2, dy);
+	move(cx, cy, dx, dy/2, dx/2, dy, fb_fix.xpanstep, fb_fix.ypanstep);
 
 	/* move up and left */
-	move(cx, cy, dx/2, dy, 0, 0);
+	move(cx, cy, dx/2, dy, 0, 0, fb_fix.xpanstep, fb_fix.ypanstep);
     } else {
 	/* move up */
-	move(cx, cy, 0, dy, 0, 0);
+	move(cx, cy, 0, dy, 0, 0, fb_fix.xpanstep, fb_fix.ypanstep);
     }
 
     wait_for_key(10);


-- 
Ondrej Zary

^ permalink raw reply

* Hello
From: lisa hedstrand @ 2011-10-28 11:36 UTC (permalink / raw)
  To: linux-fbdev

My name is Miss Lisa Please accept my apology if my mode of contacting you will in any way offend you. I am compelled to contact you via this medium because i needed a friend from that part of the world. We will get to know each other in details if my proposition accepted. l am a student in UK but originally from USA.

^ permalink raw reply

* [PATCH v3] Resurrect Intel740 driver: i740fb
From: Ondrej Zary @ 2011-10-28 18:43 UTC (permalink / raw)
  To: linux-fbdev
  Cc: Florian Tobias Schandinat, Paul Mundt, Kernel development list

Hello,
this is an v3 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 was tested on two 8MB cards: Protac AG240D and Diamond Stealth II
G460.

Changes in v3:
 - added suspend/resume support
 - fixed x panning

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>

--- 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-10-24 23:29:42.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
+	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-10-28 20:05:27.615214131 +0200
+++ linux-2.6.39-rc2/drivers/video/i740fb.c	2011-10-28 20:03:34.000000000 +0200
@@ -0,0 +1,1286 @@
+/*
+ * 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 <linux/console.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];
+	struct mutex open_lock;
+	unsigned int ref_count;
+
+	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 =	8,
+	.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);
+}
+
+static int i740fb_open(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	par->ref_count++;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static int i740fb_release(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count = 0) {
+		mutex_unlock(&(par->open_lock));
+		return -EINVAL;
+	}
+
+	par->ref_count--;
+	mutex_unlock(&(par->open_lock));
+
+	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_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n", 1000000 / var->pixclock, DACSPEED8);
+			return -EINVAL;
+		}
+		break;
+	case 9 ... 15:
+		bpp = 15;
+	case 16:
+		if ((((u32)1e6) / var->pixclock) > DACSPEED16) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n", 1000000 / 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_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n", 1000000 / var->pixclock, dacspeed24);
+			return -EINVAL;
+		}
+		break;
+	case 25 ... 32:
+		bpp = 32;
+		if ((((u32)1e6) / var->pixclock) > DACSPEED32) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n", 1000000 / 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 */
+	case 16: /* rrrrrggg gggbbbbb */
+		par->pixelpipe_cfg1 = (var->green.length = 6) ? DISPLAY_16BPP_MODE : DISPLAY_15BPP_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;
+		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;
+			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;
+			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;
+		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;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	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;
+
+	i = i740fb_decode_var(&info->var, par, info);
+	if (i)
+		return i;
+
+	memset(info->screen_base, 0, info->screen_size);
+
+	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[VGA_SEQ_CLOCK_MODE] | 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, VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
+
+	/* 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[VGA_SEQ_CLOCK_MODE]);
+
+	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;
+		if (info->var.green.length = 5)
+			((u32 *)info->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+		else if (info->var.green.length = 6)
+			((u32 *)info->pseudo_palette)[regno] = (red & 0xF800) |	((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+		else
+			return -EINVAL;
+		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;
+	mutex_init(&par->open_lock);
+
+	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;
+
+	/* maximize virtual vertical size for fast scrolling */
+	info->var.yres_virtual = info->fix.smem_len * 8 /
+			(info->var.bits_per_pixel * info->var.xres_virtual);
+
+	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 state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	/* don't disable console during hibernation and wakeup from it */
+	if (state.event = PM_EVENT_FREEZE || state.event = PM_EVENT_PRETHAW)
+		return 0;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	/* do nothing if framebuffer is not active */
+	if (par->ref_count = 0) {
+		mutex_unlock(&(par->open_lock));
+		console_unlock();
+		return 0;
+	}
+
+	fb_set_suspend(info, 1);
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+
+	return 0;
+}
+
+static int i740fb_resume(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	if (par->ref_count = 0)
+		goto fail;
+
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+	if (pci_enable_device(dev))
+		goto fail;
+
+	i740fb_set_par(info);
+	fb_set_suspend(info, 0);
+
+fail:
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+	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-10-28 20:05:27.615214131 +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

* [PATCH v3.1] Resurrect Intel740 driver: i740fb
From: Ondrej Zary @ 2011-10-28 20:50 UTC (permalink / raw)
  To: linux-fbdev
  Cc: Florian Tobias Schandinat, Paul Mundt, Kernel development list

Hello,
this is an v3 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 was tested on two 8MB cards: Protac AG240D and Diamond Stealth II
G460.

Changes in v3:
 - added suspend/resume support
 - fixed x panning

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
---
this time with Makefile patch


--- linux-2.6.39-rc2-orig/drivers/video/Makefile	2011-04-06 03:30:43.000000000 +0200
+++ linux-2.6.39-rc2/drivers/video/Makefile	2011-07-30 11:34:10.000000000 +0200
@@ -36,6 +36,7 @@ obj-$(CONFIG_FB_CYBER2000)        += cyb
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 
+obj-$(CONFIG_FB_I740)		  += i740fb.o
 obj-$(CONFIG_FB_MATROX)		  += matrox/
 obj-$(CONFIG_FB_RIVA)		  += riva/
 obj-$(CONFIG_FB_NVIDIA)		  += nvidia/
--- 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-10-24 23:29:42.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
+	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-10-28 20:05:27.615214131 +0200
+++ linux-2.6.39-rc2/drivers/video/i740fb.c	2011-10-28 20:03:34.000000000 +0200
@@ -0,0 +1,1286 @@
+/*
+ * 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 <linux/console.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];
+	struct mutex open_lock;
+	unsigned int ref_count;
+
+	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 =	8,
+	.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);
+}
+
+static int i740fb_open(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	par->ref_count++;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static int i740fb_release(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count = 0) {
+		mutex_unlock(&(par->open_lock));
+		return -EINVAL;
+	}
+
+	par->ref_count--;
+	mutex_unlock(&(par->open_lock));
+
+	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_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n", 1000000 / var->pixclock, DACSPEED8);
+			return -EINVAL;
+		}
+		break;
+	case 9 ... 15:
+		bpp = 15;
+	case 16:
+		if ((((u32)1e6) / var->pixclock) > DACSPEED16) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n", 1000000 / 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_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n", 1000000 / var->pixclock, dacspeed24);
+			return -EINVAL;
+		}
+		break;
+	case 25 ... 32:
+		bpp = 32;
+		if ((((u32)1e6) / var->pixclock) > DACSPEED32) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n", 1000000 / 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 */
+	case 16: /* rrrrrggg gggbbbbb */
+		par->pixelpipe_cfg1 = (var->green.length = 6) ? DISPLAY_16BPP_MODE : DISPLAY_15BPP_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;
+		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;
+			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;
+			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;
+		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;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	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;
+
+	i = i740fb_decode_var(&info->var, par, info);
+	if (i)
+		return i;
+
+	memset(info->screen_base, 0, info->screen_size);
+
+	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[VGA_SEQ_CLOCK_MODE] | 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, VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
+
+	/* 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[VGA_SEQ_CLOCK_MODE]);
+
+	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;
+		if (info->var.green.length = 5)
+			((u32 *)info->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+		else if (info->var.green.length = 6)
+			((u32 *)info->pseudo_palette)[regno] = (red & 0xF800) |	((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+		else
+			return -EINVAL;
+		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;
+	mutex_init(&par->open_lock);
+
+	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;
+
+	/* maximize virtual vertical size for fast scrolling */
+	info->var.yres_virtual = info->fix.smem_len * 8 /
+			(info->var.bits_per_pixel * info->var.xres_virtual);
+
+	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 state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	/* don't disable console during hibernation and wakeup from it */
+	if (state.event = PM_EVENT_FREEZE || state.event = PM_EVENT_PRETHAW)
+		return 0;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	/* do nothing if framebuffer is not active */
+	if (par->ref_count = 0) {
+		mutex_unlock(&(par->open_lock));
+		console_unlock();
+		return 0;
+	}
+
+	fb_set_suspend(info, 1);
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+
+	return 0;
+}
+
+static int i740fb_resume(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	if (par->ref_count = 0)
+		goto fail;
+
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+	if (pci_enable_device(dev))
+		goto fail;
+
+	i740fb_set_par(info);
+	fb_set_suspend(info, 0);
+
+fail:
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+	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-10-28 20:05:27.615214131 +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

* [GIT PULL] fbdev updates for 3.2
From: Florian Tobias Schandinat @ 2011-10-30 10:14 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: LKML, linux-fbdev@vger.kernel.org

Hi Linus,

please pull the following changes to the fbdev subsystem. It contains

- a series from Laurent which touches many different drivers to sanitize their
panning behavior

- two patches to fix the suspend/resume locking issue

- a little fix to our EDID parsing

- a new driver for SMSC UFX6000/7000 USB display devices

- a new driver for Aeroflex Gaisler GRVGA IP core

- a lot of driver updates for OMAP, sh_mobile, fsl-diu-fb, au1200fb, udlfb and
viafb, a few patches to others

It's the same tree (only a different branch) you used to pull viafb updates from
so, I think, you can trust it. You will probably experience some (trivial) merge
conflicts related to xgifb and OMAP, please let me know if you want me to handle
them.


Thanks,

Florian Tobias Schandinat


The following changes since commit 976d167615b64e14bc1491ca51d424e2ba9a5e84:

  Linux 3.1-rc9 (2011-10-04 18:11:50 -0700)

are available in the git repository at:
  git://github.com/schandinat/linux-2.6.git fbdev-next

Ajay Kumar (1):
      video: s3c-fb: Add S5P64X0 specific s3c_fb_driverdata

Anatolij Gustschin (1):
      video: mb862xx-i2c: fix for reliable decoder register access

Andrew Kephart (1):
      udlfb: Search config descriptor if not at device level

Andy Doan (1):
      OMAPFB: make debug message more useful

Archit Taneja (26):
      OMAP: DSS2: DISPC: Prepare dispc_dump_regs() for shortening
      OMAP: DSS2: DISPC: Shorten dispc_dump_regs()
      OMAP: DSS2: DISPC: dispc_save_context() and dispc_restore_context() cleanup
      OMAP: DSS2: DISPC: Shorten _dispc_set_color_conv_coef()
      OMAP: DSS2: Use a macro to declare size of the fifo_size array in dispc.c
      OMAP: DSS2: Use MIPI DSI enums from include/video/mipi_display.h
      OMAP: DSS2: DSI: Represent L4 and VP as sources of VC instead of modes
      OMAP: DSS2: Create enum for DSI operation modes
      OMAP: DSS2: DSI: Introduce generic write functions
      OMAP: DSS2: DSI: Remove functions dsi_vc_dcs_read_1() and dsi_vc_dcs_read_2()
      OMAP: DSS2: DSI: Split dsi_vc_dcs_read() into 2 functions
      OMAP: DSS2: DSI: Introduce generic read functions
      OMAP: DSS2: Clean up stallmode and io pad mode selection
      OMAP: DSS2: Create an enum for DSI pixel formats
      OMAP: DSS2: DSI: Send zero length packet in dsi_vc_send_null()
      OMAP: DSS2: DSI Video mode support
      OMAPDSS: DISPC: Reduce the number of arguments in dispc_ovl_setup()
      OMAPDSS: DISPC: Pass overlay params as arguments to dispc_ovl_setup()
      OMAPDSS: DISPC: Create helper function dispc_mgr_is_lcd()
      OMAPDSS: DISPC: Get correct pixel clock for TV manager
      OMAPDSS: DISPC: Remove hardcoded use of PPL in five tap clock calculation
      OMAPDSS: DISPC: Clean up scaling related clock and five tap calculations
      OMAPDSS: FEATURES: Create a range param to get max downscaling
      OMAPDSS/OMAP_VOUT: Fix incorrect OMAP3-alpha compatibility setting
      OMAPDSS: DISPC: VIDEO3 pipeline support
      OMAPDSS: DISPC: zorder support for DSS overlays

Arnd Bergmann (1):
      video/omap: fix build dependencies

Axel Lin (3):
      video: mxsfb: add missing include of linux/module.h
      video: nuc900fb: remove include of mach/clkdev.h
      video: platinumfb: Add __devexit_p at necessary place

Bernie Thompson (4):
      drivers/video/udlfb match class, subclass, and protocol
      udlfb: add more comprehensive support for DPMS FB_BLANK_* modes
      udlfb: Enable fb_defio by default
      udlfb: Enable fbcon access to framebuffer by default

Bruno Prémont (1):
      fb: sh-mobile: Fix deadlock risk between lock_fb_info() and console_lock()

Damian Hobson-Garcia (5):
      fbdev: sh_mobile_meram: Enable runtime PM
      fbdev: sh_mobile_meram: Enable/disable MERAM along with LCDC
      fbdev: sh_mobile_meram: Move private data from .h to .c
      fbdev: sh_mobile_meram: Backup/restore device registers on shutdown/resume
      fbdev: sh_mobile_meram: Assign meram to the SH7372_A4LC power domain

Dan Carpenter (1):
      smscufx: change edid data to u8 instead of char

Daniel Morsing (1):
      OMAP: DSS2: Don't allow moving managers away from enabled displays

Dima Zavin (1):
      OMAP: DSS: dispc: enable/disable clocks in error handler

Dr. David Alan Gilbert (1):
      udlfb: fix issues found with Sparse static analysis

Florian Tobias Schandinat (21):
      viafb: use display information in info not in var for panning
      viafb: improve pitch handling
      viafb: use more compact modesetting functions
      viafb: kill viafb_load_crtc_timing
      viafb: remove superfluous register unlocking/locking
      viafb: remove superfluous mode lookup
      viafb: simplify viafb_fill_crtc_timing
      viafb: remove 640x480-60 CRT special case
      viafb: add new funcions to select a single mode
      viafb: eliminate viafb_get_pixclock
      viafb: use information in var for modesetting
      viafb: seperate hardware initialization
      viafb: eliminate modetable dependancy of LCD modesetting
      viafb: get rid of the remaining modetable structure assumptions
      Merge commit 'v3.1-rc2' into HEAD
      Merge branch 'pan-fixes' of git://linuxtv.org/pinchartl/fbdev into fbdev-next
      Merge branch 'master' of git://git.kernel.org/.../lethal/fbdev-3.x into
fbdev-next
      Merge branch 'sh-mobile-lcdc' of git://linuxtv.org/pinchartl/fbdev into
fbdev-next
      Merge branch 'viafb-next' of git://github.com/schandinat/linux-2.6 into
fbdev-next
      Merge commit 'v3.1-rc9' into fbdev-next
      Merge branch 'for-florian' of git://gitorious.org/linux-omap-dss2/linux
into fbdev-next

Herton Ronaldo Krzesinski (1):
      fb: avoid possible deadlock caused by fb_set_suspend

Jean Delvare (1):
      carminefb: Fix module parameters permissions

Jesper Juhl (1):
      Remove unneeded version.h includes from drivers/video/

Jingoo Han (1):
      video: s3c-fb: Add support EXYNOS4 FIMD

Joe Perches (1):
      video: Fix speficied typo

Julia Lawall (1):
      drivers/video/msm/mdp.c: adjust error handling code

Kay Sievers (1):
      drivers/video/udlfb bind framebuffer to interface.

Kristoffer Glembo (1):
      video: Add Aeroflex Gaisler GRVGA framebuffer device driver

Laurent Pinchart (77):
      vfb: use display information in info not in var for panning
      staging: xgifb: use display information in info not in var for panning
      acornfb: Dont BUG() on invalid pan parameters
      s3fb: use display information in info not in var for panning
      mx3fb: use display information in info not in var for panning
      neofb: use display information in info not in var for panning
      savagefb: use display information in info not in var for panning
      sm501fb: use display information in info not in var for panning
      imsttfb: use display information in info not in var for panning
      gxt4500: use display information in info not in var for panning
      pm2fb: use display information in info not in var for panning
      sisfb: use display information in info not in var for panning
      atmel_lcdfb: use display information in info not in var for panning
      intelfb: use display information in info not in var for panning
      tridentfb: use display information in info not in var for panning
      vga16fb: use display information in info not in var for panning
      radeonfb: use display information in info not in var for panning
      hgafb: use display information in info not in var for panning
      pm3fb: use display information in info not in var for panning
      acornfb: use display information in info not in var for panning
      fbdev: unicore32: use display information in info not in var for panning
      s3c-fb: use display information in info not in var for panning
      mb862xxfb: use display information in info not in var for panning
      g364fb: use display information in info not in var for panning
      arkfb: use display information in info not in var for panning
      68328fb: use display information in info not in var for panning
      vt8623fb: use display information in info not in var for panning
      vt8500lcdfb: use display information in info not in var for panning
      fbdev: da8xx: use display information in info not in var for panning
      fbdev: sh_mobile_lcdc: Turn dot clock on before resuming from runtime PM
      fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
      fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
      fbdev: sh_mobile_lcdc: Compute clock pattern using divider denominator
      fbdev: sh_mobile_lcdc: Split LCDC start code from sh_mobile_lcdc_start
      fbdev: sh_mobile_lcdc: Store the frame buffer base address when panning
      fbdev: sh_mobile_lcdc: Restart LCDC in runtime PM resume handler
      fbdev: sh_mobile_meram: Replace hardcoded register values with macros
      fbdev: sh_mobile_meram: Validate ICB configuration outside mutex
      fbdev: sh_mobile_meram: Fix MExxCTL register save on runtime PM suspend
      fbdev: sh_mobile_meram: Remove unneeded sh_mobile_meram.h
      68328fb: use display information in info not in var for panning
      acornfb: Dont BUG() on invalid pan parameters
      acornfb: use display information in info not in var for panning
      arkfb: use display information in info not in var for panning
      atmel_lcdfb: use display information in info not in var for panning
      radeonfb: use display information in info not in var for panning
      fbdev: da8xx: use display information in info not in var for panning
      fbdev: unicore32: use display information in info not in var for panning
      g364fb: use display information in info not in var for panning
      gxt4500: use display information in info not in var for panning
      hgafb: use display information in info not in var for panning
      imsttfb: use display information in info not in var for panning
      intelfb: use display information in info not in var for panning
      mb862xxfb: use display information in info not in var for panning
      mx3fb: use display information in info not in var for panning
      neofb: use display information in info not in var for panning
      pm2fb: use display information in info not in var for panning
      pm3fb: use display information in info not in var for panning
      s3c-fb: use display information in info not in var for panning
      s3fb: use display information in info not in var for panning
      savagefb: use display information in info not in var for panning
      sisfb: use display information in info not in var for panning
      sm501fb: use display information in info not in var for panning
      tridentfb: use display information in info not in var for panning
      vfb: use display information in info not in var for panning
      vga16fb: use display information in info not in var for panning
      vt8500lcdfb: use display information in info not in var for panning
      vt8623fb: use display information in info not in var for panning
      staging: xgifb: use display information in info not in var for panning
      sh_mobile_meram: Reset ICBs at unregistration time
      fbdev: sh_mobile_lcdc: Adjust requested parameters in .fb_check_var
      fbdev: sh_mobile_lcdc: Add support for format changes at runtime
      fbdev: sh_mobile_lcdc: use display information in info for panning
      fbdev: sh_mobile_lcdc: Update fix.line_length in .fb_set_par()
      fbdev: sh_mobile_lcdc: Avoid forward declarations
      fbdev: sh_mobile_lcdc: Split channel initialization from probe function
      fbdev: sh_mobile_lcdc: Remove sh_mobile_lcdc_set_bpp()

Manjunathappa, Prakash (2):
      video: da8xx-fb: Interrupt configuration of revised LCDC IP
      video: da8xx-fb: Increased resolution configuration of revised LCDC IP

Manuel Lauss (7):
      au1200fb: use framebuffer_alloc()
      au1200fb: fixup PM
      au1200fb: make number of windows configurable at load time.
      au1200fb: switch to FB_SYS helpers
      au1200fb: fix hardcoded IRQ
      fbdev: au1200fb: silence debug output
      fb: fix au1100fb bitrot.

Mayuresh Janorkar (1):
      OMAP: DSS2: Add picodlp panel driver

Mythri P K (14):
      OMAP4: DSS2: HDMI: HDMI clean up to pass base_address
      OMAP4: DSS2: HDMI: Move pll and video configuration
      OMAP4: DSS2: HDMI: Use specific HDMI timings structure
      OMAP4: DSS2: HDMI: Move HDMI IP independent generic header
      OMAP4: DSS2: HDMI: Move the EDID definition from HDMI
      OMAP4: DSS2: HDMI: Split the current HDMI driver to move
      OMAP4: DSS2: HDMI: Move the HDMI IP dependent audio
      OMAP4: DSS2: HDMI: Rename the functions in HDMI IP library
      OMAP4: DSS2: HDMI: Function pointer approach to call
      OMAP4: DSS2: Rename hdmi_omap4_panel.c to hdmi_panel.c
      OMAPDSS: HDMI: Move the comments in avi infoframe
      OMAPDSS: HDMI: Replace hdmi_reg struct with u16
      OMAPDSS: HDMI: Add missing register definitions
      OMAPDSS: HDMI: Add support to dump registers through debugfs

Paul Mundt (4):
      Merge branch 'fbdev/panning-fixes'
      Merge branch 'fbdev/stable-updates'
      Merge branch 'fbdev/stable-updates'
      Merge branch 'viafb-next' of git://github.com/schandinat/linux-2.6

Steve Glendinning (2):
      Add support for SMSC UFX6000/7000 USB display adapters
      smscufx: reduce number of casts in ufx_raw_rect

Stuart Hopkins (1):
      udlfb: Add module option to do without shadow framebuffer

Tejun Heo (1):
      video: don't use flush_scheduled_work() in fb_defio

Thomas Weber (2):
      OMAP: DSS2: Support for Innolux AT070TN83
      OMAP: Devkit8000: Change lcd driver to AT070TN83

Timur Tabi (24):
      drivers/video: use strings to specify the Freescale DIU monitor port
      fbdev: fix indentation in modedb.c
      drivers/video: fsl-diu-fb: clean up whitespace and formatting
      drivers/video: fsl-diu-fb: clean up printk usage
      drivers/video: fsl-diu-fb: remove unused ioctls
      drivers/video: fsl-diu-fb: fix compilation warning
      drivers/video: fsl-diu-fb: improve device tree usage
      drivers/video: fsl-diu-fb: remove redundant default video mode
      drivers/video: fsl-diu-fb: improve local variable usage in some functions
      drivers/video: fsl-diu-fb: set the driver name to "fsl-diu-fb"
      drivers/video: fsl-diu-fb: fix potential memcpy buffer overflow bug
      drivers/video: fsl-diu-fb: fix memory leak on error
      drivers/video: fsl-diu-fb: use a normal for-loop to uninstall framebuffers
      drivers/video: fsl-diu-fb: the video buffer is not I/O memory
      drivers/video: fsl-diu-fb: remove unusued MEM_ALLOC_THRESHOLD
      drivers/video: fsl-diu-fb: fix some ioctls
      drivers/video: fsl-diu-fb: move some definitions out of the header file
      drivers/video: fsl-diu-fb: remove broken screen blanking support
      drivers/video: fsl-diu-fb: add several new video modes
      drivers/video: fsl-diu-fb: use an enum for the AOI index
      drivers/video: fsl-diu-fb: remove unused panel operating mode support
      drivers/video: fsl-diu-fb: only DIU modes 0 and 1 are supported
      drivers/video: fsl-diu-fb: merge diu_hw into fsl_diu_data
      drivers/video: fsl-diu-fb: merge diu_pool into fsl_diu_data

Tomi Valkeinen (64):
      fbdev: fix parsing of standard timings
      OMAP: DSS2: PicoDLP: fix error handling in power_on
      OMAP: DSS2: check for manager when enabling display
      Revert "HACK: OMAP: DSS2: clk hack for OMAP2/3"
      Revert "OMAP: DSS2: HDMI: fix hdmi clock name"
      OMAP: DSS2: remove unneeded fck enable/disables
      OMAP: DSS2: Change DSI device naming
      OMAP4: TWL: Add common omapdss supplies
      OMAP: DSS2: DSI: Improve dsi_mux_pads parameters
      OMAP: DSS2: Implement dsi_mux_pads for OMAP4
      OMAP: OMAPFB: make omapfb start even when a display is missing a driver
      OMAP: DSS2: fix clock sources on error and uninit
      OMAP: DSS2: Handle manager change in apply
      OMAP: DSS2: Remove "EXPERIMENTAL" from Kconfig
      OMAP: DSS2: Remove support for non-DISPC overlays
      OMAP: DSS2: DISPC: use lookup tables for bit shifts
      OMAP: DSS2: Add overlay caps to DSS features
      OMAP: DSS2: Add GLOBAL_ALPHA & PRE_MULT_ALPHA to ovl caps
      OMAP: DSS2: string parsing cleanups
      OMAP: OMAPFB: string parsing cleanups
      OMAP: DSS2: DISPC: remove non-existing func prototypes
      OMAP: DSS2: DISPC: rename overlay related funcs
      OMAP: DSS2: DISPC: rename manager related funcs
      OMAP: DSS2: reorganize functions in dss.h
      OMAP: DSS2: DISPC: Fix minimum PCD value
      OMAP: DSS2: HDMI: use default dividers
      OMAP: DSS2: HDMI: change regn definition
      OMAP: DSS2: DSI: Add comment about regn
      OMAP: DSS2: DISPC: Add missing IRQ  definitions
      OMAP: DSS2: add dss_get_hdmi_venc_clk_source()
      OMAP: DSS2: DISPC: improve dispc_mgr_enable_digit_out()
      OMAP: DSS2: HDMI: improve hdmi output enable
      OMAP: DSS2: add read_edid() to omap_dss_driver struct
      OMAP: DSS2: add detect() to omap_dss_driver struct
      OMAP: DSS2: HDMI: make set_timing saner
      OMAP: DSS2: HDMI: implement read_edid()
      OMAP: DSS2: HDMI: remove edid parsing
      OMAP: DSS2: HDMI: split hdmi_core_ddc_edid
      OMAP: DSS2: HDMI: clean up edid reading & fix checksum
      OMAP: DSS2: HDMI: remove error prints in check_timings
      OMAP: DSS2: HDMI: implement detect()
      OMAP: DSS2: add panel-dvi driver
      OMAP: use dvi panel driver instead of generic-dpi
      OMAP: stalker: Remove LCD device from board file
      OMAP: DSS2: panel-generic-dpi: remove "generic" panel
      OMAP: Add DDC i2c_bus_num to board files
      OMAPFB: find best mode from edid
      OMAPDSS: Taal: remove external backlight support
      OMAPFB: Remove unused lcd drivers
      OMAPDSS: Port 2430sdp display driver to DSS2
      OMAPDSS: Port the H4 display driver to DSS2
      OMAPDSS: Port the Apollon display driver to DSS2
      OMAPDSS: Add N800 panel driver
      OMAPDSS: remove vaddr from overlay info
      OMAP: 4430SDP: Remove unneeded lcd config
      OMAP4: 4430SDP: Add panel support to board file
      OMAP4: 4430SDP: Add picodlp support to board file
      OMAP: RX51: Remove unused old omapfb stuff
      OMAP: omap3touchbook: Remove unused lcd stuff
      OMAP: 2420SDP: Port the display driver to new DSS2
      OMAP: LDP: Port the display driver to new DSS2
      OMAP: H4: Port the display driver to new DSS2
      OMAP: Apollon: Port the display driver to new DSS2
      OMAPDSS: picodlp: add missing #include <linux/module.h>

Wang Shaoyan (2):
      viafb: fix pointer type missmatch
      viafb: replace strict_strtoul to kstrto* and check return value

Wolfram Sang (1):
      video: s3c2410: remove unused variable

Wolfram Stering (1):
      mx3fb: fix NULL pointer dereference in screen blanking.

Yong Zhang (1):
      video: irq: Remove IRQF_DISABLED

 Documentation/fb/udlfb.txt                         |   39 +-
 MAINTAINERS                                        |    6 +
 arch/arm/mach-omap2/board-2430sdp.c                |   78 +-
 arch/arm/mach-omap2/board-3430sdp.c                |    7 +-
 arch/arm/mach-omap2/board-4430sdp.c                |  208 ++-
 arch/arm/mach-omap2/board-am3517evm.c              |    6 +-
 arch/arm/mach-omap2/board-apollon.c                |   35 +-
 arch/arm/mach-omap2/board-cm-t35.c                 |    6 +-
 arch/arm/mach-omap2/board-devkit8000.c             |   10 +-
 arch/arm/mach-omap2/board-h4.c                     |   42 +-
 arch/arm/mach-omap2/board-igep0020.c               |    8 +-
 arch/arm/mach-omap2/board-ldp.c                    |  123 ++-
 arch/arm/mach-omap2/board-omap3beagle.c            |    8 +-
 arch/arm/mach-omap2/board-omap3evm.c               |    7 +-
 arch/arm/mach-omap2/board-omap3pandora.c           |    2 +-
 arch/arm/mach-omap2/board-omap3stalker.c           |   40 +-
 arch/arm/mach-omap2/board-omap3touchbook.c         |   18 -
 arch/arm/mach-omap2/board-omap4panda.c             |    8 +-
 arch/arm/mach-omap2/board-overo.c                  |    7 +-
 arch/arm/mach-omap2/board-rx51.c                   |   25 -
 arch/arm/mach-omap2/display.c                      |   60 +-
 arch/arm/mach-omap2/twl-common.c                   |   11 +-
 arch/arm/mach-shmobile/board-mackerel.c            |    1 +
 arch/powerpc/platforms/512x/mpc512x_shared.c       |   24 +-
 arch/powerpc/platforms/85xx/p1022_ds.c             |   47 +-
 arch/powerpc/platforms/86xx/mpc8610_hpcd.c         |   55 +-
 arch/powerpc/sysdev/fsl_soc.h                      |   25 +-
 drivers/media/video/omap/omap_vout.c               |   18 +-
 drivers/staging/xgifb/XGI_main_26.c                |   22 +-
 drivers/video/68328fb.c                            |    4 +-
 drivers/video/Kconfig                              |   34 +-
 drivers/video/Makefile                             |    2 +
 drivers/video/acornfb.c                            |    5 +-
 drivers/video/arkfb.c                              |    9 +-
 drivers/video/atmel_lcdfb.c                        |   15 +-
 drivers/video/aty/radeon_base.c                    |   10 +-
 drivers/video/au1100fb.c                           |  181 +--
 drivers/video/au1100fb.h                           |    6 +-
 drivers/video/au1200fb.c                           |  299 ++--
 drivers/video/backlight/adp8860_bl.c               |    1 -
 drivers/video/backlight/adp8870_bl.c               |    1 -
 drivers/video/bf54x-lq043fb.c                      |    2 +-
 drivers/video/bfin-lq035q1-fb.c                    |    2 +-
 drivers/video/bfin-t350mcqb-fb.c                   |    2 +-
 drivers/video/bfin_adv7393fb.c                     |    2 +-
 drivers/video/carminefb.c                          |    6 +-
 drivers/video/controlfb.c                          |    2 +-
 drivers/video/da8xx-fb.c                           |  186 ++-
 drivers/video/fb-puv3.c                            |    4 +-
 drivers/video/fb_defio.c                           |    3 +-
 drivers/video/fbmem.c                              |    3 -
 drivers/video/fbmon.c                              |   21 +-
 drivers/video/fbsysfs.c                            |    3 +
 drivers/video/fsl-diu-fb.c                         |  992 +++++-----
 drivers/video/g364fb.c                             |    5 +-
 drivers/video/grvga.c                              |  579 ++++++
 drivers/video/gxt4500.c                            |    4 +-
 drivers/video/hgafb.c                              |    4 +-
 drivers/video/imsttfb.c                            |    2 +-
 drivers/video/intelfb/intelfbhw.c                  |    6 +-
 drivers/video/mb862xx/mb862xx-i2c.c                |    2 +-
 drivers/video/mb862xx/mb862xxfbdrv.c               |    6 +-
 drivers/video/modedb.c                             |  444 +++---
 drivers/video/msm/mddi.c                           |    2 +-
 drivers/video/msm/mdp.c                            |    6 +-
 drivers/video/mx3fb.c                              |   19 +-
 drivers/video/mxsfb.c                              |    1 +
 drivers/video/neofb.c                              |    4 +-
 drivers/video/nuc900fb.c                           |    3 +-
 drivers/video/omap/Kconfig                         |   29 -
 drivers/video/omap/Makefile                        |    8 -
 drivers/video/omap/lcd_2430sdp.c                   |  203 --
 drivers/video/omap/lcd_apollon.c                   |  136 --
 drivers/video/omap/lcd_h4.c                        |  117 --
 drivers/video/omap/lcd_ldp.c                       |  201 --
 drivers/video/omap/lcd_omap3beagle.c               |  130 --
 drivers/video/omap/lcd_omap3evm.c                  |  193 --
 drivers/video/omap/lcd_overo.c                     |  180 --
 drivers/video/omap2/displays/Kconfig               |   28 +-
 drivers/video/omap2/displays/Makefile              |    3 +
 drivers/video/omap2/displays/panel-dvi.c           |  363 ++++
 drivers/video/omap2/displays/panel-generic-dpi.c   |  113 +-
 drivers/video/omap2/displays/panel-n8x0.c          |  747 ++++++++
 drivers/video/omap2/displays/panel-picodlp.c       |  594 ++++++
 drivers/video/omap2/displays/panel-picodlp.h       |  288 +++
 drivers/video/omap2/displays/panel-taal.c          |  125 +-
 drivers/video/omap2/dss/Kconfig                    |    2 +-
 drivers/video/omap2/dss/Makefile                   |    2 +-
 drivers/video/omap2/dss/core.c                     |    4 +
 drivers/video/omap2/dss/dispc.c                    | 1700 +++++++----------
 drivers/video/omap2/dss/dispc.h                    |   57 +
 drivers/video/omap2/dss/display.c                  |   31 +-
 drivers/video/omap2/dss/dpi.c                      |   28 +-
 drivers/video/omap2/dss/dsi.c                      |  929 ++++++----
 drivers/video/omap2/dss/dss.c                      |   18 +-
 drivers/video/omap2/dss/dss.h                      |  156 +-
 drivers/video/omap2/dss/dss_features.c             |  130 ++-
 drivers/video/omap2/dss/dss_features.h             |   17 +-
 drivers/video/omap2/dss/hdmi.c                     | 1260 ++-----------
 .../omap2/dss/{hdmi_omap4_panel.c => hdmi_panel.c} |   68 +-
 drivers/video/omap2/dss/manager.c                  |  191 +--
 drivers/video/omap2/dss/overlay.c                  |  122 +-
 drivers/video/omap2/dss/rfbi.c                     |   45 +-
 drivers/video/omap2/dss/sdi.c                      |   19 +-
 drivers/video/omap2/dss/ti_hdmi.h                  |  138 ++
 drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c          | 1239 ++++++++++++
 .../video/omap2/dss/{hdmi.h => ti_hdmi_4xxx_ip.h}  |  400 ++---
 drivers/video/omap2/dss/venc.c                     |   27 +-
 drivers/video/omap2/omapfb/Kconfig                 |    2 +-
 drivers/video/omap2/omapfb/omapfb-main.c           |  134 ++-
 drivers/video/omap2/omapfb/omapfb-sysfs.c          |    6 +-
 drivers/video/platinumfb.c                         |    4 +-
 drivers/video/pm2fb.c                              |    6 +-
 drivers/video/pm3fb.c                              |    6 +-
 drivers/video/ps3fb.c                              |    2 +-
 drivers/video/pxa3xx-gcu.c                         |    4 +-
 drivers/video/pxafb.c                              |    2 +-
 drivers/video/s3c-fb.c                             |  117 ++-
 drivers/video/s3c2410fb.c                          |    3 +-
 drivers/video/s3fb.c                               |    9 +-
 drivers/video/sa1100fb.c                           |    3 +-
 drivers/video/savage/savagefb_driver.c             |   16 +-
 drivers/video/sh_mobile_hdmi.c                     |   47 +-
 drivers/video/sh_mobile_lcdcfb.c                   | 1162 ++++++------
 drivers/video/sh_mobile_lcdcfb.h                   |   12 +-
 drivers/video/sh_mobile_meram.c                    |  208 ++-
 drivers/video/sh_mobile_meram.h                    |   41 -
 drivers/video/sis/sis_main.c                       |   30 +-
 drivers/video/skeletonfb.c                         |    2 +-
 drivers/video/sm501fb.c                            |    6 +-
 drivers/video/smscufx.c                            | 1994 ++++++++++++++++++++
 drivers/video/tmiofb.c                             |    2 +-
 drivers/video/tridentfb.c                          |    4 +-
 drivers/video/udlfb.c                              |  187 ++-
 drivers/video/valkyriefb.c                         |    2 +-
 drivers/video/vfb.c                                |    4 +-
 drivers/video/vga16fb.c                            |    2 +-
 drivers/video/via/dvi.c                            |   34 +-
 drivers/video/via/dvi.h                            |    3 +-
 drivers/video/via/global.c                         |    2 +
 drivers/video/via/global.h                         |    2 +
 drivers/video/via/hw.c                             |  544 +-----
 drivers/video/via/hw.h                             |  285 +---
 drivers/video/via/lcd.c                            |   53 +-
 drivers/video/via/lcd.h                            |    7 +-
 drivers/video/via/share.h                          |   23 +-
 drivers/video/via/via-core.c                       |    2 +-
 drivers/video/via/via_modesetting.c                |  104 +
 drivers/video/via/via_modesetting.h                |   23 +
 drivers/video/via/viafbdev.c                       |  182 +-
 drivers/video/via/viamode.c                        |   60 +-
 drivers/video/via/viamode.h                        |    4 +-
 drivers/video/vt8500lcdfb.c                        |    6 +-
 drivers/video/vt8623fb.c                           |    9 +-
 drivers/video/xilinxfb.c                           |    1 -
 include/linux/fsl-diu-fb.h                         |   92 +-
 include/video/omap-panel-dvi.h                     |   37 +
 include/video/omap-panel-n8x0.h                    |   15 +
 include/video/omap-panel-nokia-dsi.h               |    8 +-
 include/video/omap-panel-picodlp.h                 |   23 +
 include/video/omapdss.h                            |  100 +-
 include/video/sh_mobile_lcdc.h                     |  135 ++-
 include/video/udlfb.h                              |    1 +
 163 files changed, 12022 insertions(+), 7619 deletions(-)
 create mode 100644 drivers/video/grvga.c
 delete mode 100644 drivers/video/omap/lcd_2430sdp.c
 delete mode 100644 drivers/video/omap/lcd_apollon.c
 delete mode 100644 drivers/video/omap/lcd_h4.c
 delete mode 100644 drivers/video/omap/lcd_ldp.c
 delete mode 100644 drivers/video/omap/lcd_omap3beagle.c
 delete mode 100644 drivers/video/omap/lcd_omap3evm.c
 delete mode 100644 drivers/video/omap/lcd_overo.c
 create mode 100644 drivers/video/omap2/displays/panel-dvi.c
 create mode 100644 drivers/video/omap2/displays/panel-n8x0.c
 create mode 100644 drivers/video/omap2/displays/panel-picodlp.c
 create mode 100644 drivers/video/omap2/displays/panel-picodlp.h
 rename drivers/video/omap2/dss/{hdmi_omap4_panel.c => hdmi_panel.c} (79%)
 create mode 100644 drivers/video/omap2/dss/ti_hdmi.h
 create mode 100644 drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
 rename drivers/video/omap2/dss/{hdmi.h => ti_hdmi_4xxx_ip.h} (54%)
 delete mode 100644 drivers/video/sh_mobile_meram.h
 create mode 100644 drivers/video/smscufx.c
 create mode 100644 include/video/omap-panel-dvi.h
 create mode 100644 include/video/omap-panel-n8x0.h
 create mode 100644 include/video/omap-panel-picodlp.h

^ permalink raw reply

* Re: [RESENT][PATCH v2 0/2] fb: add early fb blank feature
From: Florian Tobias Schandinat @ 2011-10-30 11:24 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <003f01cc8280$7510c5c0$5f325140$%dae@samsung.com>

Hi Andrew,

can you take care of this patch series?
It seems like Richard does no longer handle LCD/backlight stuff (why is he
listed as maintainer?) and I really cannot say whether the patch to the LCD code
is correct and therefore I do not intend to carry such a patch without any Ack.
You can add an "Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>"
to the fb patch 2/2 (well actually I think the order should be swapped as 1 does
not compile without 2) but I ask you to handle it as well as it is useless
without the other patch.


Thanks,

Florian Tobias Schandinat

On 10/04/2011 10:29 AM, Inki Dae wrote:
> this patch adds early fb blank feature that a callback of lcd panel driver
> is called prior to specific fb driver's one. in case of MIPI-DSI based video
> mode LCD Panel, for lcd power off, the power off commands should be
> transferred to lcd panel with display and mipi-dsi controller enabled
> because the commands is set to lcd panel at vsync porch period. and in
> opposite case, the callback of fb driver should be called prior to lcd panel
> driver's one because of same issue. and also if fb_blank mode is changed to
> FB_BLANK_POWERDOWN then display controller would be off(clock disable) but
> lcd panel would be still on. at this time, you could see some issue like
> sparkling on lcd panel because video clock to be delivered to ldi module of
> lcd panel was disabled. this issue could occurs for all lcd panels.
> 
> the callback order is as the following:
> 
> at fb_blank function of fbmem.c
> -> fb_notifier_call_chain(FB_EARLY_EVENT_BLANK)
>        -> lcd panel driver's early_set_power()
> -> info->fbops->fb_blank()
>        -> spcefic fb driver's fb_blank()
> -> fb_notifier_call_chain(FB_EVENT_BLANK)
>        -> lcd panel driver's set_power()
>    -> fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK) if
> info->fops->fb_blank() was failed.
> 
> fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK) would be called to revert the
> effects of previous FB_EARLY_EVENT_BLANK call. and note that if
> early_set_power() of lcd_ops is NULL then early fb blank callback would be
> ignored.
> 
> this patch is based on git repository below:
> git://github.com/schandinat/linux-2.6.git
> branch: fbdev-next
> commit-id: 2b7a905dd0d24d14a1099653ba63b7113a82fc54
> 
> Links to previous versions of the patchset:
> v1: < http://lkml.indiana.edu/hypermail/linux/kernel/1109.1/00413.html >
> 
> Changelog v2:
> fb: add fb early blank event instead of early_blank_mode variable.
>        fb notifier can know whether early blank mode is support or not
> checking if early_set_power callback is NULL or not.
> 
> fb: add exception codes at fb_blank().
>        the effects of previous FB_EARLY_EVENT_BLANK call should be reverted
> if info->fbops->fb_blank() was failed.
> 
> fb: add code clean.
> 
> Changelog RESEND:
> fb: fixed condition.
>      this patch changes 'if (early_ret < 0)' to 'if (!early_ret)' of
> fb_blank function.
> 
> these patch series are as the following:
> [RESEND][PATCH v2 0/2] fb: add early fb blank feature.
>        introduce new early fb blank feature.
> [RESEND][PATCH v2 1/2] lcd: add callbacks for early fb event blank support.
> [RESEND][PATCH v2 2/2] fb: add events for early fb event support.
> 
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply

* Re: [PATCH v2] GIO bus support for SGI IP22/28
From: Florian Tobias Schandinat @ 2011-10-30 15:53 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf
In-Reply-To: <20111020221928.0C2191DA27@solo.franken.de>

On 10/20/2011 10:19 PM, Thomas Bogendoerfer wrote:
> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> ---
> 
> Changes to last version:
> - use EXPORT_SYMBOL_GPL
> - ChallengeS has only 2 slots
> - use subsys_initcall for gio detection
> 
> Florian, the whole patch should go through the MIPS tree, if it's ok for
> you.

No problem. I'm not even sure whether I'm responsible for it as it is not a
framebuffer but a console driver. Anyway I had a look at the console code so you
may add an
	Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
if you like.


Best regards,

Florian Tobias Schandinat

>  arch/mips/include/asm/gio_device.h  |   56 +++++
>  arch/mips/sgi-ip22/Makefile         |    2 +-
>  arch/mips/sgi-ip22/ip22-gio.c       |  414 +++++++++++++++++++++++++++++++++++
>  arch/mips/sgi-ip22/ip22-mc.c        |   10 +-
>  arch/mips/sgi-ip22/ip22-setup.c     |   21 --
>  drivers/video/console/newport_con.c |   61 ++++--
>  6 files changed, 518 insertions(+), 46 deletions(-)
> 
> diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
> new file mode 100644
> index 0000000..5437c84
> --- /dev/null
> +++ b/arch/mips/include/asm/gio_device.h
> @@ -0,0 +1,56 @@
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +
> +struct gio_device_id {
> +	__u8 id;
> +};
> +
> +struct gio_device {
> +	struct device   dev;
> +	struct resource resource;
> +	unsigned int    irq;
> +	unsigned int    slotno;
> +
> +	const char      *name;
> +	struct gio_device_id id;
> +	unsigned        id32:1;
> +	unsigned        gio64:1;
> +};
> +#define to_gio_device(d) container_of(d, struct gio_device, dev)
> +
> +struct gio_driver {
> +	const char    *name;
> +	struct module *owner;
> +	const struct gio_device_id *id_table;
> +
> +	int  (*probe)(struct gio_device *, const struct gio_device_id *);
> +	void (*remove)(struct gio_device *);
> +	int  (*suspend)(struct gio_device *, pm_message_t);
> +	int  (*resume)(struct gio_device *);
> +	void (*shutdown)(struct gio_device *);
> +
> +	struct device_driver driver;
> +};
> +#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
> +
> +extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
> +						    const struct gio_device *);
> +extern struct gio_device *gio_dev_get(struct gio_device *);
> +extern void gio_dev_put(struct gio_device *);
> +
> +extern int gio_device_register(struct gio_device *);
> +extern void gio_device_unregister(struct gio_device *);
> +extern void gio_release_dev(struct device *);
> +
> +static inline void gio_device_free(struct gio_device *dev)
> +{
> +	gio_release_dev(&dev->dev);
> +}
> +
> +extern int gio_register_driver(struct gio_driver *);
> +extern void gio_unregister_driver(struct gio_driver *);
> +
> +#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
> +#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
> +
> +extern void gio_set_master(struct gio_device *);
> diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
> index cc53849..411cda9 100644
> --- a/arch/mips/sgi-ip22/Makefile
> +++ b/arch/mips/sgi-ip22/Makefile
> @@ -4,7 +4,7 @@
>  #
>  
>  obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
> -	   ip22-platform.o ip22-reset.o ip22-setup.o
> +	   ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
>  
>  obj-$(CONFIG_SGI_IP22) += ip22-berr.o
>  obj-$(CONFIG_SGI_IP28) += ip28-berr.o
> diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
> new file mode 100644
> index 0000000..d841529
> --- /dev/null
> +++ b/arch/mips/sgi-ip22/ip22-gio.c
> @@ -0,0 +1,414 @@
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +
> +#include <asm/addrspace.h>
> +#include <asm/paccess.h>
> +#include <asm/gio_device.h>
> +#include <asm/sgi/gio.h>
> +#include <asm/sgi/hpc3.h>
> +#include <asm/sgi/mc.h>
> +#include <asm/sgi/ip22.h>
> +
> +static struct bus_type gio_bus;
> +
> +static struct {
> +	const char *name;
> +	__u8       id;
> +} gio_name_table[] = {
> +	{ .name = "SGI Impact", .id = 0x10 },
> +	{ .name = "Phobos G160", .id = 0x35 },
> +	/* fake IDs */
> +	{ .name = "SGI Newport", .id = 0x7e },
> +	{ .name = "SGI GR2/GR3", .id = 0x7f },
> +};
> +
> +/**
> + * gio_match_device - Tell if an of_device structure has a matching
> + * gio_match structure
> + * @ids: array of of device match structures to search in
> + * @dev: the of device structure to match against
> + *
> + * Used by a driver to check whether an of_device present in the
> + * system is in its list of supported devices.
> + */
> +const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
> +		     const struct gio_device *dev)
> +{
> +	const struct gio_device_id *ids;
> +
> +	for (ids = match; ids->id != 0xff; ids++)
> +		if (ids->id = dev->id.id)
> +			return ids;
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_match_device);
> +
> +struct gio_device *gio_dev_get(struct gio_device *dev)
> +{
> +	struct device *tmp;
> +
> +	if (!dev)
> +		return NULL;
> +	tmp = get_device(&dev->dev);
> +	if (tmp)
> +		return to_gio_device(tmp);
> +	else
> +		return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_get);
> +
> +void gio_dev_put(struct gio_device *dev)
> +{
> +	if (dev)
> +		put_device(&dev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_put);
> +
> +static ssize_t dev_show_name(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	return sprintf(buf, "%s", giodev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, dev_show_name, NULL);
> +
> +static ssize_t dev_show_id(struct device *dev,
> +			   struct device_attribute *attr, char *buf)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	return sprintf(buf, "%x", giodev->id.id);
> +}
> +
> +static DEVICE_ATTR(id, S_IRUGO, dev_show_id, NULL);
> +
> +/**
> + * gio_release_dev - free an gio device structure when all users of it are finished.
> + * @dev: device that's been disconnected
> + *
> + * Will be called only by the device core when all users of this gio device are
> + * done.
> + */
> +void gio_release_dev(struct device *dev)
> +{
> +	struct gio_device *giodev;
> +
> +	giodev = to_gio_device(dev);
> +	kfree(giodev);
> +}
> +EXPORT_SYMBOL_GPL(gio_release_dev);
> +
> +int gio_device_register(struct gio_device *giodev)
> +{
> +	int rc;
> +
> +	giodev->dev.bus = &gio_bus;
> +	rc = device_register(&giodev->dev);
> +	if (rc)
> +		return rc;
> +
> +	rc = device_create_file(&giodev->dev, &dev_attr_name);
> +	if (rc)
> +		goto err;
> +	rc = device_create_file(&giodev->dev, &dev_attr_id);
> +	if (rc)
> +		goto err;
> +
> +	return 0;
> +
> +err:
> +	device_unregister(&giodev->dev);
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(gio_device_register);
> +
> +void gio_device_unregister(struct gio_device *giodev)
> +{
> +	device_remove_file(&giodev->dev, &dev_attr_id);
> +	device_remove_file(&giodev->dev, &dev_attr_name);
> +	device_unregister(&giodev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_device_unregister);
> +
> +static int gio_bus_match(struct device *dev, struct device_driver *drv)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *gio_drv = to_gio_driver(drv);
> +
> +	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
> +}
> +
> +static int gio_device_probe(struct device *dev)
> +{
> +	int error = -ENODEV;
> +	struct gio_driver *drv;
> +	struct gio_device *gio_dev;
> +	const struct gio_device_id *match;
> +
> +	drv = to_gio_driver(dev->driver);
> +	gio_dev = to_gio_device(dev);
> +
> +	if (!drv->probe)
> +		return error;
> +
> +	gio_dev_get(gio_dev);
> +
> +	match = gio_match_device(drv->id_table, gio_dev);
> +	if (match)
> +		error = drv->probe(gio_dev, match);
> +	if (error)
> +		gio_dev_put(gio_dev);
> +
> +	return error;
> +}
> +
> +static int gio_device_remove(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> +	if (dev->driver && drv->remove)
> +		drv->remove(gio_dev);
> +	return 0;
> +}
> +
> +static int gio_device_suspend(struct device *dev, pm_message_t state)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +	int error = 0;
> +
> +	if (dev->driver && drv->suspend)
> +		error = drv->suspend(gio_dev, state);
> +	return error;
> +}
> +
> +static int gio_device_resume(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +	int error = 0;
> +
> +	if (dev->driver && drv->resume)
> +		error = drv->resume(gio_dev);
> +	return error;
> +}
> +
> +static void gio_device_shutdown(struct device *dev)
> +{
> +	struct gio_device *gio_dev = to_gio_device(dev);
> +	struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> +	if (dev->driver && drv->shutdown)
> +		drv->shutdown(gio_dev);
> +}
> +
> +int gio_register_driver(struct gio_driver *drv)
> +{
> +	/* initialize common driver fields */
> +	if (!drv->driver.name)
> +		drv->driver.name = drv->name;
> +	if (!drv->driver.owner)
> +		drv->driver.owner = drv->owner;
> +	drv->driver.bus = &gio_bus;
> +
> +	/* register with core */
> +	return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_register_driver);
> +
> +void gio_unregister_driver(struct gio_driver *drv)
> +{
> +	driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_unregister_driver);
> +
> +void gio_set_master(struct gio_device *dev)
> +{
> +	u32 tmp = sgimc->giopar;
> +
> +	switch (dev->slotno) {
> +	case 0:
> +		tmp |= SGIMC_GIOPAR_MASTERGFX;
> +		break;
> +	case 1:
> +		tmp |= SGIMC_GIOPAR_MASTEREXP0;
> +		break;
> +	case 2:
> +		tmp |= SGIMC_GIOPAR_MASTEREXP1;
> +		break;
> +	}
> +	sgimc->giopar = tmp;
> +}
> +EXPORT_SYMBOL_GPL(gio_set_master);
> +
> +void ip22_gio_set_64bit(int slotno)
> +{
> +	u32 tmp = sgimc->giopar;
> +
> +	switch (slotno) {
> +	case 0:
> +		tmp |= SGIMC_GIOPAR_GFX64;
> +		break;
> +	case 1:
> +		tmp |= SGIMC_GIOPAR_EXP064;
> +		break;
> +	case 2:
> +		tmp |= SGIMC_GIOPAR_EXP164;
> +		break;
> +	}
> +	sgimc->giopar = tmp;
> +}
> +
> +static int ip22_gio_id(unsigned long addr, u32 *res)
> +{
> +	u8 tmp8;
> +	u8 tmp16;
> +	u32 tmp32;
> +	u8 *ptr8;
> +	u16 *ptr16;
> +	u32 *ptr32;
> +
> +	ptr32 = (void *)CKSEG1ADDR(addr);
> +	if (!get_dbe(tmp32, ptr32)) {
> +		/*
> +		 * We got no DBE, but this doesn't mean anything.
> +		 * If GIO is pipelined (which can't be disabled
> +		 * for GFX slot) we don't get a DBE, but we see
> +		 * the transfer size as data. So we do an 8bit
> +		 * and a 16bit access and check whether the common
> +		 * data matches
> +		 */
> +		ptr8 = (void *)CKSEG1ADDR(addr + 3);
> +		get_dbe(tmp8, ptr8);
> +		ptr16 = (void *)CKSEG1ADDR(addr + 2);
> +		get_dbe(tmp16, ptr16);
> +		if (tmp8 = (tmp16 & 0xff) &&
> +		    tmp8 = (tmp32 & 0xff) &&
> +		    tmp16 = (tmp32 & 0xffff)) {
> +			*res = tmp32;
> +			return 1;
> +		}
> +	}
> +	return 0; /* nothing here */
> +}
> +
> +#define HQ2_MYSTERY_OFFS       0x6A07C
> +#define NEWPORT_USTATUS_OFFS   0xF133C
> +
> +static int ip22_is_gr2(unsigned long addr)
> +{
> +	u32 tmp;
> +	u32 *ptr;
> +
> +	/* HQ2 only allows 32bit accesses */
> +	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
> +	if (!get_dbe(tmp, ptr)) {
> +		if (tmp = 0xdeadbeef)
> +			return 1;
> +	}
> +	return 0;
> +}
> +
> +
> +static void ip22_check_gio(int slotno, unsigned long addr)
> +{
> +	const char *name = "Unknown";
> +	struct gio_device *gio_dev;
> +	u32 tmp;
> +	__u8 id;
> +	int i;
> +
> +	/* first look for GR2/GR3 by checking mystery register */
> +	if (ip22_is_gr2(addr))
> +		tmp = 0x7f;
> +	else {
> +		if (!ip22_gio_id(addr, &tmp)) {
> +			/*
> +			 * no GIO signature at start address of slot, but
> +			 * Newport doesn't have one, so let's check usea
> +			 * status register
> +			 */
> +			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
> +				tmp = 0x7e;
> +			else
> +				tmp = 0;
> +		}
> +	}
> +	if (tmp) {
> +		id = GIO_ID(tmp);
> +		if (tmp & GIO_32BIT_ID) {
> +			if (tmp & GIO_64BIT_IFACE)
> +				ip22_gio_set_64bit(slotno);
> +		}
> +		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
> +			if (id = gio_name_table[i].id) {
> +				name = gio_name_table[i].name;
> +				break;
> +			}
> +		}
> +		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
> +		       slotno, name, id);
> +		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
> +		gio_dev->name = name;
> +		gio_dev->slotno = slotno;
> +		gio_dev->id.id = id;
> +		gio_dev->resource.start = addr;
> +		gio_dev->resource.end = addr + 0x3fffff;
> +		gio_dev->resource.flags = IORESOURCE_MEM;
> +		dev_set_name(&gio_dev->dev, "gio%d", slotno);
> +		gio_device_register(gio_dev);
> +	} else
> +		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
> +}
> +
> +static struct bus_type gio_bus = {
> +	.name     = "gio",
> +	.match    = gio_bus_match,
> +	.probe    = gio_device_probe,
> +	.remove   = gio_device_remove,
> +	.suspend  = gio_device_suspend,
> +	.resume   = gio_device_resume,
> +	.shutdown = gio_device_shutdown,
> +};
> +
> +static struct resource gio_bus_resource = {
> +	.start = GIO_SLOT_GFX_BASE,
> +	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
> +	.name  = "GIO Bus",
> +	.flags = IORESOURCE_MEM,
> +};
> +
> +int __init ip22_gio_init(void)
> +{
> +	unsigned int pbdma __maybe_unused;
> +	int ret;
> +
> +	ret = bus_register(&gio_bus);
> +	if (!ret) {
> +		request_resource(&iomem_resource, &gio_bus_resource);
> +		printk(KERN_INFO "GIO: Probing bus...\n");
> +
> +		if (ip22_is_fullhouse() ||
> +		    !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
> +			/* Indigo2 and ChallengeS */
> +			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> +			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> +		} else {
> +			/* Indy */
> +			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> +			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> +			ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
> +		}
> +	}
> +	return ret;
> +}
> +
> +subsys_initcall(ip22_gio_init);
> +
> diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
> index d22262e..75ada8a 100644
> --- a/arch/mips/sgi-ip22/ip22-mc.c
> +++ b/arch/mips/sgi-ip22/ip22-mc.c
> @@ -139,11 +139,11 @@ void __init sgimc_init(void)
>  	 *         zero.
>  	 */
>  	/* don't touch parity settings for IP28 */
> -#ifndef CONFIG_SGI_IP28
>  	tmp = sgimc->cpuctrl0;
> -	tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
> -		SGIMC_CCTRL0_R4KNOCHKPARR);
> +#ifndef CONFIG_SGI_IP28
> +	tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
>  #endif
> +	tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
>  	sgimc->cpuctrl0 = tmp;
>  
>  	/* Step 3: Setup the MC write buffer depth, this is controlled
> @@ -178,7 +178,8 @@ void __init sgimc_init(void)
>  	 */
>  
>  	/* First the basic invariants across all GIO64 implementations. */
> -	tmp = SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
> +	tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
> +	tmp |= SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
>  	tmp |= SGIMC_GIOPAR_ONEBUS;	/* Only one physical GIO bus exists */
>  
>  	if (ip22_is_fullhouse()) {
> @@ -193,7 +194,6 @@ void __init sgimc_init(void)
>  			tmp |= SGIMC_GIOPAR_PLINEEXP0;	/* exp[01] pipelined */
>  			tmp |= SGIMC_GIOPAR_PLINEEXP1;
>  			tmp |= SGIMC_GIOPAR_MASTEREISA;	/* EISA masters */
> -			tmp |= SGIMC_GIOPAR_GFX64;	/* GFX at 64 bits */
>  		}
>  	} else {
>  		/* Guiness specific settings. */
> diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
> index 5e66213..c7bdfe4 100644
> --- a/arch/mips/sgi-ip22/ip22-setup.c
> +++ b/arch/mips/sgi-ip22/ip22-setup.c
> @@ -26,9 +26,6 @@
>  #include <asm/sgi/hpc3.h>
>  #include <asm/sgi/ip22.h>
>  
> -unsigned long sgi_gfxaddr;
> -EXPORT_SYMBOL_GPL(sgi_gfxaddr);
> -
>  extern void ip22_be_init(void) __init;
>  
>  void __init plat_mem_setup(void)
> @@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
>  		prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
>  		add_preferred_console("arc", 0, NULL);
>  	}
> -
> -#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
> -	{
> -		ULONG *gfxinfo;
> -		ULONG * (*__vec)(void) = (void *) (long)
> -			*((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
> -
> -		gfxinfo = __vec();
> -		sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
> -			       && gfxinfo[1] <= 0xc0000000)
> -			       ? gfxinfo[1] - 0xa0000000 : 0);
> -
> -		/* newport addresses? */
> -		if (sgi_gfxaddr = 0x1f0f0000 || sgi_gfxaddr = 0x1f4f0000) {
> -			conswitchp = &newport_con;
> -		}
> -	}
> -#endif
>  }
> diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
> index 93317b5..628b7ec 100644
> --- a/drivers/video/console/newport_con.c
> +++ b/drivers/video/console/newport_con.c
> @@ -25,14 +25,13 @@
>  #include <asm/system.h>
>  #include <asm/page.h>
>  #include <asm/pgtable.h>
> +#include <asm/gio_device.h>
> +
>  #include <video/newport.h>
>  
>  #include <linux/linux_logo.h>
>  #include <linux/font.h>
>  
> -
> -extern unsigned long sgi_gfxaddr;
> -
>  #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
>  
>  /* borrowed from fbcon.c */
> @@ -304,12 +303,6 @@ static const char *newport_startup(void)
>  {
>  	int i;
>  
> -	if (!sgi_gfxaddr)
> -		return NULL;
> -
> -	if (!npregs)
> -		npregs = (struct newport_regs *)/* ioremap cannot fail */
> -			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
>  	npregs->cset.config = NPORT_CFG_GD0;
>  
>  	if (newport_wait(npregs))
> @@ -743,26 +736,56 @@ const struct consw newport_con = {
>  	.con_save_screen  = DUMMY
>  };
>  
> -#ifdef MODULE
> -static int __init newport_console_init(void)
> +static int newport_probe(struct gio_device *dev,
> +			 const struct gio_device_id *id)
>  {
> -	if (!sgi_gfxaddr)
> -		return 0;
> +	unsigned long newport_addr;
>  
> -	if (!npregs)
> -		npregs = (struct newport_regs *)/* ioremap cannot fail */
> -			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> +	if (!dev->resource.start)
> +		return -EINVAL;
> +
> +	if (npregs)
> +		return -EBUSY; /* we only support one Newport as console */
> +
> +	newport_addr = dev->resource.start + 0xF0000;
> +	if (!request_mem_region(newport_addr, 0x10000, "Newport"))
> +		return -ENODEV;
> +
> +	npregs = (struct newport_regs *)/* ioremap cannot fail */
> +		ioremap(newport_addr, sizeof(struct newport_regs));
>  
>  	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
>  }
> -module_init(newport_console_init);
>  
> -static void __exit newport_console_exit(void)
> +static void newport_remove(struct gio_device *dev)
>  {
>  	give_up_console(&newport_con);
>  	iounmap((void *)npregs);
>  }
> +
> +static struct gio_device_id newport_ids[] = {
> +	{ .id = 0x7e },
> +	{ .id = 0xff }
> +};
> +
> +static struct gio_driver newport_driver = {
> +	.name = "newport",
> +	.id_table = newport_ids,
> +	.probe = newport_probe,
> +	.remove = newport_remove,
> +};
> +
> +int __init newport_console_init(void)
> +{
> +	return gio_register_driver(&newport_driver);
> +}
> +
> +void __exit newport_console_exit(void)
> +{
> +	gio_unregister_driver(&newport_driver);
> +}
> +
> +module_init(newport_console_init);
>  module_exit(newport_console_exit);
> -#endif
>  
>  MODULE_LICENSE("GPL");
> 


^ permalink raw reply

* Re: [PATCH v2] GIO bus support for SGI IP22/28
From: Joshua Kinard @ 2011-10-30 20:43 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat
In-Reply-To: <20111020221928.0C2191DA27@solo.franken.de>

On 10/20/2011 18:19, Thomas Bogendoerfer wrote:

> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>


Does this handle any glue logic for add-on NIC cards found for Indy and I2?
 I have a G130 Phobus and a rare ThunderLAN card in my Indy.  The Phobus has
an Altera GIO/PCI glue chip.  Not sure about the ThunderLAN.  Both have
normal driver support in the kernel (Phobus is just a Tulip chip).

-- 
Joshua Kinard
Gentoo/MIPS
kumba@gentoo.org
4096R/D25D95E3 2011-03-28

"The past tempts us, the present confuses us, the future frightens us.  And
our lives slip away, moment by moment, lost in that vast, terrible in-between."

--Emperor Turhan, Centauri Republic

^ permalink raw reply

* Re: [PATCH v2] GIO bus support for SGI IP22/28
From: Thomas Bogendoerfer @ 2011-10-30 22:34 UTC (permalink / raw)
  To: Joshua Kinard; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat
In-Reply-To: <4EADB701.9040506@gentoo.org>

On Sun, Oct 30, 2011 at 04:43:45PM -0400, Joshua Kinard wrote:
> Does this handle any glue logic for add-on NIC cards found for Indy and I2?

no, but it will make live a lot easier, because address and interrupts don't
need to be probed by the driver. Right now interrupts are on my todo, since
there is some weirdness between guiness and fullhouse boxes...

>  I have a G130 Phobus and a rare ThunderLAN card in my Indy.  The Phobus has
> an Altera GIO/PCI glue chip.  Not sure about the ThunderLAN.  Both have
> normal driver support in the kernel (Phobus is just a Tulip chip).

it still needs something to setup the PCI bus on the card and issue
the probing. The problem with the Tulip Phobos cards is, that they
messed up the endianess, so that none of the Linux Tulip drivers will
work out of the box...

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* Re: [PATCH v2] GIO bus support for SGI IP22/28
From: Joshua Kinard @ 2011-10-31  8:04 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat
In-Reply-To: <20111030223418.GA16346@alpha.franken.de>

On 10/30/2011 18:34, Thomas Bogendoerfer wrote:

> 
> no, but it will make live a lot easier, because address and interrupts don't
> need to be probed by the driver. Right now interrupts are on my todo, since
> there is some weirdness between guiness and fullhouse boxes...


It wouldn't be an SGI machine if it didn't implement something weird or just
plain backwards...


> it still needs something to setup the PCI bus on the card and issue
> the probing. The problem with the Tulip Phobos cards is, that they
> messed up the endianess, so that none of the Linux Tulip drivers will
> work out of the box...


A.k.a., Tulip (and possibly ThunderLAN) assume little-endian, when we're
talking big-endian archs here.  Interesting.  Simple fix, as in defining a
few driver structures with little- and big-endian versions (if they're doing
something like packing bits or using bitfields)?  Or is it more complex than
that?

-- 
Joshua Kinard
Gentoo/MIPS
kumba@gentoo.org
4096R/D25D95E3 2011-03-28

"The past tempts us, the present confuses us, the future frightens us.  And
our lives slip away, moment by moment, lost in that vast, terrible in-between."

--Emperor Turhan, Centauri Republic

^ permalink raw reply

* Re: Proposal for a low-level Linux display framework
From: Jesse Barnes @ 2011-10-31 20:24 UTC (permalink / raw)
  To: Alan Cox
  Cc: Dave Airlie, linux-fbdev, linaro-dev, Florian Tobias Schandinat,
	linux-kernel, dri-devel, Archit Taneja, Rob Clark
In-Reply-To: <20110917212529.6b452bf2@lxorguk.ukuu.org.uk>

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

On Sat, 17 Sep 2011 21:25:29 +0100
Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > Just tell the X driver to not use acceleration, and it you won't get
> > any acceleration used, then you get complete stability. If a driver
> > writer wants to turn off all accel in the kernel driver, it can, its
> 
> In fact one thing we actually need really is a "dumb" KMS X server to
> replace the fbdev X server that unaccel stuff depends upon and which
> can't do proper mode handling, multi-head or resizing as a result. A dumb
> fb generic request for a back to front copy might also be useful for
> shadowfb, or at least indicators so you know what the cache behaviour is
> so the X server can pick the right policy.
> 
> > We've fixed this in KMS, we don't pass direct mappings to userspace
> > that we can't tear down and refault. We only provide objects via
> > handles. The only place its a problem is where we expose fbdev legacy
> > emulation, since we have to fix the pages.
> 
> Which is doable. Horrible but doable. The usb framebuffer code has to
> play games like this with the virtual framebuffer in order to track
> changes by faulting.
> 
> There are still some architectural screwups however. DRM continues the
> fbdev worldview that outputs, memory and accelerators are tied together
> in lumps we call video cards. That isn't really true for all cases and
> with capture/overlay it gets even less true.

Sorry for re-opening this ancient thread; I'm catching up from the past
2 months of travel & misc.

I definitely agree about the PC card centric architecture of DRM KMS
(and before it, X).  But we have a path out of it now, and lots of
interest from vendors and developers, so I don't think it's an
insurmountable problem by any means.

I definitely understand Florian's worries about DRM vs fb.  If nothing
else, there's certainly a perception that fb is simpler and easier to
get right.  But really, as others have pointed out, it's solving a
different set of problems than the DRM layer.  The latter is actually
trying to expose the features of contemporary hardware in a way that's
as portable as possible.  That portability comes at a cost though: the
APIs we add need to get lots of review, and there's no doubt we'll need
to add more as newer, weirder hardware comes along.

Really, I see no reason why fb and DRM can't continue to live side by
side.  If a vendor really only needs the features provided by the fb
layer, they're free to stick with a simple fb driver.  However, I
expect most vendors making phones, tablets, notebooks, etc will need
and want an architecture that looks a lot like the DRM layer, with
authentication for rendering clients, an command submission ioctl for
acceleration, and memory management, so I expect most of the driver
growth to be in DRM in the near future.

And I totally agree with Dave about having a kmscon.  I really wish
someone would implement it so I could have my VTs spinning on a cube.

-- 
Jesse Barnes, Intel Open Source Technology Center

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2] GIO bus support for SGI IP22/28
From: Thomas Bogendoerfer @ 2011-11-01 10:00 UTC (permalink / raw)
  To: Joshua Kinard; +Cc: linux-mips, linux-fbdev, ralf, FlorianSchandinat
In-Reply-To: <4EAE5681.2090103@gentoo.org>

On Mon, Oct 31, 2011 at 04:04:17AM -0400, Joshua Kinard wrote:
> A.k.a., Tulip (and possibly ThunderLAN) assume little-endian, when we're
> talking big-endian archs here.  Interesting.  Simple fix, as in defining a
> few driver structures with little- and big-endian versions (if they're doing
> something like packing bits or using bitfields)?  Or is it more complex than
> that?

iirc, the PCI bridge on the cards do 32bit swaps (address invariant) so
tulip chips need to run in big endian mode, which in turn makes descriptors
also big endian. But none of the tulip driver supports big endian descriptors.
That's fixable of course.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* [PATCH 09/18] MIPS: Alchemy: move au1200fb global functions to platform data
From: Manuel Lauss @ 2011-11-01 19:03 UTC (permalink / raw)
  To: Linux-MIPS, Ralf Baechle; +Cc: Manuel Lauss, linux-fbdev
In-Reply-To: <1320174224-27305-1-git-send-email-manuel.lauss@googlemail.com>

au1200fb calls 3 functions which have to be defined in board code.
Fix this ugliness with the introduction of platform_data.

Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
---
I'd like this to go in via the MIPS tree since patches depend on it.

 arch/mips/alchemy/devboards/db1200.c         |   51 +++---
 arch/mips/alchemy/devboards/db1300.c         |   52 +++---
 arch/mips/alchemy/devboards/pb1200.c         |   55 ++++---
 arch/mips/include/asm/mach-au1x00/au1200fb.h |   14 ++
 drivers/video/au1200fb.c                     |  241 ++++++++++++--------------
 5 files changed, 213 insertions(+), 200 deletions(-)
 create mode 100644 arch/mips/include/asm/mach-au1x00/au1200fb.h

diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index 43f5f1b..e2cc5f9 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -37,6 +37,7 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1200fb.h>
 #include <asm/mach-au1x00/au1550_spi.h>
 #include <asm/mach-db1x00/bcsr.h>
 #include <asm/mach-db1x00/db1200.h>
@@ -422,6 +423,33 @@ static struct platform_device db1200_mmc0_dev = {
 
 /**********************************************************************/
 
+static int db1200fb_panel_index(void)
+{
+	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
+}
+
+static int db1200fb_panel_init(void)
+{
+	/* Apply power */
+	bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+				BCSR_BOARD_LCDBL);
+	return 0;
+}
+
+static int db1200fb_panel_shutdown(void)
+{
+	/* Remove power */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+			     BCSR_BOARD_LCDBL, 0);
+	return 0;
+}
+
+static struct au1200fb_platdata db1200fb_pd = {
+	.panel_index	= db1200fb_panel_index,
+	.panel_init	= db1200fb_panel_init,
+	.panel_shutdown	= db1200fb_panel_shutdown,
+};
+
 static struct resource au1200_lcd_res[] = {
 	[0] = {
 		.start	= AU1200_LCD_PHYS_ADDR,
@@ -443,6 +471,7 @@ static struct platform_device au1200_lcd_dev = {
 	.dev = {
 		.dma_mask		= &au1200_lcd_dmamask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &db1200fb_pd,
 	},
 	.num_resources	= ARRAY_SIZE(au1200_lcd_res),
 	.resource	= au1200_lcd_res,
@@ -681,25 +710,3 @@ static int __init db1200_dev_init(void)
 	return platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs));
 }
 device_initcall(db1200_dev_init);
-
-/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */
-int board_au1200fb_panel(void)
-{
-	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
-}
-
-int board_au1200fb_panel_init(void)
-{
-	/* Apply power */
-	bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-				BCSR_BOARD_LCDBL);
-	return 0;
-}
-
-int board_au1200fb_panel_shutdown(void)
-{
-	/* Remove power */
-	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-			     BCSR_BOARD_LCDBL, 0);
-	return 0;
-}
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index bf0d1c4..d1a7344 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -22,6 +22,7 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1200fb.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 #include <asm/mach-db1x00/db1300.h>
@@ -635,6 +636,33 @@ static struct platform_device db1300_sndi2s_dev = {
 
 /**********************************************************************/
 
+static int db1300fb_panel_index(void)
+{
+	return 9;	/* DB1300_800x480 */
+}
+
+static int db1300fb_panel_init(void)
+{
+	/* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
+			     BCSR_BOARD_LCDBL);
+	return 0;
+}
+
+static int db1300fb_panel_shutdown(void)
+{
+	/* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
+			     BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
+	return 0;
+}
+
+static struct au1200fb_platdata db1300fb_pd = {
+	.panel_index	= db1300fb_panel_index,
+	.panel_init	= db1300fb_panel_init,
+	.panel_shutdown	= db1300fb_panel_shutdown,
+};
+
 static struct resource au1300_lcd_res[] = {
 	[0] = {
 		.start	= AU1200_LCD_PHYS_ADDR,
@@ -656,6 +684,7 @@ static struct platform_device db1300_lcd_dev = {
 	.dev = {
 		.dma_mask		= &au1300_lcd_dmamask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &db1300fb_pd,
 	},
 	.num_resources	= ARRAY_SIZE(au1300_lcd_res),
 	.resource	= au1300_lcd_res,
@@ -761,26 +790,3 @@ void __init board_setup(void)
 	alchemy_uart_enable(AU1300_UART1_PHYS_ADDR);
 	alchemy_uart_enable(AU1300_UART3_PHYS_ADDR);
 }
-
-
-/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */
-int board_au1200fb_panel(void)
-{
-	return 9;	/* DB1300_800x480 */
-}
-
-int board_au1200fb_panel_init(void)
-{
-	/* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
-	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
-			     BCSR_BOARD_LCDBL);
-	return 0;
-}
-
-int board_au1200fb_panel_shutdown(void)
-{
-	/* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
-	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
-			     BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
-	return 0;
-}
diff --git a/arch/mips/alchemy/devboards/pb1200.c b/arch/mips/alchemy/devboards/pb1200.c
index a1b6497..a2676c9 100644
--- a/arch/mips/alchemy/devboards/pb1200.c
+++ b/arch/mips/alchemy/devboards/pb1200.c
@@ -26,6 +26,7 @@
 #include <linux/smc91x.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1200fb.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-db1x00/bcsr.h>
 #include <asm/mach-pb1x00/pb1200.h>
@@ -351,6 +352,33 @@ static struct platform_device pb1200_i2c_dev = {
 	.resource	= au1200_psc0_res,
 };
 
+static int pb1200fb_panel_index(void)
+{
+	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
+}
+
+static int pb1200fb_panel_init(void)
+{
+	/* Apply power */
+	bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+				BCSR_BOARD_LCDBL);
+	return 0;
+}
+
+static int pb1200fb_panel_shutdown(void)
+{
+	/* Remove power */
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+			     BCSR_BOARD_LCDBL, 0);
+	return 0;
+}
+
+static struct au1200fb_platdata pb1200fb_pd = {
+	.panel_index	= pb1200fb_panel_index,
+	.panel_init	= pb1200fb_panel_init,
+	.panel_shutdown	= pb1200fb_panel_shutdown,
+};
+
 static struct resource au1200_lcd_res[] = {
 	[0] = {
 		.start	= AU1200_LCD_PHYS_ADDR,
@@ -366,12 +394,13 @@ static struct resource au1200_lcd_res[] = {
 
 static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32);
 
-static struct platform_device au1200_lcd_dev = {
+static struct platform_device pb1200_lcd_dev = {
 	.name		= "au1200-lcd",
 	.id		= 0,
 	.dev = {
 		.dma_mask		= &au1200_lcd_dmamask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &pb1200fb_pd,
 	},
 	.num_resources	= ARRAY_SIZE(au1200_lcd_res),
 	.resource	= au1200_lcd_res,
@@ -383,7 +412,7 @@ static struct platform_device *board_platform_devices[] __initdata = {
 	&pb1200_i2c_dev,
 	&pb1200_mmc0_dev,
 	&pb1200_mmc1_dev,
-	&au1200_lcd_dev,
+	&pb1200_lcd_dev,
 };
 
 static int __init board_register_devices(void)
@@ -440,25 +469,3 @@ static int __init board_register_devices(void)
 				    ARRAY_SIZE(board_platform_devices));
 }
 device_initcall(board_register_devices);
-
-
-int board_au1200fb_panel(void)
-{
-	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
-}
-
-int board_au1200fb_panel_init(void)
-{
-	/* Apply power */
-	bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-				BCSR_BOARD_LCDBL);
-	return 0;
-}
-
-int board_au1200fb_panel_shutdown(void)
-{
-	/* Remove power */
-	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-			     BCSR_BOARD_LCDBL, 0);
-	return 0;
-}
diff --git a/arch/mips/include/asm/mach-au1x00/au1200fb.h b/arch/mips/include/asm/mach-au1x00/au1200fb.h
new file mode 100644
index 0000000..b3c87cc
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/au1200fb.h
@@ -0,0 +1,14 @@
+/*
+ * platform data for au1200fb driver.
+ */
+
+#ifndef _AU1200FB_PLAT_H_
+#define _AU1200FB_PLAT_H_
+
+struct au1200fb_platdata {
+	int (*panel_index)(void);
+	int (*panel_init)(void);
+	int (*panel_shutdown)(void);
+};
+
+#endif
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 6c4342f..04e4479 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 
 #include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1200fb.h>	/* platform_data */
 #include "au1200fb.h"
 
 #define DRIVER_NAME "au1200fb"
@@ -143,6 +144,7 @@ struct au1200_lcd_iodata_t {
 /* Private, per-framebuffer management information (independent of the panel itself) */
 struct au1200fb_device {
 	struct fb_info *fb_info;		/* FB driver info record */
+	struct au1200fb_platdata *pd;
 
 	int					plane;
 	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
@@ -201,9 +203,6 @@ struct window_settings {
 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
 #endif
 
-extern int board_au1200fb_panel_init (void);
-extern int board_au1200fb_panel_shutdown (void);
-
 /*
  * Default window configurations
  */
@@ -334,8 +333,6 @@ struct panel_settings
 	uint32 mode_toyclksrc;
 	uint32 mode_backlight;
 	uint32 mode_auxpll;
-	int (*device_init)(void);
-	int (*device_shutdown)(void);
 #define Xres min_xres
 #define Yres min_yres
 	u32	min_xres;		/* Minimum horizontal resolution */
@@ -385,8 +382,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= NULL,
-		.device_shutdown	= NULL,
 		320, 320,
 		240, 240,
 	},
@@ -415,8 +410,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= NULL,
-		.device_shutdown	= NULL,
 		640, 480,
 		640, 480,
 	},
@@ -445,8 +438,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= NULL,
-		.device_shutdown	= NULL,
 		800, 800,
 		600, 600,
 	},
@@ -475,8 +466,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 6, /* 72MHz AUXPLL */
-		.device_init		= NULL,
-		.device_shutdown	= NULL,
 		1024, 1024,
 		768, 768,
 	},
@@ -505,8 +494,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 10, /* 120MHz AUXPLL */
-		.device_init		= NULL,
-		.device_shutdown	= NULL,
 		1280, 1280,
 		1024, 1024,
 	},
@@ -535,8 +522,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= board_au1200fb_panel_init,
-		.device_shutdown	= board_au1200fb_panel_shutdown,
 		1024, 1024,
 		768, 768,
 	},
@@ -568,8 +553,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= board_au1200fb_panel_init,
-		.device_shutdown	= board_au1200fb_panel_shutdown,
 		640, 480,
 		640, 480,
 	},
@@ -601,8 +584,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= board_au1200fb_panel_init,
-		.device_shutdown	= board_au1200fb_panel_shutdown,
 		320, 320,
 		240, 240,
 	},
@@ -634,8 +615,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
 		.mode_auxpll		= 8, /* 96MHz AUXPLL */
-		.device_init		= board_au1200fb_panel_init,
-		.device_shutdown	= board_au1200fb_panel_shutdown,
 		856, 856,
 		480, 480,
 	},
@@ -670,8 +649,6 @@ static struct panel_settings known_lcd_panels[]  		.mode_toyclksrc		= 0x00000004, /* AUXPLL directly */
 		.mode_backlight		= 0x00000000,
 		.mode_auxpll		= (48/12) * 2,
-		.device_init		= board_au1200fb_panel_init,
-		.device_shutdown	= board_au1200fb_panel_shutdown,
 		800, 800,
 		480, 480,
 	},
@@ -800,7 +777,8 @@ static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
 	return 0;
 }
 
-static void au1200_setpanel (struct panel_settings *newpanel)
+static void au1200_setpanel(struct panel_settings *newpanel,
+			    struct au1200fb_platdata *pd)
 {
 	/*
 	 * Perform global setup/init of LCD controller
@@ -834,8 +812,8 @@ static void au1200_setpanel (struct panel_settings *newpanel)
 		    the controller, the clock cannot be turned off before first
 			shutting down the controller.
 		 */
-		if (panel->device_shutdown != NULL)
-			panel->device_shutdown();
+		if (pd->panel_shutdown)
+			pd->panel_shutdown();
 	}
 
 	/* Newpanel = NULL indicates a shutdown operation only */
@@ -888,7 +866,8 @@ static void au1200_setpanel (struct panel_settings *newpanel)
 	au_sync();
 
 	/* Call init of panel */
-	if (panel->device_init != NULL) panel->device_init();
+	if (pd->panel_init)
+		pd->panel_init();
 
 	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
 	lcd->intenable = 0;
@@ -1221,6 +1200,8 @@ static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  */
 static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
 {
+	struct au1200fb_device *fbdev = fbi->par;
+
 	/* Short-circuit screen blanking */
 	if (noblanking)
 		return 0;
@@ -1230,13 +1211,13 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
 	case FB_BLANK_UNBLANK:
 	case FB_BLANK_NORMAL:
 		/* printk("turn on panel\n"); */
-		au1200_setpanel(panel);
+		au1200_setpanel(panel, fbdev->pd);
 		break;
 	case FB_BLANK_VSYNC_SUSPEND:
 	case FB_BLANK_HSYNC_SUSPEND:
 	case FB_BLANK_POWERDOWN:
 		/* printk("turn off panel\n"); */
-		au1200_setpanel(NULL);
+		au1200_setpanel(NULL, fbdev->pd);
 		break;
 	default:
 		break;
@@ -1464,6 +1445,7 @@ static void get_window(unsigned int plane,
 static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
                           unsigned long arg)
 {
+	struct au1200fb_device *fbdev = info->par;
 	int plane;
 	int val;
 
@@ -1508,7 +1490,7 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
 				struct panel_settings *newpanel;
 				panel_index = iodata.global.panel_choice;
 				newpanel = &known_lcd_panels[panel_index];
-				au1200_setpanel(newpanel);
+				au1200_setpanel(newpanel, fbdev->pd);
 			}
 			break;
 
@@ -1624,22 +1606,102 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 
 /*-------------------------------------------------------------------------*/
 
-/* AU1200 LCD controller device driver */
 
+static int au1200fb_setup(struct au1200fb_platdata *pd)
+{
+	char *options = NULL;
+	char *this_opt, *endptr;
+	int num_panels = ARRAY_SIZE(known_lcd_panels);
+	int panel_idx = -1;
+
+	fb_get_options(DRIVER_NAME, &options);
+
+	if (!options)
+		goto out;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		/* Panel option - can be panel name,
+		 * "bs" for board-switch, or number/index */
+		if (!strncmp(this_opt, "panel:", 6)) {
+			int i;
+			long int li;
+			char *endptr;
+			this_opt += 6;
+			/* First check for index, which allows
+			 * to short circuit this mess */
+			li = simple_strtol(this_opt, &endptr, 0);
+			if (*endptr = '\0')
+				panel_idx = (int)li;
+			else if (strcmp(this_opt, "bs") = 0)
+				panel_idx = pd->panel_index();
+			else {
+				for (i = 0; i < num_panels; i++) {
+					if (!strcmp(this_opt,
+						    known_lcd_panels[i].name)) {
+						panel_idx = i;
+						break;
+					}
+				}
+			}
+			if ((panel_idx < 0) || (panel_idx >= num_panels))
+				print_warn("Panel %s not supported!", this_opt);
+			else
+				panel_index = panel_idx;
+
+		} else if (strncmp(this_opt, "nohwcursor", 10) = 0)
+			nohwcursor = 1;
+		else if (strncmp(this_opt, "devices:", 8) = 0) {
+			this_opt += 8;
+			device_count = simple_strtol(this_opt, &endptr, 0);
+			if ((device_count < 0) ||
+			    (device_count > MAX_DEVICE_COUNT))
+				device_count = MAX_DEVICE_COUNT;
+		} else if (strncmp(this_opt, "wincfg:", 7) = 0) {
+			this_opt += 7;
+			window_index = simple_strtol(this_opt, &endptr, 0);
+			if ((window_index < 0) ||
+			    (window_index >= ARRAY_SIZE(windows)))
+				window_index = DEFAULT_WINDOW_INDEX;
+		} else if (strncmp(this_opt, "off", 3) = 0)
+			return 1;
+		else
+			print_warn("Unsupported option \"%s\"", this_opt);
+	}
+
+out:
+	return 0;
+}
+
+/* AU1200 LCD controller device driver */
 static int __devinit au1200fb_drv_probe(struct platform_device *dev)
 {
 	struct au1200fb_device *fbdev;
+	struct au1200fb_platdata *pd;
 	struct fb_info *fbi = NULL;
 	unsigned long page;
 	int bpp, plane, ret, irq;
 
+	print_info("" DRIVER_DESC "");
+
+	pd = dev->dev.platform_data;
+	if (!pd)
+		return -ENODEV;
+
+	/* Setup driver with options */
+	if (au1200fb_setup(pd))
+		return -ENODEV;
+
+	/* Point to the panel selected */
+	panel = &known_lcd_panels[panel_index];
+	win = &windows[window_index];
+
+	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
 	/* shut gcc up */
 	ret = 0;
 	fbdev = NULL;
 
-	/* Kickstart the panel */
-	au1200_setpanel(panel);
-
 	for (plane = 0; plane < device_count; ++plane) {
 		bpp = winbpp(win->w[plane].mode_winctrl1);
 		if (win->w[plane].xres = 0)
@@ -1655,6 +1717,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev)
 		_au1200fb_infos[plane] = fbi;
 		fbdev = fbi->par;
 		fbdev->fb_info = fbi;
+		fbdev->pd = pd;
 
 		fbdev->plane = plane;
 
@@ -1716,6 +1779,11 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev)
 		goto failed;
 	}
 
+	platform_set_drvdata(dev, pd);
+
+	/* Kickstart the panel */
+	au1200_setpanel(panel, pd);
+
 	return 0;
 
 failed:
@@ -1735,12 +1803,13 @@ failed:
 
 static int __devexit au1200fb_drv_remove(struct platform_device *dev)
 {
+	struct au1200fb_platdata *pd = platform_get_drvdata(dev);
 	struct au1200fb_device *fbdev;
 	struct fb_info *fbi;
 	int plane;
 
 	/* Turn off the panel */
-	au1200_setpanel(NULL);
+	au1200_setpanel(NULL, pd);
 
 	for (plane = 0; plane < device_count; ++plane)	{
 		fbi = _au1200fb_infos[plane];
@@ -1768,7 +1837,8 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int au1200fb_drv_suspend(struct device *dev)
 {
-	au1200_setpanel(NULL);
+	struct au1200fb_platdata *pd = dev_get_drvdata(dev);
+	au1200_setpanel(NULL, pd);
 
 	lcd->outmask = 0;
 	au_sync();
@@ -1778,11 +1848,12 @@ static int au1200fb_drv_suspend(struct device *dev)
 
 static int au1200fb_drv_resume(struct device *dev)
 {
+	struct au1200fb_platdata *pd = dev_get_drvdata(dev);
 	struct fb_info *fbi;
 	int i;
 
 	/* Kickstart the panel */
-	au1200_setpanel(panel);
+	au1200_setpanel(panel, pd);
 
 	for (i = 0; i < device_count; i++) {
 		fbi = _au1200fb_infos[i];
@@ -1817,100 +1888,8 @@ static struct platform_driver au1200fb_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-/* Kernel driver */
-
-static int au1200fb_setup(void)
-{
-	char *options = NULL;
-	char *this_opt, *endptr;
-	int num_panels = ARRAY_SIZE(known_lcd_panels);
-	int panel_idx = -1;
-
-	fb_get_options(DRIVER_NAME, &options);
-
-	if (options) {
-		while ((this_opt = strsep(&options,",")) != NULL) {
-			/* Panel option - can be panel name,
-			 * "bs" for board-switch, or number/index */
-			if (!strncmp(this_opt, "panel:", 6)) {
-				int i;
-				long int li;
-				char *endptr;
-				this_opt += 6;
-				/* First check for index, which allows
-				 * to short circuit this mess */
-				li = simple_strtol(this_opt, &endptr, 0);
-				if (*endptr = '\0') {
-					panel_idx = (int)li;
-				}
-				else if (strcmp(this_opt, "bs") = 0) {
-					extern int board_au1200fb_panel(void);
-					panel_idx = board_au1200fb_panel();
-				}
-
-				else
-				for (i = 0; i < num_panels; i++) {
-					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
-						panel_idx = i;
-						break;
-					}
-				}
-
-				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
-						print_warn("Panel %s not supported!", this_opt);
-				}
-				else
-					panel_index = panel_idx;
-			}
-
-			else if (strncmp(this_opt, "nohwcursor", 10) = 0) {
-				nohwcursor = 1;
-			}
-
-			else if (strncmp(this_opt, "devices:", 8) = 0) {
-				this_opt += 8;
-				device_count = simple_strtol(this_opt,
-							     &endptr, 0);
-				if ((device_count < 0) ||
-				    (device_count > MAX_DEVICE_COUNT))
-					device_count = MAX_DEVICE_COUNT;
-			}
-
-			else if (strncmp(this_opt, "wincfg:", 7) = 0) {
-				this_opt += 7;
-				window_index = simple_strtol(this_opt,
-							     &endptr, 0);
-				if ((window_index < 0) ||
-				    (window_index >= ARRAY_SIZE(windows)))
-					window_index = DEFAULT_WINDOW_INDEX;
-			}
-
-			else if (strncmp(this_opt, "off", 3) = 0)
-				return 1;
-			/* Unsupported option */
-			else {
-				print_warn("Unsupported option \"%s\"", this_opt);
-			}
-		}
-	}
-	return 0;
-}
-
 static int __init au1200fb_init(void)
 {
-	print_info("" DRIVER_DESC "");
-
-	/* Setup driver with options */
-	if (au1200fb_setup())
-		return -ENODEV;
-
-	/* Point to the panel selected */
-	panel = &known_lcd_panels[panel_index];
-	win = &windows[window_index];
-
-	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
-	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
-
 	return platform_driver_register(&au1200fb_driver);
 }
 
-- 
1.7.7.1


^ permalink raw reply related

* [PATCH] FSL/DIU: add 1080P, 720P and 800x600 video modes
From: r66093 @ 2011-11-02  6:35 UTC (permalink / raw)
  To: linux-fbdev

From: Jerry Huang <Chang-Ming.Huang@freescale.com>

Add 1920x1080, 1280x720 and 800x600 resolution support.

Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
CC: Paul Mundt <lethal@linux-sh.org>
---
 drivers/video/fsl-diu-fb.c |   47 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 46 insertions(+), 1 deletions(-)

diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 0acc7d6..756975f 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008,2011 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  *  Freescale DIU Frame Buffer device driver
  *
@@ -60,6 +60,21 @@ static struct fb_videomode __devinitdata fsl_diu_default_mode = {
 
 static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
 	{
+		.name		= "800x600-60",
+		.refresh	= 60,
+		.xres		= 800,
+		.yres		= 600,
+		.pixclock	= 25000,
+		.left_margin	= 88,
+		.right_margin	= 40,
+		.upper_margin	= 23,
+		.lower_margin	= 1,
+		.hsync_len	= 128,
+		.vsync_len	= 4,
+		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED
+	},
+	{
 		.name		= "1024x768-60",
 		.refresh	= 60,
 		.xres		= 1024,
@@ -105,6 +120,21 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
 		.vmode		= FB_VMODE_NONINTERLACED
 	},
 	{
+		.name		= "1280x720-60",
+		.refresh	= 60,
+		.xres		= 1280,
+		.yres		= 720,
+		.pixclock	= 13426,
+		.left_margin	= 192,
+		.right_margin	= 64,
+		.upper_margin	= 22,
+		.lower_margin	= 1,
+		.hsync_len	= 136,
+		.vsync_len	= 3,
+		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED
+	},
+	{
 		.name		= "1280x1024-60",
 		.refresh	= 60,
 		.xres		= 1280,
@@ -150,6 +180,21 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
 		.vmode		= FB_VMODE_NONINTERLACED
 	},
 	{
+		.name		= "1920x1080-60",
+		.refresh	= 60,
+		.xres		= 1920,
+		.yres		= 1080,
+		.pixclock	= 5787,
+		.left_margin	= 328,
+		.right_margin	= 120,
+		.upper_margin	= 34,
+		.lower_margin	= 1,
+		.hsync_len	= 208,
+		.vsync_len	= 3,
+		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED
+	},
+	{
 		.name		= "320x240",		/* for AOI only */
 		.refresh	= 60,
 		.xres		= 320,
-- 
1.7.4.1



^ permalink raw reply related

* Re: [PATCH] FSL/DIU: add 1080P, 720P and 800x600 video modes
From: Tabi Timur-B04825 @ 2011-11-02 13:23 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1320215710-9128-1-git-send-email-r66093@freescale.com>

On Wed, Nov 2, 2011 at 1:35 AM,  <r66093@freescale.com> wrote:
> From: Jerry Huang <Chang-Ming.Huang@freescale.com>
>
> Add 1920x1080, 1280x720 and 800x600 resolution support.
>
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> CC: Paul Mundt <lethal@linux-sh.org>
> ---

These video modes are already in the driver.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* RE: [PATCH] FSL/DIU: add 1080P, 720P and 800x600 video modes
From: Huang Changming-R66093 @ 2011-11-03  2:32 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1320215710-9128-1-git-send-email-r66093@freescale.com>

Please ignore this patch.

Thanks and Best Regards
Jerry Huang


> -----Original Message-----
> From: Huang Changming-R66093
> Sent: Wednesday, November 02, 2011 2:35 PM
> To: linux-fbdev@vger.kernel.org
> Cc: Huang Changming-R66093; Paul Mundt
> Subject: [PATCH] FSL/DIU: add 1080P, 720P and 800x600 video modes
> 
> From: Jerry Huang <Chang-Ming.Huang@freescale.com>
> 
> Add 1920x1080, 1280x720 and 800x600 resolution support.
> 
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> CC: Paul Mundt <lethal@linux-sh.org>
> ---
>  drivers/video/fsl-diu-fb.c |   47
> +++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 46 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index 0acc7d6..756975f 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
> + * Copyright 2008,2011 Freescale Semiconductor, Inc. All Rights
> Reserved.
>   *
>   *  Freescale DIU Frame Buffer device driver
>   *
> @@ -60,6 +60,21 @@ static struct fb_videomode __devinitdata
> fsl_diu_default_mode = {
> 
>  static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
>  	{
> +		.name		= "800x600-60",
> +		.refresh	= 60,
> +		.xres		= 800,
> +		.yres		= 600,
> +		.pixclock	= 25000,
> +		.left_margin	= 88,
> +		.right_margin	= 40,
> +		.upper_margin	= 23,
> +		.lower_margin	= 1,
> +		.hsync_len	= 128,
> +		.vsync_len	= 4,
> +		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +		.vmode		= FB_VMODE_NONINTERLACED
> +	},
> +	{
>  		.name		= "1024x768-60",
>  		.refresh	= 60,
>  		.xres		= 1024,
> @@ -105,6 +120,21 @@ static struct fb_videomode __devinitdata
> fsl_diu_mode_db[] = {
>  		.vmode		= FB_VMODE_NONINTERLACED
>  	},
>  	{
> +		.name		= "1280x720-60",
> +		.refresh	= 60,
> +		.xres		= 1280,
> +		.yres		= 720,
> +		.pixclock	= 13426,
> +		.left_margin	= 192,
> +		.right_margin	= 64,
> +		.upper_margin	= 22,
> +		.lower_margin	= 1,
> +		.hsync_len	= 136,
> +		.vsync_len	= 3,
> +		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +		.vmode		= FB_VMODE_NONINTERLACED
> +	},
> +	{
>  		.name		= "1280x1024-60",
>  		.refresh	= 60,
>  		.xres		= 1280,
> @@ -150,6 +180,21 @@ static struct fb_videomode __devinitdata
> fsl_diu_mode_db[] = {
>  		.vmode		= FB_VMODE_NONINTERLACED
>  	},
>  	{
> +		.name		= "1920x1080-60",
> +		.refresh	= 60,
> +		.xres		= 1920,
> +		.yres		= 1080,
> +		.pixclock	= 5787,
> +		.left_margin	= 328,
> +		.right_margin	= 120,
> +		.upper_margin	= 34,
> +		.lower_margin	= 1,
> +		.hsync_len	= 208,
> +		.vsync_len	= 3,
> +		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +		.vmode		= FB_VMODE_NONINTERLACED
> +	},
> +	{
>  		.name		= "320x240",		/* for AOI only */
>  		.refresh	= 60,
>  		.xres		= 320,
> --
> 1.7.4.1



^ permalink raw reply

* [RFC] Virtual CRTCs (proposal + experimental code)
From: Ilija Hadzic @ 2011-11-03 15:59 UTC (permalink / raw)
  To: dri-devel, linux-fbdev

Hi everyone,

I would like to bring to the attention of dri-devel and linux-fbdev
community a set of hopefully useful and interesting patches that
I (and a few other colleagues) have been working on during the past
few months. Here, I will provide a short abstract, so that you can
decide whether this is of interest for you. At the end, I will
provide the pointers to the code and documentation.

The code is based on Dave Arilie's tree, drm-next branch and it
allows a GPU driver to have an arbitrary number of CRTCs
(configurable by user) instead of only those CRTCs that represent
real hardware.

The new CRTCs, that we call Virtual CRTCs can be attached to a
foreign device, that we call CTD device (short for Compression
Transmission and Display), and pixels can be streamed out of the GPU
to the device.

In one example, we use AMD/ATI Radeon GPU to do 3D rendering
(accelerated, of course) and we use our code to add additional
monitor heads using DisplayLink devices. In other words, we achieve
accelerated 3D rendering on a DisplayLink monitor. In another example
we funnel rendered pixels to userland by emulating a Video-for-Linux
device (and then userland can do whatever it wants with it). While
doing all this, GPU has no idea that we are doing this, the entire DRI
"thinks" that it is just dealing with a GPU that has a few "extra"
connectors and CRTCs. So everything ports without the need to modify
anything in the userland.

In general any device that can do something good with rendered pixels
can act as a CTD device, allowing a GPU to be an acceleration device
for a less capable display device or (the opposite) a frame-buffer-based
display device to be an expansion card for a GPU. Of course, for
each display device, a driver would have to be made compatible with our
new infrastructure (which is what we have done with DisplayLink driver
and also wrote one "synthetic" driver to fake out a V4L2 device as a
CTD device).

The newly introduced kernel module that we call VCRTCM (short for
Virtual CRTC Manager) handles the "traffic" between GPUs (actually
their CRTCs) and CTDs. The code makes use of DMA wherever possible
and also deals with specifics of CRTCs like modes, vblanks, page
flips, hardware cursor, etc. (just for kick, we played OpenArena
and watched Unigine Heaven demo on a DisplayLink monitor).

At this time, we would like to solicit feedback, comments, and
possibly contributions. The code is on github (pointers below)
and is based on the current state of drm-next branch from Dave's
tree. The code is very experimental, but complete and stable enough
that you can do something useful with it. We will be adding more
CTD drivers and updates to current ones in the near future and will
continue to maintain the code on github.

If the community finds this useful, we would be glad to work with
the maintainers on merging this upstream. So we would especially like
to hear what you would like to see changed to make this code acceptable
for the mainline of development.

My Github page is at https://github.com/ihadzic. To access the kernel
code type:

$ git clone git://github.com/ihadzic/linux-vcrtcm.git
$ git branch drm-next-vcrtcm origin/drm-next-vcrtcm
$ git checkout drm-next-vcrtcm

You will get all that's currently on Dave's drm-next plus our patches on
the top. We kept the development history preserved without squashing patches
(unless we had to due to merge/rebase conflicts), so you can see (and laugh
at) all our goofs and fixes to them.

To access the documentation, type:

$ git clone git://github.com/ihadzic/vcrtcm-doc.git

Then read the HOWTO.txt file. The first few sections provide some
general overview, and the sections that come later provide instructions
how to use our stuff.

Again, all comments, positive or negative, are very welcome.

-- Ilija

^ permalink raw reply

* Re: [RFC] Virtual CRTCs (proposal + experimental code)
From: Daniel Vetter @ 2011-11-03 17:21 UTC (permalink / raw)
  To: Ilija Hadzic; +Cc: linux-fbdev, dri-devel
In-Reply-To: <CA+4h6Hk3gE+8ou6NSMhoGJWZJ-5aM1OgC0HFoKs55fjfQ-qN8g@mail.gmail.com>

Hi,

Quick question: How does this compare to Dave Airlies' PRIME buffer
sharing work for drm respectively the more generic dma_buf buffer sharing
work pushed by Linaro? You seem to aim for a solution for similar problems
(judging by your description) using a rather different approach.

Cheers, Daniel

On Thu, Nov 03, 2011 at 11:59:21AM -0400, Ilija Hadzic wrote:
> Hi everyone,
> 
> I would like to bring to the attention of dri-devel and linux-fbdev
> community a set of hopefully useful and interesting patches that
> I (and a few other colleagues) have been working on during the past
> few months. Here, I will provide a short abstract, so that you can
> decide whether this is of interest for you. At the end, I will
> provide the pointers to the code and documentation.
> 
> The code is based on Dave Arilie's tree, drm-next branch and it
> allows a GPU driver to have an arbitrary number of CRTCs
> (configurable by user) instead of only those CRTCs that represent
> real hardware.
> 
> The new CRTCs, that we call Virtual CRTCs can be attached to a
> foreign device, that we call CTD device (short for Compression
> Transmission and Display), and pixels can be streamed out of the GPU
> to the device.
> 
> In one example, we use AMD/ATI Radeon GPU to do 3D rendering
> (accelerated, of course) and we use our code to add additional
> monitor heads using DisplayLink devices. In other words, we achieve
> accelerated 3D rendering on a DisplayLink monitor. In another example
> we funnel rendered pixels to userland by emulating a Video-for-Linux
> device (and then userland can do whatever it wants with it). While
> doing all this, GPU has no idea that we are doing this, the entire DRI
> "thinks" that it is just dealing with a GPU that has a few "extra"
> connectors and CRTCs. So everything ports without the need to modify
> anything in the userland.
> 
> In general any device that can do something good with rendered pixels
> can act as a CTD device, allowing a GPU to be an acceleration device
> for a less capable display device or (the opposite) a frame-buffer-based
> display device to be an expansion card for a GPU. Of course, for
> each display device, a driver would have to be made compatible with our
> new infrastructure (which is what we have done with DisplayLink driver
> and also wrote one "synthetic" driver to fake out a V4L2 device as a
> CTD device).
> 
> The newly introduced kernel module that we call VCRTCM (short for
> Virtual CRTC Manager) handles the "traffic" between GPUs (actually
> their CRTCs) and CTDs. The code makes use of DMA wherever possible
> and also deals with specifics of CRTCs like modes, vblanks, page
> flips, hardware cursor, etc. (just for kick, we played OpenArena
> and watched Unigine Heaven demo on a DisplayLink monitor).
> 
> At this time, we would like to solicit feedback, comments, and
> possibly contributions. The code is on github (pointers below)
> and is based on the current state of drm-next branch from Dave's
> tree. The code is very experimental, but complete and stable enough
> that you can do something useful with it. We will be adding more
> CTD drivers and updates to current ones in the near future and will
> continue to maintain the code on github.
> 
> If the community finds this useful, we would be glad to work with
> the maintainers on merging this upstream. So we would especially like
> to hear what you would like to see changed to make this code acceptable
> for the mainline of development.
> 
> My Github page is at https://github.com/ihadzic. To access the kernel
> code type:
> 
> $ git clone git://github.com/ihadzic/linux-vcrtcm.git
> $ git branch drm-next-vcrtcm origin/drm-next-vcrtcm
> $ git checkout drm-next-vcrtcm
> 
> You will get all that's currently on Dave's drm-next plus our patches on
> the top. We kept the development history preserved without squashing patches
> (unless we had to due to merge/rebase conflicts), so you can see (and laugh
> at) all our goofs and fixes to them.
> 
> To access the documentation, type:
> 
> $ git clone git://github.com/ihadzic/vcrtcm-doc.git
> 
> Then read the HOWTO.txt file. The first few sections provide some
> general overview, and the sections that come later provide instructions
> how to use our stuff.
> 
> Again, all comments, positive or negative, are very welcome.
> 
> -- Ilija
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply

* Re: [RFC] Virtual CRTCs (proposal + experimental code)
From: David Airlie @ 2011-11-03 17:27 UTC (permalink / raw)
  To: Ilija Hadzic; +Cc: linux-fbdev, dri-devel
In-Reply-To: <CA+4h6Hk3gE+8ou6NSMhoGJWZJ-5aM1OgC0HFoKs55fjfQ-qN8g@mail.gmail.com>


> 
> Hi everyone,
> 
> I would like to bring to the attention of dri-devel and linux-fbdev
> community a set of hopefully useful and interesting patches that
> I (and a few other colleagues) have been working on during the past
> few months. Here, I will provide a short abstract, so that you can
> decide whether this is of interest for you. At the end, I will
> provide the pointers to the code and documentation.
> 
> The code is based on Dave Arilie's tree, drm-next branch and it
> allows a GPU driver to have an arbitrary number of CRTCs
> (configurable by user) instead of only those CRTCs that represent
> real hardware.

Well the current plan I had for this was to do it in userspace, I don't think the kernel
has any business doing it and I think for the simple USB case its fine but will fallover
when you get to the non-trivial cases where some sort of acceleration is required to move
pixels around. But in saying that its good you've done what something, and I'll try and spend
some time reviewing it.

The current plan from my POV is to add hotplug support to the X server and just hotplug USB
devices up there, and not mess up the kernel with lots of extra state that really the drivers
don't need to know about.

I'm also not sure how you deal with tiling etc, you can also start hitting rendering limits,
where a GPU can render to 4kx4k but you can plug in more USB devices, again I'm hoping to
solve this in userspace as well.

But I'll take some time if I can find it to look over it.

Dave.

^ permalink raw reply

* Re: [RFC] Virtual CRTCs (proposal + experimental code)
From: Alan Cox @ 2011-11-03 17:53 UTC (permalink / raw)
  To: David Airlie; +Cc: linux-fbdev, dri-devel
In-Reply-To: <e80977e3-0992-454e-8ee2-2944560d3b3d@zmail16.collab.prod.int.phx2.redhat.com>

> Well the current plan I had for this was to do it in userspace, I don't think the kernel
> has any business doing it and I think for the simple USB case its fine but will fallover
> when you get to the non-trivial cases where some sort of acceleration is required to move
> pixels around. But in saying that its good you've done what something, and I'll try and spend
> some time reviewing it.

There are some clear advantages in the kernel doing bits of this I think.
The kernel understands device to device DMA, and has a better idea than
userspace about things like buffer alignment internals. It also means
this ultimately can work without X running which is a plus for some
applications (I want a displaylink gadget for my phone but thats another
story 8)).

> I'm also not sure how you deal with tiling etc, you can also start hitting rendering limits,
> where a GPU can render to 4kx4k but you can plug in more USB devices, again I'm hoping to
> solve this in userspace as well.

Tiling has to be handled by the recipient (at least when the fb is shared). The nastier end of
it that I don't see convered in the documentation is the handling of
fencing between cards. Eg if you wanted to do display on one card fed
into a second to do effects processing (think about TV type stuff)

Alan

^ permalink raw reply

* Re: [RFC] Virtual CRTCs (proposal + experimental code)
From: Ilija Hadzic @ 2011-11-03 18:00 UTC (permalink / raw)
  To: David Airlie; +Cc: linux-fbdev, dri-devel
In-Reply-To: <e80977e3-0992-454e-8ee2-2944560d3b3d@zmail16.collab.prod.int.phx2.redhat.com>



On Thu, 3 Nov 2011, David Airlie wrote:

>
> Well the current plan I had for this was to do it in userspace, I don't think the kernel
> has any business doing it and I think for the simple USB case its fine but will fallover
> when you get to the non-trivial cases where some sort of acceleration is required to move
> pixels around. But in saying that its good you've done what something, and I'll try and spend
> some time reviewing it.
>

The reason I opted for doing this in kernel is that I wanted to confine 
all the changes to a relatively small set of modules. At first this was a 
pragmatic approach, because I live out of the mainstream development tree 
and I didn't want to turn my life into an ethernal 
merging/conflict-resolution activity.

However, a more fundamental reason for it is that I didn't want to be tied 
to X. I deal with some userland applications (that unfortunately I can't 
provide much detail of .... yet) that live directly on the top of libdrm.

So I set myself a goal of "full application transparency". Whatever is 
thrown at me, I wanted to be able to handle without having to touch any 
piece of application or library that the application relies on.

I think I have achieved this goal and really everything I tried just 
worked out of the box (with an exception of two bug fixes to ATI DDX
and Xorg, that are bugs with or without my work).

-- Ilija


^ permalink raw reply

* [PATCH v3] GIO bus support for SGI IP22/28
From: Thomas Bogendoerfer @ 2011-11-04 11:09 UTC (permalink / raw)
  To: linux-mips, linux-fbdev; +Cc: ralf, FlorianSchandinat

SGI IP22/IP28 machines have GIO busses for adding graphics and other
extension cards. This patch adds support for GIO driver/device
handling and converts the newport console driver to a GIO driver.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
---

Changes in v3:
- reworked device tree for gio bus
- make module autoloading working

Changes in v2:
- use EXPORT_SYMBOL_GPL
- ChallengeS has only 2 slots
- use subsys_initcall for gio detection

 arch/mips/include/asm/gio_device.h  |   56 +++++
 arch/mips/sgi-ip22/Makefile         |    2 +-
 arch/mips/sgi-ip22/ip22-gio.c       |  428 +++++++++++++++++++++++++++++++++++
 arch/mips/sgi-ip22/ip22-mc.c        |   10 +-
 arch/mips/sgi-ip22/ip22-setup.c     |   21 --
 drivers/video/console/newport_con.c |   63 ++++--
 6 files changed, 534 insertions(+), 46 deletions(-)

diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
new file mode 100644
index 0000000..5437c84
--- /dev/null
+++ b/arch/mips/include/asm/gio_device.h
@@ -0,0 +1,56 @@
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct gio_device_id {
+	__u8 id;
+};
+
+struct gio_device {
+	struct device   dev;
+	struct resource resource;
+	unsigned int    irq;
+	unsigned int    slotno;
+
+	const char      *name;
+	struct gio_device_id id;
+	unsigned        id32:1;
+	unsigned        gio64:1;
+};
+#define to_gio_device(d) container_of(d, struct gio_device, dev)
+
+struct gio_driver {
+	const char    *name;
+	struct module *owner;
+	const struct gio_device_id *id_table;
+
+	int  (*probe)(struct gio_device *, const struct gio_device_id *);
+	void (*remove)(struct gio_device *);
+	int  (*suspend)(struct gio_device *, pm_message_t);
+	int  (*resume)(struct gio_device *);
+	void (*shutdown)(struct gio_device *);
+
+	struct device_driver driver;
+};
+#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
+
+extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
+						    const struct gio_device *);
+extern struct gio_device *gio_dev_get(struct gio_device *);
+extern void gio_dev_put(struct gio_device *);
+
+extern int gio_device_register(struct gio_device *);
+extern void gio_device_unregister(struct gio_device *);
+extern void gio_release_dev(struct device *);
+
+static inline void gio_device_free(struct gio_device *dev)
+{
+	gio_release_dev(&dev->dev);
+}
+
+extern int gio_register_driver(struct gio_driver *);
+extern void gio_unregister_driver(struct gio_driver *);
+
+#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
+#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
+
+extern void gio_set_master(struct gio_device *);
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index cc53849..411cda9 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
-	   ip22-platform.o ip22-reset.o ip22-setup.o
+	   ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
 
 obj-$(CONFIG_SGI_IP22) += ip22-berr.o
 obj-$(CONFIG_SGI_IP28) += ip28-berr.o
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
new file mode 100644
index 0000000..b6537d9
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-gio.c
@@ -0,0 +1,428 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/addrspace.h>
+#include <asm/paccess.h>
+#include <asm/gio_device.h>
+#include <asm/sgi/gio.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/ip22.h>
+
+static struct bus_type gio_bus_type;
+
+static struct {
+	const char *name;
+	__u8       id;
+} gio_name_table[] = {
+	{ .name = "SGI Impact", .id = 0x10 },
+	{ .name = "Phobos G160", .id = 0x35 },
+	/* fake IDs */
+	{ .name = "SGI Newport", .id = 0x7e },
+	{ .name = "SGI GR2/GR3", .id = 0x7f },
+};
+
+static struct device gio_bus = {
+	.init_name = "gio",
+};
+
+/**
+ * gio_match_device - Tell if an of_device structure has a matching
+ * gio_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
+		     const struct gio_device *dev)
+{
+	const struct gio_device_id *ids;
+
+	for (ids = match; ids->id != 0xff; ids++)
+		if (ids->id = dev->id.id)
+			return ids;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_match_device);
+
+struct gio_device *gio_dev_get(struct gio_device *dev)
+{
+	struct device *tmp;
+
+	if (!dev)
+		return NULL;
+	tmp = get_device(&dev->dev);
+	if (tmp)
+		return to_gio_device(tmp);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_dev_get);
+
+void gio_dev_put(struct gio_device *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_dev_put);
+
+/**
+ * gio_release_dev - free an gio device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this gio device are
+ * done.
+ */
+void gio_release_dev(struct device *dev)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	kfree(giodev);
+}
+EXPORT_SYMBOL_GPL(gio_release_dev);
+
+int gio_device_register(struct gio_device *giodev)
+{
+	giodev->dev.bus = &gio_bus_type;
+	giodev->dev.parent = &gio_bus;
+	return device_register(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_register);
+
+void gio_device_unregister(struct gio_device *giodev)
+{
+	device_unregister(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_unregister);
+
+static int gio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *gio_drv = to_gio_driver(drv);
+
+	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
+}
+
+static int gio_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct gio_driver *drv;
+	struct gio_device *gio_dev;
+	const struct gio_device_id *match;
+
+	drv = to_gio_driver(dev->driver);
+	gio_dev = to_gio_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	gio_dev_get(gio_dev);
+
+	match = gio_match_device(drv->id_table, gio_dev);
+	if (match)
+		error = drv->probe(gio_dev, match);
+	if (error)
+		gio_dev_put(gio_dev);
+
+	return error;
+}
+
+static int gio_device_remove(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(gio_dev);
+	return 0;
+}
+
+static int gio_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(gio_dev, state);
+	return error;
+}
+
+static int gio_device_resume(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(gio_dev);
+	return error;
+}
+
+static void gio_device_shutdown(struct device *dev)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	struct gio_driver *drv = to_gio_driver(dev->driver);
+
+	if (dev->driver && drv->shutdown)
+		drv->shutdown(gio_dev);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+	int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
+
+	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static ssize_t name_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	return sprintf(buf, "%s", giodev->name);
+}
+
+static ssize_t id_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
+{
+	struct gio_device *giodev;
+
+	giodev = to_gio_device(dev);
+	return sprintf(buf, "%x", giodev->id.id);
+}
+
+static struct device_attribute gio_dev_attrs[] = {
+	__ATTR_RO(modalias),
+	__ATTR_RO(name),
+	__ATTR_RO(id),
+	__ATTR_NULL,
+};
+
+static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct gio_device *gio_dev = to_gio_device(dev);
+
+	add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
+	return 0;
+}
+
+int gio_register_driver(struct gio_driver *drv)
+{
+	/* initialize common driver fields */
+	if (!drv->driver.name)
+		drv->driver.name = drv->name;
+	if (!drv->driver.owner)
+		drv->driver.owner = drv->owner;
+	drv->driver.bus = &gio_bus_type;
+
+	/* register with core */
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_register_driver);
+
+void gio_unregister_driver(struct gio_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_unregister_driver);
+
+void gio_set_master(struct gio_device *dev)
+{
+	u32 tmp = sgimc->giopar;
+
+	switch (dev->slotno) {
+	case 0:
+		tmp |= SGIMC_GIOPAR_MASTERGFX;
+		break;
+	case 1:
+		tmp |= SGIMC_GIOPAR_MASTEREXP0;
+		break;
+	case 2:
+		tmp |= SGIMC_GIOPAR_MASTEREXP1;
+		break;
+	}
+	sgimc->giopar = tmp;
+}
+EXPORT_SYMBOL_GPL(gio_set_master);
+
+void ip22_gio_set_64bit(int slotno)
+{
+	u32 tmp = sgimc->giopar;
+
+	switch (slotno) {
+	case 0:
+		tmp |= SGIMC_GIOPAR_GFX64;
+		break;
+	case 1:
+		tmp |= SGIMC_GIOPAR_EXP064;
+		break;
+	case 2:
+		tmp |= SGIMC_GIOPAR_EXP164;
+		break;
+	}
+	sgimc->giopar = tmp;
+}
+
+static int ip22_gio_id(unsigned long addr, u32 *res)
+{
+	u8 tmp8;
+	u8 tmp16;
+	u32 tmp32;
+	u8 *ptr8;
+	u16 *ptr16;
+	u32 *ptr32;
+
+	ptr32 = (void *)CKSEG1ADDR(addr);
+	if (!get_dbe(tmp32, ptr32)) {
+		/*
+		 * We got no DBE, but this doesn't mean anything.
+		 * If GIO is pipelined (which can't be disabled
+		 * for GFX slot) we don't get a DBE, but we see
+		 * the transfer size as data. So we do an 8bit
+		 * and a 16bit access and check whether the common
+		 * data matches
+		 */
+		ptr8 = (void *)CKSEG1ADDR(addr + 3);
+		get_dbe(tmp8, ptr8);
+		ptr16 = (void *)CKSEG1ADDR(addr + 2);
+		get_dbe(tmp16, ptr16);
+		if (tmp8 = (tmp16 & 0xff) &&
+		    tmp8 = (tmp32 & 0xff) &&
+		    tmp16 = (tmp32 & 0xffff)) {
+			*res = tmp32;
+			return 1;
+		}
+	}
+	return 0; /* nothing here */
+}
+
+#define HQ2_MYSTERY_OFFS       0x6A07C
+#define NEWPORT_USTATUS_OFFS   0xF133C
+
+static int ip22_is_gr2(unsigned long addr)
+{
+	u32 tmp;
+	u32 *ptr;
+
+	/* HQ2 only allows 32bit accesses */
+	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
+	if (!get_dbe(tmp, ptr)) {
+		if (tmp = 0xdeadbeef)
+			return 1;
+	}
+	return 0;
+}
+
+
+static void ip22_check_gio(int slotno, unsigned long addr)
+{
+	const char *name = "Unknown";
+	struct gio_device *gio_dev;
+	u32 tmp;
+	__u8 id;
+	int i;
+
+	/* first look for GR2/GR3 by checking mystery register */
+	if (ip22_is_gr2(addr))
+		tmp = 0x7f;
+	else {
+		if (!ip22_gio_id(addr, &tmp)) {
+			/*
+			 * no GIO signature at start address of slot, but
+			 * Newport doesn't have one, so let's check usea
+			 * status register
+			 */
+			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
+				tmp = 0x7e;
+			else
+				tmp = 0;
+		}
+	}
+	if (tmp) {
+		id = GIO_ID(tmp);
+		if (tmp & GIO_32BIT_ID) {
+			if (tmp & GIO_64BIT_IFACE)
+				ip22_gio_set_64bit(slotno);
+		}
+		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
+			if (id = gio_name_table[i].id) {
+				name = gio_name_table[i].name;
+				break;
+			}
+		}
+		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
+		       slotno, name, id);
+		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
+		gio_dev->name = name;
+		gio_dev->slotno = slotno;
+		gio_dev->id.id = id;
+		gio_dev->resource.start = addr;
+		gio_dev->resource.end = addr + 0x3fffff;
+		gio_dev->resource.flags = IORESOURCE_MEM;
+		dev_set_name(&gio_dev->dev, "%d", slotno);
+		gio_device_register(gio_dev);
+	} else
+		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
+}
+
+static struct bus_type gio_bus_type = {
+	.name      = "gio",
+	.dev_attrs = gio_dev_attrs,
+	.match     = gio_bus_match,
+	.probe     = gio_device_probe,
+	.remove    = gio_device_remove,
+	.suspend   = gio_device_suspend,
+	.resume    = gio_device_resume,
+	.shutdown  = gio_device_shutdown,
+	.uevent    = gio_device_uevent,
+};
+
+static struct resource gio_bus_resource = {
+	.start = GIO_SLOT_GFX_BASE,
+	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
+	.name  = "GIO Bus",
+	.flags = IORESOURCE_MEM,
+};
+
+int __init ip22_gio_init(void)
+{
+	unsigned int pbdma __maybe_unused;
+	int ret;
+
+	ret = device_register(&gio_bus);
+	if (ret)
+		return ret;
+
+	ret = bus_register(&gio_bus_type);
+	if (!ret) {
+		request_resource(&iomem_resource, &gio_bus_resource);
+		printk(KERN_INFO "GIO: Probing bus...\n");
+
+		if (ip22_is_fullhouse() ||
+		    !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
+			/* Indigo2 and ChallengeS */
+			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+		} else {
+			/* Indy */
+			ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+			ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+			ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
+		}
+	} else
+		device_unregister(&gio_bus);
+
+	return ret;
+}
+
+subsys_initcall(ip22_gio_init);
+
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index d22262e..75ada8a 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -139,11 +139,11 @@ void __init sgimc_init(void)
 	 *         zero.
 	 */
 	/* don't touch parity settings for IP28 */
-#ifndef CONFIG_SGI_IP28
 	tmp = sgimc->cpuctrl0;
-	tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
-		SGIMC_CCTRL0_R4KNOCHKPARR);
+#ifndef CONFIG_SGI_IP28
+	tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
 #endif
+	tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
 	sgimc->cpuctrl0 = tmp;
 
 	/* Step 3: Setup the MC write buffer depth, this is controlled
@@ -178,7 +178,8 @@ void __init sgimc_init(void)
 	 */
 
 	/* First the basic invariants across all GIO64 implementations. */
-	tmp = SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
+	tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
+	tmp |= SGIMC_GIOPAR_HPC64;	/* All 1st HPC's interface at 64bits */
 	tmp |= SGIMC_GIOPAR_ONEBUS;	/* Only one physical GIO bus exists */
 
 	if (ip22_is_fullhouse()) {
@@ -193,7 +194,6 @@ void __init sgimc_init(void)
 			tmp |= SGIMC_GIOPAR_PLINEEXP0;	/* exp[01] pipelined */
 			tmp |= SGIMC_GIOPAR_PLINEEXP1;
 			tmp |= SGIMC_GIOPAR_MASTEREISA;	/* EISA masters */
-			tmp |= SGIMC_GIOPAR_GFX64;	/* GFX at 64 bits */
 		}
 	} else {
 		/* Guiness specific settings. */
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 5e66213..c7bdfe4 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -26,9 +26,6 @@
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
 
-unsigned long sgi_gfxaddr;
-EXPORT_SYMBOL_GPL(sgi_gfxaddr);
-
 extern void ip22_be_init(void) __init;
 
 void __init plat_mem_setup(void)
@@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
 		prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
 		add_preferred_console("arc", 0, NULL);
 	}
-
-#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
-	{
-		ULONG *gfxinfo;
-		ULONG * (*__vec)(void) = (void *) (long)
-			*((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
-
-		gfxinfo = __vec();
-		sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
-			       && gfxinfo[1] <= 0xc0000000)
-			       ? gfxinfo[1] - 0xa0000000 : 0);
-
-		/* newport addresses? */
-		if (sgi_gfxaddr = 0x1f0f0000 || sgi_gfxaddr = 0x1f4f0000) {
-			conswitchp = &newport_con;
-		}
-	}
-#endif
 }
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 93317b5..a122d92 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -25,14 +25,13 @@
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/gio_device.h>
+
 #include <video/newport.h>
 
 #include <linux/linux_logo.h>
 #include <linux/font.h>
 
-
-extern unsigned long sgi_gfxaddr;
-
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
 /* borrowed from fbcon.c */
@@ -304,12 +303,6 @@ static const char *newport_startup(void)
 {
 	int i;
 
-	if (!sgi_gfxaddr)
-		return NULL;
-
-	if (!npregs)
-		npregs = (struct newport_regs *)/* ioremap cannot fail */
-			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
 	npregs->cset.config = NPORT_CFG_GD0;
 
 	if (newport_wait(npregs))
@@ -743,26 +736,58 @@ const struct consw newport_con = {
 	.con_save_screen  = DUMMY
 };
 
-#ifdef MODULE
-static int __init newport_console_init(void)
+static int newport_probe(struct gio_device *dev,
+			 const struct gio_device_id *id)
 {
-	if (!sgi_gfxaddr)
-		return 0;
+	unsigned long newport_addr;
 
-	if (!npregs)
-		npregs = (struct newport_regs *)/* ioremap cannot fail */
-			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+	if (!dev->resource.start)
+		return -EINVAL;
+
+	if (npregs)
+		return -EBUSY; /* we only support one Newport as console */
+
+	newport_addr = dev->resource.start + 0xF0000;
+	if (!request_mem_region(newport_addr, 0x10000, "Newport"))
+		return -ENODEV;
+
+	npregs = (struct newport_regs *)/* ioremap cannot fail */
+		ioremap(newport_addr, sizeof(struct newport_regs));
 
 	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 }
-module_init(newport_console_init);
 
-static void __exit newport_console_exit(void)
+static void newport_remove(struct gio_device *dev)
 {
 	give_up_console(&newport_con);
 	iounmap((void *)npregs);
 }
+
+static struct gio_device_id newport_ids[] = {
+	{ .id = 0x7e },
+	{ .id = 0xff }
+};
+
+MODULE_ALIAS("gio:7e");
+
+static struct gio_driver newport_driver = {
+	.name = "newport",
+	.id_table = newport_ids,
+	.probe = newport_probe,
+	.remove = newport_remove,
+};
+
+int __init newport_console_init(void)
+{
+	return gio_register_driver(&newport_driver);
+}
+
+void __exit newport_console_exit(void)
+{
+	gio_unregister_driver(&newport_driver);
+}
+
+module_init(newport_console_init);
 module_exit(newport_console_exit);
-#endif
 
 MODULE_LICENSE("GPL");

^ permalink raw reply related


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