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"));
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"));
* _adi.name_ and _adi.chipset_ can contain 31 readable characters max.!!! */
switch(CFGR(DEVID))
{
case 0x000110c8:
si->ps.card_type = NM2070;
sprintf(si->adi.name, "Neomagic MagicGraph 128");
sprintf(si->adi.chipset, "NM2070 (ISA)");
break;
case 0x000210c8:
si->ps.card_type = NM2090;
sprintf(si->adi.name, "Neomagic MagicGraph 128V");
sprintf(si->adi.chipset, "NM2090 (ISA)");
break;
case 0x000310c8:
si->ps.card_type = NM2093;
sprintf(si->adi.name, "Neomagic MagicGraph 128ZV");
sprintf(si->adi.chipset, "NM2093 (ISA)");
break;
case 0x008310c8:
si->ps.card_type = NM2097;
sprintf(si->adi.name, "Neomagic MagicGraph 128ZV+");
sprintf(si->adi.chipset, "NM2097 (PCI)");
break;
case 0x000410c8:
si->ps.card_type = NM2160;
sprintf(si->adi.name, "Neomagic MagicGraph 128XD");
sprintf(si->adi.chipset, "NM2160 (PCI)");
break;
case 0x000510c8:
si->ps.card_type = NM2200;
sprintf(si->adi.name, "Neomagic MagicMedia 256AV");
sprintf(si->adi.chipset, "NM2200");
break;
case 0x002510c8:
si->ps.card_type = NM2230;
sprintf(si->adi.name, "Neomagic MagicMedia 256AV+");
sprintf(si->adi.chipset, "NM2230");
break;
case 0x000610c8:
si->ps.card_type = NM2360;
sprintf(si->adi.name, "Neomagic MagicMedia 256ZX");
sprintf(si->adi.chipset, "NM2360");
break;
case 0x001610c8:
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;
}
status = nmxxxx_general_powerup();
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;
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++)
{
((uint32 *)si->fbc.frame_buffer)[offset] = value;
value = 0xffffffff - value;
}
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
{
if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
value = 0xffffffff - value;
}
return result;
}
* 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()
{
if (test_ram() == B_OK)
{
LOG(4,("INIT: RAM access OK.\n"));
return B_OK;
}
LOG(4,("INIT: RAM access errors; not fixable: missing coldstart specs.\n"));
return B_ERROR;
}
void nm_unlock()
{
ISAGRPHW(GRPHXLOCK, 0x26);
}
static status_t nmxxxx_general_powerup()
{
uint8 temp;
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();
temp = (ISARB(MISCR) | 0x01);
snooze(10);
ISAWB(MISCW, temp);
ISAGRPHW(GRPHXLOCK, 0x26);
set_specs();
dump_specs();
ISAGRPHW(IFACECTRL2, 0xc0);
ISACRTCW(VGACURCTRL, 0x00);
return nm_general_bios_to_powergraphics();
LOG(2,("INIT: powerup\n"));
nm_crtc_dpms(false, false, false);
nm_crtc_cursor_hide();
ISASEQW(CLKMODE, 0x21);
nm_crtc_dpms(true, true, true);
return B_OK;
}
status_t nm_general_output_select()
{
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;
size_outputs = ISAGRPHR(PANELCTRL1);
* - 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)
{
* 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
{
if (!(ISASEQR(CLKMODE) & 0x20))
{
* we can 'safely' copy both output devices settings... */
if (size_outputs & 0x03)
{
si->ps.outputs = (size_outputs & 0x03);
}
else
{
si->ps.outputs = 0x02;
LOG(4, ("INIT: illegal outputmode detected, assuming internal mode!\n"));
}
}
else
{
* 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 (size_outputs & 0x02) si->ps.outputs |= 0x02;
}
}
return ((size_outputs & 0xfc) | (si->ps.outputs & 0x03));
}
static
status_t nm_general_bios_to_powergraphics()
{
uint8 temp;
LOG(2, ("INIT: Skipping card coldstart!\n"));
nm_crtc_dpms(false, false, false);
ISACRTCW(MODECTL, 0xc3);
* switch to graphics mode ... */
ISASEQW(MEMMODE, 0x0e);
* NeoMagic cards have custom b4-b7 use in this register! */
ISAGRPHW(ENSETRESET, 0x80);
ISAGRPHW(DATAROTATE, 0x00);
ISAGRPHW(READMAPSEL, 0x00);
ISAGRPHW(MODE, 0x00);
* select standard adressing ... */
ISAGRPHW(MISC, 0x05);
ISAGRPHW(BITMASK, 0xff);
ISAATBW(MODECTL, 0x01);
ISAATBW(OSCANCOLOR, 0x00);
ISAATBW(COLPLANE_EN, 0x0f);
ISAATBW(HORPIXPAN, 0x00);
ISAATBW(COLSEL, 0x00);
* NeoMagic cards have custom b6 use in this register! */
ISAATBW(0x16, 0x01);
ISASEQW(MAPMASK, 0x0f);
ISASEQW(CLKMODE, 0x21);
ISAGRPHW(FBSTADDE, 0x10);
ISAGRPHW(0x15, 0x00);
temp = ((ISAGRPHR(IFACECTRL1) & 0x0f) | 0x30);
snooze(10);
ISAGRPHW(IFACECTRL1, temp);
nm_crtc_dpms(true, true, true);
return B_OK;
}
* 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)
{
* 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;
* (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;
* 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. */
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;
}
*acc_mode = true;
if ((si->ps.card_type < NM2200) && (target->space == B_RGB24)) *acc_mode = false;
if (si->ps.card_type == NM2070)
{
if (target->virtual_width > 1024) *acc_mode = false;
}
else
{
if (target->virtual_width > 1600) *acc_mode = false;
}
if (target->virtual_height > 1024) *acc_mode = false;
{
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;
}
* 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;
}
* 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;
switch (target->space)
{
case B_CMAP8: acc_mask = 0x07; break;
* The following depths have actual acc_masks of 0x03. 0x1f is used
* because on lower acc_masks more bandwidth trouble arises.
* (pixel noise) */
case B_RGB15: acc_mask = 0x1f; break;
case B_RGB16: acc_mask = 0x1f; break;
}
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
}
else
{
* 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;
mem_avail = (si->ps.memory_size * 1024);
if (si->settings.hardcursor) mem_avail -= si->ps.curmem_size;
bytes_X_height = (depth >> 3) * target->virtual_height;
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)));
*bytes_per_row = video_pitch * (depth >> 3);
return B_OK;
}