Resent-Date: Tue, 13 Oct 1998 22:30:11 +0200 (MET DST)
Sender: bharries@vossnet.de
Date: Tue, 13 Oct 1998 21:43:03 +0200
From: Bernd Harries <bha@gmx.de>
Organization: BHA Industries
To: linux-m68k@lists.linux-m68k.org
Subject: Re: 2.1.124 patch f. drivers/video/atyfb.c
References: <199810081817.UAA08558@valhall.cern.ch> <3620D0FD.14C1C634@gmx.de> <d3ww662roa.fsf@valhall.cern.ch> <3621DC0C.167E@gmx.de> <d37ly62aj1.fsf@valhall.cern.ch>
Resent-From: linux-m68k@phil.uni-sb.de

Jes Sorensen wrote:

> We do know that you know how to use a C compiler .....
Pssst, don't tell anybody...

Indeed I managed by chance to compile 2.1.124 on my Medusa and on the
x86 box. The sources were identical (geert's and my patch applied,
otherwise atyfb.c won't link ( eieio(); ))

What I am wondering about is the different sizes of the results:

m68k:
-rwxr-xr-x   1 root     system    1581500 Oct 13 20:24 vmlinux*
-rw-r--r--   1 root     system     727703 Oct 13 20:25 vmlinux.gz
Hexe:/usr/src/linux-2.1.124_JES/>

ABCDFJLMN
Linux version 2.1.124 (root@Hexe) (gcc version 2.7.2.3) #4 Tue Oct 13
20:13:45 MEST 1998
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' 



x86-m68k-cross:
-rwxr-xr-x   1 root     root      1582248 Oct 13 20:17 vmlinux*
-rw-r--r--   1 root     root       727687 Oct 13 20:17 vmlinux.gz
dose1:/usr/src/linux-2.1.124_JES/>

ABCDFJLMN
Linux version 2.1.124 (root@dose1) (gcc version 2.7.2.3) #5 Tue Oct 13
20:14:08 MEST 1998
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' 

Any clues?

Ok! Here comes what I am really working on. IIRC Geert, Andreas and Kars
had posted 2.1.124-patches before. So I numbered mine as 04-...
But it is not important in this case.

--- drivers/video/atyfb.c_21124	Sun Oct 11 13:23:08 1998
+++ drivers/video/atyfb.c	Tue Oct 13 20:05:35 1998
@@ -85,8 +85,34 @@
  */
 #undef PLL_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__
@@ -122,6 +148,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;
@@ -144,6 +178,7 @@
     union {
 	struct pll_gx gx;
 	struct pll_ct ct;
+        struct pll_18818 ics2595;
     } pll;
     u32 accel_flags;
 };
@@ -189,6 +224,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;
@@ -205,6 +241,7 @@
     u8 bus_type;
     u8 ram_type;
     u8 dac_type;
+    u8 dac_subtype;
     u8 clk_type;
     u8 mem_refresh_rate;
     struct display disp;
@@ -335,7 +372,64 @@
 			   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,
