linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexander Kern <alex.kern@gmx.de>
To: linux-fbdev-devel@lists.sourceforge.net
Cc: "Benjamin Herrenschmidt" <benh@kernel.crashing.org>,
	"Ville Syrjälä" <syrjala@sci.fi>
Subject: Re: URGENT: status of atyfb
Date: Fri, 6 Aug 2004 08:09:37 +0200	[thread overview]
Message-ID: <200408060809.37494.alex.kern@gmx.de> (raw)
In-Reply-To: <1091568340.1900.14.camel@gaston>

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

Am Dienstag, 3. August 2004 23:25 schrieb Benjamin Herrenschmidt:
> > Hi, I do not have any information or hardware about PPC. Should it own
> > something like OpenFirmware? In this case it is possible to read clock
> > information from this.
>
> On some models, yes, on some no. Older machines have a firmware that
> won't tell you anything, the MacOS driver back then was hard coding the
> values.
>
> Anyway, the clocks are ok, apparently (maybe not the engine one though,
> see later), the problem was that the DLL magic was reverted for the
> LT-G, plus some minor issues with the driver blowing up on non-BIOS
> machines that I can fix.
>
> The engine tends to lockup quickly though, I'll do experiments.
>
> > I found, that we change a little behaviour. Please give a try for this
> > patch...
>
> Your patch seem to address the DLL issue, I did that too, fixes the
> display, I'll toy around and let you know.
>
> Also, when just dropping the existing driver into the current linus tree,
> the cursor code is blowing up, I don't know why yet, I suppose some changes
> to the common code in the fbdev tree. I'll have a look.
>
> I really want this new driver to be sent upstream ASAP. What I may do is
> once I get it working well enough, I'll send it to andrew for the -mm tree
> and leave it there for a while to get it properly tested.
>
> Ben.
Hi, here a snapshot from my tree over 2.6.7 + js3

Changes:

revert SDRAM_MAGIC_PLL to old behaviour
do a "from BIOS" initialisation only by __i386__

Regards
Alex

[-- Attachment #2: mach64-js3-ak6a.diff --]
[-- Type: text/x-diff, Size: 78050 bytes --]

diff -ur -X patches/exclude linux-2.6.7.js3/drivers/video/aty/atyfb.h linux-2.6.7.ak/drivers/video/aty/atyfb.h
--- linux-2.6.7.js3/drivers/video/aty/atyfb.h	2004-06-27 01:35:27.000000000 +0200
+++ linux-2.6.7.ak/drivers/video/aty/atyfb.h	2004-08-04 22:25:21.000000000 +0200
@@ -3,6 +3,8 @@
  */
 
 #include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
     /*
      *  Elements of the hardware specific atyfb_par structure
      */
@@ -30,9 +32,18 @@
 	u32 shadow_h_sync_strt_wid;
 	u32 shadow_v_tot_disp;
 	u32 shadow_v_sync_strt_wid;
+	u32 lcd_gen_cntl;
+	u32 lcd_config_panel;
+	u32 lcd_index;
 #endif
 };
 
+struct aty_interrupt {
+	wait_queue_head_t wait;
+	unsigned int count;
+	int pan_display;
+};
+
 struct pll_info {
 	int pll_max;
 	int pll_min;
@@ -116,6 +127,7 @@
 
 struct atyfb_par {
 	struct aty_cmap_regs *aty_cmap_regs;
+	struct { u8 red, green, blue; } palette[256];
 	const struct aty_dac_ops *dac_ops;
 	const struct aty_pll_ops *pll_ops;
 	unsigned long ati_regbase;
@@ -141,8 +153,8 @@
 #ifdef __sparc__
 	struct pci_mmap_map *mmap_map;
 	u8 mmaped;
-	int open;
 #endif
+	int open;
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 	unsigned long bios_base_phys;
 	unsigned long bios_base;
@@ -165,6 +177,10 @@
 #endif
 	unsigned long aux_start; /* auxiliary aperture */
 	unsigned long aux_size;
+	struct aty_interrupt vblank;
+	unsigned long irq_flags;
+	unsigned int irq;
+	spinlock_t int_lock;
 };
 
     /*
@@ -177,7 +193,7 @@
 #define M64F_MAGIC_FIFO		0x00000002
 #define M64F_GTB_DSP		0x00000004
 #define M64F_FIFO_32		0x00000008
-#define M64F_NO_EXT_PLL		0x00000010
+#define M64F_SDRAM_MAGIC_PLL	0x00000010
 #define M64F_MAGIC_POSTDIV	0x00000020
 #define M64F_INTEGRATED		0x00000040
 #define M64F_CT_BUS		0x00000080
@@ -191,7 +207,7 @@
 #define M64F_G3_PB_1_1		0x00008000
 #define M64F_G3_PB_1024x768	0x00010000
 #define M64F_EXTRA_BRIGHT	0x00020000
-#define M64F_LT_SLEEP		0x00040000
+#define M64F_LT_LCD_REGS	0x00040000
 #define M64F_XL_DLL		0x00080000
 #define M64F_MFB_FORCE_4	0x00100000
 #define M64F_HW_TRIPLE		0x00200000
@@ -251,6 +267,11 @@
 #endif
 }
 
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
+extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
+#endif
+
     /*
      *  DAC operations
      */
@@ -275,6 +296,7 @@
 	int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, union aty_pll * pll);
 	u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll);
 	void (*set_pll)   (const struct fb_info * info, const union aty_pll * pll);
+	void (*get_pll)   (const struct fb_info *info, union aty_pll * pll);
 	int (*init_pll)   (const struct fb_info * info, union aty_pll * pll);
 };
 
diff -ur -X patches/exclude linux-2.6.7.js3/drivers/video/aty/atyfb_base.c linux-2.6.7.ak/drivers/video/aty/atyfb_base.c
--- linux-2.6.7.js3/drivers/video/aty/atyfb_base.c	2004-06-27 01:35:27.000000000 +0200
+++ linux-2.6.7.ak/drivers/video/aty/atyfb_base.c	2004-08-04 22:57:50.000000000 +0200
@@ -26,6 +26,7 @@
  *			   Anthony Tong <atong@uiuc.edu>
  *
  *  Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
+ *  Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
@@ -41,15 +42,16 @@
     - cursor support on all cards and all ramdacs.
     - cursor parameters controlable via ioctl()s.
     - guess PLL and MCLK based on the original PLL register values initialized
-      by the BIOS or Open Firmware (if they are initialized).
+      by Open Firmware (if they are initialized). BIOS is done
 
-    (Anyone to help with this?)
+    (Anyone with Mac to help with this?)
 
 ******************************************************************************/
 
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -61,6 +63,9 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -101,33 +106,63 @@
 #define GUI_RESERVE	(1 * PAGE_SIZE)
 
 /* FIXME: remove the FAIL definition */
-#define FAIL(msg) do { printk(KERN_CRIT msg "\n"); return -EINVAL; } while (0)
-#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0)
+#define FAIL(msg) do { printk(KERN_CRIT "atyfb: " msg "\n"); return -EINVAL; } while (0)
+#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0)
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...)	printk(KERN_DEBUG "atyfb: " fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define PRINTKI(fmt, args...)	printk(KERN_INFO "atyfb: " fmt, ## args)
+#define PRINTKE(fmt, args...)	 printk(KERN_ERR "atyfb: " fmt, ## args)
 
 #if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
-static void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
+static const u32 lt_lcd_regs[] = {
+	CONFIG_PANEL_LG,
+	LCD_GEN_CNTL_LG,
+	DSTN_CONTROL_LG,
+	HFB_PITCH_ADDR_LG,
+	HORZ_STRETCHING_LG,
+	VERT_STRETCHING_LG,
+	0, /* EXT_VERT_STRETCH */
+	LT_GIO_LG,
+	POWER_MANAGEMENT_LG
+};
+
+void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
 {
-	unsigned long temp;
+	if (M64_HAS(LT_LCD_REGS)) {
+		aty_st_le32(lt_lcd_regs[index], val, par);
+	} else {
+		unsigned long temp;
 
-	/* write addr byte */
-	temp = aty_ld_le32(LCD_INDEX, par);
-	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
-	/* write the register value */
-	aty_st_le32(LCD_DATA, val, par);
+		/* write addr byte */
+		temp = aty_ld_le32(LCD_INDEX, par);
+		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+		/* write the register value */
+		aty_st_le32(LCD_DATA, val, par);
+	}
 }
 
-static u32 aty_ld_lcd(int index, const struct atyfb_par *par)
+u32 aty_ld_lcd(int index, const struct atyfb_par *par)
 {
-	unsigned long temp;
+	if (M64_HAS(LT_LCD_REGS)) {
+		return aty_ld_le32(lt_lcd_regs[index], par);
+	} else {
+		unsigned long temp;
 
-	/* write addr byte */
-	temp = aty_ld_le32(LCD_INDEX, par);
-	aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
-	/* read the register value */
-	return aty_ld_le32(LCD_DATA, par);
+		/* write addr byte */
+		temp = aty_ld_le32(LCD_INDEX, par);
+		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+		/* read the register value */
+		return aty_ld_le32(LCD_DATA, par);
+	}
 }
 #endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
 
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
 /*
  * ATIReduceRatio --
  *
@@ -150,7 +185,7 @@
     *Numerator /= Divider;
     *Denominator /= Divider;
 }
-
+#endif
     /*
      *  The Hardware parameters for each card
      */
@@ -209,11 +244,11 @@
 #ifdef CONFIG_ATARI
 static int store_video_par(char *videopar, unsigned char m64_num);
 #endif
-#if 0
+
 static struct crtc saved_crtc;
 static union aty_pll saved_pll;
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
-#endif
+
 static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
 static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc);
 static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var);
@@ -254,22 +289,19 @@
 	.fb_fillrect	= atyfb_fillrect,
 	.fb_copyarea	= atyfb_copyarea,
 	.fb_imageblit	= atyfb_imageblit,
-	.fb_cursor	= atyfb_cursor,
+	.fb_cursor	= soft_cursor,
 #ifdef __sparc__
 	.fb_mmap	= atyfb_mmap,
 #endif
 	.fb_sync	= atyfb_sync,
 };
 
-static char noaccel __initdata = 0;
-static u32 default_vram __initdata = 0;
-static int default_pll __initdata = 0;
-static int default_mclk __initdata = 0;
-static int default_xclk __initdata = 0;
-
-#ifndef MODULE
-static char *mode_option __initdata = NULL;
-#endif
+static int noaccel;
+static int vram;
+static int pll;
+static int mclk;
+static int xclk;
+static char *mode;
 
 #ifdef CONFIG_PPC
 static int default_vmode __initdata = VMODE_CHOOSE;
@@ -294,20 +326,20 @@
 #define ATI_CHIP_264GT     (M64F_GT | M64F_INTEGRATED               | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT)
 
 #define ATI_CHIP_264VTB    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)
-#define ATI_CHIP_264VT3    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)
-#define ATI_CHIP_264VT4    (M64F_VT | M64F_INTEGRATED               | M64F_GTB_DSP | M64F_NO_EXT_PLL)
+#define ATI_CHIP_264VT3    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL)
+#define ATI_CHIP_264VT4    (M64F_VT | M64F_INTEGRATED               | M64F_GTB_DSP)
 
-#define ATI_CHIP_264LT     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP | M64F_NO_EXT_PLL)
+#define ATI_CHIP_264LT     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP)
 
 /* make sets shorter */
