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