Resent-Date: Fri, 6 Aug 1999 19:47:17 +0200 (MET DST)
Sender: bharries@germany.net
Date: Thu, 05 Aug 1999 22:13:20 +0200
From: Bernd Harries <bha@gmx.de>
Organization: BHA Industries
To: Geert.Uytterhoeven@cs.kuleuven.ac.be
CC: linux-m68k@lists.linux-m68k.org, scott@dmi.stevens-tech.edu
Subject: Re: 2.2.x and 2.3.x
References: <199908021347.PAA24136@faui02p.informatik.uni-erlangen.de>
Resent-From: linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de

Hi dudes!

Richard Zidlicky wrote:

> > long time. The latter 2.1.x (x>130?) and 2.{2,3}.x kernels fail on
> > execing init. I can get to a shell by forcing INIT=/bin/sh but all
> > forked commands after that fail locking up the kernel with no debug
> > information.
> 
> quite a common problem with many kernel versions. 2.2.10 with the 
> latest patches should fix this.

Ok, then I try to find them now.

>> Also after 2.1.120 or so the external video option to the atafb 
>> device has started no to work for me. I am running a mach64gx in 
>> unaccelerated external fb mode. 

I saw the bird. Try the attached atyfb.c patch. Meanwhile I'll try to
find all the 2.2.10 diffs in my mailbox.

-- 
Bernd Harries

bha@gmx.de           http://www.freeyellow.com/members/bharries
bha@nikocity.de       Tel. +49 421 809 7343 priv.  | MSB First!
harries@stn-atlas.de       +49 421 457 3966 offi.  | Linux-m68k
bernd@linux-m68k.org      8.48'21" E  52.48'52" N  | Medusa T40
           <>_<>      _______                _____
       .---|'"`|---. |  |_|  |_|_|_|_|_|_|_ (_____)  .-----.
______`o"O-OO-OO-O"o'`-o---o-'`-oo-----oo-'`-o---o-'`-o---o-'___

--- atyfb.c_2210	Tue May 11 19:40:03 1999
+++ atyfb.c	Thu Aug  5 21:40:21 1999
@@ -89,8 +89,34 @@
  */
 #undef DEBUG
 
+/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
 
-#define GUI_RESERVE	0x00001000
+#define REF_FREQ_2595       1432  /*  14.33 MHz  (exact   14.31818) */
+#define REF_DIV_2595          46  /* really 43 on ICS 2595 !!!  */
+                                  /* ohne Prescaler */
+#define MAX_FREQ_2595      15938  /* 159.38 MHz  (really 170.486) */
+#define MIN_FREQ_2595       8000  /*  80.00 MHz  (        85.565) */
+                                  /* mit Prescaler 2, 4, 8 */
+#define ABS_MIN_FREQ_2595   1000  /*  10.00 MHz  (really  10.697) */
+#define N_ADJ_2595           257
+
+#define STOP_BITS_2595     0x1800
+
+
+#define MIN_N_408		2
+
+#define MIN_N_1703		6
+
+#define MIN_M		2
+#define MAX_M		30
+#define MIN_N		35
+#define MAX_N		255-8
+
+
+/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
+/*  - must be large enough to catch all GUI-Regs   */
+/*  - must be aligned to a PAGE boundary           */
+#define GUI_RESERVE	(1 * PAGE_SIZE)
 
 
 #ifndef __powerpc__
@@ -126,6 +152,14 @@
     u8 n;
 };
 
+struct pll_18818
+{
+    u32 program_bits;
+    u32 locationAddr;
+    u32 period_in_ps;
+    u32 post_divider;
+};
+
 struct pll_ct {
     u8 pll_ref_div;
     u8 pll_gen_cntl;
@@ -148,6 +182,7 @@
     union {
 	struct pll_gx gx;
 	struct pll_ct ct;
+	struct pll_18818 ics2595;
     } pll;
     u32 accel_flags;
 };
@@ -178,7 +213,7 @@
     int blink_rate;
     u32 offset;
     struct {
-        u16 x, y;
+	u16 x, y;
     } pos, hot, size;
     u32 color[2];
     u8 bits[8][64];
@@ -193,6 +228,7 @@
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
     unsigned long frame_buffer;
+    unsigned long clk_wr_offset;
     struct pci_mmap_map *mmap_map;
     struct aty_cursor *cursor;
     struct aty_cmap_regs *aty_cmap_regs;
@@ -209,6 +245,7 @@
     u8 bus_type;
     u8 ram_type;
     u8 dac_type;
+    u8 dac_subtype;
     u8 clk_type;
     u8 mem_refresh_rate;
     struct display disp;
@@ -324,6 +361,7 @@
 
 static void reset_engine(const struct fb_info_aty *info);
 static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info);