-#define ATI_MODERN_SET     (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_NO_EXT_PLL)
+#define ATI_MODERN_SET     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP | M64F_EXTRA_BRIGHT)
 
-#define ATI_CHIP_264GTB    (ATI_MODERN_SET) 
+#define ATI_CHIP_264GTB    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) 
 /*#define ATI_CHIP_264GTDVD  ?*/
-#define ATI_CHIP_264LTG    (ATI_MODERN_SET)
+#define ATI_CHIP_264LTG    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
 
-#define ATI_CHIP_264GT2C   (ATI_MODERN_SET | M64F_HW_TRIPLE)
-#define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
+#define ATI_CHIP_264GT2C   (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE)
+#define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 #define ATI_CHIP_264LTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 
 #define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
@@ -336,7 +368,7 @@
 
 	{ PCI_CHIP_MACH64LT, "3D RAGE LT (Mach64 LT)", 135, 63, 63, ATI_CHIP_264LT },
 	 /* FIXME chipset maybe ATI_CHIP_264LTPRO ? */
-	{ PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_264LTG | M64F_LT_SLEEP | M64F_G3_PB_1024x768 },
+	{ PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 },
 
 	{ PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, ATI_CHIP_264VT4 },
 
@@ -365,19 +397,20 @@
 	{ PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL },
 
 	{ PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
-	{ PCI_CHIP_MACH64LN, "3D RAGE Mobility (Mach64 LN, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
-	{ PCI_CHIP_MACH64LR, "3D RAGE Mobility (Mach64 LR, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
-	{ PCI_CHIP_MACH64LS, "3D RAGE Mobility (Mach64 LS, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
 #endif /* CONFIG_FB_ATY_CT */
 };
 
+/* can not fail */
 static int __devinit correct_chipset(struct atyfb_par *par)
 {
-	const char *name;
-	int i, err = 0;
-	u32 chip_id;
-	u16 type;
 	u8 rev;
+	u16 type;
+	u32 chip_id;
+	const char *name;
+	int i;
 
 	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
 		if (par->pci_id == aty_chips[i].pci_id)
@@ -396,12 +429,12 @@
 	switch(par->pci_id) {
 #ifdef CONFIG_FB_ATY_GX
 	case PCI_CHIP_MACH64GX:
-		if (type != 0x00d7)
-			err = -ENXIO;	
+		if(type != 0x00d7);
+			return -ENODEV;
 		break;
 	case PCI_CHIP_MACH64CX:
-		if (type == 0x0057)
-			err = -ENXIO;
+		if(type != 0x0057);
+			return -ENODEV;
 		break;
 #endif
 #ifdef CONFIG_FB_ATY_CT
@@ -443,11 +476,9 @@
 		break;
 #endif
 	}
-	if (!err)
-		printk("atyfb: %s [0x%04x rev 0x%02x]\n", name, type, rev);
-	else
-		printk(KERN_INFO "atyfb: Unknown mach64 0x%04x rev 0x%04x\n", type, rev);	
-	return err;			
+
+	PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev);
+	return 0;
 }
 
 static char ram_dram[] __initdata = "DRAM";
@@ -457,9 +488,9 @@
 #endif /* CONFIG_FB_ATY_GX */
 #ifdef CONFIG_FB_ATY_CT
 static char ram_edo[] __initdata = "EDO";
-static char ram_sdram[] __initdata = "SDRAM";
-static char ram_sgram[] __initdata = "SGRAM";
-static char ram_wram[] __initdata = "WRAM";
+static char ram_sdram[] __initdata = "SDRAM (1:1)";
+static char ram_sgram[] __initdata = "SGRAM (1:1)";
+static char ram_sdram32[] __initdata = "SDRAM (2:1) (32-bit)";
 static char ram_off[] __initdata = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
@@ -476,7 +507,7 @@
 #ifdef CONFIG_FB_ATY_CT
 static char *aty_ct_ram[8] __initdata = {
 	ram_off, ram_dram, ram_edo, ram_edo,
-	ram_sdram, ram_sgram, ram_wram, ram_resv
+	ram_sdram, ram_sgram, ram_sdram32, ram_resv
 };
 #endif /* CONFIG_FB_ATY_CT */
 
@@ -543,9 +574,30 @@
 /*
  *  CRTC programming
  */
-#if 0
+
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
 {
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);
+		    aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+		}
+		crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par);
+		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);
+		
+
+		/* switch to non shadow registers */
+		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
+                    ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
+
+		/* save stretching */
+		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
+		crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);
+		if (!M64_HAS(LT_LCD_REGS))
+			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);
+	}
+#endif
 	crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
 	crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
 	crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
@@ -555,51 +607,34 @@
 	crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
 
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-
 	if (par->lcd_table != 0) {
 		/* switch to shadow registers */
-		u32 temp = aty_ld_lcd(LCD_GEN_CNTL, par);
-		aty_st_lcd(LCD_GEN_CNTL, temp | SHADOW_EN | SHADOW_RW_EN, par);
+		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+			SHADOW_EN | SHADOW_RW_EN, par);
 
-		/* get shadow registers */
 		crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
 		crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
 		crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
 		crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
 
-		aty_st_le32(LCD_GEN_CNTL, temp & ~(SHADOW_EN | SHADOW_RW_EN), par);
-
-		/* get stretching */
-		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
-		crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);
-		crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);
+		aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
 	}
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 }
-#endif
+
 static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
 {
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-	u32 temp;
-
-	/* Load LCD registers */
 	if (par->lcd_table != 0) {
-		// Set the CRTC to primary, and make the registers writeable
-		temp = aty_ld_lcd(LCD_GEN_CNTL, par);
-		temp &= LCD_SET_PRIMARY_MASK;
-		temp |= DONT_SHADOW_VPAR;
-		aty_st_lcd(LCD_GEN_CNTL, temp, par);
-#if 0
-		/* Stop CRTC */
-		aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl &
-			~(CRTC_EXT_DISP_EN | CRTC_EN), par);
+		/* stop CRTC */
+		aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par);
 
-		/* Update non-shadow registers first */
-		/*aty_st_lcd(LCD_CONFIG_PANEL, pATIHW->config_panel);*/
+		/* update non-shadow registers first */
+		aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par);
 		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
 			~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
-#endif
-		/* Temporarily disable stretching */
+
+		/* temporarily disable stretching */
 		aty_st_lcd(HORZ_STRETCHING,
 			crtc->horz_stretching &
 			~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par);
@@ -609,55 +644,72 @@
 			VERT_STRETCH_USE0 | VERT_STRETCH_EN), par);
 	}
 #endif
+	/* turn off CRT */
 	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par);
+
+	DPRINTK("setting up CRTC\n");
+	PRINTKI("set primary CRT to %ix%i %c%c composite %c\n",
+	    ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) & 0x7ff) + 1),
+	    (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & 0x200000)?'N':'P',
+	    (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N');
+
+	DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp);
+	DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid);
+	DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp);
+	DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid);
+	DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch);
+	DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline);
+	DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl);
+
 	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par);
 	aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par);
 	aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par);
 	aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par);
-	aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);
 	aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par);
+	aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);
+
 	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);
-#ifdef DEBUG
-	printk(KERN_INFO "setting up CRTC\n");
-	printk(KERN_INFO "CRTC_GEN_CNTL: %x\n",crtc->gen_cntl);
-	printk(KERN_INFO "CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp);
-	printk(KERN_INFO "CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid);
-	printk(KERN_INFO "CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp);
-	printk(KERN_INFO "CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid);
+#if 0
+	FIXME
+	if (par->accel_flags & FB_ACCELF_TEXT)
+		aty_init_engine(par, info);
 #endif
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-	/* After setting the CRTC registers we should set the LCD
-	 * registers.
-	 */
+	/* after setting the CRTC registers we should set the LCD registers. */
 	if (par->lcd_table != 0) {
 		/* switch to shadow registers */
-		temp = aty_ld_lcd(LCD_GEN_CNTL, par);
-		aty_st_lcd(LCD_GEN_CNTL, temp | SHADOW_EN | SHADOW_RW_EN, par);
+		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+			(SHADOW_EN | SHADOW_RW_EN), par);
+
+		PRINTKI("set secondary CRT to %ix%i %c%c\n",
+		    ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v_tot_disp>>16) & 0x7ff) + 1),
+		    (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_sync_strt_wid & 0x200000)?'N':'P'); 
+
+		DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp);
+		DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wid);
+		DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp);
+		DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wid);
 
-		/* set shadow registers */
 		aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par);
 		aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par);
 		aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par);
 		aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par);
 
-		aty_st_lcd(LCD_GEN_CNTL, temp & ~(SHADOW_EN | SHADOW_RW_EN), par);
+		/* restore CRTC selection & shadow state and enable stretching */
+		DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl);
+		DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching);
+		DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching);
+		if(!M64_HAS(LT_LCD_REGS))
+		    DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);
 
-#ifdef DEBUG
-		printk(KERN_INFO "LCD_GEN_CNTL: %x\n", temp);
-		printk(KERN_INFO "HORZ_STRETCHING: %x\n", crtc->horz_stretching);
-		printk(KERN_INFO "VERT_STRETCHING: %x\n", crtc->vert_stretching);
-		printk(KERN_INFO "EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);
-#endif
-		/* Restore CRTC selection & shadow state */
-		/*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/
-
-		/* Enable/disable stretching */
+		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
 		aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par);
 		aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par);
-		aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);
-		/*
-		outr(LCD_INDEX, pATIHW->lcd_index);
-		*/
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);
+		    aty_ld_le32(LCD_INDEX, par);
+		    aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+		}
 	}
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 }
@@ -667,14 +719,11 @@
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
-	u32 sync, vmode;
+	u32 sync, vmode, vdisplay;
 	u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
 	u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
 	u32 pix_width, dp_pix_width, dp_chain_mask;
-#ifdef CONFIG_FB_ATY_GENERIC_LCD
-	int VScan = 1;
-	u32 lcd_on_off = 0;
-#endif
+
 	/* input */
 	xres = var->xres;
 	yres = var->yres;
@@ -683,6 +732,8 @@
 	xoffset = var->xoffset;
 	yoffset = var->yoffset;
 	bpp = var->bits_per_pixel;
+	if (bpp == 16)
+		bpp = (var->green.length == 5) ? 15 : 16;
 	sync = var->sync;
 	vmode = var->vmode;
 
@@ -702,12 +753,18 @@
 		    HOST_8BPP | SRC_8BPP | DST_8BPP |
 		    BYTE_ORDER_LSB_TO_MSB;
 		dp_chain_mask = DP_CHAIN_8BPP;
-	} else if (bpp <= 16) {
+	} else if (bpp <= 15) {
 		bpp = 16;
 		pix_width = CRTC_PIX_WIDTH_15BPP;
 		dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
 		    BYTE_ORDER_LSB_TO_MSB;
 		dp_chain_mask = DP_CHAIN_15BPP;
+	} else if (bpp <= 16) {
+		bpp = 16;
+		pix_width = CRTC_PIX_WIDTH_16BPP;
+		dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_16BPP;
 	} else if (bpp <= 24 && M64_HAS(INTEGRATED)) {
 		bpp = 24;
 		pix_width = CRTC_PIX_WIDTH_24BPP;
@@ -730,30 +787,59 @@
 	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
 	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
 
+	if((xres > 1600) || (yres > 1200)) {
+		FAIL("MACH64 chips are designed for max 1600x1200\n"
+		"select anoter resolution.");
+	}
+	h_sync_strt = h_disp + var->right_margin;
+	h_sync_end = h_sync_strt + var->hsync_len;
+	h_sync_dly  = var->right_margin & 7;
+	h_total = h_sync_end + h_sync_dly + var->left_margin;
+
+	v_sync_strt = v_disp + var->lower_margin;
+	v_sync_end = v_sync_strt + var->vsync_len;
+	v_total = v_sync_end + var->upper_margin;
+
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 	if (par->lcd_table != 0) {
-		u32 lcd_index = aty_ld_le32(LCD_INDEX, par);
-		lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par);
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    u32 lcd_index = aty_ld_le32(LCD_INDEX, par);
+		    crtc->lcd_index = lcd_index &
+			~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS);
+		    aty_st_le32(LCD_INDEX, lcd_index, par);
+		}
+		
+		if (!M64_HAS(MOBIL_BUS))
+			crtc->lcd_index |= CRTC2_DISPLAY_DIS;
 
