Resent-Date: Sat, 26 Sep 1998 09:18:21 +0200 (MET DST)
Sender: bharries@germany.net
Date: Sat, 26 Sep 1998 01:12:56 +0200
From: Bernd Harries <bha@gmx.de>
Organization: BHA Industries
To: pstehlik@zln.cz, scott@dmi.stevens-tech.edu, Gerald_Haese@hro.maus.de
CC: orschied@kassandra.zx.basf-ag.de, linux-m68k@lists.linux-m68k.org
Subject: New atyfb.c patch
References: <000201bde7c4$bf0c42e0$0401a8c0@joy>
Resent-From: linux-m68k@phil.uni-sb.de

Hi!

I added some code to atyfb.c which is mainly disabled so far.
First only the code is enabled which prints info on the chips.
I would like to know if the DAC subtype is analyzed correctly 
on your boards. As I have a ATI 68860 DAC my subtype is probably 
0 anyway but you guys should have subtype 5, type 7 if all works 
as should. It may however be that the real dac subtype has to 
be read from the ROM. The clock type can also be read fromm 
ROM only. Tat is a problem on my card because I see only the 
even bytes of my ROM :-(. But since we all seem to have a 
ATI 18818 PLL we can simply leave it hardcoded in the ISA-GX 
case.

2nd I found out that the AT&T DAC wants to be setup according to 
the Dot clock and the depth. So someoneof you should try to dig 
into that because I donīt have the hardware. The code is mainly 
in but not enabled yet. I will try to find out why my DAC does
not want to be programmed.

--- drivers/video/atyfb.c_21120bha2	Wed Sep 23 00:12:56 1998
+++ drivers/video/atyfb.c	Sat Sep 26 00:25:33 1998
@@ -99,6 +99,16 @@
 #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           */
@@ -231,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;
@@ -362,25 +373,61 @@
 static void aty_set_pll_gx(const struct fb_info_aty *info,
 			   const struct pll_gx *pll);
 
-static void
-aty_set_dac_DAC_ATI68860_B(const struct fb_info_aty *info,
+static int
+aty_set_dac_ATI68860_B(
+  const struct fb_info_aty * info,
   u32 bpp,
   u32 AccelMode);
 
 static int
-aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll);
+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_pll_18818_to_var(const struct pll_18818 *pll, u32 *period_in_ps);
+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);
+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);
+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);
@@ -1193,8 +1240,9 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void
-aty_set_dac_DAC_ATI68860_B(const struct fb_info_aty *info,
+static int
+aty_set_dac_ATI68860_B(
+  const struct fb_info_aty * info,
   u32 bpp,
   u32 AccelMode)
 
@@ -1203,9 +1251,9 @@
   u32 gmr, dsra, temp, mask;
 
   /*-------------------------------------------------------------------------*/
-  printk(" aty_set_dac_DAC_ATI68860_B() bpp=$%02X \n", bpp);
+  printk(" aty_set_dac_ATI68860_B() bpp=$%02X    (still dummy) \n", bpp);
 
-  return;
+  return 0;
   
   gmr = 0;
   dsra = 0;
@@ -1213,26 +1261,27 @@
   switch(bpp)
   {
     case CRTC_PIX_WIDTH_8BPP:
-	gmr = 0x83;
-	dsra = 0x60 | 0x00  /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
-	break;
+      gmr = 0x83;
+      dsra = 0x60 | 0x00  /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
+      break;
     case CRTC_PIX_WIDTH_15BPP:
-	gmr = 0xA0;
-	dsra = 0x60;
-	break;
+      gmr = 0xA0;
+      dsra = 0x60;
+      break;
     case CRTC_PIX_WIDTH_16BPP:
-	gmr = 0xA1;
-	dsra = 0x60;
-	break;
+      gmr = 0xA1;
+      dsra = 0x60;
+      break;
     case CRTC_PIX_WIDTH_24BPP:
-	gmr = 0xC0;
-	dsra = 0x60;
-	break;
+      gmr = 0xC0;
+      dsra = 0x60;
+      break;
     case CRTC_PIX_WIDTH_32BPP:
-	gmr = 0xE3;
-	dsra = 0x60;
-	break;
+      gmr = 0xE3;
+      dsra = 0x60;
+      break;
   }
+  /*endswitch(bpp)*/
 
   if(!AccelMode)
   {
@@ -1255,7 +1304,7 @@
   else if (info->total_vram == MEM_SIZE_1M)
     mask = 0x08;
   else
-    mask = 0x0c;
+    mask = 0x0C;
 
   /* The following assumes that the BIOS has correctly set R7 of the
    * Device Setup Register A at boot time.
@@ -1267,9 +1316,87 @@
   temp = aty_ld_8(DAC_CNTL, info);
   aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info);
 
-  return;
+  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)
@@ -1616,7 +1743,7 @@
 
 
 static int
-aty_pll_18818_to_var(const struct pll_18818 *pll, u32 *period_in_ps)
+aty_pll_18818_to_var(const struct pll_18818 *pll, u32 * period_in_ps)
 {
 
   /*-------------------------------------------------------------------------*/
@@ -1626,10 +1753,11 @@
   return 0;
 }
 
+
 /*-------------------------------------------------------------------------*/
 
 static void
-aty_set_pll18818(const struct fb_info_aty *info, const struct pll_18818 *pll)
+aty_set_pll18818(const struct fb_info_aty *info, const struct pll_18818 * pll)
 
 /*-------------------------------------------------------------------------*/
 {
@@ -1698,6 +1826,458 @@
 }
 
 
+/*-------------------------------------------------------------------------*/
+
+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)
 {
     /*
@@ -2016,51 +2596,93 @@
 static void atyfb_set_par(const struct atyfb_par *par,
 			  struct fb_info_aty *info)
 {
-    u32 i;
+  u32   i;
+  int   accelmode;
+  int   muxmode;
+  u8    tmp;
+  
+  accelmode = par->accel_flags;  /* hack */
 
-    info->current_par = *par;
+  info->current_par = *par;
 
-    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);
+  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))
+  if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+  {
+    switch (info->dac_type)
     {
-      switch (info->dac_type)
+      case DAC_IBMRGB514:
       {
-	case DAC_IBMRGB514:
-	    aty_set_dac_514(info, par->crtc.bpp);
-	    break;
-        case DAC_ATI68860_B:
-        {
-          aty_set_dac_DAC_ATI68860_B(info, par->crtc.bpp, par->accel_flags);
-          break;
-        }
-        default:
-        {
-          printk(" atyfb_set_par: DAC type not implemented yet!");
-          break;
-        }
+	  aty_set_dac_514(info, par->crtc.bpp);
+	  break;
       }
-      /*endswitch*/
-      switch(info->clk_type)
+      case DAC_ATI68860_B:
       {
-        case CLK_ATI18818_1:
-          aty_set_pll18818(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;
-        }
+        muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp, accelmode);
+        break;
+      }
+      case DAC_ATT20C408:
+      {
+        muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, accelmode);
+        break;
       }
