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