-		if((lcd_on_off & LCD_ON) &&
+		crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par) | 0x4000;
+		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;
+
+		crtc->lcd_gen_cntl &=
+			~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN |
+			/*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/
+			USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+		crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT;
+	
+		if((crtc->lcd_gen_cntl & LCD_ON) &&
 			((xres > par->lcd_width) || (yres > par->lcd_height))) {
 			/* We cannot display the mode on the LCD. If the CRT is enabled
 			   we can turn off the LCD.
 			   If the CRT is off, it isn't a good idea to switch it on; we don't
 			   know if one is connected. So it's better to fail then.
 			 */
-			if (lcd_on_off & CRT_ON) {
-				printk(KERN_INFO "Disable lcd panel, because video mode does not fit.\n");
-				lcd_on_off &= ~LCD_ON;
-				aty_st_lcd(LCD_GEN_CNTL, lcd_on_off, par);
+			if (crtc->lcd_gen_cntl & CRT_ON) {
+				PRINTKI("Disable lcd panel, because video mode does not fit.\n");
+				crtc->lcd_gen_cntl &= ~LCD_ON;
+				/*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/
 			} else {
 				FAIL("Video mode exceeds size of lcd panel.\nConnect this computer to a conventional monitor if you really need this mode.");
 			}
 		}
-		aty_st_le32(LCD_INDEX, lcd_index, par);
 	}
 
-	if ((par->lcd_table != 0) && (lcd_on_off & LCD_ON)) {
+	if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) {
+		int VScan = 1;
 		/* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5
 		const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 };
 		const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 };  */
@@ -784,24 +870,9 @@
 		v_sync_strt = v_disp + par->lcd_lower_margin / VScan;
 		v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan;
 		v_total = v_disp + par->lcd_vblank_len / VScan;
-	} else {
+	}
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
-		if((xres > 1600) || (yres > 1200)) {
-		    FAIL("MACH64 chips are designed for max 1600x1200\n"
-			"select anoter resolution.");
-		}
-		h_sync_strt = h_disp + var->right_margin;
-		h_sync_end = h_sync_strt + var->hsync_len;
-		h_sync_dly  = var->right_margin & 7;
-		h_total = h_sync_end + h_sync_dly + var->left_margin;
-
-		v_sync_strt = v_disp + var->lower_margin;
-		v_sync_end = v_sync_strt + var->vsync_len;
-		v_total = v_sync_end + var->upper_margin;
 
-#ifdef CONFIG_FB_ATY_GENERIC_LCD
-	}
-#endif
 	h_disp = (h_disp >> 3) - 1;
 	h_sync_strt = (h_sync_strt >> 3) - 1;
 	h_sync_end = (h_sync_end >> 3) - 1;
@@ -810,7 +881,9 @@
 
 	FAIL_MAX("h_disp too large", h_disp, 0xff);
 	FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff);
-	FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);
+	/*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/
+	if(h_sync_wid > 0x1f)
+		h_sync_wid = 0x1f;
 	FAIL_MAX("h_total too large", h_total, 0x1ff);
 
 	if (vmode & FB_VMODE_DOUBLE) {
@@ -820,26 +893,24 @@
 		v_total <<= 1;
 	}
 
-	if(1) {
-		int VDisplay = yres;
+	vdisplay = yres;
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-		if ((par->lcd_table != 0) && (lcd_on_off & LCD_ON))
-			VDisplay  = par->lcd_height;
+	if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON))
+		vdisplay  = par->lcd_height;
 #endif
 
-		if(VDisplay < 400) {
-			h_sync_pol = 1;
-			v_sync_pol = 0;
-		} else if(VDisplay < 480) {
-			h_sync_pol = 0;
-			v_sync_pol = 1;
-		} else if(VDisplay < 768) {
-			h_sync_pol = 0;
-			v_sync_pol = 0;
-		} else {
-			h_sync_pol = 1;
-			v_sync_pol = 1;
-		}
+	if(vdisplay < 400) {
+		h_sync_pol = 1;
+		v_sync_pol = 0;
+	} else if(vdisplay < 480) {
+		h_sync_pol = 0;
+		v_sync_pol = 1;
+	} else if(vdisplay < 768) {
+		h_sync_pol = 0;
+		v_sync_pol = 0;
+	} else {
+		h_sync_pol = 1;
+		v_sync_pol = 1;
 	}
 
 	v_disp--;
@@ -850,7 +921,9 @@
 
 	FAIL_MAX("v_disp too large", v_disp, 0x7ff);
 	FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff);
-	FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);
+	/*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/
+	if(v_sync_wid > 0x1f)
+		v_sync_wid = 0x1f;
 	FAIL_MAX("v_total too large", v_total, 0x7ff);
 
 	c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
@@ -881,12 +954,12 @@
 	if (vmode & FB_VMODE_INTERLACED)
 		crtc->gen_cntl |= CRTC_INTERLACE_EN;
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-	if ((par->lcd_table != 0) && (lcd_on_off & LCD_ON)) {
-		int VDisplay = yres;
+	if (par->lcd_table != 0) {
+		vdisplay = yres;
 		if(vmode & FB_VMODE_DOUBLE)
-			VDisplay <<= 1;
+			vdisplay <<= 1;
 		if(vmode & FB_VMODE_INTERLACED) {
-			VDisplay >>= 1;
+			vdisplay >>= 1;
 
 			/* The prefered mode for the lcd is not interlaced, so disable it if
 			   it was enabled. For doublescan there is no problem, because we can
@@ -896,14 +969,16 @@
 			/*crtc->gen_cntl &= ~CRTC_INTERLACE_EN;*/
 		}
 		crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
-/*
-		crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | SCLK_SEL | USE_SHADOWED_VEND | SHADOW_EN);
-		crtc->lcd_gen_cntl |= (DONT_SHADOW_VPAR);
-*/
+		crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 |
+			/*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/
+			USE_SHADOWED_VEND | USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+		crtc->lcd_gen_cntl |= (DONT_SHADOW_VPAR/* | LOCK_8DOT*/);
+
 		/* MOBILITY M1 tested, FIXME: LT */
 		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
-		crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &
-			~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
+		if (!M64_HAS(LT_LCD_REGS))
+			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &
+				~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
 
 		crtc->horz_stretching &=
 			~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |
@@ -970,11 +1045,12 @@
 			} while (0);
 		}
 