+
 static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
 static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
 #if defined(__sparc__) || defined(DEBUG)
@@ -339,7 +377,38 @@
 			   struct fb_var_screeninfo *var);
 static void aty_set_pll_gx(const struct fb_info_aty *info,
 			   const struct pll_gx *pll);
-static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll);
+
+static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
+				  u32 AccelMode);
+static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
+				 const struct pll_18818 *pll, u32 bpp);
+void aty_dac_waste4(const struct fb_info_aty *info);
+
+static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll);
+static int aty_pll_18818_to_var(const struct pll_18818 *pll,
+				u32 *period_in_ps);
+static void aty_set_pll18818(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
+static void aty_StrobeClock(const struct fb_info_aty *info);
+
+static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info);
+
+static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll);
+static int aty_pll_408_to_var(const struct pll_18818 *pll, u32 *period_in_ps);
+static void aty_set_pll_408(const struct fb_info_aty *info,
+			    const struct pll_18818 *pll);
+
+static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll);
+static int aty_pll_1703_to_var(const struct pll_18818 *pll, u32 *period_in_ps);
+static void aty_set_pll_1703(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
+static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll);
+static int aty_pll_8398_to_var(const struct pll_18818 *pll, u32 *period_in_ps);
+static void aty_set_pll_8398(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
 static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per);
 static void aty_set_pll_ct(const struct fb_info_aty *info,
@@ -436,7 +505,7 @@
     /* mach64CT family / mach64VT class */
     { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
     { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
-    { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" },
+/*  { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */
 
     /* mach64CT family / mach64GT (3D RAGE) class */
     { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" },
@@ -445,11 +514,10 @@
     { 0x4c49, 0x4c49, "3D RAGE LT PRO" },
     { 0x4c50, 0x4c50, "3D RAGE LT PRO" },
     { 0x4c54, 0x4c54, "3D RAGE LT" },
+    { 0x4c47, 0x4c47, "3D RAGE LG" },
     { 0x4754, 0x4754, "3D RAGE (GT)" },
     { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
-    { 0x4756, 0x4756, "3D RAGE IIC (PCI)" },
-    { 0x4757, 0x4757, "3D RAGE IIC (AGP)" },
-    { 0x475a, 0x475a, "3D RAGE IIC (AGP)" },
+/*  { 0x4756, 0x4756, "3D RAGE IIC" }, */
     { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
     { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
     { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
@@ -966,23 +1034,19 @@
 	fb->total_vram -= PAGE_SIZE;
 	cursor->offset = fb->total_vram;
 
-#ifdef __sparc__
+#if defined(__sparc__)
 	addr = fb->frame_buffer - 0x800000 + cursor->offset;
 	cursor->ram = (u8 *)addr;
-#else
-#ifdef __BIG_ENDIAN
+#elif defined(__mc68000__)
+	addr = fb->frame_buffer_phys - 0x800000 + cursor->offset;
+	/* we don't have ioremap */
+#elif defined(__BIG_ENDIAN)
 	addr = fb->frame_buffer_phys - 0x800000 + cursor->offset;
 	cursor->ram = (u8 *)ioremap(addr, 1024);
 #else
 	addr = fb->frame_buffer + cursor->offset;
 	cursor->ram = (u8 *)addr;
 #endif
-#endif
-
-	if (! cursor->ram) {
-		kfree(cursor);
-		return NULL;
-	}
 
 	if (curblink) {
 		init_timer(cursor->timer);
@@ -1161,7 +1225,8 @@
     crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
     crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE;
     if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
-	((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) {
+	((Gx == VT_CHIP_ID) && !(Rev & 0x03)) ||
+	((Gx == GT_CHIP_ID) && !(Rev & 0x03))) {
 	/* Not VTB/GTB */
 	/* FIXME: magic FIFO values */
 	crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
@@ -1172,6 +1237,124 @@
     return 0;
 }
 
+
+static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
+				  u32 AccelMode)
+{
+    u32 gModeReg, devSetupRegA, temp, mask;
+
+    gModeReg = 0;
+    devSetupRegA = 0;
+    
+    switch (bpp) {
+	case 8:
+	    gModeReg = 0x83;
+	    devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */;
+	    break;
+	case 15:
+	    gModeReg = 0xA0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 16:
+	    gModeReg = 0xA1;
+	    devSetupRegA = 0x60;
+	    break;
+	case 24:
+	    gModeReg = 0xC0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 32:
+	    gModeReg = 0xE3;
+	    devSetupRegA = 0x60;
+	    break;
+    }
+
+    if (!AccelMode) {
+	gModeReg = 0x80;
+	devSetupRegA = 0x61;
+    }
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS + 2, 0x1D, info);
+    aty_st_8(DAC_REGS + 3, gModeReg, info);
+    aty_st_8(DAC_REGS, 0x02, info);
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    if (info->total_vram < MEM_SIZE_1M)
+	mask = 0x04;
+    else if (info->total_vram == MEM_SIZE_1M)
+	mask = 0x08;
+    else
+	mask = 0x0C;
+
+    /* The following assumes that the BIOS has correctly set R7 of the
+     * Device Setup Register A at boot time.
+     */
+#define A860_DELAY_L	0x80
+
+    temp = aty_ld_8(DAC_REGS, info);
+    aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info);
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info);
+
+    return 0;
+}
+
+static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
+				 const struct pll_18818 *pll, u32 bpp)
+{
+    u32 dotClock;
+    int muxmode = 0;
+    int DACMask;
+
+    dotClock = 100000000 / pll->period_in_ps;
+
+    switch (bpp) {
+	case 8:
+	    if (dotClock > 8000) {
+		DACMask = 0x24;
+		muxmode = 1;
+	    } else
+		DACMask = 0x04;
+	    break;
+	case 15:
+	    DACMask = 0x16;
+	    break;
+	case 16:
+	    DACMask = 0x36;
+	    break;
+	case 24:
+	    DACMask = 0xE6;
+	    break;
+	case 32:
+	    DACMask = 0xE6;
+	    break;
+    }
+
+    if (1 /* info->mach64DAC8Bit */)
+	DACMask |= 0x02;
+
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, DACMask, info);
+
+    return muxmode;
+}
+
+void aty_dac_waste4(const struct fb_info_aty *info)
+{
+  (void)aty_ld_8(DAC_REGS, info);
+
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+}
+
+
 static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
 {
     static struct {
@@ -1353,9 +1536,6 @@
 			   const struct pll_gx *pll)
 {
     switch (info->clk_type) {
-	case CLK_ATI18818_1:
-	    aty_st_8(CLOCK_CNTL, pll->m, info);
-	    break;
 	case CLK_IBMRGB514:
 	    aty_st_514(0x06, 0x02, info);	/* DAC Operation */
 	    aty_st_514(0x10, 0x01, info);	/* PLL Control 1 */
@@ -1369,7 +1549,9 @@
     }
 }
 
-static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll)
+#ifdef BHA_NEVER
+
+static int aty_select_pll_18818(u32 vclk_period, struct pll_gx *pll)
 {
     /*
      *  FIXME: use real calculations instead of using fixed values from the old
@@ -1413,15 +1595,489 @@
     };
     int set;
 
+    pll->m = 0x0B;
+    pll->n = 1;
     for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
 	 set++)
-	if (vclk_per <= ATI18818_clocks[set].ps_lim) {
+	if (vclk_period <= ATI18818_clocks[set].ps_lim) {
 	    pll->m = ATI18818_clocks[set].mode;
 	    pll->n = ATI18818_clocks[set].prog;
 	    return 0;
 	}
+
     return -EINVAL;
 }
+#endif  /* BHA_NEVER */
+
+
+static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll)
+{
+    u32 MHz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    u32 post_divider;
+
+    /* Calculate the programming word */
+    MHz100 = 100000000 / period_in_ps;
+    
+    program_bits = -1;
+    post_divider = 1;
+
+    if (MHz100 > MAX_FREQ_2595) {
+	MHz100 = MAX_FREQ_2595;
+	return -EINVAL;
+    } else if (MHz100 < ABS_MIN_FREQ_2595) {
+	program_bits = 0;	/* MHz100 = 257 */
+	return -EINVAL;
+    } else {
+	while (MHz100 < MIN_FREQ_2595) {
+	    MHz100 *= 2;
+	    post_divider *= 2;
+	}
+    }
+    MHz100 *= 1000;
+    MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
+
+    MHz100 += 500;    /* + 0.5 round */
+    MHz100 /= 1000;
+
+    if (program_bits == -1) {
+	program_bits = MHz100 - N_ADJ_2595;
+	switch (post_divider) {
+	    case 1:
+		program_bits |= 0x0600;
+		break;
+	    case 2:
+		program_bits |= 0x0400;
+		break;
+	    case 4:
+		program_bits |= 0x0200;
+		break;
+	    case 8:
+	    default:
+		break;
+	}
+    }
+
+    program_bits |= STOP_BITS_2595;
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = post_divider;
+    pll->period_in_ps = period_in_ps;
+
+    return 0;
+}
+
+static int aty_pll_18818_to_var(const struct pll_18818 *pll, u32 *period_in_ps)
+{
+    *period_in_ps = pll->period_in_ps;  /* default for now */
+    return 0;
+}
+
+static void aty_set_pll18818(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u32 i;
+
+    u8 old_clock_cntl;
+    u8 old_crtc_ext_disp;
+
+    old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    udelay(15000); /* delay for 50 (15) ms */
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program the clock chip */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+
+    aty_ICS2595_put1bit(1, info);    /* Send start bits */
+    aty_ICS2595_put1bit(0, info);    /* Start bit */
+    aty_ICS2595_put1bit(0, info);    /* Read / ~Write */
+
+    for (i = 0; i < 5; i++) {	/* Location 0..4 */
+	aty_ICS2595_put1bit(locationAddr & 1, info);
+	locationAddr >>= 1;
+    }
+
+    for (i = 0; i < 8 + 1 + 2 + 2; i++) {
+	aty_ICS2595_put1bit(program_bits & 1, info);
+	program_bits >>= 1;
+    }
+
+    udelay(1000); /* delay for 1 ms */
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE,
+	     info);
+
+    udelay(50000); /* delay for 50 (15) ms */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
+	     ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);
+   
+    return;
+}
+
+
+static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll)
+{
+    u32 mhz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xFF;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x40;
+	}
+
+	temp = (unsigned int)mhz100;
+	temp = (unsigned int)(temp * (MIN_N_408 + 2));
+	temp -= ((short)(mach64RefFreq << 1));
+
+	tempA = MIN_N_408;
+	preRemainder = 0xFFFF;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+	    if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x3f;
+		divider |= tempA;
+		divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8);
+	    }
+	    temp += mhz100;
+	    tempA++;
+	} while(tempA <= 32);
+
+	program_bits = divider;
+    }
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = divider;	/* fuer nix */
+    pll->period_in_ps = period_in_ps;
+
+    return 0;
+}
+
+static int aty_pll_408_to_var(const struct pll_18818 *pll, u32 *period_in_ps)
+{
+    *period_in_ps = pll->period_in_ps;  /* default for now */
+    return 0;
+}
+
+static void aty_set_pll_408(const struct fb_info_aty *info,
+			    const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u8 tmpA, tmpB, tmpC;
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+    tmpB = aty_ld_8(DAC_REGS + 2, info) | 1;
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, tmpB, info);
+
+    tmpA = tmpB;
+    tmpC = tmpA;
+    tmpA |= 8;
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+
+    locationAddr = (locationAddr << 2) + 0x40;
+    tmpB = locationAddr;
+    tmpA = program_bits >> 8;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 1;
+    tmpA = (u8)program_bits;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 2;
+    tmpA = 0x77;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+    tmpA = tmpC & (~(1 | 8));
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+
+static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll)
+{
+    u32 mhz100;			/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	divider = 0;
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x20;
+	}
+
+	temp = (unsigned int)(mhz100);
+	temp = (unsigned int)(temp * (MIN_N_1703 + 2));
+	temp -= (short)(mach64RefFreq << 1);
+
+	tempA = MIN_N_1703;
+	preRemainder = 0xffff;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+
+	    if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x1f;
+		divider |= tempA;
+		divider = (divider & 0x00ff) + ((tempB & 0xff) << 8);
+	    }
+
+	    temp += mhz100;
+	    tempA++;
+	} while (tempA <= (MIN_N_1703 << 1));
+
+	program_bits = divider;
+    }
+
+      pll->program_bits = program_bits;
+      pll->locationAddr = 0;
+      pll->post_divider = divider;  /* fuer nix */
+      pll->period_in_ps = period_in_ps;
+
+      return 0;
+}
+
+static int aty_pll_1703_to_var(const struct pll_18818 *pll, u32 *period_in_ps)
+{
+    *period_in_ps = pll->period_in_ps;  /* default for now */
+    return 0;
+}
+
+static void aty_set_pll_1703(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+
+    (void)aty_ld_8(DAC_REGS + 2, info);
+    aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info);
+    aty_st_8(DAC_REGS+2, 0, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+
+static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll)
+{
+#if 0	/* yuk, floats in kernel code */
+    float tempA, tempB, fOut, longMHz100, diff, preDiff;
+    u32 mhz100;				/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u16 m, n, k=0, save_m, save_n, twoToKth;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    save_m = 0;
+    save_n = 0;
+
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	longMHz100 = (float) mhz100/100;
+
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    k++;
+	}
+
+	twoToKth = 1 << k;
+	diff = 0.0;
+	preDiff = 0xFFFFFFFF;
+
+	for (m = MIN_M; m <= MAX_M; m++) {
+	    for (n = MIN_N; n <= MAX_N; n++) {
+		tempA = 14.31818;
+		tempA *= (float)(n+8);
+		tempB = (float)twoToKth;
+		tempB *= (m+2);
+		fOut = tempA/tempB;
+
+		if (longMHz100 > fOut)
+		    diff = longMHz100 - fOut;
+		else
+		    diff = fOut - longMHz100;
+
+		if (diff < preDiff) {
+		    save_m = m;
+		    save_n = n;
+		    preDiff = diff;
+		}
+	    }
+	}
+
+	program_bits = (k << 6) + (save_m) + (save_n << 8);
+    }
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = 0;
+    pll->period_in_ps = period_in_ps;
+#endif
+
+    return 0;
+}
+
+static int aty_pll_8398_to_var(const struct pll_18818 *pll, u32 *period_in_ps)
+{
+    *period_in_ps = pll->period_in_ps;  /* default for now */
+    return 0;
+}
+
+static void aty_set_pll_8398(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+    char tmp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS, locationAddr, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff), info);
+
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
 
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll)
 {
@@ -1453,7 +2109,42 @@
     return -EINVAL;
 }
 
