Rudolf Cornelissen 7/2003-4/2021
*/
#define MODULE_BIT 0x00002000
#include "nv_std.h"
typedef struct {
uint16 InitScriptTablePtr;
uint16 MacroIndexTablePtr;
uint16 MacroTablePtr;
uint16 ConditionTablePtr;
uint16 IOConditionTablePtr;
uint16 IOFlagConditionTablePtr;
uint16 InitFunctionTablePtr;
} PinsTables;
static void detect_panels(void);
static void setup_output_matrix(void);
static void pinsnv4_fake(void);
static void pinsnv5_nv5m64_fake(void);
static void pinsnv6_fake(void);
static void pinsnv10_arch_fake(void);
static void pinsnv20_arch_fake(void);
static void pinsnv30_arch_fake(void);
static void getRAMsize_arch_nv4(void);
static void getstrap_arch_nv4(void);
static void getRAMsize_arch_nv10_20_30_40(void);
static void getstrap_arch_nv10_20_30_40(void);
static status_t pins2_read(uint8 *rom, uint32 offset);
static status_t pins3_5_read(uint8 *rom, uint32 offset);
static status_t coldstart_card(uint8* rom, uint16 init1, uint16 init2, uint16 init_size, uint16 ram_tab);
static status_t coldstart_card_516_up(uint8* rom, PinsTables tabs, uint16 ram_tab);
static status_t exec_type1_script(uint8* rom, uint16 adress, int16* size, uint16 ram_tab);
static status_t exec_type2_script(uint8* rom, uint16 adress, int16* size, PinsTables tabs, uint16 ram_tab);
static status_t exec_type2_script_mode(uint8* rom, uint16* adress, int16* size, PinsTables tabs, uint16 ram_tab, bool* exec);
static void exec_cmd_39_type2(uint8* rom, uint32 data, PinsTables tabs, bool* exec);
static void log_pll(uint32 reg, uint32 freq);
static void setup_ram_config(uint8* rom, uint16 ram_tab);
static void setup_ram_config_nv10_up(uint8* rom);
static void setup_ram_config_nv28(uint8* rom);
static status_t translate_ISA_PCI(uint32* reg);
static status_t nv_crtc_setup_fifo(void);
status_t parse_pins ()
{
uint8 *rom;
uint8 chksum = 0;
int i;
uint32 offset;
status_t result = B_ERROR;
si->ps.pins_status = B_ERROR;
LOG(2,("INFO: Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("INFO: BIOS signature not found\n"));
return B_ERROR;
}
LOG(2,("INFO: BIOS signature $AA55 found OK\n"));
for (offset = 0; offset < 65536; offset++)
{
if (rom[offset ] != 0xff) continue;
if (rom[offset + 1] != 0x7f) continue;
if (rom[offset + 2] != 0x4e) continue;
if (rom[offset + 3] != 0x56) continue;
if (rom[offset + 4] != 0x00) continue;
LOG(8,("INFO: PINS signature found\n"));
break;
}
if (offset > 65535)
{
LOG(8,("INFO: PINS signature not found\n"));
return B_ERROR;
}
for (i = 0; i < 8; i++)
{
chksum += rom[offset + i];
}
if (chksum)
{
LOG(8,("INFO: PINS checksum error\n"));
return B_ERROR;
}
LOG(2,("INFO: PINS checksum is OK; PINS version is %d.%d\n",
rom[offset + 5], rom[offset + 6]));
switch (rom[offset + 5])
{
case 2:
result = pins2_read(rom, offset);
break;
case 3:
case 4:
case 5:
result = pins3_5_read(rom, offset);
break;
default:
LOG(8,("INFO: unknown PINS version\n"));
return B_ERROR;
break;
}
if (result == B_ERROR)
{
LOG(8,("INFO: PINS read/decode/execute error\n"));
return B_ERROR;
}
si->ps.pins_status = B_OK;
LOG(2,("INFO: PINS scan completed succesfully\n"));
return B_OK;
}
static status_t pins2_read(uint8 *rom, uint32 offset)
{
uint16 init1 = rom[offset + 18] + (rom[offset + 19] * 256);
uint16 init2 = rom[offset + 20] + (rom[offset + 21] * 256);
uint16 init_size = rom[offset + 22] + (rom[offset + 23] * 256) + 1;
uint16 ram_tab = init1 - 0x0010;
unsigned char* signon_msg
= &(rom[(rom[offset + 24] + (rom[offset + 25] * 256))]);
unsigned char* vendor_name
= &(rom[(rom[offset + 40] + (rom[offset + 41] * 256))]);
unsigned char* product_name
= &(rom[(rom[offset + 42] + (rom[offset + 43] * 256))]);
unsigned char* product_rev
= &(rom[(rom[offset + 44] + (rom[offset + 45] * 256))]);
LOG(8, ("INFO: cmdlist 1: $%04x, 2: $%04x, max. size $%04x\n", init1, init2,
init_size));
LOG(8, ("INFO: signon msg:\n%s\n", signon_msg));
LOG(8, ("INFO: vendor name: %s\n", vendor_name));
LOG(8, ("INFO: product name: %s\n", product_name));
LOG(8, ("INFO: product rev: %s\n", product_rev));
return coldstart_card(rom, init1, init2, init_size, ram_tab);
}
static status_t pins3_5_read(uint8 *rom, uint32 offset)
{
uint16 init1 = rom[offset + 18] + (rom[offset + 19] * 256);
uint16 init2 = rom[offset + 20] + (rom[offset + 21] * 256);
uint16 init_size = rom[offset + 22] + (rom[offset + 23] * 256) + 1;
uint16 ram_tab = rom[offset + 24] + (rom[offset + 25] * 256);
unsigned char* signon_msg
= &(rom[(rom[offset + 30] + (rom[offset + 31] * 256))]);
unsigned char* vendor_name
= &(rom[(rom[offset + 46] + (rom[offset + 47] * 256))]);
unsigned char* product_name
= &(rom[(rom[offset + 48] + (rom[offset + 49] * 256))]);
unsigned char* product_rev
= &(rom[(rom[offset + 50] + (rom[offset + 51] * 256))]);
LOG(8, ("INFO: pre PINS 5.16 cmdlist 1: $%04x, 2: $%04x, max. size $%04x\n",
init1, init2, init_size));
LOG(8, ("INFO: signon msg:\n%s\n", signon_msg));
LOG(8, ("INFO: vendor name: %s\n", vendor_name));
LOG(8, ("INFO: product name: %s\n", product_name));
LOG(8, ("INFO: product rev: %s\n", product_rev));
if (((rom[offset + 5]) == 5) && ((rom[offset + 6]) >= 0x06))
{
uint32 fvco_max = *((uint32*)(&(rom[offset + 67])));
uint32 fvco_min = *((uint32*)(&(rom[offset + 71])));
LOG(8,("INFO: PLL VCO range is %dkHz - %dkHz\n", fvco_min, fvco_max));
si->ps.min_system_vco = fvco_min / 1000;
si->ps.max_system_vco = fvco_max / 1000;
}
if (((rom[offset + 5]) == 5) && ((rom[offset + 6]) >= 0x10))
{
* commands to choose from as well. */
PinsTables tabs;
tabs.InitScriptTablePtr = rom[offset + 75] + (rom[offset + 76] * 256);
tabs.MacroIndexTablePtr = rom[offset + 77] + (rom[offset + 78] * 256);
tabs.MacroTablePtr = rom[offset + 79] + (rom[offset + 80] * 256);
tabs.ConditionTablePtr = rom[offset + 81] + (rom[offset + 82] * 256);
tabs.IOConditionTablePtr = rom[offset + 83] + (rom[offset + 84] * 256);
tabs.IOFlagConditionTablePtr = rom[offset + 85] + (rom[offset + 86] * 256);
tabs.InitFunctionTablePtr = rom[offset + 87] + (rom[offset + 88] * 256);
LOG(8,("INFO: PINS 5.16 and later cmdlist pointers:\n"));
LOG(8,("INFO: InitScriptTablePtr: $%04x\n", tabs.InitScriptTablePtr));
LOG(8,("INFO: MacroIndexTablePtr: $%04x\n", tabs.MacroIndexTablePtr));
LOG(8,("INFO: MacroTablePtr: $%04x\n", tabs.MacroTablePtr));
LOG(8,("INFO: ConditionTablePtr: $%04x\n", tabs.ConditionTablePtr));
LOG(8,("INFO: IOConditionTablePtr: $%04x\n", tabs.IOConditionTablePtr));
LOG(8,("INFO: IOFlagConditionTablePtr: $%04x\n", tabs.IOFlagConditionTablePtr));
LOG(8,("INFO: InitFunctionTablePtr: $%04x\n", tabs.InitFunctionTablePtr));
return coldstart_card_516_up(rom, tabs, ram_tab);
}
else
{
* table always has two entries. */
return coldstart_card(rom, init1, init2, init_size, ram_tab);
}
}
static status_t coldstart_card(uint8* rom, uint16 init1, uint16 init2, uint16 init_size, uint16 ram_tab)
{
status_t result = B_OK;
int16 size = init_size;
LOG(8,("INFO: now executing coldstart...\n"));
NV_REG8(NV8_MISCW) = 0xcb;
NV_REG8(NV8_VSE2) = 0x01;
set_crtc_owner(0);
CRTCW(LOCK, 0x57);
CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
* and framebuffer via legacy ISA I/O space.) */
CRTCW(RMA, 0x00);
if (si->ps.secondary_head)
{
set_crtc_owner(1);
CRTC2W(LOCK, 0x57);
CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
}
nv_crtc_dpms(false, false, false, true);
nv_crtc_cursor_hide();
if (si->ps.secondary_head)
{
nv_crtc2_dpms(false, false, false, true);
nv_crtc2_cursor_hide();
}
if (init1 || init2)
{
if (init1)
if (exec_type1_script(rom, init1, &size, ram_tab) != B_OK) result = B_ERROR;
if (init2 && (result == B_OK))
if (exec_type1_script(rom, init2, &size, ram_tab) != B_OK) result = B_ERROR;
CFGW(ROMSHADOW, (CFGR(ROMSHADOW) |= 0x00000001));
nv_crtc_setup_fifo();
}
else
{
result = B_ERROR;
}
if (result != B_OK)
LOG(8,("INFO: coldstart failed.\n"));
else
LOG(8,("INFO: coldstart execution completed OK.\n"));
return result;
}
static status_t coldstart_card_516_up(uint8* rom, PinsTables tabs, uint16 ram_tab)
{
status_t result = B_OK;
uint16 adress;
uint32 fb_mrs1 = 0;
uint32 fb_mrs2 = 0;
LOG(8,("INFO: now executing coldstart...\n"));
if (si->ps.card_type == NV28)
{
fb_mrs2 = NV_REG32(NV32_FB_MRS2);
fb_mrs1 = NV_REG32(NV32_FB_MRS1);
}
NV_REG8(NV8_MISCW) = 0xcb;
NV_REG8(NV8_VSE2) = 0x01;
set_crtc_owner(0);
CRTCW(LOCK, 0x57);
CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
* and framebuffer via legacy ISA I/O space.) */
CRTCW(RMA, 0x00);
if (si->ps.secondary_head)
{
set_crtc_owner(1);
CRTC2W(LOCK, 0x57);
CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
}
nv_crtc_dpms(false, false, false, true);
nv_crtc_cursor_hide();
if (si->ps.secondary_head)
{
nv_crtc2_dpms(false, false, false, true);
nv_crtc2_cursor_hide();
}
if (tabs.InitScriptTablePtr)
{
int16 size = 32767;
uint16 index = tabs.InitScriptTablePtr;
adress = *((uint16*)(&(rom[index])));
if (!adress)
{
LOG(8,("INFO: no cmdlist found!\n"));
result = B_ERROR;
}
while (adress && (result == B_OK))
{
result = exec_type2_script(rom, adress, &size, tabs, ram_tab);
index += 2;
adress = *((uint16*)(&(rom[index])));
}
if (si->ps.card_type == NV28)
{
ACCW(PT_NUMERATOR, (si->ps.std_engine_clock * 20));
ACCW(PT_DENOMINATR, 0x00000271);
NV_REG32(NV32_FB_MRS2) = fb_mrs2;
NV_REG32(NV32_FB_MRS1) = fb_mrs1;
}
CFGW(ROMSHADOW, (CFGR(ROMSHADOW) |= 0x00000001));
nv_crtc_setup_fifo();
}
else
{
result = B_ERROR;
}
if (result != B_OK)
LOG(8,("INFO: coldstart failed.\n"));
else
LOG(8,("INFO: coldstart execution completed OK.\n"));
return result;
}
* Erazor III with TNT2 (NV05) and on two no-name TNT2-M64's. All cards coldstart
* perfectly. */
static status_t exec_type1_script(uint8* rom, uint16 adress, int16* size, uint16 ram_tab)
{
status_t result = B_OK;
bool end = false;
bool exec = true;
uint8 index, byte;
uint32 reg, data, data2, and_out, or_in;
LOG(8,("\nINFO: executing type1 script at adress $%04x...\n", adress));
LOG(8,("INFO: ---Executing following command(s):\n"));
while (!end)
{
LOG(8,("INFO: $%04x ($%02x); ", adress, rom[adress]));
switch (rom[adress])
{
case 0x59:
*size -= 7;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint16*)(&(rom[adress])));
adress += 2;
data2 = *((uint16*)(&(rom[data])));
LOG(8,("cmd 'calculate indirect and set PLL 32bit reg $%08x for %.3fMHz'\n",
reg, ((float)data2)));
if (exec)
{
float calced_clk;
uint8 m, n, p;
nv_dac_sys_pll_find(((float)data2), &calced_clk, &m, &n, &p, 0);
NV_REG32(reg) = ((p << 16) | (n << 8) | m);
}
log_pll(reg, data2);
break;
case 0x5a:
*size -= 7;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint16*)(&(rom[adress])));
adress += 2;
data2 = *((uint32*)(&(rom[data])));
LOG(8,("cmd 'WR indirect 32bit reg' $%08x = $%08x\n", reg, data2));
if (exec) NV_REG32(reg) = data2;
break;
case 0x63:
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
LOG(8,("cmd 'setup RAM config' (always done)\n"));
setup_ram_config(rom, ram_tab);
break;
case 0x65:
*size -= 13;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint32*)(&(rom[adress])));
adress += 4;
data2 = *((uint32*)(&(rom[adress])));
adress += 4;
LOG(8,("cmd 'WR 32bit reg $%08x = $%08x, then = $%08x' (always done)\n",
reg, data, data2));
NV_REG32(reg) = data;
NV_REG32(reg) = data2;
CFGW(ROMSHADOW, (CFGR(ROMSHADOW) & 0xfffffffe));
break;
case 0x69:
*size -= 5;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint16*)(&(rom[adress])));
adress += 2;
and_out = *((uint8*)(&(rom[adress])));
adress += 1;
or_in = *((uint8*)(&(rom[adress])));
adress += 1;
LOG(8,("cmd 'RD 8bit ISA reg $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n",
reg, and_out, or_in));
if (exec)
{
translate_ISA_PCI(®);
byte = NV_REG8(reg);
byte &= (uint8)and_out;
byte |= (uint8)or_in;
NV_REG8(reg) = byte;
}
break;
case 0x6d:
*size -= 3;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
data = NV_REG32(NV32_NV4STRAPINFO);
and_out = *((uint8*)(&(rom[adress])));
adress += 1;
byte = *((uint8*)(&(rom[adress])));
adress += 1;
data &= (uint32)and_out;
LOG(8,("cmd 'CHK bits AND-out $%02x RAMCFG for $%02x'\n",
and_out, byte));
if (((uint8)data) != byte)
{
LOG(8,("INFO: ---No match: not executing following command(s):\n"));
exec = false;
}
else
{
LOG(8,("INFO: ---Match, so this cmd has no effect.\n"));
}
break;
case 0x6e:
*size -= 13;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
and_out = *((uint32*)(&(rom[adress])));
adress += 4;
or_in = *((uint32*)(&(rom[adress])));
adress += 4;
LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, OR-in = $%08x, WR-bk'\n",
reg, and_out, or_in));
if (exec)
{
data = NV_REG32(reg);
data &= and_out;
data |= or_in;
NV_REG32(reg) = data;
}
break;
case 0x71:
LOG(8,("cmd 'END', execution completed.\n\n"));
end = true;
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
break;
case 0x72:
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
adress += 1;
LOG(8,("cmd 'PGM commands'\n"));
LOG(8,("INFO: ---Executing following command(s):\n"));
exec = true;
break;
case 0x73:
*size -= 9;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
data = NV_REG32(NV32_NVSTRAPINFO2);
and_out = *((uint32*)(&(rom[adress])));
adress += 4;
data2 = *((uint32*)(&(rom[adress])));
adress += 4;
data &= and_out;
LOG(8,("cmd 'CHK bits AND-out $%08x STRAPCFG2 for $%08x'\n",
and_out, data2));
if (data != data2)
{
LOG(8,("INFO: ---No match: not executing following command(s):\n"));
exec = false;
}
else
{
LOG(8,("INFO: ---Match, so this cmd has no effect.\n"));
}
break;
case 0x74:
*size -= 3;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
data = *((uint16*)(&(rom[adress])));
adress += 2;
LOG(8,("cmd 'SNOOZE for %d ($%04x) microSeconds' (always done)\n", data, data));
snooze(data);
break;
case 0x77:
*size -= 7;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint16*)(&(rom[adress])));
adress += 2;
LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x (b31-16 = '0', b15-0 = data)\n",
reg, data));
if (exec) NV_REG32(reg) = data;
break;
case 0x78:
*size -= 6;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint16*)(&(rom[adress])));
adress += 2;
index = *((uint8*)(&(rom[adress])));
adress += 1;
and_out = *((uint8*)(&(rom[adress])));
adress += 1;
or_in = *((uint8*)(&(rom[adress])));
adress += 1;
LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n",
index, reg, and_out, or_in));
if (exec)
{
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
byte |= (uint8)or_in;
NV_REG8(reg + 1) = byte;
}
break;
case 0x79:
*size -= 7;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint16*)(&(rom[adress])));
adress += 2;
LOG(8,("cmd 'calculate and set PLL 32bit reg $%08x for %.3fMHz'\n", reg, (data / 100.0)));
if (exec)
{
float calced_clk;
uint8 m, n, p;
nv_dac_sys_pll_find((data / 100.0), &calced_clk, &m, &n, &p, 0);
NV_REG32(reg) = ((p << 16) | (n << 8) | m);
}
log_pll(reg, (data / 100));
break;
case 0x7a:
*size -= 9;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
adress += 1;
reg = *((uint32*)(&(rom[adress])));
adress += 4;
data = *((uint32*)(&(rom[adress])));
adress += 4;
LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x\n", reg, data));
if (exec) NV_REG32(reg) = data;
break;
default:
LOG(8,("unknown cmd, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
}
return result;
}
static void log_pll(uint32 reg, uint32 freq)
{
if ((si->ps.card_type == NV31) || (si->ps.card_type == NV36))
LOG(8,("INFO: ---WARNING: check/update PLL programming script code!!!\n"));
switch (reg)
{
case NV32_MEMPLL:
LOG(8,("INFO: ---Memory PLL accessed.\n"));
si->ps.std_memory_clock = freq;
break;
case NV32_COREPLL:
LOG(8,("INFO: ---Core PLL accessed.\n"));
si->ps.std_engine_clock = freq;
break;
case NVDAC_PIXPLLC:
LOG(8,("INFO: ---DAC1 PLL accessed.\n"));
break;
case NVDAC2_PIXPLLC:
LOG(8,("INFO: ---DAC2 PLL accessed.\n"));
break;
case NV32_MEMPLL2:
LOG(8,("INFO: ---NV31/NV36 extension to memory PLL accessed only!\n"));
break;
case NV32_COREPLL2:
LOG(8,("INFO: ---NV31/NV36 extension to core PLL accessed only!\n"));
break;
case NVDAC_PIXPLLC2:
LOG(8,("INFO: ---NV31/NV36 extension to DAC1 PLL accessed only!\n"));
break;
case NVDAC2_PIXPLLC2:
LOG(8,("INFO: ---NV31/NV36 extension to DAC2 PLL accessed only!\n"));
break;
default:
LOG(8,("INFO: ---Unknown PLL accessed!\n"));
break;
}
}
static void setup_ram_config(uint8* rom, uint16 ram_tab)
{
uint32 ram_cfg, data;
uint8 cnt;
NV_REG32(NV32_PFB_DEBUG_0) &= 0xffffffef;
ram_cfg = ((NV_REG32(NV32_NVSTRAPINFO2) >> 2) & 0x0000000f);
LOG(8,("INFO: ---RAM config strap is $%01x\n", ram_cfg));
ram_cfg = *((uint16*)(&(rom[(ram_tab + (ram_cfg * 2))])));
switch (ram_cfg & 0x00000003)
{
case 0:
LOG(8,("INFO: ---32Mb RAM should be connected\n"));
break;
case 1:
LOG(8,("INFO: ---4Mb RAM should be connected\n"));
break;
case 2:
LOG(8,("INFO: ---8Mb RAM should be connected\n"));
break;
case 3:
LOG(8,("INFO: ---16Mb RAM should be connected\n"));
break;
}
if (ram_cfg & 0x00000004)
LOG(8,("INFO: ---RAM should be 128bits wide\n"));
else
LOG(8,("INFO: ---RAM should be 64bits wide\n"));
switch ((ram_cfg & 0x00000038) >> 3)
{
case 0:
LOG(8,("INFO: ---RAM type: 8Mbit SGRAM\n"));
break;
case 1:
LOG(8,("INFO: ---RAM type: 16Mbit SGRAM\n"));
break;
case 2:
LOG(8,("INFO: ---RAM type: 4 banks of 16Mbit SGRAM\n"));
break;
case 3:
LOG(8,("INFO: ---RAM type: 16Mbit SDRAM\n"));
break;
case 4:
LOG(8,("INFO: ---RAM type: 64Mbit SDRAM\n"));
break;
case 5:
LOG(8,("INFO: ---RAM type: 64Mbit x16 SDRAM\n"));
break;
}
data = (NV_REG32(NV32_NV4STRAPINFO) & 0xffffffc0);
NV_REG32(NV32_NV4STRAPINFO) = (data | (ram_cfg & 0x0000003f));
data = (NV_REG32(NV32_PFB_CONFIG_1) & 0xff8ffffe);
data |= ((ram_cfg & 0x00000700) << 12);
NV_REG32(NV32_PFB_CONFIG_1) = data;
NV_REG32(NV32_PFB_CONFIG_1) = (data | 0x00000001);
data = 0x4e563541;
for (cnt = 0; cnt < 4; cnt++)
((volatile uint32 *)si->framebuffer)[cnt] = data;
* set to 128bits width while we should be set to 64bits width, so correct. */
if (((volatile uint32 *)si->framebuffer)[3] != data)
{
LOG(8,("INFO: ---RAM width tested: width is 64bits, correcting settings.\n"));
NV_REG32(NV32_NV4STRAPINFO) &= ~0x00000004;
}
else
{
LOG(8,("INFO: ---RAM width tested: access is OK.\n"));
}
ram_cfg = (NV_REG32(NV32_NV4STRAPINFO) & 0x00000003);
data = 0x4e563542;
if (!ram_cfg)
{
((volatile uint32 *)si->framebuffer)[(16 * 1024 * 1024) >> 2] = data;
if (((volatile uint32 *)si->framebuffer)[(16 * 1024 * 1024) >> 2] == data)
{
data = 0x4135564e;
((volatile uint32 *)si->framebuffer)[0] = data;
if (((volatile uint32 *)si->framebuffer)[0] == data)
{
LOG(8,("INFO: ---RAM size tested: size was set OK (32Mb).\n"));
return;
}
}
ram_cfg = 0x00000003;
LOG(8,("INFO: ---RAM size tested: size is 16Mb, correcting settings.\n"));
NV_REG32(NV32_NV4STRAPINFO) =
(((NV_REG32(NV32_NV4STRAPINFO)) & 0xfffffffc) | ram_cfg);
return;
}
if (ram_cfg == 0x00000003)
{
data++;
((volatile uint32 *)si->framebuffer)[(8 * 1024 * 1024) >> 2] = data;
if (((volatile uint32 *)si->framebuffer)[(8 * 1024 * 1024) >> 2] == data)
{
LOG(8,("INFO: ---RAM size tested: size was set OK (16Mb).\n"));
return;
}
else
{
ram_cfg = 0x00000002;
LOG(8,("INFO: ---RAM size tested: size is NOT 16Mb, testing for 8Mb...\n"));
NV_REG32(NV32_NV4STRAPINFO) =
(((NV_REG32(NV32_NV4STRAPINFO)) & 0xfffffffc) | ram_cfg);
}
}
{
data++;
((volatile uint32 *)si->framebuffer)[(4 * 1024 * 1024) >> 2] = data;
if (((volatile uint32 *)si->framebuffer)[(4 * 1024 * 1024) >> 2] == data)
{
ram_cfg = 0x00000002;
LOG(8,("INFO: ---RAM size tested: size is 8Mb, setting 8Mb.\n"));
NV_REG32(NV32_NV4STRAPINFO) =
(((NV_REG32(NV32_NV4STRAPINFO)) & 0xfffffffc) | ram_cfg);
return;
}
else
{
ram_cfg = 0x00000001;
LOG(8,("INFO: ---RAM size tested: size is 4Mb, setting 4Mb.\n"));
NV_REG32(NV32_NV4STRAPINFO) =
(((NV_REG32(NV32_NV4STRAPINFO)) & 0xfffffffc) | ram_cfg);
return;
}
}
}
static status_t exec_type2_script(uint8* rom, uint16 adress, int16* size, PinsTables tabs, uint16 ram_tab)
{
bool exec = true;
LOG(8,("\nINFO: executing type2 script at adress $%04x...\n", adress));
LOG(8,("INFO: ---Executing following command(s):\n"));
return exec_type2_script_mode(rom, &adress, size, tabs, ram_tab, &exec);
}
* GeForce4 MX440 (NV18), GeForce4 Ti4200 (NV28) and a GeForceFX 5200 (NV34).
* These cards coldstart perfectly. */
static status_t exec_type2_script_mode(uint8* rom, uint16* adress, int16* size, PinsTables tabs, uint16 ram_tab, bool* exec)
{
status_t result = B_OK;
bool end = false;
uint8 index, byte, byte2, shift;
uint32 reg, reg2, data, data2, and_out, and_out2, or_in, or_in2, safe32, offset32, size32;
while (!end)
{
LOG(8,("INFO: $%04x ($%02x); ", *adress, rom[*adress]));
switch (rom[*adress])
{
case 0x31:
*size -= (15 + ((*((uint8*)(&(rom[(*adress + 10)])))) << 2));
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
and_out = *((uint32*)(&(rom[*adress])));
*adress += 4;
shift = *((uint8*)(&(rom[*adress])));
*adress += 1;
size32 = ((*((uint8*)(&(rom[*adress])))) << 2);
*adress += 1;
reg2 = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, shift-right = $%02x,\n",
reg, and_out, shift));
LOG(8,("INFO: (cont.) RD 32bit data from subtable with size $%04x, at offset (result << 2),\n",
size32));
LOG(8,("INFO: (cont.) then WR result data to 32bit reg $%08x'\n", reg2));
if (*exec && reg2)
{
data = NV_REG32(reg);
data &= and_out;
data >>= shift;
data2 = *((uint32*)(&(rom[(*adress + (data << 2))])));
NV_REG32(reg2) = data2;
}
*adress += size32;
break;
case 0x32:
*size -= (11 + ((*((uint8*)(&(rom[(*adress + 6)])))) << 2));
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
index = *((uint8*)(&(rom[*adress])));
*adress += 1;
and_out = *((uint8*)(&(rom[*adress])));
*adress += 1;
byte2 = *((uint8*)(&(rom[*adress])));
*adress += 1;
size32 = ((*((uint8*)(&(rom[*adress])))) << 2);
*adress += 1;
reg2 = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, shift-right = $%02x,\n",
index, reg, and_out, byte2));
LOG(8,("INFO: (cont.) RD 32bit data from subtable with size $%04x, at offset (result << 2),\n",
size32));
LOG(8,("INFO: (cont.) then WR result data to 32bit reg $%08x'\n", reg2));
if (*exec && reg2)
{
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
byte >>= byte2;
offset32 = (byte << 2);
data = *((uint32*)(&(rom[(*adress + offset32)])));
NV_REG32(reg2) = data;
}
*adress += size32;
break;
case 0x33:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
size32 = *((uint8*)(&(rom[*adress])));
*adress += 1;
if (!size32) size32 = 256;
safe32 = *adress;
LOG(8,("cmd 'execute following part of this script $%03x times' (always done)\n", size32));
for (offset32 = 0; offset32 < size32; offset32++)
{
LOG(8,("\nINFO: (#$%02x) executing part of type2 script at adress $%04x...\n",
offset32, *adress));
LOG(8,("INFO: ---Not touching 'execution' mode at this time:\n"));
*adress = safe32;
result = exec_type2_script_mode(rom, adress, size, tabs, ram_tab, exec);
}
LOG(8,("INFO: ---Continuing script:\n"));
break;
case 0x34:
*size -= (12 + ((*((uint8*)(&(rom[(*adress + 7)])))) << 1));
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
index = *((uint8*)(&(rom[*adress])));
*adress += 1;
and_out = *((uint8*)(&(rom[*adress])));
*adress += 1;
shift = *((uint8*)(&(rom[*adress])));
*adress += 1;
offset32 = *((uint8*)(&(rom[*adress])));
*adress += 1;
size32 = ((*((uint8*)(&(rom[*adress])))) << 1);
*adress += 1;
reg2 = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, shift-right = $%02x,\n",
index, reg, and_out, shift));
LOG(8,("INFO: (cont.) RD 16bit PLL frequency to pgm from subtable with size $%04x, at offset (result << 1),\n",
size32));
LOG(8,("INFO: (cont.) RD table-index ($%02x) for cmd $39'\n",
offset32));
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
data = (byte >> shift);
data <<= 1;
data2 = *((uint16*)(&(rom[(*adress + data)])));
if (offset32 < 0x80)
{
bool double_f = true;
LOG(8,("INFO: Do subcmd ($39); "));
exec_cmd_39_type2(rom, offset32, tabs, &double_f);
LOG(8,("INFO: (cont. cmd $34) Doubling PLL frequency to be set for cmd $34.\n"));
if (double_f) data2 <<= 1;
LOG(8,("INFO: ---Reverting to pre-subcmd ($39) 'execution' mode.\n"));
}
else
{
LOG(8,("INFO: table index is negative, not executing subcmd ($39).\n"));
}
LOG(8,("INFO: (cont.) 'calc and set PLL 32bit reg $%08x for %.3fMHz'\n",
reg2, (data2 / 100.0)));
if (*exec && reg2)
{
float calced_clk;
uint8 m, n, p;
nv_dac_sys_pll_find((data2 / 100.0), &calced_clk, &m, &n, &p, 0);
data = NV_REG32(reg2);
NV_REG32(reg2) = ((data & 0xffff0000) | (n << 8) | m);
data = NV_REG32(reg2);
NV_REG32(reg2) = ((p << 16) | (n << 8) | m);
}
log_pll(reg2, (data2 / 100));
*adress += size32;
break;
case 0x35:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
byte = *((uint8*)(&(rom[*adress])));
*adress += 1;
offset32 = (byte << 1);
offset32 += tabs.InitFunctionTablePtr;
LOG(8,("cmd 'execute fixed VGA BIOS routine #$%02x at adress $%04x'\n",
byte, offset32));
* This command is BIOS/'pins' version specific. Confirmed a NV28 having NO
* entries at all in InitFunctionTable!
* (BIOS version 4.28.20.05.11; 'pins' version 5.21) */
if (*exec)
{
switch(byte)
{
default:
LOG(8,("\n\nINFO: WARNING: function not implemented, skipping!\n\n"));
break;
}
}
break;
case 0x37:
*size -= 11;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
byte2 = *((uint8*)(&(rom[*adress])));
*adress += 1;
and_out = *((uint8*)(&(rom[*adress])));
*adress += 1;
reg2 = *((uint16*)(&(rom[*adress])));
*adress += 2;
index = *((uint8*)(&(rom[*adress])));
*adress += 1;
and_out2 = *((uint8*)(&(rom[*adress])));
*adress += 1;
LOG(8,("cmd 'RD 32bit reg $%08x, shift-right = $%02x, AND-out lsb = $%02x,\n",
reg, byte2, and_out));
LOG(8,("INFO: (cont.) RD 8bit ISA reg $%02x via $%04x, AND-out = $%02x, OR-in lsb result 32bit, WR-bk'\n",
index, reg2, and_out2));
if (*exec)
{
data = NV_REG32(reg);
if (byte2 < 0x80)
{
data >>= byte2;
}
else
{
data <<= (0x0100 - byte2);
}
data &= and_out;
translate_ISA_PCI(®2);
NV_REG8(reg2) = index;
byte = NV_REG8(reg2 + 1);
byte &= (uint8)and_out2;
byte |= (uint8)data;
NV_REG8(reg2 + 1) = byte;
}
break;
case 0x38:
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
LOG(8,("cmd 'invert current mode'\n"));
*exec = !(*exec);
if (*exec)
LOG(8,("INFO: ---Executing following command(s):\n"));
else
LOG(8,("INFO: ---Not executing following command(s):\n"));
break;
case 0x39:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
data = *((uint8*)(&(rom[*adress])));
*adress += 1;
exec_cmd_39_type2(rom, data, tabs, exec);
break;
case 0x49:
size32 = *((uint8*)(&(rom[*adress + 17])));
if (!size32) size32 = 256;
*size -= (18 + (size32 << 1));
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
reg2 = *((uint32*)(&(rom[*adress])));
*adress += 4;
and_out = *((uint32*)(&(rom[*adress])));
*adress += 4;
or_in = *((uint32*)(&(rom[*adress])));
*adress += 4;
size32 = *((uint8*)(&(rom[*adress])));
if (!size32) size32 = 256;
*adress += 1;
LOG(8,("cmd 'do following cmd structure $%03x time(s)':\n", size32));
for (offset32 = 0; offset32 < size32; offset32++)
{
or_in2 = *((uint8*)(&(rom[(*adress + (offset32 << 1))])));
data2 = *((uint8*)(&(rom[(*adress + (offset32 << 1) + 1)])));
LOG(8,("INFO (cont.) (#$%02x) cmd 'WR 32bit reg $%08x = $%08x, RD 32bit reg $%08x,\n",
offset32, reg2, data2, reg));
LOG(8,("INFO (cont.) AND-out $%08x, OR-in $%08x, OR-in $%08x, WR-bk'\n",
and_out, or_in, or_in2));
}
if (*exec)
{
for (index = 0; index < size32; index++)
{
or_in2 = *((uint8*)(&(rom[*adress])));
*adress += 1;
data2 = *((uint8*)(&(rom[*adress])));
*adress += 1;
NV_REG32(reg2) = data2;
data = NV_REG32(reg);
data &= and_out;
data |= or_in;
data |= or_in2;
NV_REG32(reg) = data;
}
}
else
{
*adress += (size32 << 1);
}
break;
case 0x61:
*size -= 4;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
byte = *((uint8*)(&(rom[*adress])));
*adress += 1;
LOG(8,("cmd 'WR ISA reg $%04x = $%02x'\n", reg, byte));
if (*exec)
{
translate_ISA_PCI(®);
NV_REG8(reg) = byte;
}
break;
case 0x62:
*size -= 5;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
index = *((uint8*)(&(rom[*adress])));
*adress += 1;
byte = *((uint8*)(&(rom[*adress])));
*adress += 1;
LOG(8,("cmd 'WR idx ISA reg $%02x via $%04x = $%02x'\n", index, reg, byte));
if (*exec)
{
translate_ISA_PCI(®);
NV_REG16(reg) = ((((uint16)byte) << 8) | index);
}
break;
case 0x63:
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
LOG(8,("cmd 'setup RAM config' (always done)\n"));
switch (si->ps.card_type)
{
case NV28:
setup_ram_config_nv28(rom);
break;
default:
setup_ram_config_nv10_up(rom);
break;
}
break;
case 0x65:
*size -= 13;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
data = *((uint32*)(&(rom[*adress])));
*adress += 4;
data2 = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'WR 32bit reg $%08x = $%08x, then = $%08x' (always done)\n",
reg, data, data2));
NV_REG32(reg) = data;
NV_REG32(reg) = data2;
CFGW(ROMSHADOW, (CFGR(ROMSHADOW) & 0xfffffffe));
break;
case 0x69:
*size -= 5;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
and_out = *((uint8*)(&(rom[*adress])));
*adress += 1;
or_in = *((uint8*)(&(rom[*adress])));
*adress += 1;
LOG(8,("cmd 'RD 8bit ISA reg $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n",
reg, and_out, or_in));
if (*exec)
{
translate_ISA_PCI(®);
byte = NV_REG8(reg);
byte &= (uint8)and_out;
byte |= (uint8)or_in;
NV_REG8(reg) = byte;
}
break;
case 0x6a:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
data = *((uint8*)(&(rom[*adress])));
*adress += 1;
data2 = *((uint16*)(&(rom[(tabs.InitScriptTablePtr + (data << 1))])));
LOG(8,("cmd 'jump to script #$%02x at adress $%04x'\n", data, data2));
if (*exec)
{
*adress = data2;
LOG(8,("INFO: ---Jumping; not touching 'execution' mode.\n"));
}
break;
case 0x6b:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
data = *((uint8*)(&(rom[*adress])));
*adress += 1;
data2 = *((uint16*)(&(rom[(tabs.InitScriptTablePtr + (data << 1))])));
LOG(8,("cmd 'gosub script #$%02x at adress $%04x'\n", data, data2));
if (*exec && data2)
{
result = exec_type2_script(rom, data2, size, tabs, ram_tab);
LOG(8,("INFO: ---Reverting to pre-gosub 'execution' mode.\n"));
}
break;
case 0x6e:
*size -= 13;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
and_out = *((uint32*)(&(rom[*adress])));
*adress += 4;
or_in = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, OR-in = $%08x, WR-bk'\n",
reg, and_out, or_in));
if (*exec)
{
data = NV_REG32(reg);
data &= and_out;
data |= or_in;
NV_REG32(reg) = data;
}
break;
case 0x6f:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
byte = *((uint8*)(&(rom[*adress])));
*adress += 1;
data = tabs.MacroIndexTablePtr + (byte << 1);
offset32 = (*((uint8*)(&(rom[data]))) << 3);
size32 = *((uint8*)(&(rom[(data + 1)])));
offset32 += tabs.MacroTablePtr;
LOG(8,("cmd 'do $%02x time(s) a 32bit reg WR with 32bit data' (MacroIndexTable idx = $%02x):\n",
size32, byte));
safe32 = 0;
while (safe32 < size32)
{
reg2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3))])));
data2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3) + 4)])));
LOG(8,("INFO: (cont.) (#$%02x) cmd 'WR 32bit reg' $%08x = $%08x\n",
safe32, reg2, data2));
safe32++;
}
if (*exec)
{
safe32 = 0;
while (safe32 < size32)
{
reg2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3))])));
data2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3) + 4)])));
NV_REG32(reg2) = data2;
safe32++;
}
}
break;
case 0x36:
case 0x66:
case 0x67:
case 0x68:
case 0x6c:
case 0x71:
LOG(8,("cmd 'END', execution completed.\n\n"));
end = true;
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
*adress += 1;
break;
case 0x72:
*size -= 1;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
*adress += 1;
LOG(8,("cmd 'PGM commands'\n"));
LOG(8,("INFO: ---Executing following command(s):\n"));
*exec = true;
break;
case 0x74:
*size -= 3;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
data = *((uint16*)(&(rom[*adress])));
*adress += 2;
LOG(8,("cmd 'SNOOZE for %d ($%04x) microSeconds' (always done)\n", data, data));
snooze(data);
break;
case 0x75:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
*adress += 1;
data = *((uint8*)(&(rom[*adress])));
*adress += 1;
data *= 12;
data += tabs.ConditionTablePtr;
reg = *((uint32*)(&(rom[data])));
and_out = *((uint32*)(&(rom[(data + 4)])));
data2 = *((uint32*)(&(rom[(data + 8)])));
data = NV_REG32(reg);
data &= and_out;
LOG(8,("cmd 'CHK bits AND-out $%08x reg $%08x for $%08x'\n",
and_out, reg, data2));
if (data != data2)
{
LOG(8,("INFO: ---No match: not executing following command(s):\n"));
*exec = false;
}
else
{
LOG(8,("INFO: ---Match, so this cmd has no effect.\n"));
}
break;
case 0x76:
*size -= 2;
if (*size < 0)
{
LOG(8,("script size error!\n\n"));
result = B_ERROR;
}
*adress += 1;
data = *((uint8*)(&(rom[*adress])));
*adress += 1;
data *= 5;
data += tabs.IOConditionTablePtr;
reg = *((uint16*)(&(rom[data])));
index = *((uint8*)(&(rom[(data + 2)])));
and_out = *((uint8*)(&(rom[(data + 3)])));
byte2 = *((uint8*)(&(rom[(data + 4)])));
LOG(8,("cmd 'CHK bits AND-out $%02x idx ISA reg $%02x via $%04x for $%02x'\n",
and_out, index, reg, byte2));
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
if (byte != byte2)
{
LOG(8,("INFO: ---No match: not executing following command(s):\n"));
*exec = false;
}
else
{
LOG(8,("INFO: ---Match, so this cmd has no effect.\n"));
}
break;
case 0x78:
*size -= 6;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint16*)(&(rom[*adress])));
*adress += 2;
index = *((uint8*)(&(rom[*adress])));
*adress += 1;
and_out = *((uint8*)(&(rom[*adress])));
*adress += 1;
or_in = *((uint8*)(&(rom[*adress])));
*adress += 1;
LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n",
index, reg, and_out, or_in));
if (*exec)
{
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
byte |= (uint8)or_in;
NV_REG8(reg + 1) = byte;
}
break;
case 0x79:
*size -= 7;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
data = *((uint16*)(&(rom[*adress])));
*adress += 2;
LOG(8,("cmd 'calculate and set PLL 32bit reg $%08x for %.3fMHz'\n", reg, (data / 100.0)));
if (*exec)
{
float calced_clk;
uint8 m, n, p;
nv_dac_sys_pll_find((data / 100.0), &calced_clk, &m, &n, &p, 0);
data2 = NV_REG32(reg);
NV_REG32(reg) = ((data2 & 0xffff0000) | (n << 8) | m);
data2 = NV_REG32(reg);
NV_REG32(reg) = ((p << 16) | (n << 8) | m);
}
log_pll(reg, (data / 100));
break;
case 0x7a:
*size -= 9;
if (*size < 0)
{
LOG(8,("script size error, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
*adress += 1;
reg = *((uint32*)(&(rom[*adress])));
*adress += 4;
data = *((uint32*)(&(rom[*adress])));
*adress += 4;
LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x\n", reg, data));
if (*exec) NV_REG32(reg) = data;
break;
default:
LOG(8,("unknown cmd, aborting!\n\n"));
end = true;
result = B_ERROR;
break;
}
}
return result;
}
static void exec_cmd_39_type2(uint8* rom, uint32 data, PinsTables tabs, bool* exec)
{
uint8 index, byte, byte2, safe, shift;
uint32 reg, and_out, and_out2, offset32;
data *= 9;
data += tabs.IOFlagConditionTablePtr;
reg = *((uint16*)(&(rom[data])));
index = *((uint8*)(&(rom[(data + 2)])));
and_out = *((uint8*)(&(rom[(data + 3)])));
shift = *((uint8*)(&(rom[(data + 4)])));
offset32 = *((uint16*)(&(rom[data + 5])));
and_out2 = *((uint8*)(&(rom[(data + 7)])));
byte2 = *((uint8*)(&(rom[(data + 8)])));
LOG(8,("cmd 'AND-out bits $%02x idx ISA reg $%02x via $%04x, shift-right = $%02x,\n",
and_out, index, reg, shift));
translate_ISA_PCI(®);
NV_REG8(reg) = index;
byte = NV_REG8(reg + 1);
byte &= (uint8)and_out;
offset32 += (byte >> shift);
safe = byte = *((uint8*)(&(rom[offset32])));
byte &= (uint8)and_out2;
LOG(8,("INFO: (cont.) use result as index in table to get data $%02x,\n",
safe));
LOG(8,("INFO: (cont.) then chk bits AND-out $%02x of data for $%02x'\n",
and_out2, byte2));
if (byte != byte2)
{
LOG(8,("INFO: ---No match: not executing following command(s):\n"));
*exec = false;
}
else
{
LOG(8,("INFO: ---Match, so this cmd has no effect.\n"));
}
}
static void setup_ram_config_nv10_up(uint8* rom)
{
* After writing data to RAM a snooze is required to make the test work.
* Confirmed a NV11: without snooze it worked OK on a low-voltage AGP2.0 slot,
* but on a higher-voltage AGP 1.0 slot it failed to identify errors correctly!!
* Adding the snooze fixed that. */
uint32 data, dummy;
uint8 cnt = 0;
status_t stat = B_ERROR;
NV_REG32(NV32_PFB_REFCTRL) = 0x80000000;
while ((cnt < 4) && (stat != B_OK))
{
((volatile uint32 *)si->framebuffer)[0x07] = 0x00000000;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x07] = 0x00000000;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x07] = 0x00000000;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x07] = 0x00000000;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x07] = 0x4e563131;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x0f] = 0x00000000;
snooze(10);
if (((volatile uint32 *)si->framebuffer)[0x07] == 0x4e563131) stat = B_OK;
cnt++;
}
if (stat != B_OK)
{
LOG(8,("INFO: ---RAM test #1 done: access errors, modified setup.\n"));
data = NV_REG32(NV32_PFB_CONFIG_0);
if (data & 0x00000010)
{
data &= 0xffffffcf;
}
else
{
data &= 0xffffffcf;
data |= 0x00000020;
}
NV_REG32(NV32_PFB_CONFIG_0) = data;
}
else
{
LOG(8,("INFO: ---RAM test #1 done: access is OK.\n"));
}
cnt = 0;
stat = B_ERROR;
while ((cnt < 4) && (stat != B_OK))
{
data = NV_REG32(NV32_NV10STRAPINFO);
data -= 0x00100000;
((volatile uint32 *)si->framebuffer)[(data >> 2)] = 0x4e564441;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x00] = 0x00000000;
snooze(10);
dummy = ((volatile uint32 *)si->framebuffer)[0x00];
dummy = ((volatile uint32 *)si->framebuffer)[0x00];
dummy = ((volatile uint32 *)si->framebuffer)[0x00];
dummy = ((volatile uint32 *)si->framebuffer)[0x00];
if (((volatile uint32 *)si->framebuffer)[(data >> 2)] == 0x4e564441) stat = B_OK;
cnt++;
}
if (stat != B_OK)
{
LOG(8,("INFO: ---RAM test #2 done: access errors, modified setup.\n"));
NV_REG32(NV32_PFB_CONFIG_0) &= 0xffffefff;
}
else
{
LOG(8,("INFO: ---RAM test #2 done: access is OK.\n"));
}
}
* It doesn't matter if the card actually _has_ this amount of RAM or not(!) */
static void setup_ram_config_nv28(uint8* rom)
{
* After writing data to RAM a snooze is required to make the test work.
* Confirmed a NV11: without snooze it worked OK on a low-voltage AGP2.0 slot,
* but on a higher-voltage AGP 1.0 slot it failed to identify errors correctly!!
* Adding the snooze fixed that. */
uint32 dummy;
uint8 cnt = 0;
status_t stat = B_ERROR;
NV_REG32(NV32_PFB_REFCTRL) = 0x80000000;
while ((cnt < 4) && (stat != B_OK))
{
NV_REG32(NV32_PFB_CONFIG_0) |= 0x00000800;
((volatile uint32 *)si->framebuffer)[0x01fc0000] = 0x4e564441;
snooze(10);
((volatile uint32 *)si->framebuffer)[0x00000000] = 0x00000000;
snooze(10);
dummy = ((volatile uint32 *)si->framebuffer)[0x00000000];
LOG(8,("INFO: (#%d) dummy1 = $%08x, ", cnt, dummy));
dummy = ((volatile uint32 *)si->framebuffer)[0x00000000];
LOG(8,("dummy2 = $%08x, ", dummy));
dummy = ((volatile uint32 *)si->framebuffer)[0x00000000];
LOG(8,("dummy3 = $%08x, ", dummy));
dummy = ((volatile uint32 *)si->framebuffer)[0x00000000];
LOG(8,("dummy4 = $%08x\n", dummy));
if (((volatile uint32 *)si->framebuffer)[0x01fc0000] == 0x4e564441) stat = B_OK;
cnt++;
}
NV_REG32(NV32_PFB_CONFIG_0) &= ~0x00000800;
if (stat == B_OK)
LOG(8,("INFO: ---RAM test done: access was OK within %d iteration(s).\n", cnt));
else
LOG(8,("INFO: ---RAM test done: access was still not OK after 4 iterations.\n"));
}
static status_t translate_ISA_PCI(uint32* reg)
{
switch (*reg)
{
case 0x03c0:
*reg = NV8_ATTRDATW;
break;
case 0x03c1:
*reg = NV8_ATTRDATR;
break;
case 0x03c2:
*reg = NV8_MISCW;
break;
case 0x03c4:
*reg = NV8_SEQIND;
break;
case 0x03c5:
*reg = NV8_SEQDAT;
break;
case 0x03c6:
*reg = NV8_PALMASK;
break;
case 0x03c7:
*reg = NV8_PALINDR;
break;
case 0x03c8:
*reg = NV8_PALINDW;
break;
case 0x03c9:
*reg = NV8_PALDATA;
break;
case 0x03cc:
*reg = NV8_MISCR;
break;
case 0x03ce:
*reg = NV8_GRPHIND;
break;
case 0x03cf:
*reg = NV8_GRPHDAT;
break;
case 0x03d4:
*reg = NV8_CRTCIND;
break;
case 0x03d5:
*reg = NV8_CRTCDAT;
break;
case 0x03da:
*reg = NV8_INSTAT1;
break;
default:
LOG(8,("\n\nINFO: WARNING: ISA->PCI register adress translation failed!\n\n"));
return B_ERROR;
break;
}
return B_OK;
}
void set_pll(uint32 reg, uint32 req_clk)
{
uint32 data;
float calced_clk;
uint8 m, n, p;
nv_dac_sys_pll_find(req_clk, &calced_clk, &m, &n, &p, 0);
data = NV_REG32(reg);
NV_REG32(reg) = ((data & 0xffff0000) | (n << 8) | m);
data = NV_REG32(reg);
NV_REG32(reg) = ((p << 16) | (n << 8) | m);
if (si->ps.ext_pll)
{
if (reg == NV32_COREPLL) NV_REG32(NV32_COREPLL2) = 0x80000401;
if (reg == NV32_MEMPLL) NV_REG32(NV32_MEMPLL2) = 0x80000401;
}
log_pll(reg, req_clk);
}
static status_t nv_crtc_setup_fifo()
{
set_crtc_owner(0);
CRTCW(FIFO, 0x03);
CRTCW(FIFO_LWM, 0x20);
return B_OK;
}
void set_specs(void)
{
LOG(8,("INFO: setting up card specifications\n"));
switch (si->ps.card_type)
{
case NV04:
pinsnv4_fake();
break;
case NV05:
case NV05M64:
pinsnv5_nv5m64_fake();
break;
case NV06:
pinsnv6_fake();
break;
default:
switch (si->ps.card_arch)
{
case NV10A:
pinsnv10_arch_fake();
break;
case NV20A:
pinsnv20_arch_fake();
break;
case NV30A:
case NV40A:
pinsnv30_arch_fake();
break;
default:
pinsnv10_arch_fake();
break;
}
break;
}
switch (si->ps.card_arch)
{
case NV04A:
getstrap_arch_nv4();
break;
default:
getstrap_arch_nv10_20_30_40();
break;
}
}
void fake_panel_start(void)
{
LOG(8,("INFO: detecting RAM size\n"));
switch (si->ps.card_arch)
{
case NV04A:
getRAMsize_arch_nv4();
break;
default:
getRAMsize_arch_nv10_20_30_40();
break;
}
if (si->settings.memory != 0)
{
LOG(2,("INFO: forcing memory size (specified in settings file)\n"));
si->ps.memory_size = si->settings.memory * 1024 * 1024;
}
si->ps.tvout = false;
si->ps.tv_encoder.type = NONE;
si->ps.tv_encoder.version = 0;
i2c_init();
BT_probe();
LOG(8,("INFO: faking panel startup\n"));
detect_panels();
setup_output_matrix();
if (si->ps.secondary_head && si->settings.switchhead)
{
LOG(2,("INFO: inverting head use (specified in nvidia.settings file)\n"));
si->ps.crtc2_prim = !si->ps.crtc2_prim;
}
}
* - Since laptops don't have edid for their internal panels, and we can't switch
* digitally connected external panels to DAC's, we keep needing the info fetched
* from card programming done by the cardBIOS.
* - Because we can only output modes on digitally connected panels upto/including
* the modeline programmed into the GPU by the cardBIOS we don't use the actual
* native modelines fetched via EDID for digitally connected panels.
* - If the BIOS didn't program a modeline in the GPU for a digitally connected panel
* we can't use that panel.
* - The above restrictions exist due to missing nVidia hardware specs. */
static void detect_panels()
{
* (can) use the CRTC's in slaved mode. */
* DFP's are programmed with standard VESA modelines by the card's BIOS! */
bool slaved_for_dev1 = false, slaved_for_dev2 = false;
bool tvout1 = false, tvout2 = false;
set_crtc_owner(0);
CRTCW(LOCK, 0x57);
CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
LOG(2,("INFO: Dumping flatpanel related CRTC registers:\n"));
* b7: 1 = slaved mode (all cards). */
LOG(2,("CRTC1: PIXEL register: $%02x\n", CRTCR(PIXEL)));
* b7: 1 = stereo view (shutter glasses use) (all cards),
* b5: 1 = power ext. TMDS (or something)/0 = TVout use (?) (confirmed NV17, NV28),
* b4: 1 = power ext. TMDS (or something)/0 = TVout use (?) (confirmed NV34),
* b3: 1 = ??? (not panel related probably!) (confirmed NV34),
* b1: 1 = power ext. TMDS (or something) (?) (confirmed NV05?, NV17),
* b0: 1 = select panel encoder / 0 = select TVout encoder (all cards). */
LOG(2,("CRTC1: LCD register: $%02x\n", CRTCR(LCD)));
* b0: 1 = enable ext. TMDS clock (DPMS) (confirmed NV28, NV34). */
LOG(2,("CRTC1: register $59: $%02x\n", CRTCR(0x59)));
* b4: 0 = TVout use (?). */
LOG(2,("CRTC1: register $9f: $%02x\n", CRTCR(0x9f)));
slaved_for_dev1 = (CRTCR(PIXEL) & 0x80);
if (slaved_for_dev1)
{
tvout1 = !(CRTCR(LCD) & 0x01);
}
if (si->ps.secondary_head)
{
set_crtc_owner(1);
CRTC2W(LOCK, 0x57);
CRTC2W(VSYNCE ,(CRTC2R(VSYNCE) & 0x7f));
LOG(2,("CRTC2: PIXEL register: $%02x\n", CRTC2R(PIXEL)));
LOG(2,("CRTC2: LCD register: $%02x\n", CRTC2R(LCD)));
LOG(2,("CRTC2: register $59: $%02x\n", CRTC2R(0x59)));
LOG(2,("CRTC2: register $9f: $%02x\n", CRTC2R(0x9f)));
slaved_for_dev2 = (CRTC2R(PIXEL) & 0x80);
if (slaved_for_dev2)
{
tvout2 = !(CRTC2R(LCD) & 0x01);
}
}
LOG(2,("INFO: End flatpanel related CRTC registers dump.\n"));
si->ps.p1_timing.h_display = 0;
si->ps.p1_timing.v_display = 0;
si->ps.p2_timing.h_display = 0;
si->ps.p2_timing.v_display = 0;
si->ps.slaved_tmds1 = false;
si->ps.slaved_tmds2 = false;
si->ps.master_tmds1 = false;
si->ps.master_tmds2 = false;
si->ps.monitors = 0x00;
* relying on the cards BIOS to do it. This adds TVout options where panels
* are used!
* Currently we'd loose the panel setup while not being able to restore it. */
* -> NV11 and NV17 laptops have LVDS panels, programmed in both sets registers;
* -> NV34 laptops have TMDS panels, programmed in only one set of registers;
* -> NV11, NV25 and NV34 DVI cards, so external panels (TMDS) are programmed
* in only one set of registers;
* -> a register-set's FP_TG_CTRL register, bit 31 tells you if a LVDS panel is
* connected to the primary head (0), or to the secondary head (1) except
* on some NV11's if this bit is '0' there;
* -> for LVDS panels both registersets are programmed identically by the card's
* BIOSes;
* -> the programmed set of registers tells you where a TMDS (DVI) panel is
* connected;
* -> On all cards a CRTC is used in slaved mode when a panel is connected,
* except on NV11: here master mode is (might be?) detected. */
* external TMDS encoders are only used for logic-level translation: it's
* modeline registers are not used. Instead the GPU's internal modeline registers
* are used. The external encoder is not connected to a I2C bus (confirmed NV34). */
if (slaved_for_dev1 && !tvout1)
{
uint16 width = ((DACR(FP_HDISPEND) & 0x0000ffff) + 1);
uint16 height = ((DACR(FP_VDISPEND) & 0x0000ffff) + 1);
if ((width >= 640) && (height >= 480))
{
si->ps.slaved_tmds1 = true;
si->ps.monitors |= CRTC1_TMDS;
si->ps.p1_timing.h_display = width;
si->ps.p1_timing.v_display = height;
}
}
if (si->ps.secondary_head && slaved_for_dev2 && !tvout2)
{
uint16 width = ((DAC2R(FP_HDISPEND) & 0x0000ffff) + 1);
uint16 height = ((DAC2R(FP_VDISPEND) & 0x0000ffff) + 1);
if ((width >= 640) && (height >= 480))
{
si->ps.slaved_tmds2 = true;
si->ps.monitors |= CRTC2_TMDS;
si->ps.p2_timing.h_display = width;
si->ps.p2_timing.v_display = height;
}
}
if ((si->ps.card_type == NV11) &&
!si->ps.slaved_tmds1 && !tvout1)
{
uint16 width = ((DACR(FP_HDISPEND) & 0x0000ffff) + 1);
uint16 height = ((DACR(FP_VDISPEND) & 0x0000ffff) + 1);
if ((width >= 640) && (height >= 480))
{
si->ps.master_tmds1 = true;
si->ps.monitors |= CRTC1_TMDS;
si->ps.p1_timing.h_display = width;
si->ps.p1_timing.v_display = height;
}
}
if ((si->ps.card_type == NV11) &&
si->ps.secondary_head && !si->ps.slaved_tmds2 && !tvout2)
{
uint16 width = ((DAC2R(FP_HDISPEND) & 0x0000ffff) + 1);
uint16 height = ((DAC2R(FP_VDISPEND) & 0x0000ffff) + 1);
if ((width >= 640) && (height >= 480))
{
si->ps.master_tmds2 = true;
si->ps.monitors |= CRTC2_TMDS;
si->ps.p2_timing.h_display = width;
si->ps.p2_timing.v_display = height;
}
}
if (si->ps.laptop &&
((si->ps.monitors & (CRTC1_TMDS | CRTC2_TMDS)) == (CRTC1_TMDS | CRTC2_TMDS)) &&
((DACR(FP_TG_CTRL) & 0x80000000) == (DAC2R(FP_TG_CTRL) & 0x80000000)) &&
(si->ps.p1_timing.h_display == si->ps.p2_timing.h_display) &&
(si->ps.p1_timing.v_display == si->ps.p2_timing.v_display))
{
LOG(2,("INFO: correcting double detection of single panel!\n"));
if (si->ps.card_type == NV11)
{
si->ps.slaved_tmds1 = false;
si->ps.master_tmds1 = false;
si->ps.monitors &= ~CRTC1_TMDS;
si->ps.p1_timing.h_display = 0;
si->ps.p1_timing.v_display = 0;
}
else
{
if (DACR(FP_TG_CTRL) & 0x80000000)
{
si->ps.slaved_tmds1 = false;
si->ps.master_tmds1 = false;
si->ps.monitors &= ~CRTC1_TMDS;
si->ps.p1_timing.h_display = 0;
si->ps.p1_timing.v_display = 0;
}
else
{
si->ps.slaved_tmds2 = false;
si->ps.master_tmds2 = false;
si->ps.monitors &= ~CRTC2_TMDS;
si->ps.p2_timing.h_display = 0;
si->ps.p2_timing.v_display = 0;
}
}
}
if (si->ps.monitors & CRTC1_TMDS)
{
si->ps.p1_timing.h_sync_start = (DACR(FP_HSYNC_S) & 0x0000ffff) + 1;
si->ps.p1_timing.h_sync_end = (DACR(FP_HSYNC_E) & 0x0000ffff) + 1;
si->ps.p1_timing.h_total = (DACR(FP_HTOTAL) & 0x0000ffff) + 1;
si->ps.p1_timing.v_sync_start = (DACR(FP_VSYNC_S) & 0x0000ffff) + 1;
si->ps.p1_timing.v_sync_end = (DACR(FP_VSYNC_E) & 0x0000ffff) + 1;
si->ps.p1_timing.v_total = (DACR(FP_VTOTAL) & 0x0000ffff) + 1;
si->ps.p1_timing.flags = 0;
if (DACR(FP_TG_CTRL) & 0x00000001) si->ps.p1_timing.flags |= B_POSITIVE_VSYNC;
if (DACR(FP_TG_CTRL) & 0x00000010) si->ps.p1_timing.flags |= B_POSITIVE_HSYNC;
if (DACR(FP_TG_CTRL) & 0x10000000) si->ps.p1_timing.flags |= B_BLANK_PEDESTAL;
* fix a DVI or laptop flatpanel to 60Hz refresh! */
si->ps.p1_timing.pixel_clock =
(si->ps.p1_timing.h_total * si->ps.p1_timing.v_total * 60) / 1000;
}
if (si->ps.monitors & CRTC2_TMDS)
{
si->ps.p2_timing.h_sync_start = (DAC2R(FP_HSYNC_S) & 0x0000ffff) + 1;
si->ps.p2_timing.h_sync_end = (DAC2R(FP_HSYNC_E) & 0x0000ffff) + 1;
si->ps.p2_timing.h_total = (DAC2R(FP_HTOTAL) & 0x0000ffff) + 1;
si->ps.p2_timing.v_sync_start = (DAC2R(FP_VSYNC_S) & 0x0000ffff) + 1;
si->ps.p2_timing.v_sync_end = (DAC2R(FP_VSYNC_E) & 0x0000ffff) + 1;
si->ps.p2_timing.v_total = (DAC2R(FP_VTOTAL) & 0x0000ffff) + 1;
si->ps.p2_timing.flags = 0;
if (DAC2R(FP_TG_CTRL) & 0x00000001) si->ps.p2_timing.flags |= B_POSITIVE_VSYNC;
if (DAC2R(FP_TG_CTRL) & 0x00000010) si->ps.p2_timing.flags |= B_POSITIVE_HSYNC;
if (DAC2R(FP_TG_CTRL) & 0x10000000) si->ps.p2_timing.flags |= B_BLANK_PEDESTAL;
* fix a DVI or laptop flatpanel to 60Hz refresh! */
si->ps.p2_timing.pixel_clock =
(si->ps.p2_timing.h_total * si->ps.p2_timing.v_total * 60) / 1000;
}
LOG(2,("INFO: Dumping flatpanel registers:\n"));
LOG(2,("DUALHEAD_CTRL: $%08x\n", NV_REG32(NV32_DUALHEAD_CTRL)));
LOG(2,("DAC1: FP_HDISPEND: %d\n", DACR(FP_HDISPEND)));
LOG(2,("DAC1: FP_HTOTAL: %d\n", DACR(FP_HTOTAL)));
LOG(2,("DAC1: FP_HCRTC: %d\n", DACR(FP_HCRTC)));
LOG(2,("DAC1: FP_HSYNC_S: %d\n", DACR(FP_HSYNC_S)));
LOG(2,("DAC1: FP_HSYNC_E: %d\n", DACR(FP_HSYNC_E)));
LOG(2,("DAC1: FP_HVALID_S: %d\n", DACR(FP_HVALID_S)));
LOG(2,("DAC1: FP_HVALID_E: %d\n", DACR(FP_HVALID_E)));
LOG(2,("DAC1: FP_VDISPEND: %d\n", DACR(FP_VDISPEND)));
LOG(2,("DAC1: FP_VTOTAL: %d\n", DACR(FP_VTOTAL)));
LOG(2,("DAC1: FP_VCRTC: %d\n", DACR(FP_VCRTC)));
LOG(2,("DAC1: FP_VSYNC_S: %d\n", DACR(FP_VSYNC_S)));
LOG(2,("DAC1: FP_VSYNC_E: %d\n", DACR(FP_VSYNC_E)));
LOG(2,("DAC1: FP_VVALID_S: %d\n", DACR(FP_VVALID_S)));
LOG(2,("DAC1: FP_VVALID_E: %d\n", DACR(FP_VVALID_E)));
LOG(2,("DAC1: FP_CHKSUM: $%08x = (dec) %d\n", DACR(FP_CHKSUM),DACR(FP_CHKSUM)));
LOG(2,("DAC1: FP_TST_CTRL: $%08x\n", DACR(FP_TST_CTRL)));
LOG(2,("DAC1: FP_TG_CTRL: $%08x\n", DACR(FP_TG_CTRL)));
LOG(2,("DAC1: FP_DEBUG0: $%08x\n", DACR(FP_DEBUG0)));
LOG(2,("DAC1: FP_DEBUG1: $%08x\n", DACR(FP_DEBUG1)));
LOG(2,("DAC1: FP_DEBUG2: $%08x\n", DACR(FP_DEBUG2)));
LOG(2,("DAC1: FP_DEBUG3: $%08x\n", DACR(FP_DEBUG3)));
LOG(2,("DAC1: FUNCSEL: $%08x\n", NV_REG32(NV32_FUNCSEL)));
LOG(2,("DAC1: PANEL_PWR: $%08x\n", NV_REG32(NV32_PANEL_PWR)));
if(si->ps.secondary_head)
{
LOG(2,("DAC2: FP_HDISPEND: %d\n", DAC2R(FP_HDISPEND)));
LOG(2,("DAC2: FP_HTOTAL: %d\n", DAC2R(FP_HTOTAL)));
LOG(2,("DAC2: FP_HCRTC: %d\n", DAC2R(FP_HCRTC)));
LOG(2,("DAC2: FP_HSYNC_S: %d\n", DAC2R(FP_HSYNC_S)));
LOG(2,("DAC2: FP_HSYNC_E: %d\n", DAC2R(FP_HSYNC_E)));
LOG(2,("DAC2: FP_HVALID_S:%d\n", DAC2R(FP_HVALID_S)));
LOG(2,("DAC2: FP_HVALID_E: %d\n", DAC2R(FP_HVALID_E)));
LOG(2,("DAC2: FP_VDISPEND: %d\n", DAC2R(FP_VDISPEND)));
LOG(2,("DAC2: FP_VTOTAL: %d\n", DAC2R(FP_VTOTAL)));
LOG(2,("DAC2: FP_VCRTC: %d\n", DAC2R(FP_VCRTC)));
LOG(2,("DAC2: FP_VSYNC_S: %d\n", DAC2R(FP_VSYNC_S)));
LOG(2,("DAC2: FP_VSYNC_E: %d\n", DAC2R(FP_VSYNC_E)));
LOG(2,("DAC2: FP_VVALID_S: %d\n", DAC2R(FP_VVALID_S)));
LOG(2,("DAC2: FP_VVALID_E: %d\n", DAC2R(FP_VVALID_E)));
LOG(2,("DAC2: FP_CHKSUM: $%08x = (dec) %d\n", DAC2R(FP_CHKSUM),DAC2R(FP_CHKSUM)));
LOG(2,("DAC2: FP_TST_CTRL: $%08x\n", DAC2R(FP_TST_CTRL)));
LOG(2,("DAC2: FP_TG_CTRL: $%08x\n", DAC2R(FP_TG_CTRL)));
LOG(2,("DAC2: FP_DEBUG0: $%08x\n", DAC2R(FP_DEBUG0)));
LOG(2,("DAC2: FP_DEBUG1: $%08x\n", DAC2R(FP_DEBUG1)));
LOG(2,("DAC2: FP_DEBUG2: $%08x\n", DAC2R(FP_DEBUG2)));
LOG(2,("DAC2: FP_DEBUG3: $%08x\n", DAC2R(FP_DEBUG3)));
LOG(2,("DAC2: FUNCSEL: $%08x\n", NV_REG32(NV32_2FUNCSEL)));
LOG(2,("DAC2: PANEL_PWR: $%08x\n", NV_REG32(NV32_2PANEL_PWR)));
}
* result in a hanging system. Without reading them at least a blind (or KDL)
* restart becomes possible. Leaving the code here for debugging purposes. */
if (0) {
* - on NV11 accessing registerset(s) hangs card.
* - the same applies for NV34.
* Confirmed for DAC2 access on ID 0x0322,
* but only after a failed VESA modeswitch by the HAIKU kernel
* at boot time caused by a BIOS fault inside the gfx card: it says
* it can do VESA 1280x1024x32 on CRTC1/DAC1 but it fails: no signal. */
if ((si->ps.monitors & CRTC1_TMDS) && (si->ps.card_type != NV11))
{
* b0-7 = adress, b16 = 1 = write_enable */
DACW(FP_TMDS_CTRL, ((1 << 16) | 0x04));
if (DACR(FP_TMDS_DATA) & 0x01)
LOG(2,("INFO: Flatpanel on head 1 is LVDS type\n"));
else
LOG(2,("INFO: Flatpanel on head 1 is TMDS type\n"));
}
if ((si->ps.monitors & CRTC2_TMDS) && (si->ps.card_type != NV11))
{
* b0-7 = adress, b16 = 1 = write_enable */
DAC2W(FP_TMDS_CTRL, ((1 << 16) | 0x04));
if (DAC2R(FP_TMDS_DATA) & 0x01)
LOG(2,("INFO: Flatpanel on head 2 is LVDS type\n"));
else
LOG(2,("INFO: Flatpanel on head 2 is TMDS type\n"));
}
}
LOG(2,("INFO: End flatpanel registers dump.\n"));
}
static void setup_output_matrix()
{
si->ps.crtc2_prim = false;
si->ps.crtc1_screen.have_native_edid = false;
si->ps.crtc1_screen.have_full_edid = false;
si->ps.crtc1_screen.timing.h_display = 0;
si->ps.crtc1_screen.timing.v_display = 0;
si->ps.crtc2_screen.have_native_edid = false;
si->ps.crtc2_screen.have_full_edid = false;
si->ps.crtc2_screen.timing.h_display = 0;
si->ps.crtc2_screen.timing.v_display = 0;
if ((si->ps.secondary_head) && (si->ps.card_type != NV11))
nv_general_output_select(false);
* we can't change this (lack of info) */
if (si->ps.con1_screen.have_native_edid) {
if (!si->ps.con1_screen.digital) si->ps.monitors |= CRTC1_VGA;
} else {
if (nv_dac_crt_connected()) {
si->ps.monitors |= CRTC1_VGA;
si->ps.con1_screen.aspect = 1.33;
}
}
* to crtc1.
* Also the BIOS might have programmed for a lower mode than EDID reports:
* which limits our use of the panel (LVDS link setup too slow). */
if(si->ps.monitors & CRTC1_TMDS) {
* we need to compare: we don't know the location of a digital cross switch.
* Note: don't compare pixelclock and flags as we make them up ourselves!) */
if (si->ps.con1_screen.have_full_edid && si->ps.con1_screen.digital &&
(si->ps.p1_timing.h_display == si->ps.con1_screen.timing.h_display) &&
(si->ps.p1_timing.h_sync_start == si->ps.con1_screen.timing.h_sync_start) &&
(si->ps.p1_timing.h_sync_end == si->ps.con1_screen.timing.h_sync_end) &&
(si->ps.p1_timing.h_total == si->ps.con1_screen.timing.h_total) &&
(si->ps.p1_timing.v_display == si->ps.con1_screen.timing.v_display) &&
(si->ps.p1_timing.v_sync_start == si->ps.con1_screen.timing.v_sync_start) &&
(si->ps.p1_timing.v_sync_end == si->ps.con1_screen.timing.v_sync_end) &&
(si->ps.p1_timing.v_total == si->ps.con1_screen.timing.v_total)) {
memcpy(&(si->ps.crtc1_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc1_screen));
} else {
if (si->ps.con2_screen.have_full_edid && si->ps.con2_screen.digital &&
(si->ps.p1_timing.h_display == si->ps.con2_screen.timing.h_display) &&
(si->ps.p1_timing.h_sync_start == si->ps.con2_screen.timing.h_sync_start) &&
(si->ps.p1_timing.h_sync_end == si->ps.con2_screen.timing.h_sync_end) &&
(si->ps.p1_timing.h_total == si->ps.con2_screen.timing.h_total) &&
(si->ps.p1_timing.v_display == si->ps.con2_screen.timing.v_display) &&
(si->ps.p1_timing.v_sync_start == si->ps.con2_screen.timing.v_sync_start) &&
(si->ps.p1_timing.v_sync_end == si->ps.con2_screen.timing.v_sync_end) &&
(si->ps.p1_timing.v_total == si->ps.con2_screen.timing.v_total)) {
memcpy(&(si->ps.crtc1_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc1_screen));
} else {
si->ps.crtc1_screen.timing.pixel_clock = si->ps.p1_timing.pixel_clock;
si->ps.crtc1_screen.timing.h_display = si->ps.p1_timing.h_display;
si->ps.crtc1_screen.timing.h_sync_start = si->ps.p1_timing.h_sync_start;
si->ps.crtc1_screen.timing.h_sync_end = si->ps.p1_timing.h_sync_end;
si->ps.crtc1_screen.timing.h_total = si->ps.p1_timing.h_total;
si->ps.crtc1_screen.timing.v_display = si->ps.p1_timing.v_display;
si->ps.crtc1_screen.timing.v_sync_start = si->ps.p1_timing.v_sync_start;
si->ps.crtc1_screen.timing.v_sync_end = si->ps.p1_timing.v_sync_end;
si->ps.crtc1_screen.timing.v_total = si->ps.p1_timing.v_total;
si->ps.crtc1_screen.timing.flags = si->ps.p1_timing.flags;
si->ps.crtc1_screen.have_native_edid = true;
si->ps.crtc1_screen.aspect =
(si->ps.p1_timing.h_display / ((float)si->ps.p1_timing.v_display));
si->ps.crtc1_screen.digital = true;
}
}
} else if(si->ps.monitors & CRTC1_VGA) {
memcpy(&(si->ps.crtc1_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc1_screen));
}
if (si->settings.force_ws) si->ps.crtc1_screen.aspect = 1.78;
if (si->ps.secondary_head)
{
* connects to crtc2.
* Also the BIOS might have programmed for a lower mode than EDID reports:
* which limits our use of the panel (LVDS link setup too slow). */
if(si->ps.monitors & CRTC2_TMDS) {
* we need to compare: we don't know the location of a digital cross switch.
* Note: don't compare pixelclock and flags as we make them up ourselves!) */
if (si->ps.con1_screen.have_full_edid && si->ps.con1_screen.digital &&
(si->ps.p2_timing.h_display == si->ps.con1_screen.timing.h_display) &&
(si->ps.p2_timing.h_sync_start == si->ps.con1_screen.timing.h_sync_start) &&
(si->ps.p2_timing.h_sync_end == si->ps.con1_screen.timing.h_sync_end) &&
(si->ps.p2_timing.h_total == si->ps.con1_screen.timing.h_total) &&
(si->ps.p2_timing.v_display == si->ps.con1_screen.timing.v_display) &&
(si->ps.p2_timing.v_sync_start == si->ps.con1_screen.timing.v_sync_start) &&
(si->ps.p2_timing.v_sync_end == si->ps.con1_screen.timing.v_sync_end) &&
(si->ps.p2_timing.v_total == si->ps.con1_screen.timing.v_total)) {
memcpy(&(si->ps.crtc2_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc2_screen));
} else {
if (si->ps.con2_screen.have_full_edid && si->ps.con2_screen.digital &&
(si->ps.p2_timing.h_display == si->ps.con2_screen.timing.h_display) &&
(si->ps.p2_timing.h_sync_start == si->ps.con2_screen.timing.h_sync_start) &&
(si->ps.p2_timing.h_sync_end == si->ps.con2_screen.timing.h_sync_end) &&
(si->ps.p2_timing.h_total == si->ps.con2_screen.timing.h_total) &&
(si->ps.p2_timing.v_display == si->ps.con2_screen.timing.v_display) &&
(si->ps.p2_timing.v_sync_start == si->ps.con2_screen.timing.v_sync_start) &&
(si->ps.p2_timing.v_sync_end == si->ps.con2_screen.timing.v_sync_end) &&
(si->ps.p2_timing.v_total == si->ps.con2_screen.timing.v_total)) {
memcpy(&(si->ps.crtc2_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc2_screen));
} else {
si->ps.crtc2_screen.timing.pixel_clock = si->ps.p2_timing.pixel_clock;
si->ps.crtc2_screen.timing.h_display = si->ps.p2_timing.h_display;
si->ps.crtc2_screen.timing.h_sync_start = si->ps.p2_timing.h_sync_start;
si->ps.crtc2_screen.timing.h_sync_end = si->ps.p2_timing.h_sync_end;
si->ps.crtc2_screen.timing.h_total = si->ps.p2_timing.h_total;
si->ps.crtc2_screen.timing.v_display = si->ps.p2_timing.v_display;
si->ps.crtc2_screen.timing.v_sync_start = si->ps.p2_timing.v_sync_start;
si->ps.crtc2_screen.timing.v_sync_end = si->ps.p2_timing.v_sync_end;
si->ps.crtc2_screen.timing.v_total = si->ps.p2_timing.v_total;
si->ps.crtc2_screen.timing.flags = si->ps.p2_timing.flags;
si->ps.crtc2_screen.have_native_edid = true;
si->ps.crtc2_screen.aspect =
(si->ps.p2_timing.h_display / ((float)si->ps.p2_timing.v_display));
si->ps.crtc2_screen.digital = true;
}
}
}
if (si->ps.card_type != NV11)
{
* we can't change this (lack of info) */
if (si->ps.con2_screen.have_native_edid) {
if (!si->ps.con2_screen.digital) si->ps.monitors |= CRTC2_VGA;
} else {
if (nv_dac2_crt_connected()) {
si->ps.monitors |= CRTC2_VGA;
si->ps.con2_screen.aspect = 1.33;
}
}
if ((si->ps.monitors & (CRTC2_TMDS | CRTC2_VGA)) == CRTC2_VGA) {
memcpy(&(si->ps.crtc2_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc2_screen));
}
if (si->settings.force_ws) si->ps.crtc2_screen.aspect = 1.78;
switch (si->ps.monitors)
{
case 0x00:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x01:
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x02:
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x03:
LOG(2,("INFO: head 1 has a digital panel AND an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: correcting...\n"));
nv_general_output_select(true);
si->ps.monitors = 0x21;
memcpy(&(si->ps.crtc2_screen), &(si->ps.con1_screen), sizeof(si->ps.crtc2_screen));
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x10:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
case 0x20:
if (si->ps.card_arch < NV40A) {
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
} else {
switch (si->ps.card_type) {
case NV40:
case NV41:
case NV45:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
case NV44:
* It's hardware behaves as a NV40/41/45 but there's some unknown extra bit
* which needs to be programmed now to get CRTC2/DAC2 displaying anything
* else than blackness (with monitor ON @ correct refresh and resolution).
* We are therefore forced to use CRTC1/DAC1 instead (as these are presetup
* fully by the card's BIOS at POST in this situation). */
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: cross-switching outputs for NV44!\n"));
nv_general_output_select(true);
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
default:
* to connect a CRTC/DAC combination to a connector. The BIOSes of
* these cards connect head1 to connectors 1 and 2 simultaneously if
* only one VGA screen is found being on connector 2. Which is the
* case here.
* Confirmed on NV43, G71 and G73. */
LOG(2,("INFO: Both card outputs are connected to head 1;\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
}
}
break;
case 0x30:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has a digital panel AND an analog panel or CRT:\n"));
LOG(2,("INFO: correcting...\n"));
nv_general_output_select(true);
si->ps.monitors = 0x12;
memcpy(&(si->ps.crtc1_screen), &(si->ps.con2_screen), sizeof(si->ps.crtc1_screen));
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
case 0x11:
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x12:
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
case 0x21:
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x22:
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has an analog panel or CRT:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x32:
LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors));
* head 1 has not. */
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
default:
LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
}
}
else
{
LOG(2,("INFO: NV11 outputs are hardwired to be straight-through\n"));
if (si->settings.force_ws) si->ps.crtc2_screen.aspect = 1.78;
switch (si->ps.monitors)
{
case 0x00:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x01:
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x02:
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x03:
LOG(2,("INFO: head 1 has a digital panel AND an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has nothing connected:\n"));
LOG(2,("INFO: correction not possible...\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x10:
LOG(2,("INFO: head 1 has nothing connected;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
case 0x11:
LOG(2,("INFO: head 1 has a digital panel;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
case 0x12:
LOG(2,("INFO: head 1 has an analog panel or CRT;\n"));
LOG(2,("INFO: head 2 has a digital panel:\n"));
LOG(2,("INFO: defaulting to head 2 for primary use.\n"));
si->ps.crtc2_prim = true;
break;
default:
LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors));
LOG(2,("INFO: defaulting to head 1 for primary use.\n"));
break;
}
}
}
else
{
}
}
status_t get_crtc1_screen_native_mode(display_mode *mode)
{
if (!si->ps.crtc1_screen.have_native_edid) return B_ERROR;
mode->space = B_RGB32_LITTLE;
mode->virtual_width = si->ps.crtc1_screen.timing.h_display;
mode->virtual_height = si->ps.crtc1_screen.timing.v_display;
mode->h_display_start = 0;
mode->v_display_start = 0;
mode->flags = 0;
memcpy(&mode->timing, &si->ps.crtc1_screen.timing, sizeof(mode->timing));
return B_OK;
}
status_t get_crtc2_screen_native_mode(display_mode *mode)
{
if (!si->ps.crtc2_screen.have_native_edid) return B_ERROR;
mode->space = B_RGB32_LITTLE;
mode->virtual_width = si->ps.crtc2_screen.timing.h_display;
mode->virtual_height = si->ps.crtc2_screen.timing.v_display;
mode->h_display_start = 0;
mode->v_display_start = 0;
mode->flags = 0;
memcpy(&mode->timing, &si->ps.crtc2_screen.timing, sizeof(mode->timing));
return B_OK;
}
static void pinsnv4_fake(void)
{
si->ps.ext_pll = false;
si->ps.max_system_vco = 256;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 256;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 250;
si->ps.max_dac1_clock_8 = 250;
si->ps.max_dac1_clock_16 = 250;
si->ps.max_dac1_clock_24 = 220;
si->ps.max_dac1_clock_32 = 180;
si->ps.max_dac1_clock_32dh = 180;
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
si->ps.max_dac2_clock_32dh = 0;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 90;
si->ps.std_memory_clock = 110;
}
static void pinsnv5_nv5m64_fake(void)
{
si->ps.ext_pll = false;
si->ps.max_system_vco = 300;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 300;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 300;
si->ps.max_dac1_clock_8 = 300;
si->ps.max_dac1_clock_16 = 300;
si->ps.max_dac1_clock_24 = 270;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 230;
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
si->ps.max_dac2_clock_32dh = 0;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 125;
si->ps.std_memory_clock = 150;
}
static void pinsnv6_fake(void)
{
si->ps.ext_pll = false;
si->ps.max_system_vco = 300;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 300;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 300;
si->ps.max_dac1_clock_8 = 300;
si->ps.max_dac1_clock_16 = 300;
si->ps.max_dac1_clock_24 = 270;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 230;
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
si->ps.max_dac2_clock_32dh = 0;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 100;
si->ps.std_memory_clock = 125;
}
static void pinsnv10_arch_fake(void)
{
si->ps.ext_pll = false;
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
if (si->ps.card_type < NV17)
{
* it uses an external secondary DAC probably with limited capability. */
si->ps.max_dac2_clock = 200;
si->ps.max_dac2_clock_8 = 200;
si->ps.max_dac2_clock_16 = 200;
si->ps.max_dac2_clock_24 = 200;
si->ps.max_dac2_clock_32 = 200;
si->ps.max_dac2_clock_32dh = 180;
}
else
{
si->ps.max_dac2_clock = 350;
si->ps.max_dac2_clock_8 = 350;
si->ps.max_dac2_clock_16 = 350;
si->ps.max_dac2_clock_24 = 320;
si->ps.max_dac2_clock_32 = 280;
si->ps.max_dac2_clock_32dh = 250;
}
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 120;
si->ps.std_memory_clock = 150;
}
static void pinsnv20_arch_fake(void)
{
si->ps.ext_pll = false;
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
si->ps.max_dac2_clock = 350;
si->ps.max_dac2_clock_8 = 350;
si->ps.max_dac2_clock_16 = 350;
si->ps.max_dac2_clock_24 = 320;
si->ps.max_dac2_clock_32 = 280;
si->ps.max_dac2_clock_32dh = 250;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 175;
si->ps.std_memory_clock = 200;
}
on NV34, GeForce FX 5200, id 0x0322 DAC1 PLL observed behaviour:
- Fcomp may be as high as 27Mhz (BIOS), and current set range seems ok as well;
- Fvco may not be as low as 216Mhz (DVI pixelclock intermittant locking error,
visible as horizontal shifting picture and black screen (out of range): both intermittant);
- Fvco may be as high as 432Mhz (BIOS);
- This is not an extended PLL: the second divisor register does not do anything.
*/
static void pinsnv30_arch_fake(void)
{
if ((si->ps.card_type == NV31) ||
(si->ps.card_type == NV36) ||
(si->ps.card_type >= NV40))
{
si->ps.ext_pll = true;
}
else
{
si->ps.ext_pll = false;
}
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
if (si->ps.ext_pll)
{
si->ps.max_pixel_vco = 600;
si->ps.min_pixel_vco = 220;
si->ps.max_video_vco = 600;
si->ps.min_video_vco = 220;
}
else
{
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
}
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
si->ps.max_dac2_clock = 350;
si->ps.max_dac2_clock_8 = 350;
si->ps.max_dac2_clock_16 = 350;
si->ps.max_dac2_clock_24 = 320;
si->ps.max_dac2_clock_32 = 280;
si->ps.max_dac2_clock_32dh = 250;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.std_engine_clock = 190;
si->ps.std_memory_clock = 190;
if ((CFGR(DEVID) & 0xfff0ffff) == 0x024010de) {
si->ps.max_system_vco = 1000;
si->ps.min_system_vco = 500;
si->ps.max_pixel_vco = 1000;
si->ps.min_pixel_vco = 500;
si->ps.max_video_vco = 1000;
si->ps.min_video_vco = 500;
}
}
static void getRAMsize_arch_nv4(void)
{
uint32 strapinfo = NV_REG32(NV32_NV4STRAPINFO);
if (strapinfo & 0x00000100)
{
si->ps.memory_size = 1024 * 1024 *
((((strapinfo & 0x0000f000) >> 12) * 2) + 2);
LOG(8,("INFO: NV4 architecture chip with UMA detected\n"));
}
else
{
switch (strapinfo & 0x00000003)
{
case 0:
si->ps.memory_size = 32 * 1024 * 1024;
break;
case 1:
si->ps.memory_size = 4 * 1024 * 1024;
break;
case 2:
si->ps.memory_size = 8 * 1024 * 1024;
break;
case 3:
si->ps.memory_size = 16 * 1024 * 1024;
break;
}
}
}
static void getstrap_arch_nv4(void)
{
uint32 strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
if (strapinfo & 0x00000040)
si->ps.f_ref = 14.31818;
else
si->ps.f_ref = 13.50000;
si->ps.secondary_head = false;
}
static void getRAMsize_arch_nv10_20_30_40(void)
{
uint32 dev_manID = CFGR(DEVID);
uint32 strapinfo = NV_REG32(NV32_NV10STRAPINFO);
uint32 mem_size;
switch (dev_manID)
{
case 0x01a010de:
case 0x01f010de:
* their disposal (UMA, values read from PCI config space in other device) */
LOG(8,("INFO: nVidia GPU with UMA detected\n"));
break;
default:
LOG(8,("INFO: kerneldriver mapped %3.3fMb framebuffer memory\n",
(si->ps.memory_size / (1024.0 * 1024.0))));
LOG(8,("INFO: (Memory detection) Strapinfo value is: $%08x\n", strapinfo));
mem_size = (strapinfo & 0x3ff00000);
if (!mem_size) {
mem_size = 16 * 1024 * 1024;
LOG(8,("INFO: NV10/20/30 architecture chip with unknown RAM amount detected;\n"));
LOG(8,("INFO: Setting 16Mb\n"));
}
if (si->ps.memory_size > mem_size) si->ps.memory_size = mem_size;
}
}
static void getstrap_arch_nv10_20_30_40(void)
{
uint32 dev_manID = CFGR(DEVID);
uint32 strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
si->ps.secondary_head = false;
switch (si->ps.card_type)
{
case NV04:
case NV05:
case NV05M64:
case NV06:
case NV10:
case NV15:
case NV20:
break;
default:
if ((dev_manID & 0xfff0ffff) == 0x01a010de)
{
}
else
{
si->ps.secondary_head = true;
}
}
if ((si->ps.secondary_head) && (si->ps.card_type != NV11))
strapinfo &= 0x00400040;
else
strapinfo &= 0x00000040;
switch (strapinfo) {
case 0x00000000:
si->ps.f_ref = 13.50000;
break;
case 0x00000040:
si->ps.f_ref = 14.31818;
break;
case 0x00400000:
si->ps.f_ref = 27.00000;
break;
case 0x00400040:
si->ps.f_ref = 25.00000;
break;
}
}
void dump_pins(void)
{
char *msg = "";
LOG(2,("INFO: pinsdump follows:\n"));
LOG(2,("PLL type: %s\n", si->ps.ext_pll ? "extended" : "standard"));
LOG(2,("f_ref: %fMhz\n", si->ps.f_ref));
LOG(2,("max_system_vco: %dMhz\n", si->ps.max_system_vco));
LOG(2,("min_system_vco: %dMhz\n", si->ps.min_system_vco));
LOG(2,("max_pixel_vco: %dMhz\n", si->ps.max_pixel_vco));
LOG(2,("min_pixel_vco: %dMhz\n", si->ps.min_pixel_vco));
LOG(2,("max_video_vco: %dMhz\n", si->ps.max_video_vco));
LOG(2,("min_video_vco: %dMhz\n", si->ps.min_video_vco));
LOG(2,("std_engine_clock: %dMhz\n", si->ps.std_engine_clock));
LOG(2,("std_memory_clock: %dMhz\n", si->ps.std_memory_clock));
LOG(2,("max_dac1_clock: %dMhz\n", si->ps.max_dac1_clock));
LOG(2,("max_dac1_clock_8: %dMhz\n", si->ps.max_dac1_clock_8));
LOG(2,("max_dac1_clock_16: %dMhz\n", si->ps.max_dac1_clock_16));
LOG(2,("max_dac1_clock_24: %dMhz\n", si->ps.max_dac1_clock_24));
LOG(2,("max_dac1_clock_32: %dMhz\n", si->ps.max_dac1_clock_32));
LOG(2,("max_dac1_clock_32dh: %dMhz\n", si->ps.max_dac1_clock_32dh));
LOG(2,("max_dac2_clock: %dMhz\n", si->ps.max_dac2_clock));
LOG(2,("max_dac2_clock_8: %dMhz\n", si->ps.max_dac2_clock_8));
LOG(2,("max_dac2_clock_16: %dMhz\n", si->ps.max_dac2_clock_16));
LOG(2,("max_dac2_clock_24: %dMhz\n", si->ps.max_dac2_clock_24));
LOG(2,("max_dac2_clock_32: %dMhz\n", si->ps.max_dac2_clock_32));
LOG(2,("max_dac2_clock_32dh: %dMhz\n", si->ps.max_dac2_clock_32dh));
LOG(2,("secondary_head: %s\n", si->ps.secondary_head ? "present" : "absent"));
LOG(2,("tvout: %s\n", si->ps.tvout ? "present" : "absent"));
switch (si->ps.tv_encoder.type)
{
case NONE:
msg = "No";
break;
case CH7003:
msg = "Chrontel CH7003";
break;
case CH7004:
msg = "Chrontel CH7004";
break;
case CH7005:
msg = "Chrontel CH7005";
break;
case CH7006:
msg = "Chrontel CH7006";
break;
case CH7007:
msg = "Chrontel CH7007";
break;
case CH7008:
msg = "Chrontel CH7008";
break;
case SAA7102:
msg = "Philips SAA7102";
break;
case SAA7103:
msg = "Philips SAA7103";
break;
case SAA7104:
msg = "Philips SAA7104";
break;
case SAA7105:
msg = "Philips SAA7105";
break;
case BT868:
msg = "Brooktree/Conexant BT868";
break;
case BT869:
msg = "Brooktree/Conexant BT869";
break;
case CX25870:
msg = "Conexant CX25870";
break;
case CX25871:
msg = "Conexant CX25871";
break;
case NVIDIA:
msg = "Nvidia internal";
break;
default:
msg = "Unknown";
break;
}
LOG(2, ("%s TV encoder detected; silicon revision is $%02x\n",
msg, si->ps.tv_encoder.version));
LOG(2,("card memory_size: %3.3fMb\n", (si->ps.memory_size / (1024.0 * 1024.0))));
LOG(2,("laptop: "));
if (si->ps.laptop) LOG(2,("yes\n")); else LOG(2,("no\n"));
if (si->ps.monitors & CRTC1_TMDS)
{
LOG(2,("found DFP (digital flatpanel) on CRTC1; CRTC1 is %s\n",
si->ps.slaved_tmds1 ? "slaved" : "master"));
LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n",
si->ps.p1_timing.h_display, si->ps.p1_timing.v_display, si->ps.crtc1_screen.aspect));
}
if (si->ps.monitors & CRTC2_TMDS)
{
LOG(2,("found DFP (digital flatpanel) on CRTC2; CRTC2 is %s\n",
si->ps.slaved_tmds2 ? "slaved" : "master"));
LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n",
si->ps.p2_timing.h_display, si->ps.p2_timing.v_display, si->ps.crtc2_screen.aspect));
}
LOG(2,("monitor (output devices) setup matrix: $%02x\n", si->ps.monitors));
LOG(2,("INFO: end pinsdump.\n"));
}