Resent-Date: Wed, 28 Apr 1999 21:09:48 +0200 (MET DST)
Sender: bharries@germany.net
Date: Wed, 28 Apr 1999 21:03:51 +0200
From: Bernd Harries <bha@gmx.de>
Organization: BHA Industries
To: linux-m68k@lists.linux-m68k.org
Subject: Re: 2.2.6 atyfb.c patch
References: <199904231758.TAA62202@rsplus04.cern.ch> <19990424145207.C2337@quango.watervalley.net> <19990425183054.A5089@localhost.watervalley.net> <19990425174828.B20693@schmitzm> <d37lqzalqc.fsf@rsplus04.cern.ch> <37249EE1.45867BE2@lbl.gov> <vyz3e1l17qz.fsf@issan.cs.uni-dortmund.de>
Resent-From: linux-m68k@phil.uni-sb.de

This is a multi-part message in MIME format.

--------------41788B605E01FEE5B8FA2C2
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit

Hi folks!

Hre is a patch for atyfb.c. It seems to fix atyfb.c enough to show the
penguin and the INIT 2.74 booting message on the fb console.

Later the system crashes but that has nothing to do with atyfb.c

I should now apply Andreas' patch, perhaps it helps.

Ciao,
-- 
Bernd Harries

bha@gmx.de            http://www.freeyellow.com/members/bharries
bernd@linux-m68k.org   Tel. +49 421 809 7351 priv.  | MSB First!
harries@stn-atlas.de        +49 421 457 3966 offi.  | Linux-m68k
bharries@vossnet.de                                 | Medusa T40

Here is how far it comes:

ABCEGHIJ
Linux version 2.2.6 (root@dose1) (gcc version 2.7.2.3) #4 Wed Apr 28
20:46:34 MEST 1999
Atari hardware found: ST_MFP TT_MFP TT_SCSI_DMA STND_DMA EXTD_DMA
TT_SCSI YM2149 CODEC SCC VME SCU IDE TT_CLK ACSI 
store_video_par() '0x7f400000;0x00400000;0x7F0B0000;accel' 
 stored them all: $7F400000 $00400000 $7F0B0000 
Console: colour dummy device 80x25
Calibrating delay loop... 19.92 BogoMIPS
Memory: 63292k/65536k available (1072k kernel code, 1116k data, 56k
init)
kmem_create: Forcing size word alignment - filp
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.2
Based upon Swansea University Computer Society NET3.039
kmem_create: Forcing size word alignment - skbuff_head_cache
NET4: Unix domain sockets 1.0 for Linux NET4.0.
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
Linux IP multicast router 0.06 plus PIM-SM
IPv6 v0.8 for NET4.0
IPv6 over IPv4 tunneling driver
early initialization of device sit0 is deferred
Initializing RT netlink socket
Starting kswapd v 1.5 
atyfb: mach64GX (ATI888GX00) [0x00d7 rev 0x01] 4M VRAM, 135 MHz PLL, 50
MHz MCLK
Console: switching to colour frame buffer device 80x30
fb0: ATY Mach64 frame buffer device on ISA bus
pty: 256 Unix98 ptys configured
Atari mouse installed.
Real Time Clock Driver v1.10
Non-volatile memory driver v1.2
Probing nvram size...  found 64 bytes
RAM disk driver initialized:  16 RAM disks of 4096K size
ide0: Falcon IDE interface
scsi0: options CAN_QUEUE=16 CMD_PER_LUN=8 SCAT-GAT=255 TAGGED-QUEUING=no
HOSTID=7 generic options AUTOSENSE REAL DMA SC
SI-2 TAGGED QUEUING generic release=7
scsi0 : Atari native SCSI
scsi : 1 host.
  Vendor: SyQuest   Model: SQ3270S           Rev: 3_04
  Type:   Direct-Access                      ANSI SCSI revision: 02
Detected scsi removable disk sda at scsi0, channel 0, id 0, lun 0
  Vendor: IBM       Model: DCAS-34330        Rev: S65A
  Type:   Direct-Access                      ANSI SCSI revision: 02
Detected scsi disk sdb at scsi0, channel 0, id 1, lun 0
  Vendor: SyQuest   Model: SQ5110            Rev: CHC 
  Type:   Direct-Access                      ANSI SCSI revision: 02
