BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / accelerants / via / engine / tvout.c
blob577f1328b9c20fd8746c1101af1e08b1d0e13cc6
1 /* Authors:
2 Mark Watson 2000,
3 Rudolf Cornelissen 1/2003-12/2003
5 Thanx to Petr Vandrovec for writing matroxfb.
6 */
8 #define MODULE_BIT 0x00100000
10 #include "std.h"
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;
23 void gxx0_maventv_PAL_init(uint8* buffer);
24 void gxx0_maventv_NTSC_init(uint8* buffer);
25 void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing);
26 void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing);
28 //fixme: setup fixed CRTC2 modes for all modes and block other modes:
29 // - 640x480, 800x600, 1024x768 NTSC and PAL overscan compensated modes (desktop)
30 // - 640x480, 720x480 NTSC and 768x576, 720x576 non-overscan compensated modes (video)
31 //fixme: try to implement 'fast' and 'slow' settings for all modes,
32 // so buffer duplication or skipping won't be neccesary for realtime video.
33 //fixme: try to setup the CRTC2 in interlaced mode for the video modes on <= G400MAX cards.
35 /* find 'exact' valid video PLL setting */
36 status_t g100_g400max_maventv_vid_pll_find(
37 display_mode target, unsigned int * ht_new, unsigned int * ht_last_line,
38 uint8 * m_result, uint8 * n_result, uint8 * p_result)
40 int m = 0, n = 0, p = 0, m_max;
41 float diff, diff_smallest = 999999999;
42 int best[5], h_total_mod;
43 float fields_sec, f_vco;
44 /* We need to be exact, so work with clockperiods per field instead of with frequency.
45 * Make sure however we truncate these clocks to be integers!
46 * (The NTSC field frequency would otherwise prevent the 'whole number of clocks per field'
47 * check done in this routine later on...) */
48 uint32 vco_clks_field, max_pclks_field, req_pclks_field;
49 /* We need this variable to be a float, because we need to be able to verify if this
50 * represents a whole number of clocks per field later on! */
51 float calc_pclks_field;
53 LOG(2,("MAVENTV: searching for EXACT videoclock match\n"));
55 /* determine the max. reference-frequency postscaler setting for the current card */
56 //fixme: check G100 and G200 m_max if exist and possible...
57 switch(si->ps.card_type)
59 /* case G100:
60 LOG(2,("MAVENTV: G100 restrictions apply\n"));
61 m_max = 32;
62 break;
63 case G200:
64 LOG(2,("MAVENTV: G200 restrictions apply\n"));
65 m_max = 32;
66 break;
67 */ default:
68 LOG(2,("MAVENTV: G400/G400MAX restrictions apply\n"));
69 m_max = 32;
70 break;
73 /* set number of fields per second to generate */
74 if ((target.flags & TV_BITS) == TV_PAL)
75 fields_sec = 50.0;
76 else
77 fields_sec = 59.94;
79 /* determine the max. pixelclock for the current videomode */
80 switch (target.space)
82 case B_RGB16_LITTLE:
83 max_pclks_field = (si->ps.max_dac2_clock_16 * 1000000) / fields_sec;
84 break;
85 case B_RGB32_LITTLE:
86 max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec;
87 break;
88 default:
89 /* use fail-safe value */
90 max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec;
91 break;
93 /* if some dualhead mode is active, an extra restriction might apply */
94 if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
95 max_pclks_field = (si->ps.max_dac2_clock_32dh * 1000000) / fields_sec;
97 /* Checkout all possible Htotal settings within the current granularity step
98 * of CRTC2 to get a real close videoclock match!
99 * (The MAVEN apparantly has a granularity of 1 pixel, while CRTC2 has 8 pixels) */
100 for (h_total_mod = 0; h_total_mod < 8; h_total_mod++)
102 LOG(2,("MAVENTV: trying h_total modification of +%d...\n", h_total_mod));
104 /* Calculate videoclock to be a bit to high so we can compensate for an exact
105 * match via h_total_lastline.. */
106 *ht_new = target.timing.h_total + h_total_mod + 2;
108 /* Make sure the requested pixelclock is within the PLL's operational limits */
109 /* lower limit is min_video_vco divided by highest postscaler-factor */
110 req_pclks_field = *ht_new * target.timing.v_total;
111 if (req_pclks_field < (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0))
113 req_pclks_field = (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0);
114 LOG(4,("MAVENTV: WARNING, clamping at lowest possible videoclock\n"));
116 /* upper limit is given by pins in combination with current active mode */
117 if (req_pclks_field > max_pclks_field)
119 req_pclks_field = max_pclks_field;
120 LOG(4,("MAVENTV: WARNING, clamping at highest possible videoclock\n"));
123 /* iterate through all valid PLL postscaler settings */
124 for (p=0x01; p < 0x10; p = p<<1)
126 /* calc the needed number of VCO clocks per field for this postscaler setting */
127 vco_clks_field = req_pclks_field * p;
129 /* check if this is within range of the VCO specs */
130 if ((vco_clks_field >= ((si->ps.min_video_vco * 1000000) / fields_sec)) &&
131 (vco_clks_field <= ((si->ps.max_video_vco * 1000000) / fields_sec)))
133 /* iterate trough all valid reference-frequency postscaler settings */
134 for (m = 2; m <= m_max; m++)
136 /* calculate VCO postscaler setting for current setup.. */
137 n = (int)(((vco_clks_field * m) / ((si->ps.f_ref * 1000000) / fields_sec)) + 0.5);
138 /* ..and check for validity */
139 if ((n < 8) || (n > 128)) continue;
141 /* special TVmode stuff starts here (rest is in fact standard): */
142 /* calculate number of videoclocks per field */
143 calc_pclks_field =
144 (((uint32)((si->ps.f_ref * 1000000) / fields_sec)) * n) / ((float)(m * p));
146 /* we need a whole number of clocks per field, otherwise it won't work correctly.
147 * (TVout will flicker, green fields will occur) */
148 if (calc_pclks_field != (uint32)calc_pclks_field) continue;
150 /* check if we have the min. needed number of clocks per field for a sync lock */
151 if (calc_pclks_field < ((*ht_new * (target.timing.v_total - 1)) + 2)) continue;
153 /* calc number of clocks we have for the last field line */
154 *ht_last_line = calc_pclks_field - (*ht_new * (target.timing.v_total - 1));
156 /* check if we haven't got too much clocks in the last field line for a sync lock */
157 if (*ht_last_line > *ht_new) continue;
159 /* we have a match! */
160 /* calculate the difference between a full line and the last line */
161 diff = *ht_new - *ht_last_line;
163 /* if this last_line comes closer to a full line than earlier 'hits' then use it */
164 if (diff < diff_smallest)
166 /* log results */
167 if (diff_smallest == 999999999)
168 LOG(2,("MAVENTV: MATCH, "));
169 else
170 LOG(2,("MAVENTV: better MATCH,"));
171 f_vco = (si->ps.f_ref / m) * n;
172 LOG(2,("found vid VCO freq %fMhz, pixclk %fMhz\n", f_vco, (f_vco / p)));
173 LOG(2,("MAVENTV: mnp(ex. filter) 0x%02x 0x%02x 0x%02x, h_total %d, ht_lastline %d\n",
174 (m - 1), (n - 1), (p - 1), (*ht_new - 2), (*ht_last_line - 2)));
176 /* remember this best match */
177 diff_smallest = diff;
178 best[0] = m;
179 best[1] = n;
180 best[2] = p;
181 /* h_total to use for this setting:
182 * exclude the 'calculate clock a bit too high' trick */
183 best[3] = *ht_new - 2;
184 /* ht_last_line to use for this setting:
185 * exclude the 'calculate clock a bit too high' trick */
186 best[4] = *ht_last_line - 2;
192 LOG(2,("MAVENTV: search completed.\n"));
194 /* setup the scalers programming values for found optimum setting */
195 m = best[0] - 1;
196 n = best[1] - 1;
197 p = best[2] - 1;
199 /* if no match was found set fixed PLL frequency so we have something valid at least */
200 if (diff_smallest == 999999999)
202 LOG(4,("MAVENTV: WARNING, no MATCH found!\n"));
204 if (si->ps.f_ref == 27.000)
206 /* set 13.5Mhz */
207 m = 0x03;
208 n = 0x07;
209 p = 0x03;
211 else
213 /* set 14.31818Mhz */
214 m = 0x01;
215 n = 0x07;
216 p = 0x03;
218 best[3] = target.timing.h_total;
219 best[4] = target.timing.h_total;
222 /* calc the needed PLL loopbackfilter setting belonging to current VCO speed */
223 f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
224 LOG(2,("MAVENTV: using vid VCO frequency %fMhz\n", f_vco));
226 switch(si->ps.card_type)
228 /* case G100:
229 case G200:
230 for(;;)
232 if (f_vco >= 180) {p |= (0x03 << 3); break;};
233 if (f_vco >= 140) {p |= (0x02 << 3); break;};
234 if (f_vco >= 100) {p |= (0x01 << 3); break;};
235 break;
237 break;
238 */ default:
239 for(;;)
241 if (f_vco >= 240) {p |= (0x03 << 3); break;};
242 if (f_vco >= 170) {p |= (0x02 << 3); break;};
243 if (f_vco >= 110) {p |= (0x01 << 3); break;};
244 break;
246 break;
249 /* return results */
250 *m_result = m;
251 *n_result = n;
252 *p_result = p;
253 *ht_new = best[3];
254 *ht_last_line = best[4];
256 /* display the found pixelclock values */
257 LOG(2,("MAVENTV: vid PLL check: got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
258 (f_vco / ((p & 0x07) + 1)), m, n, p));
259 LOG(2,("MAVENTV: new h_total %d, ht_lastline %d\n", *ht_new, *ht_last_line));
261 /* return status */
262 if (diff_smallest == 999999999) return B_ERROR;
263 return B_OK;
266 /* Notes about timing:
267 * Note:
268 * all horizontal timing is measured in pixelclock periods;
269 * all? vertical timing is measured in field? lines. */
271 /* Note:
272 * <= G400MAX cards have a fixed 27Mhz(?) clock for TV timing register values,
273 * while on G450/G550 these need to be calculated based on the video pixelclock. */
276 /* Notes about signal strengths:
277 * Note:
278 * G400 and earlier cards have a fixed reference voltage of +2.6 Volt;
279 * G450 and G550 cards MAVEN DACs have a switchable ref voltage of +1.5/+2.0 Volt.
281 * This voltage is used to feed the videosignals:
282 * - Hsync pulse level;
283 * - Lowest active video output level;
284 * - Highest active video output level.
285 * These actual voltages are set via 10bit DACs.
287 * G450/G550:
288 * The color burst amplitude videosignal is fed by 80% of the above mentioned
289 * ref. voltage, and is set via an 8bit DAC.
290 * On G400 and earlier cards the ref. voltage is different, and also differs
291 * for PAL and NTSC mode. */
293 /* Note:
294 * Increasing the distance between the highest and lowest active video output
295 * level increases contrast; decreasing it decreases contrast. */
297 /* Note:
298 * Increasing both the highest and lowest active video output level with the
299 * same amount increases brightness; decreasing it decreases brightness. */
301 /* Note:
302 * Increasing the Hsync pulse level increases the black level, so decreases
303 * brightness and contrast. */
305 /* Preset maven PAL output (625lines, 50Hz mode) */
306 void gxx0_maventv_PAL_init(uint8* buffer)
308 uint16 value;
310 /* Chroma subcarrier divider */
311 buffer[0x00] = 0x2A;
312 buffer[0x01] = 0x09;
313 buffer[0x02] = 0x8A;
314 buffer[0x03] = 0xCB;
316 buffer[0x04] = 0x00;
317 buffer[0x05] = 0x00;
318 buffer[0x06] = 0xF9;
319 buffer[0x07] = 0x00;
320 /* Hsync pulse length */
321 buffer[0x08] = 0x7E;
322 /* color burst length */
323 buffer[0x09] = 0x44;
324 /* back porch length */
325 buffer[0x0a] = 0x9C;
327 /* color burst amplitude */
328 /* if (si->ps.card_type <= G400MAX)
330 buffer[0x0b] = 0x3e;
332 else
334 */ buffer[0x0b] = 0x48;
335 // }
337 buffer[0x0c] = 0x21;
338 buffer[0x0d] = 0x00;
340 // if (si->ps.card_type <= G400MAX)
341 // {
342 /* Lowest active video output level.
343 * Warning: make sure this stays above (or equals) the sync pulse level! */
344 // value = 0x0ea;
345 // buffer[0x0e] = ((value >> 2) & 0xff);
346 // buffer[0x0f] = (value & 0x03);
347 /* horizontal sync pulse level */
348 // buffer[0x10] = ((value >> 2) & 0xff);
349 // buffer[0x11] = (value & 0x03);
350 // }
351 // else
353 /* Lowest active video output level.
354 * Warning: make sure this stays above (or equals) the sync pulse level! */
355 value = 0x130;
356 buffer[0x0e] = ((value >> 2) & 0xff);
357 buffer[0x0f] = (value & 0x03);
358 /* horizontal sync pulse level */
359 buffer[0x10] = ((value >> 2) & 0xff);
360 buffer[0x11] = (value & 0x03);
363 buffer[0x12] = 0x1A;
364 buffer[0x13] = 0x2A;
366 /* functional unit */
367 buffer[0x14] = 0x1C;
368 buffer[0x15] = 0x3D;
369 buffer[0x16] = 0x14;
371 /* vertical total */ //(=625)
372 /* b9-2 */
373 buffer[0x17] = 0x9C;
374 /* b1-0 in b1-0 */
375 buffer[0x18] = 0x01;
377 buffer[0x19] = 0x00;
378 buffer[0x1a] = 0xFE;
379 buffer[0x1b] = 0x7E;
380 buffer[0x1c] = 0x60;
381 buffer[0x1d] = 0x05;
383 /* Highest active video output level.
384 * Warning: make sure this stays above the lowest active video output level! */
385 /* if (si->ps.card_type <= G400MAX)
387 value = 0x24f;
388 buffer[0x1e] = ((value >> 2) & 0xff);
389 buffer[0x1f] = (value & 0x03);
391 else
392 */ {
393 value = 0x300;
394 buffer[0x1e] = ((value >> 2) & 0xff);
395 buffer[0x1f] = (value & 0x03);
398 /* saturation (field?) #1 */
399 // if (si->ps.card_type <= G400MAX)
400 // buffer[0x20] = 0x72;
401 // else
402 buffer[0x20] = 0xA5;
404 buffer[0x21] = 0x07;
406 /* saturation (field?) #2 */
407 // if (si->ps.card_type <= G400MAX)
408 // buffer[0x22] = 0x72;
409 // else
410 buffer[0x22] = 0xA5;
412 buffer[0x23] = 0x00;
413 buffer[0x24] = 0x00;
414 /* hue? */
415 buffer[0x25] = 0x00;
417 buffer[0x26] = 0x08;
418 buffer[0x27] = 0x04;
419 buffer[0x28] = 0x00;
420 buffer[0x29] = 0x1A;
422 /* functional unit */
423 buffer[0x2a] = 0x55;
424 buffer[0x2b] = 0x01;
426 /* front porch length */
427 buffer[0x2c] = 0x26;
429 /* functional unit */
430 buffer[0x2d] = 0x07;
431 buffer[0x2e] = 0x7E;
433 /* functional unit */
434 buffer[0x2f] = 0x02;
435 buffer[0x30] = 0x54;
437 /* horizontal visible */
438 value = 0x580;
439 buffer[0x31] = ((value >> 3) & 0xff);
440 buffer[0x32] = (value & 0x07);
442 /* upper blanking (in field lines) */
443 buffer[0x33] = 0x14; //=((v_total - v_sync_end)/2) -1
445 buffer[0x34] = 0x49;
446 buffer[0x35] = 0x00;
447 buffer[0x36] = 0x00;
448 buffer[0x37] = 0xA3;
449 buffer[0x38] = 0xC8;
450 buffer[0x39] = 0x22;
451 buffer[0x3a] = 0x02;
452 buffer[0x3b] = 0x22;
454 /* functional unit */
455 buffer[0x3c] = 0x3F;
456 buffer[0x3d] = 0x03;
459 /* Preset maven NTSC output (525lines, 59.94Hz mode) */
460 void gxx0_maventv_NTSC_init(uint8* buffer)
462 uint16 value;
464 /* Chroma subcarrier frequency */
465 buffer[0x00] = 0x21;
466 buffer[0x01] = 0xF0;
467 buffer[0x02] = 0x7C;
468 buffer[0x03] = 0x1F;
470 buffer[0x04] = 0x00;
471 buffer[0x05] = 0x00;//b1 = ON enables colorbar testimage
472 buffer[0x06] = 0xF9;//b0 = ON enables MAVEN TV output
473 buffer[0x07] = 0x00;//influences the colorburst signal amplitude somehow
475 /* Hsync pulse length */
476 buffer[0x08] = 0x7E;
477 /* color burst length */
478 buffer[0x09] = 0x43;
479 /* back porch length */
480 buffer[0x0a] = 0x7E;
482 /* color burst amplitude */
483 // if (si->ps.card_type <= G400MAX)
484 // {
485 // buffer[0x0b] = 0x46;
486 // }
487 // else
489 buffer[0x0b] = 0x48;
492 buffer[0x0c] = 0x00;
493 buffer[0x0d] = 0x00;
495 // if (si->ps.card_type <= G400MAX)
496 // {
497 /* Lowest active video output level.
498 * Warning: make sure this stays above (or equals) the sync pulse level! */
499 // value = 0x0ea;
500 // buffer[0x0e] = ((value >> 2) & 0xff);
501 // buffer[0x0f] = (value & 0x03);
502 /* horizontal sync pulse level */
503 // buffer[0x10] = ((value >> 2) & 0xff);
504 // buffer[0x11] = (value & 0x03);
505 // }
506 // else
508 /* Lowest active video output level.
509 * Warning: make sure this stays above (or equals) the sync pulse level! */
510 value = 0x130;
511 buffer[0x0e] = ((value >> 2) & 0xff);
512 buffer[0x0f] = (value & 0x03);
513 /* horizontal sync pulse level */
514 buffer[0x10] = ((value >> 2) & 0xff);
515 buffer[0x11] = (value & 0x03);
518 buffer[0x12] = 0x17;
519 buffer[0x13] = 0x21;
521 /* functional unit */
522 buffer[0x14] = 0x1B;
523 buffer[0x15] = 0x1B;
524 buffer[0x16] = 0x24;
526 /* vertical total */
527 /* b9-2 */
528 buffer[0x17] = 0x83;
529 /* b1-0 in b1-0 */
530 buffer[0x18] = 0x01;
532 buffer[0x19] = 0x00;//mv register?
533 buffer[0x1a] = 0x0F;
534 buffer[0x1b] = 0x0F;
535 buffer[0x1c] = 0x60;
536 buffer[0x1d] = 0x05;
538 /* Highest active video output level.
539 * Warning: make sure this stays above the lowest active video output level! */
540 /* if (si->ps.card_type <= G400MAX)
542 value = 0x24f;
543 buffer[0x1e] = ((value >> 2) & 0xff);
544 buffer[0x1f] = (value & 0x03);
546 else
547 */ {
548 value = 0x300;
549 buffer[0x1e] = ((value >> 2) & 0xff);
550 buffer[0x1f] = (value & 0x03);
553 /* color saturation #1 (Y-B ?) */
554 // if (si->ps.card_type <= G400MAX)
555 // buffer[0x20] = 0x5F;
556 // else
557 buffer[0x20] = 0x9C;
559 buffer[0x21] = 0x04;
561 /* color saturation #2 (Y-R ?) */
562 // if (si->ps.card_type <= G400MAX)
563 // buffer[0x22] = 0x5F;
564 // else
565 buffer[0x22] = 0x9C;
567 buffer[0x23] = 0x01;
568 buffer[0x24] = 0x02;
570 /* hue: preset at 0 degrees */
571 buffer[0x25] = 0x00;
573 buffer[0x26] = 0x0A;
574 buffer[0x27] = 0x05;//sync stuff
575 buffer[0x28] = 0x00;
576 buffer[0x29] = 0x10;//field line-length stuff
578 /* functional unit */
579 buffer[0x2a] = 0xFF;
580 buffer[0x2b] = 0x03;
582 /* front porch length */
583 buffer[0x2c] = 0x24;
585 /* functional unit */
586 buffer[0x2d] = 0x0F;
587 buffer[0x2e] = 0x78;
589 /* functional unit */
590 buffer[0x2f] = 0x00;
591 buffer[0x30] = 0x00;
593 /* horizontal visible */
594 /* b10-3 */
595 buffer[0x31] = 0xB2;
596 /* b2-0 in b2-0 */
597 buffer[0x32] = 0x04;
599 /* upper blanking (in field lines) */
600 buffer[0x33] = 0x14;
602 buffer[0x34] = 0x02;//colorphase or so stuff.
603 buffer[0x35] = 0x00;
604 buffer[0x36] = 0x00;
605 buffer[0x37] = 0xA3;
606 buffer[0x38] = 0xC8;
607 buffer[0x39] = 0x15;
608 buffer[0x3a] = 0x05;
609 buffer[0x3b] = 0x3B;
611 /* functional unit */
612 buffer[0x3c] = 0x3C;
613 buffer[0x3d] = 0x00;
616 void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing)
618 /* values are given in picoseconds */
619 m_timing->h_total = 64000000;
620 /* the sum of the signal duration below should match h_total! */
621 m_timing->h_display = 52148148;
622 m_timing->h_sync_length = 4666667;
623 m_timing->front_porch = 1407407;
624 m_timing->back_porch = 5777778;
625 /* colorburst is 'superimposed' on the above timing */
626 m_timing->color_burst = 2518518;
627 /* number of lines per frame */
628 m_timing->v_total = 625;
629 /* color carrier frequency in Mhz */
630 m_timing->chroma_subcarrier = 4.43361875;
633 void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing)
635 /* values are given in picoseconds */
636 m_timing->h_total = 63555556;
637 /* the sum of the signal duration below should match h_total! */
638 m_timing->h_display = 52888889;
639 m_timing->h_sync_length = 4666667;
640 m_timing->front_porch = 1333333;
641 m_timing->back_porch = 4666667;
642 /* colorburst is 'superimposed' on the above timing */
643 m_timing->color_burst = 2418418;
644 /* number of lines per frame */
645 m_timing->v_total = 525;
646 /* color carrier frequency in Mhz */
647 m_timing->chroma_subcarrier = 3.579545454;
650 int maventv_init(display_mode target)
652 uint8 val;
653 uint8 m_result, n_result, p_result;
654 unsigned int ht_new, ht_last_line;
655 float calc_pclk = 0;
656 /* use a display_mode copy because we might tune it for TVout compatibility */
657 display_mode tv_target = target;
658 /* used as buffer for TVout signal to generate */
659 uint8 maventv_regs[64];
660 /* used in G450/G550 to calculate TVout signal timing dependant on pixelclock;
661 * <= G400MAX use fixed settings because base-clock here is the fixed crystal
662 * frequency. */
663 //fixme: if <=G400 cards with MAVEN and crystal of 14.31818Mhz exist, modify!?!
664 gx50_maven_timing m_timing;
666 /* preset new TVout mode */
667 if ((tv_target.flags & TV_BITS) == TV_PAL)
669 LOG(4, ("MAVENTV: PAL TVout\n"));
670 gxx0_maventv_PAL_init(maventv_regs);
671 gx50_maventv_PAL_timing(&m_timing);
673 else
675 LOG(4, ("MAVENTV: NTSC TVout\n"));
676 gxx0_maventv_NTSC_init(maventv_regs);
677 gx50_maventv_NTSC_timing(&m_timing);
680 /* enter mode-program mode */
681 // if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x01);
682 // else
683 // {
684 // DXIW(TVO_IDX, ENMAV_PGM);
685 // DXIW(TVO_DATA, 0x01);
686 // }
688 /* tune new TVout mode */
689 // if (si->ps.card_type <= G400MAX)
691 /* setup TV-mode 'copy' of CRTC2, setup PLL, inputs, outputs and sync-locks */
692 // MAVW(MONSET, 0x00);
693 // MAVW(MONEN, 0xA2);
695 /* xmiscctrl */
696 //unknown regs:
697 // MAVWW(WREG_0X8E_L, 0x1EFF);
698 // MAVW(BREG_0XC6, 0x01);
700 // MAVW(LOCK, 0x01);
701 // MAVW(OUTMODE, 0x08);
702 // MAVW(LUMA, 0x78);
703 // MAVW(STABLE, 0x02);
704 // MAVW(MONEN, 0xB3);
706 /* setup video PLL */
707 g100_g400max_maventv_vid_pll_find(
708 tv_target, &ht_new, &ht_last_line, &m_result, &n_result, &p_result);
709 // MAVW(PIXPLLM, m_result);
710 // MAVW(PIXPLLN, n_result);
711 // MAVW(PIXPLLP, (p_result | 0x80));
713 // MAVW(MONSET, 0x20);
715 // MAVW(TEST, 0x10);
717 /* htotal - 2 */
718 // MAVWW(HTOTALL, ht_new);
720 /* last line in field can have different length */
721 /* hlen - 2 */
722 // MAVWW(LASTLINEL, ht_last_line);
724 /* horizontal vidrst pos: 0 <= vidrst pos <= htotal - 2 */
725 // MAVWW(HVIDRSTL, (ht_last_line - si->crtc_delay -
726 // (tv_target.timing.h_sync_end - tv_target.timing.h_sync_start)));
727 //ORG (does the same but with limit checks but these limits should never occur!):
728 // slen = tv_target.timing.h_sync_end - tv_target.timing.h_sync_start;
729 // hcrt = tv_target.timing.h_total - slen - si->crtc_delay;
730 // if (ht_last_line < tv_target.timing.h_total) hcrt += ht_last_line;
731 // if (hcrt > tv_target.timing.h_total) hcrt -= tv_target.timing.h_total;
732 // if (hcrt + 2 > tv_target.timing.h_total) hcrt = 0; /* or issue warning? */
733 // MAVWW(HVIDRSTL, hcrt);
735 /* who knows */
736 // MAVWW(HSYNCSTRL, 0x0004);//must be 4!!
738 /* hblanking end: 100% */
739 // MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end));
741 /* vertical line count - 1 */
742 // MAVWW(VTOTALL, (tv_target.timing.v_total - 1));
744 /* vertical vidrst pos */
745 // MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2));
747 /* something end... [A6]+1..[A8] */
748 // MAVWW(VSYNCSTRL, 0x0001);
750 /* vblanking end: stop vblanking */
751 // MAVWW(VSYNCLENL, (tv_target.timing.v_sync_end - tv_target.timing.v_sync_start - 1));
752 //org: no visible diff:
753 //MAVWW(VSYNCLENL, (tv_target.timing.v_total - tv_target.timing.v_sync_start - 1));
755 /* something start... 0..[A4]-1 */
756 // MAVWW(VDISPLAYL, 0x0000);
757 //std setmode (no visible difference)
758 //MAVWW(VDISPLAYL, (tv_target.timing.v_total - 1));
760 /* ... */
761 // MAVWW(WREG_0X98_L, 0x0000);
763 /* moves picture up/down and so on... */
764 // MAVWW(VSOMETHINGL, 0x0001); /* Fix this... 0..VTotal */
767 uint32 h_display_tv;
768 uint8 h_scale_tv;
770 unsigned int ib_min_length;
771 unsigned int ib_length;
772 int index;
774 /* calc hor scale-back factor from input to output picture (in 1.7 format)
775 * the MAVEN has 736 pixels fixed visible? outputline length for TVout */
776 //fixme: shouldn't this be 768 (= PAL 1:1 output 4:3 ratio format)?!?
777 h_scale_tv = (736 << 7) / tv_target.timing.h_total;//should be PLL corrected
778 LOG(4,("MAVENTV: horizontal scale-back factor is: %f\n", (h_scale_tv / 128.0)));
780 /* limit values to MAVEN capabilities (scale-back factor is 0.5-1.0) */
781 //fixme: how about lowres upscaling?
782 if (h_scale_tv > 0x80)
784 h_scale_tv = 0x80;
785 LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
787 if (h_scale_tv < 0x40)
789 h_scale_tv = 0x40;
790 LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
792 /* make sure we get no round-off error artifacts on screen */
793 h_scale_tv--;
795 /* calc difference in (wanted output picture width (excl. hsync_length)) and
796 * (fixed total output line length (=768)),
797 * based on input picture and scaling factor */
798 /* (MAVEN trick (part 1) to get output picture width to fit into just 8 bits) */
799 h_display_tv = ((768 - 1) << 7) -
800 (((tv_target.timing.h_total - tv_target.timing.h_sync_end) /* is left margin */
801 + tv_target.timing.h_display - 8)
802 * h_scale_tv);
803 /* convert result from 25.7 to 32.0 format */
804 h_display_tv = h_display_tv >> 7;
805 LOG(4,("MAVENTV: displaying output on %d picture pixels\n",
806 ((768 - 1) - h_display_tv)));
808 /* half result: MAVEN trick (part 2)
809 * (258 - 768 pixels, only even number per line is possible) */
810 h_display_tv = h_display_tv >> 1;
811 /* limit value to register contraints */
812 if (h_display_tv > 0xFF) h_display_tv = 0xFF;
813 // MAVW(HSCALETV, h_scale_tv);
814 // MAVW(HDISPLAYTV, h_display_tv);
817 /* calculate line inputbuffer length */
818 /* It must be between (including):
819 * ((input picture left margin) + (input picture hor. resolution) + 4)
820 * AND
821 * (input picture total line length) (PLL corrected) */
823 /* calculate minimal line input buffer length */
824 ib_min_length = ((tv_target.timing.h_total - tv_target.timing.h_sync_end) +
825 tv_target.timing.h_display + 4);
827 /* calculate optimal line input buffer length (so top of picture is OK too) */
828 /* The following formula applies:
829 * optimal buffer length = ((((0x78 * i) - R) / hor. scaling factor) + Q)
831 * where (in 4.8 format!)
832 * R Qmin Qmax
833 * 0x0E0 0x5AE 0x5BF
834 * 0x100 0x5CF 0x5FF
835 * 0x180 0x653 0x67F
836 * 0x200 0x6F8 0x6FF
838 index = 1;
841 ib_length = ((((((0x7800 << 7) * index) - (0x100 << 7)) / h_scale_tv) + 0x05E7) >> 8);
842 index++;
843 } while (ib_length < ib_min_length);
844 LOG(4,("MAVENTV: optimal line inputbuffer length: %d\n", ib_length));
846 if (ib_length >= ht_new + 2)
848 ib_length = ib_min_length;
849 LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length));
851 // MAVWW(HDISPLAYL, ib_length);
855 uint16 t_scale_tv;
856 uint32 v_display_tv;
858 /* calc total scale-back factor from input to output picture */
860 uint32 out_clocks;
861 uint32 in_clocks;
863 //takes care of green stripes:
864 /* calc output clocks per frame */
865 out_clocks = m_timing.v_total * (ht_new + 2);
867 /* calc input clocks per frame */
868 in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) + ht_last_line + 2;
870 /* calc total scale-back factor from input to output picture in 1.15 format */
871 t_scale_tv = ((((uint64)out_clocks) << 15) / in_clocks);
872 LOG(4,("MAVENTV: total scale-back factor is: %f\n", (t_scale_tv / 32768.0)));
874 /* min. scale-back factor is 1.0 for 1:1 output */
875 if (t_scale_tv > 0x8000)
877 t_scale_tv = 0x8000;
878 LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0)));
882 /*calc output picture height based on input picture and scaling factor */
883 //warning: v_display was 'one' lower originally!
884 v_display_tv =
885 ((tv_target.timing.v_sync_end - tv_target.timing.v_sync_start) /* is sync length */
886 + (tv_target.timing.v_total - tv_target.timing.v_sync_end) /* is upper margin */
887 + tv_target.timing.v_display)
888 * t_scale_tv;
889 /* convert result from 17.15 to 32.0 format */
890 v_display_tv = (v_display_tv >> 15);
891 LOG(4,("MAVENTV: displaying output on %d picture frame-lines\n", v_display_tv));
893 /* half result, and compensate for internal register offset
894 * (MAVEN trick to get it to fit into just 8 bits).
895 * (allowed output frame height is 292 - 802 lines, only even numbers) */
896 v_display_tv = (v_display_tv >> 1) - 146;
897 /* limit value to register contraints */
898 if (v_display_tv > 0xFF) v_display_tv = 0xFF;
899 /* make sure we get no round-off error artifacts on screen */
900 t_scale_tv--;
902 // MAVWW(TSCALETVL, t_scale_tv);
903 // MAVW(VDISPLAYTV, v_display_tv);
906 // MAVW(TEST, 0x00);
908 /* gamma correction registers */
909 // MAVW(GAMMA1, 0x00);
910 // MAVW(GAMMA2, 0x00);
911 // MAVW(GAMMA3, 0x00);
912 // MAVW(GAMMA4, 0x1F);
913 // MAVW(GAMMA5, 0x10);
914 // MAVW(GAMMA6, 0x10);
915 // MAVW(GAMMA7, 0x10);
916 // MAVW(GAMMA8, 0x64); /* 100 */
917 // MAVW(GAMMA9, 0xC8); /* 200 */
919 /* set flickerfilter */
920 /* OFF: is dependant on MAVEN chip version(?): ENG_TVO_B = $40, else $00.
921 * ON : always set $a2. */
922 // MAVW(FFILTER, 0xa2);
924 /* 0x10 or anything ored with it */
925 //fixme? linux uses 0x14...
926 // MAVW(TEST, (MAVR(TEST) & 0x10));
928 /* output: SVideo/Composite */
929 // MAVW(OUTMODE, 0x08);
931 // else /* card_type is >= G450 */
933 //fixme: setup an intermediate buffer if vertical res is different than settings below!
934 //fixme: setup 2D or 3D engine to do screen_to_screen_scaled_filtered_blit between the buffers
935 // during vertical retrace!
936 if ((tv_target.flags & TV_BITS) == TV_PAL)
938 int diff;
940 /* defined by the PAL standard */
941 tv_target.timing.v_total = m_timing.v_total;
942 /* we need to center the image on TV vertically.
943 * note that 576 is the maximum supported resolution for the PAL standard,
944 * this is already overscanning by approx 8-10% */
945 diff = 576 - tv_target.timing.v_display;
946 /* if we cannot display the current vertical resolution fully, clip it */
947 if (diff < 0)
949 tv_target.timing.v_display = 576;
950 diff = 0;
952 /* now center the image on TV by centering the vertical sync pulse */
953 tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2);
954 tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1;
956 else
958 int diff;
960 /* defined by the NTSC standard */
961 tv_target.timing.v_total = m_timing.v_total;
962 /* we need to center the image on TV vertically.
963 * note that 480 is the maximum supported resolution for the NTSC standard,
964 * this is already overscanning by approx 8-10% */
965 diff = 480 - tv_target.timing.v_display;
966 /* if we cannot display the current vertical resolution fully, clip it */
967 if (diff < 0)
969 tv_target.timing.v_display = 480;
970 diff = 0;
972 /* now center the image on TV by centering the vertical sync pulse */
973 tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2);
974 tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1;
977 /* setup video PLL for G450/G550:
978 * this can be done in the normal way because the MAVEN works in slave mode!
979 * NOTE: must be done before programming CRTC2, or interlaced startup may fail. */
981 //fixme: make sure videoPLL is powered up: XPWRCTRL b1=1
983 uint16 front_porch, back_porch, h_sync_length, burst_length, h_total, h_display;
984 uint32 chromasc;
985 uint64 pix_period;
986 uint16 h_total_wanted, leftover;
988 /* calculate tv_h_display in 'half pixelclocks' and adhere to MAVEN restrictions.
989 * ('half pixelclocks' exist because the MAVEN uses them...) */
990 h_display = (((tv_target.timing.h_display << 1) + 3) & ~0x03);
991 if (h_display > 2044) h_display = 2044;
992 /* copy result to MAVEN TV mode */
993 maventv_regs[0x31] = (h_display >> 3);
994 maventv_regs[0x32] = (h_display & 0x07);
996 /* calculate needed video pixelclock in kHz.
997 * NOTE:
998 * The clock calculated is based on MAVEN output, so each pixelclock period
999 * is in fact a 'half pixelclock' period compared to monitor mode use. */
1000 tv_target.timing.pixel_clock =
1001 ((((uint64)h_display) * 1000000000) / m_timing.h_display);
1003 /* tune display_mode adhering to CRTC2 restrictions */
1004 /* (truncate h_display to 'whole pixelclocks') */
1005 tv_target.timing.h_display = ((h_display >> 1) & ~0x07);
1006 tv_target.timing.h_sync_start = tv_target.timing.h_display + 8;
1008 // g450_g550_maven_vid_pll_find(tv_target, &calc_pclk, &m_result, &n_result, &p_result, 1);
1009 /* adjust mode to actually used pixelclock */
1010 tv_target.timing.pixel_clock = (calc_pclk * 1000);
1012 /* program videoPLL */
1013 // DXIW(VIDPLLM, m_result);
1014 // DXIW(VIDPLLN, n_result);
1015 // DXIW(VIDPLLP, p_result);
1017 /* calculate videoclock 'half' period duration in picoseconds */
1018 pix_period = (1000000000 / ((float)tv_target.timing.pixel_clock)) + 0.5;
1019 LOG(4,("MAVENTV: TV videoclock period is %d picoseconds\n", pix_period));
1021 /* calculate number of 'half' clocks per line according to pixelclock set */
1022 /* fixme: try to setup the modes in such a way that
1023 * (h_total_clk % 16) == 0 because of the CRTC2 restrictions:
1024 * we want to loose the truncating h_total trick below if possible! */
1025 /* Note:
1026 * This is here so we can see the wanted and calc'd timing difference. */
1027 h_total_wanted = ((m_timing.h_total / ((float)pix_period)) + 0.5);
1028 LOG(4,("MAVENTV: TV h_total should be %d units\n", h_total_wanted));
1030 /* calculate chroma subcarrier value to setup:
1031 * do this as exact as possible because this signal is very sensitive.. */
1032 chromasc =
1033 ((((uint64)0x100000000) * (m_timing.chroma_subcarrier / calc_pclk)) + 0.5);
1034 /* copy result to MAVEN TV mode */
1035 maventv_regs[0] = ((chromasc >> 24) & 0xff);
1036 maventv_regs[1] = ((chromasc >> 16) & 0xff);
1037 maventv_regs[2] = ((chromasc >> 8) & 0xff);
1038 maventv_regs[3] = ((chromasc >> 0) & 0xff);
1039 LOG(4,("MAVENTV: TV chroma subcarrier divider set is $%08x\n", chromasc));
1041 /* calculate front porch in 'half pixelclocks' */
1042 /* we always round up because of the h_total truncating 'trick' below,
1043 * which works in combination with the existing difference between
1044 * h_total_clk and h_total */
1045 //fixme: prevent this if possible!
1046 front_porch = ((m_timing.front_porch / ((float)pix_period)) + 1);
1047 /* value must be even */
1048 front_porch &= ~0x01;
1050 /* calculate back porch in 'half pixelclocks' */
1051 /* we always round up because of the h_total truncating 'trick' below,
1052 * which works in combination with the existing difference between
1053 * h_total_clk and h_total */
1054 //fixme: prevent this if possible!
1055 back_porch = ((m_timing.back_porch / ((float)pix_period)) + 1);
1056 /* value must be even */
1057 back_porch &= ~0x01;
1059 /* calculate h_sync length in 'half pixelclocks' */
1060 /* we always round up because of the h_total truncating 'trick' below,
1061 * which works in combination with the existing difference between
1062 * h_total_clk and h_total */
1063 //fixme: prevent this if possible!
1064 h_sync_length = ((m_timing.h_sync_length / ((float)pix_period)) + 1);
1065 /* value must be even */
1066 h_sync_length &= ~0x01;
1068 /* calculate h_total in 'half pixelclocks' */
1069 h_total = h_display + front_porch + back_porch + h_sync_length;
1071 LOG(4,("MAVENTV: TV front_porch is %d clocks\n", front_porch));
1072 LOG(4,("MAVENTV: TV back_porch is %d clocks\n", back_porch));
1073 LOG(4,("MAVENTV: TV h_sync_length is %d clocks\n", h_sync_length));
1074 LOG(4,("MAVENTV: TV h_display is %d clocks \n", h_display));
1075 LOG(4,("MAVENTV: TV h_total is %d clocks\n", h_total));
1077 /* calculate color_burst length in 'half pixelclocks' */
1078 burst_length = (((m_timing.color_burst /*- 1*/) / ((float)pix_period)) + 0.5);
1079 LOG(4,("MAVENTV: TV color_burst is %d clocks.\n", burst_length));
1081 /* copy result to MAVEN TV mode */
1082 maventv_regs[0x09] = burst_length;
1084 /* Calculate line length 'rest' that remains after truncating
1085 * h_total to adhere to the CRTC2 timing restrictions. */
1086 leftover = h_total & 0x0F;
1087 /* if some 'rest' exists, we need to compensate for it... */
1088 /* Note:
1089 * It's much better to prevent this from happening because this
1090 * 'trick' will decay TVout timing! (timing is nolonger official) */
1091 if (leftover)
1093 /* truncate line length to adhere to CRTC2 restrictions */
1094 front_porch -= leftover;
1095 h_total -= leftover;
1097 /* now set line length to closest CRTC2 valid match */
1098 if (leftover < 3)
1100 /* 1 <= old rest <= 2:
1101 * Truncated line length is closest match. */
1102 LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n"));
1104 else
1106 if (leftover < 10)
1108 /* 3 <= old rest <= 9:
1109 * We use the NTSC killer circuitry to get closest match.
1110 * (The 'g400_crtc2_set_timing' routine will enable it
1111 * because of the illegal h_total timing we create here.) */
1112 front_porch += 4;
1113 h_total += 4;
1114 LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via killer (> 2, < 10)\n"));
1116 else
1118 /* 10 <= old rest <= 15:
1119 * Set closest valid CRTC2 match. */
1120 front_porch += 16;
1121 h_total += 16;
1122 LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via increase (> 9, < 16)\n"));
1127 /* (linux) fixme: maybe MAVEN has requirement 800 < h_total < 1184 */
1128 maventv_regs[0x2C] = front_porch;
1129 maventv_regs[0x0A] = back_porch;
1130 maventv_regs[0x08] = h_sync_length;
1132 /* change h_total to represent 'whole pixelclocks' */
1133 h_total = h_total >> 1;
1135 /* tune display_mode adhering to CRTC2 restrictions */
1136 tv_target.timing.h_sync_end = (h_total & ~0x07) - 8;
1137 /* h_total is checked before being programmed! (NTSC killer circuitry) */
1138 tv_target.timing.h_total = h_total;
1141 /* output Y/C and CVBS signals (| $40 needed for SCART) */
1142 // DXIW(TVO_IDX, 0x80);
1143 // DXIW(TVO_DATA, 0x03);
1145 /* select input colorspace */
1146 //fixme?: has no effect on output picture on monitor or TV...
1147 //DXIW(TVO_IDX, 0x81);
1148 //DXIW(TVO_DATA, 0x00);
1150 /* calculate vertical sync point */
1152 int upper;
1154 /* set 625 lines for PAL or 525 lines for NTSC */
1155 maventv_regs[0x17] = m_timing.v_total / 4;
1156 maventv_regs[0x18] = m_timing.v_total & 3;
1158 /* calculate upper blanking range in field lines */
1159 upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1;
1161 /* blank TVout above the line number calculated */
1162 maventv_regs[0x33] = upper - 1;
1164 /* set calculated vertical sync point */
1165 // DXIW(TVO_IDX, 0x82);
1166 // DXIW(TVO_DATA, (upper & 0xff));
1167 // DXIW(TVO_IDX, 0x83);
1168 // DXIW(TVO_DATA, ((upper >> 8) & 0xff));
1169 LOG(4,("MAVENTV: TV upper blanking range set is %d\n", upper));
1172 /* set fized horizontal sync point */
1173 // DXIW(TVO_IDX, 0x84);
1174 // DXIW(TVO_DATA, 0x01);
1175 // DXIW(TVO_IDX, 0x85);
1176 // DXIW(TVO_DATA, 0x00);
1178 /* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (TVout mode) */
1179 // DXIW(OUTPUTCONN,0x0d);
1182 /* program new TVout mode */
1183 for (val = 0x00; val <= 0x3D; val++)
1185 /* if (si->ps.card_type <= G400MAX)
1187 i2c_maven_write(val, maventv_regs[val]);
1189 else
1190 */ {
1191 // DXIW(TVO_IDX, val);
1192 // DXIW(TVO_DATA, maventv_regs[val]);
1196 /* leave mode-program mode */
1197 // if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x00);
1198 // else
1199 // {
1200 // DXIW(TVO_IDX, ENMAV_PGM);
1201 // DXIW(TVO_DATA, 0x00);
1203 /* Select 2.0 Volt MAVEN DAC ref. so we have enough contrast/brightness range */
1204 // DXIW(GENIOCTRL, DXIR(GENIOCTRL) | 0x40);
1205 // DXIW(GENIODATA, 0x00);
1206 // }
1208 /* setup CRTC2 timing */
1209 head2_set_timing(tv_target);
1211 /* start whole thing if needed */
1212 // if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20);
1214 return 0;