-    /* FIXME: ATI18818?? */
+
+static void aty_StrobeClock(const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    udelay(26);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info);
+
+    return;
+}
+
+
+static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    data &= 0x01;
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2),
+	     info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info);
+
+    aty_StrobeClock(info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info);
+
+    aty_StrobeClock(info);
+
+    return;
+}
+
 
 static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per)
 {
@@ -1484,9 +2175,10 @@
     aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
     aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
 
-    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-	  Gx == ET_CHIP_ID ||
-	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {
+    if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+	(Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+	(Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+	(Gx == VU_CHIP_ID)) {
 	if (info->ram_type >= SDRAM)
 	    aty_st_pll(DLL_CNTL, 0xa6, info);
 	else
@@ -1509,9 +2201,8 @@
 		    (vclk_fb_div*mclk_post_div*bpp);
     if (xclks_per_row < (1<<11))
 	FAIL("Dotclock to high");
-    if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID ||
-	Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID ||
-	Gx == GZ_CHIP_ID) {
+    if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == VT_CHIP_ID) ||
+	(Gx == VU_CHIP_ID)) {
 	fifo_size = 24;
 	dsp_loop_latency = 0;
     } else {
@@ -1650,21 +2341,25 @@
 	case 2:
 	    vpostdiv = 1;
 	    break;
+
 	case 3:
 	    pll_ext_cntl |= 0x10;
 	case 1:
 	    vpostdiv = 0;
 	    break;
+
 	case 6:
 	    pll_ext_cntl |= 0x10;
 	case 4:
 	    vpostdiv = 2;
 	    break;
+
 	case 12:
 	    pll_ext_cntl |= 0x10;
 	case 8:
 	    vpostdiv = 3;
 	    break;
+
     }
     vclk_post_div = vpostdiv;
 
@@ -1701,27 +2396,88 @@
 			  struct fb_info_aty *info)
 {
     u32 i;
+    int accelmode;
+    int muxmode;
+    u8 tmp;
+    
+    accelmode = par->accel_flags;  /* hack */
 
     info->current_par = *par;
 
     if (info->blitter_may_be_busy)
 	wait_for_idle(info);
+    tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
     aty_set_crtc(info, &par->crtc);
-    aty_st_8(CLOCK_CNTL, 0, info);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+					/* better call aty_StrobeClock ?? */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info);
 
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
-	switch (info->dac_type) {
+	switch (info->dac_subtype) {
 	    case DAC_IBMRGB514:
 		aty_set_dac_514(info, par->crtc.bpp);
 		break;
 	    case DAC_ATI68860_B:
-		/* FIXME */
+	    case DAC_ATI68860_C:
+		muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp,
+						 accelmode);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x47052100, info);
 		break;
-	}
-	aty_set_pll_gx(info, &par->pll.gx);
+	    case DAC_ATT20C408:
+		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
+						par->crtc.bpp);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x00072000, info);
+		break;
+	    case DAC_ATT21C498:
+		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
+						par->crtc.bpp);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x00072000, info);
+		break;
+	    default:
+		printk(" atyfb_set_par: DAC type not implemented yet!\n");
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x47052100, info);
+	/* new in 2.2.3p1 von Geert. ???????? */
 	aty_st_le32(BUS_CNTL, 0x590e10ff, info);
 	aty_st_le32(DAC_CNTL, 0x47012100, info);