+      case DAC_ATT21C498:
+      {
+        muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, accelmode);
+        break;
+      }
+      default:
+      {
+        printk(" atyfb_set_par: DAC type not implemented yet!");
+        break;
+      }
+    }
+    /*endswitch*/
 
-	aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-	aty_st_le32(DAC_CNTL, 0x47052100, info);
-    } else {
+#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;
+      }
+    }
+
+      aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+      aty_st_le32(DAC_CNTL, 0x47052100, info);
+  } 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)))
@@ -2140,6 +2762,15 @@
       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;
@@ -2191,11 +2822,20 @@
     switch (info->clk_type)
     {
       case CLK_ATI18818_1:
-	  err = aty_pll_18818_to_var(&par->pll.ics2595, &var->pixclock);
-	  break;
+        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;
+        break;
     }
   }
     else
@@ -2702,18 +3342,19 @@
     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++)
+  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)
     {
-	if (aty_features[j].chip_type == Gx) {
-	    chipname = aty_features[j].name;
+      chipname = aty_features[j].name;
       info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
-	    break;
-	}
+      break;
     }
+  }
 
     if (!chipname) {
 	printk("atyfb: Unknown mach64 0x%04X\n", Gx);
@@ -2727,10 +3368,13 @@
 	/* FIXME: clockchip/RAMDAC probing? */
 #ifdef CONFIG_ATARI
 	info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
-        /* was: DAC_ATI68860_B; */
+	info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0)
+          | info->dac_type;
+	/* info->dac_subtype = DAC_ATT20C408; */
 	info->clk_type = CLK_ATI18818_1;
 #else
 	info->dac_type = DAC_IBMRGB514;
+	info->dac_subtype = DAC_INTERNAL;
 	info->clk_type = CLK_IBMRGB514;
 #endif
 	/* FIXME */
@@ -2870,9 +3514,10 @@
     info->ati_regbase,
     info->frame_buffer,
     info->total_vram);
-  printk(" types: bus=$%02X dac=$%02X ram=$%02X clk=$%02X? wr_offset=$%02lX \n",
+  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);

-- 
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-'___