-		if (VDisplay < par->lcd_height) {
+		if (vdisplay < par->lcd_height) {
 			crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN |
-				(((VDisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));
+				(((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));
 
-			if (xres <= (M64_HAS(MOBIL_BUS)?1024:800))
+			if (!M64_HAS(LT_LCD_REGS) &&
+			    xres <= (M64_HAS(MOBIL_BUS)?1024:800))
 				crtc->ext_vert_stretch |= VERT_STRETCH_MODE;
 		} else {
 			/*
@@ -983,13 +1059,12 @@
 			 */
 			crtc->vert_stretching = 0;
 		}
+		/* copy to shadow crtc */
+		crtc->shadow_h_tot_disp = crtc->h_tot_disp;
+		crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;
+		crtc->shadow_v_tot_disp = crtc->v_tot_disp;
+		crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;
 	}
-
-	/* copy to shadow crtc */
-	crtc->shadow_h_tot_disp = crtc->h_tot_disp;
-	crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;
-	crtc->shadow_v_tot_disp = crtc->v_tot_disp;
-	crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 
 	if (M64_HAS(MAGIC_FIFO)) {
@@ -1078,7 +1153,6 @@
 		var->transp.offset = 0;
 		var->transp.length = 0;
 		break;
-#if 0
 	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
 		bpp = 16;
 		var->red.offset = 11;
@@ -1090,7 +1164,6 @@
 		var->transp.offset = 0;
 		var->transp.length = 0;
 		break;
-#endif
 	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */
 		bpp = 24;
 		var->red.offset = 16;
@@ -1183,7 +1256,6 @@
 		wait_for_idle(par);
 
 	aty_set_crtc(par, &par->crtc);
-
 	par->dac_ops->set_dac(info, &par->pll, var->bits_per_pixel, par->accel_flags);
 	par->pll_ops->set_pll(info, &par->pll);
 
@@ -1194,7 +1266,7 @@
 		pixclock_in_ps = 0;
 
 	if(0 == pixclock_in_ps) {
-		printk(KERN_CRIT "ALERT ops->pll_to_var get 0\n");
+		PRINTKE("ALERT ops->pll_to_var get 0\n");
 		pixclock_in_ps = pixclock;
 	}
 
@@ -1220,23 +1292,23 @@
         	if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
             	vRefresh /= 2;
 
-		printk("atyfb: atyfb_set_par\n");
-		printk(" Set Visible Mode to %ix%i-%i\n", var->xres, var->yres, var->bits_per_pixel);
-		printk(" Virtual resolution %ix%i, pixclock_in_ps %i (calculated %i)\n",
+		DPRINTK("atyfb_set_par\n");
+		DPRINTK(" Set Visible Mode to %ix%i-%i\n", var->xres, var->yres, var->bits_per_pixel);
+		DPRINTK(" Virtual resolution %ix%i, pixclock_in_ps %i (calculated %i)\n",
 			var->xres_virtual, var->yres_virtual, pixclock, pixclock_in_ps);
-		printk(" Dot clock:           %i MHz\n", 1000000 / pixclock_in_ps);
-		printk(" Horizontal sync:     %i kHz\n", hSync);
-		printk(" Vertical refresh:    %i Hz\n", vRefresh);
-		printk(" x  style: %i.%03i %i %i %i %i   %i %i %i %i\n",
+		DPRINTK(" Dot clock:           %i MHz\n", 1000000 / pixclock_in_ps);
+		DPRINTK(" Horizontal sync:     %i kHz\n", hSync);
+		DPRINTK(" Vertical refresh:    %i Hz\n", vRefresh);
+		DPRINTK(" x  style: %i.%03i %i %i %i %i   %i %i %i %i\n",
 			1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps,
 			h_disp, h_sync_strt, h_sync_end, h_total,
 			v_disp, v_sync_strt, v_sync_end, v_total);
-		printk( " fb style:%i  %i %i %i %i %i %i %i %i\n",
+		DPRINTK(" fb style: %i  %i %i %i %i %i %i %i %i\n",
 			pixclock_in_ps,
 			debug.left_margin, h_disp, debug.right_margin, debug.hsync_len,
 			debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len);
 	}
-#endif
+#endif /* DEBUG */
 
 	if (!M64_HAS(INTEGRATED)) {
 		/* Don't forget MEM_CNTL */
@@ -1315,9 +1387,9 @@
 
 	/* CRTC registers */
 	base = 0x2000;
-	printk("Mach64 non-shadow register values:");
+	printk("debug atyfb: Mach64 non-shadow register values:");
 	for (i = 0; i < 256; i = i+4) {
-		if(i%16 == 0) printk("\n0x%04X: ", base + i);
+		if(i%16 == 0) printk("\ndebug atyfb: 0x%04X: ", base + i);
 		printk(" %08X", aty_ld_le32(i, par));
 	}
 	printk("\n\n");
@@ -1325,9 +1397,9 @@
 #ifdef CONFIG_FB_ATY_CT	
 	/* PLL registers */
 	base = 0x00;
-	printk("Mach64 PLL register values:");
+	printk("debug atyfb: Mach64 PLL register values:");
 	for (i = 0; i < 64; i++) {
-		if(i%16 == 0) printk("\n0x%02X: ", base + i);
+		if(i%16 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
 		if(i%4 == 0)  printk(" ");
 		printk("%02X", aty_ld_pll_ct(i, par));
 	}
@@ -1338,10 +1410,20 @@
 	if (par->lcd_table != 0) {
 		/* LCD registers */
 		base = 0x00;
-		printk("LCD register values:");
-		for (i = 0; i < 64; i++) {
-			if(i%4 == 0) printk("\n0x%02X: ", base + i);
+		printk("debug atyfb: LCD register values:");
+		if(M64_HAS(LT_LCD_REGS)) {
+		    for(i = 0; i <= POWER_MANAGEMENT; i++) {
+			if(i == EXT_VERT_STRETCH)
+			    continue;
+			printk("\ndebug atyfb: 0x%04X: ", lt_lcd_regs[i]);
+			printk(" %08X", aty_ld_lcd(i, par));
+		    }
+		    
+		} else {
+		    for (i = 0; i < 64; i++) {
+			if(i%4 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
 			printk(" %08X", aty_ld_lcd(i, par));
+		    }
 		}
 		printk("\n\n");
 	}
@@ -1395,7 +1477,6 @@
 	u32 bpp = info->var.bits_per_pixel;
 
 	par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
-	aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
 }
 
 
@@ -1405,26 +1486,103 @@
 
 static int atyfb_open(struct fb_info *info, int user)
 {
-#ifdef __sparc__
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 
 	if (user) {
 		par->open++;
+#ifdef __sparc__
 		par->mmaped = 0;
-	}
 #endif
+	}
 	return (0);
 }
 
+static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct atyfb_par *par = dev_id;
+	int handled = 0;
+	u32 int_cntl;
+
+	spin_lock(&par->int_lock);
+
+	int_cntl = aty_ld_le32(CRTC_INT_CNTL, par);
+
+	if (int_cntl & CRTC_VBLANK_INT) {
+		/* clear interrupt */
+		aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | CRTC_VBLANK_INT_AK, par);
+		par->vblank.count++;
+		if (par->vblank.pan_display) {
+			par->vblank.pan_display = 0;
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+		}
+		wake_up_interruptible(&par->vblank.wait);
+		handled = 1;
+	}
+
+	spin_unlock(&par->int_lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+static int aty_enable_irq(struct atyfb_par *par, int reenable)
+{
+	u32 int_cntl;
+
+	if (!test_and_set_bit(0, &par->irq_flags)) {
+		if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) {
+			clear_bit(0, &par->irq_flags);
+			return -EINVAL;
+		}
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		/* clear interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par);
+		/* enable interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par);
+		spin_unlock_irq(&par->int_lock);
+	} else if (reenable) {
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		if (!(int_cntl & CRTC_VBLANK_INT_EN)) {
+			printk("atyfb: someone disabled IRQ [%08x]\n", int_cntl);
+			/* re-enable interrupt */
+			aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par );
+		}
+		spin_unlock_irq(&par->int_lock);
+	}
+
+	return 0;
+}
+
+static int aty_disable_irq(struct atyfb_par *par)
+{
+	u32 int_cntl;
+
+	if (test_and_clear_bit(0, &par->irq_flags)) {
+		if (par->vblank.pan_display) {
+			par->vblank.pan_display = 0;
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+		}
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		/* disable interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par );
+		spin_unlock_irq(&par->int_lock);
+		free_irq(par->irq, par);
+	}
+
+	return 0;
+}
+
 static int atyfb_release(struct fb_info *info, int user)
 {
-#ifdef __sparc__
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	if (user) {
 		par->open--;
 		mdelay(1);
 		wait_for_idle(par);
 		if (!par->open) {
+#ifdef __sparc__
 			int was_mmaped = par->mmaped;
 
 			par->mmaped = 0;
@@ -1443,15 +1601,16 @@
 				else
 					var.accel_flags |= FB_ACCELF_TEXT;
 				if (var.yres == var.yres_virtual) {
-					u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2));
-					var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual;
+					u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+					var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
 					if (var.yres_virtual < var.yres)
 						var.yres_virtual = var.yres;
 				}
 			}
+#endif
+			aty_disable_irq(par);
 		}
 	}
-#endif
 	return (0);
 }
 
@@ -1478,10 +1637,50 @@
 	info->var.yoffset = yoffset;
 	if (par->asleep)
 		return 0;
+
 	set_off_pitch(par, info);
+	if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) {
+		par->vblank.pan_display = 1;
+	} else {
+		par->vblank.pan_display = 0;
+		aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+	}
+
 	return 0;
 }
 
+static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)
+{
+	struct aty_interrupt *vbl;
+	unsigned int count;
+	int ret;
+
+	switch (crtc) {
+	case 0:
+		vbl = &par->vblank;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ret = aty_enable_irq(par, 0);
+	if (ret)
+		return ret;
+
+	count = vbl->count;
+	ret = wait_event_interruptible_timeout(vbl->wait, count != vbl->count, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		aty_enable_irq(par, 1);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+
 #ifdef DEBUG
 #define ATYIO_CLKR		0x41545900	/* ATY\00 */
 #define ATYIO_CLKW		0x41545901	/* ATY\01 */
@@ -1506,12 +1705,14 @@
 #define ATYIO_FEATW		0x41545903	/* ATY\03 */
 #endif
 
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+#endif
+
 static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 	u_long arg, struct fb_info *info)
 {
-#if defined(__sparc__) || (defined(DEBUG) && defined(CONFIG_FB_ATY_CT))
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
-#endif /* __sparc__ || DEBUG */
 #ifdef __sparc__
 	struct fbtype fbtyp;
 #endif
@@ -1529,6 +1730,18 @@
 			return -EFAULT;
 		break;
 #endif /* __sparc__ */
+
+	case FBIO_WAITFORVSYNC:
+		{
+			u32 crtc;
+
+			if (get_user(crtc, (__u32 *) arg))
+				return -EFAULT;
+
+			return aty_waitforvblank(par, crtc);
+		}
+		break;
+
 #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
 	case ATYIO_CLKR:
 		if (M64_HAS(INTEGRATED)) {
@@ -1725,6 +1938,7 @@
 				info->var.yoffset = atyfb_save.yoffset;
 				set_off_pitch(par, info);
 			}
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
 			break;
 		}
 	}
@@ -1736,69 +1950,10 @@
 #if defined(CONFIG_PM) && defined(CONFIG_PCI)
 
 /* Power management routines. Those are used for PowerBook sleep.
- *
- * It appears that Rage LT and Rage LT Pro have different power
- * management registers. There's is some confusion about which
- * chipID is a Rage LT or LT pro :(
  */
-static int aty_power_mgmt_LT(int sleep, struct atyfb_par *par)
-{
-	unsigned int pm;
-	int timeout;
-
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
-	aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-
-	timeout = 200000;
-	if (sleep) {
-		/* Sleep */
-		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-		udelay(10);
-		pm &= ~(PWR_BLON | AUTO_PWR_UP);
-		pm |= SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-			udelay(10);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
-	} else {
-		/* Wakeup */
-		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-		udelay(10);
-		pm |= (PWR_BLON | AUTO_PWR_UP);
-		pm &= ~SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
-		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-			udelay(10);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
-	}
-	mdelay(500);
-
-	return timeout ? -1 : 0;
-}
-
-static int aty_power_mgmt_LTPro(int sleep, struct atyfb_par *par)
+static int aty_power_mgmt(int sleep, struct atyfb_par *par)
 {
-	unsigned int pm;
+	u32 pm;
 	int timeout;
 
 	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -1806,7 +1961,7 @@
 	aty_st_lcd(POWER_MANAGEMENT, pm, par);
 	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
 
-	timeout = 200;
+	timeout = 2000;
 	if (sleep) {
 		/* Sleep */
 		pm &= ~PWR_MGT_ON;
@@ -1846,16 +2001,11 @@
 				break;
 		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
 	}
+	mdelay(500);
 
 	return timeout ? -1 : 0;
 }
 
-static int aty_power_mgmt(int sleep, struct atyfb_par *par)
-{
-	return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, par)
-	    : aty_power_mgmt_LTPro(sleep, par);
-}
-
 static int atyfb_pci_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
@@ -1990,7 +2140,7 @@
 	const int *refresh_tbl;
 	int i, size;
 
-	if (IS_XL(par->pci_id)) {
+	if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
 		refresh_tbl = ragexl_tbl;
 		size = sizeof(ragexl_tbl)/sizeof(int);
 	} else {
@@ -2023,15 +2173,18 @@
 	int sense;
 #endif
 
+	init_waitqueue_head(&par->vblank.wait);
+	spin_lock_init(&par->int_lock);
+
 	par->aty_cmap_regs =
 	    (struct aty_cmap_regs *) (par->ati_regbase + 0xc0);
 
-	if (default_pll)
-		par->pll_limits.pll_max = default_pll;
-	if (default_mclk)
-		par->pll_limits.mclk = default_mclk;
-	if (default_xclk)
-		par->pll_limits.xclk = default_xclk;
+	if (pll)
+		par->pll_limits.pll_max = pll;
+	if (mclk)
+		par->pll_limits.mclk = mclk;
+	if (xclk)
+		par->pll_limits.xclk = xclk;
 
 	aty_calc_mem_refresh(par, par->pll_limits.xclk);
 	par->pll_per = 1000000/par->pll_limits.pll_max;
@@ -2076,7 +2229,7 @@
 			par->dac_ops = &aty_dac_att21c498;
 			break;
 		default:
-			printk(" aty_init: DAC type not implemented yet!\n");
+			PRINTKI("aty_init: DAC type not implemented yet!\n");
 			par->dac_ops = &aty_dac_unsupported;
 			break;
 		}
@@ -2097,7 +2250,7 @@
 			par->pll_ops = &aty_pll_ibm514;
 			break;
 		default:
-			printk(" aty_init: CLK type not implemented yet!");
+			PRINTKI("aty_init: CLK type not implemented yet!");
 			par->pll_ops = &aty_pll_unsupported;
 			break;
 		}
@@ -2131,11 +2284,12 @@
 		}
 	}
 #endif /* CONFIG_FB_ATY_CT */
-#if 0
+
+	/* save previous video mode */
 	aty_get_crtc(par, &saved_crtc);
 	if(par->pll_ops->get_pll)
 		par->pll_ops->get_pll(info, &saved_pll);
-#endif
+
 	i = aty_ld_le32(MEM_CNTL, par);
 	gtb_memsize = M64_HAS(GTB_DSP);
 	if (gtb_memsize)
@@ -2189,8 +2343,8 @@
 			info->fix.smem_len += 0x400000;
 	}
 
