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