+		break;
+	}
+
+#ifdef FERTIG
+	(void)aty_ld_8(DAC_REGS, info);
+	aty_st_8(CRTC_GEN_CNTL + 3, tmp, info);
+
+	if (AccelMode && mach64Ramdac != DAC_INTERNAL) {
+	    tmp = aty_ld_8(CRTC_GEN_CNTL, info) & ~CRTC_PIX_BY_2_EN;
+	    if (muxmode || isMuxMode)
+		tmp |= CRTC_PIX_BY_2_EN;
+	    aty_st_8(CRTC_GEN_CNTL, tmp, info);
+	}
+#endif 
+
+	switch (info->clk_type) {
+	    case CLK_ATI18818_1:
+		aty_set_pll18818(info, &par->pll.ics2595);
+		break;
+	    case CLK_STG1703:
+		aty_set_pll_1703(info, &par->pll.ics2595);
+		break;
+	    case CLK_CH8398:
+		aty_set_pll_8398(info, &par->pll.ics2595);
+		break;
+	    case CLK_ATT20C408:
+		aty_set_pll_408(info, &par->pll.ics2595);
+		break;
+	    case CLK_IBMRGB514:
+		aty_set_pll_gx(info, &par->pll.gx);
+		break;
+	    default:
+		printk(" atyfb_set_par: CLK type not implemented yet!");
+		break;
+	}
 
 	/* Don't forget MEM_CNTL */
 	i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff;