Detected scsi removable disk sdc at scsi0, channel 0, id 2, lun 0
  Vendor: MATSHITA  Model: CD-ROM CR-5XX     Rev: 1.0c
  Type:   CD-ROM                             ANSI SCSI revision: 01 CCS
Detected scsi CD-ROM sr0 at scsi0, channel 0, id 5, lun 0
scsi : detected 1 SCSI cdrom 3 SCSI disks total.
Uniform CDROM driver Revision: 2.54
SCSI device sda: hdwr sector= 512 bytes. Sectors= 524288 [256 MB] [0.3
GB]
sda: Write Protect is off
SCSI device sdb: hdwr sector= 512 bytes. Sectors= 8467200 [4134 MB] [4.1
GB]
SCSI device sdc: hdwr sector= 512 bytes. Sectors= 173456 [84 MB] [0.1
GB]
sdc: Write Protect is off
eth0: Riebl-Card (with battery) at io 0xfe00fff0, mem 0xfe010000, irq
56, hwaddr 00:00:36:04:01:e8
atarilance.c: v1.3 04/04/96 Roman.Hodek@informatik.uni-erlangen.de
Partition check:
 sda: AHDI sda1 sda2
 sdb: AHDI sdb1 sdb2 sdb3 sdb4
 sdc: AHDI sdc1
Probing ACSI devices:
Found 0 ACSI device(s) total.
VFS: Mounted root (ext2 filesystem) readonly.
Unable to handle kernel access at virtual address a8b800a4
Oops: 00000000
PC: [<00006cb8>]
SR: 2700  SP: 03edd810  a2: 03edc000
d0: 0000002d    d1: 09420003    d2: 00000009    d3: 00000000
d4: 00002318    d5: 00000008    a0: a8b80000    a1: 00000009
Process ¨\ (pid: -1481375744, stackpage=03edd000)
Frame format=7 eff addr=03edd8a0 ssw=0505 faddr=a8b800a4

--------------41788B605E01FEE5B8FA2C2
Content-Type: application/octet-stream; name="atyfb.c_226.diff.gz"
Content-Transfer-Encoding: x-uuencode
Content-Disposition: attachment; filename="atyfb.c_226.diff.gz"

--- drivers/video/atyfb.c_226	Sun Mar 28 16:51:17 1999
+++ drivers/video/atyfb.c	Wed Apr 28 20:46:09 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,
@@ -437,7 +506,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)" },
@@ -446,11 +515,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)" },
@@ -963,23 +1031,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);
@@ -1158,7 +1222,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;
@@ -1169,6 +1234,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 {
@@ -1350,9 +1533,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 */
@@ -1366,7 +1546,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
@@ -1410,15 +1592,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)
 {
@@ -1450,7 +2106,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)
 {
@@ -1481,9 +2172,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
@@ -1506,9 +2198,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 {
@@ -1704,27 +2395,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;
@@ -1812,7 +2564,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);
@@ -1821,6 +2582,7 @@
     else
 	err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp,
 				&par->pll.ct);
+
     if (err)
 	return err;
 
@@ -1848,7 +2610,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)
@@ -1943,15 +2721,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;
@@ -2021,41 +2799,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;
+    }
 }
 
 
@@ -2323,6 +3101,10 @@
 	if (!map_size)
 		return -EINVAL;
 
+	/*
+	vma->vm_file = file;
+	file->f_count++;
+	*/
 	vma->vm_flags |= VM_IO;
 
 	if (!fb->mmaped) {
@@ -2436,6 +3218,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) {
@@ -2449,10 +3232,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 */
@@ -2463,6 +3252,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;
@@ -2499,11 +3289,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;
@@ -2516,9 +3306,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:
@@ -2593,7 +3385,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);
 
@@ -2666,9 +3458,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));
@@ -2951,11 +3743,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;
 
@@ -2978,11 +3765,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")) {
@@ -3012,9 +3794,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] ||
@@ -3036,9 +3820,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);
@@ -3046,7 +3848,8 @@
 	    return;
 	}
     }
-#endif
+#endif  /* CONFIG_ATARI */
+
 }
 
 #ifdef CONFIG_FB_OF
@@ -3087,13 +3890,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;
 
@@ -3115,12 +3911,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;
@@ -3471,8 +4261,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);

--------------41788B605E01FEE5B8FA2C2--

