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
40static void I128IBMShowCursor(ScrnInfoPtr pScrn);
41static void I128IBMHideCursor(ScrnInfoPtr pScrn);
42static void I128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
43static void I128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
44static void I128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
45static Bool I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs);
46
47
48Bool
49I128IBMHWCursorInit(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
82static void
83I128IBMShowCursor(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
102static void
103I128IBMHideCursor(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
122static void
123I128IBMSetCursorPosition(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
154static void
155I128IBMSetCursorColors(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
183static void
184I128IBMLoadCursorImage(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
234static Bool
235I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs)
236{
237   if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN )
238      return FALSE;
239   return TRUE;
240}
241
242
243Bool I128TIHWCursorInit(ScrnInfoPtr pScrn) { return FALSE; }
244Bool I128ProgramTi3025(ScrnInfoPtr pScrn, DisplayModePtr mode) { return FALSE; }
245
246Bool
247I128ProgramIBMRGB(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
451Bool
452I128ProgramSilverHammer(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