#define MODULE_BIT 0x00100000
#include "mga_std.h"
typedef struct {
uint32 h_total;
uint32 h_display;
uint32 h_sync_length;
uint32 front_porch;
uint32 back_porch;
uint32 color_burst;
uint32 v_total;
float chroma_subcarrier;
} gx50_maven_timing;
status_t g100_g400max_maventv_vid_pll_find(
display_mode target, unsigned int * ht_new, unsigned int * ht_last_line,
uint8 * m_result, uint8 * n_result, uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float diff, diff_smallest = INFINITY;
int best[5] = {0, 0, 0, 0, 0};
int h_total_mod;
float fields_sec, f_vco;
uint32 vco_clks_field, max_pclks_field, req_pclks_field;
float calc_pclks_field;
LOG(2, ("MAVENTV: searching for EXACT videoclock match\n"));
switch (si->ps.card_type)
{
case G100:
LOG(2, ("MAVENTV: G100 restrictions apply\n"));
m_max = 32;
break;
case G200:
LOG(2, ("MAVENTV: G200 restrictions apply\n"));
m_max = 32;
break;
default:
LOG(2, ("MAVENTV: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
if ((target.flags & TV_BITS) == TV_PAL)
fields_sec = 50.0;
else
fields_sec = 59.94;
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclks_field = (si->ps.max_dac2_clock_16 * 1000000) / fields_sec;
break;
case B_RGB32_LITTLE:
max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec;
break;
default:
max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec;
break;
}
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclks_field = (si->ps.max_dac2_clock_32dh * 1000000) / fields_sec;
for (h_total_mod = 0; h_total_mod < 8; h_total_mod++)
{
LOG(2, ("MAVENTV: trying h_total modification of +%d...\n", h_total_mod));
*ht_new = target.timing.h_total + h_total_mod + 2;
req_pclks_field = *ht_new * target.timing.v_total;
if (req_pclks_field < (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0))
{
req_pclks_field = (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0);
LOG(4, ("MAVENTV: WARNING, clamping at lowest possible videoclock\n"));
}
if (req_pclks_field > max_pclks_field)
{
req_pclks_field = max_pclks_field;
LOG(4, ("MAVENTV: WARNING, clamping at highest possible videoclock\n"));
}
for (p=0x01; p < 0x10; p = p<<1)
{
vco_clks_field = req_pclks_field * p;
if ((vco_clks_field >= ((si->ps.min_video_vco * 1000000) / fields_sec)) &&
(vco_clks_field <= ((si->ps.max_video_vco * 1000000) / fields_sec)))
{
for (m = 2; m <= m_max; m++)
{
n = (int)(((vco_clks_field * m) / ((si->ps.f_ref * 1000000) / fields_sec)) + 0.5);
if ((n < 8) || (n > 128)) continue;
calc_pclks_field =
(((uint32)((si->ps.f_ref * 1000000) / fields_sec)) * n) / ((float)(m * p));
if (calc_pclks_field != (uint32)calc_pclks_field) continue;
if (calc_pclks_field < ((*ht_new * (target.timing.v_total - 1)) + 2)) continue;
*ht_last_line = calc_pclks_field - (*ht_new * (target.timing.v_total - 1));
if (*ht_last_line > *ht_new) continue;
diff = *ht_new - *ht_last_line;
if (diff < diff_smallest)
{
if (diff_smallest == 999999999)
LOG(2, ("MAVENTV: MATCH, "));
else
LOG(2, ("MAVENTV: better MATCH,"));
f_vco = (si->ps.f_ref / m) * n;
LOG(2, ("found vid VCO freq %fMhz, pixclk %fMhz\n", f_vco, (f_vco / p)));
LOG(2, ("MAVENTV: mnp(ex. filter) 0x%02x 0x%02x 0x%02x, h_total %d, ht_lastline %d\n",
(m - 1), (n - 1), (p - 1), (*ht_new - 2), (*ht_last_line - 2)));
diff_smallest = diff;
best[0] = m;
best[1] = n;
best[2] = p;
best[3] = *ht_new - 2;
best[4] = *ht_last_line - 2;
}
}
}
}
}
LOG(2, ("MAVENTV: search completed.\n"));
m = best[0] - 1;
n = best[1] - 1;
p = best[2] - 1;
if (diff_smallest == 999999999)
{
LOG(4, ("MAVENTV: WARNING, no MATCH found!\n"));
if (si->ps.f_ref == 27.000)
{
m = 0x03;
n = 0x07;
p = 0x03;
} else {
m = 0x01;
n = 0x07;
p = 0x03;
}
best[3] = target.timing.h_total;
best[4] = target.timing.h_total;
}
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2, ("MAVENTV: using vid VCO frequency %fMhz\n", f_vco));
switch (si->ps.card_type)
{
case G100:
case G200:
for (;;)
{
if (f_vco >= 180) {p |= (0x03 << 3); break;};
if (f_vco >= 140) {p |= (0x02 << 3); break;};
if (f_vco >= 100) {p |= (0x01 << 3); break;};
break;
}
break;
default:
for (;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
*m_result = m;
*n_result = n;
*p_result = p;
*ht_new = best[3];
*ht_last_line = best[4];
LOG(2, ("MAVENTV: vid PLL check: got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
(f_vco / ((p & 0x07) + 1)), m, n, p));
LOG(2, ("MAVENTV: new h_total %d, ht_lastline %d\n", *ht_new, *ht_last_line));
if (diff_smallest == 999999999) return B_ERROR;
return B_OK;
}
static void gxx0_maventv_PAL_init(uint8* buffer)
{
uint16 value;
buffer[0x00] = 0x2A;
buffer[0x01] = 0x09;
buffer[0x02] = 0x8A;
buffer[0x03] = 0xCB;
buffer[0x04] = 0x00;
buffer[0x05] = 0x00;
buffer[0x06] = 0xF9;
buffer[0x07] = 0x00;
buffer[0x08] = 0x7E;
buffer[0x09] = 0x44;
buffer[0x0a] = 0x9C;
if (si->ps.card_type <= G400MAX)
{
buffer[0x0b] = 0x3e;
}
else
{
buffer[0x0b] = 0x48;
}
buffer[0x0c] = 0x21;
buffer[0x0d] = 0x00;
if (si->ps.card_type <= G400MAX)
{
value = 0x0ea;
buffer[0x0e] = ((value >> 2) & 0xff);
buffer[0x0f] = (value & 0x03);
buffer[0x10] = ((value >> 2) & 0xff);
buffer[0x11] = (value & 0x03);
}
else
{
value = 0x130;
buffer[0x0e] = ((value >> 2) & 0xff);
buffer[0x0f] = (value & 0x03);
buffer[0x10] = ((value >> 2) & 0xff);
buffer[0x11] = (value & 0x03);
}
buffer[0x12] = 0x1A;
buffer[0x13] = 0x2A;
buffer[0x14] = 0x1C;
buffer[0x15] = 0x3D;
buffer[0x16] = 0x14;
buffer[0x17] = 0x9C;
buffer[0x18] = 0x01;
buffer[0x19] = 0x00;
buffer[0x1a] = 0xFE;
buffer[0x1b] = 0x7E;
buffer[0x1c] = 0x60;
buffer[0x1d] = 0x05;
if (si->ps.card_type <= G400MAX)
{
value = 0x24f;
buffer[0x1e] = ((value >> 2) & 0xff);
buffer[0x1f] = (value & 0x03);
}
else
{
value = 0x300;
buffer[0x1e] = ((value >> 2) & 0xff);
buffer[0x1f] = (value & 0x03);
}
if (si->ps.card_type <= G400MAX)
buffer[0x20] = 0x72;
else
buffer[0x20] = 0xA5;
buffer[0x21] = 0x07;
if (si->ps.card_type <= G400MAX)
buffer[0x22] = 0x72;
else
buffer[0x22] = 0xA5;
buffer[0x23] = 0x00;
buffer[0x24] = 0x00;
buffer[0x25] = 0x00;
buffer[0x26] = 0x08;
buffer[0x27] = 0x04;
buffer[0x28] = 0x00;
buffer[0x29] = 0x1A;
buffer[0x2a] = 0x55;
buffer[0x2b] = 0x01;
buffer[0x2c] = 0x26;
buffer[0x2d] = 0x07;
buffer[0x2e] = 0x7E;
buffer[0x2f] = 0x02;
buffer[0x30] = 0x54;
value = 0x580;
buffer[0x31] = ((value >> 3) & 0xff);
buffer[0x32] = (value & 0x07);
buffer[0x33] = 0x14;
buffer[0x34] = 0x49;
buffer[0x35] = 0x00;
buffer[0x36] = 0x00;
buffer[0x37] = 0xA3;
buffer[0x38] = 0xC8;
buffer[0x39] = 0x22;
buffer[0x3a] = 0x02;
buffer[0x3b] = 0x22;
buffer[0x3c] = 0x3F;
buffer[0x3d] = 0x03;
}
static void gxx0_maventv_NTSC_init(uint8* buffer)
{
uint16 value;
buffer[0x00] = 0x21;
buffer[0x01] = 0xF0;
buffer[0x02] = 0x7C;
buffer[0x03] = 0x1F;
buffer[0x04] = 0x00;
buffer[0x05] = 0x00;
buffer[0x06] = 0xF9;
buffer[0x07] = 0x00;
buffer[0x08] = 0x7E;
buffer[0x09] = 0x43;
buffer[0x0a] = 0x7E;
if (si->ps.card_type <= G400MAX)
{
buffer[0x0b] = 0x46;
}
else
{
buffer[0x0b] = 0x48;
}
buffer[0x0c] = 0x00;
buffer[0x0d] = 0x00;
if (si->ps.card_type <= G400MAX)
{
value = 0x0ea;
buffer[0x0e] = ((value >> 2) & 0xff);
buffer[0x0f] = (value & 0x03);
buffer[0x10] = ((value >> 2) & 0xff);
buffer[0x11] = (value & 0x03);
}
else
{
value = 0x130;
buffer[0x0e] = ((value >> 2) & 0xff);
buffer[0x0f] = (value & 0x03);
buffer[0x10] = ((value >> 2) & 0xff);
buffer[0x11] = (value & 0x03);
}
buffer[0x12] = 0x17;
buffer[0x13] = 0x21;
buffer[0x14] = 0x1B;
buffer[0x15] = 0x1B;
buffer[0x16] = 0x24;
buffer[0x17] = 0x83;
buffer[0x18] = 0x01;
buffer[0x19] = 0x00;
buffer[0x1a] = 0x0F;
buffer[0x1b] = 0x0F;
buffer[0x1c] = 0x60;
buffer[0x1d] = 0x05;
if (si->ps.card_type <= G400MAX)
{
value = 0x24f;
buffer[0x1e] = ((value >> 2) & 0xff);
buffer[0x1f] = (value & 0x03);
}
else
{
value = 0x300;
buffer[0x1e] = ((value >> 2) & 0xff);
buffer[0x1f] = (value & 0x03);
}
if (si->ps.card_type <= G400MAX)
buffer[0x20] = 0x5F;
else
buffer[0x20] = 0x9C;
buffer[0x21] = 0x04;
if (si->ps.card_type <= G400MAX)
buffer[0x22] = 0x5F;
else
buffer[0x22] = 0x9C;
buffer[0x23] = 0x01;
buffer[0x24] = 0x02;
buffer[0x25] = 0x00;
buffer[0x26] = 0x0A;
buffer[0x27] = 0x05;
buffer[0x28] = 0x00;
buffer[0x29] = 0x10;
buffer[0x2a] = 0xFF;
buffer[0x2b] = 0x03;
buffer[0x2c] = 0x24;
buffer[0x2d] = 0x0F;
buffer[0x2e] = 0x78;
buffer[0x2f] = 0x00;
buffer[0x30] = 0x00;
buffer[0x31] = 0xB2;
buffer[0x32] = 0x04;
buffer[0x33] = 0x14;
buffer[0x34] = 0x02;
buffer[0x35] = 0x00;
buffer[0x36] = 0x00;
buffer[0x37] = 0xA3;
buffer[0x38] = 0xC8;
buffer[0x39] = 0x15;
buffer[0x3a] = 0x05;
buffer[0x3b] = 0x3B;
buffer[0x3c] = 0x3C;
buffer[0x3d] = 0x00;
}
static void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing)
{
m_timing->h_total = 64000000;
m_timing->h_display = 52148148;
m_timing->h_sync_length = 4666667;
m_timing->front_porch = 1407407;
m_timing->back_porch = 5777778;
m_timing->color_burst = 2518518;
m_timing->v_total = 625;
m_timing->chroma_subcarrier = 4.43361875;
}
static void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing)
{
m_timing->h_total = 63555556;
m_timing->h_display = 52888889;
m_timing->h_sync_length = 4666667;
m_timing->front_porch = 1333333;
m_timing->back_porch = 4666667;
m_timing->color_burst = 2418418;
m_timing->v_total = 525;
m_timing->chroma_subcarrier = 3.579545454;
}
int maventv_init(display_mode target)
{
uint8 val;
uint8 m_result, n_result, p_result;
unsigned int ht_new, ht_last_line;
float calc_pclk;
display_mode tv_target = target;
uint8 maventv_regs[64];
gx50_maven_timing m_timing;
if ((tv_target.flags & TV_BITS) == TV_PAL)
{
LOG(4, ("MAVENTV: PAL TVout\n"));
gxx0_maventv_PAL_init(maventv_regs);
gx50_maventv_PAL_timing(&m_timing);
}
else
{
LOG(4, ("MAVENTV: NTSC TVout\n"));
gxx0_maventv_NTSC_init(maventv_regs);
gx50_maventv_NTSC_timing(&m_timing);
}
if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x01);
else
{
DXIW(TVO_IDX, MGAMAV_PGM);
DXIW(TVO_DATA, 0x01);
}
if (si->ps.card_type <= G400MAX)
{
MAVW(MONSET, 0x00);
MAVW(MONEN, 0xA2);
MAVWW(WREG_0X8E_L, 0x1EFF);
MAVW(BREG_0XC6, 0x01);
MAVW(LOCK, 0x01);
MAVW(OUTMODE, 0x08);
MAVW(LUMA, 0x78);
si->maven_syncpol_offset += 1;
if (si->maven_syncpol_offset > 3) si->maven_syncpol_offset = 0;
MAVW(STABLE, 0x02);
MAVW(MONEN, 0xB3);
{
int diff;
float uscan_fact;
bool tweak = false;
if (!(tv_target.flags & TV_VIDEO))
{
LOG(4,("MAVENTV: setting underscanning ('downscaled') desktop mode\n"));
if ((tv_target.timing.h_display < 704) && ((tv_target.flags & TV_BITS) == TV_PAL))
{
uscan_fact = 0.76;
}
else
{
uscan_fact = 0.80;
}
tv_target.timing.h_total = (tv_target.timing.h_display / uscan_fact);
tv_target.timing.h_total &= ~0x0007;
tv_target.timing.v_total = (tv_target.timing.v_display / uscan_fact);
if ((tv_target.flags & TV_BITS) == TV_PAL)
{
diff = tv_target.timing.v_total - tv_target.timing.v_display;
tv_target.timing.v_sync_start = tv_target.timing.v_display + ((diff * 7) / 20);
tv_target.timing.v_sync_end = tv_target.timing.v_total;
}
else
{
diff = tv_target.timing.v_total - tv_target.timing.v_display;
tv_target.timing.v_sync_start = tv_target.timing.v_display + ((diff * 5) / 20);
tv_target.timing.v_sync_end = tv_target.timing.v_total;
}
}
else
{
uint16 mode =
(((tv_target.flags & TV_BITS) << (14 - 9)) | tv_target.timing.h_display);
LOG(4,("MAVENTV: setting overscanning ('unscaled') video mode\n"));
switch (mode)
{
case ((TV_NTSC << (14 - 9)) | 640):
tv_target.timing.h_total = 696;
tweak = true;
break;
case ((TV_NTSC << (14 - 9)) | 720):
tv_target.timing.h_total = 784;
if (!si->ps.secondary_head) si->crtc_delay += 12;
break;
case ((TV_PAL << (14 - 9)) | 768):
tv_target.timing.h_total = 832;
break;
case ((TV_PAL << (14 - 9)) | 720):
tv_target.timing.h_total = 784;
break;
default:
break;
}
if ((tv_target.flags & TV_BITS) == TV_PAL)
{
tv_target.timing.v_total = m_timing.v_total;
diff = 576 - tv_target.timing.v_display;
if (diff < 0)
{
tv_target.timing.v_display = 576;
diff = 0;
}
tv_target.timing.v_sync_start = tv_target.timing.v_display + (diff / 2);
tv_target.timing.v_sync_end = tv_target.timing.v_total;
}
else
{
tv_target.timing.v_total = m_timing.v_total;
if (tweak) tv_target.timing.v_total += 32;
diff = 480 - tv_target.timing.v_display;
if (diff < 0)
{
tv_target.timing.v_display = 480;
diff = 0;
}
tv_target.timing.v_sync_start = tv_target.timing.v_display + (diff / 2);
if (tweak) tv_target.timing.v_sync_start += 9;
tv_target.timing.v_sync_end = tv_target.timing.v_total;
}
}
if ((tv_target.flags & TV_BITS) == TV_PAL)
{
diff = tv_target.timing.h_total - tv_target.timing.h_display;
if (!si->ps.secondary_head)
{
tv_target.timing.h_sync_start = tv_target.timing.h_display - 16 + (diff / 2);
tv_target.timing.h_sync_start &= ~0x0007;
tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 32;
}
else
{
tv_target.timing.h_sync_start = tv_target.timing.h_display - 0 + (diff / 2);
tv_target.timing.h_sync_start &= ~0x0007;
tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 16;
}
}
else
{
diff = tv_target.timing.h_total - tv_target.timing.h_display;
tv_target.timing.h_sync_start = tv_target.timing.h_display - 16 + (diff / 2);
if (tweak) tv_target.timing.h_sync_start -= 16;
tv_target.timing.h_sync_start &= ~0x0007;
tv_target.timing.h_sync_end = tv_target.timing.h_sync_start + 16;
}
}
if ((tv_target.timing.h_display >= 1000) && (((tv_target.flags & TV_BITS) != TV_PAL)))
{
si->crtc_delay += 1;
}
else
{
si->crtc_delay -= 3;
}
g100_g400max_maventv_vid_pll_find(
tv_target, &ht_new, &ht_last_line, &m_result, &n_result, &p_result);
MAVW(PIXPLLM, m_result);
MAVW(PIXPLLN, n_result);
MAVW(PIXPLLP, (p_result | 0x80));
MAVW(MONSET, 0x20);
MAVW(TEST, 0x10);
MAVWW(HTOTALL, ht_new);
MAVWW(LASTLINEL, ht_last_line);
MAVWW(HVIDRSTL, (ht_last_line - si->crtc_delay -
(tv_target.timing.h_sync_end - tv_target.timing.h_sync_start)));
MAVWW(HSYNCSTRL, 0x0004);
MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end));
MAVWW(VTOTALL, (tv_target.timing.v_total - 1));
MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2));
MAVWW(VSYNCSTRL, 0x0001);
MAVWW(VSYNCLENL, (tv_target.timing.v_sync_end - tv_target.timing.v_sync_start - 1));
MAVWW(VDISPLAYL, 0x0000);
MAVWW(WREG_0X98_L, 0x0000);
MAVWW(VSOMETHINGL, 0x0001);
{
uint32 h_display_tv;
uint8 h_scale_tv;
unsigned int ib_min_length;
unsigned int ib_length;
int index;
h_scale_tv = (736 << 7) / tv_target.timing.h_total;
LOG(4,("MAVENTV: horizontal scale-back factor is: %f\n", (h_scale_tv / 128.0)));
if (h_scale_tv > 0x80)
{
h_scale_tv = 0x80;
LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
}
if (h_scale_tv < 0x40)
{
h_scale_tv = 0x40;
LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0)));
}
h_scale_tv--;
h_display_tv = ((768 - 1) << 7) -
(((tv_target.timing.h_total - tv_target.timing.h_sync_end)
+ tv_target.timing.h_display - 8)
* h_scale_tv);
h_display_tv = h_display_tv >> 7;
LOG(4,("MAVENTV: displaying output on %d picture pixels\n",
((768 - 1) - h_display_tv)));
h_display_tv = h_display_tv >> 1;
if (h_display_tv > 0xFF) h_display_tv = 0xFF;
MAVW(HSCALETV, h_scale_tv);
MAVW(HDISPLAYTV, h_display_tv);
ib_min_length = ((tv_target.timing.h_total - tv_target.timing.h_sync_end) +
tv_target.timing.h_display + 4);
index = 1;
do
{
ib_length = ((((((0x7800 << 7) * index) - (0x100 << 7)) / h_scale_tv) + 0x05E7) >> 8);
index++;
} while (ib_length < ib_min_length);
LOG(4,("MAVENTV: optimal line inputbuffer length: %d\n", ib_length));
if (ib_length >= ht_new + 2)
{
ib_length = ib_min_length;
LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length));
}
MAVWW(HDISPLAYL, ib_length);
}
{
uint16 t_scale_tv;
uint32 v_display_tv;
{
uint32 out_clocks;
uint32 in_clocks;
out_clocks = m_timing.v_total * (ht_new + 2);
in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) + ht_last_line + 2;
t_scale_tv = ((((uint64)out_clocks) << 15) / in_clocks);
LOG(4,("MAVENTV: total scale-back factor is: %f\n", (t_scale_tv / 32768.0)));
if (t_scale_tv > 0x8000)
{
t_scale_tv = 0x8000;
LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0)));
}
}
v_display_tv =
((tv_target.timing.v_sync_end - tv_target.timing.v_sync_start)
+ (tv_target.timing.v_total - tv_target.timing.v_sync_end)
+ tv_target.timing.v_display)
* t_scale_tv;
v_display_tv = (v_display_tv >> 15);
LOG(4,("MAVENTV: displaying output on %d picture frame-lines\n", v_display_tv));
v_display_tv = (v_display_tv >> 1) - 146;
if (v_display_tv > 0xFF) v_display_tv = 0xFF;
t_scale_tv--;
MAVWW(TSCALETVL, t_scale_tv);
MAVW(VDISPLAYTV, v_display_tv);
}
MAVW(TEST, 0x00);
MAVW(GAMMA1, 0x00);
MAVW(GAMMA2, 0x00);
MAVW(GAMMA3, 0x00);
MAVW(GAMMA4, 0x1F);
MAVW(GAMMA5, 0x10);
MAVW(GAMMA6, 0x10);
MAVW(GAMMA7, 0x10);
MAVW(GAMMA8, 0x64);
MAVW(GAMMA9, 0xC8);
if (!(tv_target.flags & TV_VIDEO))
{
MAVW(FFILTER, 0xa2);
LOG(4,("MAVENTV: enabling flicker filter\n"));
}
else
{
MAVW(FFILTER, 0x00);
LOG(4,("MAVENTV: disabling flicker filter\n"));
}
MAVW(TEST, (MAVR(TEST) & 0x10));
MAVW(OUTMODE, 0x08);
}
else
{
if ((tv_target.flags & TV_BITS) == TV_PAL)
{
int diff;
tv_target.timing.v_total = m_timing.v_total;
diff = 576 - tv_target.timing.v_display;
if (diff < 0)
{
tv_target.timing.v_display = 576;
diff = 0;
}
tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2);
tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1;
}
else
{
int diff;
tv_target.timing.v_total = m_timing.v_total;
diff = 480 - tv_target.timing.v_display;
if (diff < 0)
{
tv_target.timing.v_display = 480;
diff = 0;
}
tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2);
tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1;
}
{
uint16 front_porch, back_porch, h_sync_length, burst_length, h_total, h_display;
uint32 chromasc;
uint64 pix_period;
uint16 h_total_wanted, leftover;
h_display = (((tv_target.timing.h_display << 1) + 3) & ~0x03);
if (h_display > 2044) h_display = 2044;
maventv_regs[0x31] = (h_display >> 3);
maventv_regs[0x32] = (h_display & 0x07);
tv_target.timing.pixel_clock =
((((uint64)h_display) * 1000000000) / m_timing.h_display);
tv_target.timing.h_display = ((h_display >> 1) & ~0x07);
tv_target.timing.h_sync_start = tv_target.timing.h_display + 8;
g450_g550_maven_vid_pll_find(tv_target, &calc_pclk, &m_result, &n_result, &p_result, 1);
tv_target.timing.pixel_clock = (calc_pclk * 1000);
DXIW(VIDPLLM, m_result);
DXIW(VIDPLLN, n_result);
DXIW(VIDPLLP, p_result);
pix_period = (1000000000 / ((float)tv_target.timing.pixel_clock)) + 0.5;
LOG(4,("MAVENTV: TV videoclock period is %d picoseconds\n", pix_period));
h_total_wanted = ((m_timing.h_total / ((float)pix_period)) + 0.5);
LOG(4,("MAVENTV: TV h_total should be %d units\n", h_total_wanted));
chromasc =
((((uint64)0x100000000) * (m_timing.chroma_subcarrier / calc_pclk)) + 0.5);
maventv_regs[0] = ((chromasc >> 24) & 0xff);
maventv_regs[1] = ((chromasc >> 16) & 0xff);
maventv_regs[2] = ((chromasc >> 8) & 0xff);
maventv_regs[3] = ((chromasc >> 0) & 0xff);
LOG(4,("MAVENTV: TV chroma subcarrier divider set is $%08x\n", chromasc));
front_porch = ((m_timing.front_porch / ((float)pix_period)) + 1);
front_porch &= ~0x01;
back_porch = ((m_timing.back_porch / ((float)pix_period)) + 1);
back_porch &= ~0x01;
h_sync_length = ((m_timing.h_sync_length / ((float)pix_period)) + 1);
h_sync_length &= ~0x01;
h_total = h_display + front_porch + back_porch + h_sync_length;
LOG(4,("MAVENTV: TV front_porch is %d clocks\n", front_porch));
LOG(4,("MAVENTV: TV back_porch is %d clocks\n", back_porch));
LOG(4,("MAVENTV: TV h_sync_length is %d clocks\n", h_sync_length));
LOG(4,("MAVENTV: TV h_display is %d clocks \n", h_display));
LOG(4,("MAVENTV: TV h_total is %d clocks\n", h_total));
burst_length = (((m_timing.color_burst ) / ((float)pix_period)) + 0.5);
LOG(4,("MAVENTV: TV color_burst is %d clocks.\n", burst_length));
maventv_regs[0x09] = burst_length;
leftover = h_total & 0x0F;
if (leftover)
{
front_porch -= leftover;
h_total -= leftover;
if (leftover < 3)
{
LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n"));
}
else
{
if (leftover < 10)
{
front_porch += 4;
h_total += 4;
LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via killer (> 2, < 10)\n"));
}
else
{
front_porch += 16;
h_total += 16;
LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via increase (> 9, < 16)\n"));
}
}
}
maventv_regs[0x2C] = front_porch;
maventv_regs[0x0A] = back_porch;
maventv_regs[0x08] = h_sync_length;
h_total = h_total >> 1;
tv_target.timing.h_sync_end = (h_total & ~0x07) - 8;
tv_target.timing.h_total = h_total;
}
DXIW(TVO_IDX, 0x80);
DXIW(TVO_DATA, 0x03);
{
int upper;
maventv_regs[0x17] = m_timing.v_total / 4;
maventv_regs[0x18] = m_timing.v_total & 3;
upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1;
maventv_regs[0x33] = upper - 1;
DXIW(TVO_IDX, 0x82);
DXIW(TVO_DATA, (upper & 0xff));
DXIW(TVO_IDX, 0x83);
DXIW(TVO_DATA, ((upper >> 8) & 0xff));
LOG(4,("MAVENTV: TV upper blanking range set is %d\n", upper));
}
DXIW(TVO_IDX, 0x84);
DXIW(TVO_DATA, 0x01);
DXIW(TVO_IDX, 0x85);
DXIW(TVO_DATA, 0x00);
DXIW(OUTPUTCONN,0x0d);
}
for (val = 0x00; val <= 0x3D; val++)
{
if (si->ps.card_type <= G400MAX)
{
i2c_maven_write(val, maventv_regs[val]);
}
else
{
DXIW(TVO_IDX, val);
DXIW(TVO_DATA, maventv_regs[val]);
}
}
if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x00);
else
{
DXIW(TVO_IDX, MGAMAV_PGM);
DXIW(TVO_DATA, 0x00);
DXIW(GENIOCTRL, DXIR(GENIOCTRL) | 0x40);
DXIW(GENIODATA, 0x00);
}
if (si->ps.secondary_head)
{
g400_crtc2_set_timing(tv_target);
}
else
{
gx00_crtc_set_timing(tv_target);
}
if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20);
return 0;
}