1 /* program the DAC */ 2 /* Author: 3 Rudolf Cornelissen 12/2003-7/2005 4 */ 5 6 #define MODULE_BIT 0x00010000 7 8 #include "std.h" 9 10 static status_t cle266_km400_dac_pix_pll_find( 11 display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); 12 13 /* see if an analog VGA monitor is connected to connector #1 */ 14 bool eng_dac_crt_connected(void) 15 { 16 uint32 output, dac; 17 bool present; 18 19 /* save output connector setting */ 20 output = DACR(OUTPUT); 21 /* save DAC state */ 22 dac = DACR(TSTCTRL); 23 24 /* turn on DAC */ 25 DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeffff)); 26 /* select primary head and turn off CRT (and DVI?) outputs */ 27 DACW(OUTPUT, (output & 0x0000feee)); 28 /* wait for signal lines to stabilize */ 29 snooze(1000); 30 /* re-enable CRT output */ 31 DACW(OUTPUT, (DACR(OUTPUT) | 0x00000001)); 32 33 /* setup RGB test signal levels to approx 30% of DAC range and enable them */ 34 DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0))); 35 /* route test signals to output */ 36 DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000)); 37 /* wait for signal lines to stabilize */ 38 snooze(1000); 39 40 /* do actual detection: all signals paths high == CRT connected */ 41 if (DACR(TSTCTRL) & 0x10000000) 42 { 43 present = true; 44 LOG(4,("DAC: CRT detected on connector #1\n")); 45 } 46 else 47 { 48 present = false; 49 LOG(4,("DAC: no CRT detected on connector #1\n")); 50 } 51 52 /* kill test signal routing */ 53 DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff)); 54 55 /* restore output connector setting */ 56 DACW(OUTPUT, output); 57 /* restore DAC state */ 58 DACW(TSTCTRL, dac); 59 60 return present; 61 } 62 63 /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ 64 status_t eng_dac_mode(int mode,float brightness) 65 { 66 uint8 *r,*g,*b; 67 int i, ri; 68 69 /* 8-bit mode uses the palette differently */ 70 if (mode == BPP8) return B_ERROR; 71 72 /*set colour arrays to point to space reserved in shared info*/ 73 r = si->color_data; 74 g = r + 256; 75 b = g + 256; 76 77 LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness)); 78 /* init the palette for brightness specified */ 79 /* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */ 80 for (i = 0; i < 256; i++) 81 { 82 ri = i * brightness; 83 if (ri > 255) ri = 255; 84 b[i] = g[i] = r[i] = ri; 85 } 86 87 if (eng_dac_palette(r,g,b) != B_OK) return B_ERROR; 88 89 /* disable palette RAM adressing mask */ 90 ENG_REG8(RG8_PALMASK) = 0xff; 91 LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", ENG_REG8(RG8_PALMASK))); 92 93 return B_OK; 94 } 95 96 /*program the DAC palette using the given r,g,b values*/ 97 status_t eng_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256]) 98 { 99 int i; 100 LOG(4,("DAC: setting palette\n")); 101 102 /* enable primary head palette access */ 103 SEQW(MMIO_EN, ((SEQR(MMIO_EN)) & 0xfe)); 104 /* ??? */ 105 SEQW(0x1b, ((SEQR(0x1b)) | 0x20)); 106 /* disable gamma correction HW mode */ 107 SEQW(FIFOWM, ((SEQR(FIFOWM)) & 0x7f)); 108 /* select first PAL adress before starting programming */ 109 ENG_REG8(RG8_PALINDW) = 0x00; 110 111 /* loop through all 256 to program DAC */ 112 for (i = 0; i < 256; i++) 113 { 114 ENG_REG8(RG8_PALDATA) = r[i]; 115 ENG_REG8(RG8_PALDATA) = g[i]; 116 ENG_REG8(RG8_PALDATA) = b[i]; 117 } 118 if (ENG_REG8(RG8_PALINDW) != 0x00) 119 { 120 LOG(8,("DAC: PAL write index incorrect after programming\n")); 121 return B_ERROR; 122 } 123 if (0) 124 {//reread LUT 125 uint8 R, G, B; 126 127 /* select first PAL adress to read (modulo 3 counter) */ 128 ENG_REG8(RG8_PALINDR) = 0x00; 129 for (i = 0; i < 256; i++) 130 { 131 R = ENG_REG8(RG8_PALDATA); 132 G = ENG_REG8(RG8_PALDATA); 133 B = ENG_REG8(RG8_PALDATA); 134 if ((r[i] != R) || (g[i] != G) || (b[i] != B)) 135 LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed 136 } 137 } 138 139 return B_OK; 140 } 141 142 /*program the pixpll - frequency in kHz*/ 143 status_t eng_dac_set_pix_pll(display_mode target) 144 { 145 uint8 m=0,n=0,p=0; 146 // uint time = 0; 147 148 float pix_setting, req_pclk; 149 status_t result; 150 151 /* we offer this option because some panels have very tight restrictions, 152 * and there's no overlapping settings range that makes them all work. 153 * note: 154 * this assumes the cards BIOS correctly programmed the panel (is likely) */ 155 //fixme: when VESA DDC EDID stuff is implemented, this option can be deleted... 156 if (0)//si->ps.tmds1_active && !si->settings.pgm_panel) 157 { 158 LOG(4,("DAC: Not programming DFP refresh (specified in via.settings)\n")); 159 return B_OK; 160 } 161 162 /* fix a DVI or laptop flatpanel to 60Hz refresh! */ 163 /* Note: 164 * The pixelclock drives the flatpanel modeline, not the CRTC modeline. */ 165 if (0)//si->ps.tmds1_active) 166 { 167 LOG(4,("DAC: Fixing DFP refresh to 60Hz!\n")); 168 169 /* use the panel's modeline to determine the needed pixelclock */ 170 target.timing.pixel_clock = si->ps.p1_timing.pixel_clock; 171 } 172 173 req_pclk = (target.timing.pixel_clock)/1000.0; 174 LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); 175 176 /* signal that we actually want to set the mode */ 177 result = eng_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1); 178 if (result != B_OK) 179 { 180 return result; 181 } 182 183 /* reset primary pixelPLL */ 184 SEQW(PLL_RESET, ((SEQR(PLL_RESET)) | 0x02)); 185 snooze(1000); 186 SEQW(PLL_RESET, ((SEQR(PLL_RESET)) & ~0x02)); 187 188 /* program new frequency */ 189 if (si->ps.card_arch != K8M800) 190 { 191 /* fixme: b7 is a lock-indicator or a filter select: to be determined! */ 192 SEQW(PPLL_N_CLE, (n & 0x7f)); 193 SEQW(PPLL_MP_CLE, ((m & 0x3f) | ((p & 0x03) << 6))); 194 } 195 else 196 { 197 /* fixme: preliminary, still needs to be confirmed */ 198 SEQW(PPLL_N_OTH, (n & 0x7f)); 199 SEQW(PPLL_M_OTH, (m & 0x3f)); 200 SEQW(PPLL_P_OTH, (p & 0x03)); 201 } 202 203 /* reset primary pixelPLL (playing it safe) */ 204 SEQW(PLL_RESET, ((SEQR(PLL_RESET)) | 0x02)); 205 snooze(1000); 206 SEQW(PLL_RESET, ((SEQR(PLL_RESET)) & ~0x02)); 207 208 /* now select pixelclock source D (the above custom VIA programmable PLL) */ 209 snooze(1000); 210 ENG_REG8(RG8_MISCW) = 0xcf; 211 212 /* Wait for the PIXPLL frequency to lock until timeout occurs */ 213 //fixme: do VIA cards have a LOCK indication bit?? 214 /* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) 215 { 216 time++; 217 snooze(1); 218 } 219 220 if (time > 2000) 221 LOG(2,("DAC: PIX PLL frequency not locked!\n")); 222 else 223 LOG(2,("DAC: PIX PLL frequency locked\n")); 224 DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL 225 */ 226 227 //for now: 228 /* Give the PIXPLL frequency some time to lock... */ 229 snooze(1000); 230 LOG(2,("DAC: PIX PLL frequency should be locked now...\n")); 231 232 return B_OK; 233 } 234 235 /* find nearest valid pix pll */ 236 status_t eng_dac_pix_pll_find 237 (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) 238 { 239 //fixme: add K8M800 calcs if needed.. 240 switch (si->ps.card_type) { 241 default: return cle266_km400_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); 242 } 243 return B_ERROR; 244 } 245 246 /* find nearest valid pixel PLL setting */ 247 static status_t cle266_km400_dac_pix_pll_find( 248 display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) 249 { 250 int m = 0, n = 0, p = 0/*, m_max*/; 251 float error, error_best = 999999999; 252 int best[3]; 253 float f_vco, max_pclk; 254 float req_pclk = target.timing.pixel_clock/1000.0; 255 256 /* determine the max. reference-frequency postscaler setting for the 257 * current card (see G100, G200 and G400 specs). */ 258 /* switch(si->ps.card_type) 259 { 260 case G100: 261 LOG(4,("DAC: G100 restrictions apply\n")); 262 m_max = 7; 263 break; 264 case G200: 265 LOG(4,("DAC: G200 restrictions apply\n")); 266 m_max = 7; 267 break; 268 default: 269 LOG(4,("DAC: G400/G400MAX restrictions apply\n")); 270 m_max = 32; 271 break; 272 } 273 */ 274 LOG(4,("DAC: CLE266/KM400 restrictions apply\n")); 275 276 /* determine the max. pixelclock for the current videomode */ 277 switch (target.space) 278 { 279 case B_CMAP8: 280 max_pclk = si->ps.max_dac1_clock_8; 281 break; 282 case B_RGB15_LITTLE: 283 case B_RGB16_LITTLE: 284 max_pclk = si->ps.max_dac1_clock_16; 285 break; 286 case B_RGB24_LITTLE: 287 max_pclk = si->ps.max_dac1_clock_24; 288 break; 289 case B_RGB32_LITTLE: 290 max_pclk = si->ps.max_dac1_clock_32; 291 break; 292 default: 293 /* use fail-safe value */ 294 max_pclk = si->ps.max_dac1_clock_32; 295 break; 296 } 297 /* if some dualhead mode is active, an extra restriction might apply */ 298 if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) 299 max_pclk = si->ps.max_dac1_clock_32dh; 300 301 /* Make sure the requested pixelclock is within the PLL's operational limits */ 302 /* lower limit is min_pixel_vco divided by highest postscaler-factor */ 303 if (req_pclk < (si->ps.min_pixel_vco / 8.0)) 304 { 305 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", 306 req_pclk, (float)(si->ps.min_pixel_vco / 8.0))); 307 req_pclk = (si->ps.min_pixel_vco / 8.0); 308 } 309 /* upper limit is given by pins in combination with current active mode */ 310 if (req_pclk > max_pclk) 311 { 312 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", 313 req_pclk, (float)max_pclk)); 314 req_pclk = max_pclk; 315 } 316 317 /* iterate through all valid PLL postscaler settings */ 318 for (p = 0x01; p < 0x10; p = p << 1) 319 { 320 /* calculate the needed VCO frequency for this postscaler setting */ 321 f_vco = req_pclk * p; 322 323 /* check if this is within range of the VCO specs */ 324 if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco)) 325 { 326 /* iterate trough all valid reference-frequency postscaler settings */ 327 for (m = 1; m <= 63; m++) 328 { 329 /* check if phase-discriminator will be within operational limits */ 330 /* (range as used by VESA BIOS on CLE266, verified.) */ 331 if (((si->ps.f_ref / m) < 2.0) || ((si->ps.f_ref / m) > 3.6)) continue; 332 333 /* calculate VCO postscaler setting for current setup.. */ 334 n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); 335 336 /* ..and check for validity */ 337 /* (checked VESA BIOS on CLE266, b7 is NOT part of divider.) */ 338 if ((n < 1) || (n > 127)) continue; 339 340 /* find error in frequency this setting gives */ 341 error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p)); 342 343 /* note the setting if best yet */ 344 if (error < error_best) 345 { 346 error_best = error; 347 best[0]=m; 348 best[1]=n; 349 best[2]=p; 350 } 351 } 352 } 353 } 354 355 /* setup the scalers programming values for found optimum setting */ 356 m = best[0]; 357 n = best[1]; 358 p = best[2]; 359 360 /* log the VCO frequency found */ 361 f_vco = ((si->ps.f_ref / m) * n); 362 363 LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco)); 364 365 /* return the results */ 366 *calc_pclk = (f_vco / p); 367 *m_result = m; 368 *n_result = n; 369 switch(p) 370 { 371 case 1: 372 p = 0x00; 373 break; 374 case 2: 375 p = 0x01; 376 break; 377 case 4: 378 p = 0x02; 379 break; 380 case 8: 381 p = 0x03; 382 break; 383 } 384 *p_result = p; 385 386 /* display the found pixelclock values */ 387 LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", 388 req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); 389 390 return B_OK; 391 } 392 393 /* find nearest valid system PLL setting */ 394 status_t eng_dac_sys_pll_find( 395 float req_sclk, float* calc_sclk, uint8* m_result, uint8* n_result, uint8* p_result, uint8 test) 396 { 397 int m = 0, n = 0, p = 0, m_max, p_max; 398 float error, error_best = 999999999; 399 int best[3]; 400 float f_vco, discr_low, discr_high; 401 402 /* determine the max. reference-frequency postscaler setting for the 403 * current requested clock */ 404 switch (si->ps.card_arch) 405 { 406 case NV04A: 407 LOG(4,("DAC: NV04 restrictions apply\n")); 408 /* set phase-discriminator frequency range (Mhz) (verified) */ 409 discr_low = 1.0; 410 discr_high = 2.0; 411 /* set max. useable reference frequency postscaler divider factor */ 412 m_max = 14; 413 /* set max. useable VCO output postscaler divider factor */ 414 p_max = 16; 415 break; 416 default: 417 switch (si->ps.card_type) 418 { 419 case NV28: 420 //fixme: how about some other cards??? 421 LOG(4,("DAC: NV28 restrictions apply\n")); 422 /* set max. useable reference frequency postscaler divider factor; 423 * apparantly we would get distortions on high PLL output frequencies if 424 * we use the phase-discriminator at low frequencies */ 425 if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */ 426 else if (req_sclk > 200.0) m_max = 4; /* 200Mhz < Fpll <= 340Mhz */ 427 else if (req_sclk > 150.0) m_max = 6; /* 150Mhz < Fpll <= 200Mhz */ 428 else m_max = 14; /* Fpll < 150Mhz */ 429 430 /* set max. useable VCO output postscaler divider factor */ 431 p_max = 32; 432 /* set phase-discriminator frequency range (Mhz) (verified) */ 433 discr_low = 1.0; 434 discr_high = 27.0; 435 break; 436 default: 437 LOG(4,("DAC: NV10/NV20/NV30 restrictions apply\n")); 438 /* set max. useable reference frequency postscaler divider factor; 439 * apparantly we would get distortions on high PLL output frequencies if 440 * we use the phase-discriminator at low frequencies */ 441 if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */ 442 else if (req_sclk > 250.0) m_max = 6; /* 250Mhz < Fpll <= 340Mhz */ 443 else m_max = 14; /* Fpll < 250Mhz */ 444 445 /* set max. useable VCO output postscaler divider factor */ 446 p_max = 16; 447 /* set phase-discriminator frequency range (Mhz) (verified) */ 448 if (si->ps.card_type == NV36) discr_low = 3.2; 449 else discr_low = 1.0; 450 /* (high discriminator spec is failsafe) */ 451 discr_high = 14.0; 452 break; 453 } 454 break; 455 } 456 457 LOG(4,("DAC: PLL reference frequency postscaler divider range is 1 - %d\n", m_max)); 458 LOG(4,("DAC: PLL VCO output postscaler divider range is 1 - %d\n", p_max)); 459 LOG(4,("DAC: PLL discriminator input frequency range is %2.2fMhz - %2.2fMhz\n", 460 discr_low, discr_high)); 461 462 /* Make sure the requested clock is within the PLL's operational limits */ 463 /* lower limit is min_system_vco divided by highest postscaler-factor */ 464 if (req_sclk < (si->ps.min_system_vco / ((float)p_max))) 465 { 466 LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", 467 req_sclk, (si->ps.min_system_vco / ((float)p_max)))); 468 req_sclk = (si->ps.min_system_vco / ((float)p_max)); 469 } 470 /* upper limit is given by pins */ 471 if (req_sclk > si->ps.max_system_vco) 472 { 473 LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", 474 req_sclk, (float)si->ps.max_system_vco)); 475 req_sclk = si->ps.max_system_vco; 476 } 477 478 /* iterate through all valid PLL postscaler settings */ 479 for (p=0x01; p <= p_max; p = p<<1) 480 { 481 /* calculate the needed VCO frequency for this postscaler setting */ 482 f_vco = req_sclk * p; 483 484 /* check if this is within range of the VCO specs */ 485 if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco)) 486 { 487 /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ 488 if (si->ps.ext_pll) f_vco /= 4; 489 490 /* iterate trough all valid reference-frequency postscaler settings */ 491 for (m = 1; m <= m_max; m++) 492 { 493 /* check if phase-discriminator will be within operational limits */ 494 if (((si->ps.f_ref / m) < discr_low) || ((si->ps.f_ref / m) > discr_high)) 495 continue; 496 497 /* calculate VCO postscaler setting for current setup.. */ 498 n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); 499 500 /* ..and check for validity */ 501 if ((n < 1) || (n > 255)) continue; 502 503 /* find error in frequency this setting gives */ 504 if (si->ps.ext_pll) 505 { 506 /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ 507 error = fabs((req_sclk / 4) - (((si->ps.f_ref / m) * n) / p)); 508 } 509 else 510 error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p)); 511 512 /* note the setting if best yet */ 513 if (error < error_best) 514 { 515 error_best = error; 516 best[0]=m; 517 best[1]=n; 518 best[2]=p; 519 } 520 } 521 } 522 } 523 524 /* setup the scalers programming values for found optimum setting */ 525 m = best[0]; 526 n = best[1]; 527 p = best[2]; 528 529 /* log the VCO frequency found */ 530 f_vco = ((si->ps.f_ref / m) * n); 531 /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ 532 if (si->ps.ext_pll) f_vco *= 4; 533 534 LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco)); 535 536 /* return the results */ 537 *calc_sclk = (f_vco / p); 538 *m_result = m; 539 *n_result = n; 540 switch(p) 541 { 542 case 1: 543 p = 0x00; 544 break; 545 case 2: 546 p = 0x01; 547 break; 548 case 4: 549 p = 0x02; 550 break; 551 case 8: 552 p = 0x03; 553 break; 554 case 16: 555 p = 0x04; 556 break; 557 case 32: 558 p = 0x05; 559 break; 560 } 561 *p_result = p; 562 563 /* display the found pixelclock values */ 564 LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", 565 req_sclk, *calc_sclk, *m_result, *n_result, *p_result)); 566 567 return B_OK; 568 } 569