xref: /haiku/src/add-ons/accelerants/skeleton/engine/tvout.c (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /* Authors:
2    Mark Watson 2000,
3    Rudolf Cornelissen 1/2003-12/2003
4 
5    Thanx to Petr Vandrovec for writing matroxfb.
6 */
7 
8 #define MODULE_BIT 0x00100000
9 
10 #include "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 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);
27 
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.
34 
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)
39 {
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;
52 
53 	LOG(2,("MAVENTV: searching for EXACT videoclock match\n"));
54 
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)
58 	{
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;
71 	}
72 
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;
78 
79 	/* determine the max. pixelclock for the current videomode */
80 	switch (target.space)
81 	{
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;
92 	}
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;
96 
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++)
101 	{
102 		LOG(2,("MAVENTV: trying h_total modification of +%d...\n", h_total_mod));
103 
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;
107 
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))
112 		{
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"));
115 		}
116 		/* upper limit is given by pins in combination with current active mode */
117 		if (req_pclks_field > max_pclks_field)
118 		{
119 			req_pclks_field = max_pclks_field;
120 			LOG(4,("MAVENTV: WARNING, clamping at highest possible videoclock\n"));
121 		}
122 
123 		/* iterate through all valid PLL postscaler settings */
124 		for (p=0x01; p < 0x10; p = p<<1)
125 		{
126 			/* calc the needed number of VCO clocks per field for this postscaler setting */
127 			vco_clks_field = req_pclks_field * p;
128 
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)))
132 			{
133 				/* iterate trough all valid reference-frequency postscaler settings */
134 				for (m = 2; m <= m_max; m++)
135 				{
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;
140 
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));
145 
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;
149 
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;
152 
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));
155 
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;
158 
159 					/* we have a match! */
160 					/* calculate the difference between a full line and the last line */
161 					diff = *ht_new - *ht_last_line;
162 
163 					/* if this last_line comes closer to a full line than earlier 'hits' then use it */
164 					if (diff < diff_smallest)
165 					{
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)));
175 
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;
187 					}
188 				}
189 			}
190 		}
191 	}
192 	LOG(2,("MAVENTV: search completed.\n"));
193 
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;
198 
199 	/* if no match was found set fixed PLL frequency so we have something valid at least */
200 	if (diff_smallest == 999999999)
201 	{
202 		LOG(4,("MAVENTV: WARNING, no MATCH found!\n"));
203 
204 		if (si->ps.f_ref == 27.000)
205 		{
206 			/* set 13.5Mhz */
207 			m = 0x03;
208 			n = 0x07;
209 			p = 0x03;
210 		}
211 		else
212 		{
213 			/* set 14.31818Mhz */
214 			m = 0x01;
215 			n = 0x07;
216 			p = 0x03;
217 		}
218 		best[3] = target.timing.h_total;
219 		best[4] = target.timing.h_total;
220 	}
221 
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));
225 
226 	switch(si->ps.card_type)
227 	{
228 /*	case G100:
229 	case G200:
230 		for(;;)
231 		{
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;
236 		}
237 		break;
238 */	default:
239 		for(;;)
240 		{
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;
245 		}
246 		break;
247 	}
248 
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];
255 
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));
260 
261 	/* return status */
262 	if (diff_smallest == 999999999) return B_ERROR;
263 	return B_OK;
264 }
265 
266 	/* Notes about timing:
267 	 * Note:
268 	 * all horizontal timing is measured in pixelclock periods;
269 	 * all? vertical timing is measured in field? lines.  */
270 
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. */
274 
275 
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.
280 	 *
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.
286 	 *
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. */
292 
293 	/* Note:
294 	 * Increasing the distance between the highest and lowest active video output
295 	 * level increases contrast; decreasing it decreases contrast. */
296 
297 	/* Note:
298 	 * Increasing both the highest and lowest active video output level with the
299 	 * same amount increases brightness; decreasing it decreases brightness. */
300 
301 	/* Note:
302 	 * Increasing the Hsync pulse level increases the black level, so decreases
303 	 * brightness and contrast. */
304 
305 /* Preset maven PAL output (625lines, 50Hz mode) */
306 void gxx0_maventv_PAL_init(uint8* buffer)
307 {
308 	uint16 value;
309 
310 	/* Chroma subcarrier divider */
311 	buffer[0x00] = 0x2A;
312 	buffer[0x01] = 0x09;
313 	buffer[0x02] = 0x8A;
314 	buffer[0x03] = 0xCB;
315 
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;
326 
327 	/* color burst amplitude */
328 /*	if (si->ps.card_type <= G400MAX)
329 	{
330 		buffer[0x0b] = 0x3e;
331 	}
332 	else
333 	{
334 */		buffer[0x0b] = 0x48;
335 //	}
336 
337 	buffer[0x0c] = 0x21;
338 	buffer[0x0d] = 0x00;
339 
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
352 	{
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);
361 	}
362 
363 	buffer[0x12] = 0x1A;
364 	buffer[0x13] = 0x2A;
365 
366 	/* functional unit */
367 	buffer[0x14] = 0x1C;
368 	buffer[0x15] = 0x3D;
369 	buffer[0x16] = 0x14;
370 
371 	/* vertical total */ //(=625)
372 	/* b9-2 */
373 	buffer[0x17] = 0x9C;
374 	/* b1-0 in b1-0 */
375 	buffer[0x18] = 0x01;
376 
377 	buffer[0x19] = 0x00;
378 	buffer[0x1a] = 0xFE;
379 	buffer[0x1b] = 0x7E;
380 	buffer[0x1c] = 0x60;
381 	buffer[0x1d] = 0x05;
382 
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)
386 	{
387 		value = 0x24f;
388 		buffer[0x1e] = ((value >> 2) & 0xff);
389 		buffer[0x1f] = (value & 0x03);
390 	}
391 	else
392 */	{
393 		value = 0x300;
394 		buffer[0x1e] = ((value >> 2) & 0xff);
395 		buffer[0x1f] = (value & 0x03);
396 	}
397 
398 	/* saturation (field?) #1 */
399 //	if (si->ps.card_type <= G400MAX)
400 //		buffer[0x20] = 0x72;
401 //	else
402 		buffer[0x20] = 0xA5;
403 
404 	buffer[0x21] = 0x07;
405 
406 	/* saturation (field?) #2 */
407 //	if (si->ps.card_type <= G400MAX)
408 //		buffer[0x22] = 0x72;
409 //	else
410 		buffer[0x22] = 0xA5;
411 
412 	buffer[0x23] = 0x00;
413 	buffer[0x24] = 0x00;
414 	/* hue? */
415 	buffer[0x25] = 0x00;
416 
417 	buffer[0x26] = 0x08;
418 	buffer[0x27] = 0x04;
419 	buffer[0x28] = 0x00;
420 	buffer[0x29] = 0x1A;
421 
422 	/* functional unit */
423 	buffer[0x2a] = 0x55;
424 	buffer[0x2b] = 0x01;
425 
426 	/* front porch length */
427 	buffer[0x2c] = 0x26;
428 
429 	/* functional unit */
430 	buffer[0x2d] = 0x07;
431 	buffer[0x2e] = 0x7E;
432 
433 	/* functional unit */
434 	buffer[0x2f] = 0x02;
435 	buffer[0x30] = 0x54;
436 
437 	/* horizontal visible */
438 	value = 0x580;
439 	buffer[0x31] = ((value >> 3) & 0xff);
440 	buffer[0x32] = (value & 0x07);
441 
442 	/* upper blanking (in field lines) */
443 	buffer[0x33] = 0x14; //=((v_total - v_sync_end)/2) -1
444 
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;
453 
454 	/* functional unit */
455 	buffer[0x3c] = 0x3F;
456 	buffer[0x3d] = 0x03;
457 }
458 
459 /* Preset maven NTSC output (525lines, 59.94Hz mode) */
460 void gxx0_maventv_NTSC_init(uint8* buffer)
461 {
462 	uint16 value;
463 
464 	/* Chroma subcarrier frequency */
465 	buffer[0x00] = 0x21;
466 	buffer[0x01] = 0xF0;
467 	buffer[0x02] = 0x7C;
468 	buffer[0x03] = 0x1F;
469 
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
474 
475 	/* Hsync pulse length */
476 	buffer[0x08] = 0x7E;
477 	/* color burst length */
478 	buffer[0x09] = 0x43;
479 	/* back porch length */
480 	buffer[0x0a] = 0x7E;
481 
482 	/* color burst amplitude */
483 //	if (si->ps.card_type <= G400MAX)
484 //	{
485 //		buffer[0x0b] = 0x46;
486 //	}
487 //	else
488 	{
489 		buffer[0x0b] = 0x48;
490 	}
491 
492 	buffer[0x0c] = 0x00;
493 	buffer[0x0d] = 0x00;
494 
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
507 	{
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);
516 	}
517 
518 	buffer[0x12] = 0x17;
519 	buffer[0x13] = 0x21;
520 
521 	/* functional unit */
522 	buffer[0x14] = 0x1B;
523 	buffer[0x15] = 0x1B;
524 	buffer[0x16] = 0x24;
525 
526 	/* vertical total */
527 	/* b9-2 */
528 	buffer[0x17] = 0x83;
529 	/* b1-0 in b1-0 */
530 	buffer[0x18] = 0x01;
531 
532 	buffer[0x19] = 0x00;//mv register?
533 	buffer[0x1a] = 0x0F;
534 	buffer[0x1b] = 0x0F;
535 	buffer[0x1c] = 0x60;
536 	buffer[0x1d] = 0x05;
537 
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)
541 	{
542 		value = 0x24f;
543 		buffer[0x1e] = ((value >> 2) & 0xff);
544 		buffer[0x1f] = (value & 0x03);
545 	}
546 	else
547 */	{
548 		value = 0x300;
549 		buffer[0x1e] = ((value >> 2) & 0xff);
550 		buffer[0x1f] = (value & 0x03);
551 	}
552 
553 	/* color saturation #1 (Y-B ?) */
554 //	if (si->ps.card_type <= G400MAX)
555 //		buffer[0x20] = 0x5F;
556 //	else
557 		buffer[0x20] = 0x9C;
558 
559 	buffer[0x21] = 0x04;
560 
561 	/* color saturation #2 (Y-R ?) */
562 //	if (si->ps.card_type <= G400MAX)
563 //		buffer[0x22] = 0x5F;
564 //	else
565 		buffer[0x22] = 0x9C;
566 
567 	buffer[0x23] = 0x01;
568 	buffer[0x24] = 0x02;
569 
570 	/* hue: preset at 0 degrees */
571 	buffer[0x25] = 0x00;
572 
573 	buffer[0x26] = 0x0A;
574 	buffer[0x27] = 0x05;//sync stuff
575 	buffer[0x28] = 0x00;
576 	buffer[0x29] = 0x10;//field line-length stuff
577 
578 	/* functional unit */
579 	buffer[0x2a] = 0xFF;
580 	buffer[0x2b] = 0x03;
581 
582 	/* front porch length */
583 	buffer[0x2c] = 0x24;
584 
585 	/* functional unit */
586 	buffer[0x2d] = 0x0F;
587 	buffer[0x2e] = 0x78;
588 
589 	/* functional unit */
590 	buffer[0x2f] = 0x00;
591 	buffer[0x30] = 0x00;
592 
593 	/* horizontal visible */
594 	/* b10-3 */
595 	buffer[0x31] = 0xB2;
596 	/* b2-0 in b2-0 */
597 	buffer[0x32] = 0x04;
598 
599 	/* upper blanking (in field lines) */
600 	buffer[0x33] = 0x14;
601 
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;
610 
611 	/* functional unit */
612 	buffer[0x3c] = 0x3C;
613 	buffer[0x3d] = 0x00;
614 }
615 
616 void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing)
617 {
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;
631 }
632 
633 void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing)
634 {
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;
648 }
649 
650 int maventv_init(display_mode target)
651 {
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;
665 
666 	/* preset new TVout mode */
667 	if ((tv_target.flags & TV_BITS) == TV_PAL)
668 	{
669 		LOG(4, ("MAVENTV: PAL TVout\n"));
670 		gxx0_maventv_PAL_init(maventv_regs);
671 		gx50_maventv_PAL_timing(&m_timing);
672 	}
673 	else
674 	{
675 		LOG(4, ("MAVENTV: NTSC TVout\n"));
676 		gxx0_maventv_NTSC_init(maventv_regs);
677 		gx50_maventv_NTSC_timing(&m_timing);
678 	}
679 
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 //	}
687 
688 	/* tune new TVout mode */
689 //	if (si->ps.card_type <= G400MAX)
690 	{
691 		/* setup TV-mode 'copy' of CRTC2, setup PLL, inputs, outputs and sync-locks */
692 //		MAVW(MONSET, 0x00);
693 //		MAVW(MONEN, 0xA2);
694 
695 		/* xmiscctrl */
696 		//unknown regs:
697 //		MAVWW(WREG_0X8E_L, 0x1EFF);
698 //		MAVW(BREG_0XC6, 0x01);
699 
700 //		MAVW(LOCK, 0x01);
701 //		MAVW(OUTMODE, 0x08);
702 //		MAVW(LUMA, 0x78);
703 //		MAVW(STABLE, 0x02);
704 //		MAVW(MONEN, 0xB3);
705 
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));
712 
713 //		MAVW(MONSET, 0x20);
714 
715 //		MAVW(TEST, 0x10);
716 
717 		/* htotal - 2 */
718 //		MAVWW(HTOTALL, ht_new);
719 
720 		/* last line in field can have different length */
721 		/* hlen - 2 */
722 //		MAVWW(LASTLINEL, ht_last_line);
723 
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);
734 
735 		/* who knows */
736 //		MAVWW(HSYNCSTRL, 0x0004);//must be 4!!
737 
738 		/* hblanking end: 100% */
739 //		MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end));
740 
741 		/* vertical line count - 1 */
742 //		MAVWW(VTOTALL, (tv_target.timing.v_total - 1));
743 
744 		/* vertical vidrst pos */
745 //		MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2));
746 
747 		/* something end... [A6]+1..[A8] */
748 //		MAVWW(VSYNCSTRL, 0x0001);
749 
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));
754 
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));
759 
760 		/* ... */
761 //		MAVWW(WREG_0X98_L, 0x0000);
762 
763 		/* moves picture up/down and so on... */
764 //		MAVWW(VSOMETHINGL, 0x0001); /* Fix this... 0..VTotal */
765 
766 		{
767 			uint32 h_display_tv;
768 			uint8 h_scale_tv;
769 
770 			unsigned int ib_min_length;
771 			unsigned int ib_length;
772 			int index;
773 
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)));
779 
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)
783 			{
784 				h_scale_tv = 0x80;
785 				LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
786 			}
787 			if (h_scale_tv < 0x40)
788 			{
789 				h_scale_tv = 0x40;
790 				LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
791 			}
792 			/* make sure we get no round-off error artifacts on screen */
793 			h_scale_tv--;
794 
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)));
807 
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);
815 
816 
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) */
822 
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);
826 
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)
830 			 *
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
837 			 */
838 			index = 1;
839 			do
840 			{
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));
845 
846 			if (ib_length >= ht_new + 2)
847 			{
848 				ib_length = ib_min_length;
849 				LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length));
850 			}
851 //			MAVWW(HDISPLAYL, ib_length);
852 		}
853 
854 		{
855 			uint16 t_scale_tv;
856 			uint32 v_display_tv;
857 
858 			/* calc total scale-back factor from input to output picture */
859 			{
860 				uint32 out_clocks;
861 				uint32 in_clocks;
862 
863 				//takes care of green stripes:
864 				/* calc output clocks per frame */
865 				out_clocks = m_timing.v_total * (ht_new + 2);
866 
867 				/* calc input clocks per frame */
868 				in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) +	ht_last_line + 2;
869 
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)));
873 
874 				/* min. scale-back factor is 1.0 for 1:1 output */
875 				if (t_scale_tv > 0x8000)
876 				{
877 					t_scale_tv = 0x8000;
878 					LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0)));
879 				}
880 			}
881 
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));
892 
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--;
901 
902 //			MAVWW(TSCALETVL, t_scale_tv);
903 //			MAVW(VDISPLAYTV, v_display_tv);
904 		}
905 
906 //		MAVW(TEST, 0x00);
907 
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 */
918 
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);
923 
924 		/* 0x10 or anything ored with it */
925 		//fixme? linux uses 0x14...
926 //		MAVW(TEST, (MAVR(TEST) & 0x10));
927 
928 		/* output: SVideo/Composite */
929 //		MAVW(OUTMODE, 0x08);
930 	}
931 //	else /* card_type is >= G450 */
932 	{
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)
937 		{
938 			int diff;
939 
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)
948 			{
949 				tv_target.timing.v_display = 576;
950 				diff = 0;
951 			}
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;
955 		}
956 		else
957 		{
958 			int diff;
959 
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)
968 			{
969 				tv_target.timing.v_display = 480;
970 				diff = 0;
971 			}
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;
975 		}
976 
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. */
980 
981 		//fixme: make sure videoPLL is powered up: XPWRCTRL b1=1
982 		{
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;
987 
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);
995 
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);
1002 
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;
1007 
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);
1011 
1012 			/* program videoPLL */
1013 //			DXIW(VIDPLLM, m_result);
1014 //			DXIW(VIDPLLN, n_result);
1015 //			DXIW(VIDPLLP, p_result);
1016 
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));
1020 
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));
1029 
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));
1040 
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;
1049 
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;
1058 
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;
1067 
1068 			/* calculate h_total in 'half pixelclocks' */
1069 			h_total = h_display + front_porch + back_porch + h_sync_length;
1070 
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));
1076 
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));
1080 
1081 			/* copy result to MAVEN TV mode */
1082 			maventv_regs[0x09] = burst_length;
1083 
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)
1092 			{
1093 				/* truncate line length to adhere to CRTC2 restrictions */
1094 				front_porch -= leftover;
1095 				h_total -= leftover;
1096 
1097 				/* now set line length to closest CRTC2 valid match */
1098 				if (leftover < 3)
1099 				{
1100 					/* 1 <= old rest <= 2:
1101 					 * Truncated line length is closest match. */
1102 					LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n"));
1103 				}
1104 				else
1105 				{
1106 					if (leftover < 10)
1107 					{
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"));
1115 					}
1116 					else
1117 					{
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"));
1123 					}
1124 				}
1125 			}
1126 
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;
1131 
1132 			/* change h_total to represent 'whole pixelclocks' */
1133 			h_total = h_total >> 1;
1134 
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;
1139 		}
1140 
1141 		/* output Y/C and CVBS signals (| $40 needed for SCART) */
1142 //		DXIW(TVO_IDX, 0x80);
1143 //		DXIW(TVO_DATA, 0x03);
1144 
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);
1149 
1150 		/* calculate vertical sync point */
1151 		{
1152 			int upper;
1153 
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;
1157 
1158 			/* calculate upper blanking range in field lines */
1159 			upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1;
1160 
1161 			/* blank TVout above the line number calculated */
1162 			maventv_regs[0x33] = upper - 1;
1163 
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));
1170 		}
1171 
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);
1177 
1178 		/* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (TVout mode) */
1179 //		DXIW(OUTPUTCONN,0x0d);
1180 	}
1181 
1182 	/* program new TVout mode */
1183 	for (val = 0x00; val <= 0x3D; val++)
1184 	{
1185 /*		if (si->ps.card_type <= G400MAX)
1186 		{
1187 			i2c_maven_write(val, maventv_regs[val]);
1188 		}
1189 		else
1190 */		{
1191 //			DXIW(TVO_IDX, val);
1192 //			DXIW(TVO_DATA, maventv_regs[val]);
1193 		}
1194 	}
1195 
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);
1202 
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 //	}
1207 
1208 	/* setup CRTC2 timing */
1209 	head2_set_timing(tv_target);
1210 
1211 	/* start whole thing if needed */
1212 //	if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20);
1213 
1214 	return 0;
1215 }
1216