@@ -1809,7 +2565,16 @@
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
 	switch (info->clk_type) {
 	    case CLK_ATI18818_1:
-		err = aty_var_to_pll_18818(var->pixclock, &par->pll.gx);
+		err = aty_var_to_pll_18818(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_STG1703:
+		err = aty_var_to_pll_1703(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_CH8398:
+		err = aty_var_to_pll_8398(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_ATT20C408:
+		err = aty_var_to_pll_408(var->pixclock, &par->pll.ics2595);
 		break;
 	    case CLK_IBMRGB514:
 		err = aty_var_to_pll_514(var->pixclock, &par->pll.gx);
@@ -1818,6 +2583,7 @@
     else
 	err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp,
 				&par->pll.ct);
+
     if (err)
 	return err;
 
@@ -1845,7 +2611,23 @@
     if ((err = aty_crtc_to_var(&par->crtc, var)))
 	return err;
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock);
+	switch (info->clk_type) {
+	    case CLK_ATI18818_1:
+		err = aty_pll_18818_to_var(&par->pll.ics2595, &var->pixclock);
+		break;
+	    case CLK_STG1703:
+		err = aty_pll_1703_to_var(&par->pll.ics2595, &var->pixclock);
+		break;
+	    case CLK_CH8398:
+		err = aty_pll_8398_to_var(&par->pll.ics2595, &var->pixclock);
+		break;
+	    case CLK_ATT20C408:
+		err = aty_pll_408_to_var(&par->pll.ics2595, &var->pixclock);
+		break;
+	    case CLK_IBMRGB514:
+		err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock);
+		break;
+	}
     else
 	err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock);
     if (err)
