#define MODULE_BIT 0x00100000
#include "nv_std.h"
#define PRADR 0x88
#define SCADR 0x8a
#define WR 0x00
#define RD 0x01
enum
{
NOT_SUPPORTED = 0,
NTSC640_TST,
NTSC640,
NTSC800,
PAL800_TST,
PAL640,
PAL800,
NTSC720,
PAL720,
NTSC640_OS,
PAL800_OS
};
static uint8 BtNtscMacro0 [] = {
0x0f,0xfc,0x20,0xd0,0x6f,0x0f,0x00,0x00,0x0c,0xf3,0x09,
0xbd,0x67,0xb5,0x90,0xb2,0x7d,0x00,0x00};
static uint8 BtNtscMacro1 [] = {
0x0f,0xfc,0x20,0xd0,0x6f,0x0f,0x00,0x00,0x0c,0xf3,0x09,
0xbd,0x67,0xb5,0x90,0xb2,0x7d,0x63,0x00};
static uint8 BtNtscMacro2 [] = {
0x0f,0xfc,0x20,0xd0,0x6f,0x0f,0x00,0x00,0x0c,0xf3,0x09,
0xbd,0x6c,0x31,0x92,0x32,0xdd,0xe3,0x00};
static uint8 BtNtscMacro3 [] = {
0x0f,0xfc,0x20,0xd0,0x6f,0x0f,0x00,0x00,0x0c,0xf3,0x09,
0xbd,0x66,0xb5,0x90,0xb2,0x7d,0xe3,0x00};
static uint8 BtPalMacro0 [] = {
0x05,0x57,0x20,0x40,0x6e,0x7e,0xf4,0x51,0x0f,0xf1,0x05,
0xd3,0x78,0xa2,0x25,0x54,0xa5,0x00,0x00};
static uint8 BtPalMacro1 [] = {
0x05,0x57,0x20,0x40,0x6e,0x7e,0xf4,0x51,0x0f,0xf1,0x05,
0xd3,0x78,0xa2,0x25,0x54,0xa5,0x63,0x00};
static uint8 BT_set_macro (int std, int mode)
{
uint8 stat;
uint8 buffer[21];
LOG(4,("Brooktree: Setting Macro:\n"));
if ((std < 0) | (std > 1) | (mode < 0) | (mode > 3))
{
LOG(4,("Brooktree: Non existing mode or standard selected, aborting.\n"));
return 0x80;
}
switch (std)
{
case 0:
switch (mode)
{
case 0:
LOG(4,("Brooktree: NTSC, disabled\n"));
memcpy(&buffer[2], &BtNtscMacro0, 19);
break;
case 1:
LOG(4,("Brooktree: NTSC, mode 1\n"));
memcpy(&buffer[2], &BtNtscMacro1, 19);
break;
case 2:
LOG(4,("Brooktree: NTSC, mode 2\n"));
memcpy(&buffer[2], &BtNtscMacro2, 19);
break;
case 3:
LOG(4,("Brooktree: NTSC, mode 3\n"));
memcpy(&buffer[2], &BtNtscMacro3, 19);
break;
}
break;
case 1:
switch (mode)
{
case 0:
LOG(4,("Brooktree: PAL, disabled\n"));
memcpy(&buffer[2], &BtPalMacro0, 19);
break;
case 1:
case 2:
case 3:
LOG(4,("Brooktree: PAL, enabled\n"));
memcpy(&buffer[2], &BtPalMacro1, 19);
break;
}
break;
}
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xda;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting Macro\n"));
return stat;
}
static uint8 BT_check (uint8 bus, uint8 adress)
{
uint8 buffer[3];
buffer[0] = adress + WR;
buffer[1] = 0xc4;
buffer[2] = 0x01;
i2c_flag_error (-1);
i2c_bstart(bus);
i2c_writebuffer(bus, buffer, sizeof(buffer));
i2c_bstop(bus);
return i2c_flag_error(0);
}
static uint8 BT_read_type (void)
{
uint8 id, type, stat;
uint8 buffer[3];
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x6c;
buffer[2] = 0x02;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat) return stat;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebyte(si->ps.tv_encoder.bus, si->ps.tv_encoder.adress + RD);
id = i2c_readbyte(si->ps.tv_encoder.bus, true);
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat) return stat;
type = (id & 0xe0) >> 5;
if (type > 3)
{
LOG(4,("Brooktree: Found unsupported encoder type %d, aborting.\n", type));
return 0x80;
}
si->ps.tvout = true;
si->ps.tv_encoder.type = BT868 + type;
si->ps.tv_encoder.version = id & 0x1f;
return stat;
}
bool BT_probe()
{
uint8 bus;
bool btfound = false;
bool *i2c_bus = &(si->ps.i2c_bus0);
LOG(4,("Brooktree: Checking wired I2C bus(ses) for first possible TV encoder...\n"));
for (bus = 0; bus < 3; bus++)
{
if (i2c_bus[bus] && !btfound)
{
if (!BT_check(bus, PRADR))
{
btfound = true;
si->ps.tv_encoder.adress = PRADR;
si->ps.tv_encoder.bus = bus;
}
else
{
if (!BT_check(bus, SCADR))
{
btfound = true;
si->ps.tv_encoder.adress = SCADR;
si->ps.tv_encoder.bus = bus;
}
}
}
}
if (btfound)
{
uint8 stat;
uint8 cnt = 0;
while ((stat = BT_read_type()) && (cnt < 3))
{
if (stat == 0x80)
{
btfound = 0;
break;
}
cnt++;
}
if (stat & 0x7f)
{
LOG(4,("Brooktree: Too much errors occurred, aborting.\n"));
btfound = 0;
}
}
if (btfound)
LOG(4,("Brooktree: Found TV encoder on bus %d, adress $%02x\n",
si->ps.tv_encoder.bus, si->ps.tv_encoder.adress));
else
LOG(4,("Brooktree: No TV encoder Found\n"));
return btfound;
}
static uint8 BT_init_PAL640()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting PAL 640x480 desktop mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0x60;
buffer[3] = 0x80;
buffer[4] = 0x8a;
buffer[5] = 0xa6;
buffer[6] = 0x68;
buffer[7] = 0xc1;
buffer[8] = 0x2e;
buffer[9] = 0xf2;
buffer[10] = 0x27;
buffer[11] = 0x00;
buffer[12] = 0xb0;
buffer[13] = 0x0a;
buffer[14] = 0x0b;
buffer[15] = 0x71;
buffer[16] = 0x5a;
buffer[17] = 0xe0;
buffer[18] = 0x36;
buffer[19] = 0x00;
buffer[20] = 0x50;
buffer[21] = 0x72;
buffer[22] = 0x1c;
buffer[23] = 0x8d;
buffer[24] = 0x24;
buffer[25] = 0xf0;
buffer[26] = 0x58;
buffer[27] = 0x81;
buffer[28] = 0x49;
buffer[29] = 0x8c;
buffer[30] = 0x0c;
buffer[31] = 0x8c;
buffer[32] = 0x79;
buffer[33] = 0x26;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode PAL640\n"));
return stat;
}
static uint8 BT_init_PAL800()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting PAL 800x600 desktop mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0x00;
buffer[3] = 0x20;
buffer[4] = 0xaa;
buffer[5] = 0xca;
buffer[6] = 0x9a;
buffer[7] = 0x0d;
buffer[8] = 0x29;
buffer[9] = 0xfc;
buffer[10] = 0x39;
buffer[11] = 0x00;
buffer[12] = 0xc0;
buffer[13] = 0x8c;
buffer[14] = 0x03;
buffer[15] = 0xee;
buffer[16] = 0x5f;
buffer[17] = 0x58;
buffer[18] = 0x3a;
buffer[19] = 0x66;
buffer[20] = 0x96;
buffer[21] = 0x00;
buffer[22] = 0x00;
buffer[23] = 0x90;
buffer[24] = 0x24;
buffer[25] = 0xf0;
buffer[26] = 0x57;
buffer[27] = 0x80;
buffer[28] = 0x48;
buffer[29] = 0x8c;
buffer[30] = 0x18;
buffer[31] = 0x28;
buffer[32] = 0x87;
buffer[33] = 0x1f;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode PAL800\n"));
return stat;
}
static uint8 BT_init_NTSC640()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting NTSC 640x480 desktop mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0x00;
buffer[3] = 0x80;
buffer[4] = 0x84;
buffer[5] = 0x96;
buffer[6] = 0x60;
buffer[7] = 0x7d;
buffer[8] = 0x22;
buffer[9] = 0xd4;
buffer[10] = 0x27;
buffer[11] = 0x00;
buffer[12] = 0x10;
buffer[13] = 0x7e;
buffer[14] = 0x03;
buffer[15] = 0x58;
buffer[16] = 0x4b;
buffer[17] = 0xe0;
buffer[18] = 0x36;
buffer[19] = 0x92;
buffer[20] = 0x54;
buffer[21] = 0x0e;
buffer[22] = 0x88;
buffer[23] = 0x8c;
buffer[24] = 0x0a;
buffer[25] = 0xe5;
buffer[26] = 0x76;
buffer[27] = 0x79;
buffer[28] = 0x44;
buffer[29] = 0x85;
buffer[30] = 0x00;
buffer[31] = 0x00;
buffer[32] = 0x80;
buffer[33] = 0x20;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode NTSC640\n"));
return stat;
}
static uint8 BT_init_NTSC800()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting NTSC 800x600 desktop mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0xa0;
buffer[3] = 0x20;
buffer[4] = 0xb6;
buffer[5] = 0xce;
buffer[6] = 0x84;
buffer[7] = 0x55;
buffer[8] = 0x20;
buffer[9] = 0xd8;
buffer[10] = 0x39;
buffer[11] = 0x00;
buffer[12] = 0x70;
buffer[13] = 0x42;
buffer[14] = 0x03;
buffer[15] = 0xdf;
buffer[16] = 0x56;
buffer[17] = 0x58;
buffer[18] = 0x3a;
buffer[19] = 0xcd;
buffer[20] = 0x9c;
buffer[21] = 0x14;
buffer[22] = 0x3b;
buffer[23] = 0x91;
buffer[24] = 0x0a;
buffer[25] = 0xe5;
buffer[26] = 0x74;
buffer[27] = 0x77;
buffer[28] = 0x43;
buffer[29] = 0x85;
buffer[30] = 0xba;
buffer[31] = 0xe8;
buffer[32] = 0xa2;
buffer[33] = 0x17;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode PAL800\n"));
return stat;
}
static uint8 BT_init_PAL720()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting PAL 720x576 overscanning DVD mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0xf0;
buffer[3] = 0xd0;
buffer[4] = 0x82;
buffer[5] = 0x9c;
buffer[6] = 0x5a;
buffer[7] = 0x31;
buffer[8] = 0x16;
buffer[9] = 0x22;
buffer[10] = 0xa6;
buffer[11] = 0x00;
buffer[12] = 0x78;
buffer[13] = 0x93;
buffer[14] = 0x03;
buffer[15] = 0x71;
buffer[16] = 0x2a;
buffer[17] = 0x40;
buffer[18] = 0x0a;
buffer[19] = 0x00;
buffer[20] = 0x50;
buffer[21] = 0x55;
buffer[22] = 0x55;
buffer[23] = 0x8c;
buffer[24] = 0x24;
buffer[25] = 0xf0;
buffer[26] = 0x59;
buffer[27] = 0x82;
buffer[28] = 0x49;
buffer[29] = 0x8c;
buffer[30] = 0x8e;
buffer[31] = 0xb0;
buffer[32] = 0xe6;
buffer[33] = 0x28;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode PAL720\n"));
return stat;
}
static uint8 BT_init_NTSC720()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting NTSC 720x480 overscanning DVD mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0xf0;
buffer[3] = 0xd0;
buffer[4] = 0x83;
buffer[5] = 0x98;
buffer[6] = 0x5e;
if (si->ps.tv_encoder.type >= CX25870)
{
buffer[7] = 0x0c;
}
else
{
buffer[7] = 0x28;
}
buffer[8] = 0x18;
buffer[9] = 0xf2;
buffer[10] = 0x26;
buffer[11] = 0x00;
buffer[12] = 0x78;
buffer[13] = 0x90;
buffer[14] = 0x03;
buffer[15] = 0x0d;
buffer[16] = 0x1a;
buffer[17] = 0xe0;
buffer[18] = 0x36;
buffer[19] = 0x00;
buffer[20] = 0x50;
buffer[21] = 0x98;
buffer[22] = 0x6e;
buffer[23] = 0x8c;
buffer[24] = 0x0a;
buffer[25] = 0xe5;
buffer[26] = 0x75;
buffer[27] = 0x78;
buffer[28] = 0x44;
buffer[29] = 0x85;
buffer[30] = 0x3c;
buffer[31] = 0x91;
buffer[32] = 0xc2;
buffer[33] = 0x20;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode NTSC720\n"));
return stat;
}
static uint8 BT_init_PAL800_OS()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting PAL 800x600 overscanning VCD mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0x60;
buffer[3] = 0x20;
buffer[4] = 0x8b;
buffer[5] = 0xa5;
buffer[6] = 0x6b;
if (si->ps.tv_encoder.type >= CX25870)
{
buffer[7] = 0xf0;
buffer[8] = 0x17;
}
else
{
buffer[7] = 0xd0;
buffer[8] = 0x18;
}
buffer[9] = 0x2e;
buffer[10] = 0xb7;
buffer[11] = 0x00;
buffer[12] = 0xb0;
if (si->ps.tv_encoder.type >= CX25870)
buffer[13] = 0x20;
else
buffer[13] = 0x14;
buffer[14] = 0x03;
buffer[15] = 0x71;
if (si->ps.tv_encoder.type >= CX25870)
buffer[16] = 0x08;
else
buffer[16] = 0x2a;
buffer[17] = 0x58;
buffer[18] = 0x3a;
buffer[19] = 0x00;
buffer[20] = 0x10;
buffer[21] = 0x72;
buffer[22] = 0x1c;
buffer[23] = 0x8d;
buffer[24] = 0x24;
buffer[25] = 0xf0;
buffer[26] = 0x57;
buffer[27] = 0x80;
buffer[28] = 0x48;
buffer[29] = 0x8c;
buffer[30] = 0x31;
buffer[31] = 0x8c;
buffer[32] = 0x79;
buffer[33] = 0x26;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode PAL800 OS\n"));
return stat;
}
static uint8 BT_init_NTSC640_OS()
{
uint8 stat;
uint8 buffer[35];
LOG(4,("Brooktree: Setting NTSC 640x480 overscanning VCD mode\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x76;
buffer[2] = 0x20;
buffer[3] = 0x80;
buffer[4] = 0x74;
buffer[5] = 0x83;
buffer[6] = 0x44;
buffer[7] = 0xf7;
if (si->ps.tv_encoder.type >= CX25870)
buffer[8] = 0x1d;
else
buffer[8] = 0x1c;
buffer[9] = 0xf2;
buffer[10] = 0x26;
buffer[11] = 0x00;
buffer[12] = 0x10;
buffer[13] = 0x14;
buffer[14] = 0x03;
buffer[15] = 0x0d;
buffer[16] = 0x18;
buffer[17] = 0xe0;
buffer[18] = 0x36;
buffer[19] = 0x00;
buffer[20] = 0x10;
buffer[21] = 0xdb;
buffer[22] = 0xf9;
buffer[23] = 0x8a;
buffer[24] = 0x0a;
buffer[25] = 0xe5;
buffer[26] = 0x75;
buffer[27] = 0x78;
buffer[28] = 0x44;
buffer[29] = 0x85;
buffer[30] = 0x37;
buffer[31] = 0x12;
buffer[32] = 0x1b;
buffer[33] = 0x25;
buffer[34] = 0x00;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting mode NTSC640 OS\n"));
return stat;
}
static uint8 BT_testsignal(void)
{
uint8 stat;
uint8 buffer[3];
LOG(4,("Brooktree: Enabling testsignal\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xc4;
buffer[2] = 0x05;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting up flickerfilter and outputs\n"));
return stat;
}
static uint8 BT_setup_output(uint8 monstat, uint8 output, uint8 ffilter)
{
uint8 stat;
uint8 buffer[7];
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xc6;
buffer[2] = 0x98;
buffer[3] = 0x98;
if (!ffilter)
{
buffer[3] = 0xc0;
LOG(4,("Brooktree: Disabling flickerfilter\n"));
}
else
LOG(4,("Brooktree: Enabling flickerfilter\n"));
buffer[4] = 0xc0;
buffer[5] = 0xc0;
switch (output)
{
case 1:
LOG(4,("Brooktree: Forcing both Y/C and CVBS signals where supported by hardware\n"));
buffer[6] = 0x18;
break;
case 2:
LOG(4,("Brooktree: Forcing CVBS signals on all outputs\n"));
buffer[6] = 0x00;
break;
default:
LOG(4,("Brooktree: Outputting signals according to autodetect status:\n"));
switch (monstat)
{
case 1:
LOG(4,("Brooktree: Only Y connected, outputting CVBS on all outputs\n"));
buffer[6] = 0x00;
break;
case 2:
LOG(4,("Brooktree: Only C connected, outputting CVBS on all outputs\n"));
buffer[6] = 0x00;
break;
case 5:
LOG(4,("Brooktree: CVBS and only Y connected, outputting CVBS on all outputs\n"));
buffer[6] = 0x00;
break;
case 6:
LOG(4,("Brooktree: CVBS and only C connected, outputting CVBS on all outputs\n"));
buffer[6] = 0x00;
break;
default:
LOG(4,("Brooktree: Outputting both Y/C and CVBS where supported by hardware\n"));
buffer[6] = 0x18;
}
}
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting up flickerfilter and outputs\n"));
return stat;
}
static uint8 BT_setup_hphase(uint8 mode)
{
uint8 stat, hoffset;
uint8 buffer[7];
LOG(4,("Brooktree: Tuning horizontal phase\n"));
snooze(1000);
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x6c;
buffer[2] = 0x86;
buffer[3] = 0x00;
buffer[4] = 0x02;
buffer[5] = 0x00;
switch (si->ps.card_type)
{
case NV05:
case NV05M64:
case NV15:
hoffset = 8;
break;
default:
hoffset = 0;
break;
}
switch (mode)
{
case NTSC640_TST:
case NTSC640:
if (si->ps.tv_encoder.type >= CX25870) hoffset +=8;
buffer[3] = (0x1e + hoffset);
break;
case NTSC800:
if (si->ps.tv_encoder.type >= CX25870) hoffset +=8;
buffer[3] = (0xe1 + hoffset);
buffer[4] = 0xc2;
buffer[5] = 0x40;
break;
case PAL640:
if (si->ps.tv_encoder.type >= CX25870) hoffset +=8;
buffer[3] = (0xa8 + hoffset);
break;
case PAL800_TST:
case PAL800:
if (si->ps.tv_encoder.type >= CX25870) hoffset +=8;
buffer[3] = (0x2c + hoffset);
break;
case NTSC720:
if (si->ps.tv_encoder.type >= CX25870)
buffer[3] = (0xb2 + hoffset);
else
buffer[3] = (0xd0 + hoffset);
buffer[4] = 0xff;
break;
case PAL720:
buffer[3] = (0xd4 + hoffset);
buffer[4] = 0xff;
break;
case NTSC640_OS:
buffer[3] = (0xc8 + hoffset);
buffer[4] = 0xff;
break;
case PAL800_OS:
if (si->ps.tv_encoder.type >= CX25870)
buffer[3] = (0x78 + hoffset);
else
buffer[3] = (0xc4 + hoffset);
buffer[4] = 0xff;
break;
default:
break;
}
buffer[6] = 0x01;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
LOG(4,("Brooktree: I2C errors occurred while setting up h_phase\n"));
return stat;
}
static uint8 BT_read_monstat(uint8* monstat)
{
uint8 stat;
uint8 buffer[3];
*monstat = 0;
LOG(4,("Brooktree: Autodetecting connected output devices\n"));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xc4;
buffer[2] = 0x41;
i2c_flag_error (-1);
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while reading connection status (1)\n"));
return stat;
}
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xba;
buffer[2] = 0x40;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while reading connection status (2)\n"));
return stat;
}
snooze(60000);
buffer[0] = si->ps.tv_encoder.adress + RD;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, 1);
buffer[0] = 1;
i2c_readbuffer(si->ps.tv_encoder.bus, buffer, 1);
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while reading connection status (3)\n"));
return stat;
}
*monstat = ((buffer[0] & 0xe0) >> 5);
LOG(4,("Brooktree: TV output monitor status = %d\n", *monstat));
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xba;
buffer[2] = 0x00;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while reading connection status (4)\n"));
return stat;
}
return stat;
}
static uint8 BT_killclk_blackout(void)
{
uint8 stat;
uint8 buffer[4];
LOG(4,("Brooktree: Killing clock and/or blacking out (blocking output signals)\n"));
i2c_flag_error (-1);
if (si->ps.tv_encoder.type <= BT869)
{
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xa0;
buffer[2] = 0x00;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, 3);
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while doing killclk_blackout (1-BT)\n"));
return stat;
}
}
else
{
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0x6c;
buffer[2] = 0x02;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, 3);
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while doing killclk_blackout (1-CX)\n"));
return stat;
}
}
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xc4;
buffer[2] = 0x01;
buffer[3] = 0x18;
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, sizeof(buffer));
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while doing killclk_blackout (2)\n"));
return stat;
}
return stat;
}
uint8 BT_dpms(bool display)
{
uint8 stat;
uint8 buffer[3];
LOG(4,("Brooktree: setting DPMS: "));
i2c_flag_error (-1);
buffer[0] = si->ps.tv_encoder.adress + WR;
buffer[1] = 0xba;
if (display)
{
buffer[2] = 0x00;
LOG(4,("display on\n"));
}
else
{
buffer[2] = 0x10;
LOG(4,("display off\n"));
}
i2c_bstart(si->ps.tv_encoder.bus);
i2c_writebuffer(si->ps.tv_encoder.bus, buffer, 3);
i2c_bstop(si->ps.tv_encoder.bus);
stat = i2c_flag_error(0);
if (stat)
{
LOG(4,("Brooktree: I2C errors occurred while setting DPMS\n"));
return stat;
}
return stat;
}
uint8 BT_check_tvmode(display_mode target)
{
uint8 status = NOT_SUPPORTED;
uint32 mode = ((target.timing.h_display) | ((target.timing.v_display) << 16));
switch (mode)
{
case (640 | (480 << 16)):
if (((target.flags & TV_BITS) == TV_PAL) && (!(target.flags & TV_VIDEO)))
status = PAL640;
if ((target.flags & TV_BITS) == TV_NTSC)
{
if (!(target.flags & TV_VIDEO)) status = NTSC640;
else status = NTSC640_OS;
}
break;
case (768 | (576 << 16)):
if (((target.flags & TV_BITS) == TV_PAL) && (target.flags & TV_VIDEO))
status = PAL800_OS;
break;
case (800 | (600 << 16)):
if (((target.flags & TV_BITS) == TV_PAL) && (!(target.flags & TV_VIDEO)))
status = PAL800;
if (((target.flags & TV_BITS) == TV_NTSC) && (!(target.flags & TV_VIDEO)))
status = NTSC800;
break;
case (720 | (480 << 16)):
if (((target.flags & TV_BITS) == TV_NTSC) && (target.flags & TV_VIDEO))
status = NTSC720;
break;
case (720 | (576 << 16)):
if (((target.flags & TV_BITS) == TV_PAL) && (target.flags & TV_VIDEO))
status = PAL720;
break;
}
return status;
}
static status_t BT_update_mode_for_gpu(display_mode *target, uint8 tvmode)
{
switch (tvmode)
{
case NTSC640:
case NTSC640_TST:
target->timing.h_display = 640;
target->timing.h_sync_start = 640;
if (si->ps.card_type == NV05M64)
{
target->timing.h_sync_end = 648;
target->timing.h_total = 696;
}
else
{
target->timing.h_sync_end = 656;
target->timing.h_total = 688;
}
target->timing.v_display = 480;
target->timing.v_sync_start = 480;
target->timing.v_sync_end = 555;
target->timing.v_total = 556;
if (si->ps.card_type == NV05M64)
target->timing.pixel_clock = ((696 * 556 * 60) / 1000);
else
target->timing.pixel_clock = ((688 * 556 * 60) / 1000);
break;
case NTSC800:
target->timing.h_display = 800;
target->timing.h_sync_start = 800;
if (si->ps.card_type == NV05M64)
{
target->timing.h_sync_end = 808;
target->timing.h_total = 856;
}
else
{
target->timing.h_sync_end = 816;
target->timing.h_total = 848;
}
target->timing.v_display = 600;
target->timing.v_sync_start = 600;
target->timing.v_sync_end = 685;
target->timing.v_total = 686;
if (si->ps.card_type == NV05M64)
target->timing.pixel_clock = ((856 * 686 * 60) / 1000);
else
target->timing.pixel_clock = ((848 * 686 * 60) / 1000);
break;
case PAL640:
target->timing.h_display = 640;
target->timing.h_sync_start = 640;
if (si->ps.card_type == NV05M64)
{
target->timing.h_sync_end = 648;
target->timing.h_total = 696;
}
else
{
target->timing.h_sync_end = 656;
target->timing.h_total = 688;
}
target->timing.v_display = 480;
target->timing.v_sync_start = 480;
target->timing.v_sync_end = 570;
target->timing.v_total = 571;
if (si->ps.card_type == NV05M64)
target->timing.pixel_clock = ((696 * 571 * 50) / 1000);
else
target->timing.pixel_clock = ((688 * 571 * 50) / 1000);
break;
case PAL800:
case PAL800_TST:
target->timing.h_display = 800;
target->timing.h_sync_start = 800;
if (si->ps.card_type == NV05M64)
{
target->timing.h_sync_end = 808;
target->timing.h_total = 856;
}
else
{
target->timing.h_sync_end = 816;
target->timing.h_total = 848;
}
target->timing.v_display = 600;
target->timing.v_sync_start = 600;
target->timing.v_sync_end = 695;
target->timing.v_total = 696;
if (si->ps.card_type == NV05M64)
target->timing.pixel_clock = ((856 * 696 * 50) / 1000);
else
target->timing.pixel_clock = ((848 * 696 * 50) / 1000);
break;
case NTSC640_OS:
target->timing.h_display = 640;
target->timing.h_sync_start = 744;
target->timing.h_sync_end = 744+20;
target->timing.h_total = 784;
target->timing.v_display = 480;
target->timing.v_sync_start = 490;
target->timing.v_sync_end = 490+25;
target->timing.v_total = 525;
target->timing.pixel_clock = ((784 * 525 * 60) / 1000);
break;
case PAL800_OS:
target->timing.h_display = 768;
if (si->ps.tv_encoder.type <= BT869)
{
target->timing.h_sync_start = 856;
target->timing.h_sync_end = 856+20;
}
else
{
target->timing.h_sync_start = 848;
target->timing.h_sync_end = 848+20;
}
target->timing.h_total = 944;
target->timing.v_display = 576;
target->timing.v_sync_start = 579;
target->timing.v_sync_end = 579+42;
target->timing.v_total = 625;
target->timing.pixel_clock = ((944 * 625 * 50) / 1000);
break;
case NTSC720:
target->timing.h_display = 720;
if (si->ps.tv_encoder.type <= BT869)
{
target->timing.h_sync_start = 744;
target->timing.h_sync_end = 744+144;
}
else
{
target->timing.h_sync_start = 728;
target->timing.h_sync_end = 728+160;
}
target->timing.h_total = 888;
target->timing.v_display = 480;
target->timing.v_sync_start = 490;
target->timing.v_sync_end = 490+26;
target->timing.v_total = 525;
target->timing.pixel_clock = ((888 * 525 * 60) / 1000);
break;
case PAL720:
target->timing.h_display = 720;
target->timing.h_sync_start = 744;
target->timing.h_sync_end = 744+140;
target->timing.h_total = 888;
target->timing.v_display = 576;
target->timing.v_sync_start = 579;
target->timing.v_sync_end = 579+42;
target->timing.v_total = 625;
target->timing.pixel_clock = ((888 * 625 * 50) / 1000);
break;
default:
return B_ERROR;
}
return B_OK;
}
static status_t BT_start_tvout(display_mode tv_target)
{
if (tv_target.flags & TV_PRIMARY)
{
if ((tv_target.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head1_start_tvout();
else
head2_start_tvout();
}
else
{
if ((tv_target.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head2_start_tvout();
else
head1_start_tvout();
}
return B_OK;
}
status_t BT_stop_tvout(void)
{
BT_killclk_blackout();
if (si->dm.flags & TV_PRIMARY)
{
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head1_stop_tvout();
else
head2_stop_tvout();
}
else
{
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head2_stop_tvout();
else
head1_stop_tvout();
}
if (0)
{
BT_testsignal();
}
return B_OK;
}
status_t BT_setmode(display_mode target)
{
uint8 tvmode, monstat;
uint8 ffilter = 0;
display_mode tv_target = target;
tvmode = BT_check_tvmode(tv_target);
if (!tvmode) return B_ERROR;
BT_read_monstat(&monstat);
switch (tvmode)
{
case NTSC640:
case NTSC640_TST:
ffilter = 1;
BT_init_NTSC640();
break;
case NTSC800:
ffilter = 1;
BT_init_NTSC800();
break;
case PAL640:
ffilter = 1;
BT_init_PAL640();
break;
case PAL800:
case PAL800_TST:
ffilter = 1;
BT_init_PAL800();
break;
case NTSC640_OS:
BT_init_NTSC640_OS();
break;
case PAL800_OS:
BT_init_PAL800_OS();
break;
case NTSC720:
BT_init_NTSC720();
break;
case PAL720:
BT_init_PAL720();
break;
}
BT_setup_hphase(tvmode);
switch (tvmode)
{
case NTSC640:
case NTSC640_TST:
case NTSC800:
case NTSC640_OS:
case NTSC720:
BT_set_macro (0, 0);
break;
default:
BT_set_macro (1, 0);
break;
}
BT_setup_output(monstat, (uint8)(si->settings.tv_output), ffilter);
BT_update_mode_for_gpu(&tv_target, tvmode);
if (tv_target.flags & TV_PRIMARY)
{
if ((tv_target.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head1_set_timing(tv_target);
else
head2_set_timing(tv_target);
}
else
{
if ((tv_target.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
head2_set_timing(tv_target);
else
head1_set_timing(tv_target);
}
BT_start_tvout(tv_target);
return B_OK;
}