150806d53Smrg/*
250806d53Smrg * Copyright 1996-2000 by Robin Cutshaw <robin@XFree86.Org>
350806d53Smrg *
450806d53Smrg * Permission to use, copy, modify, distribute, and sell this software and its
550806d53Smrg * documentation for any purpose is hereby granted without fee, provided that
650806d53Smrg * the above copyright notice appear in all copies and that both that
750806d53Smrg * copyright notice and this permission notice appear in supporting
850806d53Smrg * documentation, and that the name of Robin Cutshaw not be used in
950806d53Smrg * advertising or publicity pertaining to distribution of the software without
1050806d53Smrg * specific, written prior permission.  Robin Cutshaw makes no representations
1150806d53Smrg * about the suitability of this software for any purpose.  It is provided
1250806d53Smrg * "as is" without express or implied warranty.
1350806d53Smrg *
1450806d53Smrg * ROBIN CUTSHAW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1550806d53Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1650806d53Smrg * EVENT SHALL ROBIN CUTSHAW BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1750806d53Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1850806d53Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1950806d53Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2050806d53Smrg * PERFORMANCE OF THIS SOFTWARE.
2150806d53Smrg *
2250806d53Smrg */
2350806d53Smrg
2450806d53Smrg
2550806d53Smrg#ifdef HAVE_CONFIG_H
2650806d53Smrg#include "config.h"
2750806d53Smrg#endif
2850806d53Smrg
2950806d53Smrg#include "xf86.h"
3050806d53Smrg#include "xf86Pci.h"
3150806d53Smrg#include "cursorstr.h"
3250806d53Smrg#include "servermd.h"
3350806d53Smrg
3450806d53Smrg#include "i128.h"
3550806d53Smrg#include "i128reg.h"
3650806d53Smrg#include "IBMRGB.h"
3750806d53Smrg
387965d9acSmrg#include <unistd.h>
3950806d53Smrg
4050806d53Smrgstatic void I128IBMShowCursor(ScrnInfoPtr pScrn);
4150806d53Smrgstatic void I128IBMHideCursor(ScrnInfoPtr pScrn);
4250806d53Smrgstatic void I128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
4350806d53Smrgstatic void I128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
4450806d53Smrgstatic void I128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
4550806d53Smrgstatic Bool I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs);
4650806d53Smrg
4750806d53Smrg
4850806d53SmrgBool
4950806d53SmrgI128IBMHWCursorInit(ScrnInfoPtr pScrn)
5050806d53Smrg{
5150806d53Smrg   xf86CursorInfoPtr infoPtr;
52a73423d7Smrg   ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
5350806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
5450806d53Smrg
5550806d53Smrg   if (!pI128->HWCursor)
5650806d53Smrg      return FALSE;
5750806d53Smrg
5850806d53Smrg   infoPtr = xf86CreateCursorInfoRec();
5950806d53Smrg   if (!infoPtr) return FALSE;
6050806d53Smrg
6150806d53Smrg   pI128->CursorInfoRec = infoPtr;
6250806d53Smrg   infoPtr->MaxWidth = 64;
6350806d53Smrg   infoPtr->MaxHeight = 64;
6450806d53Smrg   infoPtr->SetCursorColors = I128IBMSetCursorColors;
6550806d53Smrg   infoPtr->SetCursorPosition = I128IBMSetCursorPosition;
6650806d53Smrg   infoPtr->LoadCursorImage = I128IBMLoadCursorImage;
6750806d53Smrg   infoPtr->HideCursor = I128IBMHideCursor;
6850806d53Smrg   infoPtr->ShowCursor = I128IBMShowCursor;
6950806d53Smrg   infoPtr->UseHWCursor = I128IBMUseHWCursor;
7050806d53Smrg   infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
7150806d53Smrg                    HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
7250806d53Smrg                    HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1;
7350806d53Smrg
74af1a9c97Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
75af1a9c97Smrg   infoPtr->Flags |= HARDWARE_CURSOR_NIBBLE_SWAPPED;
76af1a9c97Smrg#endif
7750806d53Smrg
78af1a9c97Smrg   return(xf86InitCursor(pScreen, infoPtr));
7950806d53Smrg}
8050806d53Smrg
8150806d53Smrg
8250806d53Smrgstatic void
8350806d53SmrgI128IBMShowCursor(ScrnInfoPtr pScrn)
8450806d53Smrg{
8550806d53Smrg   CARD32 tmpl, tmph;
8650806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
8750806d53Smrg
8850806d53Smrg   /* Enable cursor - X11 mode */
8950806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
9050806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
9150806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
9250806d53Smrg   pI128->mem.rbase_g[IDXH_I] = 0;					MB;
9350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs;				MB;
9450806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x27;					MB;
9550806d53Smrg
9650806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
9750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
9850806d53Smrg
9950806d53Smrg   return;
10050806d53Smrg}
10150806d53Smrg
10250806d53Smrgstatic void
10350806d53SmrgI128IBMHideCursor(ScrnInfoPtr pScrn)
10450806d53Smrg{
10550806d53Smrg   CARD32 tmpl, tmph, tmp1;
10650806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
10750806d53Smrg
10850806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
10950806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
11050806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
11150806d53Smrg   pI128->mem.rbase_g[IDXH_I] = 0;					MB;
11250806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs;				MB;
11350806d53Smrg   tmp1 = pI128->mem.rbase_g[DATA_I] & 0xFC;
11450806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp1;					MB;
11550806d53Smrg
11650806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
11750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
11850806d53Smrg
11950806d53Smrg   return;
12050806d53Smrg}
12150806d53Smrg
12250806d53Smrgstatic void
12350806d53SmrgI128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
12450806d53Smrg{
12550806d53Smrg   CARD32 tmpl, tmph;
12650806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
12750806d53Smrg
12850806d53Smrg   x += 64;
12950806d53Smrg   y += 64;
13050806d53Smrg
13150806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
13250806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
13350806d53Smrg
13450806d53Smrg   pI128->mem.rbase_g[IDXH_I] = 0;					MB;
13550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x;			MB;
13650806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x3F;					MB;
13750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y;			MB;
13850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x3F;					MB;
13950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl;				MB;
14050806d53Smrg   pI128->mem.rbase_g[DATA_I] = x & 0xFF;				MB;
14150806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh;				MB;
14250806d53Smrg   pI128->mem.rbase_g[DATA_I] = (x >> 8) & 0x0F;			MB;
14350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl;				MB;
14450806d53Smrg   pI128->mem.rbase_g[DATA_I] = y & 0xFF;				MB;
14550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh;				MB;
14650806d53Smrg   pI128->mem.rbase_g[DATA_I] = (y >> 8) & 0x0F;			MB;
14750806d53Smrg
14850806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
14950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
15050806d53Smrg
15150806d53Smrg   return;
15250806d53Smrg}
15350806d53Smrg
15450806d53Smrgstatic void
15550806d53SmrgI128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
15650806d53Smrg{
15750806d53Smrg   CARD32 tmp;
15850806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
15950806d53Smrg
16050806d53Smrg   tmp = pI128->mem.rbase_g[IDXL_I] & 0xFF;
16150806d53Smrg
16250806d53Smrg   /* Background color */
16350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_r;			MB;
16450806d53Smrg   pI128->mem.rbase_g[DATA_I] = (bg & 0x00FF0000) >> 16;		MB;
16550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_g;			MB;
16650806d53Smrg   pI128->mem.rbase_g[DATA_I] = (bg & 0x0000FF00) >> 8;			MB;
16750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_b;			MB;
16850806d53Smrg   pI128->mem.rbase_g[DATA_I] = (bg & 0x000000FF);			MB;
16950806d53Smrg
17050806d53Smrg   /* Foreground color */
17150806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_r;			MB;
17250806d53Smrg   pI128->mem.rbase_g[DATA_I] = (fg & 0x00FF0000) >> 16;		MB;
17350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_g;			MB;
17450806d53Smrg   pI128->mem.rbase_g[DATA_I] = (fg & 0x0000FF00) >> 8;			MB;
17550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_b;			MB;
17650806d53Smrg   pI128->mem.rbase_g[DATA_I] = (fg & 0x000000FF);			MB;
17750806d53Smrg
17850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmp;					MB;
17950806d53Smrg
18050806d53Smrg   return;
18150806d53Smrg}
18250806d53Smrg
18350806d53Smrgstatic void
18450806d53SmrgI128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
18550806d53Smrg{
18650806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
18750806d53Smrg   register int   i;
18850806d53Smrg   CARD32 tmph, tmpl, tmpc;
18950806d53Smrg
19050806d53Smrg   tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
19150806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
19250806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
19350806d53Smrg
19450806d53Smrg   pI128->BlockCursor = TRUE;
19550806d53Smrg
19650806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
19750806d53Smrg
19850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x;			MB;
19950806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
20050806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y;			MB;
20150806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
20250806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl;				MB;
20350806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0xFF;					MB;
20450806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh;				MB;
20550806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x7F;					MB;
20650806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl;				MB;
20750806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0xFF;					MB;
20850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh;				MB;
20950806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x7F;					MB;
21050806d53Smrg
21150806d53Smrg   pI128->mem.rbase_g[IDXH_I] = (IBMRGB_curs_array >> 8) & 0xFF;	MB;
21250806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_array & 0xFF;		MB;
21350806d53Smrg
21450806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 1; /* enable auto-inc */		MB;
21550806d53Smrg
21650806d53Smrg   /*
21750806d53Smrg    * Output the cursor data.  The realize function has put the planes into
21850806d53Smrg    * their correct order, so we can just blast this out.
21950806d53Smrg    */
22050806d53Smrg   for (i = 0; i < 1024; i++,src++) {
22150806d53Smrg      pI128->mem.rbase_g[DATA_I] = (CARD32 )*src;			MB;
22250806d53Smrg   }
22350806d53Smrg
22450806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = tmpc;                                 MB;
22550806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;                                   MB;
22650806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;                                   MB;
22750806d53Smrg
22850806d53Smrg   pI128->BlockCursor = FALSE;
22950806d53Smrg
23050806d53Smrg   return;
23150806d53Smrg}
23250806d53Smrg
23350806d53Smrg
23450806d53Smrgstatic Bool
23550806d53SmrgI128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs)
23650806d53Smrg{
23750806d53Smrg   if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN )
23850806d53Smrg      return FALSE;
23950806d53Smrg   return TRUE;
24050806d53Smrg}
24150806d53Smrg
24250806d53Smrg
24350806d53SmrgBool I128TIHWCursorInit(ScrnInfoPtr pScrn) { return FALSE; }
24450806d53SmrgBool I128ProgramTi3025(ScrnInfoPtr pScrn, DisplayModePtr mode) { return FALSE; }
24550806d53Smrg
24650806d53SmrgBool
24750806d53SmrgI128ProgramIBMRGB(ScrnInfoPtr pScrn, DisplayModePtr mode)
24850806d53Smrg{
24950806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
25050806d53Smrg   unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n;
25150806d53Smrg   CARD32 tmpl, tmph, tmpc;
25250806d53Smrg   long f, vrf, outf, best_diff, best_outf = 0, diff;
25350806d53Smrg   long requested_freq;
25450806d53Smrg   int   freq = mode->SynthClock;
25550806d53Smrg   int   flags = mode->Flags;
25650806d53Smrg
25750806d53Smrg#define REF_FREQ	 25175000
25850806d53Smrg#define MAX_VREF	  3380000
25950806d53Smrg/* Actually, MIN_VREF can be as low as 1000000;
26050806d53Smrg * this allows clock speeds down to 17 MHz      */
26150806d53Smrg#define MIN_VREF	  1500000
26250806d53Smrg#define MAX_VCO		220000000
26350806d53Smrg#define MIN_VCO		 65000000
26450806d53Smrg
26550806d53Smrg   if (freq < 25000) {
26650806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
26750806d53Smrg              "Specified dot clock (%.3f) too low for IBM RGB52x",
26850806d53Smrg	      freq / 1000.0);
26950806d53Smrg       return(FALSE);
27050806d53Smrg   } else if (freq > MAX_VCO) {
27150806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
27250806d53Smrg              "Specified dot clock (%.3f) too high for IBM RGB52x",
27350806d53Smrg	      freq / 1000.0);
27450806d53Smrg       return(FALSE);
27550806d53Smrg   }
27650806d53Smrg
27750806d53Smrg   requested_freq = freq * 1000;
27850806d53Smrg
27950806d53Smrg   best_m = best_n = best_df = 0;
28050806d53Smrg   best_diff = requested_freq;  /* worst case */
28150806d53Smrg
28250806d53Smrg   for (df=0; df<4; df++) {
28350806d53Smrg   	max_n = REF_FREQ / MIN_VREF;
28450806d53Smrg   	if (df < 3)
28550806d53Smrg   		max_n >>= 1;
28650806d53Smrg	for (n=2; n<max_n; n++)
28750806d53Smrg		for (m=65; m<=128; m++) {
28850806d53Smrg			vrf = REF_FREQ / n;
28950806d53Smrg			if (df < 3)
29050806d53Smrg				vrf >>= 1;
29150806d53Smrg			if ((vrf > MAX_VREF) || (vrf < MIN_VREF))
29250806d53Smrg				continue;
29350806d53Smrg
29450806d53Smrg			f = vrf * m;
29550806d53Smrg			outf = f;
29650806d53Smrg			if (df < 2)
29750806d53Smrg				outf >>= 2 - df;
29850806d53Smrg			if ((f > MAX_VCO) || (f < MIN_VCO))
29950806d53Smrg				continue;
30050806d53Smrg
30150806d53Smrg			/* outf is a valid freq, pick the closest now */
30250806d53Smrg
30350806d53Smrg			if ((diff = (requested_freq - outf)) < 0)
30450806d53Smrg				diff = -diff;;
30550806d53Smrg			if (diff < best_diff) {
30650806d53Smrg				best_diff = diff;
30750806d53Smrg				best_m = m;
30850806d53Smrg				best_n = n;
30950806d53Smrg				best_df = df;
31050806d53Smrg				best_outf = outf;
31150806d53Smrg			}
31250806d53Smrg		}
31350806d53Smrg   }
31450806d53Smrg
31550806d53Smrg   /* do we have an acceptably close frequency? (less than 1% diff) */
31650806d53Smrg
31750806d53Smrg   if (best_diff > (requested_freq/100)) {
31850806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
31950806d53Smrg              "Specified dot clock (%.3f) too far (best %.3f) IBM RGB52x",
32050806d53Smrg	      requested_freq / 1000.0, best_outf / 1000.0);
32150806d53Smrg       return(FALSE);
32250806d53Smrg   }
32350806d53Smrg
32450806d53Smrg   pI128->mem.rbase_g[PEL_MASK] = 0xFF;					MB;
32550806d53Smrg
32650806d53Smrg   tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
32750806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
32850806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
32950806d53Smrg
33050806d53Smrg   pI128->mem.rbase_g[IDXH_I] = 0;					MB;
33150806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
33250806d53Smrg
33350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
33450806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
33550806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81;				MB;
33650806d53Smrg
33750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4;				MB;
33850806d53Smrg   pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f);		MB;
33950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4;				MB;
34050806d53Smrg   pI128->mem.rbase_g[DATA_I] = best_n;					MB;
34150806d53Smrg
34250806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1;			MB;
34350806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
34450806d53Smrg   pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3;  /* 8 M/N pairs in PLL */ MB;
34550806d53Smrg
34650806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2;			MB;
34750806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
34850806d53Smrg   pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2;  /* clock number 2 */	MB;
34950806d53Smrg
35050806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
35150806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0;
35250806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB;
35350806d53Smrg
35450806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync;				MB;
35550806d53Smrg   pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00)
35650806d53Smrg                           | ((flags & V_PVSYNC) ? 0x20 : 0x00);	MB;
35750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos;			MB;
35850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x01;  /* Delay syncs by 1 pclock */	MB;
35950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt;			MB;
36050806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
36150806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op;				MB;
36250806d53Smrg   tmp2 = (pI128->RamdacType == IBM528_DAC) ? 0x02 : 0x00;  /* fast slew */
36350806d53Smrg   if (pI128->DACSyncOnGreen) tmp2 |= 0x08;
36450806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
36550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl;			MB;
36650806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
36750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk;				MB;
36850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x01;					MB;
36950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1;				MB;
37050806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc;
37150806d53Smrg   tmp2 |= 0x20;
37250806d53Smrg   if ((pI128->MemoryType != I128_MEMORY_DRAM) &&
37350806d53Smrg       (pI128->MemoryType != I128_MEMORY_SGRAM))
37450806d53Smrg   	tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1;
37550806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
37650806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2;				MB;
37750806d53Smrg   tmp2 = 0x03;
37850806d53Smrg   if (pI128->DAC8Bit)
37950806d53Smrg	tmp2 |= 0x04;
38050806d53Smrg   if (!((pI128->MemoryType == I128_MEMORY_DRAM) &&
38150806d53Smrg	 (pI128->bitsPerPixel > 16)))
38250806d53Smrg	tmp2 |= 0x40;
38350806d53Smrg   if ((pI128->MemoryType == I128_MEMORY_SGRAM) &&
38450806d53Smrg	 (pI128->bitsPerPixel > 16) &&
38550806d53Smrg         (pI128->RamdacType != SILVER_HAMMER_DAC) )
38650806d53Smrg	tmp2 &= 0x3F;
38750806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
38850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3;				MB;
38950806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
39050806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4;				MB;
39150806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
39250806d53Smrg
39350806d53Smrg   /* ?? There is no write to cursor control register */
39450806d53Smrg
39550806d53Smrg   if (pI128->RamdacType == IBM526_DAC) {
39650806d53Smrg	if (pI128->MemoryType == I128_MEMORY_SGRAM) {
39750806d53Smrg	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
39850806d53Smrg	    pI128->mem.rbase_g[DATA_I] = 0x09;				MB;
39950806d53Smrg	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
40050806d53Smrg	    pI128->mem.rbase_g[DATA_I] = 0x83;				MB;
40150806d53Smrg	} else {
40250806d53Smrg	/* program mclock to 52MHz */
40350806d53Smrg	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
40450806d53Smrg	    pI128->mem.rbase_g[DATA_I] = 0x08;				MB;
40550806d53Smrg	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
40650806d53Smrg	    pI128->mem.rbase_g[DATA_I] = 0x41;				MB;
40750806d53Smrg	}
40850806d53Smrg	/* should delay at least a millisec so we'll wait 50 */
40950806d53Smrg   	usleep(50000);
41050806d53Smrg   }
41150806d53Smrg
41250806d53Smrg   switch (pI128->depth) {
41350806d53Smrg   	case 24: /* 32 bit */
41450806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
41550806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
41650806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06;		MB;
41750806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp;		MB;
41850806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0x03;			MB;
41950806d53Smrg   		break;
42050806d53Smrg	case 16:
42150806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
42250806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
42350806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
42450806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
42550806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0xC7;			MB;
42650806d53Smrg   		break;
42750806d53Smrg	case 15:
42850806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
42950806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
43050806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
43150806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
43250806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0xC5;			MB;
43350806d53Smrg   		break;
43450806d53Smrg	default: /* 8 bit */
43550806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
43650806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
43750806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03;		MB;
43850806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp;		MB;
43950806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0x00;			MB;
44050806d53Smrg   		break;
44150806d53Smrg   }
44250806d53Smrg
44350806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = tmpc;					MB;
44450806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
44550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
44650806d53Smrg
44750806d53Smrg   return(TRUE);
44850806d53Smrg}
44950806d53Smrg
45050806d53Smrg
45150806d53SmrgBool
45250806d53SmrgI128ProgramSilverHammer(ScrnInfoPtr pScrn, DisplayModePtr mode)
45350806d53Smrg{
45450806d53Smrg   /* The SilverHammer DAC is essentially the same as the IBMRGBxxx DACs,
45550806d53Smrg    * but with fewer options and a different reference frequency.
45650806d53Smrg    */
45750806d53Smrg
45850806d53Smrg   I128Ptr pI128 = I128PTR(pScrn);
45950806d53Smrg   unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n;
46050806d53Smrg   CARD32 tmpl, tmph, tmpc;
46150806d53Smrg   long f, vrf, outf, best_diff, best_outf = 0, diff;
46250806d53Smrg   long requested_freq;
46350806d53Smrg   int   freq = mode->SynthClock;
46450806d53Smrg   int   flags = mode->Flags;
46550806d53Smrg   int   skew = mode->HSkew;
46650806d53Smrg
46750806d53Smrg#undef  REF_FREQ
46850806d53Smrg#define REF_FREQ	 37500000
46950806d53Smrg#undef  MAX_VREF
47050806d53Smrg#define MAX_VREF	  9000000
47150806d53Smrg#define MIN_VREF	  1500000
47250806d53Smrg#undef  MAX_VCO
47350806d53Smrg#define MAX_VCO		270000000
47450806d53Smrg#define MIN_VCO		 65000000
47550806d53Smrg
47650806d53Smrg   if (freq < 25000) {
47750806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
47850806d53Smrg              "Specified dot clock (%.3f) too low for SilverHammer",
47950806d53Smrg	      freq / 1000.0);
48050806d53Smrg       return(FALSE);
48150806d53Smrg   } else if (freq > MAX_VCO) {
48250806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
48350806d53Smrg              "Specified dot clock (%.3f) too high for SilverHammer",
48450806d53Smrg	      freq / 1000.0);
48550806d53Smrg       return(FALSE);
48650806d53Smrg   }
48750806d53Smrg
48850806d53Smrg   requested_freq = freq * 1000;
48950806d53Smrg
49050806d53Smrg   best_m = best_n = best_df = 0;
49150806d53Smrg   best_diff = requested_freq;  /* worst case */
49250806d53Smrg
49350806d53Smrg   for (df=0; df<4; df++) {
49450806d53Smrg   	max_n = REF_FREQ / MIN_VREF;
49550806d53Smrg   	if (df < 3)
49650806d53Smrg   		max_n >>= 1;
49750806d53Smrg	for (n=2; n<max_n; n++)
49850806d53Smrg		for (m=65; m<=128; m++) {
49950806d53Smrg			vrf = REF_FREQ / n;
50050806d53Smrg			if (df < 3)
50150806d53Smrg				vrf >>= 1;
50250806d53Smrg			if ((vrf > MAX_VREF) || (vrf < MIN_VREF))
50350806d53Smrg				continue;
50450806d53Smrg
50550806d53Smrg			f = vrf * m;
50650806d53Smrg			outf = f;
50750806d53Smrg			if (df < 2)
50850806d53Smrg				outf >>= 2 - df;
50950806d53Smrg			if ((f > MAX_VCO) || (f < MIN_VCO))
51050806d53Smrg				continue;
51150806d53Smrg
51250806d53Smrg			/* outf is a valid freq, pick the closest now */
51350806d53Smrg
51450806d53Smrg			if ((diff = (requested_freq - outf)) < 0)
51550806d53Smrg				diff = -diff;;
51650806d53Smrg			if (diff < best_diff) {
51750806d53Smrg				best_diff = diff;
51850806d53Smrg				best_m = m;
51950806d53Smrg				best_n = n;
52050806d53Smrg				best_df = df;
52150806d53Smrg				best_outf = outf;
52250806d53Smrg			}
52350806d53Smrg		}
52450806d53Smrg   }
52550806d53Smrg
52650806d53Smrg   /* do we have an acceptably close frequency? (less than 1% diff) */
52750806d53Smrg
52850806d53Smrg   if (best_diff > (requested_freq/100)) {
52950806d53Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
53050806d53Smrg              "Specified dot clock (%.3f) too far (best %.3f) SilverHammer",
53150806d53Smrg	      requested_freq / 1000.0, best_outf / 1000.0);
53250806d53Smrg       return(FALSE);
53350806d53Smrg   }
53450806d53Smrg
53550806d53Smrg   pI128->mem.rbase_g[PEL_MASK] = 0xFF;					MB;
53650806d53Smrg
53750806d53Smrg   tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
53850806d53Smrg   tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
53950806d53Smrg   tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
54050806d53Smrg
54150806d53Smrg   pI128->mem.rbase_g[IDXH_I] = 0;					MB;
54250806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
54350806d53Smrg
54450806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
54550806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
54650806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81;				MB;
54750806d53Smrg
54850806d53Smrg   if (!pI128->Primary) {
54950806d53Smrg       pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0;				MB;
55050806d53Smrg       pI128->mem.rbase_g[DATA_I] = 0x15;				MB;
55150806d53Smrg       pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+1;			MB;
55250806d53Smrg       pI128->mem.rbase_g[DATA_I] = 0x10;				MB;
55350806d53Smrg       pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+2;			MB;
55450806d53Smrg       pI128->mem.rbase_g[DATA_I] = 0x2c;				MB;
55550806d53Smrg       pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+3;			MB;
55650806d53Smrg       pI128->mem.rbase_g[DATA_I] = 0x12;				MB;
55750806d53Smrg   }
55850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4;				MB;
55950806d53Smrg   pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f);		MB;
56050806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4;				MB;
56150806d53Smrg   pI128->mem.rbase_g[DATA_I] = best_n;					MB;
56250806d53Smrg
56350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1;			MB;
56450806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
56550806d53Smrg   pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3;  /* 8 M/N pairs in PLL */ MB;
56650806d53Smrg
56750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2;			MB;
56850806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
56950806d53Smrg   pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2;  /* clock number 2 */	MB;
57050806d53Smrg
57150806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
57250806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0;
57350806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB;
57450806d53Smrg
57550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync;				MB;
57650806d53Smrg   pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00)
57750806d53Smrg                           | ((flags & V_PVSYNC) ? 0x20 : 0x00);	MB;
57850806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos;			MB;
57950806d53Smrg   pI128->mem.rbase_g[DATA_I] = ((flags & V_HSKEW)  ? skew : 0x01);	MB;
58050806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt;			MB;
58150806d53Smrg/* Use 0x01 below with digital flat panel to conserve energy and reduce noise */
58250806d53Smrg   pI128->mem.rbase_g[DATA_I] = (pI128->FlatPanel ? 0x01 : 0x00);	MB;
58350806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op;				MB;
58450806d53Smrg   pI128->mem.rbase_g[DATA_I] = (pI128->DACSyncOnGreen ? 0x08 : 0x00);	MB;
58550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl;			MB;
58650806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
58750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk;				MB;
58850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x01;					MB;
58950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1;				MB;
59050806d53Smrg   tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc;
59150806d53Smrg   if ((pI128->MemoryType != I128_MEMORY_DRAM) &&
59250806d53Smrg       (pI128->MemoryType != I128_MEMORY_SGRAM))
59350806d53Smrg   	tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1;
59450806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
59550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2;				MB;
59650806d53Smrg   tmp2 = 0x03;
59750806d53Smrg   if (pI128->DAC8Bit)
59850806d53Smrg	tmp2 |= 0x04;
59950806d53Smrg   if (!((pI128->MemoryType == I128_MEMORY_DRAM) &&
60050806d53Smrg	 (pI128->bitsPerPixel > 16)))
60150806d53Smrg	tmp2 |= 0x40;
60250806d53Smrg   if ((pI128->MemoryType == I128_MEMORY_SGRAM) &&
60350806d53Smrg	 (pI128->bitsPerPixel > 16) &&
60450806d53Smrg         (pI128->RamdacType != SILVER_HAMMER_DAC) )
60550806d53Smrg	tmp2 &= 0x3F;
60650806d53Smrg   pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
60750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3;				MB;
60850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
60950806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4;				MB;
61050806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
61150806d53Smrg
61250806d53Smrg   /* ?? There is no write to cursor control register */
61350806d53Smrg
61450806d53Smrg   /* Set the memory clock speed to 95 MHz */
61550806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
61650806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x08;				MB;
61750806d53Smrg   pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
61850806d53Smrg   pI128->mem.rbase_g[DATA_I] = 0x50;				MB;
61950806d53Smrg
62050806d53Smrg   /* should delay at least a millisec so we'll wait 50 */
62150806d53Smrg   usleep(50000);
62250806d53Smrg
62350806d53Smrg   switch (pI128->depth) {
62450806d53Smrg   	case 24: /* 32 bit */
62550806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
62650806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
62750806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06;		MB;
62850806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp;		MB;
62950806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0x03;			MB;
63050806d53Smrg   		break;
63150806d53Smrg	case 16:
63250806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
63350806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
63450806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
63550806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
63650806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0xC7;			MB;
63750806d53Smrg   		break;
63850806d53Smrg	case 15:
63950806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
64050806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
64150806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
64250806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
64350806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0xC5;			MB;
64450806d53Smrg   		break;
64550806d53Smrg	default: /* 8 bit */
64650806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
64750806d53Smrg   		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
64850806d53Smrg   		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03;		MB;
64950806d53Smrg   		pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp;		MB;
65050806d53Smrg   		pI128->mem.rbase_g[DATA_I] = 0x00;			MB;
65150806d53Smrg   		break;
65250806d53Smrg   }
65350806d53Smrg
65450806d53Smrg   pI128->mem.rbase_g[IDXCTL_I] = tmpc;					MB;
65550806d53Smrg   pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
65650806d53Smrg   pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
65750806d53Smrg
65850806d53Smrg   return(TRUE);
65950806d53Smrg}
660