-	if (default_vram) {
-		info->fix.smem_len = default_vram * 1024;
+	if (vram) {
+		info->fix.smem_len = vram * 1024;
 		i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
 		if (info->fix.smem_len <= 0x80000)
 			i |= MEM_SIZE_512K;
@@ -2218,16 +2372,16 @@
 		info->fix.mmio_len = 0x400;
 		info->fix.accel = FB_ACCEL_ATI_MACH64CT;
 	} else if (M64_HAS(VT)) {
-		info->fix.mmio_start = -0x400;
+		info->fix.mmio_start -= 0x400;
 		info->fix.mmio_len = 0x800;
 		info->fix.accel = FB_ACCEL_ATI_MACH64VT;
 	} else {/* GT */
-		info->fix.mmio_start = -0x400;
+		info->fix.mmio_start -= 0x400;
 		info->fix.mmio_len = 0x800;
 		info->fix.accel = FB_ACCEL_ATI_MACH64GT;
 	}
 
-	printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
+	PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
 	       info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len >> 20),
 	       info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, par->pll_limits.pll_max,
 	       par->pll_limits.mclk, par->pll_limits.xclk);
@@ -2235,10 +2389,10 @@
 #if defined(DEBUG) && defined(CONFIG_ATY_CT)
 	if (M64_HAS(INTEGRATED)) {
 		int i;
-		printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
+		printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
 		       "DSP_CONFIG DSP_ON_OFF CLOCK_CNTL\n"
-		       "%08x %08x %08x %08x     %08x      %08x   %08x   %08x\n"
-		       "PLL",
+		       "debug atyfb: %08x %08x %08x %08x     %08x      %08x   %08x   %08x\n"
+		       "debug atyfb: PLL",
 			aty_ld_le32(BUS_CNTL, par), aty_ld_le32(DAC_CNTL, par),
 			aty_ld_le32(MEM_CNTL, par), aty_ld_le32(EXT_MEM_CNTL, par),
 			aty_ld_le32(CRTC_GEN_CNTL, par), aty_ld_le32(DSP_CONFIG, par),
@@ -2292,8 +2446,8 @@
 		 *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
 		 *         applies to all Mac video cards
 		 */
-		if (mode_option) {
-			if (!mac_find_mode(&var, info, mode_option, 8))
+		if (mode) {
+			if (!mac_find_mode(&var, info, mode, 8))
 				var = default_var;
 		} else {
 			if (default_vmode == VMODE_CHOOSE) {
@@ -2309,7 +2463,7 @@
 				else
 					default_vmode = VMODE_640_480_67;
 				sense = read_aty_sense(par);
-				printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n",
+				PRINTKI("monitor sense=%x, mode %d\n",
 					sense,  mac_map_monitor_sense(sense));
 			}
 			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
@@ -2321,7 +2475,7 @@
 		}
 	} else
 #endif /* !CONFIG_PPC */
-	if (!fb_find_mode(&var, info, mode_option, NULL, 0, &defmode, 8))
+	if (!fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8))
 		var = default_var;
 
 	if (noaccel)
@@ -2330,15 +2484,15 @@
 		var.accel_flags |= FB_ACCELF_TEXT;
 
 	if (var.yres == var.yres_virtual) {
-		u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2));
-		var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual;
+		u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+		var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
 		if (var.yres_virtual < var.yres)
 			var.yres_virtual = var.yres;
 	}
 
 	if (atyfb_check_var(&var, info)) {
-		printk(KERN_CRIT "atyfb: can't set default video mode\n");
-		return 0;
+		PRINTKE("can't set default video mode\n");
+		goto aty_init_exit;
 	}
 
 #ifdef __sparc__
@@ -2346,7 +2500,7 @@
 #endif
 
 #ifdef CONFIG_FB_ATY_CT
-	if (M64_HAS(INTEGRATED))
+	if (!noaccel && M64_HAS(INTEGRATED))
 		aty_init_cursor(info);
 #endif /* CONFIG_FB_ATY_CT */
 	info->var = var;
@@ -2354,85 +2508,21 @@
 	fb_alloc_cmap(&info->cmap, 256, 0);
 
 	if (register_framebuffer(info) < 0)
-		return 0;
+		goto aty_init_exit;
 
 	fb_list = info;
 
-	printk("fb%d: %s frame buffer device on %s\n",
+	PRINTKI("fb%d: %s frame buffer device on %s\n",
 	       info->node, info->fix.id, name);
 	return 1;
-}
-
-#ifndef MODULE
-int __init atyfb_setup(char *options)
-{
-	char *this_opt;
-
-	if (!options || !*options)
-		return 0;
+	
+aty_init_exit:
+	/* restore video mode */
+	aty_set_crtc(par, &saved_crtc);
+	par->pll_ops->set_pll(info, &saved_pll);
 
-	while ((this_opt = strsep(&options, ",")) != NULL) {
-		if (!strncmp(this_opt, "noaccel", 7)) {
-			noaccel = 1;
-		} else if (!strncmp(this_opt, "vram:", 5))
-			default_vram =
-			    simple_strtoul(this_opt + 5, NULL, 0);
-		else if (!strncmp(this_opt, "pll:", 4))
-			default_pll =
-			    simple_strtoul(this_opt + 4, NULL, 0);
-		else if (!strncmp(this_opt, "mclk:", 5))
-			default_mclk =
-			    simple_strtoul(this_opt + 5, NULL, 0);
-		else if (!strncmp(this_opt, "xclk:", 5))
-			default_xclk =
-			simple_strtoul(this_opt+5, NULL, 0);
-#ifdef CONFIG_PPC
-		else if (!strncmp(this_opt, "vmode:", 6)) {
-			unsigned int vmode =
-			    simple_strtoul(this_opt + 6, NULL, 0);
-			if (vmode > 0 && vmode <= VMODE_MAX)
-				default_vmode = vmode;
-		} else if (!strncmp(this_opt, "cmode:", 6)) {
-			unsigned int cmode =
-			    simple_strtoul(this_opt + 6, NULL, 0);
-			switch (cmode) {
-			case 0:
-			case 8:
-				default_cmode = CMODE_8;
-				break;
-			case 15:
-			case 16:
-				default_cmode = CMODE_16;
-				break;
-			case 24:
-			case 32:
-				default_cmode = CMODE_32;
-				break;
-			}
-		}
-#endif
-#ifdef CONFIG_ATARI
-		/*
-		 * Why do we need this silly Mach64 argument?
-		 * We are already here because of mach64= so its redundant.
-		 */
-		else if (MACH_IS_ATARI
-			 && (!strncmp(this_opt, "Mach64:", 7))) {
-			static unsigned char m64_num;
-			static char mach64_str[80];
-			strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str));
-			if (!store_video_par(mach64_str, m64_num)) {
-				m64_num++;
-				mach64_count = m64_num;
-			}
-		}
-#endif
-		else
-			mode_option = this_opt;
-	}
 	return 0;
 }
-#endif /* !MODULE */
 
 #ifdef CONFIG_ATARI
 static int __init store_video_par(char *video_str, unsigned char m64_num)
@@ -2440,7 +2530,7 @@
 	char *p;
 	unsigned long vmembase, size, guiregbase;
 
-	printk("store_video_par() '%s' \n", video_str);
+	PRINTKI("store_video_par() '%s' \n", video_str);
 
 	if (!(p = strsep(&video_str, ";")) || !*p)
 		goto mach64_invalid;
@@ -2455,7 +2545,7 @@
 	phys_vmembase[m64_num] = vmembase;
 	phys_size[m64_num] = size;
 	phys_guiregbase[m64_num] = guiregbase;
-	printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
+	PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
 	       guiregbase);
 	return 0;
 
@@ -2480,7 +2570,14 @@
 #ifdef CONFIG_PMAC_BACKLIGHT
 	if ((_machine == _MACH_Pmac) && blank)
 		set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+	if (par->lcd_table && blank &&
+	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		pm &= ~PWR_BLON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	}
+#endif
 
 	gen_cntl = aty_ld_8(CRTC_GEN_CNTL, par);
 	if (blank > 0)
@@ -2504,52 +2601,76 @@
 #ifdef CONFIG_PMAC_BACKLIGHT
 	if ((_machine == _MACH_Pmac) && !blank)
 		set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+	if (par->lcd_table && !blank &&
+	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		pm |= PWR_BLON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	}
+#endif
+
 	return 0;
 }
 
+static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+		       const struct atyfb_par *par)
+{
+#ifdef CONFIG_ATARI
+	out_8(&par->aty_cmap_regs->windex, regno);
+	out_8(&par->aty_cmap_regs->lut, red);
+	out_8(&par->aty_cmap_regs->lut, green);
+	out_8(&par->aty_cmap_regs->lut, blue);
+#else
+	writeb(regno, &par->aty_cmap_regs->windex);
+	writeb(red, &par->aty_cmap_regs->lut);
+	writeb(green, &par->aty_cmap_regs->lut);
+	writeb(blue, &par->aty_cmap_regs->lut);
+#endif
+}
+
     /*
      *  Set a single color register. The values supplied are already
      *  rounded down to the hardware's capabilities (according to the
      *  entries in the var structure). Return != 0 for invalid regno.
+     *  !! 4 & 8 =  PSEUDO, > 8 = DIRECTCOLOR
      */
 
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 	u_int transp, struct fb_info *info)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
-	int i, scale;
+	int i, depth;
 	u32 *pal = info->pseudo_palette;
 
+	depth = info->var.bits_per_pixel;
+	if (depth == 16)
+		depth = (info->var.green.length == 5) ? 15 : 16;
+
 	if (par->asleep)
 		return 0;
-	if (regno > 255)
+
+	if (regno > 255 ||
+	    (depth == 16 && regno > 63) ||
+	    (depth == 15 && regno > 31))
 		return 1;
+
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;
-	i = aty_ld_8(DAC_CNTL, par) & 0xfc;
-	if (M64_HAS(EXTRA_BRIGHT))
-		i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */
-	aty_st_8(DAC_CNTL, i, par);
-	aty_st_8(DAC_MASK, 0xff, par);
-	scale = (M64_HAS(INTEGRATED) && info->var.bits_per_pixel == 16) ? 3 : 0;
-#ifdef CONFIG_ATARI
-	out_8(&par->aty_cmap_regs->windex, regno << scale);
-	out_8(&par->aty_cmap_regs->lut, red);
-	out_8(&par->aty_cmap_regs->lut, green);
-	out_8(&par->aty_cmap_regs->lut, blue);
-#else
-	writeb(regno << scale, &par->aty_cmap_regs->windex);
-	writeb(red, &par->aty_cmap_regs->lut);
-	writeb(green, &par->aty_cmap_regs->lut);
-	writeb(blue, &par->aty_cmap_regs->lut);
-#endif
-	if (regno < 16)
-		switch (info->var.bits_per_pixel) {
-		case 16:
+
+	par->palette[regno].red = red;
+	par->palette[regno].green = green;
+	par->palette[regno].blue = blue;
+
+	if (regno < 16) {
+		switch (depth) {
+		case 15:
 			pal[regno] = (regno << 10) | (regno << 5) | regno;
 			break;
+		case 16:
+			pal[regno] = (regno << 11) | (regno << 5) | regno;
+			break;
 		case 24:
 			pal[regno] = (regno << 16) | (regno << 8) | regno;
 			break;
@@ -2558,6 +2679,32 @@
 			pal[regno] = (i << 16) | i;
 			break;
 		}
+	}
+
+	i = aty_ld_8(DAC_CNTL, par) & 0xfc;
+	if (M64_HAS(EXTRA_BRIGHT))
+		i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */
+	aty_st_8(DAC_CNTL, i, par);
+	aty_st_8(DAC_MASK, 0xff, par);
+
+	if (M64_HAS(INTEGRATED)) {
+		if (depth == 16) {
+			if (regno < 32)
+				aty_st_pal(regno << 3, red,
+					   par->palette[regno<<1].green,
+					   blue, par);
+			red = par->palette[regno>>1].red;
+			blue = par->palette[regno>>1].blue;
+			regno <<= 2;
+		} else if (depth == 15) {
+			regno <<= 3;
+			for(i = 0; i < 8; i++) {
+			    aty_st_pal(regno + i, red, green, blue, par);
+			}
+		}
+	}
+	aty_st_pal(regno, red, green, blue, par);
+
 	return 0;
 }
 
