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