@@ -1940,15 +2722,15 @@
      *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
      *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
      */
-    if (Gx == GX_CHIP_ID || Gx == CX_CHIP_ID) {
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
 	fix->mmio_start = (char *)info->ati_regbase_phys;
 	fix->mmio_len = 0x400;
 	fix->accel = FB_ACCEL_ATI_MACH64GX;
-    } else if (Gx == CT_CHIP_ID || Gx == ET_CHIP_ID) {
+    } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
 	fix->mmio_start = (char *)info->ati_regbase_phys;
 	fix->mmio_len = 0x400;
 	fix->accel = FB_ACCEL_ATI_MACH64CT;
-    } else if (Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == VV_CHIP_ID) {
+    } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
 	fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
 	fix->mmio_len = 0x800;
 	fix->accel = FB_ACCEL_ATI_MACH64VT;
@@ -2018,41 +2800,41 @@
 static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info,
 			   int bpp, int accel)
 {
-	    switch (bpp) {
+    switch (bpp) {
 #ifdef FBCON_HAS_CFB8
-		case 8:
-		    info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
-		    disp->dispsw = &info->dispsw;
-		    break;
+	case 8:
+	    info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
+	    disp->dispsw = &info->dispsw;
+	    break;
 #endif
 #ifdef FBCON_HAS_CFB16
-		case 16:
-		    info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb16;
-		    break;
+	case 16:
+	    info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
+	    disp->dispsw = &info->dispsw;
+	    disp->dispsw_data = info->fbcon_cmap.cfb16;
+	    break;
 #endif
 #ifdef FBCON_HAS_CFB24
-		case 24:
-		    info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb24;
-		    break;
+	case 24:
+	    info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
+	    disp->dispsw = &info->dispsw;
+	    disp->dispsw_data = info->fbcon_cmap.cfb24;
+	    break;
 #endif
 #ifdef FBCON_HAS_CFB32
-		case 32:
-		    info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb32;
-		    break;
+	case 32:
+	    info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
+	    disp->dispsw = &info->dispsw;
+	    disp->dispsw_data = info->fbcon_cmap.cfb32;
+	    break;
 #endif
-		default:
-		    disp->dispsw = &fbcon_dummy;
-	    }
-	    if (info->cursor) {
-		info->dispsw.cursor = atyfb_cursor;
-		info->dispsw.set_font = atyfb_set_font;
-	    }
+	default:
+	    disp->dispsw = &fbcon_dummy;
+    }
+    if (info->cursor) {
+	info->dispsw.cursor = atyfb_cursor;
+	info->dispsw.set_font = atyfb_set_font;
+    }
 }
 
 