@@ -2573,7 +2720,7 @@
 	struct atyfb_par *par = info->par;
 	struct pcidev_cookie *pcp;
 	char prop[128];
-	int node, len, i, j;
+	int node, len, i, j, ret;
 	u32 mem, chip_id;
 
 	/* Do not attach when we have a serial console. */
@@ -2602,7 +2749,7 @@
 
 	par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
 	if (!_par->mmap_map) {
-		printk(KERN_ERR "atyfb_init: can't alloc mmap_map\n");
+		PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
 		return -ENOMEM;
 	}
 	memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
@@ -2661,7 +2808,8 @@
 		j++;
 	}
 	
-	correct_chipset(par);
+	if((ret = correct_chipset(par)))
+		return ret;
 
 	if (IS_XL(pdev->device)) {
 		/*
@@ -2735,7 +2883,7 @@
 		 * Read the PLL to figure actual Refresh Rate.
 		 */
 		clock_cntl = aty_ld_8(CLOCK_CNTL, par);
-		/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
+		/* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */
 		for (i = 0; i < 16; i++)
 			pll_regs[i] = aty_ld_pll_ct(i, par);
 
@@ -2783,6 +2931,7 @@
 
 #else /* __sparc__ */
 
+#ifdef __i386__
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
 {
@@ -2805,7 +2954,7 @@
 		(sig == 0x544d5224) || /* Rage mobility */
 		(sig == 0x54435824) || /* Rage XC */
 		(sig == 0x544c5824)) { /* Rage XL */
-		printk(KERN_INFO "atyfb: BIOS contains driver information table.\n");
+		PRINTKI("BIOS contains driver information table.\n");
 		lcd_ofs = (*(u16 *)(driv_inf_tab + 10));
 		par->lcd_table = 0;
 		if (lcd_ofs != 0) {
@@ -2904,8 +3053,10 @@
 				txtformat = "unkown format";
 			}
 		}
-		printk(KERN_INFO "atyfb: %s%s %s monitor detected: %s\n        id=%d, %dx%d pixels, %s\n",
-			txtdual ,txtcolour, txtmonitor, model, id, width, height, txtformat);
+		PRINTKI("%s%s %s monitor detected: %s\n",
+			txtdual ,txtcolour, txtmonitor, model);
+		PRINTKI("       id=%d, %dx%d pixels, %s\n",
+			id, width, height, txtformat);
 		refresh_rates_buf[0] = 0;
 		refresh_rates = *(u16 *)(par->lcd_table+62);
 		m = 1;
@@ -2923,7 +3074,7 @@
 			m = m << 1;
 		}
 		default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;
-		printk(KERN_INFO "        supports refresh rates [%s], default %d Hz\n",
+		PRINTKI("       supports refresh rates [%s], default %d Hz\n",
 			refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);
 		par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];
 		/* We now need to determine the crtc parameters for the
@@ -2978,10 +3129,10 @@
 			lcdmodeptr++;
 		}
 		if (*lcdmodeptr == 0) {
-			printk(KERN_WARNING "atyfb: LCD monitor CRTC parameters not found!!!\n");
+			PRINTKE("LCD monitor CRTC parameters not found!!!\n");
 			/* To do: Switch to CRT if possible. */
 		} else {
-			printk(KERN_INFO "        LCD CRTC parameters: %d.%d  %d %d %d %d  %d %d %d %d\n",
+			PRINTKI("       LCD CRTC parameters: %d.%d  %d %d %d %d  %d %d %d %d\n",
 				1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,
 				par->lcd_hdisp,
 				par->lcd_hdisp + par->lcd_right_margin,
@@ -2992,7 +3143,7 @@
 				par->lcd_vdisp + par->lcd_lower_margin,
 				par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,
 				par->lcd_vtotal);
-			printk(KERN_INFO "                           : %d %d %d %d %d %d %d %d %d\n",
+			PRINTKI("                          : %d %d %d %d %d %d %d %d %d\n",
 				par->lcd_pixclock,
 				par->lcd_hblank_len - (par->lcd_right_margin +
 					par->lcd_hsync_dly + par->lcd_hsync_len),
@@ -3023,7 +3174,7 @@
 		u16 rom_table_offset, freq_table_offset;
 		PLL_BLOCK_MACH64 pll_block;
 		
-		printk(KERN_INFO "atyfb: Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
+		PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
 
 		/* check for frequncy table */
 		bios_ptr = (u8*)bios_base;
@@ -3031,11 +3182,11 @@
 		freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);
 		memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));
 
-		printk(KERN_INFO "atyfb: BIOS frequency table:\n");
-		printk(KERN_INFO " PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
+		PRINTKI("BIOS frequency table:\n");
+		PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
 			pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,
 			pll_block.ref_freq, pll_block.ref_divider);
-		printk(KERN_INFO " MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
+		PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
 			pll_block.MCLK_pwd, pll_block.MCLK_max_freq,
 			pll_block.XCLK_max_freq, pll_block.SCLK_freq);
 
@@ -3052,13 +3203,14 @@
 #endif
 		ret = 0;
 	} else {
-		printk(KERN_CRIT "atyfb: no BIOS frequency table found, use parameters\n");
+		PRINTKE("no BIOS frequency table found, use parameters\n");
 		ret = -ENXIO;
 	}
 	iounmap((void*)bios_base);
 
 	return ret;
 }
+#endif /* __i386__ */
 
 static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, unsigned long addr)
 {
@@ -3066,6 +3218,7 @@
 	u16 tmp;
 	unsigned long raddr;
 	struct resource *rrp;
+	int ret = 0;
 
 	raddr = addr + 0x7ff000UL;
 	rrp = &pdev->resource[2];
@@ -3073,7 +3226,7 @@
 		par->aux_start = rrp->start;
 		par->aux_size = rrp->end - rrp->start + 1;
 		raddr = rrp->start;
-		printk(KERN_INFO "atyfb: using auxiliary register aperture\n");
+		PRINTKI("using auxiliary register aperture\n");
 	}
 
 	info->fix.mmio_start = raddr;
@@ -3102,16 +3255,16 @@
 	info->fix.smem_start = addr;
 	info->screen_base = (char *)ioremap(addr, 0x800000);
 	if (info->screen_base == NULL) {
-		iounmap((void *)par->ati_regbase);
-		par->ati_regbase = 0;
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto atyfb_setup_generic_fail;
 	}
 
-	/* always succeeded ? */
-	if (correct_chipset(par) < 0)
-		return -ENXIO;
-	init_from_bios(par);
-
+	if((ret = correct_chipset(par)))
+		goto atyfb_setup_generic_fail;
+#ifdef __i386__
+	if((ret = init_from_bios(par)))
+		goto atyfb_setup_generic_fail;
+#endif		
 	if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN))
 		par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2;
 	else
@@ -3121,16 +3274,21 @@
 	par->clk_wr_offset = 3;
 
 	return 0;
+	
+atyfb_setup_generic_fail:
+	iounmap((void *)par->ati_regbase);
+	par->ati_regbase = 0;
+	return ret;
 }
 
 #endif /* !__sparc__ */
 
 static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	unsigned long addr;
+	unsigned long addr, res_start, res_size;
 	struct fb_info *info;
 	struct resource *rp;
-	struct atyfb_par *par = info->par;
+	struct atyfb_par *par;
 	int i, rc = -ENOMEM;
 
 	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
@@ -3142,7 +3300,7 @@
 
 	/* Enable device in PCI config */
 	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR "atyfb: Cannot enable PCI device\n");
+		PRINTKE("Cannot enable PCI device\n");
 		return -ENXIO;
 	}
 
@@ -3154,23 +3312,24 @@
 	if (!addr)
 		return -ENXIO;
 
-	/* Allocate framebuffer */
+	/* Reserve space */
+	res_start = rp->start;
+	res_size = rp->end - rp->start + 1;
+	if (!request_mem_region (res_start, res_size, "atyfb"))
+		return -EBUSY;
+        
+        /* Allocate framebuffer */
 	info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);
 	if (!info) {
-		printk(KERN_ERR "atyfb_init: can't alloc fb_info\n");
+		PRINTKE("atyfb_pci_probe() can't alloc fb_info\n");
 		return -ENOMEM;
 	}
 	par = info->par;
 	info->fix = atyfb_fix;
 	par->pci_id = aty_chips[i].pci_id;
-
-	/* Reserve space */
-	par->res_start = rp->start;
-	par->res_size = rp->end - rp->start + 1;
-	if (!request_mem_region (par->res_start, par->res_size, "atyfb")) {
-		rc = -EBUSY;
-		goto err_free;
-	}
+	par->res_start = res_start;
+	par->res_size = res_size;
+	par->irq = pdev->irq;
 
 	/* Setup "info" structure */
 #ifdef __sparc__
@@ -3224,7 +3383,6 @@
 		release_mem_region(par->aux_start, par->aux_size);
 
 	release_mem_region(par->res_start, par->res_size);
-err_free:
 	framebuffer_release(info);
 
 	return rc;
@@ -3244,19 +3402,21 @@
 	for (m64_num = 0; m64_num < mach64_count; m64_num++) {
 		if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
 		    !phys_guiregbase[m64_num]) {
-			printk(" phys_*[%d] parameters not set => returning early. \n", m64_num);
+		    PRINTKI("phys_*[%d] parameters not set => returning early. \n", m64_num);
 			continue;
 		}
 
 		info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
 		if (!info) {
-			printk("atyfb_init: can't alloc fb_info\n");
+			PRINTKE("atyfb_atari_probe() can't alloc fb_info\n");
 			return -ENOMEM;
 		}
 		par = info->par;
 
 		info->fix = atyfb_fix;
 
+		par->irq = (unsigned int) -1; /* something invalid */
+
 		/*
 		 *  Map the video memory (physical address given) to somewhere in the
 		 *  kernel address space.
@@ -3298,6 +3458,10 @@
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 
+	/* restore video mode */
+	aty_set_crtc(par, &saved_crtc);
+	par->pll_ops->set_pll(info, &saved_pll);
+
 	unregister_framebuffer(info);
 
 #ifndef __sparc__
@@ -3375,4 +3539,93 @@
 #endif
 }
 
