/* Author: Rudolf Cornelissen 4/2003-1/2006 */ #define MODULE_BIT 0x00008000 #include "nm_std.h" static status_t test_ram(void); static status_t nmxxxx_general_powerup (void); static status_t nm_general_bios_to_powergraphics(void); static void nm_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", \ NMCFG_##reg, #reg, value)); \ } while (0) DUMP_CFG (DEVID, 0); DUMP_CFG (DEVCTRL, 0); DUMP_CFG (CLASS, 0); DUMP_CFG (HEADER, 0); DUMP_CFG (BASE1FB, 0); DUMP_CFG (BASE2REG1,0); DUMP_CFG (BASE3REG2,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 (CFG_3, 0); DUMP_CFG (CFG_4, 0); DUMP_CFG (CFG_5, 0); DUMP_CFG (CFG_6, 0); DUMP_CFG (CFG_7, 0); DUMP_CFG (CFG_8, 0); DUMP_CFG (CFG_9, 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 nm_general_powerup() { status_t status; LOG(1,("POWERUP: Haiku Neomagic Accelerant 0.14 running.\n")); /* log VBLANK INT usability status */ if (si->ps.int_assigned) LOG(4,("POWERUP: Usable INT assigned to HW; Vblank semaphore enabled\n")); else LOG(4,("POWERUP: No (usable) INT assigned to HW; Vblank semaphore disabled\n")); /* WARNING: * _adi.name_ and _adi.chipset_ can contain 31 readable characters max.!!! */ /* detect card type and power it up */ switch(CFGR(DEVID)) { case 0x000110c8: //NM2070 ISA si->ps.card_type = NM2070; sprintf(si->adi.name, "Neomagic MagicGraph 128"); sprintf(si->adi.chipset, "NM2070 (ISA)"); break; case 0x000210c8: //NM2090 ISA si->ps.card_type = NM2090; sprintf(si->adi.name, "Neomagic MagicGraph 128V"); sprintf(si->adi.chipset, "NM2090 (ISA)"); break; case 0x000310c8: //NM2093 ISA si->ps.card_type = NM2093; sprintf(si->adi.name, "Neomagic MagicGraph 128ZV"); sprintf(si->adi.chipset, "NM2093 (ISA)"); break; case 0x008310c8: //NM2097 PCI si->ps.card_type = NM2097; sprintf(si->adi.name, "Neomagic MagicGraph 128ZV+"); sprintf(si->adi.chipset, "NM2097 (PCI)"); break; case 0x000410c8: //NM2160 PCI si->ps.card_type = NM2160; sprintf(si->adi.name, "Neomagic MagicGraph 128XD"); sprintf(si->adi.chipset, "NM2160 (PCI)"); break; case 0x000510c8: //NM2200 si->ps.card_type = NM2200; sprintf(si->adi.name, "Neomagic MagicMedia 256AV"); sprintf(si->adi.chipset, "NM2200"); break; case 0x002510c8: //NM2230 si->ps.card_type = NM2230; sprintf(si->adi.name, "Neomagic MagicMedia 256AV+"); sprintf(si->adi.chipset, "NM2230"); break; case 0x000610c8: //NM2360 si->ps.card_type = NM2360; sprintf(si->adi.name, "Neomagic MagicMedia 256ZX"); sprintf(si->adi.chipset, "NM2360"); break; case 0x001610c8: //NM2380 si->ps.card_type = NM2380; sprintf(si->adi.name, "Neomagic MagicMedia 256XL+"); sprintf(si->adi.chipset, "NM2380"); break; default: LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID))); return B_ERROR; } /* power up the card */ status = nmxxxx_general_powerup(); /* override memory detection if requested by user */ if (si->settings.memory != 0) si->ps.memory_size = si->settings.memory; return status; } static status_t test_ram(void) { 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 nm setup on some (DRAM) boards) */ status_t nm_set_cas_latency() { /* 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 */ LOG(4,("INIT: RAM access errors; not fixable: missing coldstart specs.\n")); return B_ERROR; } void nm_unlock() { /* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */ ISAGRPHW(GRPHXLOCK, 0x26); } static status_t nmxxxx_general_powerup() { uint8 temp; // status_t result; LOG(4, ("INIT: powerup\n")); LOG(4, ("INIT: Detected %s (%s)\n", si->adi.name, si->adi.chipset)); if (si->settings.logmask & 0x80000000) nm_dump_configuration_space(); /* set ISA registermapping to VGA colormode */ temp = (ISARB(MISCR) | 0x01); /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); ISAWB(MISCW, temp); /* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */ ISAGRPHW(GRPHXLOCK, 0x26); /* unlock cards CRTC registers */ //don't touch: most cards get into trouble on this! // ISAGRPHW(GENLOCK, 0x00); /* initialize the shared_info struct */ set_specs(); /* log the struct settings */ dump_specs(); /* activate PCI access: b7 = framebuffer, b6 = registers */ ISAGRPHW(IFACECTRL2, 0xc0); /* disable VGA-mode cursor (just to be sure) */ ISACRTCW(VGACURCTRL, 0x00); /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ /*if (si->settings.usebios || (result != B_OK)) */return nm_general_bios_to_powergraphics(); /*power up the PLLs,LUT,DAC*/ LOG(2,("INIT: powerup\n")); /* turn off both displays and the hardcursor (also disables transfers) */ nm_crtc_dpms(false, false, false); nm_crtc_cursor_hide(); /* setup sequencer clocking mode */ ISASEQW(CLKMODE, 0x21); //fixme: setup coldstart capability... /* turn on display */ nm_crtc_dpms(true, true, true); return B_OK; } status_t nm_general_output_select() { /* log currently selected output */ switch (nm_general_output_read() & 0x03) { case 0x01: LOG(2, ("INIT: external CRT only mode active\n")); break; case 0x02: LOG(2, ("INIT: internal LCD only mode active\n")); break; case 0x03: LOG(2, ("INIT: simultaneous LCD/CRT mode active\n")); break; } return B_OK; } uint8 nm_general_output_read() { uint8 size_outputs; /* read panelsize and currently active outputs */ size_outputs = ISAGRPHR(PANELCTRL1); /* update noted currently active outputs if prudent: * - tracks active output devices, even if the keyboard shortcut is used because * using that key will take the selected output devices out of DPMS sleep mode * if programmed via these bits; * - when the shortcut key is not used, and DPMS was in a power-saving mode while * programmed via these bits, an output device will (still) be shut-off. */ if (si->ps.card_type < NM2200) { /* both output devices do DPMS via these bits. * if one of the bits is on we have a valid setting if no power-saving mode * is active, or the keyboard shortcut key for selecting output devices has * been used during power-saving mode. */ if (size_outputs & 0x03) si->ps.outputs = (size_outputs & 0x03); } else { /* check if any power-saving mode active */ if (!(ISASEQR(CLKMODE) & 0x20)) { /* screen is on: * we can 'safely' copy both output devices settings... */ if (size_outputs & 0x03) { si->ps.outputs = (size_outputs & 0x03); } else { /* ... unless no output is active, as this is illegal then */ si->ps.outputs = 0x02; LOG(4, ("INIT: illegal outputmode detected, assuming internal mode!\n")); } } else { /* screen is off: * only the internal panel does DPMS via these bits, so the external setting * can always be copied */ si->ps.outputs &= 0xfe; si->ps.outputs |= (size_outputs & 0x01); /* if the panel is on, we can note that (the shortcut key has been used) */ if (size_outputs & 0x02) si->ps.outputs |= 0x02; } } return ((size_outputs & 0xfc) | (si->ps.outputs & 0x03)); } /* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/ static status_t nm_general_bios_to_powergraphics() { uint8 temp; LOG(2, ("INIT: Skipping card coldstart!\n")); /* turn off display */ nm_crtc_dpms(false, false, false); /* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */ /* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */ ISACRTCW(MODECTL, 0xc3); /* ... plain sequential memory use, more than 64Kb RAM installed, * switch to graphics mode ... */ ISASEQW(MEMMODE, 0x0e); /* ... disable bitplane tweaking ... */ /* note: * NeoMagic cards have custom b4-b7 use in this register! */ ISAGRPHW(ENSETRESET, 0x80); /* ... no logical function tweaking with display data, no data rotation ... */ ISAGRPHW(DATAROTATE, 0x00); /* ... reset read map select to plane 0 ... */ ISAGRPHW(READMAPSEL, 0x00); /* ... set standard mode ... */ ISAGRPHW(MODE, 0x00); /* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again), * select standard adressing ... */ ISAGRPHW(MISC, 0x05); /* ... disable bit masking ... */ ISAGRPHW(BITMASK, 0xff); /* ... attributes are in color, switch to graphics mode (again) ... */ ISAATBW(MODECTL, 0x01); /* ... set overscan color to black ... */ ISAATBW(OSCANCOLOR, 0x00); /* ... enable all color planes ... */ ISAATBW(COLPLANE_EN, 0x0f); /* ... reset horizontal pixelpanning ... */ ISAATBW(HORPIXPAN, 0x00); /* ... reset colorpalette groupselect bits ... */ ISAATBW(COLSEL, 0x00); /* ... do unknown standard VGA register ... */ /* note: * NeoMagic cards have custom b6 use in this register! */ ISAATBW(0x16, 0x01); /* ... and enable all four byteplanes. */ ISASEQW(MAPMASK, 0x0f); /* setup sequencer clocking mode */ ISASEQW(CLKMODE, 0x21); /* enable memory above 256Kb: set b4 (disables adress wraparound at 256Kb boundary) */ ISAGRPHW(FBSTADDE, 0x10); /* this register has influence on the CRTC framebuffer offset, so reset! */ //fixme: investigate further... ISAGRPHW(0x15, 0x00); /* enable fast PCI write bursts (b4-5) */ temp = ((ISAGRPHR(IFACECTRL1) & 0x0f) | 0x30); /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); ISAGRPHW(IFACECTRL1, temp); /* this speeds up RAM writes according to XFree driver */ // fixme: don't touch until more is known: part of RAM or CORE PLL??? // ISAGRPHW(SPEED, 0xc0); /* turn on display */ nm_crtc_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. * Then: check if virtual_width adheres to the cards _multiple_ constraints, and * create mode slopspace if not so. * We use acc multiple constraints here if we expect we can use acceleration, because * acc constraints are worse than CRTC constraints. * * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ status_t nm_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode) { /* Note: * This routine assumes that the CRTC memory pitch granularity is 'smaller than', * or 'equals' the acceleration engine memory pitch granularity! */ uint32 video_pitch = 0; uint32 crtc_mask; uint8 depth = 8; /* determine pixel multiple based on CRTC memory pitch constraints. * (Note: Don't mix this up with CRTC timing contraints! Those are * multiples of 8 for horizontal, 1 for vertical timing.) * * CRTC pitch constraints are 'officially' the same for all Neomagic cards */ switch (si->ps.card_type) { case NM2070: switch (target->space) { case B_CMAP8: crtc_mask = 0x07; depth = 8; break; /* Note for NM2070 only: * The following depths have bandwidth trouble (pixel noise) with the * 'official' crtc_masks (used as defaults below). Masks of 0x1f are * needed (confirmed 15 and 16 bit spaces) to minimize this. */ //fixme: doublecheck for NM2090 and NM2093: correct code if needed! case B_RGB15: crtc_mask = 0x1f; depth = 16; break; case B_RGB16: crtc_mask = 0x1f; depth = 16; break; case B_RGB24: crtc_mask = 0x1f; depth = 24; break; default: LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); return B_ERROR; } break; default: switch (target->space) { case B_CMAP8: crtc_mask = 0x07; depth = 8; break; case B_RGB15: crtc_mask = 0x03; depth = 16; break; case B_RGB16: crtc_mask = 0x03; depth = 16; break; case B_RGB24: crtc_mask = 0x07; depth = 24; break; default: LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); return B_ERROR; } break; } /* check if we can setup this mode with acceleration: */ *acc_mode = true; /* pre-NM2200 cards don't support accelerated 24bit modes */ if ((si->ps.card_type < NM2200) && (target->space == B_RGB24)) *acc_mode = false; /* virtual_width */ if (si->ps.card_type == NM2070) { /* confirmed NM2070 */ if (target->virtual_width > 1024) *acc_mode = false; } else { /* confirmed for all cards */ if (target->virtual_width > 1600) *acc_mode = false; } /* virtual_height (confirmed NM2070, NM2097, NM2160 and NM2200 */ if (target->virtual_height > 1024) *acc_mode = false; /* now check virtual_size based on CRTC constraints and modify if needed */ //fixme: checkout cardspecs here!! (NM2160 can do 8192 _bytes_ at least (in theory)) { /* virtual_width */ switch(target->space) { case B_CMAP8: if (target->virtual_width > 16368) target->virtual_width = 16368; break; case B_RGB15_LITTLE: case B_RGB16_LITTLE: if (target->virtual_width > 8184) target->virtual_width = 8184; break; case B_RGB24_LITTLE: if (target->virtual_width > 5456) target->virtual_width = 5456; break; } /* 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) { if (si->ps.card_type == NM2070) { uint32 acc_mask = 0; /* determine pixel multiple based on 2D engine constraints */ switch (target->space) { case B_CMAP8: acc_mask = 0x07; break; /* Note: * The following depths have actual acc_masks of 0x03. 0x1f is used * because on lower acc_masks more bandwidth trouble arises. * (pixel noise) */ //fixme: doublecheck for NM2090 and NM2093: correct code if needed! case B_RGB15: acc_mask = 0x1f; break; case B_RGB16: acc_mask = 0x1f; break; } video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); } else { /* Note: * We prefer unaccelerated modes above accelerated ones here if not enough * RAM exists and the mode can be closer matched to the requested one if * unaccelerated. We do this because of the large amount of slopspace * sometimes needed here to keep a mode accelerated. */ uint32 mem_avail, bytes_X_height; /* calculate amount of available memory */ mem_avail = (si->ps.memory_size * 1024); if (si->settings.hardcursor) mem_avail -= si->ps.curmem_size; /* helper */ bytes_X_height = (depth >> 3) * target->virtual_height; /* Accelerated modes work with a table, there are very few fixed settings.. */ if (target->virtual_width == 640) video_pitch = 640; else if (target->virtual_width <= 800) { if (((800 * bytes_X_height) > mem_avail) && (target->virtual_width < (800 - crtc_mask))) *acc_mode = false; else video_pitch = 800; } else if (target->virtual_width <= 1024) { if (((1024 * bytes_X_height) > mem_avail) && (target->virtual_width < (1024 - crtc_mask))) *acc_mode = false; else video_pitch = 1024; } else if (target->virtual_width <= 1152) { if (((1152 * bytes_X_height) > mem_avail) && (target->virtual_width < (1152 - crtc_mask))) *acc_mode = false; else video_pitch = 1152; } else if (target->virtual_width <= 1280) { if (((1280 * bytes_X_height) > mem_avail) && (target->virtual_width < (1280 - crtc_mask))) *acc_mode = false; else video_pitch = 1280; } else if (target->virtual_width <= 1600) { if (((1600 * bytes_X_height) > mem_avail) && (target->virtual_width < (1600 - crtc_mask))) *acc_mode = false; else video_pitch = 1600; } } } if (!*acc_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; }