/* Read initialisation information from card */ /* some bits are hacks, where PINS is not known */ /* Author: Rudolf Cornelissen 7/2003-5/2006 */ #define MODULE_BIT 0x00002000 #include "std.h" static void detect_panels(void); static void setup_output_matrix(void); static void pins_cle266_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(void); static void getstrap_arch_nv4(void); static void getstrap_arch_nv10_20_30_40(void); static status_t eng_crtc_setup_fifo(void); /* Parse the BIOS PINS structure if there */ status_t parse_pins () { uint8 *rom; status_t result = B_ERROR; /* preset PINS read status to failed */ si->ps.pins_status = B_ERROR; /* check the validity of PINS */ LOG(2,("INFO: Reading PINS info\n")); rom = (uint8 *) si->rom_mirror; /* check BIOS signature - this is defined in the PCI standard */ 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")); /* find the PINS struct adress */ //fixme... /* check PINS read result */ if (result == B_ERROR) { LOG(8,("INFO: PINS read/decode/execute error\n")); return B_ERROR; } /* PINS scan succeeded */ si->ps.pins_status = B_OK; LOG(2,("INFO: PINS scan completed succesfully\n")); return B_OK; } //fixme: move to crtc sourcefile, also setup for crtc2(?) static status_t eng_crtc_setup_fifo() { /* enable access to primary head */ set_crtc_owner(0); //fixme: setup according to colordepth and RAM bus width... /* set CRTC FIFO burst size to 256 */ CRTCW(FIFO, 0x03); /* set CRTC FIFO low watermark to 32 */ CRTCW(FIFO_LWM, 0x20); return B_OK; } /* (pre)set 'fixed' card specifications */ void set_specs(void) { LOG(8,("INFO: setting up card specifications\n")); /* set failsave speeds */ switch (si->ps.card_arch) { case CLE266: default: pins_cle266_fake(); break; } /* detect reference crystal frequency and dualhead */ /* switch (si->ps.card_arch) { case NV04A: getstrap_arch_nv4(); break; default: getstrap_arch_nv10_20_30_40(); break; } */ } /* this routine presumes the card was coldstarted by the card's BIOS for panel stuff */ void fake_panel_start(void) { LOG(8,("INFO: detecting RAM size\n")); /* detect RAM amount */ getRAMsize(); /* override memory detection if requested by user */ 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; } /* find out if the card has a tvout chip */ si->ps.tvout = false; si->ps.tvout_chip_type = NONE; //fixme ;-) /* if (i2c_maven_probe() == B_OK) { si->ps.tvout = true; si->ps.tvout_chip_bus = ???; si->ps.tvout_chip_type = ???; } */ LOG(8,("INFO: faking panel startup\n")); /* find out the BIOS preprogrammed panel use status... */ // detect_panels(); /* determine and setup output devices and heads */ setup_output_matrix(); /* select other CRTC for primary head use if specified by user in settings file */ if (si->ps.secondary_head && si->settings.switchhead) { LOG(2,("INFO: inverting head use (specified in settings file)\n")); si->ps.crtc2_prim = !si->ps.crtc2_prim; } } static void detect_panels() { /* detect if the BIOS enabled LCD's (internal panels or DVI) or TVout */ /* both external TMDS transmitters (used for LCD/DVI) and external TVencoders * (can) use the CRTC's in slaved mode. */ /* Note: * 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; /* check primary head: */ /* enable access to primary head */ set_crtc_owner(0); /* unlock head's registers for R/W access */ CRTCW(LOCK, 0x57); CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); LOG(2,("INFO: Dumping flatpanel related CRTC registers:\n")); /* related info PIXEL register: * b7: 1 = slaved mode (all cards). */ LOG(2,("CRTC1: PIXEL register: $%02x\n", CRTCR(PIXEL))); /* info LCD register: * 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))); /* info 0x59 register: * b0: 1 = enable ext. TMDS clock (DPMS) (confirmed NV28, NV34). */ LOG(2,("CRTC1: register $59: $%02x\n", CRTCR(0x59))); /* info 0x9f register: * b4: 0 = TVout use (?). */ LOG(2,("CRTC1: register $9f: $%02x\n", CRTCR(0x9f))); /* detect active slave device (if any) */ slaved_for_dev1 = (CRTCR(PIXEL) & 0x80); if (slaved_for_dev1) { /* if the panel isn't selected, tvout is.. */ tvout1 = !(CRTCR(LCD) & 0x01); } if (si->ps.secondary_head) { /* check secondary head: */ /* enable access to secondary head */ set_crtc_owner(1); /* unlock head's registers for R/W access */ 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))); /* detect active slave device (if any) */ slaved_for_dev2 = (CRTC2R(PIXEL) & 0x80); if (slaved_for_dev2) { /* if the panel isn't selected, tvout is.. */ tvout2 = !(CRTC2R(LCD) & 0x01); } } LOG(2,("INFO: End flatpanel related CRTC registers dump.\n")); /* do some presets */ si->ps.p1_timing.h_display = 0; si->ps.p1_timing.v_display = 0; si->ps.panel1_aspect = 0; si->ps.p2_timing.h_display = 0; si->ps.p2_timing.v_display = 0; si->ps.panel2_aspect = 0; si->ps.slaved_tmds1 = false; si->ps.slaved_tmds2 = false; si->ps.master_tmds1 = false; si->ps.master_tmds2 = false; si->ps.tmds1_active = false; si->ps.tmds2_active = false; /* determine the situation we are in... (regarding flatpanels) */ /* fixme: add VESA DDC EDID stuff one day... */ /* fixme: find out how to program those transmitters one day instead of * 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. */ /* note: (facts) * -> 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. */ /* note also: * 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.tmds1_active = true; 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.tmds2_active = true; 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.tmds1_active = true; 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.tmds2_active = true; si->ps.p2_timing.h_display = width; si->ps.p2_timing.v_display = height; } } //fixme...: //we are assuming that no DVI is used as external monitor on laptops; //otherwise we probably get into trouble here if the checked specs match. if (si->ps.laptop && si->ps.tmds1_active && si->ps.tmds2_active && ((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) { /* LVDS panel is _always_ on CRTC2, so clear false primary detection */ si->ps.slaved_tmds1 = false; si->ps.master_tmds1 = false; si->ps.tmds1_active = false; si->ps.p1_timing.h_display = 0; si->ps.p1_timing.v_display = 0; } else { if (DACR(FP_TG_CTRL) & 0x80000000) { /* LVDS panel is on CRTC2, so clear false primary detection */ si->ps.slaved_tmds1 = false; si->ps.master_tmds1 = false; si->ps.tmds1_active = false; si->ps.p1_timing.h_display = 0; si->ps.p1_timing.v_display = 0; } else { /* LVDS panel is on CRTC1, so clear false secondary detection */ si->ps.slaved_tmds2 = false; si->ps.master_tmds2 = false; si->ps.tmds2_active = false; si->ps.p2_timing.h_display = 0; si->ps.p2_timing.v_display = 0; } } } /* fetch panel(s) modeline(s) */ if (si->ps.tmds1_active) { /* determine panel aspect ratio */ si->ps.panel1_aspect = (si->ps.p1_timing.h_display / ((float)si->ps.p1_timing.v_display)); /* horizontal timing */ 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; /* vertical timing */ 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; /* sync polarity */ 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; /* refreshrate: * 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.tmds2_active) { /* determine panel aspect ratio */ si->ps.panel2_aspect = (si->ps.p2_timing.h_display / ((float)si->ps.p2_timing.v_display)); /* horizontal timing */ 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; /* vertical timing */ 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; /* sync polarity */ 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; /* refreshrate: * 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; } /* dump some panel configuration registers... */ LOG(2,("INFO: Dumping flatpanel registers:\n")); LOG(2,("DUALHEAD_CTRL: $%08x\n", ENG_REG32(RG32_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", ENG_REG32(RG32_FUNCSEL))); LOG(2,("DAC1: PANEL_PWR: $%08x\n", ENG_REG32(RG32_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", ENG_REG32(RG32_2FUNCSEL))); LOG(2,("DAC2: PANEL_PWR: $%08x\n", ENG_REG32(RG32_2PANEL_PWR))); } LOG(2,("INFO: End flatpanel registers dump.\n")); } static void setup_output_matrix() { /* setup defaults: */ /* no monitors (output devices) detected */ si->ps.monitors = 0x00; /* head 1 will be the primary head */ si->ps.crtc2_prim = false; /* setup output devices and heads */ if (0)//si->ps.secondary_head) { if (si->ps.card_type != NV11) { /* setup defaults: */ /* connect analog outputs straight through */ eng_general_output_select(false); /* presetup by the card's BIOS, we can't change this (lack of info) */ if (si->ps.tmds1_active) si->ps.monitors |= 0x01; if (si->ps.tmds2_active) si->ps.monitors |= 0x10; /* detect analog monitors (confirmed working OK on NV18, NV28 and NV34): */ /* sense analog monitor on primary connector */ if (eng_dac_crt_connected()) si->ps.monitors |= 0x02; /* sense analog monitor on secondary connector */ if (eng_dac2_crt_connected()) si->ps.monitors |= 0x20; /* setup correct output and head use */ //fixme? add TVout (only, so no CRT(s) connected) support... switch (si->ps.monitors) { case 0x00: /* no monitor found at all */ 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: /* digital panel on head 1, nothing on head 2 */ 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: /* analog panel or CRT on head 1, nothing on head 2 */ 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: /* both types on head 1, nothing on head 2 */ 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")); /* cross connect analog outputs so analog panel or CRT gets head 2 */ eng_general_output_select(true); 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: /* nothing on head 1, digital panel on head 2 */ 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: /* nothing on head 1, analog panel or CRT on head 2 */ 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 0x30: /* nothing on head 1, both types on head 2 */ 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")); /* cross connect analog outputs so analog panel or CRT gets head 1 */ eng_general_output_select(true); 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: /* digital panels on both heads */ 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: /* analog panel or CRT on head 1, digital panel on head 2 */ 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: /* digital panel on head 1, analog panel or CRT on head 2 */ 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: /* analog panel(s) or CRT(s) on both heads */ 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; default: /* more than two monitors connected to just two outputs: illegal! */ LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors)); LOG(2,("INFO: defaulting to head 1 for primary use.\n")); break; } } else /* dualhead NV11 cards */ { /* confirmed no analog output switch-options for NV11 */ LOG(2,("INFO: NV11 outputs are hardwired to be straight-through\n")); /* presetup by the card's BIOS, we can't change this (lack of info) */ if (si->ps.tmds1_active) si->ps.monitors |= 0x01; if (si->ps.tmds2_active) si->ps.monitors |= 0x10; /* detect analog monitor (confirmed working OK on NV11): */ /* sense analog monitor on primary connector */ if (eng_dac_crt_connected()) si->ps.monitors |= 0x02; /* (sense analog monitor on secondary connector is impossible on NV11) */ /* setup correct output and head use */ //fixme? add TVout (only, so no CRT(s) connected) support... switch (si->ps.monitors) { case 0x00: /* no monitor found at all */ 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: /* digital panel on head 1, nothing on head 2 */ 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: /* analog panel or CRT on head 1, nothing on head 2 */ 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: /* both types on head 1, nothing on head 2 */ 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: /* nothing on head 1, digital panel on head 2 */ 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: /* digital panels on both heads */ 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: /* analog panel or CRT on head 1, digital panel on head 2 */ 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: /* more than two monitors connected to just two outputs: illegal! */ LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors)); LOG(2,("INFO: defaulting to head 1 for primary use.\n")); break; } } } else /* singlehead cards */ { //temporary (VIA) si->ps.tmds1_active = false; si->ps.tmds2_active = false; /* presetup by the card's BIOS, we can't change this (lack of info) */ if (si->ps.tmds1_active) si->ps.monitors |= 0x01; /* detect analog monitor (confirmed working OK on all cards): */ /* sense analog monitor on primary connector */ //temporary (VIA) if (1/*eng_dac_crt_connected()*/) si->ps.monitors |= 0x02; //fixme? add TVout (only, so no CRT connected) support... } } void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2) { if (si->ps.tmds1_active) { /* timing ('modeline') */ p1->timing = si->ps.p1_timing; /* setup the rest */ p1->space = B_CMAP8; p1->virtual_width = p1->timing.h_display; p1->virtual_height = p1->timing.v_display; p1->h_display_start = 0; p1->v_display_start = 0; p1->flags = 0; *pan1 = true; } else *pan1 = false; if (si->ps.tmds2_active) { /* timing ('modeline') */ p2->timing = si->ps.p2_timing; /* setup the rest */ p2->space = B_CMAP8; p2->virtual_width = p2->timing.h_display; p2->virtual_height = p2->timing.v_display; p2->h_display_start = 0; p2->v_display_start = 0; p2->flags = 0; *pan2 = true; } else *pan2 = false; } static void pins_cle266_fake(void) { si->ps.f_ref = 14.31818; /* we have a standard PLL */ si->ps.ext_pll = false; /* carefull not to take to high limits, and high should be >= 2x low. */ si->ps.max_system_vco = 230; si->ps.min_system_vco = 20; si->ps.max_pixel_vco = 400; /* VESA BIOS uses upto 433Mhz */ si->ps.min_pixel_vco = 50; /* VESA BIOS uses downto 53.2Mhz */ si->ps.max_video_vco = 0; si->ps.min_video_vco = 0; si->ps.max_dac1_clock = 230; si->ps.max_dac1_clock_8 = 230; si->ps.max_dac1_clock_16 = 230; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 200; si->ps.max_dac1_clock_32 = 180; si->ps.max_dac1_clock_32dh = 180; /* secondary head */ 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; /* 'failsave' values */ si->ps.max_dac2_clock_32dh = 0; //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 90; si->ps.std_memory_clock = 110; } static void pinsnv5_nv5m64_fake(void) { /* we have a standard PLL */ si->ps.ext_pll = false; /* carefull not to take to high limits, and high should be >= 2x low. */ 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; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 270; si->ps.max_dac1_clock_32 = 230; si->ps.max_dac1_clock_32dh = 230; /* secondary head */ 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; /* 'failsave' values */ si->ps.max_dac2_clock_32dh = 0; //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 125; si->ps.std_memory_clock = 150; } static void pinsnv6_fake(void) { /* we have a standard PLL */ si->ps.ext_pll = false; /* carefull not to take to high limits, and high should be >= 2x low. */ 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; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 270; si->ps.max_dac1_clock_32 = 230; si->ps.max_dac1_clock_32dh = 230; /* secondary head */ 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; /* 'failsave' values */ si->ps.max_dac2_clock_32dh = 0; //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 100; si->ps.std_memory_clock = 125; } static void pinsnv10_arch_fake(void) { /* we have a standard PLL */ si->ps.ext_pll = false; /* carefull not to take to high limits, and high should be >= 2x low. */ 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; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 320; si->ps.max_dac1_clock_32 = 280; si->ps.max_dac1_clock_32dh = 250; /* secondary head */ if (si->ps.card_type < NV17) { /* if a GeForce2 has analog VGA dualhead capability, * it uses an external secondary DAC probably with limited capability. */ /* (called twinview technology) */ 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; /* 'failsave' values */ si->ps.max_dac2_clock_32dh = 180; } else { /* GeForce4 cards have dual integrated DACs with identical capaability */ /* (called nview technology) */ si->ps.max_dac2_clock = 350; si->ps.max_dac2_clock_8 = 350; si->ps.max_dac2_clock_16 = 350; /* 'failsave' values */ si->ps.max_dac2_clock_24 = 320; si->ps.max_dac2_clock_32 = 280; si->ps.max_dac2_clock_32dh = 250; } //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 120; si->ps.std_memory_clock = 150; } static void pinsnv20_arch_fake(void) { /* we have a standard PLL */ si->ps.ext_pll = false; /* carefull not to take to high limits, and high should be >= 2x low. */ 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; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 320; si->ps.max_dac1_clock_32 = 280; si->ps.max_dac1_clock_32dh = 250; /* secondary head */ /* GeForce4 cards have dual integrated DACs with identical capaability */ /* (called nview technology) */ si->ps.max_dac2_clock = 350; si->ps.max_dac2_clock_8 = 350; si->ps.max_dac2_clock_16 = 350; /* 'failsave' values */ si->ps.max_dac2_clock_24 = 320; si->ps.max_dac2_clock_32 = 280; si->ps.max_dac2_clock_32dh = 250; //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 175; si->ps.std_memory_clock = 200; } static void pinsnv30_arch_fake(void) { /* determine PLL type */ LOG(8,("INFO: NV30 architecture chip, PIXPLLC2 DAC1 = $%08x, DAC2 = $%08x\n", DACR(PIXPLLC2), DAC2R(PIXPLLC2))); switch (si->ps.card_type) { case NV31: case NV36: case NV40: /* we have a extended PLL */ si->ps.ext_pll = true; break; default: /* we have a standard PLL */ si->ps.ext_pll = false; break; } /* carefull not to take to high limits, and high should be >= 2x low. */ 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; /* 'failsave' values */ si->ps.max_dac1_clock_24 = 320; si->ps.max_dac1_clock_32 = 280; si->ps.max_dac1_clock_32dh = 250; /* secondary head */ /* GeForceFX cards have dual integrated DACs with identical capaability */ /* (called nview technology) */ si->ps.max_dac2_clock = 350; si->ps.max_dac2_clock_8 = 350; si->ps.max_dac2_clock_16 = 350; /* 'failsave' values */ si->ps.max_dac2_clock_24 = 320; si->ps.max_dac2_clock_32 = 280; si->ps.max_dac2_clock_32dh = 250; //fixme: primary & secondary_dvi should be overrule-able via skel.settings si->ps.primary_dvi = false; si->ps.secondary_dvi = false; /* not used (yet) because no coldstart will be attempted (yet) */ si->ps.std_engine_clock = 190; si->ps.std_memory_clock = 190; } static void getRAMsize(void) { uint8 ram_size = 0; if (si->ps.card_arch == CLE266) { ram_size = SEQR(MSIZE_CLE266); } else { ram_size = SEQR(MSIZE_OTHER); } if ((ram_size > 16) && (ram_size <= 128)) { /* 9.0 - 64.5Mb in 0.5Mb steps */ si->ps.memory_size = (ram_size + 1) * 512 * 1024; } else { if ((ram_size > 0) && (ram_size <= 16)) { /* 4 - 64Mb in 4Mb steps */ si->ps.memory_size = ram_size * 4 * 1024 * 1024; } else { LOG(8,("INFO: unable to detect RAMsize (read $%02x), assuming 16Mb\n")); si->ps.memory_size = 16 * 1024 * 1024; } } } static void getstrap_arch_nv4(void) { uint32 strapinfo = ENG_REG32(RG32_NVSTRAPINFO2); /* determine PLL reference crystal frequency */ if (strapinfo & 0x00000040) si->ps.f_ref = 14.31818; else si->ps.f_ref = 13.50000; /* these cards are always singlehead */ si->ps.secondary_head = false; } static void getstrap_arch_nv10_20_30_40(void) { uint32 dev_manID = CFGR(DEVID); uint32 strapinfo = ENG_REG32(RG32_NVSTRAPINFO2); /* determine PLL reference crystal frequency: three types are used... */ if (strapinfo & 0x00000040) si->ps.f_ref = 14.31818; else si->ps.f_ref = 13.50000; switch (dev_manID & 0xfff0ffff) { /* Nvidia cards: */ case 0x004010de: case 0x00c010de: case 0x00f010de: case 0x014010de: case 0x017010de: case 0x018010de: case 0x01f010de: case 0x025010de: case 0x028010de: case 0x030010de: case 0x031010de: case 0x032010de: case 0x033010de: case 0x034010de: /* Varisys cards: */ case 0x35001888: if (strapinfo & 0x00400000) si->ps.f_ref = 27.00000; break; default: break; } /* determine if we have a dualhead card */ switch (dev_manID & 0xfff0ffff) { /* Nvidia cards: */ case 0x004010de: case 0x00c010de: case 0x00f010de: case 0x011010de: case 0x014010de: case 0x017010de: case 0x018010de: case 0x01f010de: case 0x025010de: case 0x028010de: case 0x030010de: case 0x031010de: case 0x032010de: case 0x033010de: case 0x034010de: /* Varisys cards: */ case 0x35001888: si->ps.secondary_head = true; break; default: si->ps.secondary_head = false; break; } } void dump_pins(void) { char *msg = ""; LOG(2,("INFO: pinsdump follows:\n")); LOG(2,("PLL type: ")); if (si->ps.ext_pll) LOG(2,("extended\n")); else LOG(2,("standard\n")); 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: ")); if (si->ps.secondary_head) LOG(2,("present\n")); else LOG(2,("absent\n")); LOG(2,("tvout: ")); if (si->ps.tvout) LOG(2,("present\n")); else LOG(2,("absent\n")); /* setup TVout logmessage text */ switch (si->ps.tvout_chip_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 TVout chip detected\n", msg)); // LOG(2,("primary_dvi: ")); // if (si->ps.primary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n")); // LOG(2,("secondary_dvi: ")); // if (si->ps.secondary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n")); 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.tmds1_active) { LOG(2,("found DFP (digital flatpanel) on CRTC1; CRTC1 is ")); if (si->ps.slaved_tmds1) LOG(2,("slaved\n")); else LOG(2,("master\n")); 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.panel1_aspect)); } if (si->ps.tmds2_active) { LOG(2,("found DFP (digital flatpanel) on CRTC2; CRTC2 is ")); if (si->ps.slaved_tmds2) LOG(2,("slaved\n")); else LOG(2,("master\n")); 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.panel2_aspect)); } LOG(2,("monitor (output devices) setup matrix: $%02x\n", si->ps.monitors)); LOG(2,("INFO: end pinsdump.\n")); }