@@ -420,7 +514,7 @@
     const char *name;
 } aty_features[] __initdata = {
     /* mach64GX family */
-    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
+    { 0x4758, 0x00D7, "mach64GX (ATI888GX00)" },
     { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
 
     /* mach64CT family */
@@ -948,7 +1042,7 @@
 #else
 #ifdef __BIG_ENDIAN
 	addr = fb->frame_buffer_phys - 0x800000 + cursor->offset;
-	cursor->ram = (u8 *)ioremap(addr, 1024);
+/*	cursor->ram = (u8 *)ioremap(addr, 1024);  */
 #else
 	addr = fb->frame_buffer + cursor->offset;
 	cursor->ram = (u8 *)addr;
@@ -1111,8 +1205,11 @@
     } else
 	FAIL("invalid bpp");
 
-    if (vxres*vyres*bpp/8 > info->total_vram)
+    if (vxres * vyres * bpp / 8 > info->total_vram)
+    {
+      printk(" vxres=%d vyres=%d bpp=%d \n", vxres, vyres, bpp);
 	FAIL("not enough video RAM");
+    }
 
     if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
 	FAIL("invalid vmode");
@@ -1144,6 +1241,169 @@
     return 0;
 }
 
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+aty_set_dac_ATI68860_B(
+  const struct fb_info_aty * info,
+  u32 bpp,
+  u32 AccelMode)
+
+/*-------------------------------------------------------------------------*/
+{
+  u32 gmr, dsra, temp, mask;
+
+  /*-------------------------------------------------------------------------*/
+  printk(" aty_set_dac_ATI68860_B() bpp=$%02X    (still dummy) \n", bpp);
+
+  return 0;
+  
+  gmr = 0;
+  dsra = 0;
+  
+  switch(bpp)
+  {
+    case CRTC_PIX_WIDTH_8BPP:
+      gmr = 0x83;
+      dsra = 0x60 | 0x00  /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
+      break;
+    case CRTC_PIX_WIDTH_15BPP:
+      gmr = 0xA0;
+      dsra = 0x60;
+      break;
+    case CRTC_PIX_WIDTH_16BPP:
+      gmr = 0xA1;
+      dsra = 0x60;
+      break;
+    case CRTC_PIX_WIDTH_24BPP:
+      gmr = 0xC0;
+      dsra = 0x60;
+      break;
+    case CRTC_PIX_WIDTH_32BPP:
+      gmr = 0xE3;
+      dsra = 0x60;
+      break;
+  }
+  /*endswitch(bpp)*/
+
+  if(!AccelMode)
+  {
+    gmr = 0x80;
+    dsra = 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, gmr, 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, (dsra | 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;
+
+  /*-------------------------------------------------------------------------*/
+  printk(" aty_set_dac_ATT21C498() bpp=$%02X    (still dummy) \n", bpp);
+
+  return muxmode;
+
+  dotClock = 100000000 / pll->period_in_ps;
+
+  switch(bpp)
+  {
+    case CRTC_PIX_WIDTH_8BPP:
+      if (dotClock > 8000)
+      {
+        DACMask = 0x24;
+        muxmode = 1;
+      }
+      else
+      {
+        DACMask = 0x04;
+      }
+      break;
+    case CRTC_PIX_WIDTH_15BPP:
+      DACMask = 0x16;
+      break;
+    case CRTC_PIX_WIDTH_16BPP:
+      DACMask = 0x36;
+      break;
+    case CRTC_PIX_WIDTH_24BPP:
+      DACMask = 0xE6;
+      break;
+    case CRTC_PIX_WIDTH_32BPP:
+      DACMask = 0xE6;
+      break;
+  }
+  /*endswitch(bpp)*/
+
+  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 {
@@ -1325,9 +1585,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 */
@@ -1341,13 +1598,20 @@
     }
 }
 
-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) /* in Picosec */
+
+/*-------------------------------------------------------------------------*/
 {
     /*
      *  FIXME: use real calculations instead of using fixed values from the old
      *	       driver
      */
-    static struct {
+    static struct
+    {
 	u32 ps_lim;	/* pixclock period rounding limit (arbitrary) */
 	u8 mode;	/* (prescsaler << 4) | Select */
 	u8 prog;	/* ref_div_count */
@@ -1385,16 +1649,640 @@
     };
     int set;
 
+  /*-------------------------------------------------------------------------*/
+
+    printk("aty_select_pll_18818() $%08X\n", vclk_period);
+    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;
+            printk(" m=$%02X n=%X \n", pll->m, pll->n);
 	    return 0;
 	}
+
+  return -EINVAL;
+}
+#endif  /* BHA_NEVER */
+
+/*-------------------------------------------------------------------------*/
+
+static int
+aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll) /* in Picosec */
+
+/*-------------------------------------------------------------------------*/
+{
+  u32     MHz100;                 /* in 0.01 MHz */
+  u32     program_bits;
+  u32     post_divider;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_var_to_pll_18818() $%08X\n", period_in_ps); */
+
+  /* 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;
+    }
+  }
+  /*endif*/
+  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;
+      }
+    }
+    /*endswitch(post_divider)*/
+  }
+
+  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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_set_pll18818(): program_bits=$%08X locationAddr=$%08X\n",
+    pll->program_bits, pll->locationAddr); */
+
+  old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+  /* printk(" old_clock_cntl=$%08X\n", old_clock_cntl); */
+  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;
+
+  /* Turn off interrupts */
+  /*(void)xf86DisableInterrupts(); */
+
+  /* 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;
+  }
+
+  /* Enable interrupts */
+  /*(void)xf86EnableInterrupts();*/
+
+  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) /* in Picosec */
+
+/*-------------------------------------------------------------------------*/
+{
+  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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_var_to_pll_408() $%08X\n", period_in_ps); */
+
+  /* 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;
+  }
+  /*endif*/
+
+  pll->program_bits = program_bits;
+  pll->locationAddr = 0;
+  pll->post_divider = divider;  /* fuer nix */
+  pll->period_in_ps = period_in_ps;
+
+  return 0;
+}
+/*endproc aty_var_to_pll_408*/
+
+
+/*-------------------------------------------------------------------------*/
+
+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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_set_pll_408(): program_bits=$%08X locationAddr=$%08X\n",
+    pll->program_bits, pll->locationAddr); */
+
+  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;
+}
+/*endproc aty_set_pll_408*/
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll) /* in Picosec */
+
+/*-------------------------------------------------------------------------*/
+{
+  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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_var_to_pll_1703() $%08X\n", period_in_ps); */
+
+  /* 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;
+  }
+  /*endif*/
+
+  pll->program_bits = program_bits;
+  pll->locationAddr = 0;
+  pll->post_divider = divider;  /* fuer nix */
+  pll->period_in_ps = period_in_ps;
+
+  return 0;
+}
+/*endproc aty_var_to_pll_1703*/
+
+
+/*-------------------------------------------------------------------------*/
+
+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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_set_pll_408(): program_bits=$%08X locationAddr=$%08X\n",
+    pll->program_bits, pll->locationAddr); */
+
+  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;
+}
+/*endproc aty_set_pll_1703*/
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll) /* in Picosec */
+
+/*-------------------------------------------------------------------------*/
+{
+  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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_var_to_pll_8398() $%08X\n", period_in_ps); */
+
+  /* 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;
+	}
+      }
+      /*next n*/
+    }
+    /*next m*/
+
+    program_bits = (k << 6) + (save_m) + (save_n << 8);
+  }
+  /*endif*/
+
+  pll->program_bits = program_bits;
+  pll->locationAddr = 0;
+  pll->post_divider = 0;
+  pll->period_in_ps = period_in_ps;
+
+  return 0;
+}
+/*endproc aty_var_to_pll_8398*/
+
+
+/*-------------------------------------------------------------------------*/
+
+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;
+
+  /*-------------------------------------------------------------------------*/
+  /* printk("aty_set_pll_8398(): program_bits=$%08X locationAddr=$%08X\n",
+    pll->program_bits, pll->locationAddr); */
+
+  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;
+}
+/*endproc aty_set_pll_8398*/
+
+
+
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll)
 {
     /*
@@ -1425,7 +2313,50 @@
     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)
 {
@@ -1670,27 +2601,101 @@
 static void atyfb_set_par(const struct atyfb_par *par,
 			  struct fb_info_aty *info)
 {
-    u32 i;
-
-    info->current_par = *par;
-
-    aty_set_crtc(info, &par->crtc);
-    aty_st_8(CLOCK_CNTL, 0, info);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
-
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
-	switch (info->dac_type) {
-	    case DAC_IBMRGB514:
-		aty_set_dac_514(info, par->crtc.bpp);
-		break;
-	    case DAC_ATI68860_B:
-		/* FIXME */
-		break;
-	}
-	aty_set_pll_gx(info, &par->pll.gx);
-	aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-	aty_st_le32(DAC_CNTL, 0x47052100, info);
-    } else {
+  u32   i;
+  int   accelmode;
+  int   muxmode;
+  u8    tmp;
+  
+  accelmode = par->accel_flags;  /* hack */
+
+  info->current_par = *par;
+
+  tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+  aty_set_crtc(info, &par->crtc);
+  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_subtype)
+    {
+      case DAC_IBMRGB514:
+      {
+	  aty_set_dac_514(info, par->crtc.bpp);
+	  break;
+      }
+      case DAC_ATI68860_B:
+      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;
+      }
+      case DAC_ATT20C408:
+      {
+        muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, accelmode);
+        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, accelmode);
+        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);
+        break;
+      }
+    }
+    /*endswitch*/
+
+#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;
+      }
+    }
+  }
+  else 
+  {
 	aty_set_pll_ct(info, &par->pll.ct);
 	i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
 	if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
@@ -1757,21 +2762,50 @@
     int err;
 
     if ((err = aty_var_to_crtc(info, var, &par->crtc)))
-	return err;
-    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);
-		break;
-	    case CLK_IBMRGB514:
-		err = aty_var_to_pll_514(var->pixclock, &par->pll.gx);
-		break;
-	}
-    else
-	err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp,
-				&par->pll.ct);
-    if (err)
-	return err;
+  {
+    printk(" aty_var_to_crtc failed! \n");
+    return err;
+  }
+
+  if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))  /* why was here *_PCI_ID ?? */
+  {
+    /* printk(" GX / CX \n"); */
+    switch (info->clk_type)
+    {
+      case CLK_ATI18818_1:
+        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);
+	break;
+    }
+  }
+  else if (Gx == CT_CHIP_ID) 
+  {
+    printk(" CT \n");
+    err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp, &par->pll.ct);
+  }
+  else
+  {
+    printk(" chip_type=$%04X ?????\n", Gx);
+
+    err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp, &par->pll.ct);
+  }
+
+  if (err)
+  {
+    printk(" aty_var_to_pll failed! \n");
+    return err;
+  }
 
     if (var->accel_flags & FB_ACCELF_TEXT)
 	par->accel_flags = FB_ACCELF_TEXT;
