1 /* Authors: 2 Mark Watson 2000, 3 Rudolf Cornelissen 1/2003-5/2006 4 5 Thanx to Petr Vandrovec for writing matroxfb. 6 */ 7 8 #define MODULE_BIT 0x00100000 9 10 #include "mga_std.h" 11 12 typedef struct { 13 uint32 h_total; 14 uint32 h_display; 15 uint32 h_sync_length; 16 uint32 front_porch; 17 uint32 back_porch; 18 uint32 color_burst; 19 uint32 v_total; 20 float chroma_subcarrier; 21 } gx50_maven_timing; 22 23 24 // FIXME: try to implement 'fast' and 'slow' settings for all modes, so buffer 25 // duplication or skipping won't be neccesary for realtime video. 26 // FIXME: try to setup the CRTC2 in interlaced mode for the video modes 27 // on <= G400MAX cards. 28 29 /* find 'exact' valid video PLL setting */ 30 status_t g100_g400max_maventv_vid_pll_find( 31 display_mode target, unsigned int * ht_new, unsigned int * ht_last_line, 32 uint8 * m_result, uint8 * n_result, uint8 * p_result) 33 { 34 int m = 0, n = 0, p = 0, m_max; 35 float diff, diff_smallest = INFINITY; 36 int best[5] = {0, 0, 0, 0, 0}; 37 int h_total_mod; 38 float fields_sec, f_vco; 39 /* We need to be exact, so work with clockperiods per field instead of with frequency. 40 * Make sure however we truncate these clocks to be integers! 41 * (The NTSC field frequency would otherwise prevent the 'whole number of clocks per field' 42 * check done in this routine later on...) */ 43 uint32 vco_clks_field, max_pclks_field, req_pclks_field; 44 /* We need this variable to be a float, because we need to be able to verify if this 45 * represents a whole number of clocks per field later on! */ 46 float calc_pclks_field; 47 48 LOG(2, ("MAVENTV: searching for EXACT videoclock match\n")); 49 50 /* determine the max. reference-frequency postscaler setting for the current card */ 51 //fixme: check G100 and G200 m_max if exist and possible... 52 switch (si->ps.card_type) 53 { 54 case G100: 55 LOG(2, ("MAVENTV: G100 restrictions apply\n")); 56 m_max = 32; 57 break; 58 case G200: 59 LOG(2, ("MAVENTV: G200 restrictions apply\n")); 60 m_max = 32; 61 break; 62 default: 63 LOG(2, ("MAVENTV: G400/G400MAX restrictions apply\n")); 64 m_max = 32; 65 break; 66 } 67 68 /* set number of fields per second to generate */ 69 if ((target.flags & TV_BITS) == TV_PAL) 70 fields_sec = 50.0; 71 else 72 fields_sec = 59.94; 73 74 /* determine the max. pixelclock for the current videomode */ 75 switch (target.space) 76 { 77 case B_RGB16_LITTLE: 78 max_pclks_field = (si->ps.max_dac2_clock_16 * 1000000) / fields_sec; 79 break; 80 case B_RGB32_LITTLE: 81 max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; 82 break; 83 default: 84 /* use fail-safe value */ 85 max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; 86 break; 87 } 88 /* if some dualhead mode is active, an extra restriction might apply */ 89 if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) 90 max_pclks_field = (si->ps.max_dac2_clock_32dh * 1000000) / fields_sec; 91 92 /* Checkout all possible Htotal settings within the current granularity step 93 * of CRTC2 to get a real close videoclock match! 94 * (The MAVEN apparantly has a granularity of 1 pixel, while CRTC2 has 8 pixels) */ 95 for (h_total_mod = 0; h_total_mod < 8; h_total_mod++) 96 { 97 LOG(2, ("MAVENTV: trying h_total modification of +%d...\n", h_total_mod)); 98 99 /* Calculate videoclock to be a bit to high so we can compensate for an exact 100 * match via h_total_lastline.. */ 101 *ht_new = target.timing.h_total + h_total_mod + 2; 102 103 /* Make sure the requested pixelclock is within the PLL's operational limits */ 104 /* lower limit is min_video_vco divided by highest postscaler-factor */ 105 req_pclks_field = *ht_new * target.timing.v_total; 106 if (req_pclks_field < (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0)) 107 { 108 req_pclks_field = (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0); 109 LOG(4, ("MAVENTV: WARNING, clamping at lowest possible videoclock\n")); 110 } 111 /* upper limit is given by pins in combination with current active mode */ 112 if (req_pclks_field > max_pclks_field) 113 { 114 req_pclks_field = max_pclks_field; 115 LOG(4, ("MAVENTV: WARNING, clamping at highest possible videoclock\n")); 116 } 117 118 /* iterate through all valid PLL postscaler settings */ 119 for (p=0x01; p < 0x10; p = p<<1) 120 { 121 /* calc the needed number of VCO clocks per field for this postscaler setting */ 122 vco_clks_field = req_pclks_field * p; 123 124 /* check if this is within range of the VCO specs */ 125 if ((vco_clks_field >= ((si->ps.min_video_vco * 1000000) / fields_sec)) && 126 (vco_clks_field <= ((si->ps.max_video_vco * 1000000) / fields_sec))) 127 { 128 /* iterate trough all valid reference-frequency postscaler settings */ 129 for (m = 2; m <= m_max; m++) 130 { 131 /* calculate VCO postscaler setting for current setup.. */ 132 n = (int)(((vco_clks_field * m) / ((si->ps.f_ref * 1000000) / fields_sec)) + 0.5); 133 /* ..and check for validity */ 134 if ((n < 8) || (n > 128)) continue; 135 136 /* special TVmode stuff starts here (rest is in fact standard): */ 137 /* calculate number of videoclocks per field */ 138 calc_pclks_field = 139 (((uint32)((si->ps.f_ref * 1000000) / fields_sec)) * n) / ((float)(m * p)); 140 141 /* we need a whole number of clocks per field, otherwise it won't work correctly. 142 * (TVout will flicker, green fields will occur) */ 143 if (calc_pclks_field != (uint32)calc_pclks_field) continue; 144 145 /* check if we have the min. needed number of clocks per field for a sync lock */ 146 if (calc_pclks_field < ((*ht_new * (target.timing.v_total - 1)) + 2)) continue; 147 148 /* calc number of clocks we have for the last field line */ 149 *ht_last_line = calc_pclks_field - (*ht_new * (target.timing.v_total - 1)); 150 151 /* check if we haven't got too much clocks in the last field line for a sync lock */ 152 if (*ht_last_line > *ht_new) continue; 153 154 /* we have a match! */ 155 /* calculate the difference between a full line and the last line */ 156 diff = *ht_new - *ht_last_line; 157 158 /* if this last_line comes closer to a full line than earlier 'hits' then use it */ 159 if (diff < diff_smallest) 160 { 161 /* log results */ 162 if (diff_smallest == 999999999) 163 LOG(2, ("MAVENTV: MATCH, ")); 164 else 165 LOG(2, ("MAVENTV: better MATCH,")); 166 f_vco = (si->ps.f_ref / m) * n; 167 LOG(2, ("found vid VCO freq %fMhz, pixclk %fMhz\n", f_vco, (f_vco / p))); 168 LOG(2, ("MAVENTV: mnp(ex. filter) 0x%02x 0x%02x 0x%02x, h_total %d, ht_lastline %d\n", 169 (m - 1), (n - 1), (p - 1), (*ht_new - 2), (*ht_last_line - 2))); 170 171 /* remember this best match */ 172 diff_smallest = diff; 173 best[0] = m; 174 best[1] = n; 175 best[2] = p; 176 /* h_total to use for this setting: 177 * exclude the 'calculate clock a bit too high' trick */ 178 best[3] = *ht_new - 2; 179 /* ht_last_line to use for this setting: 180 * exclude the 'calculate clock a bit too high' trick */ 181 best[4] = *ht_last_line - 2; 182 } 183 } 184 } 185 } 186 } 187 LOG(2, ("MAVENTV: search completed.\n")); 188 189 /* setup the scalers programming values for found optimum setting */ 190 m = best[0] - 1; 191 n = best[1] - 1; 192 p = best[2] - 1; 193 194 /* if no match was found set fixed PLL frequency so we have something valid at least */ 195 if (diff_smallest == 999999999) 196 { 197 LOG(4, ("MAVENTV: WARNING, no MATCH found!\n")); 198 199 if (si->ps.f_ref == 27.000) 200 { 201 /* set 13.5Mhz */ 202 m = 0x03; 203 n = 0x07; 204 p = 0x03; 205 } else { 206 /* set 14.31818Mhz */ 207 m = 0x01; 208 n = 0x07; 209 p = 0x03; 210 } 211 best[3] = target.timing.h_total; 212 best[4] = target.timing.h_total; 213 } 214 215 /* calc the needed PLL loopbackfilter setting belonging to current VCO speed */ 216 f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); 217 LOG(2, ("MAVENTV: using vid VCO frequency %fMhz\n", f_vco)); 218 219 switch (si->ps.card_type) 220 { 221 case G100: 222 case G200: 223 for (;;) 224 { 225 if (f_vco >= 180) {p |= (0x03 << 3); break;}; 226 if (f_vco >= 140) {p |= (0x02 << 3); break;}; 227 if (f_vco >= 100) {p |= (0x01 << 3); break;}; 228 break; 229 } 230 break; 231 default: 232 for (;;) 233 { 234 if (f_vco >= 240) {p |= (0x03 << 3); break;}; 235 if (f_vco >= 170) {p |= (0x02 << 3); break;}; 236 if (f_vco >= 110) {p |= (0x01 << 3); break;}; 237 break; 238 } 239 break; 240 } 241 242 /* return results */ 243 *m_result = m; 244 *n_result = n; 245 *p_result = p; 246 *ht_new = best[3]; 247 *ht_last_line = best[4]; 248 249 /* display the found pixelclock values */ 250 LOG(2, ("MAVENTV: vid PLL check: got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", 251 (f_vco / ((p & 0x07) + 1)), m, n, p)); 252 LOG(2, ("MAVENTV: new h_total %d, ht_lastline %d\n", *ht_new, *ht_last_line)); 253 254 /* return status */ 255 if (diff_smallest == 999999999) return B_ERROR; 256 return B_OK; 257 } 258 259 /* Notes about timing: 260 * Note: 261 * all horizontal timing is measured in pixelclock periods; 262 * all? vertical timing is measured in field? lines. */ 263 264 /* Note: 265 * <= G400MAX cards have a fixed 27Mhz(?) clock for TV timing register values, 266 * while on G450/G550 these need to be calculated based on the video pixelclock. */ 267 268 269 /* Notes about signal strengths: 270 * Note: 271 * G400 and earlier cards have a fixed reference voltage of +2.6 Volt; 272 * G450 and G550 cards MAVEN DACs have a switchable ref voltage of +1.5/+2.0 Volt. 273 * 274 * This voltage is used to feed the videosignals: 275 * - Hsync pulse level; 276 * - Lowest active video output level; 277 * - Highest active video output level. 278 * These actual voltages are set via 10bit DACs. 279 * 280 * G450/G550: 281 * The color burst amplitude videosignal is fed by 80% of the above mentioned 282 * ref. voltage, and is set via an 8bit DAC. 283 * On G400 and earlier cards the ref. voltage is different, and also differs 284 * for PAL and NTSC mode. */ 285 286 /* Note: 287 * Increasing the distance between the highest and lowest active video output 288 * level increases contrast; decreasing it decreases contrast. */ 289 290 /* Note: 291 * Increasing both the highest and lowest active video output level with the 292 * same amount increases brightness; decreasing it decreases brightness. */ 293 294 /* Note: 295 * Increasing the Hsync pulse level increases the black level, so decreases 296 * brightness and contrast. */ 297 298 /* Preset maven PAL output (625lines, 50Hz mode) */ 299 static void gxx0_maventv_PAL_init(uint8* buffer) 300 { 301 uint16 value; 302 303 /* Chroma subcarrier divider */ 304 buffer[0x00] = 0x2A; 305 buffer[0x01] = 0x09; 306 buffer[0x02] = 0x8A; 307 buffer[0x03] = 0xCB; 308 309 buffer[0x04] = 0x00; 310 buffer[0x05] = 0x00; 311 buffer[0x06] = 0xF9; 312 buffer[0x07] = 0x00; 313 /* Hsync pulse length */ 314 buffer[0x08] = 0x7E; 315 /* color burst length */ 316 buffer[0x09] = 0x44; 317 /* back porch length */ 318 buffer[0x0a] = 0x9C; 319 320 /* color burst amplitude */ 321 if (si->ps.card_type <= G400MAX) 322 { 323 buffer[0x0b] = 0x3e; 324 } 325 else 326 { 327 buffer[0x0b] = 0x48; 328 } 329 330 buffer[0x0c] = 0x21; 331 buffer[0x0d] = 0x00; 332 333 if (si->ps.card_type <= G400MAX) 334 { 335 /* Lowest active video output level. 336 * Warning: make sure this stays above (or equals) the sync pulse level! */ 337 value = 0x0ea; 338 buffer[0x0e] = ((value >> 2) & 0xff); 339 buffer[0x0f] = (value & 0x03); 340 /* horizontal sync pulse level */ 341 buffer[0x10] = ((value >> 2) & 0xff); 342 buffer[0x11] = (value & 0x03); 343 } 344 else 345 { 346 /* Lowest active video output level. 347 * Warning: make sure this stays above (or equals) the sync pulse level! */ 348 value = 0x130; 349 buffer[0x0e] = ((value >> 2) & 0xff); 350 buffer[0x0f] = (value & 0x03); 351 /* horizontal sync pulse level */ 352 buffer[0x10] = ((value >> 2) & 0xff); 353 buffer[0x11] = (value & 0x03); 354 } 355 356 buffer[0x12] = 0x1A; 357 buffer[0x13] = 0x2A; 358 359 /* functional unit */ 360 buffer[0x14] = 0x1C; 361 buffer[0x15] = 0x3D; 362 buffer[0x16] = 0x14; 363 364 /* vertical total */ //(=625) 365 /* b9-2 */ 366 buffer[0x17] = 0x9C; 367 /* b1-0 in b1-0 */ 368 buffer[0x18] = 0x01; 369 370 buffer[0x19] = 0x00; 371 buffer[0x1a] = 0xFE; 372 buffer[0x1b] = 0x7E; 373 buffer[0x1c] = 0x60; 374 buffer[0x1d] = 0x05; 375 376 /* Highest active video output level. 377 * Warning: make sure this stays above the lowest active video output level! */ 378 if (si->ps.card_type <= G400MAX) 379 { 380 value = 0x24f; 381 buffer[0x1e] = ((value >> 2) & 0xff); 382 buffer[0x1f] = (value & 0x03); 383 } 384 else 385 { 386 value = 0x300; 387 buffer[0x1e] = ((value >> 2) & 0xff); 388 buffer[0x1f] = (value & 0x03); 389 } 390 391 /* saturation (field?) #1 */ 392 if (si->ps.card_type <= G400MAX) 393 buffer[0x20] = 0x72; 394 else 395 buffer[0x20] = 0xA5; 396 397 buffer[0x21] = 0x07; 398 399 /* saturation (field?) #2 */ 400 if (si->ps.card_type <= G400MAX) 401 buffer[0x22] = 0x72; 402 else 403 buffer[0x22] = 0xA5; 404 405 buffer[0x23] = 0x00; 406 buffer[0x24] = 0x00; 407 /* hue? */ 408 buffer[0x25] = 0x00; 409 410 buffer[0x26] = 0x08; 411 buffer[0x27] = 0x04; 412 buffer[0x28] = 0x00; 413 buffer[0x29] = 0x1A; 414 415 /* functional unit */ 416 buffer[0x2a] = 0x55; 417 buffer[0x2b] = 0x01; 418 419 /* front porch length */ 420 buffer[0x2c] = 0x26; 421 422 /* functional unit */ 423 buffer[0x2d] = 0x07; 424 buffer[0x2e] = 0x7E; 425 426 /* functional unit */ 427 buffer[0x2f] = 0x02; 428 buffer[0x30] = 0x54; 429 430 /* horizontal visible */ 431 value = 0x580; 432 buffer[0x31] = ((value >> 3) & 0xff); 433 buffer[0x32] = (value & 0x07); 434 435 /* upper blanking (in field lines) */ 436 buffer[0x33] = 0x14; //=((v_total - v_sync_end)/2) -1 437 438 buffer[0x34] = 0x49; 439 buffer[0x35] = 0x00; 440 buffer[0x36] = 0x00; 441 buffer[0x37] = 0xA3; 442 buffer[0x38] = 0xC8; 443 buffer[0x39] = 0x22; 444 buffer[0x3a] = 0x02; 445 buffer[0x3b] = 0x22; 446 447 /* functional unit */ 448 buffer[0x3c] = 0x3F; 449 buffer[0x3d] = 0x03; 450 } 451 452 /* Preset maven NTSC output (525lines, 59.94Hz mode) */ 453 static void gxx0_maventv_NTSC_init(uint8* buffer) 454 { 455 uint16 value; 456 457 /* Chroma subcarrier frequency */ 458 buffer[0x00] = 0x21; 459 buffer[0x01] = 0xF0; 460 buffer[0x02] = 0x7C; 461 buffer[0x03] = 0x1F; 462 463 buffer[0x04] = 0x00; 464 buffer[0x05] = 0x00;//b1 = ON enables colorbar testimage 465 buffer[0x06] = 0xF9;//b0 = ON enables MAVEN TV output 466 buffer[0x07] = 0x00;//influences the colorburst signal amplitude somehow 467 468 /* Hsync pulse length */ 469 buffer[0x08] = 0x7E; 470 /* color burst length */ 471 buffer[0x09] = 0x43; 472 /* back porch length */ 473 buffer[0x0a] = 0x7E; 474 475 /* color burst amplitude */ 476 if (si->ps.card_type <= G400MAX) 477 { 478 buffer[0x0b] = 0x46; 479 } 480 else 481 { 482 buffer[0x0b] = 0x48; 483 } 484 485 buffer[0x0c] = 0x00; 486 buffer[0x0d] = 0x00; 487 488 if (si->ps.card_type <= G400MAX) 489 { 490 /* Lowest active video output level. 491 * Warning: make sure this stays above (or equals) the sync pulse level! */ 492 value = 0x0ea; 493 buffer[0x0e] = ((value >> 2) & 0xff); 494 buffer[0x0f] = (value & 0x03); 495 /* horizontal sync pulse level */ 496 buffer[0x10] = ((value >> 2) & 0xff); 497 buffer[0x11] = (value & 0x03); 498 } 499 else 500 { 501 /* Lowest active video output level. 502 * Warning: make sure this stays above (or equals) the sync pulse level! */ 503 value = 0x130; 504 buffer[0x0e] = ((value >> 2) & 0xff); 505 buffer[0x0f] = (value & 0x03); 506 /* horizontal sync pulse level */ 507 buffer[0x10] = ((value >> 2) & 0xff); 508 buffer[0x11] = (value & 0x03); 509 } 510 511 buffer[0x12] = 0x17; 512 buffer[0x13] = 0x21; 513 514 /* functional unit */ 515 buffer[0x14] = 0x1B; 516 buffer[0x15] = 0x1B; 517 buffer[0x16] = 0x24; 518 519 /* vertical total */ 520 /* b9-2 */ 521 buffer[0x17] = 0x83; 522 /* b1-0 in b1-0 */ 523 buffer[0x18] = 0x01; 524 525 buffer[0x19] = 0x00;//mv register? 526 buffer[0x1a] = 0x0F; 527 buffer[0x1b] = 0x0F; 528 buffer[0x1c] = 0x60; 529 buffer[0x1d] = 0x05; 530 531 /* Highest active video output level. 532 * Warning: make sure this stays above the lowest active video output level! */ 533 if (si->ps.card_type <= G400MAX) 534 { 535 value = 0x24f; 536 buffer[0x1e] = ((value >> 2) & 0xff); 537 buffer[0x1f] = (value & 0x03); 538 } 539 else 540 { 541 value = 0x300; 542 buffer[0x1e] = ((value >> 2) & 0xff); 543 buffer[0x1f] = (value & 0x03); 544 } 545 546 /* color saturation #1 (Y-B ?) */ 547 if (si->ps.card_type <= G400MAX) 548 buffer[0x20] = 0x5F; 549 else 550 buffer[0x20] = 0x9C; 551 552 buffer[0x21] = 0x04; 553 554 /* color saturation #2 (Y-R ?) */ 555 if (si->ps.card_type <= G400MAX) 556 buffer[0x22] = 0x5F; 557 else 558 buffer[0x22] = 0x9C; 559 560 buffer[0x23] = 0x01; 561 buffer[0x24] = 0x02; 562 563 /* hue: preset at 0 degrees */ 564 buffer[0x25] = 0x00; 565 566 buffer[0x26] = 0x0A; 567 buffer[0x27] = 0x05;//sync stuff 568 buffer[0x28] = 0x00; 569 buffer[0x29] = 0x10;//field line-length stuff 570 571 /* functional unit */ 572 buffer[0x2a] = 0xFF; 573 buffer[0x2b] = 0x03; 574 575 /* front porch length */ 576 buffer[0x2c] = 0x24; 577 578 /* functional unit */ 579 buffer[0x2d] = 0x0F; 580 buffer[0x2e] = 0x78; 581 582 /* functional unit */ 583 buffer[0x2f] = 0x00; 584 buffer[0x30] = 0x00; 585 586 /* horizontal visible */ 587 /* b10-3 */ 588 buffer[0x31] = 0xB2; 589 /* b2-0 in b2-0 */ 590 buffer[0x32] = 0x04; 591 592 /* upper blanking (in field lines) */ 593 buffer[0x33] = 0x14; 594 595 buffer[0x34] = 0x02;//colorphase or so stuff. 596 buffer[0x35] = 0x00; 597 buffer[0x36] = 0x00; 598 buffer[0x37] = 0xA3; 599 buffer[0x38] = 0xC8; 600 buffer[0x39] = 0x15; 601 buffer[0x3a] = 0x05; 602 buffer[0x3b] = 0x3B; 603 604 /* functional unit */ 605 buffer[0x3c] = 0x3C; 606 buffer[0x3d] = 0x00; 607 } 608 609 static void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing) 610 { 611 /* values are given in picoseconds */ 612 m_timing->h_total = 64000000; 613 /* the sum of the signal duration below should match h_total! */ 614 m_timing->h_display = 52148148; 615 m_timing->h_sync_length = 4666667; 616 m_timing->front_porch = 1407407; 617 m_timing->back_porch = 5777778; 618 /* colorburst is 'superimposed' on the above timing */ 619 m_timing->color_burst = 2518518; 620 /* number of lines per frame */ 621 m_timing->v_total = 625; 622 /* color carrier frequency in Mhz */ 623 m_timing->chroma_subcarrier = 4.43361875; 624 } 625 626 static void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing) 627 { 628 /* values are given in picoseconds */ 629 m_timing->h_total = 63555556; 630 /* the sum of the signal duration below should match h_total! */ 631 m_timing->h_display = 52888889; 632 m_timing->h_sync_length = 4666667; 633 m_timing->front_porch = 1333333; 634 m_timing->back_porch = 4666667; 635 /* colorburst is 'superimposed' on the above timing */ 636 m_timing->color_burst = 2418418; 637 /* number of lines per frame */ 638 m_timing->v_total = 525; 639 /* color carrier frequency in Mhz */ 640 m_timing->chroma_subcarrier = 3.579545454; 641 } 642 643 int maventv_init(display_mode target) 644 { 645 uint8 val; 646 uint8 m_result, n_result, p_result; 647 unsigned int ht_new, ht_last_line; 648 float calc_pclk; 649 /* use a display_mode copy because we might tune it for TVout compatibility */ 650 display_mode tv_target = target; 651 /* used as buffer for TVout signal to generate */ 652 uint8 maventv_regs[64]; 653 /* used in G450/G550 to calculate TVout signal timing dependant on pixelclock; 654 * <= G400MAX use fixed settings because base-clock here is the fixed crystal 655 * frequency. */ 656 //fixme: 657 //if <=G400 cards with MAVEN and crystal of 14.31818Mhz exist, modify!?! 658 //only saw 27Mhz versions of G100 and G200 that (can) hold a MAVEN upto now... 659 gx50_maven_timing m_timing; 660 661 /* preset new TVout mode */ 662 if ((tv_target.flags & TV_BITS) == TV_PAL) 663 { 664 LOG(4, ("MAVENTV: PAL TVout\n")); 665 gxx0_maventv_PAL_init(maventv_regs); 666 gx50_maventv_PAL_timing(&m_timing); 667 } 668 else 669 { 670 LOG(4, ("MAVENTV: NTSC TVout\n")); 671 gxx0_maventv_NTSC_init(maventv_regs); 672 gx50_maventv_NTSC_timing(&m_timing); 673 } 674 675 /* enter mode-program mode */ 676 if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x01); 677 else 678 { 679 DXIW(TVO_IDX, MGAMAV_PGM); 680 DXIW(TVO_DATA, 0x01); 681 } 682 683 /* tune new TVout mode */ 684 if (si->ps.card_type <= G400MAX) 685 { 686 /* setup TV-mode 'copy' of CRTC2, setup PLL, inputs, outputs and sync-locks */ 687 MAVW(MONSET, 0x00); 688 MAVW(MONEN, 0xA2); 689 690 /* xmiscctrl */ 691 //unknown regs: 692 MAVWW(WREG_0X8E_L, 0x1EFF); 693 MAVW(BREG_0XC6, 0x01); 694 695 MAVW(LOCK, 0x01); 696 MAVW(OUTMODE, 0x08); 697 698 /* set high contrast/brightness range for TVout */ 699 /* Note: 700 * b4-5 have contrast/brightness function during TVout, while these bits 701 * are used to set sync polarity in a serial fashion during monitor modes. 702 * Setting both these bits here will 'increase' the sync polarity offset 703 * by one! */ 704 MAVW(LUMA, 0x78); 705 /* We just made a sync polarity programming step for monitor modes, so: 706 * note the offset from 'reset position' we will have now. 707 * Note: 708 * Not applicable for singlehead cards with a MAVEN, since it's only used 709 * for TVout there. */ 710 si->maven_syncpol_offset += 1; 711 if (si->maven_syncpol_offset > 3) si->maven_syncpol_offset = 0; 712 713 //unknown regs: 714 MAVW(STABLE, 0x02); 715 MAVW(MONEN, 0xB3); 716 717 /* modify mode to center and size correctly on TV */ 718 { 719 int diff; 720 float uscan_fact; 721 bool tweak = false; /* needed for NTSC VCD mode */ 722 723 if (!(tv_target.flags & TV_VIDEO)) /* Desktop modes */ 724 { 725 LOG(4,("MAVENTV: setting underscanning ('downscaled') desktop mode\n")); 726 727 /* adapt mode to underscan correctly */ 728 if ((tv_target.timing.h_display < 704) && ((tv_target.flags & TV_BITS) == TV_PAL)) 729 { 730 /* can't be higher because of scaling limitations in MAVEN! */ 731 uscan_fact = 0.76; 732 } 733 else 734 { 735 /* optimal setting for desktop modes.. */ 736 uscan_fact = 0.80; 737 } 738 /* horizontal */ 739 tv_target.timing.h_total = (tv_target.timing.h_display / uscan_fact); 740 /* adhere to CRTC constraints */ 741 tv_target.timing.h_total &= ~0x0007; 742 /* vertical */ 743 tv_target.timing.v_total = (tv_target.timing.v_display / uscan_fact); 744 745 /* now do vertical centering */ 746 if ((tv_target.flags & TV_BITS) == TV_PAL) 747 { 748 diff = tv_target.timing.v_total - tv_target.timing.v_display; 749 tv_target.timing.v_sync_start = tv_target.timing.v_display + ((diff * 7) / 20); 750 /* sync all the way 'to the end' to prevent vertical overscanning 751 * rubbish on top of screen due to MAVEN hardware design fault */ 752 tv_target.timing.v_sync_end = tv_target.timing.v_total; 753 } 754 else 755 { 756 diff = tv_target.timing.v_total - tv_target.timing.v_display; 757 tv_target.timing.v_sync_start = tv_target.timing.v_display + ((diff * 5) / 20); 758 /* sync all the way 'to the end' to prevent vertical overscanning 759 * rubbish on top of screen due to MAVEN hardware design fault */ 760 tv_target.timing.v_sync_end = tv_target.timing.v_total; 761 } 762 } 763 else /* Video modes */ 764 { 765 uint16 mode = 766 (((tv_target.flags & TV_BITS) << (14 - 9)) | tv_target.timing.h_display); 767 768 LOG(4,("MAVENTV: setting overscanning ('unscaled') video mode\n")); 769 770 /* adapt standard modes to be displayed 1:1 */ 771 switch (mode) 772 { 773 case ((TV_NTSC << (14 - 9)) | 640): /* NTSC VCD mode */ 774 /* horizontal: adhere to CRTC granularity (8) */ 775 /* Note: h_total = 704 has no PLL match! */ 776 tv_target.timing.h_total = 696; 777 /* because this 'low' horizontal resolution cannot be scaled up 778 * for overscanning use (MAVEN restriction) we need to do some 779 * tweaking to get a mode we can work with that still has the 780 * correct aspect ratio. 781 * This mode has just a little bit horizontal overscanning. */ 782 tweak = true; 783 break; 784 case ((TV_NTSC << (14 - 9)) | 720): /* NTSC DVD mode */ 785 /* horizontal: adhere to CRTC granularity (8) */ 786 tv_target.timing.h_total = 784; 787 /* MGA_TVOs need additional tweaking */ 788 if (!si->ps.secondary_head) si->crtc_delay += 12; 789 break; 790 case ((TV_PAL << (14 - 9)) | 768): /* PAL VCD mode */ 791 /* horizontal: adhere to CRTC granularity (8) */ 792 tv_target.timing.h_total = 832; 793 break; 794 case ((TV_PAL << (14 - 9)) | 720): /* PAL DVD mode */ 795 /* horizontal: adhere to CRTC granularity (8) */ 796 tv_target.timing.h_total = 784; 797 break; 798 default: 799 /* non-standard mode: just hope for he best. */ 800 break; 801 } 802 803 /* now do vertical centering and clipping */ 804 if ((tv_target.flags & TV_BITS) == TV_PAL) 805 { 806 /* defined by the PAL standard */ 807 tv_target.timing.v_total = m_timing.v_total; 808 /* we need to center the image on TV vertically. 809 * note that 576 is the maximum supported resolution for the PAL standard, 810 * this is already overscanning by approx 8-10% */ 811 diff = 576 - tv_target.timing.v_display; 812 /* if we cannot display the current vertical resolution fully, clip it */ 813 if (diff < 0) 814 { 815 tv_target.timing.v_display = 576; 816 diff = 0; 817 } 818 /* now center the image on TV */ 819 tv_target.timing.v_sync_start = tv_target.timing.v_display + (diff / 2); 820 /* sync all the way 'to the end' to prevent vertical overscanning 821 * rubbish on top of screen due to MAVEN hardware design fault */ 822 /* note: probably invisible in these Video modes */ 823 tv_target.timing.v_sync_end = tv_target.timing.v_total; 824 } 825 else 826 { 827 /* defined by the NTSC standard */ 828 tv_target.timing.v_total = m_timing.v_total; 829 /* NTSC VCD mode needs to be scaled down vertically to get correct 830 * aspect ratio... */ 831 if (tweak) tv_target.timing.v_total += 32; 832 /* we need to center the image on TV vertically. 833 * note that 480 is the maximum supported resolution for the NTSC standard, 834 * this is already overscanning by approx 8-10% */ 835 diff = 480 - tv_target.timing.v_display; 836 /* if we cannot display the current vertical resolution fully, clip it */ 837 if (diff < 0) 838 { 839 tv_target.timing.v_display = 480; 840 diff = 0; 841 } 842 /* now center the image on TV */ 843 tv_target.timing.v_sync_start = tv_target.timing.v_display + (diff / 2); 844 /* ...NTSC VCD mode needs to be moved up to center the tweaked mode 845 * correcty... */ 846 if (tweak) tv_target.timing.v_sync_start += 9; 847 /* sync all the way 'to the end' to prevent vertical overscanning 848 * rubbish on top of screen due to MAVEN hardware design fault */ 849 /* note: might be visible in the NTSC VCD Video mode */ 850 tv_target.timing.v_sync_end = tv_target.timing.v_total; 851 } 852 } 853 854 /* finally do horizontal centering */ 855 if ((tv_target.flags & TV_BITS) == TV_PAL) 856 { 857 diff = tv_target.timing.h_total - tv_target.timing.h_display; 858 if (!si->ps.secondary_head) 859 { 860 tv_target.timing.h_sync_start = tv_target.timing.h_display - 16 + (diff / 2); 861 /* keep adhering to CRTC constraints */ 862 tv_target.timing.h_sync_start &= ~0x0007; 863 tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 32; 864 } 865 else 866 { 867 tv_target.timing.h_sync_start = tv_target.timing.h_display - 0 + (diff / 2); 868 /* keep adhering to CRTC constraints */ 869 tv_target.timing.h_sync_start &= ~0x0007; 870 tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 16; 871 } 872 } 873 else 874 { 875 diff = tv_target.timing.h_total - tv_target.timing.h_display; 876 tv_target.timing.h_sync_start = tv_target.timing.h_display - 16 + (diff / 2); 877 /* ...and finally the NTSC VCD mode needs to be moved to the right to 878 * center the tweaked mode correctly. */ 879 if (tweak) tv_target.timing.h_sync_start -= 16; 880 /* keep adhering to CRTC constraints */ 881 tv_target.timing.h_sync_start &= ~0x0007; 882 tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 16; 883 } 884 } 885 886 /* tune crtc delay */ 887 if ((tv_target.timing.h_display >= 1000) && (((tv_target.flags & TV_BITS) != TV_PAL))) 888 { 889 si->crtc_delay += 1; 890 } 891 else 892 { 893 si->crtc_delay -= 3; 894 } 895 896 /* setup video PLL */ 897 g100_g400max_maventv_vid_pll_find( 898 tv_target, &ht_new, &ht_last_line, &m_result, &n_result, &p_result); 899 MAVW(PIXPLLM, m_result); 900 MAVW(PIXPLLN, n_result); 901 MAVW(PIXPLLP, (p_result | 0x80)); 902 903 MAVW(MONSET, 0x20); 904 905 MAVW(TEST, 0x10); 906 907 /* htotal - 2 */ 908 MAVWW(HTOTALL, ht_new); 909 910 /* last line in field can have different length */ 911 /* hlen - 2 */ 912 MAVWW(LASTLINEL, ht_last_line); 913 914 /* horizontal vidrst pos: 0 <= vidrst pos <= htotal - 2 */ 915 MAVWW(HVIDRSTL, (ht_last_line - si->crtc_delay - 916 (tv_target.timing.h_sync_end - tv_target.timing.h_sync_start))); 917 //ORG (does the same but with limit checks but these limits should never occur!): 918 // slen = tv_target.timing.h_sync_end - tv_target.timing.h_sync_start; 919 // hcrt = tv_target.timing.h_total - slen - si->crtc_delay; 920 // if (ht_last_line < tv_target.timing.h_total) hcrt += ht_last_line; 921 // if (hcrt > tv_target.timing.h_total) hcrt -= tv_target.timing.h_total; 922 // if (hcrt + 2 > tv_target.timing.h_total) hcrt = 0; /* or issue warning? */ 923 // MAVWW(HVIDRSTL, hcrt); 924 925 /* who knows */ 926 MAVWW(HSYNCSTRL, 0x0004);//must be 4!! 927 928 /* hblanking end: 100% */ 929 MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end)); 930 931 /* vertical line count - 1 */ 932 MAVWW(VTOTALL, (tv_target.timing.v_total - 1)); 933 934 /* vertical vidrst pos */ 935 MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2)); 936 937 /* something end... [A6]+1..[A8] */ 938 MAVWW(VSYNCSTRL, 0x0001); 939 940 /* vblanking end: stop vblanking */ 941 MAVWW(VSYNCLENL, (tv_target.timing.v_sync_end - tv_target.timing.v_sync_start - 1)); 942 //org: no visible diff: 943 //MAVWW(VSYNCLENL, (tv_target.timing.v_total - tv_target.timing.v_sync_start - 1)); 944 945 /* something start... 0..[A4]-1 */ 946 MAVWW(VDISPLAYL, 0x0000); 947 //std setmode (no visible difference) 948 //MAVWW(VDISPLAYL, (tv_target.timing.v_total - 1)); 949 950 /* ... */ 951 MAVWW(WREG_0X98_L, 0x0000); 952 953 /* moves picture up/down and so on... */ 954 MAVWW(VSOMETHINGL, 0x0001); /* Fix this... 0..VTotal */ 955 956 { 957 uint32 h_display_tv; 958 uint8 h_scale_tv; 959 960 unsigned int ib_min_length; 961 unsigned int ib_length; 962 int index; 963 964 /* calc hor scale-back factor from input to output picture (in 1.7 format) 965 * the MAVEN has 736 pixels fixed total outputline length for TVout */ 966 h_scale_tv = (736 << 7) / tv_target.timing.h_total;//should be PLL corrected 967 LOG(4,("MAVENTV: horizontal scale-back factor is: %f\n", (h_scale_tv / 128.0))); 968 969 /* limit values to MAVEN capabilities (scale-back factor is 0.5-1.0) */ 970 if (h_scale_tv > 0x80) 971 { 972 h_scale_tv = 0x80; 973 LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); 974 } 975 if (h_scale_tv < 0x40) 976 { 977 h_scale_tv = 0x40; 978 LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); 979 } 980 /* make sure we get no round-off error artifacts on screen */ 981 h_scale_tv--; 982 983 /* calc difference in (wanted output picture width (excl. hsync_length)) and 984 * (fixed total output line length (=768)), 985 * based on input picture and scaling factor */ 986 /* (MAVEN trick (part 1) to get output picture width to fit into just 8 bits) */ 987 h_display_tv = ((768 - 1) << 7) - 988 (((tv_target.timing.h_total - tv_target.timing.h_sync_end) /* is left margin */ 989 + tv_target.timing.h_display - 8) 990 * h_scale_tv); 991 /* convert result from 25.7 to 32.0 format */ 992 h_display_tv = h_display_tv >> 7; 993 LOG(4,("MAVENTV: displaying output on %d picture pixels\n", 994 ((768 - 1) - h_display_tv))); 995 996 /* half result: MAVEN trick (part 2) 997 * (258 - 768 pixels, only even number per line is possible) */ 998 h_display_tv = h_display_tv >> 1; 999 /* limit value to register contraints */ 1000 if (h_display_tv > 0xFF) h_display_tv = 0xFF; 1001 MAVW(HSCALETV, h_scale_tv); 1002 MAVW(HDISPLAYTV, h_display_tv); 1003 1004 1005 /* calculate line inputbuffer length */ 1006 /* It must be between (including): 1007 * ((input picture left margin) + (input picture hor. resolution) + 4) 1008 * AND 1009 * (input picture total line length) (PLL corrected) */ 1010 1011 /* calculate minimal line input buffer length */ 1012 ib_min_length = ((tv_target.timing.h_total - tv_target.timing.h_sync_end) + 1013 tv_target.timing.h_display + 4); 1014 1015 /* calculate optimal line input buffer length (so top of picture is OK too) */ 1016 /* The following formula applies: 1017 * optimal buffer length = ((((0x78 * i) - R) / hor. scaling factor) + Q) 1018 * 1019 * where (in 4.8 format!) 1020 * R Qmin Qmax 1021 * 0x0E0 0x5AE 0x5BF 1022 * 0x100 0x5CF 0x5FF 1023 * 0x180 0x653 0x67F 1024 * 0x200 0x6F8 0x6FF 1025 */ 1026 index = 1; 1027 do 1028 { 1029 ib_length = ((((((0x7800 << 7) * index) - (0x100 << 7)) / h_scale_tv) + 0x05E7) >> 8); 1030 index++; 1031 } while (ib_length < ib_min_length); 1032 LOG(4,("MAVENTV: optimal line inputbuffer length: %d\n", ib_length)); 1033 1034 if (ib_length >= ht_new + 2) 1035 { 1036 ib_length = ib_min_length; 1037 LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length)); 1038 } 1039 MAVWW(HDISPLAYL, ib_length); 1040 } 1041 1042 { 1043 uint16 t_scale_tv; 1044 uint32 v_display_tv; 1045 1046 /* calc total scale-back factor from input to output picture */ 1047 { 1048 uint32 out_clocks; 1049 uint32 in_clocks; 1050 1051 //takes care of green stripes: 1052 /* calc output clocks per frame */ 1053 out_clocks = m_timing.v_total * (ht_new + 2); 1054 1055 /* calc input clocks per frame */ 1056 in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) + ht_last_line + 2; 1057 1058 /* calc total scale-back factor from input to output picture in 1.15 format */ 1059 t_scale_tv = ((((uint64)out_clocks) << 15) / in_clocks); 1060 LOG(4,("MAVENTV: total scale-back factor is: %f\n", (t_scale_tv / 32768.0))); 1061 1062 /* min. scale-back factor is 1.0 for 1:1 output */ 1063 if (t_scale_tv > 0x8000) 1064 { 1065 t_scale_tv = 0x8000; 1066 LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0))); 1067 } 1068 } 1069 1070 /*calc output picture height based on input picture and scaling factor */ 1071 //warning: v_display was 'one' lower originally! 1072 v_display_tv = 1073 ((tv_target.timing.v_sync_end - tv_target.timing.v_sync_start) /* is sync length */ 1074 + (tv_target.timing.v_total - tv_target.timing.v_sync_end) /* is upper margin */ 1075 + tv_target.timing.v_display) 1076 * t_scale_tv; 1077 /* convert result from 17.15 to 32.0 format */ 1078 v_display_tv = (v_display_tv >> 15); 1079 LOG(4,("MAVENTV: displaying output on %d picture frame-lines\n", v_display_tv)); 1080 1081 /* half result, and compensate for internal register offset 1082 * (MAVEN trick to get it to fit into just 8 bits). 1083 * (allowed output frame height is 292 - 802 lines, only even numbers) */ 1084 v_display_tv = (v_display_tv >> 1) - 146; 1085 /* limit value to register contraints */ 1086 if (v_display_tv > 0xFF) v_display_tv = 0xFF; 1087 /* make sure we get no round-off error artifacts on screen */ 1088 t_scale_tv--; 1089 1090 MAVWW(TSCALETVL, t_scale_tv); 1091 MAVW(VDISPLAYTV, v_display_tv); 1092 } 1093 1094 MAVW(TEST, 0x00); 1095 1096 /* gamma correction registers */ 1097 MAVW(GAMMA1, 0x00); 1098 MAVW(GAMMA2, 0x00); 1099 MAVW(GAMMA3, 0x00); 1100 MAVW(GAMMA4, 0x1F); 1101 MAVW(GAMMA5, 0x10); 1102 MAVW(GAMMA6, 0x10); 1103 MAVW(GAMMA7, 0x10); 1104 MAVW(GAMMA8, 0x64); /* 100 */ 1105 MAVW(GAMMA9, 0xC8); /* 200 */ 1106 1107 /* set flickerfilter */ 1108 if (!(tv_target.flags & TV_VIDEO)) 1109 { 1110 /* Desktop modes (those are scaled): filter on to prevent artifacts */ 1111 MAVW(FFILTER, 0xa2); 1112 LOG(4,("MAVENTV: enabling flicker filter\n")); 1113 } 1114 else 1115 { 1116 /* Video modes (those are unscaled): filter off to increase sharpness */ 1117 //fixme? OFF is dependant on MAVEN version(?): MGA_TVO_B = $40, else $00. 1118 MAVW(FFILTER, 0x00); 1119 LOG(4,("MAVENTV: disabling flicker filter\n")); 1120 } 1121 1122 /* 0x10 or anything ored with it */ 1123 //fixme? linux uses 0x14... 1124 MAVW(TEST, (MAVR(TEST) & 0x10)); 1125 1126 /* output: SVideo/Composite */ 1127 MAVW(OUTMODE, 0x08); 1128 } 1129 else /* card_type is >= G450 */ 1130 { 1131 //fixme: setup an intermediate buffer if vertical res is different than settings below! 1132 //fixme: setup 2D or 3D engine to do screen_to_screen_scaled_filtered_blit between the buffers 1133 // during vertical retrace! 1134 if ((tv_target.flags & TV_BITS) == TV_PAL) 1135 { 1136 int diff; 1137 1138 /* defined by the PAL standard */ 1139 tv_target.timing.v_total = m_timing.v_total; 1140 /* we need to center the image on TV vertically. 1141 * note that 576 is the maximum supported resolution for the PAL standard, 1142 * this is already overscanning by approx 8-10% */ 1143 diff = 576 - tv_target.timing.v_display; 1144 /* if we cannot display the current vertical resolution fully, clip it */ 1145 if (diff < 0) 1146 { 1147 tv_target.timing.v_display = 576; 1148 diff = 0; 1149 } 1150 /* now center the image on TV by centering the vertical sync pulse */ 1151 tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); 1152 tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; 1153 } 1154 else 1155 { 1156 int diff; 1157 1158 /* defined by the NTSC standard */ 1159 tv_target.timing.v_total = m_timing.v_total; 1160 /* we need to center the image on TV vertically. 1161 * note that 480 is the maximum supported resolution for the NTSC standard, 1162 * this is already overscanning by approx 8-10% */ 1163 diff = 480 - tv_target.timing.v_display; 1164 /* if we cannot display the current vertical resolution fully, clip it */ 1165 if (diff < 0) 1166 { 1167 tv_target.timing.v_display = 480; 1168 diff = 0; 1169 } 1170 /* now center the image on TV by centering the vertical sync pulse */ 1171 tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); 1172 tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; 1173 } 1174 1175 /* setup video PLL for G450/G550: 1176 * this can be done in the normal way because the MAVEN works in slave mode! 1177 * NOTE: must be done before programming CRTC2, or interlaced startup may fail. */ 1178 1179 //fixme: make sure videoPLL is powered up: XPWRCTRL b1=1 1180 { 1181 uint16 front_porch, back_porch, h_sync_length, burst_length, h_total, h_display; 1182 uint32 chromasc; 1183 uint64 pix_period; 1184 uint16 h_total_wanted, leftover; 1185 1186 /* calculate tv_h_display in 'half pixelclocks' and adhere to MAVEN restrictions. 1187 * ('half pixelclocks' exist because the MAVEN uses them...) */ 1188 h_display = (((tv_target.timing.h_display << 1) + 3) & ~0x03); 1189 if (h_display > 2044) h_display = 2044; 1190 /* copy result to MAVEN TV mode */ 1191 maventv_regs[0x31] = (h_display >> 3); 1192 maventv_regs[0x32] = (h_display & 0x07); 1193 1194 /* calculate needed video pixelclock in kHz. 1195 * NOTE: 1196 * The clock calculated is based on MAVEN output, so each pixelclock period 1197 * is in fact a 'half pixelclock' period compared to monitor mode use. */ 1198 tv_target.timing.pixel_clock = 1199 ((((uint64)h_display) * 1000000000) / m_timing.h_display); 1200 1201 /* tune display_mode adhering to CRTC2 restrictions */ 1202 /* (truncate h_display to 'whole pixelclocks') */ 1203 tv_target.timing.h_display = ((h_display >> 1) & ~0x07); 1204 tv_target.timing.h_sync_start = tv_target.timing.h_display + 8; 1205 1206 g450_g550_maven_vid_pll_find(tv_target, &calc_pclk, &m_result, &n_result, &p_result, 1); 1207 /* adjust mode to actually used pixelclock */ 1208 tv_target.timing.pixel_clock = (calc_pclk * 1000); 1209 1210 /* program videoPLL */ 1211 DXIW(VIDPLLM, m_result); 1212 DXIW(VIDPLLN, n_result); 1213 DXIW(VIDPLLP, p_result); 1214 1215 /* calculate videoclock 'half' period duration in picoseconds */ 1216 pix_period = (1000000000 / ((float)tv_target.timing.pixel_clock)) + 0.5; 1217 LOG(4,("MAVENTV: TV videoclock period is %d picoseconds\n", pix_period)); 1218 1219 /* calculate number of 'half' clocks per line according to pixelclock set */ 1220 /* fixme: try to setup the modes in such a way that 1221 * (h_total_clk % 16) == 0 because of the CRTC2 restrictions: 1222 * we want to loose the truncating h_total trick below if possible! */ 1223 /* Note: 1224 * This is here so we can see the wanted and calc'd timing difference. */ 1225 h_total_wanted = ((m_timing.h_total / ((float)pix_period)) + 0.5); 1226 LOG(4,("MAVENTV: TV h_total should be %d units\n", h_total_wanted)); 1227 1228 /* calculate chroma subcarrier value to setup: 1229 * do this as exact as possible because this signal is very sensitive.. */ 1230 chromasc = 1231 ((((uint64)0x100000000) * (m_timing.chroma_subcarrier / calc_pclk)) + 0.5); 1232 /* copy result to MAVEN TV mode */ 1233 maventv_regs[0] = ((chromasc >> 24) & 0xff); 1234 maventv_regs[1] = ((chromasc >> 16) & 0xff); 1235 maventv_regs[2] = ((chromasc >> 8) & 0xff); 1236 maventv_regs[3] = ((chromasc >> 0) & 0xff); 1237 LOG(4,("MAVENTV: TV chroma subcarrier divider set is $%08x\n", chromasc)); 1238 1239 /* calculate front porch in 'half pixelclocks' */ 1240 /* we always round up because of the h_total truncating 'trick' below, 1241 * which works in combination with the existing difference between 1242 * h_total_clk and h_total */ 1243 //fixme: prevent this if possible! 1244 front_porch = ((m_timing.front_porch / ((float)pix_period)) + 1); 1245 /* value must be even */ 1246 front_porch &= ~0x01; 1247 1248 /* calculate back porch in 'half pixelclocks' */ 1249 /* we always round up because of the h_total truncating 'trick' below, 1250 * which works in combination with the existing difference between 1251 * h_total_clk and h_total */ 1252 //fixme: prevent this if possible! 1253 back_porch = ((m_timing.back_porch / ((float)pix_period)) + 1); 1254 /* value must be even */ 1255 back_porch &= ~0x01; 1256 1257 /* calculate h_sync length in 'half pixelclocks' */ 1258 /* we always round up because of the h_total truncating 'trick' below, 1259 * which works in combination with the existing difference between 1260 * h_total_clk and h_total */ 1261 //fixme: prevent this if possible! 1262 h_sync_length = ((m_timing.h_sync_length / ((float)pix_period)) + 1); 1263 /* value must be even */ 1264 h_sync_length &= ~0x01; 1265 1266 /* calculate h_total in 'half pixelclocks' */ 1267 h_total = h_display + front_porch + back_porch + h_sync_length; 1268 1269 LOG(4,("MAVENTV: TV front_porch is %d clocks\n", front_porch)); 1270 LOG(4,("MAVENTV: TV back_porch is %d clocks\n", back_porch)); 1271 LOG(4,("MAVENTV: TV h_sync_length is %d clocks\n", h_sync_length)); 1272 LOG(4,("MAVENTV: TV h_display is %d clocks \n", h_display)); 1273 LOG(4,("MAVENTV: TV h_total is %d clocks\n", h_total)); 1274 1275 /* calculate color_burst length in 'half pixelclocks' */ 1276 burst_length = (((m_timing.color_burst /*- 1*/) / ((float)pix_period)) + 0.5); 1277 LOG(4,("MAVENTV: TV color_burst is %d clocks.\n", burst_length)); 1278 1279 /* copy result to MAVEN TV mode */ 1280 maventv_regs[0x09] = burst_length; 1281 1282 /* Calculate line length 'rest' that remains after truncating 1283 * h_total to adhere to the CRTC2 timing restrictions. */ 1284 leftover = h_total & 0x0F; 1285 /* if some 'rest' exists, we need to compensate for it... */ 1286 /* Note: 1287 * It's much better to prevent this from happening because this 1288 * 'trick' will decay TVout timing! (timing is nolonger official) */ 1289 if (leftover) 1290 { 1291 /* truncate line length to adhere to CRTC2 restrictions */ 1292 front_porch -= leftover; 1293 h_total -= leftover; 1294 1295 /* now set line length to closest CRTC2 valid match */ 1296 if (leftover < 3) 1297 { 1298 /* 1 <= old rest <= 2: 1299 * Truncated line length is closest match. */ 1300 LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n")); 1301 } 1302 else 1303 { 1304 if (leftover < 10) 1305 { 1306 /* 3 <= old rest <= 9: 1307 * We use the NTSC killer circuitry to get closest match. 1308 * (The 'g400_crtc2_set_timing' routine will enable it 1309 * because of the illegal h_total timing we create here.) */ 1310 front_porch += 4; 1311 h_total += 4; 1312 LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via killer (> 2, < 10)\n")); 1313 } 1314 else 1315 { 1316 /* 10 <= old rest <= 15: 1317 * Set closest valid CRTC2 match. */ 1318 front_porch += 16; 1319 h_total += 16; 1320 LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via increase (> 9, < 16)\n")); 1321 } 1322 } 1323 } 1324 1325 /* (linux) fixme: maybe MAVEN has requirement 800 < h_total < 1184 */ 1326 maventv_regs[0x2C] = front_porch; 1327 maventv_regs[0x0A] = back_porch; 1328 maventv_regs[0x08] = h_sync_length; 1329 1330 /* change h_total to represent 'whole pixelclocks' */ 1331 h_total = h_total >> 1; 1332 1333 /* tune display_mode adhering to CRTC2 restrictions */ 1334 tv_target.timing.h_sync_end = (h_total & ~0x07) - 8; 1335 /* h_total is checked before being programmed! (NTSC killer circuitry) */ 1336 tv_target.timing.h_total = h_total; 1337 } 1338 1339 /* output Y/C and CVBS signals (| $40 needed for SCART) */ 1340 DXIW(TVO_IDX, 0x80); 1341 DXIW(TVO_DATA, 0x03); 1342 1343 /* select input colorspace */ 1344 //fixme?: has no effect on output picture on monitor or TV... 1345 //DXIW(TVO_IDX, 0x81); 1346 //DXIW(TVO_DATA, 0x00); 1347 1348 /* calculate vertical sync point */ 1349 { 1350 int upper; 1351 1352 /* set 625 lines for PAL or 525 lines for NTSC */ 1353 maventv_regs[0x17] = m_timing.v_total / 4; 1354 maventv_regs[0x18] = m_timing.v_total & 3; 1355 1356 /* calculate upper blanking range in field lines */ 1357 upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1; 1358 1359 /* blank TVout above the line number calculated */ 1360 maventv_regs[0x33] = upper - 1; 1361 1362 /* set calculated vertical sync point */ 1363 DXIW(TVO_IDX, 0x82); 1364 DXIW(TVO_DATA, (upper & 0xff)); 1365 DXIW(TVO_IDX, 0x83); 1366 DXIW(TVO_DATA, ((upper >> 8) & 0xff)); 1367 LOG(4,("MAVENTV: TV upper blanking range set is %d\n", upper)); 1368 } 1369 1370 /* set fized horizontal sync point */ 1371 DXIW(TVO_IDX, 0x84); 1372 DXIW(TVO_DATA, 0x01); 1373 DXIW(TVO_IDX, 0x85); 1374 DXIW(TVO_DATA, 0x00); 1375 1376 /* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (TVout mode) */ 1377 DXIW(OUTPUTCONN,0x0d); 1378 } 1379 1380 /* program new TVout mode */ 1381 for (val = 0x00; val <= 0x3D; val++) 1382 { 1383 if (si->ps.card_type <= G400MAX) 1384 { 1385 i2c_maven_write(val, maventv_regs[val]); 1386 } 1387 else 1388 { 1389 DXIW(TVO_IDX, val); 1390 DXIW(TVO_DATA, maventv_regs[val]); 1391 } 1392 } 1393 1394 /* leave mode-program mode */ 1395 if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x00); 1396 else 1397 { 1398 DXIW(TVO_IDX, MGAMAV_PGM); 1399 DXIW(TVO_DATA, 0x00); 1400 1401 /* Select 2.0 Volt MAVEN DAC ref. so we have enough contrast/brightness range */ 1402 DXIW(GENIOCTRL, DXIR(GENIOCTRL) | 0x40); 1403 DXIW(GENIODATA, 0x00); 1404 } 1405 1406 /* setup CRTC timing */ 1407 if (si->ps.secondary_head) 1408 { 1409 /* on dualhead cards TVout is always used on CRTC2 */ 1410 g400_crtc2_set_timing(tv_target); 1411 } 1412 else 1413 { 1414 /* on singlehead cards TVout is always used on CRTC1 */ 1415 gx00_crtc_set_timing(tv_target); 1416 } 1417 1418 /* start whole thing if needed */ 1419 if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20); 1420 1421 return 0; 1422 } 1423