diff --git a/src/add-ons/accelerants/via/engine/general.c b/src/add-ons/accelerants/via/engine/general.c new file mode 100644 index 0000000000..bf597d3eef --- /dev/null +++ b/src/add-ons/accelerants/via/engine/general.c @@ -0,0 +1,858 @@ +/* Authors: + Mark Watson 12/1999, + Apsed, + Rudolf Cornelissen 10/2002-11/2004 +*/ + +#define MODULE_BIT 0x00008000 + +#include "std.h" + +static status_t test_ram(void); +static status_t engxx_general_powerup (void); +static status_t eng_general_bios_to_powergraphics(void); + +static void eng_dump_configuration_space (void) +{ +#define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \ + uint32 value = CFGR(reg); \ + MSG(("configuration_space 0x%02x %20s 0x%08x\n", \ + ENCFG_##reg, #reg, value)); \ +} while (0) + DUMP_CFG (DEVID, 0); + DUMP_CFG (DEVCTRL, 0); + DUMP_CFG (CLASS, 0); + DUMP_CFG (HEADER, 0); + DUMP_CFG (BASE1REGS,0); + DUMP_CFG (BASE2FB, 0); + DUMP_CFG (BASE3, 0); + DUMP_CFG (BASE4, 0); + DUMP_CFG (BASE5, 0); + DUMP_CFG (BASE6, 0); + DUMP_CFG (BASE7, 0); + DUMP_CFG (SUBSYSID1,0); + DUMP_CFG (ROMBASE, 0); + DUMP_CFG (CAPPTR, 0); + DUMP_CFG (CFG_1, 0); + DUMP_CFG (INTERRUPT,0); + DUMP_CFG (SUBSYSID2,0); + DUMP_CFG (AGPREF, 0); + DUMP_CFG (AGPSTAT, 0); + DUMP_CFG (AGPCMD, 0); + DUMP_CFG (ROMSHADOW,0); + DUMP_CFG (VGA, 0); + DUMP_CFG (SCHRATCH, 0); + DUMP_CFG (CFG_10, 0); + DUMP_CFG (CFG_11, 0); + DUMP_CFG (CFG_12, 0); + DUMP_CFG (CFG_13, 0); + DUMP_CFG (CFG_14, 0); + DUMP_CFG (CFG_15, 0); + DUMP_CFG (CFG_16, 0); + DUMP_CFG (CFG_17, 0); + DUMP_CFG (CFG_18, 0); + DUMP_CFG (CFG_19, 0); + DUMP_CFG (CFG_20, 0); + DUMP_CFG (CFG_21, 0); + DUMP_CFG (CFG_22, 0); + DUMP_CFG (CFG_23, 0); + DUMP_CFG (CFG_24, 0); + DUMP_CFG (CFG_25, 0); + DUMP_CFG (CFG_26, 0); + DUMP_CFG (CFG_27, 0); + DUMP_CFG (CFG_28, 0); + DUMP_CFG (CFG_29, 0); + DUMP_CFG (CFG_30, 0); + DUMP_CFG (CFG_31, 0); + DUMP_CFG (CFG_32, 0); + DUMP_CFG (CFG_33, 0); + DUMP_CFG (CFG_34, 0); + DUMP_CFG (CFG_35, 0); + DUMP_CFG (CFG_36, 0); + DUMP_CFG (CFG_37, 0); + DUMP_CFG (CFG_38, 0); + DUMP_CFG (CFG_39, 0); + DUMP_CFG (CFG_40, 0); + DUMP_CFG (CFG_41, 0); + DUMP_CFG (CFG_42, 0); + DUMP_CFG (CFG_43, 0); + DUMP_CFG (CFG_44, 0); + DUMP_CFG (CFG_45, 0); + DUMP_CFG (CFG_46, 0); + DUMP_CFG (CFG_47, 0); + DUMP_CFG (CFG_48, 0); + DUMP_CFG (CFG_49, 0); + DUMP_CFG (CFG_50, 0); +#undef DUMP_CFG +} + +status_t eng_general_powerup() +{ + status_t status; + + LOG(1,("POWERUP: Haiku skeleton Accelerant 0.01 running.\n")); + + /* preset no laptop */ + si->ps.laptop = false; + + /* detect card type and power it up */ + switch(CFGR(DEVID)) + { + /* Vendor Via */ + case 0x31221106: /* */ + si->ps.card_type = NV04; + si->ps.card_arch = NV04A; + LOG(4,("POWERUP: Detected Nvidia TNT1 (NV04)\n")); + status = engxx_general_powerup(); + break; + default: + LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID))); + return B_ERROR; + } + + return status; +} + +static status_t test_ram() +{ + uint32 value, offset; + status_t result = B_OK; + + /* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */ + if (si->fbc.frame_buffer == NULL) + { + LOG(8,("INIT: test_ram detected NULL pointer.\n")); + return B_ERROR; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* write testpattern to cardRAM */ + ((uint32 *)si->fbc.frame_buffer)[offset] = value; + /* toggle testpattern */ + value = 0xffffffff - value; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* readback and verify testpattern from cardRAM */ + if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR; + /* toggle testpattern */ + value = 0xffffffff - value; + } + return result; +} + +/* NOTE: + * This routine *has* to be done *after* SetDispplayMode has been executed, + * or test results will not be representative! + * (CAS latency is dependant on NV setup on some (DRAM) boards) */ +status_t eng_set_cas_latency() +{ + status_t result = B_ERROR; + uint8 latency = 0; + + /* check current RAM access to see if we need to change anything */ + if (test_ram() == B_OK) + { + LOG(4,("INIT: RAM access OK.\n")); + return B_OK; + } + + /* check if we read PINS at starttime so we have valid registersettings at our disposal */ + if (si->ps.pins_status != B_OK) + { + LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n")); + return B_ERROR; + } + + /* OK. We might have a problem, try to fix it now.. */ + LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n")); + + switch(si->ps.card_type) + { + default: + LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n")); + return B_OK; + break; + } + if (result == B_OK) + LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency)); + else + LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency)); + + return result; +} + +void setup_virtualized_heads(bool cross) +{ + if (cross) + { + head1_validate_timing = (crtc_validate_timing) eng_crtc2_validate_timing; + head1_set_timing = (crtc_set_timing) eng_crtc2_set_timing; + head1_depth = (crtc_depth) eng_crtc2_depth; + head1_dpms = (crtc_dpms) eng_crtc2_dpms; + head1_dpms_fetch = (crtc_dpms_fetch) eng_crtc2_dpms_fetch; + head1_set_display_pitch = (crtc_set_display_pitch) eng_crtc2_set_display_pitch; + head1_set_display_start = (crtc_set_display_start) eng_crtc2_set_display_start; + head1_cursor_init = (crtc_cursor_init) eng_crtc2_cursor_init; + head1_cursor_show = (crtc_cursor_show) eng_crtc2_cursor_show; + head1_cursor_hide = (crtc_cursor_hide) eng_crtc2_cursor_hide; + head1_cursor_define = (crtc_cursor_define) eng_crtc2_cursor_define; + head1_cursor_position = (crtc_cursor_position) eng_crtc2_cursor_position; + + head1_mode = (dac_mode) eng_dac2_mode; + head1_palette = (dac_palette) eng_dac2_palette; + head1_set_pix_pll = (dac_set_pix_pll) eng_dac2_set_pix_pll; + head1_pix_pll_find = (dac_pix_pll_find) eng_dac2_pix_pll_find; + + head2_validate_timing = (crtc_validate_timing) eng_crtc_validate_timing; + head2_set_timing = (crtc_set_timing) eng_crtc_set_timing; + head2_depth = (crtc_depth) eng_crtc_depth; + head2_dpms = (crtc_dpms) eng_crtc_dpms; + head2_dpms_fetch = (crtc_dpms_fetch) eng_crtc_dpms_fetch; + head2_set_display_pitch = (crtc_set_display_pitch) eng_crtc_set_display_pitch; + head2_set_display_start = (crtc_set_display_start) eng_crtc_set_display_start; + head2_cursor_init = (crtc_cursor_init) eng_crtc_cursor_init; + head2_cursor_show = (crtc_cursor_show) eng_crtc_cursor_show; + head2_cursor_hide = (crtc_cursor_hide) eng_crtc_cursor_hide; + head2_cursor_define = (crtc_cursor_define) eng_crtc_cursor_define; + head2_cursor_position = (crtc_cursor_position) eng_crtc_cursor_position; + + head2_mode = (dac_mode) eng_dac_mode; + head2_palette = (dac_palette) eng_dac_palette; + head2_set_pix_pll = (dac_set_pix_pll) eng_dac_set_pix_pll; + head2_pix_pll_find = (dac_pix_pll_find) eng_dac_pix_pll_find; + } + else + { + head1_validate_timing = (crtc_validate_timing) eng_crtc_validate_timing; + head1_set_timing = (crtc_set_timing) eng_crtc_set_timing; + head1_depth = (crtc_depth) eng_crtc_depth; + head1_dpms = (crtc_dpms) eng_crtc_dpms; + head1_dpms_fetch = (crtc_dpms_fetch) eng_crtc_dpms_fetch; + head1_set_display_pitch = (crtc_set_display_pitch) eng_crtc_set_display_pitch; + head1_set_display_start = (crtc_set_display_start) eng_crtc_set_display_start; + head1_cursor_init = (crtc_cursor_init) eng_crtc_cursor_init; + head1_cursor_show = (crtc_cursor_show) eng_crtc_cursor_show; + head1_cursor_hide = (crtc_cursor_hide) eng_crtc_cursor_hide; + head1_cursor_define = (crtc_cursor_define) eng_crtc_cursor_define; + head1_cursor_position = (crtc_cursor_position) eng_crtc_cursor_position; + + head1_mode = (dac_mode) eng_dac_mode; + head1_palette = (dac_palette) eng_dac_palette; + head1_set_pix_pll = (dac_set_pix_pll) eng_dac_set_pix_pll; + head1_pix_pll_find = (dac_pix_pll_find) eng_dac_pix_pll_find; + + head2_validate_timing = (crtc_validate_timing) eng_crtc2_validate_timing; + head2_set_timing = (crtc_set_timing) eng_crtc2_set_timing; + head2_depth = (crtc_depth) eng_crtc2_depth; + head2_dpms = (crtc_dpms) eng_crtc2_dpms; + head2_dpms_fetch = (crtc_dpms_fetch) eng_crtc2_dpms_fetch; + head2_set_display_pitch = (crtc_set_display_pitch) eng_crtc2_set_display_pitch; + head2_set_display_start = (crtc_set_display_start) eng_crtc2_set_display_start; + head2_cursor_init = (crtc_cursor_init) eng_crtc2_cursor_init; + head2_cursor_show = (crtc_cursor_show) eng_crtc2_cursor_show; + head2_cursor_hide = (crtc_cursor_hide) eng_crtc2_cursor_hide; + head2_cursor_define = (crtc_cursor_define) eng_crtc2_cursor_define; + head2_cursor_position = (crtc_cursor_position) eng_crtc2_cursor_position; + + head2_mode = (dac_mode) eng_dac2_mode; + head2_palette = (dac_palette) eng_dac2_palette; + head2_set_pix_pll = (dac_set_pix_pll) eng_dac2_set_pix_pll; + head2_pix_pll_find = (dac_pix_pll_find) eng_dac2_pix_pll_find; + } +} + +void set_crtc_owner(bool head) +{ + if (si->ps.secondary_head) + { + if (!head) + { + /* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's, + * while non-NV11 cards behave normally. + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: needed on NV11 */ + CRTCW(OWNER, 0xff); + /* enable access to CRTC1, SEQ1, GRPH1, ATB1, ??? */ + CRTCW(OWNER, 0x00); + } + else + { + /* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's, + * while non-NV11 cards behave normally. + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: needed on NV11 */ + CRTC2W(OWNER, 0xff); + /* enable access to CRTC2, SEQ2, GRPH2, ATB2, ??? */ + CRTC2W(OWNER, 0x03); + } + } +} + +static status_t engxx_general_powerup() +{ + LOG(4, ("INIT: card powerup\n")); + + /* setup cardspecs */ + /* note: + * this MUST be done before the driver attempts a card coldstart */ + set_specs(); + + /* only process BIOS for finetuning specs and coldstarting card if requested + * by the user; + * note: + * this in fact frees the driver from relying on the BIOS to be executed + * at system power-up POST time. */ + if (!si->settings.usebios) + { + LOG(2, ("INIT: Attempting card coldstart!\n")); + /* update the cardspecs in the shared_info PINS struct according to reported + * specs as much as is possible; + * this also coldstarts the card if possible (executes BIOS CMD script(s)) */ +// parse_pins(); + } + else + { + LOG(2, ("INIT: Skipping card coldstart!\n")); + } + + /* get RAM size and fake panel startup (panel init code is still missing) */ + fake_panel_start(); + + /* log the final card specifications */ + dump_pins(); + + /* dump config space as it is after a possible coldstart attempt */ + if (si->settings.logmask & 0x80000000) eng_dump_configuration_space(); + + /* setup CRTC and DAC functions access: determined in fake_panel_start */ + setup_virtualized_heads(si->ps.crtc2_prim); + + /* do powerup needed from pre-inited card state as done by system POST cardBIOS + * execution or driver coldstart above */ + return eng_general_bios_to_powergraphics(); +} + +/* this routine switches the CRTC/DAC sets to 'connectors', but only for analog + * outputs. We need this to make sure the analog 'switch' is set in the same way the + * digital 'switch' is set by the BIOS or we might not be able to use dualhead. */ +status_t eng_general_output_select(bool cross) +{ + /* make sure this call is warranted */ + if (si->ps.secondary_head) + { + /* NV11 cards can't switch heads (confirmed) */ + if (si->ps.card_type != NV11) + { + if (cross) + { + LOG(4,("INIT: switching analog outputs to be cross-connected\n")); + + /* enable head 2 on connector 1 */ + /* (b8 = select CRTC (head) for output, + * b4 = ??? (confirmed not to be a FP switch), + * b0 = enable CRT) */ + DACW(OUTPUT, 0x00000101); + /* enable head 1 on connector 2 */ + DAC2W(OUTPUT, 0x00000001); + } + else + { + LOG(4,("INIT: switching analog outputs to be straight-through\n")); + + /* enable head 1 on connector 1 */ + DACW(OUTPUT, 0x00000001); + /* enable head 2 on connector 2 */ + DAC2W(OUTPUT, 0x00000101); + } + } + else + { + LOG(4,("INIT: NV11 analog outputs are hardwired to be straight-through\n")); + } + return B_OK; + } + else + { + return B_ERROR; + } +} + +/* this routine switches CRTC/DAC set use. We need this because it's unknown howto + * switch digital panels to/from a specific CRTC/DAC set. */ +status_t eng_general_head_select(bool cross) +{ + /* make sure this call is warranted */ + if (si->ps.secondary_head) + { + /* invert CRTC/DAC use to do switching */ + if (cross) + { + LOG(4,("INIT: switching CRTC/DAC use to be cross-connected\n")); + si->crtc_switch_mode = !si->ps.crtc2_prim; + } + else + { + LOG(4,("INIT: switching CRTC/DAC use to be straight-through\n")); + si->crtc_switch_mode = si->ps.crtc2_prim; + } + /* update CRTC and DAC functions access */ + setup_virtualized_heads(si->crtc_switch_mode); + + return B_OK; + } + else + { + return B_ERROR; + } +} + +/* basic change of card state from VGA to enhanced mode: + * Should work from VGA BIOS POST init state. */ +static status_t eng_general_bios_to_powergraphics() +{ + /* let acc engine make power off/power on cycle to start 'fresh' */ +// ENG_RG32(RG32_PWRUPCTRL) = 0x13110011; + snooze(1000); + + /* power-up all hardware function blocks */ + /* bit 28: OVERLAY ENGINE (BES), + * bit 25: CRTC2, (> NV04A) + * bit 24: CRTC1, + * bit 20: framebuffer, + * bit 16: PPMI, + * bit 12: PGRAPH, + * bit 8: PFIFO, + * bit 4: PMEDIA, + * bit 0: TVOUT. (> NV04A) */ +// ENG_RG32(RG32_PWRUPCTRL) = 0x13111111; + + /* select colormode CRTC registers base adresses */ +// ENG_REG8(RG8_MISCW) = 0xcb; + + /* 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)); +// if (si->ps.secondary_head) + if (0) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* unlock head's registers for R/W access */ + CRTC2W(LOCK, 0x57); + CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + } + + /* turn off both displays and the hardcursors (also disables transfers) */ +// head1_dpms(false, false, false); +// head1_cursor_hide(); +// if (si->ps.secondary_head) + if (0) + { +// head2_dpms(false, false, false); +// head2_cursor_hide(); + } + +// if (si->ps.secondary_head) + if (0) + { + /* switch overlay engine to CRTC1 */ + /* bit 17: GPU FP port #1 (confirmed NV25, NV28, confirmed not on NV34), + * bit 16: GPU FP port #2 (confirmed NV25, NV28, NV34), + * bit 12: overlay engine (all cards), + * bit 9: TVout chip #2 (confirmed on NV18, NV25, NV28), + * bit 8: TVout chip #1 (all cards), + * bit 4: both I2C busses (all cards) */ + ENG_RG32(RG32_2FUNCSEL) &= ~0x00001000; + ENG_RG32(RG32_FUNCSEL) |= 0x00001000; + } + si->overlay.crtc = false; + + /* enable 'enhanced' mode on primary head: */ + /* enable access to primary head */ +// set_crtc_owner(0); + /* note: 'BUFFER' is a non-standard register in behaviour(!) on most + * NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards + * behave normally. + * Also readback is not nessesarily what was written before! + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: don't doublebuffer CRTC access: set programmed values immediately... */ +// CRTCW(BUFFER, 0xff); + /* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */ + /* note: this has no effect on possible bandwidth issues. */ +// CRTCW(BUFFER, 0xfb); + /* select VGA mode (old VGA register) */ +// CRTCW(MODECTL, 0xc3); + /* select graphics mode (old VGA register) */ +// SEQW(MEMMODE, 0x0e); + /* select 8 dots character clocks (old VGA register) */ +// SEQW(CLKMODE, 0x21); + /* select VGA mode (old VGA register) */ +// GRPHW(MODE, 0x00); + /* select graphics mode (old VGA register) */ +// GRPHW(MISC, 0x01); + /* select graphics mode (old VGA register) */ +// ATBW(MODECTL, 0x01); + /* enable 'enhanced mode', enable Vsync & Hsync, + * set DAC palette to 8-bit width, disable large screen */ +// CRTCW(REPAINT1, 0x04); + + /* enable 'enhanced' mode on secondary head: */ +// if (si->ps.secondary_head) + if (0) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* select colormode CRTC2 registers base adresses */ + ENG_REG8(RG8_MISCW) = 0xcb; + /* note: 'BUFFER' is a non-standard register in behaviour(!) on most + * NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards + * behave normally. + * Also readback is not nessesarily what was written before! + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: don't doublebuffer CRTC2 access: set programmed values immediately... */ + CRTC2W(BUFFER, 0xff); + /* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */ + /* note: this has no effect on possible bandwidth issues. */ + CRTC2W(BUFFER, 0xfb); + /* select VGA mode (old VGA register) */ + CRTC2W(MODECTL, 0xc3); + /* select graphics mode (old VGA register) */ + SEQW(MEMMODE, 0x0e); + /* select 8 dots character clocks (old VGA register) */ + SEQW(CLKMODE, 0x21); + /* select VGA mode (old VGA register) */ + GRPHW(MODE, 0x00); + /* select graphics mode (old VGA register) */ + GRPHW(MISC, 0x01); + /* select graphics mode (old VGA register) */ + ATB2W(MODECTL, 0x01); + /* enable 'enhanced mode', enable Vsync & Hsync, + * set DAC palette to 8-bit width, disable large screen */ + CRTC2W(REPAINT1, 0x04); + } + + /* enable palettes */ +// DACW(GENCTRL, 0x00100100); +// if (si->ps.secondary_head) DAC2W(GENCTRL, 0x00100100); + + /* enable programmable PLLs */ +// DACW(PLLSEL, 0x10000700); +// if (si->ps.secondary_head) DACW(PLLSEL, (DACR(PLLSEL) | 0x20000800)); + + /* turn on DAC and make sure detection testsignal routing is disabled + * (b16 = disable DAC, + * b12 = enable testsignal output */ +// DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeefff)); + /* turn on DAC2 if it exists + * (NOTE: testsignal function block resides in DAC1 only (!)) */ +// if (si->ps.secondary_head) DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeefff)); + + /* setup AGP: + * Note: + * This may only be done when no transfers are in progress on the bus, so now + * is probably a good time.. */ + eng_agp_setup(); + + /* turn screen one on */ +// head1_dpms(true, true, true); + + return B_OK; +} + +/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify + * virtual_size to the nearest valid maximum for the mode on the card if not so. + * Also: check if virtual_width adheres to the cards granularity constraints, and + * create mode slopspace if not so. + * We use acc or crtc granularity constraints based on the 'worst case' scenario. + * + * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ +status_t eng_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode) +{ + uint32 video_pitch; + uint32 acc_mask, crtc_mask; + uint32 max_crtc_width, max_acc_width; + uint8 depth = 8; + + /* determine pixel multiple based on 2D/3D engine constraints */ + switch (si->ps.card_arch) + { + default: + /* confirmed for: + * TNT1, TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */ + switch (target->space) + { + case B_CMAP8: acc_mask = 0x0f; depth = 8; break; + case B_RGB15: acc_mask = 0x07; depth = 16; break; + case B_RGB16: acc_mask = 0x07; depth = 16; break; + case B_RGB24: acc_mask = 0x0f; depth = 24; break; + case B_RGB32: acc_mask = 0x03; depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + /* NV31 (confirmed GeForceFX 5600) has NV20A granularity! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + case NV20A: + /* confirmed for: + * GeForce4 Ti4200 */ + switch (target->space) + { + case B_CMAP8: acc_mask = 0x3f; depth = 8; break; + case B_RGB15: acc_mask = 0x1f; depth = 16; break; + case B_RGB16: acc_mask = 0x1f; depth = 16; break; + case B_RGB24: acc_mask = 0x3f; depth = 24; break; + case B_RGB32: acc_mask = 0x0f; depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + } + + /* determine pixel multiple based on CRTC memory pitch constraints: + * -> all NV cards have same granularity constraints on CRTC1 and CRTC2, + * provided that the CRTC1 and CRTC2 BUFFER register b2 = 0; + * + * (Note: Don't mix this up with CRTC timing contraints! Those are + * multiples of 8 for horizontal, 1 for vertical timing.) */ + switch (si->ps.card_type) + { + default: +// case NV04: + /* confirmed for: + * TNT1 always; + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */ + /* NOTE: + * Unfortunately older cards have a hardware fault that prevents use. + * We need doubled granularity on those to prevent the single top line + * from shifting to the left! + * This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400. + * Confirmed OK are: + * GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */ + switch (target->space) + { + case B_CMAP8: crtc_mask = 0x0f; break; /* 0x07 */ + case B_RGB15: crtc_mask = 0x07; break; /* 0x03 */ + case B_RGB16: crtc_mask = 0x07; break; /* 0x03 */ + case B_RGB24: crtc_mask = 0x0f; break; /* 0x07 */ + case B_RGB32: crtc_mask = 0x03; break; /* 0x01 */ + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +// default: + /* confirmed for: + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */ +/* switch (target->space) + { + case B_CMAP8: crtc_mask = 0x1f; break; + case B_RGB15: crtc_mask = 0x0f; break; + case B_RGB16: crtc_mask = 0x0f; break; + case B_RGB24: crtc_mask = 0x1f; break; + case B_RGB32: crtc_mask = 0x07; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +*/ } + + /* set virtual_width limit for accelerated modes */ + switch (si->ps.card_arch) + { + case NV04A: + /* confirmed for: + * TNT1, TNT2, TNT2-M64 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 8176; break; + case B_RGB15: max_acc_width = 4088; break; + case B_RGB16: max_acc_width = 4088; break; + case B_RGB24: max_acc_width = 2720; break; + case B_RGB32: max_acc_width = 2044; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + default: + /* confirmed for: + * GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 16368; break; + case B_RGB15: max_acc_width = 8184; break; + case B_RGB16: max_acc_width = 8184; break; + case B_RGB24: max_acc_width = 5456; break; + case B_RGB32: max_acc_width = 4092; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + /* NV31 (confirmed GeForceFX 5600) has NV20A granularity! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + case NV20A: + /* confirmed for: + * GeForce4 Ti4200 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 16320; break; + case B_RGB15: max_acc_width = 8160; break; + case B_RGB16: max_acc_width = 8160; break; + case B_RGB24: max_acc_width = 5440; break; + case B_RGB32: max_acc_width = 4080; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + } + + /* set virtual_width limit for unaccelerated modes */ + switch (si->ps.card_type) + { + default: +// case NV04: + /* confirmed for: + * TNT1 always; + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */ + /* NOTE: + * Unfortunately older cards have a hardware fault that prevents use. + * We need doubled granularity on those to prevent the single top line + * from shifting to the left! + * This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400. + * Confirmed OK are: + * GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */ + switch(target->space) + { + case B_CMAP8: max_crtc_width = 16368; break; /* 16376 */ + case B_RGB15: max_crtc_width = 8184; break; /* 8188 */ + case B_RGB16: max_crtc_width = 8184; break; /* 8188 */ + case B_RGB24: max_crtc_width = 5456; break; /* 5456 */ + case B_RGB32: max_crtc_width = 4092; break; /* 4094 */ + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +// default: + /* confirmed for: + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */ +/* switch(target->space) + { + case B_CMAP8: max_crtc_width = 16352; break; + case B_RGB15: max_crtc_width = 8176; break; + case B_RGB16: max_crtc_width = 8176; break; + case B_RGB24: max_crtc_width = 5440; break; + case B_RGB32: max_crtc_width = 4088; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +*/ } + + /* check for acc capability, and adjust mode to adhere to hardware constraints */ + if (max_acc_width <= max_crtc_width) + { + /* check if we can setup this mode with acceleration */ +// *acc_mode = true; +//blocking acc totally: +*acc_mode = false; + /* virtual_width */ + if (target->virtual_width > max_acc_width) *acc_mode = false; + /* virtual_height */ + /* (NV cards can even do more than this(?)... + * but 4096 is confirmed on all cards at max. accelerated width.) */ + if (target->virtual_height > 4096) *acc_mode = false; + + /* now check virtual_size based on CRTC constraints */ + if (target->virtual_width > max_crtc_width) target->virtual_width = max_crtc_width; + /* virtual_height: The only constraint here is the cards memory size which is + * checked later on in ProposeMode: virtual_height is adjusted then if needed. + * 'Limiting here' to the variable size that's at least available (uint16). */ + if (target->virtual_height > 65535) target->virtual_height = 65535; + + /* OK, now we know that virtual_width is valid, and it's needing no slopspace if + * it was confined above, so we can finally calculate safely if we need slopspace + * for this mode... */ + if (*acc_mode) + { + /* the mode needs to adhere to the largest granularity imposed... */ + if (acc_mask < crtc_mask) + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + else + video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); + } + else /* unaccelerated mode */ + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + } + else /* max_acc_width > max_crtc_width */ + { + /* check if we can setup this mode with acceleration */ + *acc_mode = true; + /* (we already know virtual_width will be no problem) */ + /* virtual_height */ + /* (NV cards can even do more than this(?)... + * but 4096 is confirmed on all cards at max. accelerated width.) */ + if (target->virtual_height > 4096) *acc_mode = false; + + /* now check virtual_size based on CRTC constraints */ + if (*acc_mode) + { + /* note that max_crtc_width already adheres to crtc_mask */ + if (target->virtual_width > (max_crtc_width & ~acc_mask)) + target->virtual_width = (max_crtc_width & ~acc_mask); + } + else /* unaccelerated mode */ + { + if (target->virtual_width > max_crtc_width) + target->virtual_width = max_crtc_width; + } + /* virtual_height: The only constraint here is the cards memory size which is + * checked later on in ProposeMode: virtual_height is adjusted then if needed. + * 'Limiting here' to the variable size that's at least available (uint16). */ + if (target->virtual_height > 65535) target->virtual_height = 65535; + + /* OK, now we know that virtual_width is valid, and it's needing no slopspace if + * it was confined above, so we can finally calculate safely if we need slopspace + * for this mode... */ + if (*acc_mode) + { + /* the mode needs to adhere to the largest granularity imposed... */ + if (acc_mask < crtc_mask) + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + else + video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); + } + else /* unaccelerated mode */ + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + } + + LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n", + video_pitch, target->space)); + if (target->virtual_width != video_pitch) + LOG(2,("INIT: effective mode slopspace is %d pixels\n", + (video_pitch - target->virtual_width))); + + /* now calculate bytes_per_row for this mode */ + *bytes_per_row = video_pitch * (depth >> 3); + + return B_OK; +}