@@ -1796,8 +2830,27 @@
 
     if ((err = aty_crtc_to_var(&par->crtc, var)))
 	return err;
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+  if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+  {
+    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)
@@ -2295,7 +3348,9 @@
      *  Initialisation
      */
 
-__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
+__initfunc(
+static int
+aty_init(struct fb_info_aty *info, const char *name))
 {
     u32 chip_id;
     u32 i;
@@ -2308,29 +3363,45 @@
     int sense;
 #endif
 
-    info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
-    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
-    Gx = chip_id & CFG_CHIP_TYPE;
-    Rev = (chip_id & CFG_CHIP_REV)>>24;
-    for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
-	if (aty_features[j].chip_type == Gx) {
-	    chipname = aty_features[j].name;
-	    break;
-	}
+  info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
+  chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+  Gx = chip_id & CFG_CHIP_TYPE;
+  Rev = (chip_id & CFG_CHIP_REV)>>24;
+  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) {
-	printk("atyfb: Unknown mach64 0x%04x\n", Gx);
+	printk("atyfb: Unknown mach64 0x%04X\n", Gx);
 	return 0;
     } else
-	printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, Gx, Rev);
+	printk("atyfb: %s [0x%04X rev 0x%02X] ", chipname, Gx, Rev);
+
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
 	info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
 	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
 	/* 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(DAC_CNTL, info) >> 16) & 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 */