+int __init atyfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+		} else if (!strncmp(this_opt, "vram:", 5))
+			vram = simple_strtoul(this_opt + 5, NULL, 0);
+		else if (!strncmp(this_opt, "pll:", 4))
+			pll = simple_strtoul(this_opt + 4, NULL, 0);
+		else if (!strncmp(this_opt, "mclk:", 5))
+			mclk = simple_strtoul(this_opt + 5, NULL, 0);
+		else if (!strncmp(this_opt, "xclk:", 5))
+			xclk = simple_strtoul(this_opt+5, NULL, 0);
+#ifdef CONFIG_PPC
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			switch (cmode) {
+			case 0:
+			case 8:
+				default_cmode = CMODE_8;
+				break;
+			case 15:
+			case 16:
+				default_cmode = CMODE_16;
+				break;
+			case 24:
+			case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+		}
+#endif
+#ifdef CONFIG_ATARI
+		/*
+		 * Why do we need this silly Mach64 argument?
+		 * We are already here because of mach64= so its redundant.
+		 */
+		else if (MACH_IS_ATARI
+			 && (!strncmp(this_opt, "Mach64:", 7))) {
+			static unsigned char m64_num;
+			static char mach64_str[80];
+			strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str));
+			if (!store_video_par(mach64_str, m64_num)) {
+				m64_num++;
+				mach64_count = m64_num;
+			}
+		}
+#endif
+		else
+			mode = this_opt;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+module_init(atyfb_init);
+module_exit(atyfb_exit);
+#endif
+
+MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");
 MODULE_LICENSE("GPL");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "int: override size of video ram");
+module_param(pll, int, 0);
+MODULE_PARM_DESC(pll, "int: override video clock");
+module_param(mclk, int, 0);
+MODULE_PARM_DESC(mclk, "int: override memory clock");
+module_param(xclk, int, 0);
+MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");
+#ifdef CONFIG_PPC
+module_param(vmode, int, 0);
+MODULE_PARM_DESC(vmode, "int: video mode for mac");
+module_param(cmode, int, 0);
+MODULE_PARM_DESC(cmode, "int: color mode for mac");
+#endif
+module_param(mode, charp, 0);
+MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
diff -ur -X patches/exclude linux-2.6.7.js3/drivers/video/aty/mach64_ct.c linux-2.6.7.ak/drivers/video/aty/mach64_ct.c
--- linux-2.6.7.js3/drivers/video/aty/mach64_ct.c	2004-06-27 01:35:27.000000000 +0200
+++ linux-2.6.7.ak/drivers/video/aty/mach64_ct.c	2004-08-04 22:32:10.000000000 +0200
@@ -115,7 +115,6 @@
 
 static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
 {
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u32 dsp_off, dsp_on, dsp_xclks;
 	u32 multiplier, divider, ras_multiplier, ras_divider, tmp;
 	u8 vshift, xshift;
@@ -137,6 +136,8 @@
 
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 	if (pll->xres != 0) {
+		struct atyfb_par *par = (struct atyfb_par *) info->par;
+
 		multiplier = multiplier * par->lcd_width;
 		divider = divider * pll->xres & ~7;
 
@@ -281,8 +282,8 @@
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 	if (par->lcd_table != 0) {
 		/* turn off LCD */
-		lcd_gen_cntrl = aty_ld_le32(LCD_GEN_CNTL, par);
-		aty_st_le32(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
+		lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par);
+		aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
 	}
 #endif
 	aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par);
@@ -351,12 +352,12 @@
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 	if (par->lcd_table != 0) {
 		/* restore LCD */
-		aty_st_le32(LCD_GEN_CNTL, lcd_gen_cntrl, par);
+		aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par);
 	}
 #endif
 }
-#if 0
-void aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
+
+void __init aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u8 tmp, clock;
@@ -378,7 +379,7 @@
 		pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
 	}
 }
-#endif
+
 int __init aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll) {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
@@ -526,10 +527,10 @@
 		__FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
 #endif
 
-	pll->ct.pll_gen_cntl = OSC_EN;
-	
-	if (M64_HAS(NO_EXT_PLL))
-		pll->ct.pll_gen_cntl |= (DLL_PWDN | FORCE_DCLK_TRI_STATE);
+	if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
+		pll->ct.pll_gen_cntl = OSC_EN;
+	else
+		pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */;
 
 	if (M64_HAS(MAGIC_POSTDIV))
 		pll->ct.pll_ext_cntl = 0;
@@ -608,5 +609,6 @@
 	.var_to_pll	= aty_var_to_pll_ct,
 	.pll_to_var	= aty_pll_to_var_ct,
 	.set_pll	= aty_set_pll_ct,
+	.get_pll	= aty_get_pll_ct,
 	.init_pll       = aty_init_pll_ct
 };
diff -ur -X patches/exclude linux-2.6.7.js3/drivers/video/aty/mach64_cursor.c linux-2.6.7.ak/drivers/video/aty/mach64_cursor.c
--- linux-2.6.7.js3/drivers/video/aty/mach64_cursor.c	2004-06-27 01:35:27.000000000 +0200
+++ linux-2.6.7.ak/drivers/video/aty/mach64_cursor.c	2004-07-23 23:51:53.000000000 +0200
@@ -71,26 +71,6 @@
 	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
 };		
 
-void aty_set_cursor_shape(struct fb_info *info, u8 *dst, u8 *src, unsigned int width)
-{
-	int i, j, offset = info->sprite.scan_align - width*2;
-	u8 *mask = info->cursor.mask, m, b;
-
-	for (i = 0; i < info->cursor.image.height; i++) {
-		for (j = 0; j < width; j++) {
-			b = *src++;
-			m = *mask++;
-			// Upper 4 bits of mask data
-			fb_writeb(cursor_mask_lookup[m >> 4 ] |
-				  cursor_bits_lookup[(b & m) >> 4], dst++);
-			// Lower 4 bits of mask
-			fb_writeb(cursor_mask_lookup[m & 0x0f ] |
-				  cursor_bits_lookup[(b & m) & 0x0f], dst++);
-		}
-		dst += offset;
-	}
-}
-
 int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -176,9 +156,46 @@
 	}
 	
 	if (cursor->set & FB_CUR_SETSHAPE) {
-		// Clear cursor image with 1010101010... 
-		fb_memset(info->sprite.addr, 0xaa, 1024);
-		fb_load_cursor_image(info);
+	    u8 *src = (u8 *)cursor->image.data;
+	    u8 *msk = (u8 *)info->cursor.mask;
+	    u8 *dst = (u8 *)info->sprite.addr;
+	    unsigned int width = (info->cursor.image.width + 7) >> 3;
+	    unsigned int height = info->cursor.image.height;
+	    unsigned int align = info->sprite.scan_align;
+	    
+	    unsigned int i, j, offset;
+	    u8 m, b;
+
+	    // Clear cursor image with 1010101010... 
+	    fb_memset(dst, 0xaa, 1024);
+
+	    offset = align - width*2;
+
+	    for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j++) {
+			b = *src++;
+			m = *msk++;
+			switch (info->cursor.rop) {
+			case ROP_XOR:
+			    // Upper 4 bits of mask data
+			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
+				cursor_bits_lookup[(b ^ m) >> 4], dst++);
+			    // Lower 4 bits of mask
+			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+				cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+			    break;
+			case ROP_COPY:
+			    // Upper 4 bits of mask data
+			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
+				cursor_bits_lookup[(b & m) >> 4], dst++);
+			    // Lower 4 bits of mask
+			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+				cursor_bits_lookup[(b & m) & 0x0f], dst++);
+			    break;
+			}
+		}
+		dst += offset;
+	    }
 	}	
 	
 	if (cursor->enable) {
@@ -210,10 +227,12 @@
 	if (!info->sprite.addr)
 		return -ENXIO;
 	info->sprite.size = PAGE_SIZE;
-	info->sprite.scan_align = 16;	// Scratch pad 64 bytes wide
-	info->sprite.buf_align = 16; 	// *64;	// and 64 lines tall.
+	info->sprite.scan_align = 16;	/* Scratch pad 64 bytes wide */
+	info->sprite.buf_align = 16; 	/* and 64 lines tall. */
 	info->sprite.flags = FB_PIXMAP_IO;
-	info->sprite.outbuf = aty_set_cursor_shape;
+	
+	info->fbops->fb_cursor = atyfb_cursor;
+
 	return 0;
 }
 
diff -ur -X patches/exclude linux-2.6.7.js3/drivers/video/modedb.c linux-2.6.7.ak/drivers/video/modedb.c
--- linux-2.6.7.js3/drivers/video/modedb.c	2004-06-16 07:19:22.000000000 +0200
+++ linux-2.6.7.ak/drivers/video/modedb.c	2004-07-21 22:05:06.000000000 +0200
@@ -16,12 +16,14 @@
 #include <linux/fb.h>
 #include <linux/sched.h>
 
-#undef DEBUG
+#define DEBUG
 
 #define name_matches(v, s, l) \
     ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
 #define res_matches(v, x, y) \
     ((v).xres == (x) && (v).yres == (y))
+#define refresh_closest_to(v, x, y) \
+    ((!y || (abs((x)->refresh - (v)) < abs((y)->refresh - (v))))?x:y)
 
 #ifdef DEBUG
 #define DPRINTK(fmt, args...)	printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
@@ -126,16 +128,16 @@
 	0, FB_VMODE_NONINTERLACED
     }, {
 	/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
-	NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
-	0, FB_VMODE_NONINTERLACED   	
+	NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
+	0, FB_VMODE_NONINTERLACED
     }, {
-	/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
-	NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
-	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	/* 1400x1050 @ 64 Hz, 68.8 kHz */
+        NULL, 64, 1400, 1050, 8197, 184, 28, 10, 2, 152, 12,
+	0, FB_VMODE_NONINTERLACED
     }, {
-	/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
-        NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
-	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	/* 1400x1050 @ 75 Hz, 81,3 kHz */
+	NULL, 75, 1400, 1050, 6418, 128, 64, 26, 2, 320, 12,
+	0, FB_VMODE_NONINTERLACED
     }, {
 	/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
 	NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6,
@@ -528,25 +530,44 @@
 	    res_specified = 1;
 	}
 done:
-	for (i = refresh_specified; i >= 0; i--) {
-	    DPRINTK("Trying specified video mode%s\n",
-		    i ? "" : " (ignoring refresh rate)");
-	    for (j = 0; j < dbsize; j++)
-		if ((name_matches(db[j], name, namelen) ||
-		     (res_specified && res_matches(db[j], xres, yres))) &&
-		    (!i || db[j].refresh == refresh) &&
-		    !fb_try_mode(var, info, &db[j], bpp))
-		    return 2-i;
+	{
+	    if(refresh_specified) {
+		const struct fb_videomode *na = 0; /* nearest accepted with given refreshrate */
+	        
+		DPRINTK("Trying all video modes with refresh rate %i\n", refresh);
+
+		for(j = 0; j < dbsize; j++) {
+		    if((name_matches(db[j], name, namelen) || (res_specified && res_matches(db[j], xres, yres)))) {
+			if(!fb_try_mode(var, info, &db[j], bpp)) {
+			    na = refresh_closest_to(refresh, &db[j], na);
+			}
+		    }
+		}
+		if(na) {
+		    DPRINTK("Try the winner %ix%i@%i one more time\n", na->xres, na->yres, na->refresh);
+		    if(!fb_try_mode(var, info, na, bpp))
+	    	    	return 1;
+		}
+	    } else {
+		DPRINTK("Trying specified video mode(ignoring refresh rate), first win\n");
+		for(j = 0; j < dbsize; j++) {
+		    if((name_matches(db[j], name, namelen) || (res_specified && res_matches(db[j], xres, yres)))) {
+			if(!fb_try_mode(var, info, &db[j], bpp)) {
+			    return 2;
+			}
+		    }
+		}
+	    }
 	}
     }
 
     DPRINTK("Trying default video mode\n");
