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