@@ -2340,6 +3411,7 @@
 	info->bus_type = PCI;
 	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
 	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;
@@ -2425,7 +3497,7 @@
 	    default:
 		info->total_vram = 0x80000;
 	}
-    else
+    else   /* not GT-chip */
 	switch (i & MEM_SIZE_ALIAS) {
 	    case MEM_SIZE_512K:
 		info->total_vram = 0x80000;
@@ -2448,6 +3520,7 @@
 	    default:
 		info->total_vram = 0x80000;
 	}
+  /*endif(GT-chip)*/
 
     if (Gx == GI_CHIP_ID) {
 	if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000)
@@ -2459,10 +3532,26 @@
     	   info->total_vram == 0x80000 ? 'K' : 'M', pll, mclk);
     
     if (info->bus_type == ISA)
+    {
 	if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
 	    /* protect GUI-regs if complete Aperture is VRAM */
 	    info->total_vram -= GUI_RESERVE;
 	}
+#if 1
+  printk(" aty_init: regbase=$%08lX, frame_buffer=$%08lX, total_vram=$%08X\n",
+    info->ati_regbase,
+    info->frame_buffer,
+    info->total_vram);
+  printk(" types: bus=$%02X dac=$%02X dacsub=$%02X ram=$%02X clk=$%02X? wr_offset=$%02lX \n",
+    info->bus_type,
+    info->dac_type,
+    info->dac_subtype,
+    info->ram_type,
+    info->clk_type,
+    info->clk_wr_offset);
+#endif
+
+    }
 
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
     if (default_vmode == VMODE_NVRAM) {
@@ -2544,16 +3633,21 @@
 	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
     return 1;
 }
+/*endproc aty_init()*/
+
 
 __initfunc(void atyfb_init(void))
 {
+
 #if defined(CONFIG_FB_OF)
     /* We don't want to be called like this. */
     /* We rely on Open Firmware (offb) instead. */
+
 #elif defined(CONFIG_PCI)
     struct pci_dev *pdev;
     struct fb_info_aty *info;
     unsigned long addr;
+
 #ifdef __sparc__
     extern int con_is_present(void);
     struct pcidev_cookie *pcp;
@@ -2780,9 +3874,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] ||
@@ -2806,10 +3902,38 @@
 	info->frame_buffer = kernel_map(phys_vmembase[m64_num],
 					phys_size[m64_num],
 					KERNELMAP_NOCACHE_SER, NULL);
-	info->frame_buffer_phys = info->frame_buffer;
+	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
 	info->ati_regbase = kernel_map(phys_guiregbase[m64_num], 0x10000,
 				       KERNELMAP_NOCACHE_SER, NULL)+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;
+          }
+        }
+        /*endswitch*/
 
 	if (!aty_init(info, "ISA bus")) {
 	    kfree(info);
@@ -2817,8 +3941,10 @@
 	    return;
 	}
     }
-#endif
+#endif  /* defined(CONFIG_ATARI) */
+
 }
+/*endproc atyfb_init()*/
 
 #ifdef CONFIG_FB_OF
 __initfunc(void atyfb_of_init(struct device_node *dp))

-- 
Bernd Harries

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