-    if (!fb_try_mode(var, info, default_mode, default_bpp))
+    if(!fb_try_mode(var, info, default_mode, default_bpp))
 	return 3;
 
     DPRINTK("Trying all modes\n");
-    for (i = 0; i < dbsize; i++)
-	if (!fb_try_mode(var, info, &db[i], default_bpp))
+    for(i = 0; i < dbsize; i++)
+	if(!fb_try_mode(var, info, &db[i], default_bpp))
 	    return 4;
 
     DPRINTK("No valid mode found\n");

[-- Attachment #3: mach64-js3-ak6b.diff --]
[-- Type: text/x-diff, Size: 6580 bytes --]

diff -ur -X patches/exclude linux-2.6.7.js3/include/video/mach64.h linux-2.6.7.ak/include/video/mach64.h
--- linux-2.6.7.js3/include/video/mach64.h	2004-06-27 01:35:27.000000000 +0200
+++ linux-2.6.7.ak/include/video/mach64.h	2004-07-28 21:55:35.000000000 +0200
@@ -68,6 +68,8 @@
 
 #define I2C_CNTL_0		0x003C	/* Dword offset 0_0F */
 
+#define DSTN_CONTROL_LG		0x003C	/* Dword offset 0_0F (LG) */
+
 /* Overscan */
 #define OVR_CLR			0x0040	/* Dword offset 0_10 */
 #define OVR2_CLR		0x0040	/* Dword offset 0_10 */
@@ -101,7 +103,7 @@
 #define CUR_HORZ_VERT_OFF	0x0070	/* Dword offset 0_1C */
 #define CUR2_HORZ_VERT_OFF	0x0070	/* Dword offset 0_1C */
 
-#define CONFIG_PANEL_LG		0x0074	/* Dword offset 0_1D */
+#define CONFIG_PANEL_LG		0x0074	/* Dword offset 0_1D (LG) */
 
 /* General I/O Control */
 #define GP_IO			0x0078	/* Dword offset 0_1E */
@@ -153,6 +155,8 @@
 #define LCD_INDEX		0x00A4	/* Dword offset 0_29 */
 #define LCD_DATA		0x00A8	/* Dword offset 0_2A */
 
+#define HFB_PITCH_ADDR_LG	0x00A8	/* Dword offset 0_2A (LG) */
+
 /* Memory Control */
 #define EXT_MEM_CNTL		0x00AC	/* Dword offset 0_2B */
 #define MEM_CNTL		0x00B0	/* Dword offset 0_2C */
@@ -161,6 +165,8 @@
 
 #define I2C_CNTL_1		0x00BC	/* Dword offset 0_2F */
 
+#define LT_GIO_LG		0x00BC	/* Dword offset 0_2F (LG) */
+
 /* DAC Control */
 #define DAC_REGS		0x00C0	/* Dword offset 0_30 */
 #define DAC_W_INDEX		0x00C0	/* Dword offset 0_30 */
@@ -171,14 +177,16 @@
 
 #define EXT_DAC_REGS		0x00C8	/* Dword offset 0_32 */
 
+#define HORZ_STRETCHING_LG	0x00C8	/* Dword offset 0_32 (LG) */
+#define VERT_STRETCHING_LG	0x00CC	/* Dword offset 0_33 (LG) */
+
 /* Test and Debug */
 #define GEN_TEST_CNTL		0x00D0	/* Dword offset 0_34 */
 
 /* Custom Macros */
 #define CUSTOM_MACRO_CNTL	0x00D4	/* Dword offset 0_35 */
 
-#define LCD_GEN_CNTL_LG		0x00D4	/* Dword offset 0_35 */
-
+#define LCD_GEN_CNTL_LG		0x00D4	/* Dword offset 0_35 (LG) */
 #define POWER_MANAGEMENT_LG	0x00D8	/* Dword offset 0_36 (LG) */
 
 /* Configuration */
@@ -508,7 +516,7 @@
 #define SCALER_BUF0_OFFSET_V	0x05D8	/* Dword offset 1_76 */
 #define SCALER_BUF1_OFFSET_U	0x05DC	/* Dword offset 1_77 */
 #define SCALER_BUF1_OFFSET_V	0x05E0	/* Dword offset 1_78 */
-
+    
 /* Setup Engine */
 #define VERTEX_1_S		0x0640	/* Dword offset 1_90 */
 #define VERTEX_1_T		0x0644	/* Dword offset 1_91 */
@@ -622,10 +630,70 @@
 #define CRTC_CUR_B_TEST		0x80000000
 
 #define CRTC_CRNT_VLINE		0x07f00000
-#define CRTC_VBLANK		0x00000001
 
 #define CRTC_PRESERVED_MASK	0x0001f000
 
+#define CRTC_VBLANK		0x00000001
+#define CRTC_VBLANK_INT_EN	0x00000002
+#define CRTC_VBLANK_INT		0x00000004
+#define CRTC_VBLANK_INT_AK	CRTC_VBLANK_INT
+#define CRTC_VLINE_INT_EN	0x00000008
+#define CRTC_VLINE_INT		0x00000010
+#define CRTC_VLINE_INT_AK	CRTC_VLINE_INT
+#define CRTC_VLINE_SYNC		0x00000020
+#define CRTC_FRAME		0x00000040
+#define SNAPSHOT_INT_EN		0x00000080
+#define SNAPSHOT_INT		0x00000100
+#define SNAPSHOT_INT_AK		SNAPSHOT_INT
+#define I2C_INT_EN		0x00000200
+#define I2C_INT			0x00000400
+#define I2C_INT_AK		I2C_INT
+#define CRTC2_VBLANK		0x00000800
+#define CRTC2_VBLANK_INT_EN	0x00001000
+#define CRTC2_VBLANK_INT	0x00002000
+#define CRTC2_VBLANK_INT_AK	CRTC2_VBLANK_INT
+#define CRTC2_VLINE_INT_EN	0x00004000
+#define CRTC2_VLINE_INT		0x00008000
+#define CRTC2_VLINE_INT_AK	CRTC2_VLINE_INT
+#define CAPBUF0_INT_EN		0x00010000
+#define CAPBUF0_INT		0x00020000
+#define CAPBUF0_INT_AK		CAPBUF0_INT
+#define CAPBUF1_INT_EN		0x00040000
+#define CAPBUF1_INT		0x00080000
+#define CAPBUF1_INT_AK		CAPBUF1_INT
+#define OVERLAY_EOF_INT_EN	0x00100000
+#define OVERLAY_EOF_INT		0x00200000
+#define OVERLAY_EOF_INT_AK	OVERLAY_EOF_INT
+#define ONESHOT_CAP_INT_EN	0x00400000
+#define ONESHOT_CAP_INT		0x00800000
+#define ONESHOT_CAP_INT_AK	ONESHOT_CAP_INT
+#define BUSMASTER_EOL_INT_EN	0x01000000
+#define BUSMASTER_EOL_INT	0x02000000
+#define BUSMASTER_EOL_INT_AK	BUSMASTER_EOL_INT
+#define GP_INT_EN		0x04000000
+#define GP_INT			0x08000000
+#define GP_INT_AK		GP_INT
+#define CRTC2_VLINE_SYNC	0x10000000
+#define SNAPSHOT2_INT_EN	0x20000000
+#define SNAPSHOT2_INT		0x40000000
+#define SNAPSHOT2_INT_AK	SNAPSHOT2_INT
+#define VBLANK_BIT2_INT		0x80000000
+#define VBLANK_BIT2_INT_AK	VBLANK_BIT2_INT
+
+#define CRTC_INT_EN_MASK	(CRTC_VBLANK_INT_EN |	\
+				 CRTC_VLINE_INT_EN |	\
+				 SNAPSHOT_INT_EN |	\
+				 I2C_INT_EN |		\
+				 CRTC2_VBLANK_INT_EN |	\
+				 CRTC2_VLINE_INT_EN |	\
+				 CAPBUF0_INT_EN |	\
+				 CAPBUF1_INT_EN |	\
+				 OVERLAY_EOF_INT_EN |	\
+				 ONESHOT_CAP_INT_EN |	\
+				 BUSMASTER_EOL_INT_EN |	\
+				 GP_INT_EN |		\
+				 SNAPSHOT2_INT_EN)
+
 /* DAC control values */
 
 #define DAC_EXT_SEL_RS2		0x01
@@ -640,6 +708,24 @@
 #define DAC_BLANK_ADJ_1		0x00000800
 #define DAC_BLANK_ADJ_2		0x00001000
 
+/* DAC control values (my source XL/XC Register reference) */
+#define DAC_OUTPUT_MASK         0x00000001  /* 0 - PAL, 1 - NTSC */
+#define DAC_MISTERY_BIT         0x00000002  /* PS2 ? RS343 ?, EXTRA_BRIGHT for GT */
+#define DAC_BLANKING            0x00000004
+#define DAC_CMP_DISABLE         0x00000008
+#define DAC1_CLK_SEL            0x00000010
+#define PALETTE_ACCESS_CNTL     0x00000020
+#define PALETTE2_SNOOP_EN       0x00000040
+#define DAC_CMP_OUTPUT          0x00000080 /* read only */
+/* #define DAC_8BIT_EN is ok */
+#define CRT_SENSE               0x00000800 /* read only */
+#define CRT_DETECTION_ON        0x00001000
+#define DAC_VGA_ADR_EN          0x00002000
+#define DAC_FEA_CON_EN          0x00004000
+#define DAC_PDWN                0x00008000
+#define DAC_TYPE_MASK           0x00070000 /* read only */
+                
+
 
 /* Mix control values */
 
@@ -912,10 +998,14 @@
 #define GI_CHIP_ID	0x4749	/* RAGE PRO, BGA, PCI33 only */
 #define GP_CHIP_ID	0x4750	/* RAGE PRO, PQFP, PCI33, full 3D */
 #define GQ_CHIP_ID	0x4751	/* RAGE PRO, PQFP, PCI33, limited 3D */
-#define LM_CHIP_ID	0x4c4d	/* RAGE Mobility PCI */
-#define LN_CHIP_ID	0x4c4e	/* RAGE Mobility AGP */
 
+#define LM_CHIP_ID	0x4c4d	/* RAGE Mobility AGP, full function */
+#define LN_CHIP_ID	0x4c4e	/* RAGE Mobility AGP */
+#define LR_CHIP_ID	0x4c52	/* RAGE Mobility PCI, full function */
+#define LS_CHIP_ID	0x4c53	/* RAGE Mobility PCI */
 
+#define IS_MOBILITY(id) ((id)==LM_CHIP_ID || (id)==LN_CHIP_ID || \
+			(id)==LR_CHIP_ID || (id)==LS_CHIP_ID)
 /* Mach64 major ASIC revisions */
 #define MACH64_ASIC_NEC_VT_A3		0x08
 #define MACH64_ASIC_NEC_VT_A4		0x48

  parent reply	other threads:[~2004-08-06  6:10 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-02  3:31 URGENT: status of atyfb Benjamin Herrenschmidt
2004-08-02  5:21 ` Benjamin Herrenschmidt
2004-08-03 20:57   ` Alexander Kern
2004-08-03 21:25     ` Benjamin Herrenschmidt
2004-08-03 22:05       ` Ville Syrjälä
2004-08-06  6:09       ` Alexander Kern [this message]
2004-08-06  8:10         ` Benjamin Herrenschmidt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200408060809.37494.alex.kern@gmx.de \
    --to=alex.kern@gmx.de \
    --cc=benh@kernel.crashing.org \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    --cc=syrjala@sci.fi \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).