@@ -2332,6 +3114,10 @@
 	if (!map_size)
 		return -EINVAL;
 
+	/*
+	vma->vm_file = file;
+	file->f_count++;
+	*/
 	vma->vm_flags |= VM_IO;
 
 	if (!fb->mmaped) {
@@ -2445,6 +3231,7 @@
     for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
 	if (aty_features[j].chip_type == Gx) {
 	    chipname = aty_features[j].name;
+	    info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
 	    break;
 	}
     if (!chipname) {
@@ -2458,10 +3245,16 @@
 	ramname = aty_gx_ram[info->ram_type];
 	/* FIXME: clockchip/RAMDAC probing? */
 #ifdef CONFIG_ATARI
-	info->dac_type = DAC_ATI68860_B;
 	info->clk_type = CLK_ATI18818_1;
+	info->dac_type = (aty_ld_le32(CONFIG_STAT0, info) >> 9) & 0x07;
+	if (info->dac_type == 0x07)
+	    info->dac_subtype = DAC_ATT20C408;
+	else
+	    info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) |
+				info->dac_type;
 #else
 	info->dac_type = DAC_IBMRGB514;
+	info->dac_subtype = DAC_IBMRGB514;
 	info->clk_type = CLK_IBMRGB514;
 #endif
 	/* FIXME */
@@ -2472,6 +3265,7 @@
 	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
 	ramname = aty_ct_ram[info->ram_type];
 	info->dac_type = DAC_INTERNAL;
+	info->dac_subtype = DAC_INTERNAL;
 	info->clk_type = CLK_INTERNAL;
 	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
 	    pll = 135;
@@ -2508,11 +3302,11 @@
 		/* RAGE IIC */
 		pll = 230;
 		mclk = 83;
-	    } else if (Gx == GB_CHIP_ID || Gx == GD_CHIP_ID ||
-		       Gx == GI_CHIP_ID || Gx == GP_CHIP_ID ||
-		       Gx == GQ_CHIP_ID || Gx == LB_CHIP_ID ||
-		       Gx == LD_CHIP_ID || Gx == LG_CHIP_ID ||
-		       Gx == LI_CHIP_ID || Gx == LP_CHIP_ID) {
+	    } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+		       (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) ||
+		       (Gx == GQ_CHIP_ID) || (Gx == LB_CHIP_ID) ||
+		       (Gx == LD_CHIP_ID) || (Gx == LG_CHIP_ID) ||
+		       (Gx == LI_CHIP_ID) || (Gx == LP_CHIP_ID)) {
 		/* RAGE PRO or LT PRO */
 		pll = 230;
 		mclk = 100;
@@ -2525,9 +3319,11 @@
     }
 
     i = aty_ld_le32(MEM_CNTL, info);
-    gtb_memsize = !(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-		    Gx == ET_CHIP_ID ||
-		    ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)));
+    gtb_memsize = (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID)
+		|| ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID)
+		|| (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID)
+		|| (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID)
+		|| (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID));
     if (gtb_memsize)
 	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
 	    case MEM_SIZE_512K:
@@ -2602,7 +3398,7 @@
     if (default_mclk)
 	mclk = default_mclk;
 
-    printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n", 
+    printk("%d%c %s, %d MHz PLL, %d MHz MCLK\n", 
     	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), 
     	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
 
@@ -2675,9 +3471,9 @@
     var = default_var;
 #endif /* !CONFIG_PPC */
     if (noaccel)
-        var.accel_flags &= ~FB_ACCELF_TEXT;
+	var.accel_flags &= ~FB_ACCELF_TEXT;
     else
