1 /*
2  * Copyright 1996-2000 by Robin Cutshaw <robin@XFree86.Org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Robin Cutshaw not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  Robin Cutshaw makes no representations
11  * about the suitability of this software for any purpose.  It is provided
12  * "as is" without express or implied warranty.
13  *
14  * ROBIN CUTSHAW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL ROBIN CUTSHAW BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  */
23 
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "xf86.h"
30 #include "xf86Pci.h"
31 #include "cursorstr.h"
32 #include "servermd.h"
33 
34 #include "i128.h"
35 #include "i128reg.h"
36 #include "IBMRGB.h"
37 
38 #include <unistd.h>
39 
40 static void I128IBMShowCursor(ScrnInfoPtr pScrn);
41 static void I128IBMHideCursor(ScrnInfoPtr pScrn);
42 static void I128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
43 static void I128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
44 static void I128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
45 static Bool I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs);
46 
47 
48 Bool
I128IBMHWCursorInit(ScrnInfoPtr pScrn)49 I128IBMHWCursorInit(ScrnInfoPtr pScrn)
50 {
51    xf86CursorInfoPtr infoPtr;
52    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
53    I128Ptr pI128 = I128PTR(pScrn);
54 
55    if (!pI128->HWCursor)
56       return FALSE;
57 
58    infoPtr = xf86CreateCursorInfoRec();
59    if (!infoPtr) return FALSE;
60 
61    pI128->CursorInfoRec = infoPtr;
62    infoPtr->MaxWidth = 64;
63    infoPtr->MaxHeight = 64;
64    infoPtr->SetCursorColors = I128IBMSetCursorColors;
65    infoPtr->SetCursorPosition = I128IBMSetCursorPosition;
66    infoPtr->LoadCursorImage = I128IBMLoadCursorImage;
67    infoPtr->HideCursor = I128IBMHideCursor;
68    infoPtr->ShowCursor = I128IBMShowCursor;
69    infoPtr->UseHWCursor = I128IBMUseHWCursor;
70    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
71                     HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
72                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1;
73 
74 #if X_BYTE_ORDER == X_BIG_ENDIAN
75    infoPtr->Flags |= HARDWARE_CURSOR_NIBBLE_SWAPPED;
76 #endif
77 
78    return(xf86InitCursor(pScreen, infoPtr));
79 }
80 
81 
82 static void
I128IBMShowCursor(ScrnInfoPtr pScrn)83 I128IBMShowCursor(ScrnInfoPtr pScrn)
84 {
85    CARD32 tmpl, tmph;
86    I128Ptr pI128 = I128PTR(pScrn);
87 
88    /* Enable cursor - X11 mode */
89    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
90    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
91    pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
92    pI128->mem.rbase_g[IDXH_I] = 0;					MB;
93    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs;				MB;
94    pI128->mem.rbase_g[DATA_I] = 0x27;					MB;
95 
96    pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
97    pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
98 
99    return;
100 }
101 
102 static void
I128IBMHideCursor(ScrnInfoPtr pScrn)103 I128IBMHideCursor(ScrnInfoPtr pScrn)
104 {
105    CARD32 tmpl, tmph, tmp1;
106    I128Ptr pI128 = I128PTR(pScrn);
107 
108    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
109    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
110    pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
111    pI128->mem.rbase_g[IDXH_I] = 0;					MB;
112    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs;				MB;
113    tmp1 = pI128->mem.rbase_g[DATA_I] & 0xFC;
114    pI128->mem.rbase_g[DATA_I] = tmp1;					MB;
115 
116    pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
117    pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
118 
119    return;
120 }
121 
122 static void
I128IBMSetCursorPosition(ScrnInfoPtr pScrn,int x,int y)123 I128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
124 {
125    CARD32 tmpl, tmph;
126    I128Ptr pI128 = I128PTR(pScrn);
127 
128    x += 64;
129    y += 64;
130 
131    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
132    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
133 
134    pI128->mem.rbase_g[IDXH_I] = 0;					MB;
135    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x;			MB;
136    pI128->mem.rbase_g[DATA_I] = 0x3F;					MB;
137    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y;			MB;
138    pI128->mem.rbase_g[DATA_I] = 0x3F;					MB;
139    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl;				MB;
140    pI128->mem.rbase_g[DATA_I] = x & 0xFF;				MB;
141    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh;				MB;
142    pI128->mem.rbase_g[DATA_I] = (x >> 8) & 0x0F;			MB;
143    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl;				MB;
144    pI128->mem.rbase_g[DATA_I] = y & 0xFF;				MB;
145    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh;				MB;
146    pI128->mem.rbase_g[DATA_I] = (y >> 8) & 0x0F;			MB;
147 
148    pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
149    pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
150 
151    return;
152 }
153 
154 static void
I128IBMSetCursorColors(ScrnInfoPtr pScrn,int bg,int fg)155 I128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
156 {
157    CARD32 tmp;
158    I128Ptr pI128 = I128PTR(pScrn);
159 
160    tmp = pI128->mem.rbase_g[IDXL_I] & 0xFF;
161 
162    /* Background color */
163    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_r;			MB;
164    pI128->mem.rbase_g[DATA_I] = (bg & 0x00FF0000) >> 16;		MB;
165    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_g;			MB;
166    pI128->mem.rbase_g[DATA_I] = (bg & 0x0000FF00) >> 8;			MB;
167    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_b;			MB;
168    pI128->mem.rbase_g[DATA_I] = (bg & 0x000000FF);			MB;
169 
170    /* Foreground color */
171    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_r;			MB;
172    pI128->mem.rbase_g[DATA_I] = (fg & 0x00FF0000) >> 16;		MB;
173    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_g;			MB;
174    pI128->mem.rbase_g[DATA_I] = (fg & 0x0000FF00) >> 8;			MB;
175    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_b;			MB;
176    pI128->mem.rbase_g[DATA_I] = (fg & 0x000000FF);			MB;
177 
178    pI128->mem.rbase_g[IDXL_I] = tmp;					MB;
179 
180    return;
181 }
182 
183 static void
I128IBMLoadCursorImage(ScrnInfoPtr pScrn,unsigned char * src)184 I128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
185 {
186    I128Ptr pI128 = I128PTR(pScrn);
187    register int   i;
188    CARD32 tmph, tmpl, tmpc;
189 
190    tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
191    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
192    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
193 
194    pI128->BlockCursor = TRUE;
195 
196    pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
197 
198    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x;			MB;
199    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
200    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y;			MB;
201    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
202    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl;				MB;
203    pI128->mem.rbase_g[DATA_I] = 0xFF;					MB;
204    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh;				MB;
205    pI128->mem.rbase_g[DATA_I] = 0x7F;					MB;
206    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl;				MB;
207    pI128->mem.rbase_g[DATA_I] = 0xFF;					MB;
208    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh;				MB;
209    pI128->mem.rbase_g[DATA_I] = 0x7F;					MB;
210 
211    pI128->mem.rbase_g[IDXH_I] = (IBMRGB_curs_array >> 8) & 0xFF;	MB;
212    pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_array & 0xFF;		MB;
213 
214    pI128->mem.rbase_g[IDXCTL_I] = 1; /* enable auto-inc */		MB;
215 
216    /*
217     * Output the cursor data.  The realize function has put the planes into
218     * their correct order, so we can just blast this out.
219     */
220    for (i = 0; i < 1024; i++,src++) {
221       pI128->mem.rbase_g[DATA_I] = (CARD32 )*src;			MB;
222    }
223 
224    pI128->mem.rbase_g[IDXCTL_I] = tmpc;                                 MB;
225    pI128->mem.rbase_g[IDXH_I] = tmph;                                   MB;
226    pI128->mem.rbase_g[IDXL_I] = tmpl;                                   MB;
227 
228    pI128->BlockCursor = FALSE;
229 
230    return;
231 }
232 
233 
234 static Bool
I128IBMUseHWCursor(ScreenPtr pScrn,CursorPtr pCurs)235 I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs)
236 {
237    if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN )
238       return FALSE;
239    return TRUE;
240 }
241 
242 
I128TIHWCursorInit(ScrnInfoPtr pScrn)243 Bool I128TIHWCursorInit(ScrnInfoPtr pScrn) { return FALSE; }
I128ProgramTi3025(ScrnInfoPtr pScrn,DisplayModePtr mode)244 Bool I128ProgramTi3025(ScrnInfoPtr pScrn, DisplayModePtr mode) { return FALSE; }
245 
246 Bool
I128ProgramIBMRGB(ScrnInfoPtr pScrn,DisplayModePtr mode)247 I128ProgramIBMRGB(ScrnInfoPtr pScrn, DisplayModePtr mode)
248 {
249    I128Ptr pI128 = I128PTR(pScrn);
250    unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n;
251    CARD32 tmpl, tmph, tmpc;
252    long f, vrf, outf, best_diff, best_outf = 0, diff;
253    long requested_freq;
254    int   freq = mode->SynthClock;
255    int   flags = mode->Flags;
256 
257 #define REF_FREQ	 25175000
258 #define MAX_VREF	  3380000
259 /* Actually, MIN_VREF can be as low as 1000000;
260  * this allows clock speeds down to 17 MHz      */
261 #define MIN_VREF	  1500000
262 #define MAX_VCO		220000000
263 #define MIN_VCO		 65000000
264 
265    if (freq < 25000) {
266        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
267               "Specified dot clock (%.3f) too low for IBM RGB52x",
268 	      freq / 1000.0);
269        return(FALSE);
270    } else if (freq > MAX_VCO) {
271        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
272               "Specified dot clock (%.3f) too high for IBM RGB52x",
273 	      freq / 1000.0);
274        return(FALSE);
275    }
276 
277    requested_freq = freq * 1000;
278 
279    best_m = best_n = best_df = 0;
280    best_diff = requested_freq;  /* worst case */
281 
282    for (df=0; df<4; df++) {
283    	max_n = REF_FREQ / MIN_VREF;
284    	if (df < 3)
285    		max_n >>= 1;
286 	for (n=2; n<max_n; n++)
287 		for (m=65; m<=128; m++) {
288 			vrf = REF_FREQ / n;
289 			if (df < 3)
290 				vrf >>= 1;
291 			if ((vrf > MAX_VREF) || (vrf < MIN_VREF))
292 				continue;
293 
294 			f = vrf * m;
295 			outf = f;
296 			if (df < 2)
297 				outf >>= 2 - df;
298 			if ((f > MAX_VCO) || (f < MIN_VCO))
299 				continue;
300 
301 			/* outf is a valid freq, pick the closest now */
302 
303 			if ((diff = (requested_freq - outf)) < 0)
304 				diff = -diff;;
305 			if (diff < best_diff) {
306 				best_diff = diff;
307 				best_m = m;
308 				best_n = n;
309 				best_df = df;
310 				best_outf = outf;
311 			}
312 		}
313    }
314 
315    /* do we have an acceptably close frequency? (less than 1% diff) */
316 
317    if (best_diff > (requested_freq/100)) {
318        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
319               "Specified dot clock (%.3f) too far (best %.3f) IBM RGB52x",
320 	      requested_freq / 1000.0, best_outf / 1000.0);
321        return(FALSE);
322    }
323 
324    pI128->mem.rbase_g[PEL_MASK] = 0xFF;					MB;
325 
326    tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
327    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
328    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
329 
330    pI128->mem.rbase_g[IDXH_I] = 0;					MB;
331    pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
332 
333    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
334    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
335    pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81;				MB;
336 
337    pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4;				MB;
338    pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f);		MB;
339    pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4;				MB;
340    pI128->mem.rbase_g[DATA_I] = best_n;					MB;
341 
342    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1;			MB;
343    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
344    pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3;  /* 8 M/N pairs in PLL */ MB;
345 
346    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2;			MB;
347    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
348    pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2;  /* clock number 2 */	MB;
349 
350    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
351    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0;
352    pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB;
353 
354    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync;				MB;
355    pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00)
356                            | ((flags & V_PVSYNC) ? 0x20 : 0x00);	MB;
357    pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos;			MB;
358    pI128->mem.rbase_g[DATA_I] = 0x01;  /* Delay syncs by 1 pclock */	MB;
359    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt;			MB;
360    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
361    pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op;				MB;
362    tmp2 = (pI128->RamdacType == IBM528_DAC) ? 0x02 : 0x00;  /* fast slew */
363    if (pI128->DACSyncOnGreen) tmp2 |= 0x08;
364    pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
365    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl;			MB;
366    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
367    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk;				MB;
368    pI128->mem.rbase_g[DATA_I] = 0x01;					MB;
369    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1;				MB;
370    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc;
371    tmp2 |= 0x20;
372    if ((pI128->MemoryType != I128_MEMORY_DRAM) &&
373        (pI128->MemoryType != I128_MEMORY_SGRAM))
374    	tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1;
375    pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
376    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2;				MB;
377    tmp2 = 0x03;
378    if (pI128->DAC8Bit)
379 	tmp2 |= 0x04;
380    if (!((pI128->MemoryType == I128_MEMORY_DRAM) &&
381 	 (pI128->bitsPerPixel > 16)))
382 	tmp2 |= 0x40;
383    if ((pI128->MemoryType == I128_MEMORY_SGRAM) &&
384 	 (pI128->bitsPerPixel > 16) &&
385          (pI128->RamdacType != SILVER_HAMMER_DAC) )
386 	tmp2 &= 0x3F;
387    pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
388    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3;				MB;
389    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
390    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4;				MB;
391    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
392 
393    /* ?? There is no write to cursor control register */
394 
395    if (pI128->RamdacType == IBM526_DAC) {
396 	if (pI128->MemoryType == I128_MEMORY_SGRAM) {
397 	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
398 	    pI128->mem.rbase_g[DATA_I] = 0x09;				MB;
399 	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
400 	    pI128->mem.rbase_g[DATA_I] = 0x83;				MB;
401 	} else {
402 	/* program mclock to 52MHz */
403 	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
404 	    pI128->mem.rbase_g[DATA_I] = 0x08;				MB;
405 	    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
406 	    pI128->mem.rbase_g[DATA_I] = 0x41;				MB;
407 	}
408 	/* should delay at least a millisec so we'll wait 50 */
409    	usleep(50000);
410    }
411 
412    switch (pI128->depth) {
413    	case 24: /* 32 bit */
414    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
415    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
416    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06;		MB;
417    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp;		MB;
418    		pI128->mem.rbase_g[DATA_I] = 0x03;			MB;
419    		break;
420 	case 16:
421    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
422    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
423    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
424    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
425    		pI128->mem.rbase_g[DATA_I] = 0xC7;			MB;
426    		break;
427 	case 15:
428    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
429    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
430    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
431    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
432    		pI128->mem.rbase_g[DATA_I] = 0xC5;			MB;
433    		break;
434 	default: /* 8 bit */
435    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
436    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
437    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03;		MB;
438    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp;		MB;
439    		pI128->mem.rbase_g[DATA_I] = 0x00;			MB;
440    		break;
441    }
442 
443    pI128->mem.rbase_g[IDXCTL_I] = tmpc;					MB;
444    pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
445    pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
446 
447    return(TRUE);
448 }
449 
450 
451 Bool
I128ProgramSilverHammer(ScrnInfoPtr pScrn,DisplayModePtr mode)452 I128ProgramSilverHammer(ScrnInfoPtr pScrn, DisplayModePtr mode)
453 {
454    /* The SilverHammer DAC is essentially the same as the IBMRGBxxx DACs,
455     * but with fewer options and a different reference frequency.
456     */
457 
458    I128Ptr pI128 = I128PTR(pScrn);
459    unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n;
460    CARD32 tmpl, tmph, tmpc;
461    long f, vrf, outf, best_diff, best_outf = 0, diff;
462    long requested_freq;
463    int   freq = mode->SynthClock;
464    int   flags = mode->Flags;
465    int   skew = mode->HSkew;
466 
467 #undef  REF_FREQ
468 #define REF_FREQ	 37500000
469 #undef  MAX_VREF
470 #define MAX_VREF	  9000000
471 #define MIN_VREF	  1500000
472 #undef  MAX_VCO
473 #define MAX_VCO		270000000
474 #define MIN_VCO		 65000000
475 
476    if (freq < 25000) {
477        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
478               "Specified dot clock (%.3f) too low for SilverHammer",
479 	      freq / 1000.0);
480        return(FALSE);
481    } else if (freq > MAX_VCO) {
482        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
483               "Specified dot clock (%.3f) too high for SilverHammer",
484 	      freq / 1000.0);
485        return(FALSE);
486    }
487 
488    requested_freq = freq * 1000;
489 
490    best_m = best_n = best_df = 0;
491    best_diff = requested_freq;  /* worst case */
492 
493    for (df=0; df<4; df++) {
494    	max_n = REF_FREQ / MIN_VREF;
495    	if (df < 3)
496    		max_n >>= 1;
497 	for (n=2; n<max_n; n++)
498 		for (m=65; m<=128; m++) {
499 			vrf = REF_FREQ / n;
500 			if (df < 3)
501 				vrf >>= 1;
502 			if ((vrf > MAX_VREF) || (vrf < MIN_VREF))
503 				continue;
504 
505 			f = vrf * m;
506 			outf = f;
507 			if (df < 2)
508 				outf >>= 2 - df;
509 			if ((f > MAX_VCO) || (f < MIN_VCO))
510 				continue;
511 
512 			/* outf is a valid freq, pick the closest now */
513 
514 			if ((diff = (requested_freq - outf)) < 0)
515 				diff = -diff;;
516 			if (diff < best_diff) {
517 				best_diff = diff;
518 				best_m = m;
519 				best_n = n;
520 				best_df = df;
521 				best_outf = outf;
522 			}
523 		}
524    }
525 
526    /* do we have an acceptably close frequency? (less than 1% diff) */
527 
528    if (best_diff > (requested_freq/100)) {
529        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
530               "Specified dot clock (%.3f) too far (best %.3f) SilverHammer",
531 	      requested_freq / 1000.0, best_outf / 1000.0);
532        return(FALSE);
533    }
534 
535    pI128->mem.rbase_g[PEL_MASK] = 0xFF;					MB;
536 
537    tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF;
538    tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF;
539    tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF;
540 
541    pI128->mem.rbase_g[IDXH_I] = 0;					MB;
542    pI128->mem.rbase_g[IDXCTL_I] = 0;					MB;
543 
544    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
545    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
546    pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81;				MB;
547 
548    if (!pI128->Primary) {
549        pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0;				MB;
550        pI128->mem.rbase_g[DATA_I] = 0x15;				MB;
551        pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+1;			MB;
552        pI128->mem.rbase_g[DATA_I] = 0x10;				MB;
553        pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+2;			MB;
554        pI128->mem.rbase_g[DATA_I] = 0x2c;				MB;
555        pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+3;			MB;
556        pI128->mem.rbase_g[DATA_I] = 0x12;				MB;
557    }
558    pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4;				MB;
559    pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f);		MB;
560    pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4;				MB;
561    pI128->mem.rbase_g[DATA_I] = best_n;					MB;
562 
563    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1;			MB;
564    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
565    pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3;  /* 8 M/N pairs in PLL */ MB;
566 
567    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2;			MB;
568    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF;
569    pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2;  /* clock number 2 */	MB;
570 
571    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock;			MB;
572    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0;
573    pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB;
574 
575    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync;				MB;
576    pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00)
577                            | ((flags & V_PVSYNC) ? 0x20 : 0x00);	MB;
578    pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos;			MB;
579    pI128->mem.rbase_g[DATA_I] = ((flags & V_HSKEW)  ? skew : 0x01);	MB;
580    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt;			MB;
581 /* Use 0x01 below with digital flat panel to conserve energy and reduce noise */
582    pI128->mem.rbase_g[DATA_I] = (pI128->FlatPanel ? 0x01 : 0x00);	MB;
583    pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op;				MB;
584    pI128->mem.rbase_g[DATA_I] = (pI128->DACSyncOnGreen ? 0x08 : 0x00);	MB;
585    pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl;			MB;
586    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
587    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk;				MB;
588    pI128->mem.rbase_g[DATA_I] = 0x01;					MB;
589    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1;				MB;
590    tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc;
591    if ((pI128->MemoryType != I128_MEMORY_DRAM) &&
592        (pI128->MemoryType != I128_MEMORY_SGRAM))
593    	tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1;
594    pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
595    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2;				MB;
596    tmp2 = 0x03;
597    if (pI128->DAC8Bit)
598 	tmp2 |= 0x04;
599    if (!((pI128->MemoryType == I128_MEMORY_DRAM) &&
600 	 (pI128->bitsPerPixel > 16)))
601 	tmp2 |= 0x40;
602    if ((pI128->MemoryType == I128_MEMORY_SGRAM) &&
603 	 (pI128->bitsPerPixel > 16) &&
604          (pI128->RamdacType != SILVER_HAMMER_DAC) )
605 	tmp2 &= 0x3F;
606    pI128->mem.rbase_g[DATA_I] = tmp2;					MB;
607    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3;				MB;
608    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
609    pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4;				MB;
610    pI128->mem.rbase_g[DATA_I] = 0x00;					MB;
611 
612    /* ?? There is no write to cursor control register */
613 
614    /* Set the memory clock speed to 95 MHz */
615    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div;		MB;
616    pI128->mem.rbase_g[DATA_I] = 0x08;				MB;
617    pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div;		MB;
618    pI128->mem.rbase_g[DATA_I] = 0x50;				MB;
619 
620    /* should delay at least a millisec so we'll wait 50 */
621    usleep(50000);
622 
623    switch (pI128->depth) {
624    	case 24: /* 32 bit */
625    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
626    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
627    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06;		MB;
628    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp;		MB;
629    		pI128->mem.rbase_g[DATA_I] = 0x03;			MB;
630    		break;
631 	case 16:
632    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
633    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
634    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
635    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
636    		pI128->mem.rbase_g[DATA_I] = 0xC7;			MB;
637    		break;
638 	case 15:
639    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
640    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
641    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04;		MB;
642    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp;		MB;
643    		pI128->mem.rbase_g[DATA_I] = 0xC5;			MB;
644    		break;
645 	default: /* 8 bit */
646    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt;		MB;
647    		tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8;
648    		pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03;		MB;
649    		pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp;		MB;
650    		pI128->mem.rbase_g[DATA_I] = 0x00;			MB;
651    		break;
652    }
653 
654    pI128->mem.rbase_g[IDXCTL_I] = tmpc;					MB;
655    pI128->mem.rbase_g[IDXH_I] = tmph;					MB;
656    pI128->mem.rbase_g[IDXL_I] = tmpl;					MB;
657 
658    return(TRUE);
659 }
660