-        var.accel_flags |= FB_ACCELF_TEXT;
+	var.accel_flags |= FB_ACCELF_TEXT;
 
     if (var.yres == var.yres_virtual) {
 	u32 vram = (info->total_vram - (PAGE_SIZE << 2));
@@ -2829,11 +3625,12 @@
 		 * to stay compatible with older ones...
 		 */
 		if (base == addr) {
-		    info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
-		    info->mmap_map[j].poff = __pa(base & PAGE_MASK);
-		    info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+		    info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
+		    info->mmap_map[j].poff = __pa((base+0x800000) & PAGE_MASK);
+		    info->mmap_map[j].size = 0x800000;
 		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
-		    info->mmap_map[j].prot_flag = _PAGE_E;
+		    info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
+		    size -= 0x800000;
 		    j++;
 		}
 
@@ -2842,13 +3639,14 @@
 		 * set for the big endian half of the framebuffer...
 		 */
 		if (base == addr) {
-		    info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
-		    info->mmap_map[j].poff = __pa((base+0x800000) & PAGE_MASK);
-		    info->mmap_map[j].size = 0x800000;
-		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
-		    info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
-		    size -= 0x800000;
-		    j++;
+			info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
+			info->mmap_map[j].poff = __pa((base + 0x800000)
+								& PAGE_MASK);
+			info->mmap_map[j].size = 0x800000;
+			info->mmap_map[j].prot_mask = _PAGE_CACHE;
+			info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
+			size -= 0x800000;
+			j++;
 		}
 
 		info->mmap_map[j].voff = pbase & PAGE_MASK;
@@ -2978,11 +3776,6 @@
 	    info->ati_regbase = (unsigned long)
 				ioremap(info->ati_regbase_phys, 0x1000);
 
-	    if(!info->ati_regbase) {
-		    kfree(info);
-		    return;
-	    }
-
 	    info->ati_regbase_phys += 0xc00;
 	    info->ati_regbase += 0xc00;
 
@@ -3005,11 +3798,6 @@
 	    info->frame_buffer_phys = addr;
 	    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
-	    if(!info->frame_buffer) {
-		    kfree(info);
-		    return;
-	    }
-
 #endif /* __sparc__ */
 
 	    if (!aty_init(info, "PCI")) {
@@ -3039,9 +3827,11 @@
 #endif /* __sparc__ */
 	}
     }
+
 #elif defined(CONFIG_ATARI)
-    int m64_num;
-    struct fb_info_aty *info;
+  u32   clock_r;
+  int   m64_num;
+  struct fb_info_aty *info;
 
     for (m64_num = 0; m64_num < mach64_count; m64_num++) {
 	if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
@@ -3063,9 +3853,27 @@
 	 *  kernel address space.
 	 */
 	info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
-	info->frame_buffer_phys = info->frame_buffer;
+	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
 	info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul;
-	info->ati_regbase_phys = info->ati_regbase;
+	info->ati_regbase_phys = info->ati_regbase;  /* Fake! */
+
+	aty_st_le32(CLOCK_CNTL, 0x12345678, info);
+	clock_r = aty_ld_le32(CLOCK_CNTL, info);
+
+	switch (clock_r & 0x003F) {
+	    case 0x12:
+		info->clk_wr_offset = 3;  /*  */
+		break;
+	    case 0x34:
+		info->clk_wr_offset = 2;  /* Medusa ST-IO ISA Adapter etc. */
+		break;
+	    case 0x16:
+		info->clk_wr_offset = 1;  /*  */
+		break;
+	    case 0x38:
+		info->clk_wr_offset = 0;  /* Panther 1 ISA Adapter (Gerald) */
+		break;
+	}
 
 	if (!aty_init(info, "ISA bus")) {
 	    kfree(info);
@@ -3073,7 +3881,8 @@
 	    return;
 	}
     }
-#endif
+#endif  /* CONFIG_ATARI */
+
 }
 
 #ifdef CONFIG_FB_OF
@@ -3114,13 +3923,6 @@
     info->ati_regbase_phys = 0x7ff000+addr;
     info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
 						   0x1000);
-
-    if(! info->ati_regbase) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
-	    kfree(info);
-	    return;
-    }
-
     info->ati_regbase_phys += 0xc00;
     info->ati_regbase += 0xc00;
 
@@ -3142,12 +3944,6 @@
     info->frame_buffer_phys = addr;
     info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
-    if(! info->frame_buffer) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
-	    kfree(info);
-	    return;
-    }
-
     if (!aty_init(info, dp->full_name)) {
 	kfree(info);
 	return;
@@ -3498,8 +4294,14 @@
     } else
 	direction |= DST_X_LEFT_TO_RIGHT;
 
-    wait_for_fifo(4, info);
+    wait_for_fifo(5, info);
     aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info);
+    /*
+     * ++Geert:
+     * Warning: SRC_OFF_PITCH may be thrashed by writing to other registers
+     * (e.g. CRTC_H_TOTAL_DISP, DP_SRC, DP_FRGD_CLR)
+     */
+    aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info);
     aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info);
     aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info);
     aty_st_le32(DST_CNTL, direction, info);

