diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index f4d1b649f5..0905a5d76d 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -83,7 +83,7 @@ BEOS_NETWORK_PROTOCOLS = ipv4 tcp udp icmp unix ; BEOS_ADD_ONS_ACCELERANTS = $(X86_ONLY)radeon.accelerant $(X86_ONLY)nvidia.accelerant $(X86_ONLY)matrox.accelerant $(X86_ONLY)neomagic.accelerant - $(X86_ONLY)intel_extreme.accelerant $(X86_ONLY)s3savage.accelerant vesa.accelerant + $(X86_ONLY)intel_extreme.accelerant $(X86_ONLY)s3.accelerant vesa.accelerant #$(X86_ONLY)via.accelerant #$(X86_ONLY)vmware.accelerant ; @@ -122,7 +122,7 @@ BEOS_ADD_ONS_SCREENSAVERS = Haiku IFS Spider ; BEOS_ADD_ONS_DRIVERS_AUDIO = auich auvia emuxki ; #hda BEOS_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon $(X86_ONLY)nvidia $(X86_ONLY)neomagic $(X86_ONLY)matrox $(X86_ONLY)intel_extreme - $(X86_ONLY)s3savage vesa #$(X86_ONLY)via #$(X86_ONLY)vmware + $(X86_ONLY)s3 vesa #$(X86_ONLY)via #$(X86_ONLY)vmware ; BEOS_ADD_ONS_DRIVERS_MIDI = emuxki ; BEOS_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com etherpci $(X86_ONLY)ipro1000 diff --git a/headers/private/graphics/s3/DriverInterface.h b/headers/private/graphics/s3/DriverInterface.h new file mode 100644 index 0000000000..b64bd75d36 --- /dev/null +++ b/headers/private/graphics/s3/DriverInterface.h @@ -0,0 +1,238 @@ +/* + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Other authors: + Gerald Zajac 2007-2008 +*/ + +#ifndef DRIVERINTERFACE_H +#define DRIVERINTERFACE_H + + +#include +#include +#include +#include + + +// This is the info that needs to be shared between the kernel driver and +// the accelerant for the sample driver. + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ENABLE_DEBUG_TRACE // if defined, turns on debug output to syslog + + +#define NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array + +struct benaphore { + sem_id sem; + int32 ben; +}; + +#define INIT_BEN(x) x.sem = create_sem(0, "S3 "#x" benaphore"); x.ben = 0; +#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem); +#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem); +#define DELETE_BEN(x) delete_sem(x.sem); + + +#define S3_PRIVATE_DATA_MAGIC 0x4521 // a private driver rev, of sorts + + +enum { + S3_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, + S3_DEVICE_NAME, + S3_GET_PIO, + S3_SET_PIO, + S3_RUN_INTERRUPTS, +}; + + +// Chip type numbers. These are used to group the chips into related +// groups. See table S3_ChipTable in driver.c + +enum S3_ChipType { + S3_TRIO64 = 1, + S3_TRIO64_VP, // Trio64V+ has same ID as Trio64 but different revision number + S3_TRIO64_UVP, + S3_TRIO64_V2, + Trio64ChipsEnd, + S3_VIRGE, + S3_VIRGE_VX, + S3_VIRGE_DXGX, + S3_VIRGE_GX2, + S3_VIRGE_MX, + S3_VIRGE_MXP, + S3_TRIO_3D, + S3_TRIO_3D_2X, + VirgeChipsEnd, + S3_SAVAGE_3D, + S3_SAVAGE_MX, + S3_SAVAGE4, + S3_PROSAVAGE, + S3_TWISTER, + S3_PROSAVAGE_DDR, + S3_SUPERSAVAGE, + S3_SAVAGE2000, +}; + + +#define S3_TRIO64_FAMILY(chip) (chip < Trio64ChipsEnd) +#define S3_VIRGE_FAMILY(chip) (chip > Trio64ChipsEnd && chip < VirgeChipsEnd) +#define S3_SAVAGE_FAMILY(chip) (chip > VirgeChipsEnd) + +#define S3_VIRGE_GX2_SERIES(chip) (chip == S3_VIRGE_GX2 || chip == S3_TRIO_3D_2X) +#define S3_VIRGE_MX_SERIES(chip) (chip == S3_VIRGE_MX || chip == S3_VIRGE_MXP) + +#define S3_SAVAGE_3D_SERIES(chip) ((chip == S3_SAVAGE_3D) || (chip == S3_SAVAGE_MX)) +#define S3_SAVAGE4_SERIES(chip) ((chip == S3_SAVAGE4) \ + || (chip == S3_PROSAVAGE) \ + || (chip == S3_TWISTER) \ + || (chip == S3_PROSAVAGE_DDR)) +#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip == S3_SAVAGE_MX) \ + || (chip == S3_SUPERSAVAGE)) +#define S3_MOBILE_TWISTER_SERIES(chip) ((chip == S3_TWISTER) \ + || (chip == S3_PROSAVAGE_DDR)) + + + +enum MonitorType { + MT_CRT, + MT_LCD, // laptop LCD display + MT_DFP // DVI display +}; + + +// Bitmap descriptor structures for BCI (for Savage chips) +struct HIGH { + unsigned short Stride; + unsigned char Bpp; + unsigned char ResBWTile; +}; + +struct BMPDESC1 { + unsigned long Offset; + HIGH HighPart; +}; + +struct BMPDESC2 { + unsigned long LoPart; + unsigned long HiPart; +}; + +union BMPDESC { + BMPDESC1 bd1; + BMPDESC2 bd2; +}; + + + +struct DisplayModeEx : display_mode { + uint32 bpp; // bits/pixel + uint32 bytesPerRow; // number of bytes in one line/row +}; + + +struct SharedInfo { + // Device ID info. + uint16 vendorID; // PCI vendor ID, from pci_info + uint16 deviceID; // PCI device ID, from pci_info + uint8 revision; // PCI device revsion, from pci_info + uint32 chipType; // indicates group in which chip belongs (a group has similar functionality) + char chipName[32]; // user recognizable name of chip + + bool bAccelerantInUse; // true = accelerant has been initialized + bool bInterruptAssigned; // card has a useable interrupt assigned to it + + sem_id vertBlankSem; // vertical blank semaphore; if < 0, there is no semaphore + + // Memory mappings. + area_id regsArea; // area_id for the memory mapped registers. It will + // be cloned into accelerant's address space. + area_id videoMemArea; // video memory area_id. The addresses are shared with all teams. + void* videoMemAddr; // video memory addr as viewed from virtual memory + void* videoMemPCI; // video memory addr as viewed from the PCI bus (for DMA) + uint32 videoMemSize; // video memory size in bytes. + + uint32 cursorOffset; // offset of cursor in video memory + uint32 frameBufferOffset; // offset of frame buffer in video memory + uint32 maxFrameBufferSize; // max available video memory for frame buffer + + // Color spaces supported by current video chip/driver. + color_space colorSpaces[6]; + uint32 colorSpaceCount; // number of color spaces in array colorSpaces + + // List of screen modes. + area_id modeArea; // area containing list of display modes the driver supports + uint32 modeCount; // number of display modes in the list + + // Cursor info. + struct { + uint16 hot_x; // Cursor hot spot. Top left corner of the cursor + uint16 hot_y; // is 0,0 + } cursor; + + // Current display mode configuration, and other parameters related to + // current display mode. + DisplayModeEx displayMode; // current display mode configuration + int32 commonCmd; // flags common to drawing commands of current display mode + + edid1_info edidInfo; + bool bHaveEDID; // true = EDID info from device is in edidInfo + + // Acceleration engine. + struct { + uint64 count; // last fifo slot used + uint64 lastIdle; // last fifo slot we *know* the engine was idle after + benaphore lock; // for serializing access to the acceleration engine + } engine; + + int mclk; + + MonitorType displayType; + + uint16 panelX; // laptop LCD width + uint16 panelY; // laptop LCD height + + // Command Overflow Buffer (COB) parameters for Savage chips. + bool bDisableCOB; // enable/disable COB for Savage 4 & ProSavage + uint32 cobIndex; // size index + uint32 cobSize; // size in bytes + uint32 cobOffset; // offset in video memory + uint32 bciThresholdLo; // low and high thresholds for + uint32 bciThresholdHi; // shadow status update (32bit words) + + BMPDESC GlobalBD; // Bitmap Descriptor for BCI +}; + + +// Set some boolean condition (like enabling or disabling interrupts) +struct S3SetBoolState { + uint32 magic; // magic number to make sure the caller groks us + bool bEnable; // state to set +}; + + +// Retrieve the area_id of the kernel/accelerant shared info +struct S3GetPrivateData { + uint32 magic; // magic number to make sure the caller groks us + area_id sharedInfoArea; // ID of area containing shared information +}; + + +struct S3GetSetPIO { + uint32 magic; // magic number to make sure the caller groks us + uint32 offset; // offset of PIO register to read/write + uint32 size; // number of bytes to transfer + uint32 value; // value to write or value that was read +}; + + +#if defined(__cplusplus) +} +#endif + +#endif // DRIVERINTERFACE_H diff --git a/headers/private/graphics/s3savage/DriverInterface.h b/headers/private/graphics/s3savage/DriverInterface.h deleted file mode 100644 index 6970347367..0000000000 --- a/headers/private/graphics/s3savage/DriverInterface.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ -#ifndef DRIVERINTERFACE_H -#define DRIVERINTERFACE_H - - -#include -#include -#include -#include -#include - -/* - This is the info that needs to be shared between the kernel driver and - the accelerant for the sample driver. -*/ -#if defined(__cplusplus) -extern "C" { -#endif - -#if 1 /* DEBUG */ -# define TRACE_S3SAVAGE - // turns on debug output -#endif - -#define NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array - -typedef struct { - sem_id sem; - int32 ben; -} benaphore; - -#define INIT_BEN(x) x.sem = create_sem(0, "SAVAGE "#x" benaphore"); x.ben = 0; -#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem); -#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem); -#define DELETE_BEN(x) delete_sem(x.sem); - - -#define SAVAGE_PRIVATE_DATA_MAGIC 0x5791 // a private driver rev, of sorts - - -enum { - SAVAGE_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, - SAVAGE_GET_PCI, - SAVAGE_SET_PCI, - SAVAGE_DEVICE_NAME, - SAVAGE_RUN_INTERRUPTS, -}; - - -// Chip tags. These are used to group the adapters into related -// families. See table SavageChipsetTable in driver.c - -enum S3ChipTags { - S3_UNKNOWN = 0, - S3_SAVAGE3D, - S3_SAVAGE_MX, - S3_SAVAGE4, - S3_PROSAVAGE, - S3_TWISTER, - S3_PROSAVAGEDDR, - S3_SUPERSAVAGE, - S3_SAVAGE2000, -}; - -#define S3_SAVAGE3D_SERIES(chip) ((chip==S3_SAVAGE3D) || (chip==S3_SAVAGE_MX)) - -#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) \ - || (chip==S3_PROSAVAGE) \ - || (chip==S3_TWISTER) \ - || (chip==S3_PROSAVAGEDDR)) - -#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE)) - -#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip==S3_PROSAVAGEDDR)) - - -typedef enum { - MT_NONE, - MT_CRT, - MT_LCD, - MT_DFP, - MT_TV -} SavageMonitorType; - - -// Bitmap descriptor structures for BCI -typedef struct _HIGH { - unsigned short Stride; - unsigned char Bpp; - unsigned char ResBWTile; -} HIGH; - -typedef struct _BMPDESC1 { - unsigned long Offset; - HIGH HighPart; -} BMPDESC1; - -typedef struct _BMPDESC2 { - unsigned long LoPart; - unsigned long HiPart; -} BMPDESC2; - -typedef union _BMPDESC { - BMPDESC1 bd1; - BMPDESC2 bd2; -} BMPDESC; - - -typedef struct { - // Device ID info. - uint16 vendorID; // PCI vendor ID, from pci_info - uint16 deviceID; // PCI device ID, from pci_info - uint8 revision; // PCI device revsion, from pci_info - uint32 chipset; // indicates family in which chipset belongs (a family has similar functionality) - char chipsetName[32]; // user recognizable name of chipset - - bool bAccelerantInUse; // true = accelerant has been initialized - bool bInterruptAssigned; // card has a useable interrupt assigned to it - - // Memory mappings. - area_id regsArea; // area_id for the memory mapped registers. It will - // be cloned into accelerant's address space. - area_id videoMemArea; // video memory area_id. The addresses are shared with all teams. - void* videoMemAddr; // video memory addr as viewed from virtual memory - void* videoMemPCI; // video memory addr as viewed from the PCI bus (for DMA) - uint32 videoMemSize; // video memory size in bytes. - - uint32 cursorOffset; // offset of cursor in video memory - uint32 frameBufferOffset; // offset of frame buffer in video memory - uint32 maxFrameBufferSize; // max available video memory for frame buffer - - // List of screen modes. - area_id modeArea; // Contains the list of display modes the driver supports - uint32 modeCount; // Number of display modes in the list - - // Vertical blank semaphore. - sem_id vblank; // vertical blank semaphore; if < 0, there is no semaphore - // Ownership will be transfered to team opening device first - // Flags used by driver. - int32 flags; - - // Cursor info. - struct { - uint16 hot_x; // Cursor hot spot. The top left corner of the cursor - uint16 hot_y; // is 0,0 - uint16 x; // The location of the cursor hot spot on the - uint16 y; // display (or desktop?) - uint16 width; // Width and height of the cursor shape - uint16 height; - bool bIsVisible; // Is the cursor currently displayed? - } cursor; - - display_mode dm; // current display mode configuration - int bitsPerPixel; // bits per pixel of current display mode - - frame_buffer_config fbc; // frame buffer addresses and bytes_per_row - - // Acceleration engine. - struct { - uint64 count; // last fifo slot used - uint64 lastIdle; // last fifo slot we *know* the engine was idle after - benaphore lock; // for serializing access to the acceleration engine - } engine; - - int mclk; - uint32 pix_clk_max8; // The maximum speed the pixel clock should run - uint32 pix_clk_max16; // at for a given pixel width. Usually a function - uint32 pix_clk_max32; // of memory and DAC bandwidths. - - // Command Overflow Buffer (COB) parameters. - bool bDisableCOB; // enable/disable COB for Savage 4 & ProSavage - uint32 cobIndex; // size index - uint32 cobSize; // size in bytes - uint32 cobOffset; // offset in video memory - uint32 bciThresholdLo; // low and high thresholds for - uint32 bciThresholdHi; // shadow status update (32bit words) - - BMPDESC GlobalBD; // Bitmap Descriptor for BCI - - int panelX; // LCD panel width - int panelY; // LCD panel height - - int frameX0; // viewport position - int frameY0; - - // The various Savage wait handlers. - bool (*WaitQueue)(int); - bool (*WaitIdleEmpty)(); - - SavageMonitorType displayType; - -} SharedInfo; - - -// Read or write a value in PCI configuration space -typedef struct { - uint32 magic; // magic number to make sure the caller groks us - uint32 offset; // Offset to read/write - uint32 size; // Number of bytes to transfer - uint32 value; // The value read or written -} SavageGetSetPci; - - -// Set some boolean condition (like enabling or disabling interrupts) -typedef struct { - uint32 magic; // magic number to make sure the caller groks us - bool bEnable; // state to set -} SavageSetBoolState; - - -// Retrieve the area_id of the kernel/accelerant shared info -typedef struct { - uint32 magic; // magic number to make sure the caller groks us - area_id sharedInfoArea; // ID of area containing shared information -} SavageGetPrivateData; - - -// Retrieve the device name. Usefull for when we have a file handle, but want -// to know the device name (like when we are cloning the accelerant) -typedef struct { - uint32 magic; // magic number to make sure the caller groks us - char *name; // The name of the device, less the /dev root -} SavageDeviceName; - - -#if defined(__cplusplus) -} -#endif - -#endif /* DRIVERINTERFACE_H */ diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index 3eb78a25dd..107c0ab6fc 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -7,7 +7,7 @@ SubInclude HAIKU_TOP src add-ons accelerants matrox ; SubInclude HAIKU_TOP src add-ons accelerants neomagic ; SubInclude HAIKU_TOP src add-ons accelerants nvidia ; SubInclude HAIKU_TOP src add-ons accelerants radeon ; -SubInclude HAIKU_TOP src add-ons accelerants s3savage ; +SubInclude HAIKU_TOP src add-ons accelerants s3 ; SubInclude HAIKU_TOP src add-ons accelerants tdfx ; SubInclude HAIKU_TOP src add-ons accelerants vesa ; SubInclude HAIKU_TOP src add-ons accelerants via ; diff --git a/src/add-ons/accelerants/s3/Jamfile b/src/add-ons/accelerants/s3/Jamfile new file mode 100644 index 0000000000..3fb069744e --- /dev/null +++ b/src/add-ons/accelerants/s3/Jamfile @@ -0,0 +1,43 @@ +SubDir HAIKU_TOP src add-ons accelerants s3 ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics s3 ] ; +UsePrivateHeaders [ FDirName graphics common ] ; + +Addon s3.accelerant : + accel.cpp + cursor.cpp + engine.cpp + hooks.cpp + mode.cpp + register_io.cpp + + savage_cursor.cpp + savage_dpms.cpp + savage_draw.cpp + savage_edid.cpp + savage_init.cpp + savage_mode.cpp + + trio64_cursor.cpp + trio64_dpms.cpp + trio64_draw.cpp + trio64_init.cpp + trio64_mode.cpp + + virge_cursor.cpp + virge_dpms.cpp + virge_draw.cpp + virge_edid.cpp + virge_init.cpp + virge_mode.cpp + + : be libaccelerantscommon.a +; + +Package haiku-s3-cvs : + s3.accelerant : + boot home config add-ons accelerants ; + diff --git a/src/add-ons/accelerants/s3/accel.cpp b/src/add-ons/accelerants/s3/accel.cpp new file mode 100644 index 0000000000..1662e9c6a0 --- /dev/null +++ b/src/add-ons/accelerants/s3/accel.cpp @@ -0,0 +1,217 @@ +/* + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" + +#include +#include +#include + + + +AccelerantInfo gInfo; // global data used by various source files of accelerant. + + + +static status_t +InitCommon(int fileDesc) +{ + // Initialization function used by primary and cloned accelerants. + + gInfo.deviceFileDesc = fileDesc; + + // Get pointer to registers and shared data from driver. + + S3GetPrivateData gpd; + gpd.magic = S3_PRIVATE_DATA_MAGIC; + + status_t result = ioctl(gInfo.deviceFileDesc, S3_GET_PRIVATE_DATA, &gpd, sizeof(gpd)); + if (result != B_OK) + return result; + + gInfo.sharedInfoArea = clone_area("S3 shared info", (void**)&(gInfo.sharedInfo), + B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gpd.sharedInfoArea); + if (gInfo.sharedInfoArea < 0) + return gInfo.sharedInfoArea; // sharedInfoArea has error code + + gInfo.regsArea = clone_area("S3 regs area", (void**)&(gInfo.regs), + B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gInfo.sharedInfo->regsArea); + if (gInfo.regsArea < 0) { + delete_area(gInfo.sharedInfoArea); + return gInfo.regsArea; // regsArea has error code + } + + // Set pointers to various device specific functions. + + if (S3_SAVAGE_FAMILY(gInfo.sharedInfo->chipType)) + Savage_SetFunctionPointers(); + else if (S3_TRIO64_FAMILY(gInfo.sharedInfo->chipType)) + Trio64_SetFunctionPointers(); + else if (S3_VIRGE_FAMILY(gInfo.sharedInfo->chipType)) + Virge_SetFunctionPointers(); + else + return B_ERROR; // undefined chip type code + + return B_OK; +} + + +static void +UninitCommon(void) +{ + // This function is used by both primary and cloned accelerants. + + delete_area(gInfo.regsArea); + gInfo.regs = 0; + + delete_area(gInfo.sharedInfoArea); + gInfo.sharedInfo = 0; +} + + +status_t +InitAccelerant(int fileDesc) +{ + // Initialize the accelerant. fileDesc is the file handle of the device + // (in /dev/graphics) that has been opened by the app_server. + + TRACE("Enter InitAccelerant()\n"); + + gInfo.bAccelerantIsClone = false; // indicate this is primary accelerant + + status_t result = InitCommon(fileDesc); + if (result == B_OK) { + SharedInfo& si = *gInfo.sharedInfo; + + TRACE("Vendor ID: 0x%X, Device ID: 0x%X\n", si.vendorID, si.deviceID); + + // Ensure that InitAccelerant is executed just once (copies should be clones) + + if (si.bAccelerantInUse) { + result = B_NOT_ALLOWED; + } else { + result = gInfo.ChipInit(); // perform init related to current chip + if (result == B_OK) { + + INIT_BEN(si.engine.lock); + si.engine.lastIdle = 0; + si.engine.count = 0; + + gInfo.ShowCursor(false); + + // ensure that this function won't be executed again (copies should be clones) + si.bAccelerantInUse = true; + } + } + + if (result != B_OK) + UninitCommon(); + } + + TRACE("Leave InitAccelerant(), result: 0x%X\n", result); + return result; +} + + +ssize_t +AccelerantCloneInfoSize(void) +{ + // Return the number of bytes required to hold the information required + // to clone the device. The information is merely the name of the device; + // thus, return the size of the name buffer. + + return B_OS_NAME_LENGTH; +} + + +void +GetAccelerantCloneInfo(void* data) +{ + // Return the info required to clone the device. Argument data points to + // a buffer which is the size returned by AccelerantCloneInfoSize(). + + ioctl(gInfo.deviceFileDesc, S3_DEVICE_NAME, data, B_OS_NAME_LENGTH); +} + + +status_t +CloneAccelerant(void* data) +{ + // Initialize a copy of the accelerant as a clone. Argument data points to + // a copy of the data which was returned by GetAccelerantCloneInfo(). + + TRACE("Enter CloneAccelerant()\n"); + + char path[MAXPATHLEN] = "/dev/"; + strcat(path, (const char*)data); + + gInfo.deviceFileDesc = open(path, B_READ_WRITE); // open the device + if (gInfo.deviceFileDesc < 0) + return errno; + + gInfo.bAccelerantIsClone = true; + + status_t result = InitCommon(gInfo.deviceFileDesc); + if (result != B_OK) { + close(gInfo.deviceFileDesc); + return result; + } + + result = gInfo.modeListArea = clone_area("S3 cloned display_modes", + (void**) &gInfo.modeList, B_ANY_ADDRESS, B_READ_AREA, + gInfo.sharedInfo->modeArea); + if (result < 0) { + UninitCommon(); + close(gInfo.deviceFileDesc); + return result; + } + + TRACE("Leave CloneAccelerant()\n"); + return B_OK; +} + + +void +UninitAccelerant(void) +{ + delete_area(gInfo.modeListArea); + gInfo.modeList = NULL; + + UninitCommon(); + + if (gInfo.bAccelerantIsClone) + close(gInfo.deviceFileDesc); +} + + +sem_id +AccelerantRetraceSemaphore(void) +{ + // Return the semaphore id that will be used to signal that a vertical + // retrace occured. + + return B_ERROR; +} + + +status_t +GetAccelerantDeviceInfo(accelerant_device_info* adi) +{ + // Get info about the device. + + SharedInfo& si = *gInfo.sharedInfo; + + adi->version = 1; + strcpy(adi->name, "S3 chipset"); + strcpy(adi->chipset, si.chipName); + strcpy(adi->serial_no, "unknown"); + adi->memory = si.maxFrameBufferSize; + adi->dac_speed = 270; + + return B_OK; +} diff --git a/src/add-ons/accelerants/s3/accel.h b/src/add-ons/accelerants/s3/accel.h new file mode 100644 index 0000000000..b8245bb2f2 --- /dev/null +++ b/src/add-ons/accelerants/s3/accel.h @@ -0,0 +1,202 @@ +/* + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#ifndef _ACCEL_H +#define _ACCEL_H + +#include "DriverInterface.h" +#include "register_io.h" + + +#if defined(__cplusplus) +extern "C" { +#endif + + + +#undef TRACE + +#ifdef ENABLE_DEBUG_TRACE +extern "C" void _sPrintf(const char* format, ...); +# define TRACE(x...) _sPrintf("S3: " x) +#else +# define TRACE(x...) ; +#endif + + +// Global data used by various source files of the accelerant. + +struct AccelerantInfo { + int deviceFileDesc; // file descriptor of kernel driver + + SharedInfo* sharedInfo; // address of info shared between accelerants & driver + area_id sharedInfoArea; // shared info area ID + + uint8* regs; // base address of MMIO register area + area_id regsArea; // MMIO register area ID + + display_mode* modeList; // list of standard display modes + area_id modeListArea; // mode list area ID + + bool bAccelerantIsClone;// true if this is a cloned accelerant + + // Pointers to wait handlers. + void (*WaitQueue)(uint32); + void (*WaitIdleEmpty)(); + + // Pointers to DPMS functions. + uint32 (*DPMSCapabilities)(void); + uint32 (*DPMSMode)(void); + status_t (*SetDPMSMode)(uint32 dpms_flags); + + // Pointers to cursor functions. + bool (*LoadCursorImage)(int width, int height, uint8* and_mask, uint8* xor_mask); + void (*SetCursorPosition)(int x, int y); + void (*ShowCursor)(bool bShow); + + // Pointers to 2D acceleration functions. + void (*FillRectangle)(engine_token*, uint32 color, fill_rect_params*, uint32 count); + void (*FillSpan)(engine_token*, uint32 color, uint16* list, uint32 count); + void (*InvertRectangle)(engine_token*, fill_rect_params*, uint32 count); + void (*ScreenToScreenBlit)(engine_token*, blit_params*, uint32 count); + + // Pointers to other functions. + void (*AdjustFrame)(const DisplayModeEx& mode); + status_t (*ChipInit)(void); + bool (*GetColorSpaceParams)(int colorSpace, uint32& bpp, uint32& maxPixelClk); + bool (*SetDisplayMode)(const DisplayModeEx& mode); + void (*SetIndexedColors)(uint count, uint8 first, uint8* color_data, uint32 flags); +}; + +extern AccelerantInfo gInfo; + + +// Prototypes of the interface functions called by the app_server. Note that +// the functions that are unique to a particular chip family, will be prefixed +// with the name of the family, and the functions that are applicable to all +// chips will have no prefix. +//================================================================ + +// General +status_t InitAccelerant(int fd); +ssize_t AccelerantCloneInfoSize(void); +void GetAccelerantCloneInfo(void* data); +status_t CloneAccelerant(void* data); +void UninitAccelerant(void); +status_t GetAccelerantDeviceInfo(accelerant_device_info* adi); +sem_id AccelerantRetraceSemaphore(void); + +// Mode Configuration +uint32 AccelerantModeCount(void); +status_t GetModeList(display_mode* dm); +status_t ProposeDisplayMode(display_mode* target, const display_mode* low, const display_mode* high); +status_t SetDisplayMode(display_mode* mode_to_set); +status_t GetDisplayMode(display_mode* current_mode); +status_t GetFrameBufferConfig(frame_buffer_config* a_frame_buffer); +status_t GetPixelClockLimits(display_mode* dm, uint32* low, uint32* high); +status_t MoveDisplay(uint16 h_display_start, uint16 v_display_start); +status_t GetTimingConstraints(display_timing_constraints* dtc); +void Savage_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags); +void Trio64_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags); +void Virge_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags); +status_t GetPreferredDisplayMode(display_mode* preferredMode); +status_t GetEdidInfo(void* info, size_t size, uint32* _version); + +// DPMS +uint32 Savage_DPMSCapabilities(void); +uint32 Savage_DPMSMode(void); +status_t Savage_SetDPMSMode(uint32 dpms_flags); + +uint32 Trio64_DPMSCapabilities(void); +uint32 Trio64_DPMSMode(void); +status_t Trio64_SetDPMSMode(uint32 dpms_flags); + +uint32 Virge_DPMSCapabilities(void); +uint32 Virge_DPMSMode(void); +status_t Virge_SetDPMSMode(uint32 dpms_flags); + +// Cursor +status_t SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, + uint8* andMask, uint8* xorMask); +void MoveCursor(uint16 x, uint16 y); +void Savage_ShowCursor(bool bShow); +void Trio64_ShowCursor(bool bShow); +void Virge_ShowCursor(bool bShow); + +// Engine Management +uint32 AccelerantEngineCount(void); +status_t AcquireEngine(uint32 capabilities, uint32 max_wait, sync_token* st, engine_token** et); +status_t ReleaseEngine(engine_token* et, sync_token* st); +void WaitEngineIdle(void); +status_t GetSyncToken(engine_token* et, sync_token* st); +status_t SyncToToken(sync_token* st); + +// 2D acceleration +void Savage_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count); +void Savage_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count); +void Savage_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count); +void Savage_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count); + +void Trio64_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count); +void Trio64_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count); +void Trio64_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count); +void Trio64_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count); + +void Virge_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count); +void Virge_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count); +void Virge_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count); +void Virge_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count); + + + +// Prototypes for other functions that are called from source files other than +// where they are defined. +//============================================================================ + +status_t CreateModeList(bool (*checkMode)(const display_mode* mode)); +void InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[], + uint8& cr3b, uint8& cr3c, uint8& cr5d, uint8& cr5e); +bool IsModeUsable(const display_mode* mode); + +// Savage functions. + +bool Savage_GetEdidInfo(void); + +bool Savage_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); +void Savage_SetCursorPosition(int x, int y); + +void Savage_AdjustFrame(const DisplayModeEx& mode); +bool Savage_SetDisplayMode(const DisplayModeEx& mode); +void Savage_SetFunctionPointers(void); + +// Trio64 functions. + +bool Trio64_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); +void Trio64_SetCursorPosition(int x, int y); + +void Trio64_AdjustFrame(const DisplayModeEx& mode); +bool Trio64_SetDisplayMode(const DisplayModeEx& mode); +void Trio64_SetFunctionPointers(void); + +// Virge functions. + +bool Virge_GetEdidInfo(void); + +bool Virge_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); +void Virge_SetCursorPosition(int x, int y); + +void Virge_AdjustFrame(const DisplayModeEx& mode); +bool Virge_SetDisplayMode(const DisplayModeEx& mode); +void Virge_SetFunctionPointers(void); + + +#if defined(__cplusplus) +} +#endif + +#endif // _ACCEL_H diff --git a/src/add-ons/accelerants/s3/cursor.cpp b/src/add-ons/accelerants/s3/cursor.cpp new file mode 100644 index 0000000000..e516d01110 --- /dev/null +++ b/src/add-ons/accelerants/s3/cursor.cpp @@ -0,0 +1,81 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" + + +status_t +SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, + uint8* andMask, uint8* xorMask) +{ + // NOTE: Currently, for BeOS, cursor width and height must be equal to 16. + + if ((width != 16) || (height != 16)) { + return B_ERROR; + } else if ((hot_x >= width) || (hot_y >= height)) { + return B_ERROR; + } else { + // Update cursor variables appropriately. + + SharedInfo& si = *gInfo.sharedInfo; + si.cursor.hot_x = hot_x; + si.cursor.hot_y = hot_y; + + if ( ! gInfo.LoadCursorImage(width, height, andMask, xorMask)) + return B_ERROR; + } + + return B_OK; +} + + +void +MoveCursor(uint16 xPos, uint16 yPos) +{ + // Move the cursor to the specified position on the desktop. If we're + // using some kind of virtual desktop, adjust the display start position + // accordingly and position the cursor in the proper "virtual" location. + + int x = xPos; // use signed int's since chip specific functions + int y = yPos; // need signed int to determine if cursor off screen + + SharedInfo& si = *gInfo.sharedInfo; + DisplayModeEx& dm = si.displayMode; + + uint16 hds = dm.h_display_start; // current horizontal starting pixel + uint16 vds = dm.v_display_start; // current vertical starting line + + // Clamp cursor to virtual display. + if (x >= dm.virtual_width) + x = dm.virtual_width - 1; + if (y >= dm.virtual_height) + y = dm.virtual_height - 1; + + // Adjust h/v display start to move cursor onto screen. + if (x >= (dm.timing.h_display + hds)) + hds = x - dm.timing.h_display + 1; + else if (x < hds) + hds = x; + + if (y >= (dm.timing.v_display + vds)) + vds = y - dm.timing.v_display + 1; + else if (y < vds) + vds = y; + + // Reposition the desktop on the display if required. + if (hds != dm.h_display_start || vds != dm.v_display_start) + MoveDisplay(hds, vds); + + // Put cursor in correct physical position. + x -= (hds + si.cursor.hot_x); + y -= (vds + si.cursor.hot_y); + + // Position the cursor on the display. + gInfo.SetCursorPosition(x, y); +} + diff --git a/src/add-ons/accelerants/s3/engine.cpp b/src/add-ons/accelerants/s3/engine.cpp new file mode 100644 index 0000000000..d9834ea8ef --- /dev/null +++ b/src/add-ons/accelerants/s3/engine.cpp @@ -0,0 +1,79 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Gerald Zajac 2007 +*/ + +#include "accel.h" + + +static engine_token engineToken = { 1, B_2D_ACCELERATION, NULL }; + + +uint32 +AccelerantEngineCount(void) +{ + return 1; +} + + +status_t +AcquireEngine(uint32 capabilities, uint32 max_wait, + sync_token* st, engine_token** et) +{ + (void)capabilities; // avoid compiler warning for unused arg + (void)max_wait; // avoid compiler warning for unused arg + + // Acquire the shared benaphore. + AQUIRE_BEN(gInfo.sharedInfo->engine.lock) + // Sync if required. + if (st) + SyncToToken(st); + + // Return an engine token. + *et = &engineToken; + return B_OK; +} + + +status_t +ReleaseEngine(engine_token* et, sync_token* st) +{ + // Update the sync token, if any. + if (st) + GetSyncToken(et, st); + + // Release the shared benaphore. + RELEASE_BEN(gInfo.sharedInfo->engine.lock) + return B_OK; +} + + +void +WaitEngineIdle(void) +{ + gInfo.WaitIdleEmpty(); // wait until engine is completely idle +} + + +status_t +GetSyncToken(engine_token* et, sync_token* st) +{ + // Engine count will always be zero: we don't support syncing to token (yet). + st->engine_id = et->engine_id; + st->counter = gInfo.sharedInfo->engine.count; + return B_OK; +} + + +status_t +SyncToToken(sync_token* st) +{ + (void)st; // avoid compiler warning for unused arg + + WaitEngineIdle(); + return B_OK; +} + diff --git a/src/add-ons/accelerants/s3/hooks.cpp b/src/add-ons/accelerants/s3/hooks.cpp new file mode 100644 index 0000000000..8beed5ddfb --- /dev/null +++ b/src/add-ons/accelerants/s3/hooks.cpp @@ -0,0 +1,69 @@ +/* + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + +#include "accel.h" + + +extern "C" void* +get_accelerant_hook(uint32 feature, void* data) +{ + (void)data; // avoid compiler warning for unused arg + + switch (feature) { + // General + case B_INIT_ACCELERANT: return (void*)InitAccelerant; + case B_UNINIT_ACCELERANT: return (void*)UninitAccelerant; + case B_CLONE_ACCELERANT: return (void*)CloneAccelerant; + case B_ACCELERANT_CLONE_INFO_SIZE: return (void*)AccelerantCloneInfoSize; + case B_GET_ACCELERANT_CLONE_INFO: return (void*)GetAccelerantCloneInfo; + case B_GET_ACCELERANT_DEVICE_INFO: return (void*)GetAccelerantDeviceInfo; + case B_ACCELERANT_RETRACE_SEMAPHORE: return (void*)AccelerantRetraceSemaphore; + + // Mode Configuration + case B_ACCELERANT_MODE_COUNT: return (void*)AccelerantModeCount; + case B_GET_MODE_LIST: return (void*)GetModeList; + case B_PROPOSE_DISPLAY_MODE: return (void*)ProposeDisplayMode; + case B_SET_DISPLAY_MODE: return (void*)SetDisplayMode; + case B_GET_DISPLAY_MODE: return (void*)GetDisplayMode; +#ifdef __HAIKU__ + case B_GET_PREFERRED_DISPLAY_MODE: return (void*)GetPreferredDisplayMode; + case B_GET_EDID_INFO: return (void*)GetEdidInfo; +#endif + case B_GET_FRAME_BUFFER_CONFIG: return (void*)GetFrameBufferConfig; + case B_GET_PIXEL_CLOCK_LIMITS: return (void*)GetPixelClockLimits; + case B_MOVE_DISPLAY: return (void*)MoveDisplay; + case B_SET_INDEXED_COLORS: return (void*)(gInfo.SetIndexedColors); + case B_GET_TIMING_CONSTRAINTS: return (void*)GetTimingConstraints; + + // DPMS + case B_DPMS_CAPABILITIES: return (void*)(gInfo.DPMSCapabilities); + case B_DPMS_MODE: return (void*)(gInfo.DPMSMode); + case B_SET_DPMS_MODE: return (void*)(gInfo.SetDPMSMode); + + // Cursor + case B_SET_CURSOR_SHAPE: return (void*)SetCursorShape; + case B_MOVE_CURSOR: return (void*)MoveCursor; + case B_SHOW_CURSOR: return (void*)(gInfo.ShowCursor); + + // Engine Management + case B_ACCELERANT_ENGINE_COUNT: return (void*)AccelerantEngineCount; + case B_ACQUIRE_ENGINE: return (void*)AcquireEngine; + case B_RELEASE_ENGINE: return (void*)ReleaseEngine; + case B_WAIT_ENGINE_IDLE: return (void*)WaitEngineIdle; + case B_GET_SYNC_TOKEN: return (void*)GetSyncToken; + case B_SYNC_TO_TOKEN: return (void*)SyncToToken; + + // 2D acceleration + case B_SCREEN_TO_SCREEN_BLIT: return (void*)(gInfo.ScreenToScreenBlit); + case B_FILL_RECTANGLE: return (void*)(gInfo.FillRectangle); + case B_INVERT_RECTANGLE: return (void*)(gInfo.InvertRectangle); + case B_FILL_SPAN: return (void*)(gInfo.FillSpan); + } + + return NULL; // Return null pointer for any feature not handled above +} diff --git a/src/add-ons/accelerants/s3/mode.cpp b/src/add-ons/accelerants/s3/mode.cpp new file mode 100644 index 0000000000..749fe7075d --- /dev/null +++ b/src/add-ons/accelerants/s3/mode.cpp @@ -0,0 +1,470 @@ +/* + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" + +#include + + + +void +InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[], + uint8& cr3b, uint8& cr3c, uint8& cr5d, uint8& cr5e) +{ + // Initialize the timing values for CRTC registers cr00 to cr18 and cr3a, + // cr3b, cr5d, and cr5e. Note that the number following the letters 'cr' + // is a hexadecimal number. Argument crtc will contain registers cr00 to + // cr18; thus, it must contain at least 25 (0x19) elements. + + // Normally the horizontal timing values are divided by 8; however, some + // chips require the horizontal timings to be doubled when the color depth + // is 16 bpp. The horizontal scale factor is used for this purpose. + + int hTotal = (mode.timing.h_total * horzScaleFactor) / 8 - 5; + int hDisp_e = (mode.timing.h_display * horzScaleFactor) / 8 - 1; + int hSync_s = (mode.timing.h_sync_start * horzScaleFactor) / 8; + int hSync_e = (mode.timing.h_sync_end * horzScaleFactor) / 8; + int hBlank_s = hDisp_e; // start of horizontal blanking + int hBlank_e = hTotal; // end of horizontal blanking + + int vTotal = mode.timing.v_total - 2; + int vDisp_e = mode.timing.v_display - 1; + int vSync_s = mode.timing.v_sync_start; + int vSync_e = mode.timing.v_sync_end; + int vBlank_s = vDisp_e; // start of vertical blanking + int vBlank_e = vTotal; // end of vertical blanking + + TRACE("InitCrtcTimingValues()\n"); + + // CRTC Controller values + + crtc[0x00] = hTotal; + crtc[0x01] = hDisp_e; + crtc[0x02] = hBlank_s; + crtc[0x03] = (hBlank_e & 0x1f) | 0x80; + crtc[0x04] = hSync_s; + crtc[0x05] = ((hSync_e & 0x1f) | ((hBlank_e & 0x20) << 2)); + crtc[0x06] = vTotal; + crtc[0x07] = (((vTotal & 0x100) >> 8) + | ((vDisp_e & 0x100) >> 7) + | ((vSync_s & 0x100) >> 6) + | ((vBlank_s & 0x100) >> 5) + | 0x10 + | ((vTotal & 0x200) >> 4) + | ((vDisp_e & 0x200) >> 3) + | ((vSync_s & 0x200) >> 2)); + + crtc[0x08] = 0x00; + crtc[0x09] = ((vBlank_s & 0x200) >> 4) | 0x40; + crtc[0x0a] = 0x00; + crtc[0x0b] = 0x00; + crtc[0x0c] = 0x00; + crtc[0x0d] = 0x00; + crtc[0x0e] = 0x00; + crtc[0x0f] = 0x00; + crtc[0x10] = vSync_s; + crtc[0x11] = (vSync_e & 0x0f) | 0x20; + crtc[0x12] = vDisp_e; + crtc[0x13] = mode.bytesPerRow / 8; + crtc[0x14] = 0x00; + crtc[0x15] = vBlank_s; + crtc[0x16] = vBlank_e; + crtc[0x17] = 0xc3; + crtc[0x18] = 0xff; + + int i = ((hTotal & 0x100) >> 8) | + ((hDisp_e & 0x100) >> 7) | + ((hBlank_s & 0x100) >> 6) | + ((hSync_s & 0x100) >> 4); + + if (hSync_e - hSync_s > 64) + i |= 0x08; // add another 64 DCLKs to blank pulse width + + if (hSync_e - hSync_s > 32) + i |= 0x20; // add another 32 DCLKs to hsync pulse width + + int j = (crtc[0] + ((i & 0x01) << 8) + crtc[4] + ((i & 0x10) << 4) + 1) / 2; + + if (j - (crtc[4] + ((i & 0x10) << 4)) < 4) { + if (crtc[4] + ((i & 0x10) << 4) + 4 <= crtc[0] + ((i & 0x01) << 8)) + j = crtc[4] + ((i & 0x10) << 4) + 4; + else + j = crtc[0] + ((i & 0x01) << 8) + 1; + } + + cr3b = j & 0xff; + i |= (j & 0x100) >> 2; + cr3c = (crtc[0] + ((i & 0x01) << 8)) / 2; + cr5d = i; + + cr5e = ((vTotal & 0x400) >> 10) | + ((vDisp_e & 0x400) >> 9) | + ((vBlank_s & 0x400) >> 8) | + ((vSync_s & 0x400) >> 6) | 0x40; +} + + +static display_mode* +FindDisplayMode(int width, int height, int refreshRate, uint32 colorDepth) +{ + // Search the mode list for the mode with specified width, height, + // refresh rate, and color depth. If argument colorDepth is zero, this + // function will search for a mode satisfying the other 3 arguments, and + // if more than one matching mode is found, the one with the greatest color + // depth will be selected. + // + // If successful, return a pointer to the selected display_mode object; + // else return NULL. + + display_mode* selectedMode = NULL; + uint32 modeCount = gInfo.sharedInfo->modeCount; + + for (uint32 j = 0; j < modeCount; j++) { + display_mode& mode = gInfo.modeList[j]; + + if (mode.timing.h_display == width && mode.timing.v_display == height) { + int modeRefreshRate = int(((mode.timing.pixel_clock * 1000.0 / + mode.timing.h_total) / mode.timing.v_total) + 0.5); + if (modeRefreshRate == refreshRate) { + if (colorDepth == 0) { + if (selectedMode == NULL || mode.space > selectedMode->space) + selectedMode = &mode; + } else { + if (mode.space == colorDepth) + return &mode; + } + } + } + } + + return selectedMode; +} + + +bool +IsModeUsable(const display_mode* mode) +{ + // Test if the display mode is usable by the current video chip. That is, + // does the chip have enough memory for the mode and is the pixel clock + // within the chips allowable range, etc. + // + // Return true if the mode is usable. + + SharedInfo& si = *gInfo.sharedInfo; + uint32 bitsPerPixel; + uint32 maxPixelClock; + + if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock)) + return false; + + // Is there enough memory to handle the mode? + + if (mode->virtual_width * mode->virtual_height * ((bitsPerPixel + 7) / 8) + > si.maxFrameBufferSize) + return false; + + if (mode->timing.pixel_clock > maxPixelClock) + return false; + + // Is the color space supported? + + bool bColorSpaceSupported = false; + for (uint32 j = 0; j < si.colorSpaceCount; j++) { + if (mode->space == uint32(si.colorSpaces[j])) { + bColorSpaceSupported = true; + break; + } + } + + if ( ! bColorSpaceSupported) + return false; + + // Reject modes with a width of 640 and a height < 480 since they do not + // work properly with the S3 chipsets. + + if (mode->timing.h_display == 640 && mode->timing.v_display < 480) + return false; + + // In most mode lists, there are three entries for 640 x 480 which have a + // refresh rate of 60 Hz. The one with a pixel clock of 25175 works fine + // with the S3 chips; however, the other two with higher clock rates + // cause the display to be offset down and to the right; thus, reject them. + + if (mode->timing.h_display == 640 && mode->timing.v_display == 480) { + int modeRefreshRate = int(((mode->timing.pixel_clock * 1000.0 / + mode->timing.h_total) / mode->timing.v_total) + 0.5); + if (modeRefreshRate == 60 && mode->timing.pixel_clock > 26000) + return false; + } + + // If the video is connected directly to an LCD display (ie, laptop + // computer), restrict the display mode to resolutions where the width and + // height of the mode are less than or equal to the width and height of the + // LCD display. Note that this code is not needed under Haiku since it can + // get the preferred mode which should be the resolution of the LCD display. + +#ifndef __HAIKU__ + + if (si.displayType == MT_LCD && si.panelX > 0 && si.panelY > 0 && + (mode->timing.h_display > si.panelX + || mode->timing.v_display > si.panelY)) { + return false; + } + +#endif // __HAIKU__ + + return true; +} + + +status_t +CreateModeList(bool (*checkMode)(const display_mode* mode)) +{ + SharedInfo& si = *gInfo.sharedInfo; + display_mode* list; + uint32 count = 0; + area_id listArea; + + listArea = create_display_modes("S3 modes", + si.bHaveEDID ? &si.edidInfo : NULL, + NULL, 0, si.colorSpaces, si.colorSpaceCount, checkMode, + &list, &count); + + if (listArea < 0) + return listArea; // listArea has error code + + si.modeArea = gInfo.modeListArea = listArea; + si.modeCount = count; + gInfo.modeList = list; + + return B_OK; +} + + + +status_t +ProposeDisplayMode(display_mode *target, const display_mode *low, + const display_mode *high) +{ + (void)low; // avoid compiler warning for unused arg + (void)high; // avoid compiler warning for unused arg + + TRACE("ProposeDisplayMode() clock: %d, width: %d, height: %d, space: 0x%X\n", + target->timing.pixel_clock, target->virtual_width, target->virtual_height, + target->space); + + // Search the mode list for the specified mode. + + uint32 modeCount = gInfo.sharedInfo->modeCount; + + for (uint32 j = 0; j < modeCount; j++) { + display_mode& mode = gInfo.modeList[j]; + + if (target->timing.h_display == mode.timing.h_display + && target->timing.v_display == mode.timing.v_display + && target->space == mode.space) + return B_OK; // mode found in list + } + + return B_BAD_VALUE; // mode not found in list +} + + +status_t +SetDisplayMode(display_mode* pMode) +{ + // First validate the mode, then call a function to set the registers. + + TRACE("SetDisplayMode() begin\n"); + + SharedInfo& si = *gInfo.sharedInfo; + DisplayModeEx mode; + (display_mode&)mode = *pMode; + + uint32 maxPixelClock; + if ( ! gInfo.GetColorSpaceParams(mode.space, mode.bpp, maxPixelClock)) + return B_ERROR; + + mode.bytesPerRow = mode.virtual_width * ((mode.bpp + 7) / 8); // use virtual width + + if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK) + return B_ERROR; + + // Test if there is sufficient memory for this mode. Use the virtual width + // and height for this calculation since one or both might be greater than + // the actual dimensions of the mode. + + if (mode.bytesPerRow * mode.virtual_height > si.maxFrameBufferSize) + return B_ERROR; + + TRACE("Display Mode: width = %d, height = %d, depth = %d\n", + mode.virtual_width, mode.virtual_height, mode.bpp); + + TRACE("Mode Timing = { %d %d %d %d %d %d %d %d %d 0x%x }\n", + mode.timing.pixel_clock, + mode.timing.h_display, mode.timing.h_sync_start, mode.timing.h_sync_end, + mode.timing.h_total, + mode.timing.v_display, mode.timing.v_sync_start, mode.timing.v_sync_end, + mode.timing.v_total, mode.timing.flags); + + if ( ! gInfo.SetDisplayMode(mode)) + return B_ERROR; + + si.displayMode = mode; + + TRACE("SetDisplayMode() done\n"); + return B_OK; +} + + + +status_t +MoveDisplay(uint16 horizontalStart, uint16 verticalStart) +{ + // Set which pixel of the virtual frame buffer will show up in the + // top left corner of the display device. Used for page-flipping + // games and virtual desktops. + + DisplayModeEx& mode = gInfo.sharedInfo->displayMode; + + if (mode.timing.h_display + horizontalStart > mode.virtual_width + || mode.timing.v_display + verticalStart > mode.virtual_height) + return B_ERROR; + + mode.h_display_start = horizontalStart; + mode.v_display_start = verticalStart; + + gInfo.AdjustFrame(mode); + return B_OK; +} + + +uint32 +AccelerantModeCount(void) +{ + // Return the number of display modes in the mode list. + + return gInfo.sharedInfo->modeCount; +} + + +status_t +GetModeList(display_mode* dmList) +{ + // Copy the list of supported video modes to the location pointed at + // by dmList. + + memcpy(dmList, gInfo.modeList, gInfo.sharedInfo->modeCount * sizeof(display_mode)); + return B_OK; +} + + +status_t +GetDisplayMode(display_mode* current_mode) +{ + *current_mode = gInfo.sharedInfo->displayMode; // return current display mode + return B_OK; +} + + +status_t +GetFrameBufferConfig(frame_buffer_config* pFBC) +{ + SharedInfo& si = *gInfo.sharedInfo; + + pFBC->frame_buffer = (void*)((addr_t)si.videoMemAddr + si.frameBufferOffset); + pFBC->frame_buffer_dma = (void*)((addr_t)si.videoMemPCI + si.frameBufferOffset); + pFBC->bytes_per_row = si.displayMode.bytesPerRow; + + return B_OK; +} + + +status_t +GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high) +{ + // Return the maximum and minium pixel clock limits for the specified mode. + + uint32 bitsPerPixel; + uint32 maxPixelClock; + + if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock)) + return B_ERROR; + + if (low != NULL) { + // lower limit of about 48Hz vertical refresh + uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total; + uint32 lowClock = (totalClocks * 48L) / 1000L; + if (lowClock > maxPixelClock) + return B_ERROR; + + *low = lowClock; + } + + if (high != NULL) + *high = maxPixelClock; + + return B_OK; +} + + +status_t +GetTimingConstraints(display_timing_constraints *constraints) +{ + (void)constraints; // avoid compiler warning for unused arg + + TRACE("GetTimingConstraints() called\n"); + return B_ERROR; +} + + +status_t +GetPreferredDisplayMode(display_mode* preferredMode) +{ + // If the chip is connected to a laptop LCD panel, find the mode with + // matching width and height, 60 Hz refresh rate, and greatest color depth. + + TRACE("GetPreferredDisplayMode()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + if (si.displayType == MT_LCD) { + display_mode* mode = FindDisplayMode(si.panelX, si.panelY, 60, 0); + + if (mode != NULL) { + *preferredMode = *mode; + return B_OK; + } + } + + return B_ERROR; +} + + + +#ifdef __HAIKU__ + +status_t +GetEdidInfo(void* info, size_t size, uint32* _version) +{ + TRACE("GetEdidInfo()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + if ( ! si.bHaveEDID) + return B_ERROR; + + if (size < sizeof(struct edid1_info)) + return B_BUFFER_OVERFLOW; + + memcpy(info, &si.edidInfo, sizeof(struct edid1_info)); + *_version = EDID_VERSION_1; + return B_OK; +} + +#endif // __HAIKU__ diff --git a/src/add-ons/accelerants/s3/register_io.cpp b/src/add-ons/accelerants/s3/register_io.cpp new file mode 100644 index 0000000000..930e9e62de --- /dev/null +++ b/src/add-ons/accelerants/s3/register_io.cpp @@ -0,0 +1,245 @@ +/* + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + +#include "accel.h" + +#include + + +// Macros for memory mapped I/O. +//============================== + +#define INREG8(addr) *((vuint8*)(gInfo.regs + addr)) +#define INREG16(addr) *((vuint16*)(gInfo.regs + addr)) +#define INREG32(addr) *((vuint32*)(gInfo.regs + addr)) + +#define OUTREG8(addr, val) *((vuint8*)(gInfo.regs + addr)) = val +#define OUTREG16(addr, val) *((vuint16*)(gInfo.regs + addr)) = val +#define OUTREG32(addr, val) *((vuint32*)(gInfo.regs + addr)) = val + + +// Functions for PIO. +//=================== + +uint32 ReadPIO(uint32 addr, uint8 numBytes) +{ + S3GetSetPIO gsp; + gsp.magic = S3_PRIVATE_DATA_MAGIC; + gsp.offset = addr; + gsp.size = numBytes; + gsp.value = 0; + + status_t result = ioctl(gInfo.deviceFileDesc, S3_GET_PIO, &gsp, sizeof(gsp)); + if (result != B_OK) + TRACE("ReadPIO() failed, result = 0x%x\n", result); + + return gsp.value; +} + + +void WritePIO(uint32 addr, uint8 numBytes, uint32 value) +{ + S3GetSetPIO gsp; + gsp.magic = S3_PRIVATE_DATA_MAGIC; + gsp.offset = addr; + gsp.size = numBytes; + gsp.value = value; + + status_t result = ioctl(gInfo.deviceFileDesc, S3_SET_PIO, &gsp, sizeof(gsp)); + if (result != B_OK) + TRACE("WritePIO() failed, result = 0x%x\n", result); +} + + +// Functions to read 8/16/32 bit registers. +//========================================= + +uint8 ReadReg8(uint32 addr) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + return ReadPIO(addr, 1); + + return INREG8(addr); +} + + +uint16 ReadReg16(uint32 addr) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + return ReadPIO(addr, 2); + + return INREG16(addr); +} + + +uint32 ReadReg32(uint32 addr) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + return ReadPIO(addr, 4); + + return INREG32(addr); +} + + +// Functions to write 8/16/32 bit registers. +//========================================= + +void WriteReg8(uint32 addr, uint8 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + WritePIO(addr, 1, value); + else + OUTREG8(addr, value); +} + + +void WriteReg16(uint32 addr, uint16 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + WritePIO(addr, 2, value); + else + OUTREG16(addr, value); +} + + +void WriteReg32(uint32 addr, uint32 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + WritePIO(addr, 4, value); + else + OUTREG32(addr, value); +} + + +// Functions to read/write CRTC registers. +//======================================== + +uint8 ReadCrtcReg(uint8 index) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3d4, index); + return ReadPIO_8(0x3d5); + } + + OUTREG8(0x83d4, index); + return INREG8(0x83d5); +} + + +void WriteCrtcReg(uint8 index, uint8 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3d4, index); + WritePIO_8(0x3d5, value); + } else { + OUTREG8(0x83d4, index); + OUTREG8(0x83d5, value); + } +} + + +void WriteCrtcReg(uint8 index, uint8 value, uint8 mask) +{ + // Write a value to a CRTC reg using a mask. The mask selects the + // bits to be modified. + + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3d4, index); + WritePIO_8(0x3d5, (ReadPIO_8(0x3d5) & ~mask) | (value & mask)); + } else { + OUTREG8(0x83d4, index); + OUTREG8(0x83d5, (INREG8(0x83d5) & ~mask) | (value & mask)); + } +} + + +// Functions to read/write Sequence registers. +//============================================ + +uint8 ReadSeqReg(uint8 index) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3c4, index); + return ReadPIO_8(0x3c5); + } + + OUTREG8(0x83c4, index); + return INREG8(0x83c5); +} + + +void WriteSeqReg(uint8 index, uint8 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3c4, index); + WritePIO_8(0x3c5, value); + } else { + OUTREG8(0x83c4, index); + OUTREG8(0x83c5, value); + } +} + + +void WriteSeqReg(uint8 index, uint8 value, uint8 mask) +{ + // Write a value to a Sequencer reg using a mask. The mask selects the + // bits to be modified. + + if (gInfo.sharedInfo->chipType == S3_TRIO64) { + WritePIO_8(0x3c4, index); + WritePIO_8(0x3c5, (ReadPIO_8(0x3c5) & ~mask) | (value & mask)); + } else { + OUTREG8(0x83c4, index); + OUTREG8(0x83c5, (INREG8(0x83c5) & ~mask) | (value & mask)); + } +} + + +// Functions to read/write the misc output register. +//================================================== + +uint8 ReadMiscOutReg() +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + return ReadPIO_8(0x3cc); + + return INREG8(0x83cc); +} + + +void WriteMiscOutReg(uint8 value) +{ + if (gInfo.sharedInfo->chipType == S3_TRIO64) + WritePIO_8(0x3c2, value); + else + OUTREG8(0x83c2, value); +} + + +void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue) +{ + // Write an indexed color. Argument index is the index (0-255) of the + // color, and arguments red, green, & blue are the components of the color. + + // Note that although the Trio64V+ chip supports MMIO in nearly all areas, + // it does not support MMIO for setting indexed colors; thus, use PIO to + // set the indexed color. + + if (gInfo.sharedInfo->chipType == S3_TRIO64 + || gInfo.sharedInfo->chipType == S3_TRIO64_VP) { + WritePIO_8(0x3c8, index); // color index + WritePIO_8(0x3c9, red); + WritePIO_8(0x3c9, green); + WritePIO_8(0x3c9, blue); + } else { + OUTREG8(0x83c8, index); // color index + OUTREG8(0x83c9, red); + OUTREG8(0x83c9, green); + OUTREG8(0x83c9, blue); + } +} diff --git a/src/add-ons/accelerants/s3/register_io.h b/src/add-ons/accelerants/s3/register_io.h new file mode 100644 index 0000000000..0be1fe7024 --- /dev/null +++ b/src/add-ons/accelerants/s3/register_io.h @@ -0,0 +1,59 @@ +/* + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + +#ifndef __REGISTER_IO_H__ +#define __REGISTER_IO_H__ + + +// PIO address of various VGA registers. If accessing these registers using +// MMIO, add 0x8000 to thses addresses. + +#define VGA_ENABLE 0x3c3 +#define MISC_OUT_R 0x3cc // read +#define MISC_OUT_W 0x3c2 // write +#define CRTC_INDEX 0x3d4 +#define CRTC_DATA 0x3d5 +#define SEQ_INDEX 0x3c4 +#define SEQ_DATA 0x3c5 + + +// Prototypes of I/O functions for accessing registers using PIO. + +uint32 ReadPIO(uint32 addr, uint8 numBytes); +void WritePIO(uint32 addr, uint8 numBytes, uint32 value); + +inline uint8 ReadPIO_8(uint32 addr) { return ReadPIO(addr, 1); } +inline void WritePIO_8(uint32 addr, uint8 value) { WritePIO(addr, 1, value); } + + +// Prototypes of I/O functions for accessing registers using PIO or MMIO +// depending upon the type of S3 chip. + +uint8 ReadReg8(uint32 addr); +uint16 ReadReg16(uint32 addr); +uint32 ReadReg32(uint32 addr); + +void WriteReg8(uint32 addr, uint8 value); +void WriteReg16(uint32 addr, uint16 value); +void WriteReg32(uint32 addr, uint32 value); + +uint8 ReadCrtcReg(uint8 index); +void WriteCrtcReg(uint8 index, uint8 value); +void WriteCrtcReg(uint8 index, uint8 value, uint8 mask); + +uint8 ReadSeqReg(uint8 index); +void WriteSeqReg(uint8 index, uint8 value); +void WriteSeqReg(uint8 index, uint8 value, uint8 mask); + +uint8 ReadMiscOutReg(); +void WriteMiscOutReg(uint8 value); + +void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue); + + +#endif // __REGISTER_IO_H__ diff --git a/src/add-ons/accelerants/s3/savage.h b/src/add-ons/accelerants/s3/savage.h new file mode 100644 index 0000000000..b03e6482ca --- /dev/null +++ b/src/add-ons/accelerants/s3/savage.h @@ -0,0 +1,116 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2006-2008 +*/ + +#ifndef __SAVAGE_H__ +#define __SAVAGE_H__ + + + +#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory + +#define ADVANCED_FUNC_CTRL 0x850C +#define SYSTEM_CONTROL_REG 0x83DA + + +// Stream Processor 1. + +// Primary Stream 1 Frame Buffer Address 0. +#define PRI_STREAM_FBUF_ADDR0 0x81c0 +// Primary Stream 1 Frame Buffer Address 1. +#define PRI_STREAM_FBUF_ADDR1 0x81c4 +// Primary Stream 1 Stride. +#define PRI_STREAM_STRIDE 0x81c8 + +// Stream Processor 2. + +// Primary Stream 2 Frame Buffer Address 0. +#define PRI_STREAM2_FBUF_ADDR0 0x81b0 +// Primary Stream 2 Frame Buffer Address 1. +#define PRI_STREAM2_FBUF_ADDR1 0x81b4 +// Primary Stream 2 Stride. +#define PRI_STREAM2_STRIDE 0x81b8 + +#define MEMORY_CTRL0_REG 0xCA +#define MEMORY_CONFIG_REG 0x31 + +// Bitmap descriptor register. +#define S3_GLB_BD_LOW 0x8168 +#define S3_GLB_BD_HIGH 0x816C +#define S3_PRI_BD_LOW 0x8170 +#define S3_PRI_BD_HIGH 0x8174 +#define S3_SEC_BD_LOW 0x8178 +#define S3_SEC_BD_HIGH 0x817c + +#define MEM_PS1 0x10 // CRCA_4 :Primary stream 1 +#define MEM_PS2 0x20 // CRCA_5 :Primary stream 2 + +#define SRC_BASE 0xa4d4 +#define DEST_BASE 0xa4d8 +#define CLIP_L_R 0xa4dc +#define CLIP_T_B 0xa4e0 +#define DEST_SRC_STR 0xa4e4 +#define MONO_PAT_0 0xa4e8 +#define MONO_PAT_1 0xa4ec + +#define DISABLE_BLOCK_WRITE_2D 0x10 // CR88_4 =1 : disable block write + +#define STATUS_WORD0 (ReadReg32(0x48C00)) +#define ALT_STATUS_WORD0 (ReadReg32(0x48C60)) +#define MAXFIFO 0x7f00 + +// BCI definitions. +//================= + +#define TILE_FORMAT_LINEAR 0 + +// BD - BCI enable. +#define BCI_ENABLE 8 // savage4, MX, IX, 3D +#define BCI_ENABLE_TWISTER 0 // twister, prosavage, DDR, supersavage, 2000 + +#define S3_BIG_ENDIAN 4 +#define S3_LITTLE_ENDIAN 0 +#define S3_BD64 1 + +#define BCI_BUFFER_OFFSET 0x10000 + +#define BCI_GET_PTR vuint32* bci_ptr = ((uint32*)(gInfo.regs + BCI_BUFFER_OFFSET)) +#define BCI_SEND(dw) (*bci_ptr++ = ((uint32)(dw))) + +#define BCI_CMD_NOP 0x40000000 +#define BCI_CMD_RECT 0x48000000 +#define BCI_CMD_RECT_XP 0x01000000 +#define BCI_CMD_RECT_YP 0x02000000 +#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF) +#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) + +#define BCI_CMD_SEND_COLOR 0x00008000 +#define BCI_CMD_DEST_PBD_NEW 0x00000C00 +#define BCI_CMD_SRC_SOLID 0x00000000 +#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140 + +#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF) +#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF) + + +static inline void VerticalRetraceWait() +{ + if (ReadCrtcReg(0x17) & 0x80) { + int i = 0x10000; + while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ; + i = 0x10000; + while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ; + } +} + + +#endif // __SAVAGE_H__ diff --git a/src/add-ons/accelerants/s3/savage_cursor.cpp b/src/add-ons/accelerants/s3/savage_cursor.cpp new file mode 100644 index 0000000000..3e613fbd5a --- /dev/null +++ b/src/add-ons/accelerants/s3/savage_cursor.cpp @@ -0,0 +1,144 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2006-2008 +*/ + + +#include "accel.h" +#include "savage.h" + + + +// Certain HW cursor operations seem to require a delay to prevent lockups. + +static void +WaitHSync(int n) +{ + while (n--) { + while (ReadReg8(SYSTEM_CONTROL_REG) & 0x01) {}; + while ( ! ReadReg8(SYSTEM_CONTROL_REG) & 0x01) {}; + } +} + + +void +Savage_ShowCursor(bool bShow) +{ + // Turn cursor on/off. + + if ( ! bShow && S3_SAVAGE4_SERIES(gInfo.sharedInfo->chipType)) + WaitHSync(5); + + WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01); +} + + +void +Savage_SetCursorPosition(int x, int y) +{ + SharedInfo& si = *gInfo.sharedInfo; + + if (S3_SAVAGE4_SERIES(si.chipType)) + WaitHSync(5); + + // xOffset & yOffset are used for displaying partial cursors on screen edges. + + uint8 xOffset = 0; + uint8 yOffset = 0; + + if (x < 0) { + xOffset = (( -x) & 0xFE); + x = 0; + } + + if (y < 0) { + yOffset = (( -y) & 0xFE); + y = 0; + } + + + // Note: when setting the cursor position, register 48 must be set last + // since setting register 48 activates the new cursor position. + + WriteCrtcReg( 0x4e, xOffset ); + WriteCrtcReg( 0x4f, yOffset ); + + WriteCrtcReg( 0x47, (x & 0xff) ); + WriteCrtcReg( 0x46, (x & 0x0700) >> 8 ); + + WriteCrtcReg( 0x49, (y & 0xff) ); + WriteCrtcReg( 0x48, (y & 0x0700) >> 8 ); +} + + +bool +Savage_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask) +{ + SharedInfo& si = *gInfo.sharedInfo; + + if (andMask == NULL || xorMask == NULL) + return false; + + // Initialize the hardware cursor as completely transparent. + + uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int i = 0; i < CURSOR_BYTES; i += 4) { + *fbCursor16++ = ~0; // and bits + *fbCursor16++ = 0; // xor bits + } + + // Now load the AND & XOR masks for the cursor image into the cursor + // buffer. Note that a particular bit in these masks will have the + // following effect upon the corresponding cursor pixel: + // AND XOR Result + // 0 0 White pixel + // 0 1 Black pixel + // 1 0 Screen color (for transparency) + // 1 1 Reverse screen color to black or white + + uint8* fbCursor = (uint8*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int row = 0; row < height; row++) { + for (int colByte = 0; colByte < width / 8; colByte++) { + fbCursor[row * 16 + colByte] = *andMask++; + fbCursor[row * 16 + colByte + 2] = *xorMask++; + } + } + + if (S3_SAVAGE4_SERIES(si.chipType)) { + + // Bug in Savage4 Rev B requires us to do an MMIO read after + // loading the cursor. + + volatile unsigned int k = ALT_STATUS_WORD0; + (void)k++; // Not to be optimised out + } + + // Set cursor location in video memory. + + WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024)); + WriteCrtcReg(0x4c, (0xff00 & si.cursorOffset / 1024) >> 8); + + // Set the cursor colors which are black foreground and white background. + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes + WriteCrtcReg(0x4a, 0); + WriteCrtcReg(0x4a, 0); + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes + WriteCrtcReg(0x4b, ~0); + WriteCrtcReg(0x4b, ~0); + + return true; +} diff --git a/src/add-ons/accelerants/s3/savage_dpms.cpp b/src/add-ons/accelerants/s3/savage_dpms.cpp new file mode 100644 index 0000000000..10f737317f --- /dev/null +++ b/src/add-ons/accelerants/s3/savage_dpms.cpp @@ -0,0 +1,118 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2006-2008 +*/ + + +#include "accel.h" +#include "savage.h" + + + +uint32 +Savage_DPMSCapabilities(void) +{ + // Return DPMS modes supported by this device. + + return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; +} + + +uint32 +Savage_DPMSMode(void) +{ + // Return the current DPMS mode. + + // Note: I do not know whether the following code is correctly reading + // the current DPMS mode. I'm assuming that reading back the bits that + // were set by function SET_DPMS_MODE will give the current DPMS mode. + + SharedInfo& si = *gInfo.sharedInfo; + uint32 mode = B_DPMS_ON; + + if (si.displayType == MT_CRT) { + switch (ReadSeqReg(0x0d) & 0x70) { + case 0: + mode = B_DPMS_ON; + break; + case 0x10: + mode = B_DPMS_STAND_BY; + break; + case 0x40: + mode = B_DPMS_SUSPEND; + break; + case 0x50: + mode = B_DPMS_OFF; + break; + default: + TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d)); + } + } else if (si.displayType == MT_LCD || si.displayType == MT_DFP) { + mode = ((ReadSeqReg(0x31) & 0x10) ? B_DPMS_ON : B_DPMS_OFF); + } + + TRACE("Savage_DPMSMode() mode: %d\n", mode); + return mode; +} + + +status_t +Savage_SetDPMSMode(uint32 dpmsMode) +{ + // Set the display into one of the Display Power Management modes, + // and return B_OK if successful, else return B_ERROR. + + SharedInfo& si = *gInfo.sharedInfo; + + TRACE("Savage_SetDPMSMode() mode: %d, display type: %d\n", dpmsMode, si.displayType); + + if (si.displayType == MT_CRT) { + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 sr0D = ReadSeqReg(0x0d) & 0x03; + + switch (dpmsMode) { + case B_DPMS_ON: + break; + case B_DPMS_STAND_BY: + sr0D |= 0x10; + break; + case B_DPMS_SUSPEND: + sr0D |= 0x40; + break; + case B_DPMS_OFF: + sr0D |= 0x50; + break; + default: + TRACE("Invalid DPMS mode %d\n", dpmsMode); + return B_ERROR; + } + + WriteSeqReg(0x0d, sr0D); + } else if (si.displayType == MT_LCD || si.displayType == MT_DFP) { + switch (dpmsMode) { + case B_DPMS_ON: + WriteSeqReg(0x31, 0x10, 0x10); // SR31 bit 4 - FP enable + break; + case B_DPMS_STAND_BY: + case B_DPMS_SUSPEND: + case B_DPMS_OFF: + WriteSeqReg(0x31, 0x00, 0x10); // SR31 bit 4 - FP enable + break; + default: + TRACE("Invalid DPMS mode %d\n", dpmsMode); + return B_ERROR; + } + } + + return B_OK; +} + diff --git a/src/add-ons/accelerants/s3savage/Acceleration.c b/src/add-ons/accelerants/s3/savage_draw.cpp similarity index 71% rename from src/add-ons/accelerants/s3savage/Acceleration.c rename to src/add-ons/accelerants/s3/savage_draw.cpp index 4177b4edbd..30161a7565 100644 --- a/src/add-ons/accelerants/s3savage/Acceleration.c +++ b/src/add-ons/accelerants/s3/savage_draw.cpp @@ -4,30 +4,27 @@ Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. Copyright (c) 2003-2006, X.Org Foundation - Copyright 2007 Haiku, Inc. All rights reserved. + Copyright 2007-2008 Haiku, Inc. All rights reserved. Distributed under the terms of the MIT license. Authors: - Gerald Zajac 2006-2007 + Gerald Zajac 2006-2008 */ -#include "GlobalData.h" -#include "AccelerantPrototypes.h" +#include "accel.h" #include "savage.h" void -FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32 count) +Savage_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, uint32 count) { int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_PBD_NEW | BCI_CMD_SRC_SOLID | BCI_CMD_SEND_COLOR; (void)et; // avoid compiler warning for unused arg -// TRACE(("FILL_RECTANGLE, color: %X count: %d\n", color, count)); - BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop while (count--) { @@ -38,11 +35,11 @@ FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32 BCI_GET_PTR; - si->WaitQueue(7); + gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(si->GlobalBD.bd2.LoPart); - BCI_SEND(si->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); BCI_SEND(color); BCI_SEND(BCI_X_Y(x, y)); @@ -54,15 +51,13 @@ FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32 void -FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count) +Savage_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count) { int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_PBD_NEW | BCI_CMD_SRC_SOLID | BCI_CMD_SEND_COLOR; (void)et; // avoid compiler warning for unused arg -// TRACE(("FILL_SPAN, count: %d\n", count)); - BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop while (count--) { @@ -76,15 +71,15 @@ FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count) // spans which the Savage chips display as a line completely across the // screen; thus, the following if statement discards any span with zero // or negative width. - + if (w <= 0) continue; - si->WaitQueue(7); + gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(si->GlobalBD.bd2.LoPart); - BCI_SEND(si->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); BCI_SEND(color); BCI_SEND(BCI_X_Y(x, y)); @@ -94,15 +89,13 @@ FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count) void -INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count) +Savage_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count) { int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_PBD_NEW; (void)et; // avoid compiler warning for unused arg -// TRACE(("INVERT_RECTANGLE, count: %d\n", count)); - BCI_CMD_SET_ROP(cmd, 0x55); // use GXinvert for rop while (count--) { @@ -113,11 +106,11 @@ INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count) BCI_GET_PTR; - si->WaitQueue(7); + gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(si->GlobalBD.bd2.LoPart); - BCI_SEND(si->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); BCI_SEND(BCI_X_Y(x, y)); BCI_SEND(BCI_W_H(w, h)); @@ -128,10 +121,8 @@ INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count) void -SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *pList, uint32 count) +Savage_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count) { -// TRACE(("SCREEN_TO_SCREEN_BLIT\n")); - (void)et; // avoid compiler warning for unused arg while (count--) { @@ -162,15 +153,15 @@ SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *pList, uint32 count) dest_y += height; } - si->WaitQueue(9); + gInfo.WaitQueue(9); BCI_SEND(cmd); - BCI_SEND(si->GlobalBD.bd2.LoPart); - BCI_SEND(si->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); - BCI_SEND(si->GlobalBD.bd2.LoPart); - BCI_SEND(si->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); + BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); BCI_SEND(BCI_X_Y(src_x, src_y)); BCI_SEND(BCI_X_Y(dest_x, dest_y)); diff --git a/src/add-ons/accelerants/s3/savage_edid.cpp b/src/add-ons/accelerants/s3/savage_edid.cpp new file mode 100644 index 0000000000..64c0a63ba7 --- /dev/null +++ b/src/add-ons/accelerants/s3/savage_edid.cpp @@ -0,0 +1,99 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" +#include "savage.h" + +#include +#include +#include + + + +static status_t +GetI2CSignals(void* cookie, int* _clock, int* data) +{ + uint32 index = (uint32)cookie; + uint8 value = ReadCrtcReg(index); + + *_clock = (value & 0x4) != 0; + *data = (value & 0x8) != 0; + return B_OK; +} + + +static status_t +SetI2CSignals(void* cookie, int _clock, int data) +{ + uint32 index = (uint32)cookie; + uint8 value = 0x10; + + if (_clock) + value |= 0x1; + if (data) + value |= 0x2; + + WriteCrtcReg(index, value); + return B_OK; +} + + + +bool +Savage_GetEdidInfo(void) +{ + // Get the EDID info and return true if successful. + + SharedInfo& si = *gInfo.sharedInfo; + + uint32 DDCPort = 0; + + switch (si.chipType) { + case S3_SAVAGE_3D: + case S3_SAVAGE_MX: + case S3_SUPERSAVAGE: + case S3_SAVAGE2000: + DDCPort = 0xAA; + break; + + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_TWISTER: + case S3_PROSAVAGE_DDR: + DDCPort = 0xB1; + break; + } + + i2c_bus bus; + bus.cookie = (void*)DDCPort; + bus.set_signals = &SetI2CSignals; + bus.get_signals = &GetI2CSignals; + ddc2_init_timing(&bus); + + uint8 tmp = ReadCrtcReg(DDCPort); + WriteCrtcReg(DDCPort, tmp | 0x13); + + si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); + + WriteCrtcReg(DDCPort, tmp); + + if (si.bHaveEDID) { +#ifdef ENABLE_DEBUG_TRACE + edid_dump(&(si.edidInfo)); +#endif + } else { + TRACE("Savage_GetEdidInfo() failed!\n"); + } + + return si.bHaveEDID; +} diff --git a/src/add-ons/accelerants/s3/savage_init.cpp b/src/add-ons/accelerants/s3/savage_init.cpp new file mode 100644 index 0000000000..9782568c67 --- /dev/null +++ b/src/add-ons/accelerants/s3/savage_init.cpp @@ -0,0 +1,400 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2006-2008 +*/ + + +#include "accel.h" +#include "savage.h" + + + +static bool +Savage_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock) +{ + // Get parameters for a color space which is supported by the Savage chips. + // Argument maxPixelClock is in KHz. + // Return true if the color space is supported; else return false. + + switch (colorSpace) { + case B_RGB32: + bitsPerPixel = 32; + maxPixelClock = 220000; + break; + case B_RGB16: + bitsPerPixel = 16; + maxPixelClock = 250000; + break; + case B_CMAP8: + bitsPerPixel = 8; + maxPixelClock = 250000; + break; + default: + TRACE("Unsupported color space: 0x%X\n", colorSpace); + return false; + } + + return true; +} + + +// Wait until "v" queue entries are free. + +static void +WaitQueue3D(uint32 v) +{ + uint32 slots = MAXFIFO - v; + while ((STATUS_WORD0 & 0x0000ffff) > slots); +} + + +static void +WaitQueue4(uint32 v) +{ + uint32 slots = MAXFIFO - v; + while ((ALT_STATUS_WORD0 & 0x001fffff) > slots); +} + + +static void +WaitQueue2K(uint32 v) +{ + uint32 slots = MAXFIFO - v; + while ((ALT_STATUS_WORD0 & 0x000fffff) > slots); +} + + +// Wait until GP is idle and queue is empty. + +static void +WaitIdleEmpty3D() +{ + while ((STATUS_WORD0 & 0x0008ffff) != 0x80000); +} + + +static void +WaitIdleEmpty4() +{ + while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ; +} + + +static void +WaitIdleEmpty2K() +{ + while ((ALT_STATUS_WORD0 & 0x009fffff) != 0); +} + + +static bool +IsLCDWidthValid(int width) +{ + // Search the array of valid LCD widths to find a width that matches the + // width by the caller, and return true if a match is found. + + const int lcdWidths[] = { 640, 800, 1024, 1152, 1280, 1400, 1440, 1600, 1680 }; + + for (int i = 0; i < NUM_ELEMENTS(lcdWidths); i++) { + if (lcdWidths[i] == width) + return true; + } + + return false; // match not found +} + + +static void +Savage_GetPanelInfo() +{ + SharedInfo& si = *gInfo.sharedInfo; + + enum ACTIVE_DISPLAYS { // these are the bits in CR6B + ActiveCRT = 0x01, + ActiveLCD = 0x02, + ActiveTV = 0x04, + ActiveCRT2 = 0x20, + ActiveDUO = 0x80 + }; + + // Check LCD panel information. + + uint8 cr6b = ReadCrtcReg(0x6b); + + int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8; + int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1; + + if ( ! IsLCDWidthValid(panelX)) { + + // Some chips such as the Savage IX/MV in a Thinkpad T-22 will return + // a width that is 8 pixels too wide probably because reg SR61 is set + // to a value +1 higher than it should be. Subtract 8 from the width, + // and check if that is a valid width. + + panelX -= 8; + if ( ! IsLCDWidthValid(panelX)) { + TRACE("%dx%d LCD panel width invalid.\n", panelX + 8, panelY); + si.displayType = MT_CRT; + return; + } + } + + char* sTechnology; + + if ((ReadSeqReg(0x39) & 0x03) == 0) + sTechnology = "TFT"; + else if ((ReadSeqReg(0x30) & 0x01) == 0) + sTechnology = "DSTN"; + else + sTechnology = "STN"; + + TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology, + cr6b & ActiveLCD ? "and active" : "but not active"); + + if (cr6b & ActiveLCD) { + TRACE("Limiting max video mode to %dx%d\n", panelX, panelY); + si.panelX = panelX; + si.panelY = panelY; + } else { + si.displayType = MT_CRT; + } +} + + +status_t +Savage_Init(void) +{ + TRACE("Savage_Init()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + // MMIO should be automatically enabled for Savage chips; thus, use MMIO + // to enable VGA and turn color on. + + WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01); + WriteMiscOutReg(ReadMiscOutReg() | 0x01); // turn color on + + if (si.chipType >= S3_SAVAGE4) + WriteCrtcReg(0x40, 0x01, 0x01); + + WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 + WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F + WriteCrtcReg(0x39, 0xa0); // unlock sys regs CR40~CRFF + WriteSeqReg(0x08, 0x06); // unlock sequencer regs SR09~SRFF + + WriteCrtcReg(0x40, 0x00, 0x01); + WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F + + // Compute the amount of video memory and offscreen memory. + + static const uint8 RamSavage3D[] = { 8, 4, 4, 2 }; + static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; + static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; + static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; + int ramSizeMB = 0; // memory size in megabytes + + uint8 cr36 = ReadCrtcReg(0x36); // get amount of video ram + + switch (si.chipType) { + case S3_SAVAGE_3D: + ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ]; + break; + + case S3_SAVAGE4: + // The Savage4 has one ugly special case to consider. On + // systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB + // when it really means 8MB. Why do it the same when you + // can do it different... + if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6)) + RamSavage4[1] = 8; + + // FALL THROUGH + + case S3_SAVAGE2000: + ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ]; + break; + + case S3_SAVAGE_MX: + case S3_SUPERSAVAGE: + ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ]; + break; + + case S3_PROSAVAGE: + case S3_PROSAVAGE_DDR: + case S3_TWISTER: + ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ]; + break; + + default: + // How did we get here? + ramSizeMB = 0; + break; + } + + TRACE("Savage_Init() memory size: %d MB\n", ramSizeMB); + + if (ramSizeMB <= 0) + return B_ERROR; + + si.videoMemSize = ramSizeMB * 1024 * 1024; + + + // Certain Savage4 and ProSavage chips can have coherency problems + // with respect to the Command Overflow Buffer (COB); thus, to avoid + // problems with these chips, set bDisableCOB to true. + + si.bDisableCOB = false; + + // Compute the Command Overflow Buffer (COB) location. + + if ((S3_SAVAGE4_SERIES(si.chipType) || S3_SUPERSAVAGE == si.chipType) + && si.bDisableCOB) { + + // The Savage4 and ProSavage have COB coherency bugs which render + // the buffer useless. + + si.cobIndex = 0; + si.cobSize = 0; + si.bciThresholdHi = 32; + si.bciThresholdLo = 0; + } else { + // We use 128kB for the COB on all other chips. + si.cobSize = 0x20000; + if (S3_SAVAGE_3D_SERIES(si.chipType) || si.chipType == S3_SAVAGE2000) + si.cobIndex = 7; // rev.A savage4 apparently also uses 7 + else + si.cobIndex = 2; + + // Max command size: 2560 entries. + si.bciThresholdHi = si.cobSize / 4 + 32 - 2560; + si.bciThresholdLo = si.bciThresholdHi - 2560; + } + + // Note that the X.org developers stated that the command overflow buffer + // (COB) must END at a 4MB boundary which for all practical purposes means + // the very end of the video memory. The cursor must be at the beginning + // of the video memory. It had been tried immediately preceding the COB, + // but the Savage MX chip screws up the cursor in that case. + + si.cobOffset = (si.videoMemSize - si.cobSize) & ~0x1ffff; // align cob to 128k + si.cursorOffset = 0; + si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES; + si.maxFrameBufferSize = si.cobOffset - si.frameBufferOffset; + + TRACE("cobIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobIndex, si.cobSize, si.cobOffset); + TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset); + + // Reset graphics engine to avoid memory corruption. + + WriteCrtcReg(0x66, 0x02, 0x02); // set reset flag + snooze(10000); + WriteCrtcReg(0x66, 0x00, 0x02); // clear reset flag + snooze(10000); + + // Check for DVI/flat panel. + + bool bDvi = false; + if (si.chipType == S3_SAVAGE4) { + WriteSeqReg(0x30, 0x00, 0x02); // clear bit 1 + if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) { + bDvi = true; + TRACE("Digital Flat Panel Detected\n"); + } + } + + if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) { + si.displayType = MT_LCD; + Savage_GetPanelInfo(); + } + else if (bDvi) + si.displayType = MT_DFP; + else + si.displayType = MT_CRT; + + TRACE("Display Type: %d\n", si.displayType); + + // Detect current mclk. + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 m = ReadSeqReg(0x11) & 0x7f; + uint8 n = ReadSeqReg(0x10); + uint8 n1 = n & 0x1f; + uint8 n2 = (n >> 5) & 0x03; + si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100; + + TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0); + + // Set up the array of color spaces supported by the Savage chips. + + si.colorSpaces[0] = B_CMAP8; + si.colorSpaces[1] = B_RGB16; + si.colorSpaces[2] = B_RGB32; + si.colorSpaceCount = 3; + + // Get info about the display capabilities (EDID). + + Savage_GetEdidInfo(); + + // Setup the mode list. + + return CreateModeList(IsModeUsable); +} + + +void +Savage_SetFunctionPointers(void) +{ + // Setting the function pointers must be done prior to first ModeInit call + // or any accel activity. + + switch (gInfo.sharedInfo->chipType) { + case S3_SAVAGE_3D: + case S3_SAVAGE_MX: + gInfo.WaitQueue = WaitQueue3D; + gInfo.WaitIdleEmpty = WaitIdleEmpty3D; + break; + + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_SUPERSAVAGE: + case S3_PROSAVAGE_DDR: + case S3_TWISTER: + gInfo.WaitQueue = WaitQueue4; + gInfo.WaitIdleEmpty = WaitIdleEmpty4; + break; + + case S3_SAVAGE2000: + gInfo.WaitQueue = WaitQueue2K; + gInfo.WaitIdleEmpty = WaitIdleEmpty2K; + break; + } + + gInfo.DPMSCapabilities = Savage_DPMSCapabilities; + gInfo.DPMSMode = Savage_DPMSMode; + gInfo.SetDPMSMode = Savage_SetDPMSMode; + + gInfo.LoadCursorImage = Savage_LoadCursorImage; + gInfo.SetCursorPosition = Savage_SetCursorPosition; + gInfo.ShowCursor = Savage_ShowCursor; + + gInfo.FillRectangle = Savage_FillRectangle; + gInfo.FillSpan = Savage_FillSpan; + gInfo.InvertRectangle = Savage_InvertRectangle; + gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit; + + gInfo.AdjustFrame = Savage_AdjustFrame; + gInfo.ChipInit = Savage_Init; + gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams; + gInfo.SetDisplayMode = Savage_SetDisplayMode; + gInfo.SetIndexedColors = Savage_SetIndexedColors; +} + diff --git a/src/add-ons/accelerants/s3/savage_mode.cpp b/src/add-ons/accelerants/s3/savage_mode.cpp new file mode 100644 index 0000000000..4a36d47ca9 --- /dev/null +++ b/src/add-ons/accelerants/s3/savage_mode.cpp @@ -0,0 +1,1088 @@ +/* + Haiku S3 Savage driver adapted from the X.org Savage driver. + + Copyright 1995-1997 The XFree86 Project, Inc. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2006-2008 +*/ + + +#include "accel.h" +#include "savage.h" + + +#define BASE_FREQ 14.31818 + + +struct SavageRegRec { + uint8 CRTC[25]; // Crtc Controller reg's + + uint8 SR12, SR13, SR15, SR18, SR1B, SR29; + uint8 CR31, CR33, CR34, CR3A, CR3B, CR3C; + uint8 CR40, CR42, CR43, CR45; + uint8 CR50, CR51, CR53, CR58, CR5D, CR5E; + uint8 CR65, CR66, CR67, CR69; + uint8 CR86, CR88; + uint8 CR90, CR91, CRB0; +}; + + + + +static void +Savage_SetGBD_Twister(const DisplayModeEx& mode) +{ + SharedInfo& si = *gInfo.sharedInfo; + int bci_enable; + + TRACE("Savage_SetGBD_Twister()\n"); + + if (si.chipType == S3_SAVAGE4) + bci_enable = BCI_ENABLE; + else + bci_enable = BCI_ENABLE_TWISTER; + + // MM81C0 and 81C4 are used to control primary stream. + WriteReg32(PRI_STREAM_FBUF_ADDR0, 0); + WriteReg32(PRI_STREAM_FBUF_ADDR1, 0); + + // Program Primary Stream Stride Register. + // + // Tell engine if tiling on or off, set primary stream stride, and + // if tiling, set tiling bits/pixel and primary stream tile offset. + // Note that tile offset (bits 16 - 29) must be scanline width in + // bytes/128bytespertile * 256 Qwords/tile. This is equivalent to + // lDelta * 2. Remember that if tiling, lDelta is screenwidth in + // bytes padded up to an even number of tilewidths. + + WriteReg32(PRI_STREAM_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) | + (mode.bytesPerRow & 0x00001fff)); + + // CR69, bit 7 = 1 + // to use MM streams processor registers to control primary stream. + + WriteCrtcReg(0x69, 0x80, 0x80); + + WriteReg32(0x8128, 0xFFFFFFFFL); + WriteReg32(0x812C, 0xFFFFFFFFL); + + WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + + // If MS1NB style linear tiling mode. + // bit MM850C[15] = 0 select NB linear tile mode. + // bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode. + + uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000; // use MS-s style tile mode + WriteReg32(ADVANCED_FUNC_CTRL, ulTmp); + + // Set up Tiled Surface Registers + // Bit 25:20 - Surface width in tiles. + // Bit 29 - Y Range Flag. + // Bit 31:30 = 00, 4 bpp. + // = 01, 8 bpp. + // = 10, 16 bpp. + // = 11, 32 bpp. + + // Global Bitmap Descriptor Register MM816C - twister/prosavage + // bit 24~25: tile format + // 00: linear + // 01: destination tiling format + // 10: texture tiling format + // 11: reserved + // bit 28: block write disble/enable + // 0: disable + // 1: enable + + // Global Bitmap Descriptor Register MM816C - savage4 + // bit 24~25: tile format + // 00: linear + // 01: reserved + // 10: 16 bpp tiles + // 11: 32 bpp tiles + // bit 28: block write disable/enable + // 0: enable + // 1: disable + + // Do not enable block_write even for non-tiling modes, because + // the driver cannot determine if the memory type is the certain + // type of SGRAM for which block_write can be used. + + si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear + si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write + // HW uses width. + si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line + si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); + si.GlobalBD.bd1.Offset = si.frameBufferOffset; + + // CR88, bit 4 - Block write enabled/disabled. + // + // Note: Block write must be disabled when writing to tiled + // memory. Even when writing to non-tiled memory, block + // write should only be enabled for certain types of SGRAM. + + WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D); + + // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). + // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window + // at A000:0. + + WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); + + // Program the GBD and SBD's. + + WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); + WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); +} + + +static void +Savage_SetGBD_3D(const DisplayModeEx& mode) +{ + TRACE("Savage_SetGBD_3D()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + int bci_enable = BCI_ENABLE; + + // MM81C0 and 81C4 are used to control primary stream. + WriteReg32(PRI_STREAM_FBUF_ADDR0, 0); + WriteReg32(PRI_STREAM_FBUF_ADDR1, 0); + + // Program Primary Stream Stride Register. + // + // Tell engine if tiling on or off, set primary stream stride, and + // if tiling, set tiling bits/pixel and primary stream tile offset. + // Note that tile offset (bits 16 - 29) must be scanline width in + // bytes/128bytespertile * 256 Qwords/tile. This is equivalent to + // lDelta * 2. Remember that if tiling, lDelta is screenwidth in + // bytes padded up to an even number of tilewidths. + + WriteReg32(PRI_STREAM_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) | + (mode.bytesPerRow & 0x00001fff)); + + // CR69, bit 7 = 1 to use MM streams processor registers to control primary + // stream. + + WriteCrtcReg(0x69, 0x80, 0x80); + + WriteReg32(0x8128, 0xFFFFFFFFL); + WriteReg32(0x812C, 0xFFFFFFFFL); + + WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + + // If MS1NB style linear tiling mode. + // bit MM850C[15] = 0 select NB linear tile mode. + // bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode. + + uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000; // use MS-s style tile mode + WriteReg32(ADVANCED_FUNC_CTRL, ulTmp); + + // Tiled Surface 0 Registers MM48C40: + // bit 0~23: tile surface 0 frame buffer offset + // bit 24~29:tile surface 0 width + // bit 30~31:tile surface 0 bits/pixel + // 00: reserved + // 01, 8 bits + // 10, 16 Bits. + // 11, 32 Bits. + + // Global Bitmap Descriptor Register MM816C + // bit 24~25: tile format + // 00: linear + // 01: reserved + // 10: 16 bpp tiles + // 11: 32 bpp tiles + // bit 28: block write disable/enable + // 0: enable + // 1: disable + + // Do not enable block_write even for non-tiling modes, because + // the driver cannot determine if the memory type is the certain + // type of SGRAM for which block_write can be used. + + si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear + si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write + // HW uses width. + si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line + si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); + si.GlobalBD.bd1.Offset = si.frameBufferOffset; + + // CR88, bit 4 - Block write enabled/disabled. + // + // Note: Block write must be disabled when writing to tiled + // memory. Even when writing to non-tiled memory, block + // write should only be enabled for certain types of SGRAM. + + WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D); + + // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). + // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window + // at A000:0. + + WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); + + // Program the GBD and SBD's. + WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); + WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); +} + + +static void +Savage_SetGBD_MX(const DisplayModeEx& mode) +{ + TRACE("Savage_SetGBD_MX()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + int bci_enable = BCI_ENABLE; + + // CR67_3: + // = 1 stream processor MMIO address and stride register + // are used to control the primary stream. + // = 0 standard VGA address and stride registers + // are used to control the primary streams. + + WriteCrtcReg(0x67, 0x08, 0x08); + // IGA 2. + WriteSeqReg(0x26, 0x4f); // select IGA 2 read/writes + WriteCrtcReg(0x67, 0x08, 0x08); + WriteSeqReg(0x26, 0x40); // select IGA 1 + + // Set primary stream to bank 0 via reg CRCA. + WriteCrtcReg(MEMORY_CTRL0_REG, 0x00, MEM_PS1 + MEM_PS2); + + // MM81C0 and 81C4 are used to control primary stream. + WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset & 0x7fffff); + WriteReg32(PRI_STREAM_FBUF_ADDR1, si.frameBufferOffset & 0x7fffff); + WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset & 0x7fffff); + WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0x7fffff); + + // Program Primary Stream Stride Register. + // + // Tell engine if tiling on or off, set primary stream stride, and + // if tiling, set tiling bits/pixel and primary stream tile offset. + // Note that tile offset (bits 16 - 29) must be scanline width in + // bytes/128bytespertile * 256 Qwords/tile. This is equivalent to + // lDelta * 2. Remember that if tiling, lDelta is screenwidth in + // bytes padded up to an even number of tilewidths. + + WriteReg32(PRI_STREAM_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) | + (mode.bytesPerRow & 0x00003fff)); + WriteReg32(PRI_STREAM2_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) | + (mode.bytesPerRow & 0x00003fff)); + + WriteReg32(0x8128, 0xFFFFFFFFL); + WriteReg32(0x812C, 0xFFFFFFFFL); + + WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + + // CR78, bit 3 - Block write enabled(1)/disabled(0). + // bit 2 - Block write cycle time(0:2 cycles,1: 1 cycle) + // Note: Block write must be disabled when writing to tiled + // memory. Even when writing to non-tiled memory, block + // write should only be enabled for certain types of SGRAM. + + WriteCrtcReg(0x78, 0xfb, 0xfb); + + // Tiled Surface 0 Registers MM48C40: + // bit 0~23: tile surface 0 frame buffer offset + // bit 24~29:tile surface 0 width + // bit 30~31:tile surface 0 bits/pixel + // 00: reserved + // 01, 8 bits + // 10, 16 Bits. + // 11, 32 Bits. + + // Global Bitmap Descriptor Register MM816C + // bit 24~25: tile format + // 00: linear + // 01: reserved + // 10: 16 bit + // 11: 32 bit + // bit 28: block write disble/enable + // 0: enable + // 1: disable + + // Do not enable block_write even for non-tiling modes, because + // the driver cannot determine if the memory type is the certain + // type of SGRAM for which block_write can be used. + + si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear + si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write + // HW uses width. + si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line + si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); + si.GlobalBD.bd1.Offset = si.frameBufferOffset; + + // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). + // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window + // at A000:0. + + WriteCrtcReg(MEMORY_CONFIG_REG, 0x04, 0x05); // CR31 + + // Program the GBD and SBD's. + WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); + // 8: bci enable. + WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart + | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); + WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); + WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); +} + + +static void +Savage_SetGBD_Super(const DisplayModeEx& mode) +{ + TRACE("Savage_SetGBD_Super()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + int bci_enable = BCI_ENABLE_TWISTER; + + // CR67_3: + // = 1 stream processor MMIO address and stride register + // are used to control the primary stream. + // = 0 standard VGA address and stride registers + // are used to control the primary streams. + + WriteCrtcReg(0x67, 0x08, 0x08); + // IGA 2. + WriteSeqReg(0x26, 0x4f); // select IGA 2 read/writes + WriteCrtcReg(0x67, 0x08, 0x08); + WriteSeqReg(0x26, 0x40); // select IGA 1 + + // Load ps1 active registers as determined by MM81C0/81C4. + // Load ps2 active registers as determined by MM81B0/81B4. + + WriteCrtcReg(0x65, 0x03, 0x03); + + // Program Primary Stream Stride Register. + // + // Tell engine if tiling on or off, set primary stream stride, and + // if tiling, set tiling bits/pixel and primary stream tile offset. + // Note that tile offset (bits 16 - 29) must be scanline width in + // bytes/128bytespertile * 256 Qwords/tile. This is equivalent to + // lDelta * 2. Remember that if tiling, lDelta is screenwidth in + // bytes padded up to an even number of tilewidths. + + WriteReg32(PRI_STREAM_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) | + (mode.bytesPerRow & 0x00001fff)); + WriteReg32(PRI_STREAM2_STRIDE, + (((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) | + (mode.bytesPerRow & 0x00001fff)); + + // MM81C0 and 81C4 are used to control primary stream. + WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset); + WriteReg32(PRI_STREAM_FBUF_ADDR1, 0x80000000); + WriteReg32(PRI_STREAM2_FBUF_ADDR0, (si.frameBufferOffset & 0xfffffffc) | 0x80000000); + WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0xfffffffc); + + WriteReg32(0x8128, 0xFFFFFFFFL); + WriteReg32(0x812C, 0xFFFFFFFFL); + + // Bit 28:block write disable. + WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + + // Do not enable block_write even for non-tiling modes, because + // the driver cannot determine if the memory type is the certain + // type of SGRAM for which block_write can be used. + + si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear + si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write + // HW uses width. + si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line + si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); + si.GlobalBD.bd1.Offset = si.frameBufferOffset; + + // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). + // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window + // at A000:0. + + WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); + + // Program the GBD and SBDs. + WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); + WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart + | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); + WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); + WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); +} + + +static void +Savage_SetGBD_2000(const DisplayModeEx& mode) +{ + TRACE("Savage_SetGBD_2000()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + int bci_enable = BCI_ENABLE_TWISTER; + + // MM81C0 and 81B0 are used to control primary stream. + WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset); + WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset); + + // Program Primary Stream Stride Register. + // + // Tell engine if tiling on or off, set primary stream stride, and + // if tiling, set tiling bits/pixel and primary stream tile offset. + // Note that tile offset (bits 16 - 29) must be scanline width in + // bytes/128bytespertile * 256 Qwords/tile. This is equivalent to + // lDelta * 2. Remember that if tiling, lDelta is screenwidth in + // bytes padded up to an even number of tilewidths. + + WriteReg32(PRI_STREAM_STRIDE, ((mode.bytesPerRow << 4) & 0x7ff0)); + WriteReg32(PRI_STREAM2_STRIDE, ((mode.bytesPerRow << 4) & 0x7ff0)); + + // CR67_3: + // = 1 stream processor MMIO address and stride register + // are used to control the primary stream. + // = 0 standard VGA address and stride registers + // are used to control the primary streams + + WriteCrtcReg(0x67, 0x08, 0x08); + + WriteReg32(0x8128, 0xFFFFFFFFL); + WriteReg32(0x812C, 0xFFFFFFFFL); + + // Bit 28:block write disable. + WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + WriteCrtcReg(0x73, 0x00, 0x20); // CR73 bit 5 = 0 block write disable + + // Do not enable block_write even for non-tiling modes, because + // the driver cannot determine if the memory type is the certain + // type of SGRAM for which block_write can be used. + + si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear + si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write + // HW uses width. + si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line + si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); + si.GlobalBD.bd1.Offset = si.frameBufferOffset; + + // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). + // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window + // at A000:0. + + WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); + + // Program the GBD and SBDs. + WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); + WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart + | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); + WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); + WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); + WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); +} + + +static void +Savage_SetGBD(const DisplayModeEx& mode) +{ + TRACE("Savage_SetGBD()\n"); + + VerticalRetraceWait(); + + switch (gInfo.sharedInfo->chipType) { + case S3_SAVAGE_3D: + Savage_SetGBD_3D(mode); + break; + + case S3_SAVAGE_MX: + Savage_SetGBD_MX(mode); + break; + + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_TWISTER: + case S3_PROSAVAGE_DDR: + Savage_SetGBD_Twister(mode); + break; + + case S3_SUPERSAVAGE: + Savage_SetGBD_Super(mode); + break; + + case S3_SAVAGE2000: + Savage_SetGBD_2000(mode); + break; + } +} + + +static void +Savage_Initialize2DEngine(const DisplayModeEx& mode) +{ + TRACE("Savage_Initialize2DEngine()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + uint32 thresholds; + + WriteCrtcReg(0x40, 0x01); + WriteCrtcReg(0x31, 0x0c); + + // Setup plane masks. + WriteReg32(0x8128, ~0); // enable all write planes + WriteReg32(0x812C, ~0); // enable all read planes + WriteReg16(0x8134, 0x27); + WriteReg16(0x8136, 0x07); + + switch (si.chipType) { + case S3_SAVAGE_3D: + case S3_SAVAGE_MX: + + // Disable BCI. + WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); + // Setup BCI command overflow buffer. + WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29)); // tim + // Program shadow status update. + thresholds = ((si.bciThresholdLo & 0xffff) << 16) | + (si.bciThresholdHi & 0xffff); + WriteReg32(0x48C10, thresholds); + + WriteReg32(0x48C0C, 0); + // Enable BCI and command overflow buffer. + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C); + break; + + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_TWISTER: + case S3_PROSAVAGE_DDR: + case S3_SUPERSAVAGE: + + // Disable BCI. + WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); + + if ( ! si.bDisableCOB) { + // Setup BCI command overflow buffer. + WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29)); + } + // Program shadow status update; AGD: what should this be? + thresholds = ((si.bciThresholdLo & 0x1fffe0) << 11) + | ((si.bciThresholdHi & 0x1fffe0) >> 5); + WriteReg32(0x48C10, thresholds); + + WriteReg32(0x48C0C, 0); + if (si.bDisableCOB) + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x08); // enable BCI without COB + else + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C); // enable BCI with COB + + break; + + case S3_SAVAGE2000: + + // Disable BCI. + WriteReg32(0x48C18, 0); + // Setup BCI command overflow buffer. + WriteReg32(0x48C18, (si.cobOffset >> 7) | (si.cobIndex)); + // Disable shadow status update. + WriteReg32(0x48A30, 0); + // Enable BCI and command overflow buffer. + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x00280000 ); + + break; + } + + // Use and set global bitmap descriptor. + + // For reasons I do not fully understand yet, on the Savage4, the + // write to the GBD register, MM816C, does not "take" at this time. + // Only the low-order byte is acknowledged, resulting in an incorrect + // stride. Writing the register later, after the mode switch, works + // correctly. This needs to get resolved. + + Savage_SetGBD(mode); +} + + +static void +Savage_GEReset(const DisplayModeEx& mode) +{ + TRACE("Savage_GEReset() begin\n"); + + gInfo.WaitIdleEmpty(); + snooze(10000); + + for (int r = 1; r < 10; r++) { + bool bSuccess = false; + + WriteCrtcReg(0x66, 0x02, 0x02); + snooze(10000); + WriteCrtcReg(0x66, 0x00, 0x02); + snooze(10000); + + gInfo.WaitIdleEmpty(); + + WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); + + snooze(10000); + switch (gInfo.sharedInfo->chipType) { + case S3_SAVAGE_3D: + case S3_SAVAGE_MX: + bSuccess = (STATUS_WORD0 & 0x0008ffff) == 0x00080000; + break; + + case S3_SAVAGE4: + case S3_PROSAVAGE: + case S3_PROSAVAGE_DDR: + case S3_TWISTER: + case S3_SUPERSAVAGE: + bSuccess = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000; + break; + + case S3_SAVAGE2000: + bSuccess = (ALT_STATUS_WORD0 & 0x008fffff) == 0; + break; + } + + if (bSuccess) + break; + + snooze(10000); + TRACE("Restarting S3 graphics engine reset %2d ...\n", r); + } + + // At this point, the FIFO is empty and the engine is idle. + + WriteReg32(SRC_BASE, 0); + WriteReg32(DEST_BASE, 0); + WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); + WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); + WriteReg32(MONO_PAT_0, ~0); + WriteReg32(MONO_PAT_1, ~0); + + Savage_SetGBD(mode); + + TRACE("Savage_GEReset() end\n"); +} + + +static void +Savage_CalcClock(long freq, int min_m, + int min_n1, int max_n1, + int min_n2, int max_n2, + long freq_min, long freq_max, + unsigned int *mdiv, unsigned int *ndiv, unsigned int *r) +{ + uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2; + + double ffreq = freq / 1000.0 / BASE_FREQ; + double ffreq_max = freq_max / 1000.0 / BASE_FREQ; + double ffreq_min = freq_min / 1000.0 / BASE_FREQ; + + if (ffreq < ffreq_min / (1 << max_n2)) { + TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ); + ffreq = ffreq_min / (1 << max_n2); + } + if (ffreq > ffreq_max / (1 << min_n2)) { + TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ); + ffreq = ffreq_max / (1 << min_n2); + } + + // Work out suitable timings. + + double best_diff = ffreq; + + for (uint8 n2 = min_n2; n2 <= max_n2; n2++) { + for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { + int m = (int)(ffreq * n1 * (1 << n2) + 0.5); + if (m < min_m + 2 || m > 127 + 2) + continue; + + double div = (double)(m) / (double)(n1); + if ((div >= ffreq_min) && (div <= ffreq_max)) { + double diff = ffreq - div / (1 << n2); + if (diff < 0.0) + diff = -diff; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + *ndiv = best_n1 - 2; + *r = best_n2; + *mdiv = best_m - 2; +} + + +static void +Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) +{ + TRACE("Savage_WriteMode() enter\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + gInfo.WaitIdleEmpty(); + + WriteMiscOutReg(0x23); + WriteCrtcReg(0x38, 0x48); // unlock sys regs CR20~CR3F + WriteCrtcReg(0x39, 0xa0); // unlock sys regs CR40~CRFF + WriteSeqReg(0x08, 0x06); // unlock sequencer regs SR09~SRFF + + if ( ! S3_SAVAGE_MOBILE_SERIES(si.chipType)) + Savage_Initialize2DEngine(mode); + + if (ReadCrtcReg(0x66) & 0x01) { + Savage_GEReset(mode); // reset GE to make sure nothing is going on + } + + WriteCrtcReg(0x67, regRec.CR67 & ~0x0e); // no STREAMS yet old and new + + // Set register SR19 to zero so that the ProSavage chips will start up + // when booting under BeOS using the default boot screen. + + if (si.chipType == S3_PROSAVAGE || si.chipType == S3_TWISTER) + WriteSeqReg(0x19, 0); + + // Clear bit 3 in SR30 so that Savage MX chip will startup. If bit 3 is + // not cleared, it will startup only if booting under BeOS using the + // default boot screen or the boot screen resolution matches the resolution + // of the mode currently being set. + + if (si.chipType == S3_SAVAGE_MX) + WriteSeqReg(0x30, 0x00, 0x08); + + // Set extended regs. + + WriteCrtcReg(0x66, regRec.CR66); + WriteCrtcReg(0x3a, regRec.CR3A); + WriteCrtcReg(0x31, regRec.CR31); + WriteCrtcReg(0x58, regRec.CR58); + WriteCrtcReg(0x53, regRec.CR53 & 0x7f); + + // Set DCLK registers. + + WriteSeqReg(0x29, regRec.SR29); + WriteSeqReg(0x15, regRec.SR15); + + // Set the standard CRTC vga regs. + + WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 + + for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++) + WriteCrtcReg(j, regRec.CRTC[j]); + + // Setup HSYNC & VSYNC polarity. + + uint8 temp = ((ReadMiscOutReg() & 0x3f) | 0x0c); + + if (!(mode.timing.flags & B_POSITIVE_HSYNC)) + temp |= 0x40; + if (!(mode.timing.flags & B_POSITIVE_VSYNC)) + temp |= 0x80; + + WriteMiscOutReg(temp); + + // Extended mode timing registers. + WriteCrtcReg(0x53, regRec.CR53); + WriteCrtcReg(0x5d, regRec.CR5D); + WriteCrtcReg(0x5e, regRec.CR5E); + WriteCrtcReg(0x3b, regRec.CR3B); + WriteCrtcReg(0x3c, regRec.CR3C); + WriteCrtcReg(0x43, regRec.CR43); + WriteCrtcReg(0x65, regRec.CR65); + + // Restore the desired video mode with cr67. + WriteCrtcReg(0x67, regRec.CR67 & ~0x0e); // no streams for new and old streams engines + + // Other mode timing and extended regs. + WriteCrtcReg(0x34, regRec.CR34); + WriteCrtcReg(0x40, regRec.CR40); + WriteCrtcReg(0x42, regRec.CR42); + WriteCrtcReg(0x45, regRec.CR45); + WriteCrtcReg(0x50, regRec.CR50); + WriteCrtcReg(0x51, regRec.CR51); + + // Memory timings. + VerticalRetraceWait(); + WriteCrtcReg(0x69, regRec.CR69); + + WriteCrtcReg(0x33, regRec.CR33); + WriteCrtcReg(0x86, regRec.CR86); + WriteCrtcReg(0x88, regRec.CR88); + WriteCrtcReg(0x90, regRec.CR90); + WriteCrtcReg(0x91, regRec.CR91); + + if (si.chipType == S3_SAVAGE4) + WriteCrtcReg(0xb0, regRec.CRB0); + + // Set extended seq regs for dclk. + WriteSeqReg(0x12, regRec.SR12); + WriteSeqReg(0x13, regRec.SR13); + WriteSeqReg(0x29, regRec.SR29); + + WriteSeqReg(0x18, regRec.SR18); + WriteSeqReg(0x1b, regRec.SR1B); + + // Load new m, n pll values for dclk & mclk. + temp = ReadSeqReg(0x15) & ~0x21; + + WriteSeqReg(0x15, temp | 0x03); + WriteSeqReg(0x15, temp | 0x23); + WriteSeqReg(0x15, temp | 0x03); + WriteSeqReg(0x15, regRec.SR15); + snooze( 100 ); + + // Now write out cr67 in full, possibly starting STREAMS. + VerticalRetraceWait(); + WriteCrtcReg(0x67, regRec.CR67); + + uint8 cr66 = ReadCrtcReg(0x66); + WriteCrtcReg(0x66, cr66 | 0x80); + uint8 cr3a = ReadCrtcReg(0x3a); + WriteCrtcReg(0x3a, cr3a | 0x80); + + Savage_GEReset(mode); + + WriteCrtcReg(0x66, cr66); + WriteCrtcReg(0x3a, cr3a); + + Savage_Initialize2DEngine(mode); + + WriteCrtcReg(0x40, 0x01); // enable graphics engine + + Savage_SetGBD(mode); + + TRACE("Savage_WriteMode() end\n"); + + return; +} + + +static bool +Savage_ModeInit(const DisplayModeEx& mode) +{ + TRACE("Savage_ModeInit(%dx%d, %dHz)\n", + mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); + + SharedInfo& si = *gInfo.sharedInfo; + SavageRegRec regRec; + + int horizScaleFactor = 1; + + if (mode.bpp == 16 && si.chipType == S3_SAVAGE_3D) + horizScaleFactor = 2; + + InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC, + regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E); + regRec.CRTC[23] = 0xEB; + + int dclk = mode.timing.pixel_clock; + regRec.CR67 = 0x00; + + switch (mode.bpp) { + case 8: + if ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000)) + regRec.CR67 = 0x10; // 8bpp, 2 pixels/clock + else + regRec.CR67 = 0x00; // 8bpp, 1 pixel/clock + break; + + case 15: + if (S3_SAVAGE_MOBILE_SERIES(si.chipType) + || ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000))) + regRec.CR67 = 0x30; // 15bpp, 2 pixel/clock + else + regRec.CR67 = 0x20; // 15bpp, 1 pixels/clock + break; + + case 16: + if (S3_SAVAGE_MOBILE_SERIES(si.chipType) + || ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000))) + regRec.CR67 = 0x50; // 16bpp, 2 pixel/clock + else + regRec.CR67 = 0x40; // 16bpp, 1 pixels/clock + break; + + case 32: + regRec.CR67 = 0xd0; + break; + } + + + // Use traditional register-crunching to set mode. + + regRec.CR3A = (ReadCrtcReg(0x3a) & 0x7f) | 0x15; + regRec.CR53 = 0x00; + regRec.CR31 = 0x8c; + regRec.CR66 = 0x89; + regRec.CR58 = (ReadCrtcReg(0x58) & 0x80) | 0x13; + + if (si.chipType == S3_SAVAGE2000) + regRec.SR15 = 0x02; + else + regRec.SR15 = 0x83; + + regRec.SR18 = 0x00; + regRec.SR1B = ReadSeqReg(0x1b) | 0x10; // enable 8-bit Color Lookup Table + + regRec.CR43 = regRec.CR45 = regRec.CR65 = 0x00; + regRec.CR40 = ReadCrtcReg(0x40) & ~0x01; + + unsigned int m, n, r; + Savage_CalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); + regRec.SR12 = (r << 6) | (n & 0x3f); + regRec.SR13 = m & 0xff; + regRec.SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; + + TRACE("CalcClock, m: %d n: %d r: %d\n", m, n, r); + + regRec.CR42 = 0x00; + regRec.CR34 = 0x10; + + int width = mode.bytesPerRow / 8; + regRec.CR91 = 0xff & width; + regRec.CR51 = (0x300 & width) >> 4; + regRec.CR90 = 0x80 | (width >> 8); + + // Set frame buffer description. + + if (mode.bpp <= 8) + regRec.CR50 = 0; + else if (mode.bpp <= 16) + regRec.CR50 = 0x10; + else + regRec.CR50 = 0x30; + + width = mode.timing.h_display; // width of display in pixels + + if (width == 640) + regRec.CR50 |= 0x40; + else if (width == 800) + regRec.CR50 |= 0x80; + else if (width == 1024) + regRec.CR50 |= 0x00; + else if (width == 1152) + regRec.CR50 |= 0x01; + else if (width == 1280) + regRec.CR50 |= 0xc0; + else if (width == 1600) + regRec.CR50 |= 0x81; + else + regRec.CR50 |= 0xc1; // use GBD + + if (S3_SAVAGE_MOBILE_SERIES(si.chipType)) + regRec.CR33 = 0x00; + else + regRec.CR33 = 0x08; + + regRec.CR67 |= 1; + regRec.CR69 = 0; + regRec.CR86 = ReadCrtcReg(0x86) | 0x08; + regRec.CR88 = ReadCrtcReg(0x88) | DISABLE_BLOCK_WRITE_2D; + regRec.CRB0 = ReadCrtcReg(0xb0) | 0x80; + + Savage_WriteMode(mode, regRec); // write registers to set mode + + return true; +} + + + +bool +Savage_SetDisplayMode(const DisplayModeEx& mode) +{ + // The code to actually configure the display. + // All the error checking must be done in ProposeDisplayMode(), + // and assume that the mode values we get here are acceptable. + + WriteSeqReg(0x01, 0x20, 0x20); // blank the screen + + if ( ! Savage_ModeInit(mode)) { + TRACE("Savage_ModeInit() failed\n"); + return false; + } + + Savage_AdjustFrame(mode); + + WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen + return true; +} + + + +void +Savage_AdjustFrame(const DisplayModeEx& mode) +{ + // Adjust start address in frame buffer. + + SharedInfo& si = *gInfo.sharedInfo; + + int address = (mode.v_display_start * mode.virtual_width) + + ((mode.h_display_start & ~0x3F) * (mode.bpp / 8)); + address &= ~0x1F; + address += si.frameBufferOffset; + + switch (si.chipType) { + case S3_SAVAGE_MX: + WriteReg32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC); + WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC); + break; + case S3_SUPERSAVAGE: + WriteReg32(PRI_STREAM_FBUF_ADDR0, 0x80000000); + WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8); + break; + case S3_SAVAGE2000: + // Certain Y values seems to cause havoc, not sure why + WriteReg32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8)); + WriteReg32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8)); + break; + default: + WriteReg32(PRI_STREAM_FBUF_ADDR0, address | 0xFFFFFFFC); + WriteReg32(PRI_STREAM_FBUF_ADDR1, address | 0x80000000); + break; + } + + return; +} + + +void +Savage_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) +{ + // Set the indexed color palette for 8-bit color depth mode. + + (void)flags; // avoid compiler warning for unused arg + + if (gInfo.sharedInfo->displayMode.space != B_CMAP8) + return ; + + while (count--) { + WriteIndexedColor(first++, // color index + colorData[0], // red + colorData[1], // green + colorData[2]); // blue + colorData += 3; + } +} diff --git a/src/add-ons/accelerants/s3/trio64.h b/src/add-ons/accelerants/s3/trio64.h new file mode 100644 index 0000000000..f3faee81e1 --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64.h @@ -0,0 +1,62 @@ +/* + Haiku S3 Trio64 driver adapted from the X.org S3 driver. + + Copyright 2001 Ani Joshi + + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + + +#ifndef __TRIO64_H__ +#define __TRIO64_H__ + + +// Note that the cursor normally needs only 1024 bytes; however, if 1024 bytes +// are used, some of the Trio64 chips draw a short white horizontal line below +// and to the right of the cursor. Setting the number of bytes to 2048 solves +// the problem. + +#define CURSOR_BYTES 2048 // see comment above + + +// Command Registers. +#define ADVFUNC_CNTL 0x4ae8 +#define SUBSYS_STAT 0x42e8 +#define SUBSYS_CNTL 0x42e8 +#define CUR_Y 0x82e8 +#define CUR_X 0x86e8 +#define DESTY_AXSTP 0x8ae8 +#define DESTX_DIASTP 0x8ee8 +#define CUR_WIDTH 0x96e8 +#define CMD 0x9ae8 +#define GP_STAT 0x9ae8 +#define FRGD_COLOR 0xa6e8 +#define WRT_MASK 0xaae8 +#define FRGD_MIX 0xbae8 +#define MULTIFUNC_CNTL 0xbee8 + +// Command register bits. +#define CMD_RECT 0x4000 +#define CMD_BITBLT 0xc000 +#define INC_Y 0x0080 +#define INC_X 0x0020 +#define DRAW 0x0010 +#define WRTDATA 0x0001 + +// Foreground mix register. +#define FSS_FRGDCOL 0x0020 +#define FSS_BITBLT 0x0060 + +#define GP_BUSY 0x0200 + +#define SCISSORS_T 0x1000 +#define SCISSORS_L 0x2000 +#define SCISSORS_B 0x3000 +#define SCISSORS_R 0x4000 + + +#endif // __TRIO64_H__ diff --git a/src/add-ons/accelerants/s3/trio64_cursor.cpp b/src/add-ons/accelerants/s3/trio64_cursor.cpp new file mode 100644 index 0000000000..035c4ded56 --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64_cursor.cpp @@ -0,0 +1,112 @@ +/* + Haiku S3 Trio64 driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" +#include "trio64.h" + + + +void +Trio64_ShowCursor(bool bShow) +{ + // Turn cursor on/off. + + WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01); +} + + +void +Trio64_SetCursorPosition(int x, int y) +{ + uint8 xOffset = 0; + uint8 yOffset = 0; + + // xOffset & yOffset are used for displaying partial cursors on screen edges. + + if (x < 0) { + xOffset = (( -x) & 0xfe); + x = 0; + } + + if (y < 0) { + yOffset = (( -y) & 0xfe); + y = 0; + } + + // Note: when setting the cursor position, register 48 must be set last + // since setting register 48 activates the new cursor position. + + WriteCrtcReg( 0x4e, xOffset ); + WriteCrtcReg( 0x4f, yOffset ); + + WriteCrtcReg( 0x47, (x & 0xff) ); + WriteCrtcReg( 0x46, (x & 0x0700) >> 8 ); + + WriteCrtcReg( 0x49, (y & 0xff) ); + WriteCrtcReg( 0x48, (y & 0x0700) >> 8 ); +} + + +bool +Trio64_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask) +{ + SharedInfo& si = *gInfo.sharedInfo; + + if (andMask == NULL || xorMask == NULL) + return false; + + // Initialize hardware cursor to be completely transparent. + + uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int i = 0; i < CURSOR_BYTES; i += 4) { + *fbCursor16++ = ~0; // and bits + *fbCursor16++ = 0; // xor bits + } + + // Now load the AND & XOR masks for the cursor image into the cursor + // buffer. Note that a particular bit in these masks will have the + // following effect upon the corresponding cursor pixel: + // AND XOR Result + // 0 0 White pixel + // 0 1 Black pixel + // 1 0 Screen color (for transparency) + // 1 1 Reverse screen color to black or white + + uint8* fbCursor = (uint8*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int row = 0; row < height; row++) { + for (int colByte = 0; colByte < width / 8; colByte++) { + fbCursor[row * 16 + colByte] = *andMask++; + fbCursor[row * 16 + colByte + 2] = *xorMask++; + } + } + + // Set cursor location in video memory. + + WriteCrtcReg(0x4c, (0x0f00 & si.cursorOffset / 1024) >> 8); + WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024)); + + // Set the cursor colors which are black foreground and white background. + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes + WriteCrtcReg(0x4a, 0); + WriteCrtcReg(0x4a, 0); + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes + WriteCrtcReg(0x4b, ~0); + WriteCrtcReg(0x4b, ~0); + + return true; +} diff --git a/src/add-ons/accelerants/s3/trio64_dpms.cpp b/src/add-ons/accelerants/s3/trio64_dpms.cpp new file mode 100644 index 0000000000..112d98dcc2 --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64_dpms.cpp @@ -0,0 +1,93 @@ +/* + Haiku S3 Trio64 DPMS functions adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + + +#include "accel.h" +#include "trio64.h" + + + +uint32 +Trio64_DPMSCapabilities(void) +{ + // Return DPMS modes supported by this device. + + return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; +} + + +uint32 +Trio64_DPMSMode(void) +{ + // Return the current DPMS mode. + + // Note: I do not know whether the following code is correctly reading + // the current DPMS mode. I'm assuming that reading back the bits that + // were set by function Trio64_SetDPMSMode will give the current DPMS mode. + + uint32 mode = B_DPMS_ON; + + switch (ReadSeqReg(0x0d) & 0x70) { + case 0: + mode = B_DPMS_ON; + break; + case 0x10: + mode = B_DPMS_STAND_BY; + break; + case 0x40: + mode = B_DPMS_SUSPEND; + break; + case 0x50: + mode = B_DPMS_OFF; + break; + default: + TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d)); + } + + TRACE("Trio64_DPMSMode() mode: %d\n", mode); + return mode; +} + + +status_t +Trio64_SetDPMSMode(uint32 dpmsMode) +{ + // Set the display into one of the Display Power Management modes, + // and return B_OK if successful, else return B_ERROR. + + TRACE("Trio64_SetDPMSMode() mode: %d\n", dpmsMode); + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 sr0D = ReadSeqReg(0x0d) & 0x03; + + switch (dpmsMode) { + case B_DPMS_ON: + break; + case B_DPMS_STAND_BY: + sr0D |= 0x10; + break; + case B_DPMS_SUSPEND: + sr0D |= 0x40; + break; + case B_DPMS_OFF: + sr0D |= 0x50; + break; + default: + TRACE("Invalid DPMS mode %d\n", dpmsMode); + return B_ERROR; + } + + WriteSeqReg(0x0d, sr0D); + + return B_OK; +} diff --git a/src/add-ons/accelerants/s3/trio64_draw.cpp b/src/add-ons/accelerants/s3/trio64_draw.cpp new file mode 100644 index 0000000000..6f3d5bcc1e --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64_draw.cpp @@ -0,0 +1,155 @@ +/* + Haiku S3 Trio64 driver adapted from the X.org S3 driver. + + Copyright 2001 Ani Joshi + + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + + +#include "accel.h" +#include "trio64.h" + + + +void +Trio64_FillRectangle(engine_token* et, uint32 color, fill_rect_params* pList, + uint32 count) +{ + (void)et; // avoid compiler warning for unused arg + + gInfo.WaitQueue(3); + WriteReg16(MULTIFUNC_CNTL, 0xa000); + WriteReg32(FRGD_COLOR, color); + WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x07); // 7 = GXcopy rop + + while (count--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x; + int h = pList->bottom - y; + + gInfo.WaitQueue(5); + WriteReg16(CUR_X, x); + WriteReg16(CUR_Y, y); + WriteReg16(CUR_WIDTH, w); + WriteReg16(MULTIFUNC_CNTL, h); + WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA); + + pList++; + } +} + + +void +Trio64_FillSpan(engine_token* et, uint32 color, uint16* pList, uint32 count) +{ + (void)et; // avoid compiler warning for unused arg + + gInfo.WaitQueue(3); + WriteReg16(MULTIFUNC_CNTL, 0xa000); + WriteReg32(FRGD_COLOR, color); + WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x07); // 7 = GXcopy rop + + while (count--) { + int y = *pList++; + int x = *pList++; + int w = *pList++ - x; + + // Some S3 chips display a line completely across the screen when a + // span has zero width; thus, the following if statement discards any + // span with zero or negative width. + + if (w < 0) + continue; + + // Draw the span as a rectangle with a height of 1 to avoid the + // extra complexity of drawing a line. + + gInfo.WaitQueue(5); + WriteReg16(CUR_X, x); + WriteReg16(CUR_Y, y); + WriteReg16(CUR_WIDTH, w); + WriteReg16(MULTIFUNC_CNTL, 0); // height is 1; but as computed it is 0 + WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA); + } +} + + +void +Trio64_InvertRectangle(engine_token* et, fill_rect_params* pList, uint32 count) +{ + (void)et; // avoid compiler warning for unused arg + + gInfo.WaitQueue(2); + WriteReg16(MULTIFUNC_CNTL, 0xa000); + WriteReg16(FRGD_MIX, FSS_FRGDCOL | 0x00); // 0 = GXinvert rop + + while (count--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x; + int h = pList->bottom - y; + + gInfo.WaitQueue(5); + WriteReg16(CUR_X, x); + WriteReg16(CUR_Y, y); + WriteReg16(CUR_WIDTH, w); + WriteReg16(MULTIFUNC_CNTL, h); + WriteReg16(CMD, CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA); + + pList++; + } +} + + +void +Trio64_ScreenToScreenBlit(engine_token* et, blit_params* pList, uint32 count) +{ + (void)et; // avoid compiler warning for unused arg + + gInfo.WaitQueue(2); + WriteReg16(MULTIFUNC_CNTL, 0xa000); + WriteReg16(FRGD_MIX, FSS_BITBLT | 0x07); // 7 = GXcopy rop + + while (count--) { + int src_x = pList->src_left; + int src_y = pList->src_top; + int dest_x = pList->dest_left; + int dest_y = pList->dest_top; + int width = pList->width; + int height = pList->height; + + if (src_x == dest_x && src_y == dest_y) + continue; + + int cmd = CMD_BITBLT | DRAW | INC_X | INC_Y | WRTDATA; + + if (src_x < dest_x) { + src_x += width; + dest_x += width; + cmd &= ~INC_X; + } + + if (src_y < dest_y) { + src_y += height; + dest_y += height; + cmd &= ~INC_Y; + } + + gInfo.WaitQueue(7); + WriteReg16(CUR_X, src_x); + WriteReg16(CUR_Y, src_y); + WriteReg16(DESTX_DIASTP, dest_x); + WriteReg16(DESTY_AXSTP, dest_y); + WriteReg16(CUR_WIDTH, width); + WriteReg16(MULTIFUNC_CNTL, height); + WriteReg16(CMD, cmd); + + pList ++; + } +} diff --git a/src/add-ons/accelerants/s3/trio64_init.cpp b/src/add-ons/accelerants/s3/trio64_init.cpp new file mode 100644 index 0000000000..2566ce87fa --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64_init.cpp @@ -0,0 +1,176 @@ +/* + Haiku S3 Trio64 driver adapted from the X.org S3 driver. + + Copyright 2001 Ani Joshi + + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + + +#include "accel.h" +#include "trio64.h" + + + +static void +WaitQueue(uint32 slots ) +{ + // Wait until the requested number of queue slots are available. + + while (ReadReg16(GP_STAT) & (0x0100 >> slots)) {} +} + + +static void +WaitIdle() +{ + // Wait until Graphics Processor is idle. + + while (ReadReg16(GP_STAT) & GP_BUSY); +} + + + +static bool +Trio64_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock) +{ + // Get parameters for a color space which is supported by the Trio64 chips. + // Argument maxPixelClock is in KHz. + // Return true if the color space is supported; else return false. + + switch (colorSpace) { + case B_RGB16: + bitsPerPixel = 16; + maxPixelClock = 110000; + break; + case B_CMAP8: + bitsPerPixel = 8; + maxPixelClock = 180000; + break; + default: + TRACE("Unsupported color space: 0x%X\n", colorSpace); + return false; + } + + return true; +} + + +static bool +Trio64_IsModeUsable(const display_mode* mode) +{ + // Test if the display mode is usable by the current video chip. + // Return true if the mode is usable. + + SharedInfo& si = *gInfo.sharedInfo; + + if (si.chipType == S3_TRIO64 && mode->timing.h_display >= 1600) + return false; + + return IsModeUsable(mode); +} + + +static status_t +Trio64_Init(void) +{ + TRACE("Trio64_Init()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + // Use PIO to enable VGA, enable color instead of monochrome, and + // enable MMIO. + + WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01); + WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01); // enable color + + WritePIO_8(CRTC_INDEX, 0x53); + WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8); // enable MMIO + + WriteCrtcReg(0x38, 0x48); // unlock sys regs + WriteCrtcReg(0x39, 0xa5); // unlock sys regs + + WriteCrtcReg(0x40, 0x01, 0x01); + WriteCrtcReg(0x35, 0x00, 0x30); + WriteCrtcReg(0x33, 0x20, 0x72); + + if (si.chipType == S3_TRIO64_V2) { + WriteCrtcReg(0x86, 0x80); + WriteCrtcReg(0x90, 0x00); + } + + // Detect number of megabytes of installed ram. + + static const uint8 ramSizes[] = { 4, 0, 3, 8, 2, 6, 1, 0 }; + int ramSizeMB = ramSizes[(ReadCrtcReg(0x36) >> 5) & 0x7]; + + TRACE("memory size: %d MB\n", ramSizeMB); + + if (ramSizeMB <= 0) + return B_ERROR; + + si.videoMemSize = ramSizeMB * 1024 * 1024; + si.cursorOffset = si.videoMemSize - CURSOR_BYTES; // put cursor at end of video memory + si.frameBufferOffset = 0; + si.maxFrameBufferSize = si.videoMemSize - CURSOR_BYTES; + + // Detect current mclk. + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 m = ReadSeqReg(0x11) & 0x7f; + uint8 n = ReadSeqReg(0x10); + uint8 n1 = n & 0x1f; + uint8 n2 = (n >> 5) & 0x03; + si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100; + + TRACE("MCLK value: %1.3f MHz\n", si.mclk / 1000.0); + + // Set up the array of color spaces supported by the Trio64 chips. + + si.colorSpaces[0] = B_CMAP8; + si.colorSpaces[1] = B_RGB16; + si.colorSpaceCount = 2; + + // Setup the mode list. + + return CreateModeList(Trio64_IsModeUsable); +} + + +void +Trio64_SetFunctionPointers(void) +{ + // Setting the function pointers must be done prior to first ModeInit call + // or any accel activity. + + gInfo.WaitQueue = WaitQueue; + gInfo.WaitIdleEmpty = WaitIdle; + + gInfo.DPMSCapabilities = Trio64_DPMSCapabilities; + gInfo.DPMSMode = Trio64_DPMSMode; + gInfo.SetDPMSMode = Trio64_SetDPMSMode; + + gInfo.LoadCursorImage = Trio64_LoadCursorImage; + gInfo.SetCursorPosition = Trio64_SetCursorPosition; + gInfo.ShowCursor = Trio64_ShowCursor; + + // Note that the 2D accel functions set below do not work with all display + // modes; thus, when a mode is set, the function setting the mode will + // adjust the pointers according to the mode that is set. + + gInfo.FillRectangle = Trio64_FillRectangle; + gInfo.FillSpan = Trio64_FillSpan; + gInfo.InvertRectangle = Trio64_InvertRectangle; + gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit; + + gInfo.AdjustFrame = Trio64_AdjustFrame; + gInfo.ChipInit = Trio64_Init; + gInfo.GetColorSpaceParams = Trio64_GetColorSpaceParams; + gInfo.SetDisplayMode = Trio64_SetDisplayMode; + gInfo.SetIndexedColors = Trio64_SetIndexedColors; +} diff --git a/src/add-ons/accelerants/s3/trio64_mode.cpp b/src/add-ons/accelerants/s3/trio64_mode.cpp new file mode 100644 index 0000000000..fc212e2d74 --- /dev/null +++ b/src/add-ons/accelerants/s3/trio64_mode.cpp @@ -0,0 +1,333 @@ +/* + Haiku S3 Trio64 driver adapted from the X.org S3 driver. + + Copyright 2001 Ani Joshi + + Copyright 2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2008 +*/ + + +#include "accel.h" +#include "trio64.h" + + +#define BASE_FREQ 14.31818 // MHz + + +static void +Trio64_CalcClock(long freq, int min_m, int min_n1, int max_n1, + int min_n2, int max_n2, long freq_min, long freq_max, + uint8* mdiv, uint8* ndiv) +{ + uint8 best_n1 = 18, best_n2 = 2, best_m = 127; + + double ffreq = freq / 1000.0 / BASE_FREQ; + double ffreq_min = freq_min / 1000.0 / BASE_FREQ; + double ffreq_max = freq_max / 1000.0 / BASE_FREQ; + + if (ffreq < ffreq_min / (1 << max_n2)) { + TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n", + ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1 << max_n2)); + ffreq = ffreq_min / (1 << max_n2); + } + if (ffreq > ffreq_max / (1 << min_n2)) { + TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n", + ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1 << min_n2)); + ffreq = ffreq_max / (1 << min_n2); + } + + double best_diff = ffreq; + + for (uint8 n2 = min_n2; n2 <= max_n2; n2++) { + for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { + int m = (int)(ffreq * n1 * (1 << n2) + 0.5); + if (m < min_m + 2 || m > 127 + 2) + continue; + + double div = (double)(m) / (double)(n1); + if ((div >= ffreq_min) && (div <= ffreq_max)) { + double diff = ffreq - div / (1 << n2); + if (diff < 0.0) + diff = -diff; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + if (max_n1 == 63) + *ndiv = (best_n1 - 2) | (best_n2 << 6); + else + *ndiv = (best_n1 - 2) | (best_n2 << 5); + *mdiv = best_m - 2; +} + + + +static bool +Trio64_ModeInit(const DisplayModeEx& mode) +{ + SharedInfo& si = *gInfo.sharedInfo; + + TRACE("Trio64_ModeInit(%d x %d, %d KHz)\n", + mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); + + uint32 videoRamMB = si.videoMemSize / (1024 * 1024); // MB's of video RAM + + WriteCrtcReg(0x38, 0x48); // unlock sys regs + WriteCrtcReg(0x39, 0xa5); // unlock sys regs + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + WriteCrtcReg(0x45, 0x00, 0x01); // turn off hardware cursor + + uint8 sr12, sr13; + Trio64_CalcClock(mode.timing.pixel_clock, 1, 1, 31, 0, 3, 135000, 270000, + &sr13, &sr12); + + // Set clock registers. + + WriteSeqReg(0x12, sr12); + WriteSeqReg(0x13, sr13); + + // Activate clock + + uint8 tmp = ReadSeqReg(0x15) & ~0x21; + WriteSeqReg(0x15, tmp | 0x02); + WriteSeqReg(0x15, tmp | 0x22); + WriteSeqReg(0x15, tmp | 0x02); + + uint8 cr33 = ReadCrtcReg(0x33) & ~0x28; + uint8 cr50 = 0; + uint8 pixmux = 0; + + if (si.chipType == S3_TRIO64_V2) + cr33 |= 0x20; + + switch (mode.bpp) { + case 8: + break; + case 15: + cr33 |= 0x08; + cr50 = 0x10; + pixmux = 0x30; + break; + case 16: + cr33 |= 0x08; + cr50 = 0x10; + pixmux = 0x50; + break; + case 32: + cr50 = 0x30; + pixmux = 0xd0; + break; + } + + bool bEnableAccelFuncs = true; + + switch (mode.timing.h_display) { + case 640: + cr50 |= 0x40; + break; + case 800: + cr50 |= 0x80; + break; + case 1024: + cr50 |= 0x00; + break; + case 1152: + cr50 |= 0x01; + break; + case 1280: + cr50 |= 0xc0; + break; + case 1600: + cr50 |= 0x81; + break; + default: + bEnableAccelFuncs = false; // use app_server default accel functions + break; + } + + WriteCrtcReg(0x33, cr33); + WriteCrtcReg(0x50, cr50); // set number of bits per pixel & display width + WriteCrtcReg(0x67, pixmux); // set pixel format + + WriteSeqReg(0x15, 0x00, 0x10); // turn off pixel multiplex + WriteSeqReg(0x18, 0x00, 0x80); + + // Note that the 2D acceleration (drawing) functions in this accelerant work + // only with the display widths defined in the above switch statement. For + // the other widths, the default functions in the app_server will be used. + + if (bEnableAccelFuncs) + { + gInfo.FillRectangle = Trio64_FillRectangle; + gInfo.FillSpan = Trio64_FillSpan; + gInfo.InvertRectangle = Trio64_InvertRectangle; + gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit; + } + else + { + gInfo.FillRectangle = NULL; + gInfo.FillSpan = NULL; + gInfo.InvertRectangle = NULL; + gInfo.ScreenToScreenBlit = NULL; + } + + // Set the standard CRTC vga regs. + + uint8 crtc[25], cr3b, cr3c, cr5d, cr5e; + + InitCrtcTimingValues(mode, (mode.bpp > 8) ? 2 : 1, crtc, cr3b, cr3c, cr5d, cr5e); + crtc[0x17] = 0xe3; + + WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 + + for (int k = 0; k < NUM_ELEMENTS(crtc); k++) { + WriteCrtcReg(k, crtc[k]); + } + + WriteCrtcReg(0x3b, cr3b); + WriteCrtcReg(0x3c, cr3c); + WriteCrtcReg(0x5d, cr5d); + WriteCrtcReg(0x5e, cr5e); + + uint8 miscOutReg = 0x2f; + + if ( ! (mode.timing.flags & B_POSITIVE_HSYNC)) + miscOutReg |= 0x40; + if ( ! (mode.timing.flags & B_POSITIVE_VSYNC)) + miscOutReg |= 0x80; + + WriteMiscOutReg(miscOutReg); + + uint8 cr58; + if (videoRamMB <= 1) + cr58 = 0x01; + else if (videoRamMB <= 2) + cr58 = 0x02; + else + cr58 = 0x03; + + WriteCrtcReg(0x58, cr58 | 0x10, 0x13); // enable linear addressing & set memory size + + WriteCrtcReg(0x31, 0x08); + WriteCrtcReg(0x32, 0x00); + WriteCrtcReg(0x34, 0x10); + WriteCrtcReg(0x3a, 0x15); + + WriteCrtcReg(0x51, mode.bytesPerRow >> 7, 0x30); + WriteCrtcReg(0x53, 0x18, 0x18); + + int n = 255; + int clock2 = mode.timing.pixel_clock * (mode.bpp / 8); + if (videoRamMB < 2) + clock2 *= 2; + int m = (int)((gInfo.sharedInfo->mclk / 1000.0 * .72 + 16.867) * 89.736 + / (clock2 / 1000.0 + 39) - 21.1543); + if (videoRamMB < 2) + m /= 2; + if (m > 31) + m = 31; + else if (m < 0) { + m = 0; + n = 16; + } + + if (n < 0) + n = 0; + else if (n > 255) + n = 255; + + WriteCrtcReg(0x54, m << 3); + WriteCrtcReg(0x60, n); + + WriteCrtcReg(0x42, 0x00, 0x20); // disable interlace mode + WriteCrtcReg(0x66, 0x89, 0x8f); + + WriteReg16(ADVFUNC_CNTL, 0x0001); // enable enhanced functions + + WriteReg16(SUBSYS_CNTL, 0x8000); // reset graphics engine + WriteReg16(SUBSYS_CNTL, 0x4000); // enable graphics engine + ReadReg16(SUBSYS_STAT); + + WriteReg16(MULTIFUNC_CNTL, 0x5000 | 0x0004 | 0x000c); + + gInfo.WaitQueue(5); + WriteReg16(MULTIFUNC_CNTL, SCISSORS_L | 0); + WriteReg16(MULTIFUNC_CNTL, SCISSORS_T | 0); + WriteReg16(MULTIFUNC_CNTL, SCISSORS_R | (mode.timing.h_display - 1)); + WriteReg16(MULTIFUNC_CNTL, SCISSORS_B | ((si.maxFrameBufferSize / mode.bytesPerRow) - 1)); + + WriteReg32(WRT_MASK, ~0); // enable all planes + + TRACE("Trio64_ModeInit() exit\n"); + return true; +} + + +bool +Trio64_SetDisplayMode(const DisplayModeEx& mode) +{ + // The code to actually configure the display. + // All the error checking must be done in ProposeDisplayMode(), + // and assume that the mode values we get here are acceptable. + + WriteSeqReg(0x01, 0x20, 0x20); // blank the screen + + if ( ! Trio64_ModeInit(mode)) { + TRACE("Trio64_ModeInit() failed\n"); + return false; + } + + Trio64_AdjustFrame(mode); + + WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen + + return true; +} + + + +void +Trio64_AdjustFrame(const DisplayModeEx& mode) +{ + // Adjust start address in frame buffer. + + int base = (((mode.v_display_start * mode.virtual_width + mode.h_display_start) + * (mode.bpp / 8)) >> 2) & ~1; + base += gInfo.sharedInfo->frameBufferOffset; + + WriteCrtcReg(0x0c, (base >> 8) & 0xff); + WriteCrtcReg(0x0d, base & 0xff); + WriteCrtcReg(0x31, base >> 12, 0x30); // put bits 16-17 in bits 4-5 of CR31 + WriteCrtcReg(0x51, base >> 18, 0x03); // put bits 18-19 in bits 0-1 of CR51 +} + + +void +Trio64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) +{ + // Set the indexed color palette for 8-bit color depth mode. + + (void)flags; // avoid compiler warning for unused arg + + if (gInfo.sharedInfo->displayMode.space != B_CMAP8) + return ; + + while (count--) { + WriteIndexedColor(first++, // color index + colorData[0] >> 2, // red + colorData[1] >> 2, // green + colorData[2] >> 2); // blue + colorData += 3; + } +} diff --git a/src/add-ons/accelerants/s3/virge.h b/src/add-ons/accelerants/s3/virge.h new file mode 100644 index 0000000000..5886c04baa --- /dev/null +++ b/src/add-ons/accelerants/s3/virge.h @@ -0,0 +1,78 @@ +/* + Haiku S3 Virge driver adapted from the X.org S3 Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + + +#ifndef __VIRGE_H__ +#define __VIRGE_H__ + + + +#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory + +// Miscellaneous registers. +#define SUBSYS_STAT_REG 0x8504 +#define SYSTEM_CONTROL_REG 0x83DA +#define DDC_REG 0xFF20 + +// Memory port controller registers. +#define FIFO_CONTROL_REG 0x8200 + +// Image write stuff. +#define SRC_BASE 0xA4D4 +#define DEST_BASE 0xA4D8 +#define CLIP_L_R 0xA4DC +#define CLIP_T_B 0xA4E0 +#define DEST_SRC_STR 0xA4E4 +#define MONO_PAT_0 0xA4E8 +#define MONO_PAT_1 0xA4EC +#define PAT_BG_CLR 0xA4F0 +#define PAT_FG_CLR 0xA4F4 +#define CMD_SET 0xA500 +#define RWIDTH_HEIGHT 0xA504 +#define RSRC_XY 0xA508 +#define RDEST_XY 0xA50C + +// Command Register. +#define CMD_OP_MSK (0xf << 27) +#define CMD_BITBLT (0x0 << 27) +#define CMD_RECT ((0x2 << 27) | 0x0100) +#define CMD_LINE (0x3 << 27) +#define CMD_POLYFILL (0x5 << 27) +#define CMD_NOP (0xf << 27) + +#define DRAW 0x0020 + +// Destination Color Format. +#define DST_8BPP 0x00 +#define DST_16BPP 0x04 +#define DST_24BPP 0x08 + +// X Positive, Y Positive (Bit BLT). +#define CMD_XP 0x02000000 +#define CMD_YP 0x04000000 + + +#define IN_SUBSYS_STAT() (ReadReg32(SUBSYS_STAT_REG)) + + +static inline void VerticalRetraceWait() +{ + if (ReadCrtcReg(0x17) & 0x80) { + int i = 0x10000; + while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ; + i = 0x10000; + while ((ReadReg8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ; + } +} + + +#endif // __VIRGE_H__ diff --git a/src/add-ons/accelerants/s3/virge_cursor.cpp b/src/add-ons/accelerants/s3/virge_cursor.cpp new file mode 100644 index 0000000000..ef831f4c1f --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_cursor.cpp @@ -0,0 +1,112 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" +#include "virge.h" + + + +void +Virge_ShowCursor(bool bShow) +{ + // Turn cursor on/off. + + WriteCrtcReg(0x45, bShow ? 0x01 : 0x00, 0x01); +} + + +void +Virge_SetCursorPosition(int x, int y) +{ + uint8 xOffset = 0; + uint8 yOffset = 0; + + // xOffset & yOffset are used for displaying partial cursors on screen edges. + + if (x < 0) { + xOffset = (( -x) & 0xfe); + x = 0; + } + + if (y < 0) { + yOffset = (( -y) & 0xfe); + y = 0; + } + + // Note: when setting the cursor position, register 48 must be set last + // since setting register 48 activates the new cursor position. + + WriteCrtcReg( 0x4e, xOffset ); + WriteCrtcReg( 0x4f, yOffset ); + + WriteCrtcReg( 0x47, (x & 0xff) ); + WriteCrtcReg( 0x46, (x & 0x0700) >> 8 ); + + WriteCrtcReg( 0x49, (y & 0xff) ); + WriteCrtcReg( 0x48, (y & 0x0700) >> 8 ); +} + + +bool +Virge_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask) +{ + SharedInfo& si = *gInfo.sharedInfo; + + if (andMask == NULL || xorMask == NULL) + return false; + + // Initialize hardware cursor to be completely transparent. + + uint16* fbCursor16 = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int i = 0; i < CURSOR_BYTES; i += 4) { + *fbCursor16++ = ~0; // and bits + *fbCursor16++ = 0; // xor bits + } + + // Now load the AND & XOR masks for the cursor image into the cursor + // buffer. Note that a particular bit in these masks will have the + // following effect upon the corresponding cursor pixel: + // AND XOR Result + // 0 0 White pixel + // 0 1 Black pixel + // 1 0 Screen color (for transparency) + // 1 1 Reverse screen color to black or white + + uint8* fbCursor = (uint8*)((addr_t)si.videoMemAddr + si.cursorOffset); + + for (int row = 0; row < height; row++) { + for (int colByte = 0; colByte < width / 8; colByte++) { + fbCursor[row * 16 + colByte] = *andMask++; + fbCursor[row * 16 + colByte + 2] = *xorMask++; + } + } + + // Set cursor location in video memory. + + WriteCrtcReg(0x4d, (0xff & si.cursorOffset / 1024)); + WriteCrtcReg(0x4c, (0x0f00 & si.cursorOffset / 1024) >> 8); + + // Set the cursor colors which are black foreground and white background. + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4a, 0); // set foreground color stack low, mid, high bytes + WriteCrtcReg(0x4a, 0); + WriteCrtcReg(0x4a, 0); + + ReadCrtcReg(0x45); // reset cursor color stack pointer + WriteCrtcReg(0x4b, ~0); // set background color stack low, mid, high bytes + WriteCrtcReg(0x4b, ~0); + WriteCrtcReg(0x4b, ~0); + + return true; +} diff --git a/src/add-ons/accelerants/s3/virge_dpms.cpp b/src/add-ons/accelerants/s3/virge_dpms.cpp new file mode 100644 index 0000000000..55eb108ae8 --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_dpms.cpp @@ -0,0 +1,93 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + + +#include "accel.h" +#include "virge.h" + + + +uint32 +Virge_DPMSCapabilities(void) +{ + // Return DPMS modes supported by this device. + + return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; +} + + +uint32 +Virge_DPMSMode(void) +{ + // Return the current DPMS mode. + + // Note: I do not know whether the following code is correctly reading + // the current DPMS mode. I'm assuming that reading back the bits that + // were set by function Virge_SetDPMSMode will give the current DPMS mode. + + uint32 mode = B_DPMS_ON; + + switch (ReadSeqReg(0x0d) & 0x70) { + case 0: + mode = B_DPMS_ON; + break; + case 0x10: + mode = B_DPMS_STAND_BY; + break; + case 0x40: + mode = B_DPMS_SUSPEND; + break; + case 0x50: + mode = B_DPMS_OFF; + break; + default: + TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d)); + } + + TRACE("Virge_DPMSMode() mode: %d\n", mode); + return mode; +} + + +status_t +Virge_SetDPMSMode(uint32 dpmsMode) +{ + // Set the display into one of the Display Power Management modes, + // and return B_OK if successful, else return B_ERROR. + + TRACE("Virge_SetDPMSMode() mode: %d\n", dpmsMode); + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 sr0D = ReadSeqReg(0x0d) & 0x03; + + switch (dpmsMode) { + case B_DPMS_ON: + break; + case B_DPMS_STAND_BY: + sr0D |= 0x10; + break; + case B_DPMS_SUSPEND: + sr0D |= 0x40; + break; + case B_DPMS_OFF: + sr0D |= 0x50; + break; + default: + TRACE("Invalid DPMS mode %d\n", dpmsMode); + return B_ERROR; + } + + WriteSeqReg(0x0d, sr0D); + + return B_OK; +} diff --git a/src/add-ons/accelerants/s3/virge_draw.cpp b/src/add-ons/accelerants/s3/virge_draw.cpp new file mode 100644 index 0000000000..153fa062bb --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_draw.cpp @@ -0,0 +1,161 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007 +*/ + + +#include "accel.h" +#include "virge.h" + + + +static inline void WaitForSync() +{ + while ((IN_SUBSYS_STAT() & 0x2000) == 0) ; +} + + + +void +Virge_FillRectangle(engine_token* et, uint32 color, fill_rect_params* pList, uint32 count) +{ + int rop = 0xF0; + int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP ; + + (void)et; // avoid compiler warning for unused arg + + cmd |= gInfo.sharedInfo->commonCmd; + + while (count--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x + 1; + int h = pList->bottom - y + 1; + + gInfo.WaitQueue(4); + WriteReg32(PAT_FG_CLR, color); + WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) | h); + WriteReg32(RDEST_XY, (x << 16) | y); + WriteReg32(CMD_SET, cmd); + WaitForSync(); + + pList++; + } +} + + +void +Virge_FillSpan(engine_token* et, uint32 color, uint16* pList, uint32 count) +{ + int rop = 0xF0; + int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP ; + + (void)et; // avoid compiler warning for unused arg + + cmd |= gInfo.sharedInfo->commonCmd; + + while (count--) { + int y = *pList++; + int x = *pList++; + int w = *pList++ - x + 1; + + // The MediaPlayer in Zeta 1.21 displays a window which has 2 zero width + // spans which the Virge chips display as a line completely across the + // screen; thus, the following if statement discards any span with zero + // or negative width. + + if (w <= 0) + continue; + + // Draw the span as a rectangle with a height of 1 to avoid the + // extra complexity of drawing a line. + + gInfo.WaitQueue(4); + WriteReg32(PAT_FG_CLR, color); + WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) | 1); + WriteReg32(RDEST_XY, (x << 16) | y); + WriteReg32(CMD_SET, cmd); + WaitForSync(); + } +} + + +void +Virge_InvertRectangle(engine_token* et, fill_rect_params* pList, uint32 count) +{ + int rop = 0x55; // use GXinvert for rop + int cmd = DRAW | rop << 17 | CMD_RECT | CMD_XP | CMD_YP; + + (void)et; // avoid compiler warning for unused arg + + cmd |= gInfo.sharedInfo->commonCmd; + + while (count--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x + 1; + int h = pList->bottom - y + 1; + + gInfo.WaitQueue(3); + WriteReg32(RWIDTH_HEIGHT, ((w - 1) << 16) + h); + WriteReg32(RDEST_XY, (x << 16) | y); + WriteReg32(CMD_SET, cmd); + WaitForSync(); + + pList++; + } +} + + +void +Virge_ScreenToScreenBlit(engine_token* et, blit_params* pList, uint32 count) +{ + int rop = 0xCC; // use GXcopy for rop + int cmd = DRAW | rop << 17 | CMD_BITBLT | CMD_XP | CMD_YP; + + (void)et; // avoid compiler warning for unused arg + + cmd |= gInfo.sharedInfo->commonCmd; + + while (count--) { + int src_x = pList->src_left; + int src_y = pList->src_top; + int dest_x = pList->dest_left; + int dest_y = pList->dest_top; + int width = pList->width; + int height = pList->height; + + if (src_x == dest_x && src_y == dest_y) + continue; + + cmd |= CMD_XP | CMD_YP; // restore these flags in case removed on last iteration + + if (src_x < dest_x) { + src_x += width; + dest_x += width; + cmd &= ~CMD_XP; + } + + if (src_y < dest_y) { + src_y += height; + dest_y += height; + cmd &= ~CMD_YP; + } + + gInfo.WaitQueue(4); + WriteReg32(RWIDTH_HEIGHT, ((width) << 16) | (height + 1)); + WriteReg32(RSRC_XY, (src_x << 16) | src_y); + WriteReg32(RDEST_XY, (dest_x << 16) | dest_y); + WriteReg32(CMD_SET, cmd); + WaitForSync(); + + pList ++; + } +} diff --git a/src/add-ons/accelerants/s3/virge_edid.cpp b/src/add-ons/accelerants/s3/virge_edid.cpp new file mode 100644 index 0000000000..57d7e6c932 --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_edid.cpp @@ -0,0 +1,130 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge and Savage driver. + + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + +#include "accel.h" +#include "virge.h" + +#include +#include +#include + + + +static status_t +GetI2CSignals_Alt(void* cookie, int* _clock, int* data) +{ + uint32 index = (uint32)cookie; + uint8 value = ReadCrtcReg(index); + + *_clock = (value & 0x4) != 0; + *data = (value & 0x8) != 0; + return B_OK; +} + + +static status_t +SetI2CSignals_Alt(void* cookie, int _clock, int data) +{ + uint32 index = (uint32)cookie; + uint8 value = 0x10; + + if (_clock) + value |= 0x1; + if (data) + value |= 0x2; + + WriteCrtcReg(index, value); + return B_OK; +} + + + +static status_t +GetI2CSignals(void* cookie, int* _clock, int* data) +{ + (void)cookie; // avoid compiler warning for unused arg + + uint8 reg = ReadReg8(DDC_REG); + + *_clock = (reg & 0x4) != 0; + *data = (reg & 0x8) != 0; + return B_OK; +} + + +static status_t +SetI2CSignals(void* cookie, int _clock, int data) +{ + (void)cookie; // avoid compiler warning for unused arg + + uint8 reg = 0x10; + + if (_clock) + reg |= 0x1; + if (data) + reg |= 0x2; + + WriteReg8(DDC_REG, reg); + return B_OK; +} + + + +bool +Virge_GetEdidInfo(void) +{ + // Get the EDID info and return true if successful. + + SharedInfo& si = *gInfo.sharedInfo; + + si.bHaveEDID = false; + + if (si.chipType == S3_TRIO_3D_2X) { + uint32 DDCPort = 0xAA; + + i2c_bus bus; + bus.cookie = (void*)DDCPort; + bus.set_signals = &SetI2CSignals_Alt; + bus.get_signals = &GetI2CSignals_Alt; + ddc2_init_timing(&bus); + + uint8 tmp = ReadCrtcReg(DDCPort); + WriteCrtcReg(DDCPort, tmp | 0x13); + + si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); + + WriteCrtcReg(DDCPort, tmp); + } else { + i2c_bus bus; + bus.cookie = (void*)DDC_REG; + bus.set_signals = &SetI2CSignals; + bus.get_signals = &GetI2CSignals; + ddc2_init_timing(&bus); + + uint8 tmp = ReadReg8(DDC_REG); + WriteReg8(DDC_REG, tmp | 0x13); + + si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); + + WriteReg8(DDC_REG, tmp); + } + + if (si.bHaveEDID) { +#ifdef ENABLE_DEBUG_TRACE + edid_dump(&(si.edidInfo)); +#endif + } else { + TRACE("Virge_GetEdidInfo() failed!\n"); + } + + return si.bHaveEDID; +} diff --git a/src/add-ons/accelerants/s3/virge_init.cpp b/src/add-ons/accelerants/s3/virge_init.cpp new file mode 100644 index 0000000000..5fa89bb401 --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_init.cpp @@ -0,0 +1,271 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + + +#include "accel.h" +#include "virge.h" + + + +static void +VirgeWaitFifoGX2(uint32 slots ) +{ + while (((ReadReg32(SUBSYS_STAT_REG) >> 9) & 0x60) < slots) {} +} + + + +static void +VirgeWaitFifoMain(uint32 slots ) +{ + while (((ReadReg32(SUBSYS_STAT_REG) >> 8) & 0x1f) < slots) {} +} + + +static void +VirgeWaitIdleEmpty() +{ + // Wait until GP is idle and queue is empty. + + if(gInfo.sharedInfo->chipType == S3_TRIO_3D) + while ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000); + else + while ((IN_SUBSYS_STAT() & 0x3f00) != 0x3000); +} + + +static bool +Virge_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock) +{ + // Get parameters for a color space which is supported by the Virge chips. + // Argument maxPixelClock is in KHz. + // Return true if the color space is supported; else return false. + + // Note that the X.org code set the max clock to 440000 for a Virge VX chip + // and 270000 for all other chips. 440000 seems rather high for a chip that + // old; thus, 270000 is used for all chips. + + switch (colorSpace) { + case B_RGB16: + bitsPerPixel = 16; + maxPixelClock = 270000; + break; + case B_CMAP8: + bitsPerPixel = 8; + maxPixelClock = 270000; + break; + default: + TRACE("Unsupported color space: 0x%X\n", colorSpace); + return false; + } + + return true; +} + + + +status_t +Virge_Init(void) +{ + TRACE("Virge_Init()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + // Use PIO for following operations since MMIO may not be currently enabled. + + WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01); // enable VGA + WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01); // enable color + + // Set linear base register to the PCI register value; + // some DX chipsets don't seem to do it automatically. + + WritePIO_8(CRTC_INDEX, 0x59); + WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 24); + WritePIO_8(CRTC_INDEX, 0x5A); + WritePIO_8(CRTC_DATA, (uint32)(si.videoMemPCI) >> 16); + + // Enable MMIO. + + WritePIO_8(CRTC_INDEX, 0x53); + WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8); + + if (si.chipType == S3_TRIO_3D) + WriteCrtcReg(0x40, 0x01, 0x01); + + // Detect amount of installed ram. + + uint8 config1 = ReadCrtcReg(0x36); // get amount of vram installed + uint8 config2 = ReadCrtcReg(0x37); // get amount of off-screen ram + + // Compute the amount of video memory and offscreen memory. + + int ramOffScreenMB = 0; // off screen memory size in megabytes + int ramSizeMB = 0; // memory size in megabytes + + if (si.chipType == S3_VIRGE_VX) { + switch ((config2 & 0x60) >> 5) { + case 1: + ramOffScreenMB = 4; + break; + case 2: + ramOffScreenMB = 2; + break; + } + + switch ((config1 & 0x60) >> 5) { + case 0: + ramSizeMB = 2; + break; + case 1: + ramSizeMB = 4; + break; + case 2: + ramSizeMB = 6; + break; + case 3: + ramSizeMB = 8; + break; + } + ramSizeMB -= ramOffScreenMB; + + } else if (si.chipType == S3_TRIO_3D_2X) { + switch ((config1 & 0xE0) >> 5) { + case 0: // 8MB -- only 4MB usable for display/cursor + ramSizeMB = 4; + ramOffScreenMB = 4; + break; + case 1: // 32 bit interface -- yuck + TRACE("Undefined video memory size on S3 Trio 3D/2X\n"); + case 2: + ramSizeMB = 4; + break; + case 6: + ramSizeMB = 2; + break; + } + } else if (si.chipType == S3_TRIO_3D) { + switch ((config1 & 0xE0) >> 5) { + case 0: + case 2: + ramSizeMB = 4; + break; + case 4: + ramSizeMB = 2; + break; + } + } else if (si.chipType == S3_VIRGE_GX2 || S3_VIRGE_MX_SERIES(si.chipType)) { + switch ((config1 & 0xC0) >> 6) { + case 1: + ramSizeMB = 4; + break; + case 3: + ramSizeMB = 2; + break; + } + } else { + switch ((config1 & 0xE0) >> 5) { + case 0: + ramSizeMB = 4; + break; + case 4: + ramSizeMB = 2; + break; + case 6: + ramSizeMB = 1; + break; + } + } + + TRACE("usable memory: %d MB, off-screen memory: %d MB\n", ramSizeMB, ramOffScreenMB); + + if (ramSizeMB <= 0) + return B_ERROR; + + si.videoMemSize = ramSizeMB * 1024 * 1024; + si.cursorOffset = si.videoMemSize - CURSOR_BYTES; // put cursor at end of video memory + si.frameBufferOffset = 0; + si.maxFrameBufferSize = si.videoMemSize - CURSOR_BYTES; + + // Detect current mclk. + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + uint8 m = ReadSeqReg(0x11) & 0x7f; + uint8 n = ReadSeqReg(0x10); + uint8 n1 = n & 0x1f; + uint8 n2 = (n >> 5) & 0x03; + si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100; + + TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0); + + if (S3_VIRGE_MX_SERIES(si.chipType)) { + si.displayType = ((ReadSeqReg(0x31) & 0x10) ? MT_LCD : MT_CRT); + si.panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8; + si.panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1; + + TRACE("%dx%d LCD panel detected %s\n", si.panelX, si.panelY, + si.displayType == MT_LCD ? "and active" : "but not active"); + } else { + si.displayType = MT_CRT; + si.panelX = 0; + si.panelY = 0; + } + + // Set up the array of color spaces supported by the Virge/Trio3D chips. + + si.colorSpaces[0] = B_CMAP8; + si.colorSpaces[1] = B_RGB16; + si.colorSpaceCount = 2; + + // Get info about the display capabilities (EDID). + + Virge_GetEdidInfo(); + + // Setup the mode list. + + return CreateModeList(IsModeUsable); +} + + +void +Virge_SetFunctionPointers(void) +{ + // Setting the function pointers must be done prior to first ModeInit call + // or any accel activity. + + if (S3_VIRGE_GX2_SERIES(gInfo.sharedInfo->chipType)) { + gInfo.WaitQueue = VirgeWaitFifoGX2; + } else { + gInfo.WaitQueue = VirgeWaitFifoMain; + } + + gInfo.WaitIdleEmpty = VirgeWaitIdleEmpty; + + gInfo.DPMSCapabilities = Virge_DPMSCapabilities; + gInfo.DPMSMode = Virge_DPMSMode; + gInfo.SetDPMSMode = Virge_SetDPMSMode; + + gInfo.LoadCursorImage = Virge_LoadCursorImage; + gInfo.SetCursorPosition = Virge_SetCursorPosition; + gInfo.ShowCursor = Virge_ShowCursor; + + gInfo.FillRectangle = Virge_FillRectangle; + gInfo.FillSpan = Virge_FillSpan; + gInfo.InvertRectangle = Virge_InvertRectangle; + gInfo.ScreenToScreenBlit = Virge_ScreenToScreenBlit; + + gInfo.AdjustFrame = Virge_AdjustFrame; + gInfo.ChipInit = Virge_Init; + gInfo.GetColorSpaceParams = Virge_GetColorSpaceParams; + gInfo.SetDisplayMode = Virge_SetDisplayMode; + gInfo.SetIndexedColors = Virge_SetIndexedColors; +} diff --git a/src/add-ons/accelerants/s3/virge_mode.cpp b/src/add-ons/accelerants/s3/virge_mode.cpp new file mode 100644 index 0000000000..87bfcf39d1 --- /dev/null +++ b/src/add-ons/accelerants/s3/virge_mode.cpp @@ -0,0 +1,767 @@ +/* + Haiku S3 Virge driver adapted from the X.org Virge driver. + + Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. + + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. + + Authors: + Gerald Zajac 2007-2008 +*/ + + +#include "accel.h" +#include "virge.h" + + +#define BASE_FREQ 14.31818 // MHz + + +struct VirgeRegRec { + uint8 CRTC[25]; // Crtc Controller reg's + + uint8 SR0A, SR0F; + uint8 SR12, SR13, SR15, SR18; // SR9-SR1C, ext seq. + uint8 SR29; + uint8 SR54, SR55, SR56, SR57; + uint8 CR31, CR33, CR34, CR3A, CR3B, CR3C; + uint8 CR40, CR41, CR42, CR43, CR45; + uint8 CR51, CR53, CR54, CR58, CR5D, CR5E; + uint8 CR63, CR65, CR66, CR67, CR68, CR69, CR6D; // Video attrib. + uint8 CR7B, CR7D; + uint8 CR85, CR86, CR87; + uint8 CR90, CR91, CR92, CR93; +}; + + + + +static void +Virge_EngineReset(const DisplayModeEx& mode) +{ + SharedInfo& si = *gInfo.sharedInfo; + + switch (mode.bpp) { + case 8: + si.commonCmd = DRAW | DST_8BPP; + break; + case 16: + si.commonCmd = DRAW | DST_16BPP; + break; + case 24: + si.commonCmd = DRAW | DST_24BPP; + break; + } + + + gInfo.WaitQueue(6); + WriteReg32(CMD_SET, CMD_NOP); // turn off auto-execute + WriteReg32(SRC_BASE, 0); + WriteReg32(DEST_BASE, 0); + WriteReg32(DEST_SRC_STR, mode.bytesPerRow | (mode.bytesPerRow << 16)); + + WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); + WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); +} + + + +static void +Virge_NopAllCmdSets() +{ + // This function should be called only for the Trio 3D chip. + + for (int i = 0; i < 1000; i++) { + if ( (IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) == 0x20002000) { + break; + } + } + + gInfo.WaitQueue(7); + WriteReg32(CMD_SET, CMD_NOP); +} + + + +static void +Virge_GEReset(const DisplayModeEx& mode) +{ + SharedInfo& si = *gInfo.sharedInfo; + + if (si.chipType == S3_TRIO_3D) + Virge_NopAllCmdSets(); + + gInfo.WaitIdleEmpty(); + + if (si.chipType == S3_TRIO_3D) { + bool ge_was_on = false; + snooze(10000); + + for (int r = 1; r < 10; r++) { + uint8 resetidx = 0x66; + + VerticalRetraceWait(); + uint8 tmp = ReadCrtcReg(resetidx); + + VerticalRetraceWait(); + IN_SUBSYS_STAT(); + + // turn off the GE + + if (tmp & 0x01) { + WriteCrtcReg(resetidx, tmp); + ge_was_on = true; + snooze(10000); + } + + IN_SUBSYS_STAT(); + WriteCrtcReg(resetidx, tmp | 0x02); + snooze(10000); + + VerticalRetraceWait(); + WriteCrtcReg(resetidx, tmp & ~0x02); + snooze(10000); + + if (ge_was_on) { + tmp |= 0x01; + WriteCrtcReg(resetidx, tmp); + snooze(10000); + } + + VerticalRetraceWait(); + + Virge_NopAllCmdSets(); + gInfo.WaitIdleEmpty(); + + WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); + snooze(10000); + + if ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000) { + TRACE("Restarting S3 graphics engine reset %2d ...%lx\n", + r, IN_SUBSYS_STAT() ); + } else + break; + } + } else { + uint8 regIndex = (si.chipType == S3_VIRGE_VX ? 0x63 : 0x66); + uint8 tmp = ReadCrtcReg(regIndex); + snooze(10000); + + // try multiple times to avoid lockup of VIRGE/MX + + for (int r = 1; r < 10; r++) { + WriteCrtcReg(regIndex, tmp | 0x02); + snooze(10000); + WriteCrtcReg(regIndex, tmp & ~0x02); + snooze(10000); + gInfo.WaitIdleEmpty(); + + WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); + snooze(10000); + + if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) { + TRACE("Restarting S3 graphics engine reset %2d ...\n", r); + } else + break; + } + } + + gInfo.WaitQueue(2); + WriteReg32(SRC_BASE, 0); + WriteReg32(DEST_BASE, 0); + + gInfo.WaitQueue(4); + WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); + WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); + WriteReg32(MONO_PAT_0, ~0); + WriteReg32(MONO_PAT_1, ~0); + + if (si.chipType == S3_TRIO_3D) + Virge_NopAllCmdSets(); +} + + + +static void +Virge_CalcClock(long freq, int min_m, + int min_n1, int max_n1, + int min_n2, int max_n2, + long freq_min, long freq_max, + uint8* mdiv, uint8* ndiv) +{ + uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2; + + double ffreq = freq / 1000.0 / BASE_FREQ; + double ffreq_min = freq_min / 1000.0 / BASE_FREQ; + double ffreq_max = freq_max / 1000.0 / BASE_FREQ; + + if (ffreq < ffreq_min / (1 << max_n2)) { + TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f MHz]\n", + ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2) ); + ffreq = ffreq_min / (1 << max_n2); + } + if (ffreq > ffreq_max / (1 << min_n2)) { + TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f MHz]\n", + ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2) ); + ffreq = ffreq_max / (1 << min_n2); + } + + // Work out suitable timings. + + double best_diff = ffreq; + + for (uint8 n2 = min_n2; n2 <= max_n2; n2++) { + for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { + int m = (int)(ffreq * n1 * (1 << n2) + 0.5) ; + if (m < min_m + 2 || m > 127 + 2) + continue; + + double div = (double)(m) / (double)(n1); + if ((div >= ffreq_min) && (div <= ffreq_max)) { + double diff = ffreq - div / (1 << n2); + if (diff < 0.0) + diff = -diff; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + if (max_n1 == 63) + *ndiv = (best_n1 - 2) | (best_n2 << 6); + else + *ndiv = (best_n1 - 2) | (best_n2 << 5); + *mdiv = best_m - 2; +} + + + +static void +Virge_WriteMode(const DisplayModeEx& mode, VirgeRegRec& regRec) +{ + // This function writes out all of the standard VGA and extended S3 registers + // needed to setup a video mode. + + TRACE("Virge_WriteMode()\n"); + + SharedInfo& si = *gInfo.sharedInfo; + + // First reset GE to make sure nothing is going on. + + if (ReadCrtcReg(si.chipType == S3_VIRGE_VX ? 0x63 : 0x66) & 0x01) + Virge_GEReset(mode); + + // As per databook, always disable STREAMS before changing modes. + + if ((ReadCrtcReg(0x67) & 0x0c) == 0x0c) { + // STREAMS running, disable it + VerticalRetraceWait(); + WriteReg32(FIFO_CONTROL_REG, 0xC000); + + WriteCrtcReg(0x67, 0x00, 0x0c); // disable STREAMS processor + } + + // Restore S3 extended regs. + WriteCrtcReg(0x63, regRec.CR63); + WriteCrtcReg(0x66, regRec.CR66); + WriteCrtcReg(0x3a, regRec.CR3A); + WriteCrtcReg(0x31, regRec.CR31); + WriteCrtcReg(0x58, regRec.CR58); + + // Extended mode timings registers. + WriteCrtcReg(0x53, regRec.CR53); + WriteCrtcReg(0x5d, regRec.CR5D); + WriteCrtcReg(0x5e, regRec.CR5E); + WriteCrtcReg(0x3b, regRec.CR3B); + WriteCrtcReg(0x3c, regRec.CR3C); + WriteCrtcReg(0x43, regRec.CR43); + WriteCrtcReg(0x65, regRec.CR65); + WriteCrtcReg(0x6d, regRec.CR6D); + + // Restore the desired video mode with CR67. + + WriteCrtcReg(0x67, 0x50, 0xf0); // possible hardware bug on VX? + snooze(10000); + WriteCrtcReg(0x67, regRec.CR67 & ~0x0c); // Don't enable STREAMS + + // Other mode timing and extended regs. + + WriteCrtcReg(0x34, regRec.CR34); + if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { + WriteCrtcReg(0x40, regRec.CR40); + } + + if (S3_VIRGE_MX_SERIES(si.chipType)) { + WriteCrtcReg(0x41, regRec.CR41); + } + + WriteCrtcReg(0x42, regRec.CR42); + WriteCrtcReg(0x45, regRec.CR45); + WriteCrtcReg(0x51, regRec.CR51); + WriteCrtcReg(0x54, regRec.CR54); + + // Memory timings. + WriteCrtcReg(0x68, regRec.CR68); + WriteCrtcReg(0x69, regRec.CR69); + + WriteCrtcReg(0x33, regRec.CR33); + if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType) + /* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) { + WriteCrtcReg(0x85, regRec.CR85); + } + + if (si.chipType == S3_VIRGE_DXGX) { + WriteCrtcReg(0x86, regRec.CR86); + } + + if ( (si.chipType == S3_VIRGE_GX2) || S3_VIRGE_MX_SERIES(si.chipType) ) { + WriteCrtcReg(0x7b, regRec.CR7B); + WriteCrtcReg(0x7d, regRec.CR7D); + WriteCrtcReg(0x87, regRec.CR87); + WriteCrtcReg(0x92, regRec.CR92); + WriteCrtcReg(0x93, regRec.CR93); + } + + if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) || + S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) { + WriteCrtcReg(0x90, regRec.CR90); + WriteCrtcReg(0x91, regRec.CR91); + } + + WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs + + // Restore extended sequencer regs for DCLK. + + WriteSeqReg(0x12, regRec.SR12); + WriteSeqReg(0x13, regRec.SR13); + + if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { + WriteSeqReg(0x29, regRec.SR29); + } + if (S3_VIRGE_MX_SERIES(si.chipType)) { + WriteSeqReg(0x54, regRec.SR54); + WriteSeqReg(0x55, regRec.SR55); + WriteSeqReg(0x56, regRec.SR56); + WriteSeqReg(0x57, regRec.SR57); + } + + WriteSeqReg(0x18, regRec.SR18); + + // Load new m,n PLL values for DCLK & MCLK. + uint8 tmp = ReadSeqReg(0x15) & ~0x21; + WriteSeqReg(0x15, tmp | 0x03); + WriteSeqReg(0x15, tmp | 0x23); + WriteSeqReg(0x15, tmp | 0x03); + WriteSeqReg(0x15, regRec.SR15); + + if (si.chipType == S3_TRIO_3D) { + WriteSeqReg(0x0a, regRec.SR0A); + WriteSeqReg(0x0f, regRec.SR0F); + } + + // Now write out CR67 in full, possibly starting STREAMS. + + VerticalRetraceWait(); + WriteCrtcReg(0x67, 0x50); // For possible bug on VX?! + snooze(10000); + WriteCrtcReg(0x67, regRec.CR67); + + uint8 cr66 = ReadCrtcReg(0x66); + WriteCrtcReg(0x66, cr66 | 0x80); + + WriteCrtcReg(0x3a, regRec.CR3A | 0x80); + + // Now, before we continue, check if this mode has the graphic engine ON. + // If yes, then we reset it. + + if (si.chipType == S3_VIRGE_VX) { + if (regRec.CR63 & 0x01) + Virge_GEReset(mode); + } else { + if (regRec.CR66 & 0x01) + Virge_GEReset(mode); + } + + VerticalRetraceWait(); + if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { + WriteCrtcReg(0x85, 0x1f); // primary stream threshold + } + + // Set the standard CRTC vga regs. + + WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 + + for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++) { + WriteCrtcReg(j, regRec.CRTC[j]); + } + + // Setup HSYNC & VSYNC polarity and select clock source 2 (0x0c) for + // programmable PLL. + + uint8 miscOutReg = 0x23 | 0x0c; + + if (!(mode.timing.flags & B_POSITIVE_HSYNC)) + miscOutReg |= 0x40; + if (!(mode.timing.flags & B_POSITIVE_VSYNC)) + miscOutReg |= 0x80; + + WriteMiscOutReg(miscOutReg); + + WriteCrtcReg(0x66, cr66); + WriteCrtcReg(0x3a, regRec.CR3A); + + return ; +} + + + +static bool +Virge_ModeInit(const DisplayModeEx& mode) +{ + SharedInfo& si = *gInfo.sharedInfo; + VirgeRegRec regRec; + + TRACE("Virge_ModeInit(%d x %d, %d KHz)\n", + mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); + + // Set scale factors for mode timings. + + int horizScaleFactor = 1; + + if (si.chipType == S3_VIRGE_VX || S3_VIRGE_GX2_SERIES(si.chipType) || + S3_VIRGE_MX_SERIES(si.chipType)) { + horizScaleFactor = 1; + } else if (mode.bpp == 8) { + horizScaleFactor = 1; + } else if (mode.bpp == 16) { + if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000) + horizScaleFactor = 1; + else + horizScaleFactor = 2; + } else { + horizScaleFactor = 1; + } + + InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC, + regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E); + + // Now we fill in the rest of the stuff we need for the Virge. + // Start with MMIO, linear address regs. + + uint8 temp = ReadCrtcReg(0x3a); + if ( S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) + regRec.CR3A = (temp & 0x7f) | 0x10; // ENH 256, PCI burst + else + regRec.CR3A = (temp & 0x7f) | 0x15; // ENH 256, PCI burst + + regRec.CR53 = ReadCrtcReg(0x53); + + if (si.chipType == S3_TRIO_3D) { + regRec.CR31 = 0x0c; // [trio3d] page 54 + } else { + regRec.CR53 = 0x08; // Enables MMIO + regRec.CR31 = 0x8c; // Dis. 64k window, en. ENH maps + } + + // Enables S3D graphic engine and PCI disconnects. + if (si.chipType == S3_VIRGE_VX) { + regRec.CR66 = 0x90; + regRec.CR63 = 0x09; + } else { + regRec.CR66 = 0x89; + // Set display fifo. + if ( S3_VIRGE_GX2_SERIES(si.chipType) || + S3_VIRGE_MX_SERIES(si.chipType) ) { + // Changed from 0x08 based on reports that this + // prevents MX from running properly below 1024x768. + regRec.CR63 = 0x10; + } else { + regRec.CR63 = 0; + } + } + + // Now set linear address registers. + // LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX. + regRec.CR58 = ReadCrtcReg(0x58) & 0x80; + + if (si.videoMemSize == 1 * 1024 * 1024) + regRec.CR58 |= 0x01 | 0x10; + else if (si.videoMemSize == 2 * 1024 * 1024) + regRec.CR58 |= 0x02 | 0x10; + else { + if (si.chipType == S3_TRIO_3D_2X && si.videoMemSize == 8 * 1024 * 1024) + regRec.CR58 |= 0x07 | 0x10; // 8MB window on Trio3D/2X + else + regRec.CR58 |= 0x03 | 0x10; // 4MB window on virge, 8MB on VX + } + + if (si.chipType == S3_VIRGE_VX) + regRec.CR58 |= 0x40; + + // ** On PCI bus, no need to reprogram the linear window base address. + + // Now do clock PLL programming. Use the s3gendac function to get m,n. + // Also determine if we need doubling etc. + + int dclk = mode.timing.pixel_clock; + + if (si.chipType == S3_TRIO_3D) { + regRec.SR15 = (ReadSeqReg(0x15) & 0x80) | 0x03; // keep BIOS init defaults + regRec.SR0A = ReadSeqReg(0x0a); + } else + regRec.SR15 = 0x03 | 0x80; + + regRec.SR18 = 0x00; + regRec.CR43 = 0x00; + regRec.CR45 = 0x00; + // Enable MMIO to RAMDAC registers. + regRec.CR65 = 0x00; // CR65_2 must be zero, doc seems to be wrong + regRec.CR54 = 0x00; + + if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { + regRec.CR40 = ReadCrtcReg(0x40) & ~0x01; + } + + if (S3_VIRGE_MX_SERIES(si.chipType)) { + // Fix problems with APM suspend/resume trashing CR90/91. + switch (mode.bpp) { + case 8: + regRec.CR41 = 0x38; + break; + case 16: + regRec.CR41 = 0x48; + break; + default: + regRec.CR41 = 0x77; + } + } + + regRec.CR67 = 0x00; // defaults + + if (si.chipType == S3_VIRGE_VX) { + if (mode.bpp == 8) { + if (dclk <= 110000) + regRec.CR67 = 0x00; // 8bpp, 135MHz + else + regRec.CR67 = 0x10; // 8bpp, 220MHz + } else if (mode.bpp == 16) { + if (dclk <= 110000) + regRec.CR67 = 0x40; // 16bpp, 135MHz + else + regRec.CR67 = 0x50; // 16bpp, 220MHz + } + Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 220000, 440000, + ®Rec.SR13, ®Rec.SR12); + } // end VX if() + + else if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { + uint8 ndiv; + + if (mode.bpp == 8) + regRec.CR67 = 0x00; + else if (mode.bpp == 16) + regRec.CR67 = 0x50; + + // X.org code had a somewhat convuluted way of computing the clock for + // MX chips. I hope this simpler method works for most MX cases. + + Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 170000, 340000, + ®Rec.SR13, &ndiv); + + regRec.SR29 = ndiv >> 7; + regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1); + } // end GX2 or MX if() + + else if (si.chipType == S3_TRIO_3D) { + regRec.SR0F = 0x00; + if (mode.bpp == 8) { + if (dclk > 115000) { // We need pixmux + regRec.CR67 = 0x10; + regRec.SR15 |= 0x10; // Set DCLK/2 bit + regRec.SR18 = 0x80; // Enable pixmux + } + } else if (mode.bpp == 16) { + if (dclk > 115000) { + regRec.CR67 = 0x40; + regRec.SR15 |= 0x10; + regRec.SR18 = 0x80; + regRec.SR0F = 0x10; + } else { + regRec.CR67 = 0x50; + } + } + Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 230000, 460000, + ®Rec.SR13, ®Rec.SR12); + } // end TRIO_3D if() + + else { // Everything else ... (only VIRGE & VIRGE DX/GX). + if (mode.bpp == 8) { + if (dclk > 80000) { // We need pixmux + regRec.CR67 = 0x10; + regRec.SR15 |= 0x10; // Set DCLK/2 bit + regRec.SR18 = 0x80; // Enable pixmux + } + } else if (mode.bpp == 16) { + regRec.CR67 = 0x50; + } + Virge_CalcClock(dclk, 1, 1, 31, 0, 3, 135000, 270000, + ®Rec.SR13, ®Rec.SR12); + } // end great big if()... + + + regRec.CR42 = 0x00; + + if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { + regRec.CR34 = 0; + } else { + regRec.CR34 = 0x10; // set display fifo + } + + int width = mode.bytesPerRow >> 3; + regRec.CRTC[19] = 0xFF & width; + regRec.CR51 = (0x300 & width) >> 4; // Extension bits + + regRec.CR33 = 0x20; + if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType) + /* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) { + regRec.CR85 = 0x12; // avoid sreen flickering + // by increasing FIFO filling, larger # fills FIFO from memory earlier + // on GX2 this affects all depths, not just those running STREAMS. + // new, secondary stream settings. + regRec.CR87 = 0x10; + // gx2 - set up in XV init code + regRec.CR92 = 0x00; + regRec.CR93 = 0x00; + // gx2 primary mclk timeout, def=0xb + regRec.CR7B = 0xb; + // gx2 secondary mclk timeout, def=0xb + regRec.CR7D = 0xb; + } + + if (si.chipType == S3_VIRGE_DXGX || si.chipType == S3_TRIO_3D) { + regRec.CR86 = 0x80; // disable DAC power saving to avoid bright left edge + } + + if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) || + S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) { + int dbytes = mode.bytesPerRow; + regRec.CR91 = (dbytes + 7) / 8; + regRec.CR90 = (((dbytes + 7) / 8) >> 8) | 0x80; + } + + // S3_BLANK_DELAY settings based on defaults only. From 3.3.3. + + int blank_delay; + + if (si.chipType == S3_VIRGE_VX) { + // These values need to be changed once CR67_1 is set + // for gamma correction (see S3V server)! + if (mode.bpp == 8) + blank_delay = 0x00; + else if (mode.bpp == 16) + blank_delay = 0x00; + else + blank_delay = 0x51; + } else { + if (mode.bpp == 8) + blank_delay = 0x00; + else if (mode.bpp == 16) + blank_delay = 0x02; + else + blank_delay = 0x04; + } + + if (si.chipType == S3_VIRGE_VX) { + regRec.CR6D = blank_delay; + } else { + regRec.CR65 = (regRec.CR65 & ~0x38) | (blank_delay & 0x07) << 3; + regRec.CR6D = ReadCrtcReg(0x6d); + } + + regRec.CR68 = ReadCrtcReg(0x68); + regRec.CR69 = 0; + + // Flat panel centering and expansion registers. + regRec.SR54 = 0x1f ; + regRec.SR55 = 0x9f ; + regRec.SR56 = 0x1f ; + regRec.SR57 = 0xff ; + + Virge_WriteMode(mode, regRec); // write mode registers to hardware + + return true; +} + + +bool +Virge_SetDisplayMode(const DisplayModeEx& mode) +{ + // The code to actually configure the display. + // All the error checking must be done in PROPOSE_DISPLAY_MODE(), + // and assume that the mode values we get here are acceptable. + + WriteSeqReg(0x01, 0x20, 0x20); // blank the screen + + if ( ! Virge_ModeInit(mode)) { + TRACE("Virge_ModeInit() failed\n"); + return false; + } + + Virge_AdjustFrame(mode); + Virge_EngineReset(mode); + + WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen + + return true; +} + + + +void +Virge_AdjustFrame(const DisplayModeEx& mode) +{ + // Adjust start address in frame buffer. We use the new CR69 reg + // for this purpose instead of the older CR31/CR51 combo. + + SharedInfo& si = *gInfo.sharedInfo; + + int base = ((mode.v_display_start * mode.virtual_width + mode.h_display_start) + * (mode.bpp / 8)) >> 2; + + if (mode.bpp == 16) + if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000) + base &= ~1; + + base += si.frameBufferOffset; + + // Now program the start address registers. + + WriteCrtcReg(0x0c, (base >> 8) & 0xff); + WriteCrtcReg(0x0d, base & 0xff); + WriteCrtcReg(0x69, (base & 0x0F0000) >> 16); +} + + +void +Virge_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) +{ + // Set the indexed color palette for 8-bit color depth mode. + + (void)flags; // avoid compiler warning for unused arg + + if (gInfo.sharedInfo->displayMode.space != B_CMAP8) + return ; + + while (count--) { + WriteIndexedColor(first++, // color index + colorData[0] >> 2, // red + colorData[1] >> 2, // green + colorData[2] >> 2); // blue + colorData += 3; + } +} diff --git a/src/add-ons/accelerants/s3savage/AccelerantPrototypes.h b/src/add-ons/accelerants/s3savage/AccelerantPrototypes.h deleted file mode 100644 index f8bbf350c4..0000000000 --- a/src/add-ons/accelerants/s3savage/AccelerantPrototypes.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. -*/ - -#ifndef ACCELERANT_PROTOTYPES_H -#define ACCELERANT_PROTOTYPES_H - -#include - -status_t INIT_ACCELERANT(int fd); -ssize_t ACCELERANT_CLONE_INFO_SIZE(void); -void GET_ACCELERANT_CLONE_INFO(void *data); -status_t CLONE_ACCELERANT(void *data); -void UNINIT_ACCELERANT(void); -status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi); -sem_id ACCELERANT_RETRACE_SEMAPHORE(void); - -uint32 ACCELERANT_MODE_COUNT(void); -status_t GET_MODE_LIST(display_mode *dm); -status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high); -status_t SET_DISPLAY_MODE(display_mode *mode_to_set); -status_t GET_DISPLAY_MODE(display_mode *current_mode); -status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer); -status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high); -status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start); -status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc); -void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags); - -uint32 DPMS_CAPABILITIES(void); -uint32 DPMS_MODE(void); -status_t SET_DPMS_MODE(uint32 dpms_flags); - -status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask); -void MOVE_CURSOR(uint16 x, uint16 y); -void SHOW_CURSOR(bool is_visible); - -uint32 ACCELERANT_ENGINE_COUNT(void); -status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et); -status_t RELEASE_ENGINE(engine_token *et, sync_token *st); -void WAIT_ENGINE_IDLE(void); -status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st); -status_t SYNC_TO_TOKEN(sync_token *st); - -void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count); -void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count); -void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count); - -void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count); - -// Prototype for other functions that are called from source files -// other than where they are defined. - -status_t create_mode_list(void); - -#endif diff --git a/src/add-ons/accelerants/s3savage/Cursor.c b/src/add-ons/accelerants/s3savage/Cursor.c deleted file mode 100644 index 825cb79178..0000000000 --- a/src/add-ons/accelerants/s3savage/Cursor.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" - - -status_t -SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, - uint8* andMask, uint8* xorMask) -{ - /* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */ - - if ((width != 16) || (height != 16)) { - return B_ERROR; - } else if ((hot_x >= width) || (hot_y >= height)) { - return B_ERROR; - } else { - /* Update cursor variables appropriately. */ - si->cursor.width = width; - si->cursor.height = height; - si->cursor.hot_x = hot_x; - si->cursor.hot_y = hot_y; - - if (!SavageLoadCursorImage(width, height, andMask, xorMask)) - return B_ERROR; - } - - return B_OK; -} - -/* -Move the cursor to the specified position on the desktop. If we're -using some kind of virtual desktop, adjust the display start position -accordingly and position the cursor in the proper "virtual" location. -*/ -void -MOVE_CURSOR(uint16 xPos, uint16 yPos) -{ - int x = xPos; // use signed int's since SavageSetCursorPosition() - int y = yPos; // needs signed int to determine if cursor off screen - - uint16 hds = si->dm.h_display_start; /* current horizontal starting pixel */ - uint16 vds = si->dm.v_display_start; /* current vertical starting line */ - - /* clamp cursor to virtual display */ - if (x >= si->dm.virtual_width) - x = si->dm.virtual_width - 1; - if (y >= si->dm.virtual_height) - y = si->dm.virtual_height - 1; - - /* adjust h/v display start to move cursor onto screen */ - if (x >= (si->dm.timing.h_display + hds)) - hds = x - si->dm.timing.h_display + 1; - else if (x < hds) - hds = x; - - if (y >= (si->dm.timing.v_display + vds)) - vds = y - si->dm.timing.v_display + 1; - else if (y < vds) - vds = y; - - /* reposition the desktop on the display if required */ - if (hds != si->dm.h_display_start || vds != si->dm.v_display_start) - MOVE_DISPLAY(hds, vds); - - /* put cursor in correct physical position */ - x -= (hds + si->cursor.hot_x); - y -= (vds + si->cursor.hot_y); - - /* position the cursor on the display */ - SavageSetCursorPosition(x, y); -} - - -void -SHOW_CURSOR(bool bShow) -{ - if (bShow) - SavageShowCursor(); - else - SavageHideCursor(); -} - diff --git a/src/add-ons/accelerants/s3savage/EngineManagement.c b/src/add-ons/accelerants/s3savage/EngineManagement.c deleted file mode 100644 index 54684986eb..0000000000 --- a/src/add-ons/accelerants/s3savage/EngineManagement.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" - - -static engine_token savage_engine_token = { 1, B_2D_ACCELERATION, NULL }; - - -uint32 -ACCELERANT_ENGINE_COUNT(void) -{ - return 1; -} - - -status_t -ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, - sync_token *st, engine_token **et) -{ - (void)capabilities; // avoid compiler warning for unused arg - (void)max_wait; // avoid compiler warning for unused arg - - /* acquire the shared benaphore */ - AQUIRE_BEN(si->engine.lock) - /* sync if required */ - if (st) - SYNC_TO_TOKEN(st); - - /* return an engine token */ - *et = &savage_engine_token; - return B_OK; -} - - -status_t -RELEASE_ENGINE(engine_token *et, sync_token *st) -{ - /* update the sync token, if any */ - if (st) - GET_SYNC_TOKEN(et, st); - - /* release the shared benaphore */ - RELEASE_BEN(si->engine.lock) - return B_OK; -} - - -void -WAIT_ENGINE_IDLE(void) -{ - si->WaitIdleEmpty(); // wait until engine is completely idle -} - - -status_t -GET_SYNC_TOKEN(engine_token *et, sync_token *st) -{ - /* engine count will always be zero: we don't support syncing to token (yet) */ - st->engine_id = et->engine_id; - st->counter = si->engine.count; - return B_OK; -} - - -status_t -SYNC_TO_TOKEN(sync_token *st) -{ - (void)st; // avoid compiler warning for unused arg - - WAIT_ENGINE_IDLE(); - return B_OK; -} - diff --git a/src/add-ons/accelerants/s3savage/GetAccelerantHook.c b/src/add-ons/accelerants/s3savage/GetAccelerantHook.c deleted file mode 100644 index 01bc3d60f5..0000000000 --- a/src/add-ons/accelerants/s3savage/GetAccelerantHook.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "AccelerantPrototypes.h" - -/* - -The standard entry point. Given a uint32 feature identifier, this routine -returns a pointer to the function that implements the feature. Some features -require more information than just the identifier to select the proper -function. The extra information (which is specific to the feature) is -pointed at by the void *data parameter. By default, no extra information -is available. Any extra information available to choose the function will be -noted on a case by case below. - -*/ -void * -get_accelerant_hook(uint32 feature, void *data) -{ - (void)data; // avoid compiler warning for unused arg - - switch (feature) { - /* - These definitions are out of pure lazyness. - */ -#define HOOK(x) case B_##x: return (void *)x -#define ZERO(x) case B_##x: return (void *)0 - - /* - One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and - subsequently called before any other hook is requested. All other feature - hook selections can be predicated on variables assigned during the accelerant - initialization process. - */ - /* initialization */ - HOOK(INIT_ACCELERANT); - HOOK(CLONE_ACCELERANT); - - HOOK(ACCELERANT_CLONE_INFO_SIZE); - HOOK(GET_ACCELERANT_CLONE_INFO); - HOOK(UNINIT_ACCELERANT); - HOOK(GET_ACCELERANT_DEVICE_INFO); - HOOK(ACCELERANT_RETRACE_SEMAPHORE); - - /* mode configuration */ - HOOK(ACCELERANT_MODE_COUNT); - HOOK(GET_MODE_LIST); - HOOK(PROPOSE_DISPLAY_MODE); - HOOK(SET_DISPLAY_MODE); - HOOK(GET_DISPLAY_MODE); - HOOK(GET_FRAME_BUFFER_CONFIG); - HOOK(GET_PIXEL_CLOCK_LIMITS); - HOOK(MOVE_DISPLAY); - HOOK(SET_INDEXED_COLORS); - //HOOK(GET_TIMING_CONSTRAINTS); - - HOOK(DPMS_CAPABILITIES); - HOOK(DPMS_MODE); - HOOK(SET_DPMS_MODE); - - /* cursor managment */ - HOOK(SET_CURSOR_SHAPE); - HOOK(MOVE_CURSOR); - HOOK(SHOW_CURSOR); - - /* synchronization */ - HOOK(ACCELERANT_ENGINE_COUNT); - HOOK(ACQUIRE_ENGINE); - HOOK(RELEASE_ENGINE); - HOOK(WAIT_ENGINE_IDLE); - HOOK(GET_SYNC_TOKEN); - HOOK(SYNC_TO_TOKEN); - - /* - When requesting an acceleration hook, the calling application provides a - pointer to the display_mode for which the acceleration function will be used. - Depending on the engine architecture, you may choose to provide a different - function to be used with each bit-depth. In the sample driver we return - the same function all the time. - */ - /* 2D acceleration */ - HOOK(SCREEN_TO_SCREEN_BLIT); - HOOK(FILL_RECTANGLE); - HOOK(INVERT_RECTANGLE); - HOOK(FILL_SPAN); -#undef HOOK -#undef ZERO - - } - /* - Return a null pointer for any feature we don't understand. - */ - return 0; -} - diff --git a/src/add-ons/accelerants/s3savage/GetDeviceInfo.c b/src/add-ons/accelerants/s3savage/GetDeviceInfo.c deleted file mode 100644 index 8fbb5f03c8..0000000000 --- a/src/add-ons/accelerants/s3savage/GetDeviceInfo.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2007 -*/ - -#include "AccelerantPrototypes.h" -#include "GlobalData.h" -#include - - -// Get info about the device. - -status_t -GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi) -{ - adi->version = 1; - strcpy(adi->name, "S3 Savage chipset"); - strcpy(adi->chipset, si->chipsetName); - strcpy(adi->serial_no, "unknown"); - adi->memory = si->videoMemSize; - adi->dac_speed = 250; - - return B_OK; -} - diff --git a/src/add-ons/accelerants/s3savage/GetModeInfo.c b/src/add-ons/accelerants/s3savage/GetModeInfo.c deleted file mode 100644 index 8ea53f4ad9..0000000000 --- a/src/add-ons/accelerants/s3savage/GetModeInfo.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" - -/* - Return the current display mode. The only time you might return an - error is if a mode hasn't been set. -*/ -status_t -GET_DISPLAY_MODE (display_mode *current_mode) -{ - /* easy for us, we return the last mode we set */ - *current_mode = si->dm; - return B_OK; -} - - -/* - Return the frame buffer configuration information. -*/ -status_t -GET_FRAME_BUFFER_CONFIG(frame_buffer_config *pFBC) -{ -// TRACE(("GET_FRAME_BUFFER_CONFIG called\n")); - - *pFBC = si->fbc; - return B_OK; -} - - -/* - Return the maximum and minium pixel clock limits for the specified mode. -*/ -status_t -GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) -{ - /* - Note that we're not making any guarantees about the ability of the attached - display to handle pixel clocks within the limits we return. A future monitor - capablilities database will post-process this information. - */ - uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total; - uint32 clock_limit; - - /* max pixel clock is pixel depth dependant */ - switch (dm->space & ~0x3000) { - case B_RGB32: - clock_limit = si->pix_clk_max32; - break; - case B_RGB15: - case B_RGB16: - clock_limit = si->pix_clk_max16; - break; - case B_CMAP8: - clock_limit = si->pix_clk_max8; - break; - default: - clock_limit = 0; - } - /* lower limit of about 48Hz vertical refresh */ - *low = (total_pix * 48L) / 1000L; - if (*low > clock_limit) - return B_ERROR; - *high = clock_limit; - return B_OK; -} - - -/* - Return the semaphore id that will be used to signal a vertical retrace - occured. -*/ -sem_id -ACCELERANT_RETRACE_SEMAPHORE(void) -{ -// TRACE(("ACCELERANT_RETRACE_SEMAPHORE() called\n")); - -// if (si->bInterruptAssigned && si->vblank >= 0) -// return si->vblank; -// else - return B_ERROR; -} - diff --git a/src/add-ons/accelerants/s3savage/GlobalData.c b/src/add-ons/accelerants/s3savage/GlobalData.c deleted file mode 100644 index b4a3fdbc53..0000000000 --- a/src/add-ons/accelerants/s3savage/GlobalData.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" - -int driverFileDesc; -SharedInfo* si; -area_id sharedInfoArea; -uint8* regs; -area_id regsArea; -display_mode* modeList; -area_id modeListArea; -bool bAccelerantIsClone; - diff --git a/src/add-ons/accelerants/s3savage/GlobalData.h b/src/add-ons/accelerants/s3savage/GlobalData.h deleted file mode 100644 index 63b5331d15..0000000000 --- a/src/add-ons/accelerants/s3savage/GlobalData.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#ifndef GLOBALDATA_H -#define GLOBALDATA_H - -#include "DriverInterface.h" - -extern int driverFileDesc; // file descriptor of kernel driver -extern SharedInfo* si; // address of info shared between accelerants -extern area_id sharedInfoArea; // shared info area ID -extern uint8* regs; // base address of MMIO register area -extern area_id regsArea; // MMIO register area ID -extern display_mode* modeList; // list of standard display modes -extern area_id modeListArea; // mode list area ID -extern bool bAccelerantIsClone;// true if this is a cloned accelerant - - -void TraceLog(const char* fmt, ...); - -#ifdef TRACE_S3SAVAGE -# define TRACE(a) TraceLog a -#else -# define TRACE(a) -#endif - -#endif // GLOBALDATA_H diff --git a/src/add-ons/accelerants/s3savage/InitAccelerant.c b/src/add-ons/accelerants/s3savage/InitAccelerant.c deleted file mode 100644 index 6eb8d63e2b..0000000000 --- a/src/add-ons/accelerants/s3savage/InitAccelerant.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" - -#include "errno.h" -#include "fcntl.h" -#include "stdio.h" -#include "string.h" -#include "unistd.h" -#include "sys/types.h" -#include "sys/stat.h" -#include - - -/* Initialization code shared between primary and cloned accelerants */ - -static status_t -init_common(int the_fd) -{ - status_t result; - SavageGetPrivateData gpd; - - /* memorize the file descriptor */ - driverFileDesc = the_fd; - - /* set the magic number so the driver knows we're for real */ - gpd.magic = SAVAGE_PRIVATE_DATA_MAGIC; - - /* contact driver and get a pointer to the registers and shared data */ - result = ioctl(driverFileDesc, SAVAGE_GET_PRIVATE_DATA, &gpd, sizeof(gpd)); - if (result != B_OK) - goto error0; - - /* clone the shared area for our use */ - sharedInfoArea = clone_area("SAVAGE shared info", (void**)&si, B_ANY_ADDRESS, - B_READ_AREA | B_WRITE_AREA, gpd.sharedInfoArea); - if (sharedInfoArea < 0) { - result = sharedInfoArea; - goto error0; - } - - /* clone the memory mapped registers for our use */ - regsArea = clone_area("SAVAGE regs area", (void**)®s, B_ANY_ADDRESS, - B_READ_AREA | B_WRITE_AREA, si->regsArea); - if (regsArea < 0) { - result = regsArea; - goto error1; - } - - /* all done */ - goto error0; - -error1: - delete_area(sharedInfoArea); -error0: - return result; -} - - -/* Clean up code shared between primary and cloned accelrants */ -static void -uninit_common(void) -{ - /* release the memory mapped registers */ - delete_area(regsArea); - regs = 0; - /* release our copy of the shared info from the kernel driver */ - delete_area(sharedInfoArea); - si = 0; -} - - -/* -Initialize the accelerant. the_fd is the file handle of the device (in -/dev/graphics) that has been opened by the app_server (or some test harness). -We need to determine if the kernel driver and the accelerant are compatible. -If they are, get the accelerant ready to handle other hook functions and -report success or failure. -*/ -status_t -INIT_ACCELERANT(int the_fd) -{ - status_t result; - - TRACE(("Enter INIT_ACCELERANT\n")); - - /* note that we're the primary accelerant (bAccelerantIsClone is global) */ - bAccelerantIsClone = false; - - /* do the initialization common to both the primary and the clones */ - result = init_common(the_fd); - if (result != B_OK) - goto error0; // common initialization failed - - TRACE(("Vendor ID: 0x%X, Device ID: 0x%X\n", si->vendorID, si->deviceID)); - - /* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */ - if (si->bAccelerantInUse) { - result = B_NOT_ALLOWED; - goto error1; - } - - /* call the device specific init code */ - - if (!SavagePreInit()) - goto error1; - - /* - Now would be a good time to figure out what video modes your card supports. - We'll place the list of modes in another shared area so all of the copies - of the driver can see them. The primary copy of the accelerant (ie the one - initialized with this routine) will own the "one true copy" of the list. - Everybody else get's a read-only clone. - */ - result = create_mode_list(); - if (result != B_OK) - goto error1; - - /* Initialize the cursor information */ - si->cursor.width = 0; - si->cursor.height = 0; - si->cursor.hot_x = 0; - si->cursor.hot_y = 0; - si->cursor.x = 0; - si->cursor.y = 0; - - si->fbc.frame_buffer = (void *)((addr_t)si->videoMemAddr + si->frameBufferOffset); - si->fbc.frame_buffer_dma = (void *)((addr_t)si->videoMemPCI + si->frameBufferOffset); - - /* init the shared semaphore */ - INIT_BEN(si->engine.lock); - - /* initialize the engine synchronization variables */ - /* count of issued parameters or commands */ - si->engine.lastIdle = si->engine.count = 0; - - /* ensure cursor state */ - SHOW_CURSOR(false); - - /* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */ - si->bAccelerantInUse = true; - - result = B_OK; - goto error0; - -error1: - /* - Initialization failed after init_common() succeeded, so we need to clean - up before quiting. - */ - uninit_common(); - -error0: - TRACE(("Exit INIT_ACCELERANT, result: 0x%X\n", result)); - return result; -} - - -/* -Return the number of bytes required to hold the information required -to clone the device. -*/ -ssize_t -ACCELERANT_CLONE_INFO_SIZE(void) -{ - /* - Since we're passing the name of the device as the only required - info, return the size of the name buffer - */ - return B_OS_NAME_LENGTH; -} - - -/* -Return the info required to clone the device. void* data points to -a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length. -*/ -void -GET_ACCELERANT_CLONE_INFO(void* data) -{ - SavageDeviceName dn; - status_t result; - - /* call the kernel driver to get the device name */ - dn.magic = SAVAGE_PRIVATE_DATA_MAGIC; - /* store the returned info directly into the passed buffer */ - dn.name = (char*)data; - result = ioctl(driverFileDesc, SAVAGE_DEVICE_NAME, &dn, sizeof(dn)); -} - -/* -Initialize a copy of the accelerant as a clone. void* data points to -a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). -*/ -status_t -CLONE_ACCELERANT(void* data) -{ - status_t result; - char path[MAXPATHLEN]; - - /* the data is the device name */ - strcpy(path, "/dev/"); - strcat(path, (const char*)data); - /* open the device, the permissions aren't important */ - driverFileDesc = open(path, B_READ_WRITE); - if (driverFileDesc < 0) - return errno; - - /* note that we're a clone accelerant */ - bAccelerantIsClone = true; - - /* call the shared initialization code */ - result = init_common(driverFileDesc); - - /* bail out if the common initialization failed */ - if (result != B_OK) - goto error1; - - /* get shared area for display modes */ - result = modeListArea = clone_area( - "SAVAGE cloned display_modes", - (void**) &modeList, - B_ANY_ADDRESS, - B_READ_AREA, - si->modeArea - ); - - if (result < B_OK) - goto error2; - - /* all done */ - result = B_OK; - goto error0; - -error2: - /* free up the areas we cloned */ - uninit_common(); -error1: - /* close the device we opened */ - close(driverFileDesc); -error0: - return result; -} - - -void -UNINIT_ACCELERANT(void) -{ - /* free our mode list area */ - delete_area(modeListArea); - modeList = 0; - /* release our cloned data */ - uninit_common(); - /* close file handle ONLY if we're the clone */ - if (bAccelerantIsClone) - close(driverFileDesc); -} - - -// Kernel function dprintf() is not available in user space; however, -// _sPrintf performs the same function in user space but is undefined -// in the OS header files. Thus, it is defined here. -void _sPrintf(const char *format, ...); - -void -TraceLog(const char* fmt, ...) -{ - char string[1024]; - va_list args; - - strcpy(string, "savage: "); - va_start(args, fmt); - vsprintf(&string[strlen(string)], fmt, args); - _sPrintf(string); -} - diff --git a/src/add-ons/accelerants/s3savage/Jamfile b/src/add-ons/accelerants/s3savage/Jamfile deleted file mode 100644 index 7e59acc6b2..0000000000 --- a/src/add-ons/accelerants/s3savage/Jamfile +++ /dev/null @@ -1,31 +0,0 @@ -SubDir HAIKU_TOP src add-ons accelerants s3savage ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -UsePrivateHeaders graphics ; -UsePrivateHeaders [ FDirName graphics s3savage ] ; - -Addon s3savage.accelerant : - Acceleration.c - Cursor.c - EngineManagement.c - GetAccelerantHook.c - GetDeviceInfo.c - GetModeInfo.c - GlobalData.c - InitAccelerant.c - ProposeDisplayMode.c - SetDisplayMode.c - - savage_accel.c - savage_cursor.c - savage_dpms.c - savage_driver.c - - : be -; - -Package haiku-s3savage-cvs : - s3savage.accelerant : - boot home config add-ons accelerants ; - diff --git a/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c b/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c deleted file mode 100644 index 19f2341733..0000000000 --- a/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" - -#include - - -#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) -#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS) -#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode)) - -static const display_mode mode_list[] = { - { { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ - { { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ - { { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ - { { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ - - { { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) */ - { { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ - { { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */ - { { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */ - { { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */ - { { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */ - - { { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */ - { { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */ - { { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ - { { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ - - { { 81642, 1152, 1216, 1336, 1520, 864, 865, 868, 895, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, // 1152x864x60Hz - { { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ - { { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ - { { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ - { { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ - - { { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */ - { { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */ - { { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */ - - { { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */ - { { 155800, 1400, 1464, 1784, 1912, 1050, 1052, 1064, 1090, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1400X1050) */ - - { { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */ - { { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */ - { { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */ - { { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */ - { { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */ - { { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */ - - { { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) */ - { { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) */ - - { { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) */ - { { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) */ - - // widescreen resolutions, 16:10 - { { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */ - { { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */ - - // widescreen resolutions, 16:9 - { { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@60Hz_(1280X720) */ -}; - - -/* create a mask of one "bits" bits wide */ -#define MASKFROMWIDTH(bits) ((1 << bits) - 1) - -/* - Validate a target display mode is both - a) a valid display mode for this device and - b) falls between the contraints imposed by "low" and "high" - - Return values: - B_ERROR - mode is not (or cannot) be made valid for this device. - B_BAD_VALUE - valid mode can be constructed, but it is not within limits. - B_OK - mode is both valid AND is within the limits. -*/ -status_t -PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) -{ - const uint16 h_sync_bits = MASKFROMWIDTH(5); - const uint16 h_total_bits = MASKFROMWIDTH(9); - const uint16 v_display_bits = MASKFROMWIDTH(11); - const uint16 v_sync_bits = MASKFROMWIDTH(5); - - status_t result = B_OK; - uint32 row_bytes, limit_clock; - double target_refresh = ((double)target->timing.pixel_clock * 1000.0) - / ((double)target->timing.h_total - * (double)target->timing.v_total); - bool want_same_width = (target->timing.h_display == target->virtual_width); - bool want_same_height = (target->timing.v_display == target->virtual_height); - - /* - NOTE: - Different devices provide different levels of control over the - various CRTC values. This code should be used as a *GUIDELINE ONLY*. - The device you're controling may have very different constraints, - and the code below may be insufficient to insure that a particular - display_mode is valid for your device. You would do well to spend - quite a bit of time ensuring that you understand the limitations of - your device, as setting these values incorrectly can create a - display_mode that could turn your monitor into a useless slag of - molten components, burn up your card, lock up the PCI bus, cause - partialy or multiply repeating display images, or otherwise look - just plain wierd. Honest. - */ - /* - NOTE: - This code doesn't explicitly support interlaced video modes. - */ - -// TRACE(("ProposeDisplayMode; clock = %d, width = %d, height = %d\n", -// target->timing.pixel_clock, target->virtual_width, target->virtual_height)); - - /* validate horizontal timings */ - { - /* for most devices, horizontal parameters must be multiples of 8 */ - uint16 h_display = target->timing.h_display >> 3; - uint16 h_sync_start = target->timing.h_sync_start >> 3; - uint16 h_sync_end = target->timing.h_sync_end >> 3; - uint16 h_total = target->timing.h_total >> 3; - - /* ensure reasonable minimum display and sequential order of parms */ - if (h_display < (320 >> 3)) - h_display = 320 >> 3; - if (h_display > (2048 >> 3)) - h_display = 2048 >> 3; - if (h_sync_start < (h_display + 2)) - h_sync_start = h_display + 2; - if (h_sync_end < (h_sync_start + 3)) - h_sync_end = h_sync_start + 3; /*(0x001f >> 2);*/ - if (h_total < (h_sync_end + 1)) - h_total = h_sync_end + 1; - /* adjust for register limitations: */ - /* h_total is 9 bits */ - if (h_total > h_total_bits) - h_total = h_total_bits; - /* h_display is 8 bits - handled above */ - /* h_sync_start is 9 bits */ - /* h_sync_width is 5 bits */ - if ((h_sync_end - h_sync_start) > h_sync_bits) - h_sync_end = h_sync_start + h_sync_bits; - - /* shift back to the full width values */ - target->timing.h_display = h_display << 3; - target->timing.h_sync_start = h_sync_start << 3; - target->timing.h_sync_end = h_sync_end << 3; - target->timing.h_total = h_total << 3; - } - - /* did we fall out of one of the limits? */ - if ((target->timing.h_display < low->timing.h_display) - || (target->timing.h_display > high->timing.h_display) - || (target->timing.h_sync_start < low->timing.h_sync_start) - || (target->timing.h_sync_start > high->timing.h_sync_start) - || (target->timing.h_sync_end < low->timing.h_sync_end) - || (target->timing.h_sync_end > high->timing.h_sync_end) - || (target->timing.h_total < low->timing.h_total) - || (target->timing.h_total > high->timing.h_total)) - result = B_BAD_VALUE; - - - /* validate vertical timings */ - { - uint16 v_display = target->timing.v_display; - uint16 v_sync_start = target->timing.v_sync_start; - uint16 v_sync_end = target->timing.v_sync_end; - uint16 v_total = target->timing.v_total; - - /* ensure reasonable minium display and sequential order of parms */ - /* v_display is 11 bits */ - /* v_total is 11 bits */ - /* v_sync_start is 11 bits */ - /* v_sync_width is 5 bits */ - if (v_display < 200) - v_display = 200; - if (v_display > (v_display_bits - 5)) - v_display = (v_display_bits - 5); /* leave room for the sync pulse */ - if (v_sync_start < (v_display + 1)) - v_sync_start = v_display + 1; - if (v_sync_end < v_sync_start) - v_sync_end = v_sync_start + 3; - if (v_total < (v_sync_end + 1)) - v_total = v_sync_end + 1; - /* adjust for register limitations */ - if ((v_sync_end - v_sync_start) > v_sync_bits) - v_sync_end = v_sync_start + v_sync_bits; - - target->timing.v_display = v_display; - target->timing.v_sync_start = v_sync_start; - target->timing.v_sync_end = v_sync_end; - target->timing.v_total = v_total; - } - - /* did we fall out of one of the limits? */ - if ((target->timing.v_display < low->timing.v_display) - || (target->timing.v_display > high->timing.v_display) - || (target->timing.v_sync_start < low->timing.v_sync_start) - || (target->timing.v_sync_start > high->timing.h_sync_start) - || (target->timing.v_sync_end < low->timing.v_sync_end) - || (target->timing.v_sync_end > high->timing.v_sync_end) - || (target->timing.v_total < low->timing.v_total) - || (target->timing.v_total > high->timing.v_total)) - result = B_BAD_VALUE; - - // If the video is connected directly to an LCD display (ie, notebook - // computer), restrict the display mode to resolutions where the width and - // height of the mode are less than or equal to the width and height of the - // LCD display. - - if (MT_LCD == si->displayType && si->panelX > 0 && si->panelY > 0 && - (target->timing.h_display > si->panelX - || target->timing.v_display > si->panelY)) { - return B_ERROR; - } - - /* adjust pixel clock for DAC limits and target refresh rate */ - /* - We're re-calcuating the pixel_clock here because we might have - changed the h/v totals above. If we didn't change anything - the calculation is wasted, but it's no big deal. - */ - target->timing.pixel_clock = target_refresh - * ((double)target->timing.h_total) - * ((double)target->timing.v_total) / 1000.0; - - /* - Select the maximum pixel clock based on the color space. Your - device may have other constraints. In this sample driver, we - calculated the maximum pixel clock for this device in the - initialization code. - This is also a convienient place to determine the number of bytes - per pixel for a later display pitch calculation. - */ - switch (target->space & 0x0fff) { - case B_CMAP8: - limit_clock = si->pix_clk_max8; - row_bytes = 1; - break; - //case B_RGB15: - case B_RGB16: - limit_clock = si->pix_clk_max16; - row_bytes = 2; - break; - case B_RGB32: - limit_clock = si->pix_clk_max32; - row_bytes = 4; - break; - default: - /* no amount of adjusting will fix not being able to support - the pixel format */ - return B_ERROR; - } - /* make sure we don't generate more pixel bandwidth than the device - can handle */ - if (target->timing.pixel_clock > limit_clock) - target->timing.pixel_clock = limit_clock; - /* we probably ought to check against too low of a pixel rate, - but I'm lazy */ - - /* note if we fell outside the limits */ - if ((target->timing.pixel_clock < low->timing.pixel_clock) - || (target->timing.pixel_clock > high->timing.pixel_clock)) - result = B_BAD_VALUE; - - /* validate display vs. virtual */ - if ((target->timing.h_display > target->virtual_width) || want_same_width) - target->virtual_width = target->timing.h_display; - if ((target->timing.v_display > target->virtual_height) || want_same_height) - target->virtual_height = target->timing.v_display; - if (target->virtual_width > 2048) - target->virtual_width = 2048; - - /* adjust virtual width for engine limitations */ - target->virtual_width = (target->virtual_width + 7) & ~7; - if ( (target->virtual_width < low->virtual_width) - || (target->virtual_width > high->virtual_width)) - result = B_BAD_VALUE; - - /* calculate rowbytes after we've nailed the virtual width */ - row_bytes *= target->virtual_width; - - /* memory requirement for frame buffer */ - if ((row_bytes * target->virtual_height) > si->maxFrameBufferSize) - target->virtual_height = si->maxFrameBufferSize / row_bytes; - - if (target->virtual_height > 2048) - target->virtual_height = 2048; - - if (target->virtual_height < target->timing.v_display) - /* not enough frame buffer memory for the mode */ - return B_ERROR; - else if ((target->virtual_height < low->virtual_height) - || (target->virtual_height > high->virtual_height)) - result = B_BAD_VALUE; - - return result; -} - -/* - Return the number of modes this device will return from GET_MODE_LIST(). -*/ -uint32 -ACCELERANT_MODE_COUNT(void) -{ - /* return the number of 'built-in' display modes */ - return si->modeCount; -} - -/* - Copy the list of guaranteed supported video modes to the location - provided. -*/ -status_t -GET_MODE_LIST(display_mode *dm) -{ - /* copy them to the buffer pointed at by *dm */ - memcpy(dm, modeList, si->modeCount * sizeof(display_mode)); - return B_OK; -} - - -/* - Create a list of display_modes to pass back to the caller. -*/ -status_t -create_mode_list(void) -{ - size_t max_size; - uint32 i; - uint32 pix_clk_range; - const display_mode *src; - display_mode *dst, low, high; - - /* - We prefer frame buffers to have the same endianness as the host - CPU, but it's not required. You can even return both, although - there isn't a way for the current Screen preferences panel to - allow the user to choose which one to use. - */ -#if defined(__INTEL__) - color_space colorSpaces[] = { B_CMAP8, B_RGB16_LITTLE, B_RGB32_LITTLE }; -#else - color_space colorSpaces[] = { B_CMAP8, B_RGB16_BIG, B_RGB32_BIG }; -#endif - - int numColorSpaces = sizeof(colorSpaces) / sizeof(colorSpaces[0]); - - /* figure out how big the list could be, and adjust up to nearest - multiple of B_PAGE_SIZE */ - max_size = ((MODE_COUNT * numColorSpaces * sizeof(display_mode)) - + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); - /* create an area to hold the info */ - si->modeArea = modeListArea = create_area("SAVAGE accelerant mode info", - (void **) &modeList, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); - if (modeListArea < B_OK) - return modeListArea; - - /* walk through our predefined list and see which modes fit this device */ - src = mode_list; - dst = modeList; - si->modeCount = 0; - - for (i = 0; i < MODE_COUNT; i++) { - int j; - - /* set ranges for acceptable values */ - low = high = *src; - /* Expand range of default clock by 3.1% on each end: arbitrarily picked */ - pix_clk_range = low.timing.pixel_clock >> 5; // divide by 32 to get ~3.1% - low.timing.pixel_clock -= pix_clk_range; - high.timing.pixel_clock += pix_clk_range; - - /* do it once for each depth we want to support */ - for (j = 0; j < numColorSpaces; j++) { - /* set target values */ - *dst = *src; - /* poke the specific space */ - dst->space = low.space = high.space = colorSpaces[j]; - /* ask for a compatible mode */ - if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) { - /* count it, and move on to next mode */ - dst++; - si->modeCount++; - } - } - /* advance to next mode */ - src++; - } - - return B_OK; -} - - -bool -IsDisplaySizeValid(int width, int height) -{ - // Search the mode list for a mode which has the width and height passed - // by the caller, and return true if a match is found. - - uint32 i; - - for (i = 0; i < MODE_COUNT; i++) { - if (mode_list[i].virtual_width == width && mode_list[i].virtual_height == height) - return true; - } - - return false; // match not found -} diff --git a/src/add-ons/accelerants/s3savage/SetDisplayMode.c b/src/add-ons/accelerants/s3savage/SetDisplayMode.c deleted file mode 100644 index f44540a26b..0000000000 --- a/src/add-ons/accelerants/s3savage/SetDisplayMode.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" -#include -#include - -/* - Enable/Disable interrupts. Just a wrapper around the - ioctl() to the kernel driver. - */ -static void -interrupt_enable(bool bEnable) -{ - status_t result; - SavageSetBoolState sbs; - - if (si->bInterruptAssigned) { - /* set the magic number so the driver knows we're for real */ - sbs.magic = SAVAGE_PRIVATE_DATA_MAGIC; - sbs.bEnable = bEnable; - /* contact driver and get a pointer to the registers and shared data */ - result = ioctl(driverFileDesc, SAVAGE_RUN_INTERRUPTS, &sbs, sizeof(sbs)); - } -} - -/* - Calculates the number of bits for a given color_space. - Usefull for mode setup routines, etc. - */ -static uint32 -CalcBitsPerPixel(uint32 cs) -{ - uint32 bpp = 0; - - switch (cs) { - case B_RGB32_BIG: - case B_RGBA32_BIG: - case B_RGB32_LITTLE: - case B_RGBA32_LITTLE: - bpp = 32; - break; - case B_RGB24_BIG: - case B_RGB24_LITTLE: - bpp = 24; - break; - case B_RGB16_BIG: - case B_RGB16_LITTLE: - bpp = 16; - break; - case B_RGB15_BIG: - case B_RGBA15_BIG: - case B_RGB15_LITTLE: - case B_RGBA15_LITTLE: - bpp = 15; - break; - case B_CMAP8: - bpp = 8; - break; - } - return bpp; -} - - -/* - The code to actually configure the display. - Do all of the error checking in PROPOSE_DISPLAY_MODE(), - and just assume that the values I get here are acceptable. -*/ -static void -SetDisplayMode(display_mode* dm) -{ - // The code to actually configure the display. - // All the error checking must be done in PROPOSE_DISPLAY_MODE(), - // and assume that the mode values we get here are acceptable. - - uint bpp = CalcBitsPerPixel(dm->space); - DisplayMode mode; - - TRACE(("SetDisplayMode begin; depth = %d, width = %d, height = %d\n", - bpp, dm->virtual_width, dm->virtual_height)); - - interrupt_enable(false); // disable interrupts using kernel driver - - - mode.timing = dm->timing; - mode.bpp = bpp; - mode.width = dm->virtual_width; - mode.bytesPerRow = dm->virtual_width * ((bpp + 7) / 8); - TRACE(("TIMING = { %d %d %d %d %d %d %d %d %d 0x%x }\n", - mode.timing.pixel_clock, - mode.timing.h_display, mode.timing.h_sync_start, mode.timing.h_sync_end, - mode.timing.h_total, - mode.timing.v_display, mode.timing.v_sync_start, mode.timing.v_sync_end, - mode.timing.v_total, mode.timing.flags)); - - if (SavageModeInit(&mode)) { - TRACE(("SavageModeInit succeeded\n")); - } else { - TRACE(("SavageModeInit failed\n")); - } - - interrupt_enable(true); // enable interrupts using kernel driver - - si->fbc.bytes_per_row = dm->virtual_width * ((bpp + 7) / 8); - si->bitsPerPixel = bpp; - - SavageAdjustFrame(dm->h_display_start, dm->v_display_start); - - TRACE(("SetDisplayMode done\n")); -} - - -status_t -SET_DISPLAY_MODE (display_mode* mode_to_set) -{ - // The exported mode setting routine. First validate the mode, - // then call our private routine to hammer the registers. - - display_mode bounds, target; - - /* ask for the specific mode */ - target = bounds = *mode_to_set; - if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR) - return B_ERROR; - - SetDisplayMode(&target); - si->dm = target; - return B_OK; -} - -/* - Set which pixel of the virtual frame buffer will show up in the - top left corner of the display device. Used for page-flipping - games and virtual desktops. - */ -status_t -MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) -{ - /* - Many devices have limitations on the granularity of the horizontal offset. - Make any checks for this here. A future revision of the driver API will - add a hook to return the granularity for a given display mode. - */ - /* most cards can handle multiples of 8 */ - if (h_display_start & 0x07) - return B_ERROR; - /* do not run past end of display */ - if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) - return B_ERROR; - if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) - return B_ERROR; - - /* everybody remember where we parked... */ - si->dm.h_display_start = h_display_start; - si->dm.v_display_start = v_display_start; - - /* actually set the registers */ - SavageAdjustFrame(h_display_start, v_display_start); - - return B_OK; -} - -/* - Set the indexed color palette. - */ -void -SET_INDEXED_COLORS(uint count, uint8 first, uint8* colorData, uint32 flags) -{ - (void)flags; // avoid compiler warning for unused arg - - /* - Some cards use the indexed color regisers in the DAC for gamma correction. - If this is true with your device (and it probably is), you need to protect - against setting these registers when not in an indexed mode. - */ - if (si->dm.space != B_CMAP8) - return ; - - /* - There isn't any need to keep a copy of the data being stored, - as the app_server will set the colors each time it switches to - an 8bpp mode, or takes ownership of an 8bpp mode after a GameKit - app has used it. - */ - - OUTREG16(VGA_SEQ_INDEX, 0x101b); - - while (count--) { - OUTREG8(0x83c8, first++); // color index - OUTREG8(0x83c9, colorData[0]); // red - OUTREG8(0x83c9, colorData[1]); // green - OUTREG8(0x83c9, colorData[2]); // blue - colorData += 3; - } -} - diff --git a/src/add-ons/accelerants/s3savage/savage.h b/src/add-ons/accelerants/s3savage/savage.h deleted file mode 100644 index c1796844ea..0000000000 --- a/src/add-ons/accelerants/s3savage/savage.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - Haiku S3 Savage driver adapted from the X.org Savage driver. - - Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - Copyright (c) 2003-2006, X.Org Foundation - - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2006-2007 -*/ - - -#ifndef __SAVAGE_H__ -#define __SAVAGE_H__ - - -#define BASE_FREQ 14.31818 - -#define FIFO_CONTROL_REG 0x8200 -#define MIU_CONTROL_REG 0x8204 -#define STREAMS_TIMEOUT_REG 0x8208 -#define MISC_TIMEOUT_REG 0x820c - -#define ADVANCED_FUNC_CTRL 0x850C -#define SYSTEM_CONTROL_REG 0x83DA - -#define VGA_ATTR_INDEX 0x83C0 -#define VGA_ATTR_DATA_W 0x83C0 -#define VGA_MISC_OUT_R 0x83CC /* read */ -#define VGA_MISC_OUT_W 0x83C2 /* write */ -#define VGA_SEQ_INDEX 0x83C4 -#define VGA_SEQ_DATA 0x83C5 -#define VGA_GRAPH_INDEX 0x83CE -#define VGA_GRAPH_DATA 0x83CF -#define VGA_CRTC_INDEX 0x83D4 -#define VGA_CRTC_DATA 0x83D5 -#define VGA_IN_STAT_1 SYSTEM_CONTROL_REG - - -/* Stream Processor 1 */ - -/* Primary Stream 1 Frame Buffer Address 0 */ -#define PRI_STREAM_FBUF_ADDR0 0x81c0 -/* Primary Stream 1 Frame Buffer Address 1 */ -#define PRI_STREAM_FBUF_ADDR1 0x81c4 -/* Primary Stream 1 Stride */ -#define PRI_STREAM_STRIDE 0x81c8 - -/* Stream Processor 2 */ - -/* Primary Stream 2 Frame Buffer Address 0 */ -#define PRI_STREAM2_FBUF_ADDR0 0x81b0 -/* Primary Stream 2 Frame Buffer Address 1 */ -#define PRI_STREAM2_FBUF_ADDR1 0x81b4 -/* Primary Stream 2 Stride */ -#define PRI_STREAM2_STRIDE 0x81b8 - - -/* GX-3 Configuration/Status Registers */ -#define S3_BUFFER_THRESHOLD 0x48C10 -#define S3_OVERFLOW_BUFFER 0x48C14 -#define S3_OVERFLOW_BUFFER_PTR 0x48C18 - -#define MEMORY_CTRL0_REG 0xCA - -#define MEMORY_CONFIG_REG 0x31 - -/* bitmap descriptor register */ -#define S3_GLB_BD_LOW 0x8168 -#define S3_GLB_BD_HIGH 0x816C -#define S3_PRI_BD_LOW 0x8170 -#define S3_PRI_BD_HIGH 0x8174 -#define S3_SEC_BD_LOW 0x8178 -#define S3_SEC_BD_HIGH 0x817c - -/* duoview */ - -#define SELECT_IGA1 0x4026 -#define SELECT_IGA2_READS_WRITES 0x4f26 - -#define MEM_PS1 0x10 /*CRCA_4 :Primary stream 1*/ -#define MEM_PS2 0x20 /*CRCA_5 :Primary stream 2*/ -#define MEM_SS1 0x40 /*CRCA_6 :Secondary stream 1*/ -#define MEM_SS2 0x80 /*CRCA_7 :Secondary stream 2*/ - -#define SRC_BASE 0xa4d4 -#define DEST_BASE 0xa4d8 -#define CLIP_L_R 0xa4dc -#define CLIP_T_B 0xa4e0 -#define DEST_SRC_STR 0xa4e4 -#define MONO_PAT_0 0xa4e8 -#define MONO_PAT_1 0xa4ec - -/* - * CR88_4 =1 : disable block write - * the "2D" is partly to set this apart from "BLOCK_WRITE_DISABLE" - * constant used for bitmap descriptor - */ -#define DISABLE_BLOCK_WRITE_2D 0x10 -#define BLOCK_WRITE_DISABLE 0x0 - -/* CR31[0] set = Enable 8MB display memory through 64K window at A0000H. */ -#define ENABLE_CPUA_BASE_A0000 0x01 - -/* - * reads from SUBSYS_STAT - */ -#define STATUS_WORD0 (INREG(0x48C00)) -#define ALT_STATUS_WORD0 (INREG(0x48C60)) -#define MAXLOOP 0xffffff -#define MAXFIFO 0x7f00 - -// BCI definitions. -//================= - -#define TILE_FORMAT_LINEAR 0 - -/* BD - BCI enable */ -#define BCI_ENABLE 8 // savage4, MX, IX, 3D -#define BCI_ENABLE_TWISTER 0 // twister, prosavage, DDR, supersavage, 2000 - -#define S3_BIG_ENDIAN 4 -#define S3_LITTLE_ENDIAN 0 -#define S3_BD64 1 - -#define BCI_BUFFER_OFFSET 0x10000 - -#define BCI_GET_PTR vuint32* bci_ptr = ((uint32*)(regs + BCI_BUFFER_OFFSET)) -#define BCI_SEND(dw) (*bci_ptr++ = ((uint32)(dw))) - -#define BCI_CMD_NOP 0x40000000 -#define BCI_CMD_RECT 0x48000000 -#define BCI_CMD_RECT_XP 0x01000000 -#define BCI_CMD_RECT_YP 0x02000000 -#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF) -#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) - -#define BCI_CMD_SEND_COLOR 0x00008000 -#define BCI_CMD_DEST_PBD_NEW 0x00000C00 -#define BCI_CMD_SRC_SOLID 0x00000000 -#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140 - -#define BCI_BD_BW_DISABLE 0x10000000 -#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16)) -#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF)) - -#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF) -#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF) - - -// Macros for memory mapped I/O. -//============================== - -#define INREG8(addr) *((vuint8*)(regs + addr)) -#define INREG16(addr) *((vuint16*)(regs + addr)) -#define INREG32(addr) *((vuint32*)(regs + addr)) - -#define OUTREG8(addr, val) *((vuint8*)(regs + addr)) = val -#define OUTREG16(addr, val) *((vuint16*)(regs + addr)) = val -#define OUTREG32(addr, val) *((vuint32*)(regs + addr)) = val - -#define INREG(addr) INREG32(addr) -#define OUTREG(addr, val) OUTREG32(addr, val) - - -static inline uint8 ReadCrtc(uint8 index) -{ - OUTREG8(VGA_CRTC_INDEX, index); - return INREG8(VGA_CRTC_DATA); -} - -static inline void WriteCrtc(uint8 index, uint8 value) -{ - OUTREG8(VGA_CRTC_INDEX, index); - OUTREG8(VGA_CRTC_DATA, value); -} - -static inline uint8 ReadSeq(uint8 index) -{ - OUTREG8(VGA_SEQ_INDEX, index); - return INREG8(VGA_SEQ_DATA); -} - -static inline void WriteSeq(uint8 index, uint8 value) -{ - OUTREG8(VGA_SEQ_INDEX, index); - OUTREG8(VGA_SEQ_DATA, value); -} - -static inline uint8 ReadST01() -{ - return INREG8(VGA_IN_STAT_1); -} - -/* - * unprotect CRTC[0-7] - * CR11_7 = 0: Writing to all CRT Controller registers enabled - * = 1: Writing to all bits of CR0~CR7 except CR7_4 disabled - */ -static inline void UnProtectCRTC() -{ - unsigned char byte; - OUTREG8(VGA_CRTC_INDEX, 0x11); - byte = INREG8(VGA_CRTC_DATA) & 0x7F; - OUTREG16(VGA_CRTC_INDEX, byte << 8 | 0x11); -} - -/* - * unlock extended regs - * CR38:unlock CR20~CR3F - * CR39:unlock CR40~CRFF - * SR08:unlock SR09~SRFF - */ -static inline void UnLockExtRegs() -{ - OUTREG16(VGA_CRTC_INDEX, 0x4838); - OUTREG16(VGA_CRTC_INDEX, 0xA039); - OUTREG16(VGA_SEQ_INDEX, 0x0608); -} - - -static inline void VerticalRetraceWait() -{ - INREG8(VGA_CRTC_INDEX); - OUTREG8(VGA_CRTC_INDEX, 0x17); - if (INREG8(VGA_CRTC_DATA) & 0x80) - { - int i = 0x10000; - while ((INREG8(SYSTEM_CONTROL_REG) & 0x08) == 0x08 && i--) ; - i = 0x10000; - while ((INREG8(SYSTEM_CONTROL_REG) & 0x08) == 0x00 && i--) ; - } -} - - -typedef struct -{ - display_timing timing; // CRTC info - int bpp; // bits/pixel - int width; // screen width in pixels - int bytesPerRow; // number of bytes in one line/row -} DisplayMode; - - - -bool IsDisplaySizeValid(int width, int height); - -bool SavageLoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); -void SavageSetCursorPosition(int x, int y); -void SavageShowCursor(void); -void SavageHideCursor(void); - -bool SavageDPMS(int mode); - -bool SavagePreInit(void); -bool SavageModeInit(DisplayMode* pMode); -void SavageInitialize2DEngine(DisplayMode* pMode); -void SavageSetGBD(DisplayMode* pMode); -void SavageAdjustFrame(int x, int y); - - -#endif // __SAVAGE_H__ diff --git a/src/add-ons/accelerants/s3savage/savage_accel.c b/src/add-ons/accelerants/s3savage/savage_accel.c deleted file mode 100644 index 9be90d5452..0000000000 --- a/src/add-ons/accelerants/s3savage/savage_accel.c +++ /dev/null @@ -1,768 +0,0 @@ -/* - Haiku S3 Savage driver adapted from the X.org Savage driver. - - Copyright 1995-1997 The XFree86 Project, Inc. - - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2006-2007 -*/ - - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" - - -static void -SavageSetGBD_Twister(DisplayMode* pMode) -{ - uint32 ulTmp; - uint8 byte; - int bci_enable; - - TRACE(("SavageSetGBD_Twister\n")); - - if (si->chipset == S3_SAVAGE4) - bci_enable = BCI_ENABLE; - else - bci_enable = BCI_ENABLE_TWISTER; - - /* MM81C0 and 81C4 are used to control primary stream. */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, 0); - OUTREG32(PRI_STREAM_FBUF_ADDR1, 0); - - /* - * Program Primary Stream Stride Register. - * - * Tell engine if tiling on or off, set primary stream stride, and - * if tiling, set tiling bits/pixel and primary stream tile offset. - * Note that tile offset (bits 16 - 29) must be scanline width in - * bytes/128bytespertile * 256 Qwords/tile. This is equivalent to - * lDelta * 2. Remember that if tiling, lDelta is screenwidth in - * bytes padded up to an even number of tilewidths. - */ - - OUTREG32(PRI_STREAM_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFFE000) | - (pMode->bytesPerRow & 0x00001fff)); - - /* - * CR69, bit 7 = 1 - * to use MM streams processor registers to control primary stream. - */ - OUTREG8(VGA_CRTC_INDEX, 0x69); - byte = INREG8(VGA_CRTC_DATA) | 0x80; - OUTREG8(VGA_CRTC_DATA, byte); - - OUTREG32(0x8128, 0xFFFFFFFFL); - OUTREG32(0x812C, 0xFFFFFFFFL); - - OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - /* CR50, bit 7,6,0 = 111, Use GBD.*/ - OUTREG8(VGA_CRTC_INDEX, 0x50); - byte = INREG8(VGA_CRTC_DATA) | 0xC1; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * if MS1NB style linear tiling mode. - * bit MM850C[15] = 0 select NB linear tile mode. - * bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode. - */ - ulTmp = INREG32(ADVANCED_FUNC_CTRL) | 0x8000; /* use MS-s style tile mode*/ - OUTREG32(ADVANCED_FUNC_CTRL, ulTmp); - - /* - * Set up Tiled Surface Registers - * Bit 25:20 - Surface width in tiles. - * Bit 29 - Y Range Flag. - * Bit 31:30 = 00, 4 bpp. - * = 01, 8 bpp. - * = 10, 16 bpp. - * = 11, 32 bpp. - */ - /* - * Global Bitmap Descriptor Register MM816C - twister/prosavage - * bit 24~25: tile format - * 00: linear - * 01: destination tiling format - * 10: texture tiling format - * 11: reserved - * bit 28: block write disble/enable - * 0: disable - * 1: enable - */ - /* - * Global Bitmap Descriptor Register MM816C - savage4 - * bit 24~25: tile format - * 00: linear - * 01: reserved - * 10: 16 bpp tiles - * 11: 32 bpp tiles - * bit 28: block write disable/enable - * 0: enable - * 1: disable - */ - - /* - * Do not enable block_write even for non-tiling modes, because - * the driver cannot determine if the memory type is the certain - * type of SGRAM for which block_write can be used. - */ - si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */ - si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */ - /* HW uses width */ - si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line - si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp); - si->GlobalBD.bd1.Offset = si->frameBufferOffset; - - /* - * CR88, bit 4 - Block write enabled/disabled. - * - * Note: Block write must be disabled when writing to tiled - * memory. Even when writing to non-tiled memory, block - * write should only be enabled for certain types of SGRAM. - */ - OUTREG8(VGA_CRTC_INDEX, 0x88); - byte = INREG8(VGA_CRTC_DATA) | DISABLE_BLOCK_WRITE_2D; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - * bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - * at A000:0. - */ - OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */ - byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000)); - OUTREG8(VGA_CRTC_DATA, byte); /* perhaps this should be 0x0c */ - - /* turn on screen */ - OUTREG8(VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) & ~0x20; - OUTREG8(VGA_SEQ_DATA, byte); - - /* program the GBD and SBD's */ - OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_GLB_BD_HIGH, si->GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart); -} - - -static void -SavageSetGBD_3D(DisplayMode* pMode) -{ - uint32 ulTmp; - uint8 byte; - int bci_enable; - - TRACE(("SavageSetGBD_3D\n")); - - bci_enable = BCI_ENABLE; - - /* MM81C0 and 81C4 are used to control primary stream. */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, 0); - OUTREG32(PRI_STREAM_FBUF_ADDR1, 0); - - /* - * Program Primary Stream Stride Register. - * - * Tell engine if tiling on or off, set primary stream stride, and - * if tiling, set tiling bits/pixel and primary stream tile offset. - * Note that tile offset (bits 16 - 29) must be scanline width in - * bytes/128bytespertile * 256 Qwords/tile. This is equivalent to - * lDelta * 2. Remember that if tiling, lDelta is screenwidth in - * bytes padded up to an even number of tilewidths. - */ - - OUTREG32(PRI_STREAM_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFFE000) | - (pMode->bytesPerRow & 0x00001fff)); - - /* - * CR69, bit 7 = 1 - * to use MM streams processor registers to control primary stream. - */ - OUTREG8(VGA_CRTC_INDEX, 0x69); - byte = INREG8(VGA_CRTC_DATA) | 0x80; - OUTREG8(VGA_CRTC_DATA, byte); - - OUTREG32(0x8128, 0xFFFFFFFFL); - OUTREG32(0x812C, 0xFFFFFFFFL); - - OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - /* CR50, bit 7,6,0 = 111, Use GBD.*/ - OUTREG8(VGA_CRTC_INDEX, 0x50); - byte = INREG8(VGA_CRTC_DATA) | 0xC1; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * if MS1NB style linear tiling mode. - * bit MM850C[15] = 0 select NB linear tile mode. - * bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode. - */ - ulTmp = INREG32(ADVANCED_FUNC_CTRL) | 0x8000; /* use MS-s style tile mode*/ - OUTREG32(ADVANCED_FUNC_CTRL, ulTmp); - - /* - * Tiled Surface 0 Registers MM48C40: - * bit 0~23: tile surface 0 frame buffer offset - * bit 24~29:tile surface 0 width - * bit 30~31:tile surface 0 bits/pixel - * 00: reserved - * 01, 8 bits - * 10, 16 Bits. - * 11, 32 Bits. - */ - /* - * Global Bitmap Descriptor Register MM816C - * bit 24~25: tile format - * 00: linear - * 01: reserved - * 10: 16 bpp tiles - * 11: 32 bpp tiles - * bit 28: block write disable/enable - * 0: enable - * 1: disable - */ - - /* - * Do not enable block_write even for non-tiling modes, because - * the driver cannot determine if the memory type is the certain - * type of SGRAM for which block_write can be used. - */ - si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */ - si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */ - /* HW uses width */ - si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line - si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp); - si->GlobalBD.bd1.Offset = si->frameBufferOffset; - - /* - * CR88, bit 4 - Block write enabled/disabled. - * - * Note: Block write must be disabled when writing to tiled - * memory. Even when writing to non-tiled memory, block - * write should only be enabled for certain types of SGRAM. - */ - OUTREG8(VGA_CRTC_INDEX, 0x88); - byte = INREG8(VGA_CRTC_DATA) | DISABLE_BLOCK_WRITE_2D; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - * bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - * at A000:0. - */ - OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */ - byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000)); - OUTREG8(VGA_CRTC_DATA, byte); /* perhaps this should be 0x0c */ - - /* turn on screen */ - OUTREG8(VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) & ~0x20; - OUTREG8(VGA_SEQ_DATA, byte); - - /* program the GBD and SBD's */ - OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_GLB_BD_HIGH, si->GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart); -} - - -static void -SavageSetGBD_M7(DisplayMode* pMode) -{ - uint8 byte; - int bci_enable; - - TRACE(("SavageSetGBD_M7\n")); - - bci_enable = BCI_ENABLE; - - /* following is the enable case */ - - /* SR01:turn off screen */ - OUTREG8 (VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) | 0x20; - OUTREG8(VGA_SEQ_DATA, byte); - - /* - * CR67_3: - * = 1 stream processor MMIO address and stride register - * are used to control the primary stream - * = 0 standard VGA address and stride registers - * are used to control the primary streams - */ - - OUTREG8(VGA_CRTC_INDEX, 0x67); - byte = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_DATA, byte); - /* IGA 2 */ - OUTREG16(VGA_SEQ_INDEX, SELECT_IGA2_READS_WRITES); - OUTREG8(VGA_CRTC_INDEX, 0x67); - byte = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_DATA, byte); - OUTREG16(VGA_SEQ_INDEX, SELECT_IGA1); - - /* Set primary stream to bank 0 */ - OUTREG8(VGA_CRTC_INDEX, MEMORY_CTRL0_REG); /* CRCA */ - byte = INREG8(VGA_CRTC_DATA) & ~(MEM_PS1 + MEM_PS2) ; - OUTREG8(VGA_CRTC_DATA, byte); - - /* MM81C0 and 81C4 are used to control primary stream. */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset & 0x7fffff); - OUTREG32(PRI_STREAM_FBUF_ADDR1, si->frameBufferOffset & 0x7fffff); - OUTREG32(PRI_STREAM2_FBUF_ADDR0, si->frameBufferOffset & 0x7fffff); - OUTREG32(PRI_STREAM2_FBUF_ADDR1, si->frameBufferOffset & 0x7fffff); - - /* - * Program Primary Stream Stride Register. - * - * Tell engine if tiling on or off, set primary stream stride, and - * if tiling, set tiling bits/pixel and primary stream tile offset. - * Note that tile offset (bits 16 - 29) must be scanline width in - * bytes/128bytespertile * 256 Qwords/tile. This is equivalent to - * lDelta * 2. Remember that if tiling, lDelta is screenwidth in - * bytes padded up to an even number of tilewidths. - */ - - OUTREG32(PRI_STREAM_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) | - (pMode->bytesPerRow & 0x00003fff)); - OUTREG32(PRI_STREAM2_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) | - (pMode->bytesPerRow & 0x00003fff)); - - OUTREG32(0x8128, 0xFFFFFFFFL); - OUTREG32(0x812C, 0xFFFFFFFFL); - - OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - /* CR50, bit 7,6,0 = 111, Use GBD.*/ - OUTREG8(VGA_CRTC_INDEX, 0x50); - byte = INREG8(VGA_CRTC_DATA) | 0xC1; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * CR78, bit 3 - Block write enabled(1)/disabled(0). - * bit 2 - Block write cycle time(0:2 cycles,1: 1 cycle) - * Note: Block write must be disabled when writing to tiled - * memory. Even when writing to non-tiled memory, block - * write should only be enabled for certain types of SGRAM. - */ - OUTREG8(VGA_CRTC_INDEX, 0x78); - byte = INREG8(VGA_CRTC_DATA) | 0xfb; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * Tiled Surface 0 Registers MM48C40: - * bit 0~23: tile surface 0 frame buffer offset - * bit 24~29:tile surface 0 width - * bit 30~31:tile surface 0 bits/pixel - * 00: reserved - * 01, 8 bits - * 10, 16 Bits. - * 11, 32 Bits. - */ - /* - * Global Bitmap Descriptor Register MM816C - * bit 24~25: tile format - * 00: linear - * 01: reserved - * 10: 16 bit - * 11: 32 bit - * bit 28: block write disble/enable - * 0: enable - * 1: disable - */ - - /* - * Do not enable block_write even for non-tiling modes, because - * the driver cannot determine if the memory type is the certain - * type of SGRAM for which block_write can be used. - */ - si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */ - si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */ - /* HW uses width */ - si->GlobalBD.bd1.HighPart.Stride = (uint16)(pMode->width); // number of pixels per line - si->GlobalBD.bd1.HighPart.Bpp = (uint8)(pMode->bpp); - si->GlobalBD.bd1.Offset = si->frameBufferOffset; - - /* - * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - * bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - * at A000:0. - */ - - OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); /* cr31 */ - byte = (INREG8(VGA_CRTC_DATA) | 0x04) & 0xFE; - OUTREG8(VGA_CRTC_DATA, byte); - - /* program the GBD and SBD's */ - OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart ); - /* 8: bci enable */ - OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart); - OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart); - - /* turn on screen */ - OUTREG8(VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) & ~0x20; - OUTREG8(VGA_SEQ_DATA, byte); -} - - -static void -SavageSetGBD_PM(DisplayMode* pMode) -{ - uint8 byte; - int bci_enable; - - TRACE(("SavageSetGBD_PM\n")); - - bci_enable = BCI_ENABLE_TWISTER; - - /* following is the enable case */ - - /* SR01:turn off screen */ - OUTREG8 (VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) | 0x20; - OUTREG8(VGA_SEQ_DATA, byte); - - /* - * CR67_3: - * = 1 stream processor MMIO address and stride register - * are used to control the primary stream - * = 0 standard VGA address and stride registers - * are used to control the primary streams - */ - - OUTREG8(VGA_CRTC_INDEX, 0x67); - byte = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_DATA, byte); - /* IGA 2 */ - OUTREG16(VGA_SEQ_INDEX, SELECT_IGA2_READS_WRITES); - - OUTREG8(VGA_CRTC_INDEX, 0x67); - byte = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_DATA, byte); - - OUTREG16(VGA_SEQ_INDEX, SELECT_IGA1); - - /* - * load ps1 active registers as determined by MM81C0/81C4 - * load ps2 active registers as determined by MM81B0/81B4 - */ - OUTREG8(VGA_CRTC_INDEX, 0x65); - byte = INREG8(VGA_CRTC_DATA) | 0x03; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * Program Primary Stream Stride Register. - * - * Tell engine if tiling on or off, set primary stream stride, and - * if tiling, set tiling bits/pixel and primary stream tile offset. - * Note that tile offset (bits 16 - 29) must be scanline width in - * bytes/128bytespertile * 256 Qwords/tile. This is equivalent to - * lDelta * 2. Remember that if tiling, lDelta is screenwidth in - * bytes padded up to an even number of tilewidths. - */ - - OUTREG32(PRI_STREAM_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) | - (pMode->bytesPerRow & 0x00001fff)); - OUTREG32(PRI_STREAM2_STRIDE, - (((pMode->bytesPerRow * 2) << 16) & 0x3FFF0000) | - (pMode->bytesPerRow & 0x00001fff)); - - /* MM81C0 and 81C4 are used to control primary stream. */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset); - OUTREG32(PRI_STREAM_FBUF_ADDR1, 0x80000000); - OUTREG32(PRI_STREAM2_FBUF_ADDR0, (si->frameBufferOffset & 0xfffffffc) | 0x80000000); - OUTREG32(PRI_STREAM2_FBUF_ADDR1, si->frameBufferOffset & 0xfffffffc); - - OUTREG32(0x8128, 0xFFFFFFFFL); - OUTREG32(0x812C, 0xFFFFFFFFL); - - /* bit 28:block write disable */ - OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); - - /* CR50, bit 7,6,0 = 111, Use GBD.*/ - OUTREG8(VGA_CRTC_INDEX, 0x50); - byte = INREG8(VGA_CRTC_DATA) | 0xC1; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * Do not enable block_write even for non-tiling modes, because - * the driver cannot determine if the memory type is the certain - * type of SGRAM for which block_write can be used. - */ - si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */ - si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */ - /* HW uses width */ - si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line - si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp); - si->GlobalBD.bd1.Offset = si->frameBufferOffset; - - /* - * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - * bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - * at A000:0. - */ - OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); - byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000)); - OUTREG8(VGA_CRTC_DATA, byte); - - /* program the GBD and SBDs */ - OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart ); - OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart); - OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart); - - /* turn on screen */ - OUTREG8(VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) & ~0x20; - OUTREG8(VGA_SEQ_DATA, byte); -} - - -static void -SavageSetGBD_2000(DisplayMode* pMode) -{ - uint32 ulYRange; - uint8 byte; - int bci_enable; - - TRACE(("SavageSetGBD_2000\n")); - - bci_enable = BCI_ENABLE_TWISTER; - - if (pMode->width > 1024) - ulYRange = 0x40000000; - else - ulYRange = 0x20000000; - - /* following is the enable case */ - - /* SR01:turn off screen */ - OUTREG8 (VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) | 0x20; - OUTREG8(VGA_SEQ_DATA, byte); - - /* MM81C0 and 81B0 are used to control primary stream. */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, si->frameBufferOffset); - OUTREG32(PRI_STREAM2_FBUF_ADDR0, si->frameBufferOffset); - - /* - * Program Primary Stream Stride Register. - * - * Tell engine if tiling on or off, set primary stream stride, and - * if tiling, set tiling bits/pixel and primary stream tile offset. - * Note that tile offset (bits 16 - 29) must be scanline width in - * bytes/128bytespertile * 256 Qwords/tile. This is equivalent to - * lDelta * 2. Remember that if tiling, lDelta is screenwidth in - * bytes padded up to an even number of tilewidths. - */ - OUTREG32(PRI_STREAM_STRIDE, ((pMode->bytesPerRow << 4) & 0x7ff0)); - OUTREG32(PRI_STREAM2_STRIDE, ((pMode->bytesPerRow << 4) & 0x7ff0)); - - /* - * CR67_3: - * = 1 stream processor MMIO address and stride register - * are used to control the primary stream - * = 0 standard VGA address and stride registers - * are used to control the primary streams - */ - - OUTREG8(VGA_CRTC_INDEX, 0x67); - byte = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_DATA, byte); - - - OUTREG32(0x8128, 0xFFFFFFFFL); - OUTREG32(0x812C, 0xFFFFFFFFL); - - /* bit 28:block write disable */ - OUTREG32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); - - /* CR50, bit 7,6,0 = 111, Use GBD.*/ - OUTREG8(VGA_CRTC_INDEX, 0x50); - byte = INREG8(VGA_CRTC_DATA) | 0xC1; - OUTREG8(VGA_CRTC_DATA, byte); - - /* CR73 bit 5 = 0 block write disable */ - OUTREG8(VGA_CRTC_INDEX, 0x73); - byte = INREG8(VGA_CRTC_DATA) & ~0x20; - OUTREG8(VGA_CRTC_DATA, byte); - - /* - * Do not enable block_write even for non-tiling modes, because - * the driver cannot determine if the memory type is the certain - * type of SGRAM for which block_write can be used. - */ - si->GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; /* linear */ - si->GlobalBD.bd1.HighPart.ResBWTile |= 0x10; /* disable block write */ - /* HW uses width */ - si->GlobalBD.bd1.HighPart.Stride = (uint16) (pMode->width); // number of pixels per line - si->GlobalBD.bd1.HighPart.Bpp = (uint8) (pMode->bpp); - si->GlobalBD.bd1.Offset = si->frameBufferOffset; - - /* - * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - * bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - * at A000:0. - */ - OUTREG8(VGA_CRTC_INDEX, MEMORY_CONFIG_REG); - byte = INREG8(VGA_CRTC_DATA) & (~(ENABLE_CPUA_BASE_A0000)); - OUTREG8(VGA_CRTC_DATA, byte); - - /* program the GBD and SBDs */ - OUTREG32(S3_GLB_BD_LOW, si->GlobalBD.bd2.LoPart ); - OUTREG32(S3_GLB_BD_HIGH, (si->GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - OUTREG32(S3_PRI_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_PRI_BD_HIGH, si->GlobalBD.bd2.HiPart); - OUTREG32(S3_SEC_BD_LOW, si->GlobalBD.bd2.LoPart); - OUTREG32(S3_SEC_BD_HIGH, si->GlobalBD.bd2.HiPart); - - /* turn on screen */ - OUTREG8(VGA_SEQ_INDEX, 0x01); - byte = INREG8(VGA_SEQ_DATA) & ~0x20; - OUTREG8(VGA_SEQ_DATA, byte); -} - - -void -SavageSetGBD(DisplayMode* pMode) -{ - TRACE(("SavageSetGBD\n")); - - UnProtectCRTC(); - UnLockExtRegs(); - VerticalRetraceWait(); - - switch (si->chipset) { - case S3_SAVAGE3D: - SavageSetGBD_3D(pMode); - break; - - case S3_SAVAGE_MX: - SavageSetGBD_M7(pMode); - break; - - case S3_SAVAGE4: - case S3_PROSAVAGE: - case S3_TWISTER: - case S3_PROSAVAGEDDR: - SavageSetGBD_Twister(pMode); - break; - - case S3_SUPERSAVAGE: - SavageSetGBD_PM(pMode); - break; - - case S3_SAVAGE2000: - SavageSetGBD_2000(pMode); - break; - } -} - - -void -SavageInitialize2DEngine(DisplayMode* pMode) -{ - uint32 thresholds; - - TRACE(("SavageInitialize2DEngine\n")); - - OUTREG16(VGA_CRTC_INDEX, 0x0140); - OUTREG8(VGA_CRTC_INDEX, 0x31); - OUTREG8(VGA_CRTC_DATA, 0x0c); - - /* Setup plane masks */ - OUTREG(0x8128, ~0); /* enable all write planes */ - OUTREG(0x812C, ~0); /* enable all read planes */ - OUTREG16(0x8134, 0x27); - OUTREG16(0x8136, 0x07); - - switch (si->chipset) { - case S3_SAVAGE3D: - case S3_SAVAGE_MX: - - /* Disable BCI */ - OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0); - /* Setup BCI command overflow buffer */ - OUTREG(0x48C14, (si->cobOffset >> 11) | (si->cobIndex << 29)); /* tim */ - /* Program shadow status update. */ - thresholds = ((si->bciThresholdLo & 0xffff) << 16) | - (si->bciThresholdHi & 0xffff); - OUTREG(0x48C10, thresholds); - - OUTREG(0x48C0C, 0); - /* Enable BCI and command overflow buffer */ - OUTREG(0x48C18, INREG(0x48C18) | 0x0C); - break; - - case S3_SAVAGE4: - case S3_PROSAVAGE: - case S3_TWISTER: - case S3_PROSAVAGEDDR: - case S3_SUPERSAVAGE: - - /* Disable BCI */ - OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0); - - if (!si->bDisableCOB) { - /* Setup BCI command overflow buffer */ - OUTREG(0x48C14, (si->cobOffset >> 11) | (si->cobIndex << 29)); - } - /* Program shadow status update */ /* AGD: what should this be? */ - thresholds = ((si->bciThresholdLo & 0x1fffe0) << 11) - | ((si->bciThresholdHi & 0x1fffe0) >> 5); - OUTREG(0x48C10, thresholds); - - OUTREG(0x48C0C, 0); - if (si->bDisableCOB) - OUTREG(0x48C18, INREG(0x48C18) | 0x08); // enable BCI without COB - else - OUTREG(0x48C18, INREG(0x48C18) | 0x0C); // enable BCI with COB - - break; - - case S3_SAVAGE2000: - - /* Disable BCI */ - OUTREG(0x48C18, 0); - /* Setup BCI command overflow buffer */ - OUTREG(0x48C18, (si->cobOffset >> 7) | (si->cobIndex)); - /* Disable shadow status update */ - OUTREG(0x48A30, 0); - /* Enable BCI and command overflow buffer */ - OUTREG(0x48C18, INREG(0x48C18) | 0x00280000 ); - - break; - } - - /* Use and set global bitmap descriptor. */ - - /* For reasons I do not fully understand yet, on the Savage4, the */ - /* write to the GBD register, MM816C, does not "take" at this time. */ - /* Only the low-order byte is acknowledged, resulting in an incorrect */ - /* stride. Writing the register later, after the mode switch, works */ - /* correctly. This needs to get resolved. */ - - SavageSetGBD(pMode); -} - diff --git a/src/add-ons/accelerants/s3savage/savage_cursor.c b/src/add-ons/accelerants/s3savage/savage_cursor.c deleted file mode 100644 index da74b4f3e4..0000000000 --- a/src/add-ons/accelerants/s3savage/savage_cursor.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - Haiku S3 Savage driver adapted from the X.org Savage driver. - - Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - Copyright (c) 2003-2006, X.Org Foundation - - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2006-2007 -*/ - - -#include "GlobalData.h" -#include "savage.h" - - - -// Certain HW cursor operations seem to require a delay to prevent lockups. - -static void -WaitHSync(int n) -{ - while (n--) { - while ((ReadST01()) & 0x01) {}; - while (!(ReadST01()) & 0x01) {}; - } -} - - -void -SavageHideCursor(void) -{ - /* Turn cursor off. */ - - if (S3_SAVAGE4_SERIES(si->chipset)) - WaitHSync(5); - - WriteCrtc(0x45, ReadCrtc(0x45) & 0xfe); - si->cursor.bIsVisible = false; -} - - -void -SavageShowCursor(void) -{ - /* Turn cursor on. */ - - WriteCrtc(0x45, ReadCrtc(0x45) | 0x01); - si->cursor.bIsVisible = true; -} - - -void -SavageSetCursorPosition(int x, int y) -{ - uint8 xoff, yoff; - - if (S3_SAVAGE4_SERIES(si->chipset)) - WaitHSync(5); - - /* adjust for frame buffer base address granularity */ - if (si->bitsPerPixel == 8) - x += ((si->frameX0) & 3); - else if (si->bitsPerPixel == 16) - x += ((si->frameX0) & 1); - else if (si->bitsPerPixel == 32) - x += ((si->frameX0 + 2) & 3) - 2; - - /* - * Make these even when used. There is a bug/feature on at least - * some chipsets that causes a "shadow" of the cursor in interlaced - * mode. Making this even seems to have no visible effect, so just - * do it for the generic case. - */ - - if (x < 0) { - xoff = (( -x) & 0xFE); - x = 0; - } else { - xoff = 0; - } - - if (y < 0) { - yoff = (( -y) & 0xFE); - y = 0; - } else { - yoff = 0; - } - - /* This is the recomended order to move the cursor */ - WriteCrtc( 0x46, (x & 0xff00) >> 8 ); - WriteCrtc( 0x47, (x & 0xff) ); - WriteCrtc( 0x49, (y & 0xff) ); - WriteCrtc( 0x4e, xoff ); - WriteCrtc( 0x4f, yoff ); - WriteCrtc( 0x48, (y & 0xff00) >> 8 ); -} - - -static void -SavageSetCursorColors(int bg, int fg) -{ - /* With the streams engine on HW Cursor seems to be 24bpp ALWAYS */ - -//@ TRACE(("SavageSetCursorColors\n")); - - /* Do it straight, full 24 bit color. */ - /* Reset the cursor color stack pointer */ - ReadCrtc(0x45); - /* Write low, mid, high bytes - foreground */ - WriteCrtc(0x4a, fg); - WriteCrtc(0x4a, fg >> 8); - WriteCrtc(0x4a, fg >> 16); - /* Reset the cursor color stack pointer */ - ReadCrtc(0x45); - /* Write low, mid, high bytes - background */ - WriteCrtc(0x4b, bg); - WriteCrtc(0x4b, bg >> 8); - WriteCrtc(0x4b, bg >> 16); -} - - -/* Assume width and height are byte-aligned. */ - -bool -SavageLoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask) -{ - int i, colByte, row; - uint8* fbCursor; - uint16* fbCursor16; - -// TRACE(("SavageLoadCursorImage, width: %ld height: %ld\n", width, height)); - - if ( ! andMask || ! xorMask) - return false; - - // Initialize the hardware cursor as completely transparent. - - fbCursor16 = (void *)((addr_t)si->videoMemAddr + si->cursorOffset); - - for (i = 0; i < 1024 / 4; i++) { - *fbCursor16++ = ~0; // and bits - *fbCursor16++ = 0; // xor bits - } - - // Now load the AND & XOR masks for the cursor image into the cursor - // buffer. - - fbCursor = (void *)((addr_t)si->videoMemAddr + si->cursorOffset); - - for (row = 0; row < height; row++) { - for (colByte = 0; colByte < width / 8; colByte++) { - fbCursor[row * 16 + colByte] = *andMask++; - fbCursor[row * 16 + colByte + 2] = *xorMask++; - } - } - - SavageSetCursorColors(~0, 0); // set cursor colors to black & white - - /* Set cursor location in video memory. */ - WriteCrtc(0x4d, (0xff & si->cursorOffset / 1024)); - WriteCrtc(0x4c, (0xff00 & si->cursorOffset / 1024) >> 8); - - if (S3_SAVAGE4_SERIES(si->chipset)) { - /* - * Bug in Savage4 Rev B requires us to do an MMIO read after - * loading the cursor. - */ - volatile unsigned int k = ALT_STATUS_WORD0; - (void)k++; /* Not to be optimised out */ - } - - return true; -} - diff --git a/src/add-ons/accelerants/s3savage/savage_dpms.c b/src/add-ons/accelerants/s3savage/savage_dpms.c deleted file mode 100644 index abe6d7ba57..0000000000 --- a/src/add-ons/accelerants/s3savage/savage_dpms.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - Haiku S3 Savage driver adapted from the X.org Savage driver. - - Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - Copyright (c) 2003-2006, X.Org Foundation - - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2006-2007 -*/ - - -#include "GlobalData.h" -#include "AccelerantPrototypes.h" -#include "savage.h" - - - -status_t -SET_DPMS_MODE(uint32 dpmsMode) -{ - // Set the display into one of the Display Power Management modes, - // and return B_OK if successful, else return B_ERROR. - - uint8 sr8 = 0x00, srd = 0x00; - - TRACE(("SET_DPMS_MODE, mode: %d, display type: %d\n", dpmsMode, si->displayType)); - - if (si->displayType == MT_CRT) { - OUTREG8(VGA_SEQ_INDEX, 0x08); - sr8 = INREG8(VGA_SEQ_DATA); - sr8 |= 0x06; - OUTREG8(VGA_SEQ_DATA, sr8); - - OUTREG8(VGA_SEQ_INDEX, 0x0d); - srd = INREG8(VGA_SEQ_DATA); - - srd &= 0x03; - - switch (dpmsMode) { - case B_DPMS_ON: - break; - case B_DPMS_STAND_BY: - srd |= 0x10; - break; - case B_DPMS_SUSPEND: - srd |= 0x40; - break; - case B_DPMS_OFF: - srd |= 0x50; - break; - default: - TRACE(("Invalid DPMS mode %d\n", dpmsMode)); - return B_ERROR; - } - - OUTREG8(VGA_SEQ_INDEX, 0x0d); - OUTREG8(VGA_SEQ_DATA, srd); - } else if (si->displayType == MT_LCD || si->displayType == MT_DFP) { - switch (dpmsMode) { - case B_DPMS_ON: - OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */ - OUTREG8(VGA_SEQ_DATA, INREG8(VGA_SEQ_DATA) | 0x10); - break; - case B_DPMS_STAND_BY: - case B_DPMS_SUSPEND: - case B_DPMS_OFF: - OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */ - OUTREG8(VGA_SEQ_DATA, INREG8(VGA_SEQ_DATA) & ~0x10); - break; - default: - TRACE(("Invalid DPMS mode %d\n", dpmsMode)); - return B_ERROR; - } - } - - return B_OK; -} - - -uint32 -DPMS_CAPABILITIES (void) -{ - // Return DPMS modes supported by this device. - - return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; -} - - -uint32 -DPMS_MODE (void) -{ - // Return the current DPMS mode. - - // Note: I do not know whether the following code is correctly reading - // the current DPMS mode. I'm assuming that reading back the bits that - // were set by function SET_DPMS_MODE will give the current DPMS mode. - - uint32 mode = B_DPMS_ON; - uint8 srd; - - if (si->displayType == MT_CRT) { - OUTREG8(VGA_SEQ_INDEX, 0x0d); - srd = INREG8(VGA_SEQ_DATA); - - switch (srd & 0x70) { - case 0: - mode = B_DPMS_ON; - break; - case 0x10: - mode = B_DPMS_STAND_BY; - break; - case 0x40: - mode = B_DPMS_SUSPEND; - break; - case 0x50: - mode = B_DPMS_OFF; - break; - default: - TRACE(("Unknown DPMS mode read from device %X\n", srd)); - } - } else if (si->displayType == MT_LCD || si->displayType == MT_DFP) { - OUTREG8(VGA_SEQ_INDEX, 0x31); /* SR31 bit 4 - FP enable */ - srd = INREG8(VGA_SEQ_DATA); - mode = ((srd & 0x10) ? B_DPMS_ON : B_DPMS_OFF); - } - - TRACE(("DPMS_MODE = %d\n", mode)); - return mode; -} - diff --git a/src/add-ons/accelerants/s3savage/savage_driver.c b/src/add-ons/accelerants/s3savage/savage_driver.c deleted file mode 100644 index 3d21cdbc84..0000000000 --- a/src/add-ons/accelerants/s3savage/savage_driver.c +++ /dev/null @@ -1,1260 +0,0 @@ -/* - Haiku S3 Savage driver adapted from the X.org Savage driver. - - Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - Copyright (c) 2003-2006, X.Org Foundation - - Copyright 2007 Haiku, Inc. All rights reserved. - Distributed under the terms of the MIT license. - - Authors: - Gerald Zajac 2006-2007 -*/ - - -#include "GlobalData.h" -#include "savage.h" - - -#define CURSOR_KBYTES 4 // kilobytes used for cursor image in video memory - - -typedef struct -{ - unsigned char CRTC[25]; // Crtc Controller reg's - - unsigned char SR08, SR0E, SR0F; - unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR1B, SR29, SR30; - unsigned char SR54[8]; - unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; - unsigned char CR40, CR41, CR42, CR43, CR45; - unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; - unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; - unsigned char CR86, CR88; - unsigned char CR90, CR91, CRB0; - unsigned int MMPR0, MMPR1, MMPR2, MMPR3; -} SavageRegRec; - - - - -static void -InitCrtcTimingValues(DisplayMode* pMode, SavageRegRec* pRegRec) -{ - int hTotal = ((pMode->timing.h_total >> 3) - 5); - int hDisp_e = ((pMode->timing.h_display >> 3) - 1); - int hSync_s = (pMode->timing.h_sync_start >> 3); - int hSync_e = (pMode->timing.h_sync_end >> 3); - int hBlank_s = hDisp_e; // start of horizontal blanking - int hBlank_e = hTotal; // end of horizontal blanking - - int vTotal = pMode->timing.v_total - 2; - int vDisp_e = pMode->timing.v_display - 1; - int vSync_s = pMode->timing.v_sync_start; - int vSync_e = pMode->timing.v_sync_end; - int vBlank_s = vDisp_e; // start of vertical blanking - int vBlank_e = vTotal; // end of vertical blanking - - TRACE(("InitCrtcTimingValues\n")); - - // CRTC Controller values - - pRegRec->CRTC[0] = hTotal; - pRegRec->CRTC[1] = hDisp_e; - pRegRec->CRTC[2] = hBlank_s; - pRegRec->CRTC[3] = (hBlank_e & 0x1F) | 0x80; - pRegRec->CRTC[4] = hSync_s; - pRegRec->CRTC[5] = ((hSync_e & 0x1F) | ((hBlank_e & 0x20) << 2)); - pRegRec->CRTC[6] = vTotal; - pRegRec->CRTC[7] = (((vTotal & 0x100) >> 8) - | ((vDisp_e & 0x100) >> 7) - | ((vSync_s & 0x100) >> 6) - | ((vBlank_s & 0x100) >> 5) - | 0x10 - | ((vTotal & 0x200) >> 4) - | ((vDisp_e & 0x200) >> 3) - | ((vSync_s & 0x200) >> 2)); - - pRegRec->CRTC[8] = 0x00; - pRegRec->CRTC[9] = ((vBlank_s & 0x200) >> 4) | 0x40; - pRegRec->CRTC[10] = 0x00; - pRegRec->CRTC[11] = 0x00; - pRegRec->CRTC[12] = 0x00; - pRegRec->CRTC[13] = 0x00; - pRegRec->CRTC[14] = 0x00; - pRegRec->CRTC[15] = 0x00; - pRegRec->CRTC[16] = vSync_s; - pRegRec->CRTC[17] = (vSync_e & 0x0f) | 0x20; - pRegRec->CRTC[18] = vDisp_e; - pRegRec->CRTC[19] = pMode->bytesPerRow / 16; // should we divide by 8? - pRegRec->CRTC[20] = 0x00; - pRegRec->CRTC[21] = vBlank_s; - pRegRec->CRTC[22] = vBlank_e; -// pRegRec->CRTC[23] = 0xC3; - pRegRec->CRTC[23] = 0xEB; - pRegRec->CRTC[24] = 0xFF; -} - - -static void -ResetBCI2K() -{ - uint32 cob = INREG( 0x48c18 ); - /* if BCI is enabled and BCI is busy... */ - - if ( (cob & 0x00000008) && ! (ALT_STATUS_WORD0 & 0x00200000) ) { - TRACE(("Resetting BCI, stat = %08lx...\n", (uint32)ALT_STATUS_WORD0)); - /* Turn off BCI */ - OUTREG( 0x48c18, cob & ~8 ); - snooze(10000); - /* Turn it back on */ - OUTREG( 0x48c18, cob ); - snooze(10000); - } -} - - -/* Wait until "v" queue entries are free */ - -static bool -WaitQueue3D(int v) -{ - int loop = 0; - uint32 slots = MAXFIFO - v; - - while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP) ); - return loop >= MAXLOOP; -} - - -static bool -WaitQueue4(int v) -{ - int loop = 0; - uint32 slots = MAXFIFO - v; - - while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP) ); - return loop >= MAXLOOP; -} - - -static bool -WaitQueue2K(int v) -{ - int loop = 0; - uint32 slots = (MAXFIFO - v) / 4; - - while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP) ); - - if (loop >= MAXLOOP) - ResetBCI2K(); - - return loop >= MAXLOOP; -} - - -/* Wait until GP is idle and queue is empty */ - -static bool -WaitIdleEmpty3D() -{ - int loop = 0; - - while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) ); - return loop >= MAXLOOP; -} - - -static bool -WaitIdleEmpty4() -{ - int loop = 0; - - while (((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) && (loop++ < MAXLOOP)) ; - return loop >= MAXLOOP; -} - - -static bool -WaitIdleEmpty2K() -{ - int loop = 0; - - while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) ); - - if (loop >= MAXLOOP) - ResetBCI2K(); - - return loop >= MAXLOOP; -} - - -static void -SavageGetPanelInfo() -{ - uint8 cr6b; - int panelX, panelY; - char * sTechnology = "Unknown"; - enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */ - ActiveCRT = 0x01, - ActiveLCD = 0x02, - ActiveTV = 0x04, - ActiveCRT2 = 0x20, - ActiveDUO = 0x80 - }; - - /* Check LCD panel information */ - - cr6b = ReadCrtc(0x6b); - - panelX = (ReadSeq(0x61) + ((ReadSeq(0x66) & 0x02) << 7) + 1) * 8; - panelY = ReadSeq(0x69) + ((ReadSeq(0x6e) & 0x70) << 4) + 1; - - if ( ! IsDisplaySizeValid(panelX, panelY)) { - - // Some chips such as the Savage IX/MV in a Thinkpad T-22 will return - // a width that is 8 pixels too wide probably because reg SR61 is set - // to a value +1 higher than it should be. Subtract 8 from the width, - // and check if that is a valid width. - - panelX -= 8; - if ( ! IsDisplaySizeValid(panelX, panelY)) { - TRACE(("%dx%d LCD panel size invalid. No matching video mode\n", panelX + 8, panelY)); - si->displayType = MT_CRT; - return; - } - } - - if ((ReadSeq(0x39) & 0x03) == 0) - sTechnology = "TFT"; - else if ((ReadSeq(0x30) & 0x01) == 0) - sTechnology = "DSTN"; - else - sTechnology = "STN"; - - TRACE(("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology, - cr6b & ActiveLCD ? "and active" : "but not active")); - - if (cr6b & ActiveLCD) { - TRACE(("Limiting max video mode to %dx%d\n", panelX, panelY)); - - si->panelX = panelX; - si->panelY = panelY; - } else { - si->displayType = MT_CRT; - } -} - - -bool -SavagePreInit(void) -{ - bool bDvi; - uint8 m, n, n1, n2, sr8; - uint8 config1; - uint8 cr66; - uint8 temp; - uint8 val; - - TRACE(("SavagePreInit\n")); - - val = INREG8(0x83c3); - OUTREG8(0x83c3, val | 0x01); - - val = INREG8(VGA_MISC_OUT_R); - OUTREG8(VGA_MISC_OUT_W, val | 0x01); - - if (si->chipset >= S3_SAVAGE4) { - OUTREG8(VGA_CRTC_INDEX, 0x40); - val = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, val | 1); - } - - /* unprotect CRTC[0-7] */ - OUTREG8(VGA_CRTC_INDEX, 0x11); - temp = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, temp & 0x7f); - - /* unlock extended regs */ - OUTREG16(VGA_CRTC_INDEX, 0x4838); - OUTREG16(VGA_CRTC_INDEX, 0xa039); - OUTREG16(VGA_SEQ_INDEX, 0x0608); - - OUTREG8(VGA_CRTC_INDEX, 0x40); - temp = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, temp & ~0x01); - - /* unlock sys regs */ - OUTREG8(VGA_CRTC_INDEX, 0x38); - OUTREG8(VGA_CRTC_DATA, 0x48); - - /* Unlock system registers. */ - OUTREG16(VGA_CRTC_INDEX, 0x4838); - - /* Next go on to detect amount of installed ram */ - - OUTREG8(VGA_CRTC_INDEX, 0x36); /* for register CR36 (CONFG_REG1), */ - config1 = INREG8(VGA_CRTC_DATA); /* get amount of vram installed */ - - /* Compute the amount of video memory and offscreen memory. */ - - { - static const uint8 RamSavage3D[] = { 8, 4, 4, 2 }; - static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; - static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; - static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; - int ramSizeMB = 0; // memory size in megabytes - - switch (si->chipset) { - case S3_SAVAGE3D: - ramSizeMB = RamSavage3D[ (config1 & 0xC0) >> 6 ]; - break; - - case S3_SAVAGE4: - /* - * The Savage4 has one ugly special case to consider. On - * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB - * when it really means 8MB. Why do it the same when you - * can do it different... - */ - OUTREG8(VGA_CRTC_INDEX, 0x68); /* memory control 1 */ - if ( (INREG8(VGA_CRTC_DATA) & 0xC0) == (0x01 << 6) ) - RamSavage4[1] = 8; - - /*FALLTHROUGH*/ - - case S3_SAVAGE2000: - ramSizeMB = RamSavage4[ (config1 & 0xE0) >> 5 ]; - break; - - case S3_SAVAGE_MX: - case S3_SUPERSAVAGE: - ramSizeMB = RamSavageMX[ (config1 & 0x0E) >> 1 ]; - break; - - case S3_PROSAVAGE: - case S3_PROSAVAGEDDR: - case S3_TWISTER: - ramSizeMB = RamSavageNB[ (config1 & 0xE0) >> 5 ]; - break; - - default: - /* How did we get here? */ - ramSizeMB = 0; - break; - } - - TRACE(("memory size: %d MB\n", ramSizeMB)); - - si->videoMemSize = ramSizeMB * 1024 * 1024; - } - - - // Certain Savage4 and ProSavage chips can have coherency problems - // with respect to the Command Overflow Buffer (COB); thus, to avoid - // problems with these chips, set bDisableCOB to true. - - si->bDisableCOB = false; - - /* - * Compute the Command Overflow Buffer (COB) location. - */ - if ((S3_SAVAGE4_SERIES(si->chipset) || S3_SUPERSAVAGE == si->chipset) - && si->bDisableCOB) { - /* - * The Savage4 and ProSavage have COB coherency bugs which render - * the buffer useless. - */ - si->cobIndex = 0; - si->cobSize = 0; - si->bciThresholdHi = 32; - si->bciThresholdLo = 0; - } else { - /* We use 128kB for the COB on all other chips. */ - si->cobSize = 0x20000; - if (S3_SAVAGE3D_SERIES(si->chipset) || si->chipset == S3_SAVAGE2000) - si->cobIndex = 7; /* rev.A savage4 apparently also uses 7 */ - else - si->cobIndex = 2; - - /* max command size: 2560 entries */ - si->bciThresholdHi = si->cobSize / 4 + 32 - 2560; - si->bciThresholdLo = si->bciThresholdHi - 2560; - } - - // Note that the X.org developers stated that the command overflow buffer - // (COB) must END at a 4MB boundary which for all practical purposes means - // the very end of the video memory. However, for Haiku it has been put - // at the beginning of the video memory and has worked fine for the - // Savage4, ProSavage, Savage/IX, SuperSavage chipsets. If any problems - // are detected in this area with other chipsets, the following 4 lines of - // code can be uncommented and the 4 lines after those can be commented - // out to put the COB at the end of video memory. - -// si->cobOffset = (si->videoMemSize - si->cobSize) & ~0x1ffff; // align cob to 128k -// si->cursorOffset = 0; -// si->frameBufferOffset = si->cursorOffset + CURSOR_KBYTES * 1024; -// si->maxFrameBufferSize = si->cobOffset - si->frameBufferOffset; - - si->cobOffset = 0; - si->cursorOffset = (si->cobSize + 0x3FF) & ~0x3FF; - si->frameBufferOffset = si->cursorOffset + CURSOR_KBYTES * 1024; - si->maxFrameBufferSize = si->videoMemSize - si->frameBufferOffset; - - TRACE(("cobIndex: %d cobSize: %d cobOffset: 0x%X\n", si->cobIndex, si->cobSize, si->cobOffset)); - TRACE(("cursorOffset: 0x%X frameBufferOffset: 0x%X\n", si->cursorOffset, si->frameBufferOffset)); - - - /* reset graphics engine to avoid memory corruption */ - OUTREG8(VGA_CRTC_INDEX, 0x66); - cr66 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr66 | 0x02); - snooze(10000); - - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, cr66 & ~0x02); /* clear reset flag */ - snooze(10000); - - /* Check for DVI/flat panel */ - - bDvi = false; - if (si->chipset == S3_SAVAGE4) { - uint8 sr30 = 0; - OUTREG8(VGA_SEQ_INDEX, 0x30); - /* clear bit 1 */ - OUTREG8(VGA_SEQ_DATA, INREG8(VGA_SEQ_DATA) & ~0x02); - sr30 = INREG8(VGA_SEQ_DATA); - if (sr30 & 0x02 /*0x04 */) { - bDvi = true; - TRACE(("Digital Flat Panel Detected\n")); - } - } - - if (S3_SAVAGE_MOBILE_SERIES(si->chipset) || S3_MOBILE_TWISTER_SERIES(si->chipset)) { - si->displayType = MT_LCD; - SavageGetPanelInfo(); - } - else if (bDvi) - si->displayType = MT_DFP; - else - si->displayType = MT_CRT; - - TRACE(("Display Type: %d\n", si->displayType)); - - // Set max pixel clocks for the various color depths. - - si->pix_clk_max8 = 250000; - si->pix_clk_max16 = 250000; - si->pix_clk_max32 = 220000; - - /* detect current mclk */ - - OUTREG8(VGA_SEQ_INDEX, 0x08); - sr8 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_DATA, 0x06); - OUTREG8(VGA_SEQ_INDEX, 0x10); - n = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x11); - m = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x08); - OUTREG8(VGA_SEQ_DATA, sr8); - m &= 0x7f; - n1 = n & 0x1f; - n2 = (n >> 5) & 0x03; - si->mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; - - TRACE(("Detected current MCLK value of %1.3f MHz\n", si->mclk / 1000.0)); - - // Set the wait functions to be used for the current chip type. - - switch (si->chipset) { - case S3_SAVAGE3D: - case S3_SAVAGE_MX: - si->WaitQueue = WaitQueue3D; - si->WaitIdleEmpty = WaitIdleEmpty3D; - break; - - case S3_SAVAGE4: - case S3_PROSAVAGE: - case S3_SUPERSAVAGE: - case S3_PROSAVAGEDDR: - case S3_TWISTER: - si->WaitQueue = WaitQueue4; - si->WaitIdleEmpty = WaitIdleEmpty4; - break; - - case S3_SAVAGE2000: - si->WaitQueue = WaitQueue2K; - si->WaitIdleEmpty = WaitIdleEmpty2K; - break; - } - - return true; -} - - -void -SavageAdjustFrame(int x, int y) -{ - int address; - - TRACE(("SavageAdjustFrame(%d,%d)\n", x, y)); - - x &= ~0x3F; - address = (y * si->fbc.bytes_per_row) + (x * (si->bitsPerPixel >> 3)); - address &= ~0x1F; - - address += si->frameBufferOffset; - - /* - * because we align the viewport to the width and height of one tile - * we should update the location of frame - */ - si->frameX0 = x; - si->frameY0 = y; - - if (si->chipset == S3_SAVAGE_MX) { - OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC); - OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC); - } - else if (si->chipset == S3_SUPERSAVAGE) { - OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000); - OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8); - } - else if (si->chipset == S3_SAVAGE2000) { - /* certain Y values seems to cause havoc, not sure why */ - OUTREG32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8)); - OUTREG32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8)); - } else { - OUTREG32(PRI_STREAM_FBUF_ADDR0, address | 0xFFFFFFFC); - OUTREG32(PRI_STREAM_FBUF_ADDR1, address | 0x80000000); - } - - return; -} - - -static void -SavageGEReset(DisplayMode* pMode) -{ - uint8 cr66; - int r; - - TRACE(("SavageGEReset begin\n")); - - si->WaitIdleEmpty(); - - OUTREG8(VGA_CRTC_INDEX, 0x66); - cr66 = INREG8(VGA_CRTC_DATA); - - snooze(10000); - - for (r = 1; r < 10; r++) { - bool bSuccess = false; - - OUTREG8(VGA_CRTC_DATA, cr66 | 0x02); - snooze(10000); - OUTREG8(VGA_CRTC_DATA, cr66 & ~0x02); - snooze(10000); - - si->WaitIdleEmpty(); - - OUTREG(DEST_SRC_STR, pMode->bytesPerRow << 16 | pMode->bytesPerRow); - - snooze(10000); - switch (si->chipset) { - case S3_SAVAGE3D: - case S3_SAVAGE_MX: - bSuccess = (STATUS_WORD0 & 0x0008ffff) == 0x00080000; - break; - - case S3_SAVAGE4: - case S3_PROSAVAGE: - case S3_PROSAVAGEDDR: - case S3_TWISTER: - case S3_SUPERSAVAGE: - bSuccess = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000; - break; - - case S3_SAVAGE2000: - bSuccess = (ALT_STATUS_WORD0 & 0x008fffff) == 0; - break; - } - - if (bSuccess) - break; - - snooze(10000); - TRACE(("Restarting S3 graphics engine reset %2d ...\n", r)); - } - - /* At this point, the FIFO is empty and the engine is idle. */ - - OUTREG(SRC_BASE, 0); - OUTREG(DEST_BASE, 0); - OUTREG(CLIP_L_R, ((0) << 16) | pMode->timing.h_display); - OUTREG(CLIP_T_B, ((0) << 16) | pMode->timing.v_display); - OUTREG(MONO_PAT_0, ~0); - OUTREG(MONO_PAT_1, ~0); - - SavageSetGBD(pMode); - - TRACE(("SavageGEReset end\n")); -} - - -static void -SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, - int min_n2, int max_n2, long freq_min, - long freq_max, unsigned int *mdiv, - unsigned int *ndiv, unsigned int *r) -{ - double ffreq, ffreq_min, ffreq_max; - double div, diff, best_diff; - int m; - unsigned char n1, n2, best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2; - - ffreq = freq / 1000.0 / BASE_FREQ; - ffreq_max = freq_max / 1000.0 / BASE_FREQ; - ffreq_min = freq_min / 1000.0 / BASE_FREQ; - - if (ffreq < ffreq_min / (1 << max_n2)) { - TRACE(("SavageCalcClock invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ)); - ffreq = ffreq_min / (1 << max_n2); - } - if (ffreq > ffreq_max / (1 << min_n2)) { - TRACE(("SavageCalcClock invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ)); - ffreq = ffreq_max / (1 << min_n2); - } - - /* work out suitable timings */ - - best_diff = ffreq; - - for (n2 = min_n2; n2 <= max_n2; n2++) { - for (n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { - m = (int)(ffreq * n1 * (1 << n2) + 0.5); - if (m < min_m + 2 || m > 127 + 2) - continue; - - div = (double)(m) / (double)(n1); - if ((div >= ffreq_min) && (div <= ffreq_max)) { - diff = ffreq - div / (1 << n2); - if (diff < 0.0) - diff = -diff; - if (diff < best_diff) { - best_diff = diff; - best_m = m; - best_n1 = n1; - best_n2 = n2; - } - } - } - } - - *ndiv = best_n1 - 2; - *r = best_n2; - *mdiv = best_m - 2; -} - - - -static void -SavageSave(SavageRegRec* pRegRec) -{ - unsigned char cr3a, cr53, cr66; - - TRACE(("SavageSave()\n")); - - OUTREG16(VGA_CRTC_INDEX, 0x4838); - OUTREG16(VGA_CRTC_INDEX, 0xa039); - OUTREG16(VGA_SEQ_INDEX, 0x0608); - - OUTREG8(VGA_CRTC_INDEX, 0x66); - cr66 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr66 | 0x80); - - OUTREG8(VGA_CRTC_INDEX, 0x3a); - cr3a = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr3a | 0x80); - - OUTREG8(VGA_CRTC_INDEX, 0x53); - cr53 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr53 & 0x7f); - - - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, cr66); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - OUTREG8(VGA_CRTC_DATA, cr3a); - - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, cr66); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - OUTREG8(VGA_CRTC_DATA, cr3a); - - /* unlock extended seq regs */ - OUTREG8(VGA_SEQ_INDEX, 0x08); - pRegRec->SR08 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_DATA, 0x06); - - /* now save all the extended regs we need */ - OUTREG8(VGA_CRTC_INDEX, 0x31); - pRegRec->CR31 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x32); - pRegRec->CR32 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x34); - pRegRec->CR34 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x36); - pRegRec->CR36 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - pRegRec->CR3A = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x40); - pRegRec->CR40 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x42); - pRegRec->CR42 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x45); - pRegRec->CR45 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x50); - pRegRec->CR50 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x51); - pRegRec->CR51 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x53); - pRegRec->CR53 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x58); - pRegRec->CR58 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x60); - pRegRec->CR60 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x66); - pRegRec->CR66 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x67); - pRegRec->CR67 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x68); - pRegRec->CR68 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x69); - pRegRec->CR69 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x6f); - pRegRec->CR6F = INREG8(VGA_CRTC_DATA); - - OUTREG8(VGA_CRTC_INDEX, 0x33); - pRegRec->CR33 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x86); - pRegRec->CR86 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x88); - pRegRec->CR88 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x90); - pRegRec->CR90 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x91); - pRegRec->CR91 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0xb0); - pRegRec->CRB0 = INREG8(VGA_CRTC_DATA) | 0x80; - - /* extended mode timing regs */ - OUTREG8(VGA_CRTC_INDEX, 0x3b); - pRegRec->CR3B = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x3c); - pRegRec->CR3C = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x43); - pRegRec->CR43 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x5d); - pRegRec->CR5D = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x5e); - pRegRec->CR5E = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x65); - pRegRec->CR65 = INREG8(VGA_CRTC_DATA); - - /* save seq extended regs for DCLK PLL programming */ - OUTREG8(VGA_SEQ_INDEX, 0x0e); - pRegRec->SR0E = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x0f); - pRegRec->SR0F = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x10); - pRegRec->SR10 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x11); - pRegRec->SR11 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x12); - pRegRec->SR12 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x13); - pRegRec->SR13 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x29); - pRegRec->SR29 = INREG8(VGA_SEQ_DATA); - - OUTREG8(VGA_SEQ_INDEX, 0x15); - pRegRec->SR15 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x30); - pRegRec->SR30 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x18); - pRegRec->SR18 = INREG8(VGA_SEQ_DATA); - OUTREG8(VGA_SEQ_INDEX, 0x1b); - pRegRec->SR1B = INREG8(VGA_SEQ_DATA); - - /* Save flat panel expansion registers. */ - - if (S3_SAVAGE_MOBILE_SERIES(si->chipset) || S3_MOBILE_TWISTER_SERIES(si->chipset)) { - int i; - for (i = 0; i < 8; i++) { - OUTREG8(VGA_SEQ_INDEX, 0x54 + i); - pRegRec->SR54[i] = INREG8(VGA_SEQ_DATA); - } - } - - OUTREG8(VGA_CRTC_INDEX, 0x66); - cr66 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr66 | 0x80); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - cr3a = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr3a | 0x80); - - /* now save MIU regs */ - if (!S3_SAVAGE_MOBILE_SERIES(si->chipset)) { - pRegRec->MMPR0 = INREG(FIFO_CONTROL_REG); - pRegRec->MMPR1 = INREG(MIU_CONTROL_REG); - pRegRec->MMPR2 = INREG(STREAMS_TIMEOUT_REG); - pRegRec->MMPR3 = INREG(MISC_TIMEOUT_REG); - } - - OUTREG8(VGA_CRTC_INDEX, 0x3a); - OUTREG8(VGA_CRTC_DATA, cr3a); - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, cr66); - - return; -} - - -static void -SavageWriteMode(DisplayMode* pMode, SavageRegRec* pRegRec) -{ - uint8 temp, cr3a, cr66; - int j; - - TRACE(("SavageWriteMode\n")); - - si->WaitIdleEmpty(); - - if (!S3_SAVAGE_MOBILE_SERIES(si->chipset)) - SavageInitialize2DEngine(pMode); - - OUTREG8(VGA_MISC_OUT_W, 0x23); - - OUTREG16(VGA_CRTC_INDEX, 0x4838); - OUTREG16(VGA_CRTC_INDEX, 0xa039); - OUTREG16(VGA_SEQ_INDEX, 0x0608); - - /* reset GE to make sure nothing is going on */ - OUTREG8(VGA_CRTC_INDEX, 0x66); - if (INREG8(VGA_CRTC_DATA) & 0x01) - SavageGEReset(pMode); - - /* - * Some Savage/MX and /IX systems go nuts when trying to exit the - * server after WindowMaker has displayed a gradient background. I - * haven't been able to find what causes it, but a non-destructive - * switch to mode 3 here seems to eliminate the issue. - */ - - OUTREG8(VGA_CRTC_INDEX, 0x67); - (void) INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR67 & ~0x0e); /* no STREAMS yet old and new */ - - /* restore extended regs */ - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR66); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR3A); - OUTREG8(VGA_CRTC_INDEX, 0x31); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR31); - OUTREG8(VGA_CRTC_INDEX, 0x32); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR32); - OUTREG8(VGA_CRTC_INDEX, 0x58); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR58); - OUTREG8(VGA_CRTC_INDEX, 0x53); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR53 & 0x7f); - - OUTREG16(VGA_SEQ_INDEX, 0x0608); - - /* Restore DCLK registers. */ - - OUTREG8(VGA_SEQ_INDEX, 0x0e); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR0E); - OUTREG8(VGA_SEQ_INDEX, 0x0f); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR0F); - OUTREG8(VGA_SEQ_INDEX, 0x29); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR29); - OUTREG8(VGA_SEQ_INDEX, 0x15); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR15); - - /* Restore flat panel expansion registers. */ - - if (S3_SAVAGE_MOBILE_SERIES(si->chipset) || S3_MOBILE_TWISTER_SERIES(si->chipset)) { - int i; - for ( i = 0; i < 8; i++ ) { - OUTREG8(VGA_SEQ_INDEX, 0x54 + i); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR54[i]); - } - } - - /* Set the standard CRTC vga regs */ - - WriteCrtc(17, pRegRec->CRTC[17] & 0x7f); // unlock CRTC reg's 0-7 by clearing bit 7 of CRTC[17] - - for (j = 0; j < NUM_ELEMENTS(pRegRec->CRTC); j++) - WriteCrtc(j, pRegRec->CRTC[j]); - - /* setup HSYNC & VSYNC polarity */ - - temp = ((INREG8(VGA_MISC_OUT_R) & 0x3f) | 0x0c); - - if (!(pMode->timing.flags & B_POSITIVE_HSYNC)) - temp |= 0x40; - if (!(pMode->timing.flags & B_POSITIVE_VSYNC)) - temp |= 0x80; - - OUTREG8(VGA_MISC_OUT_W, temp); - - - /* extended mode timing registers */ - OUTREG8(VGA_CRTC_INDEX, 0x53); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR53); - OUTREG8(VGA_CRTC_INDEX, 0x5d); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR5D); - OUTREG8(VGA_CRTC_INDEX, 0x5e); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR5E); - OUTREG8(VGA_CRTC_INDEX, 0x3b); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR3B); - OUTREG8(VGA_CRTC_INDEX, 0x3c); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR3C); - OUTREG8(VGA_CRTC_INDEX, 0x43); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR43); - OUTREG8(VGA_CRTC_INDEX, 0x65); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR65); - - /* restore the desired video mode with cr67 */ - OUTREG8(VGA_CRTC_INDEX, 0x67); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR67 & ~0x0e); /* no streams for new and old streams engines */ - - /* other mode timing and extended regs */ - OUTREG8(VGA_CRTC_INDEX, 0x34); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR34); - OUTREG8(VGA_CRTC_INDEX, 0x40); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR40); - OUTREG8(VGA_CRTC_INDEX, 0x42); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR42); - OUTREG8(VGA_CRTC_INDEX, 0x45); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR45); - OUTREG8(VGA_CRTC_INDEX, 0x50); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR50); - OUTREG8(VGA_CRTC_INDEX, 0x51); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR51); - - /* memory timings */ - OUTREG8(VGA_CRTC_INDEX, 0x36); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR36); - OUTREG8(VGA_CRTC_INDEX, 0x60); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR60); - OUTREG8(VGA_CRTC_INDEX, 0x68); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR68); - VerticalRetraceWait(); - OUTREG8(VGA_CRTC_INDEX, 0x69); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR69); - OUTREG8(VGA_CRTC_INDEX, 0x6f); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR6F); - - OUTREG8(VGA_CRTC_INDEX, 0x33); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR33); - OUTREG8(VGA_CRTC_INDEX, 0x86); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR86); - OUTREG8(VGA_CRTC_INDEX, 0x88); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR88); - OUTREG8(VGA_CRTC_INDEX, 0x90); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR90); - OUTREG8(VGA_CRTC_INDEX, 0x91); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR91); - - if (si->chipset == S3_SAVAGE4) { - OUTREG8(VGA_CRTC_INDEX, 0xb0); - OUTREG8(VGA_CRTC_DATA, pRegRec->CRB0); - } - - OUTREG8(VGA_CRTC_INDEX, 0x32); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR32); - - /* unlock extended seq regs */ - OUTREG8(VGA_SEQ_INDEX, 0x08); - OUTREG8(VGA_SEQ_DATA, 0x06); - - /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that - * we should leave the default SR10 and SR11 values there. - */ - - if (pRegRec->SR10 != 255) { - OUTREG8(VGA_SEQ_INDEX, 0x10); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR10); - OUTREG8(VGA_SEQ_INDEX, 0x11); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR11); - } - - /* restore extended seq regs for dclk */ - OUTREG8(VGA_SEQ_INDEX, 0x0e); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR0E); - OUTREG8(VGA_SEQ_INDEX, 0x0f); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR0F); - OUTREG8(VGA_SEQ_INDEX, 0x12); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR12); - OUTREG8(VGA_SEQ_INDEX, 0x13); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR13); - OUTREG8(VGA_SEQ_INDEX, 0x29); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR29); - - OUTREG8(VGA_SEQ_INDEX, 0x18); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR18); - OUTREG8(VGA_SEQ_INDEX, 0x1b); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR1B); - - /* load new m, n pll values for dclk & mclk */ - OUTREG8(VGA_SEQ_INDEX, 0x15); - temp = INREG8(VGA_SEQ_DATA) & ~0x21; - - OUTREG8(VGA_SEQ_DATA, temp | 0x03); - OUTREG8(VGA_SEQ_DATA, temp | 0x23); - OUTREG8(VGA_SEQ_DATA, temp | 0x03); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR15); - snooze( 100 ); - - OUTREG8(VGA_SEQ_INDEX, 0x30); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR30); - OUTREG8(VGA_SEQ_INDEX, 0x08); - OUTREG8(VGA_SEQ_DATA, pRegRec->SR08); - - /* now write out cr67 in full, possibly starting STREAMS */ - VerticalRetraceWait(); - OUTREG8(VGA_CRTC_INDEX, 0x67); - OUTREG8(VGA_CRTC_DATA, pRegRec->CR67); - - OUTREG8(VGA_CRTC_INDEX, 0x66); - cr66 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr66 | 0x80); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - cr3a = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_DATA, cr3a | 0x80); - - SavageGEReset(pMode); - - if (!S3_SAVAGE_MOBILE_SERIES(si->chipset)) { - VerticalRetraceWait(); - OUTREG(FIFO_CONTROL_REG, pRegRec->MMPR0); - OUTREG(MIU_CONTROL_REG, pRegRec->MMPR1); - OUTREG(STREAMS_TIMEOUT_REG, pRegRec->MMPR2); - OUTREG(MISC_TIMEOUT_REG, pRegRec->MMPR3); - } - - /* If we're going into graphics mode and acceleration was enabled, */ - /* go set up the BCI buffer and the global bitmap descriptor. */ - - OUTREG8(VGA_CRTC_INDEX, 0x66); - OUTREG8(VGA_CRTC_DATA, cr66); - OUTREG8(VGA_CRTC_INDEX, 0x3a); - OUTREG8(VGA_CRTC_DATA, cr3a); - - SavageInitialize2DEngine(pMode); - - OUTREG16(VGA_CRTC_INDEX, 0x0140); - - SavageSetGBD(pMode); - - TRACE(("SavageWriteMode end\n")); - - return; -} - - -bool -SavageModeInit(DisplayMode* pMode) -{ - int width, dclk, i, j; - unsigned int m, n, r; - uint8 temp = 0; - SavageRegRec regRec; - - InitCrtcTimingValues(pMode, ®Rec); - SavageSave(®Rec); - - TRACE(("SavageModeInit(%dx%d, %dHz)\n", - pMode->timing.h_display, pMode->timing.v_display, pMode->timing.pixel_clock)); - - /* We need to set CR67 whether or not we use the BIOS. */ - - dclk = pMode->timing.pixel_clock; - regRec.CR67 = 0x00; - - switch (pMode->bpp) { - case 8: - if ((si->chipset == S3_SAVAGE2000) && (dclk >= 230000)) - regRec.CR67 = 0x10; /* 8bpp, 2 pixels/clock */ - else - regRec.CR67 = 0x00; /* 8bpp, 1 pixel/clock */ - break; - - case 15: - if (S3_SAVAGE_MOBILE_SERIES(si->chipset) - || ((si->chipset == S3_SAVAGE2000) && (dclk >= 230000))) - regRec.CR67 = 0x30; /* 15bpp, 2 pixel/clock */ - else - regRec.CR67 = 0x20; /* 15bpp, 1 pixels/clock */ - break; - - case 16: - if (S3_SAVAGE_MOBILE_SERIES(si->chipset) - || ((si->chipset == S3_SAVAGE2000) && (dclk >= 230000))) - regRec.CR67 = 0x50; /* 16bpp, 2 pixel/clock */ - else - regRec.CR67 = 0x40; /* 16bpp, 1 pixels/clock */ - break; - - case 24: - regRec.CR67 = 0x70; - break; - - case 32: - regRec.CR67 = 0xd0; - break; - } - - - // Use traditional register-crunching to set mode. - - OUTREG8(VGA_CRTC_INDEX, 0x3a); - temp = INREG8(VGA_CRTC_DATA); - if (true /*psav->pci_burst*/) - regRec.CR3A = (temp & 0x7f) | 0x15; - else - regRec.CR3A = temp | 0x95; - - regRec.CR53 = 0x00; - regRec.CR31 = 0x8c; - regRec.CR66 = 0x89; - - OUTREG8(VGA_CRTC_INDEX, 0x58); - regRec.CR58 = INREG8(VGA_CRTC_DATA) & 0x80; - regRec.CR58 |= 0x13; - - regRec.SR15 = 0x03 | 0x80; - regRec.SR18 = 0x00; - - /* set 8-bit CLUT */ - regRec.SR1B |= 0x10; - - regRec.CR43 = regRec.CR45 = regRec.CR65 = 0x00; - - OUTREG8(VGA_CRTC_INDEX, 0x40); - regRec.CR40 = INREG8(VGA_CRTC_DATA) & ~0x01; - - regRec.MMPR0 = 0x010400; - regRec.MMPR1 = 0x00; - regRec.MMPR2 = 0x0808; - regRec.MMPR3 = 0x08080810; - - if (si->mclk <= 0) { - regRec.SR10 = 255; - regRec.SR11 = 255; - } - - SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); - regRec.SR12 = (r << 6) | (n & 0x3f); - regRec.SR13 = m & 0xff; - regRec.SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; - - TRACE(("CalcClock, m: %d n: %d r: %d\n", m, n, r)); - - if (pMode->bpp < 24) - regRec.MMPR0 -= 0x8000; - else - regRec.MMPR0 -= 0x4000; - - regRec.CR42 = 0x00; - regRec.CR34 = 0x10; - - i = ((((pMode->timing.h_total >> 3) - 5) & 0x100) >> 8) | - ((((pMode->timing.h_display >> 3) - 1) & 0x100) >> 7) | - ((((pMode->timing.h_sync_start >> 3) - 1) & 0x100) >> 6) | - ((pMode->timing.h_sync_start & 0x800) >> 7); - - if ((pMode->timing.h_sync_end >> 3) - (pMode->timing.h_sync_start >> 3) > 64) - i |= 0x08; - if ((pMode->timing.h_sync_end >> 3) - (pMode->timing.h_sync_start >> 3) > 32) - i |= 0x20; - - j = (regRec.CRTC[0] + ((i & 0x01) << 8) + regRec.CRTC[4] + ((i & 0x10) << 4) + 1) / 2; - - if (j - (regRec.CRTC[4] + ((i & 0x10) << 4)) < 4) { - if (regRec.CRTC[4] + ((i & 0x10) << 4) + 4 <= regRec.CRTC[0] + ((i & 0x01) << 8)) - j = regRec.CRTC[4] + ((i & 0x10) << 4) + 4; - else - j = regRec.CRTC[0] + ((i & 0x01) << 8) + 1; - } - - regRec.CR3B = j & 0xff; - i |= (j & 0x100) >> 2; - regRec.CR3C = (regRec.CRTC[0] + ((i & 0x01) << 8)) / 2 ; - regRec.CR5D = i; - regRec.CR5E = (((pMode->timing.v_total - 2) & 0x400) >> 10) | - (((pMode->timing.v_display - 1) & 0x400) >> 9) | - (((pMode->timing.v_sync_start) & 0x400) >> 8) | - (((pMode->timing.v_sync_start) & 0x400) >> 6) | 0x40; - width = pMode->bytesPerRow >> 3; - regRec.CR91 = 0xff & width; - regRec.CR51 = (0x300 & width) >> 4; - regRec.CR90 = 0x80 | (width >> 8); - - /* Set frame buffer description. */ - - if (pMode->bpp <= 8) - regRec.CR50 = 0; - else if (pMode->bpp <= 16) - regRec.CR50 = 0x10; - else - regRec.CR50 = 0x30; - - if (pMode->width == 640) - regRec.CR50 |= 0x40; - else if (pMode->width == 800) - regRec.CR50 |= 0x80; - else if (pMode->width == 1024) - regRec.CR50 |= 0x00; - else if (pMode->width == 1152) - regRec.CR50 |= 0x01; - else if (pMode->width == 1280) - regRec.CR50 |= 0xc0; - else if (pMode->width == 1600) - regRec.CR50 |= 0x81; - else - regRec.CR50 |= 0xc1; /* Use GBD */ - - if (S3_SAVAGE_MOBILE_SERIES(si->chipset)) - regRec.CR33 = 0x00; - else - regRec.CR33 = 0x08; - - regRec.CR67 |= 1; - - OUTREG8(VGA_CRTC_INDEX, 0x36); - regRec.CR36 = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x68); - regRec.CR68 = INREG8(VGA_CRTC_DATA); - - regRec.CR69 = 0; - OUTREG8(VGA_CRTC_INDEX, 0x6f); - regRec.CR6F = INREG8(VGA_CRTC_DATA); - OUTREG8(VGA_CRTC_INDEX, 0x86); - regRec.CR86 = INREG8(VGA_CRTC_DATA) | 0x08; - OUTREG8(VGA_CRTC_INDEX, 0x88); - regRec.CR88 = INREG8(VGA_CRTC_DATA) | DISABLE_BLOCK_WRITE_2D; - OUTREG8(VGA_CRTC_INDEX, 0xb0); - regRec.CRB0 = INREG8(VGA_CRTC_DATA) | 0x80; - - /* do it! */ - SavageWriteMode(pMode, ®Rec); - - return true; -} - diff --git a/src/add-ons/kernel/drivers/graphics/Jamfile b/src/add-ons/kernel/drivers/graphics/Jamfile index 2e7aa628ff..0d970ad452 100644 --- a/src/add-ons/kernel/drivers/graphics/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/Jamfile @@ -7,7 +7,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon ; -SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3savage ; +SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3 ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics tdfx ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics vesa ; diff --git a/src/add-ons/kernel/drivers/graphics/s3/Jamfile b/src/add-ons/kernel/drivers/graphics/s3/Jamfile new file mode 100644 index 0000000000..c206713c88 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/s3/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src add-ons kernel drivers graphics s3 ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders [ FDirName graphics s3 ] ; +UsePrivateHeaders [ FDirName graphics common ] ; +UsePrivateHeaders graphics kernel ; + +KernelAddon s3 : + driver.cpp +; + +Package haiku-s3-cvs : + s3 : + boot home config add-ons kernel drivers bin ; +PackageDriverSymLink haiku-s3-cvs : graphics s3 ; diff --git a/src/add-ons/kernel/drivers/graphics/s3/driver.cpp b/src/add-ons/kernel/drivers/graphics/s3/driver.cpp new file mode 100644 index 0000000000..3c890bc060 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/s3/driver.cpp @@ -0,0 +1,799 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Gerald Zajac 2007-2008 +*/ + +#include +#include +#include +#include +#include +#include + +#include "DriverInterface.h" + + +#undef TRACE + +#ifdef ENABLE_DEBUG_TRACE +# define TRACE(x...) dprintf("S3: " x) +#else +# define TRACE(x...) ; +#endif + + +#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) +#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v)) + +#define SKD_HANDLER_INSTALLED 0x80000000 +#define MAX_DEVICES 8 +#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" + +int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support + + +struct ChipInfo { + uint16 chipID; // PCI device id of the chip + uint16 chipType; // assigned chip type identifier + char* chipName; // user recognizable name for chip (must be < 32 chars) +}; + +// This table maps a PCI device ID to a chip type identifier and the chip name. +// Note that the Trio64 and Trio64V+ chips have the same ID, but have a different +// revision number. After the revision number is examined, the Trio64V+ will +// have a different chip type code and name assigned. + +static const ChipInfo S3_ChipTable[] = { + { 0x8811, S3_TRIO64, "Trio64" }, // see comment above + { 0x8814, S3_TRIO64_UVP, "Trio64 UV+" }, + { 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" }, + + { 0x5631, S3_VIRGE, "Virge" }, + { 0x883D, S3_VIRGE_VX, "Virge VX" }, + { 0x8A01, S3_VIRGE_DXGX, "Virge DX/GX" }, + { 0x8A10, S3_VIRGE_GX2, "Virge GX2" }, + { 0x8C01, S3_VIRGE_MX, "Virge MX" }, + { 0x8C03, S3_VIRGE_MXP, "Virge MX+" }, + { 0x8904, S3_TRIO_3D, "Trio 3D" }, + { 0x8A13, S3_TRIO_3D_2X, "Trio 3D/2X" }, + + { 0x8a20, S3_SAVAGE_3D, "Savage3D" }, + { 0x8a21, S3_SAVAGE_3D, "Savage3D-MV" }, + { 0x8a22, S3_SAVAGE4, "Savage4" }, + { 0x8a25, S3_PROSAVAGE, "ProSavage PM133" }, + { 0x8a26, S3_PROSAVAGE, "ProSavage KM133" }, + { 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" }, + { 0x8c11, S3_SAVAGE_MX, "Savage/MX" }, + { 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" }, + { 0x8c13, S3_SAVAGE_MX, "Savage/IX" }, + { 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" }, + { 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" }, + { 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" }, + { 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" }, + { 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" }, + { 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" }, + { 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" }, + { 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" }, + { 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" }, + { 0x8d01, S3_TWISTER, "Twister PN133" }, + { 0x8d02, S3_TWISTER, "Twister KN133" }, + { 0x8d03, S3_PROSAVAGE_DDR, "ProSavage DDR" }, + { 0x8d04, S3_PROSAVAGE_DDR, "ProSavage DDR-K" }, + { 0x9102, S3_SAVAGE2000, "Savage2000" }, + { 0, 0, NULL } +}; + + +#define VENDOR_ID 0x5333 // S3 vendor ID + +static struct { + uint16 vendorID; + const ChipInfo* devices; +} SupportedDevices[] = { + { VENDOR_ID, S3_ChipTable }, + { 0x0000, NULL } +}; + + +struct DeviceInfo { + uint32 openCount; // count of how many times device has been opened + int32 flags; + area_id sharedArea; // area shared between driver and all accelerants + SharedInfo* si; // pointer to the shared area + vuint8* regs; // kernel's pointer to memory mapped registers + const ChipInfo* pChipInfo; // info about the selected chip + pci_info pcii; // copy of pci info for this device + char name[B_OS_NAME_LENGTH]; // name of device +}; + + +struct DeviceData { + uint32 count; // number of devices actually found + benaphore kernel; // for serializing opens/closes + char* deviceNames[MAX_DEVICES + 1]; // device name pointer storage + DeviceInfo di[MAX_DEVICES]; // device specific stuff +}; + + +// Prototypes for our private functions. + +static status_t open_hook (const char* name, uint32 flags, void** cookie); +static status_t close_hook (void* dev); +static status_t free_hook (void* dev); +static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len); +static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len); +static status_t control_hook (void* dev, uint32 msg, void* buf, size_t len); +static status_t map_device(DeviceInfo* di); +static void unmap_device(DeviceInfo* di); +static void probe_devices(void); +static int32 s3_interrupt(void* data); + +static DeviceData* pd; +static pci_module_info* pci_bus; +static device_hooks graphics_device_hooks = +{ + open_hook, + close_hook, + free_hook, + control_hook, + read_hook, + write_hook, + NULL, + NULL, + NULL, + NULL +}; + + + +// Functions for dealing with Vertical Blanking Interrupts. Currently, I do +// not know the commands to handle these operations; thus, these functions +// currently do nothing. + +static bool +InterruptIsVBI() +{ + // return true only if a vertical blanking interrupt has occured + return false; +} + + +static void +ClearVBI() +{ +} + +static void +EnableVBI() +{ +} + +static void +DisableVBI() +{ +} + + + +static const ChipInfo* +FindDeviceMatch(uint16 vendorID, uint16 deviceID) +{ + // Search the table of supported devices to find a chip/device that + // matches the vendor ID and device ID passed by the caller. + // Return pointer to the struct containing the chip info if match + // is found; else return NULL. + + int vendor = 0; + + while (SupportedDevices[vendor].vendorID != 0) { // end of table? + if (SupportedDevices[vendor].vendorID == vendorID) { + const ChipInfo* pDevice = SupportedDevices[vendor].devices; + + while (pDevice->chipID != 0) { // end of table? + if (pDevice->chipID == deviceID) + return pDevice; // matching device/chip found + + pDevice++; + } + } + vendor++; + } + + return NULL; // no match found +} + + +status_t +init_hardware(void) +{ + // Return B_OK if a device supported by this driver is found; otherwise, + // return B_ERROR so the driver will be unloaded. + + long pci_index = 0; + pci_info pcii; + const ChipInfo* pDevice = NULL; + + if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) + return B_ERROR; // unable to access PCI bus + + // Check all pci devices for a device supported by this driver. + + while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) { + pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id); + if (pDevice != NULL) + break; + + pci_index++; + } + + TRACE("init_hardware() - %s\n", pDevice == NULL ? "no supported devices" : "device supported"); + + put_module(B_PCI_MODULE_NAME); // put away the module manager + return (pDevice == NULL ? B_ERROR : B_OK); +} + + +status_t init_driver(void) +{ + // Get handle for the pci bus. + + if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) + return B_ERROR; + + pd = (DeviceData*)calloc(1, sizeof(DeviceData)); + if (NULL == pd) { + put_module(B_PCI_MODULE_NAME); + return B_ERROR; + } + + INIT_BEN(pd->kernel); // initialize the benaphore + probe_devices(); // find all devices supported by this driver + + return B_OK; +} + + +const char** +publish_devices(void) +{ + return (const char**)pd->deviceNames; // return list of supported devices +} + + +device_hooks* +find_device(const char* name) +{ + int index = 0; + while (pd->deviceNames[index]) { + if (strcmp(name, pd->deviceNames[index]) == 0) + return &graphics_device_hooks; + index++; + } + return NULL; +} + + +void + uninit_driver(void) +{ + // Free the driver data. + + DELETE_BEN(pd->kernel); + free(pd); + pd = NULL; + + put_module(B_PCI_MODULE_NAME); // put the pci module away +} + + +static status_t +map_device(DeviceInfo* di) +{ + char areaName[B_OS_NAME_LENGTH]; + SharedInfo* si = di->si; + pci_info* pcii = &(di->pcii); + + TRACE("enter map_device()\n"); + + // enable memory mapped IO and VGA I/O + + uint32 tmpUlong = get_pci(PCI_command, 2); + tmpUlong |= PCI_command_io | PCI_command_memory | PCI_command_master; + set_pci(PCI_command, 2, tmpUlong); + + const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB + const uint32 SavageMmioRegBaseNew = 0x0000000; + const uint32 SavageMmioRegSize = 0x0080000; // 512 KB reg area size + + const uint32 VirgeMmioRegBase = 0x1000000; // 16 MB + const uint32 VirgeMmioRegSize = 0x10000; // 64 KB reg area size + + uint32 videoRamAddr = 0; + uint32 videoRamSize = 0; + uint32 regsBase = 0; + uint32 regAreaSize = 0; + + // Since we do not know at this point the actual size of the video + // memory, set it to the largest value that the respective chipset + // family can have. + + if (S3_SAVAGE_FAMILY(di->pChipInfo->chipType)) { + if (S3_SAVAGE_3D_SERIES(di->pChipInfo->chipType)) { + // Savage 3D & Savage MX chips. + + regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseOld; + regAreaSize = SavageMmioRegSize; + + videoRamAddr = di->pcii.u.h0.base_registers[0]; + videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series + si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); + } else { + // All other Savage chips. + + regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseNew; + regAreaSize = SavageMmioRegSize; + + videoRamAddr = di->pcii.u.h0.base_registers[1]; + videoRamSize = di->pcii.u.h0.base_register_sizes[1]; + si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]); + } + } else { + // Trio/Virge chips. + + regsBase = di->pcii.u.h0.base_registers[0] + VirgeMmioRegBase; + regAreaSize = VirgeMmioRegSize; + + videoRamAddr = di->pcii.u.h0.base_registers[0]; + videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips + si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); + } + + // Map the MMIO register area. + + sprintf(areaName, DEVICE_FORMAT " regs", + di->pcii.vendor_id, di->pcii.device_id, + di->pcii.bus, di->pcii.device, di->pcii.function); + + si->regsArea = map_physical_memory(areaName, (void*)regsBase, regAreaSize, + B_ANY_KERNEL_ADDRESS, + 0, // neither read nor write, to hide it from user space apps + (void**)(&(di->regs))); + + if (si->regsArea < 0) + return si->regsArea; // return error code + + // Map the video memory. + + sprintf(areaName, DEVICE_FORMAT " framebuffer", + di->pcii.vendor_id, di->pcii.device_id, + di->pcii.bus, di->pcii.device, di->pcii.function); + + si->videoMemArea = map_physical_memory( + areaName, + (void*)videoRamAddr, + videoRamSize, + B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, + B_READ_AREA + B_WRITE_AREA, + &(si->videoMemAddr)); + + if (si->videoMemArea < 0) { + // Try to map this time without write combining. + si->videoMemArea = map_physical_memory( + areaName, + (void*)videoRamAddr, + videoRamSize, + B_ANY_KERNEL_BLOCK_ADDRESS, + B_READ_AREA + B_WRITE_AREA, + &(si->videoMemAddr)); + } + + TRACE("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si->videoMemArea, + (uint32)(si->videoMemAddr), videoRamSize); + + // If there was an error, delete other areas. + if (si->videoMemArea < 0) { + delete_area(si->regsArea); + si->regsArea = -1; + } + + TRACE("leave map_device(); result: %ld\n", si->videoMemArea); + return si->videoMemArea; +} + + +static void +unmap_device(DeviceInfo* di) +{ + SharedInfo* si = di->si; + pci_info* pcii = &(di->pcii); + + TRACE("enter unmap_device()\n"); + + // Disable memory mapped IO. + uint32 tmpUlong = get_pci(PCI_command, 2); + tmpUlong &= ~(PCI_command_io | PCI_command_memory); + set_pci(PCI_command, 2, tmpUlong); + + if (si->regsArea >= 0) + delete_area(si->regsArea); + if (si->videoMemArea >= 0) + delete_area(si->videoMemArea); + + si->regsArea = si->videoMemArea = -1; + si->videoMemAddr = NULL; + di->regs = NULL; + + TRACE("exit unmap_device()\n"); +} + + +static void +probe_devices(void) +{ + uint32 pci_index = 0; + uint32 count = 0; + DeviceInfo* di = pd->di; + const ChipInfo* pDevice; + + while ((count < MAX_DEVICES) + && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) { + + pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id); + if (pDevice != NULL) { + // Compose device name. + sprintf(di->name, "graphics/" DEVICE_FORMAT, + di->pcii.vendor_id, di->pcii.device_id, + di->pcii.bus, di->pcii.device, di->pcii.function); + TRACE("probe_devices() match found; name: %s\n", di->name); + + pd->deviceNames[count] = di->name; + di->openCount = 0; // mark driver as available for R/W open + di->sharedArea = -1; // indicate shared area not yet created + di->si = NULL; + di->pChipInfo = pDevice; + di++; + count++; + } + + pci_index++; + } + + pd->count = count; + pd->deviceNames[pd->count] = NULL; // terminate list with null pointer + + TRACE("probe_devices() %ld supported devices\n", pd->count); +} + + +static uint32 +thread_interrupt_work(DeviceInfo* di) +{ + SharedInfo* si = di->si; + uint32 handled = B_HANDLED_INTERRUPT; + + // Release vertical blanking semaphore. + if (si->vertBlankSem >= 0) { + int32 blocked; + if ((get_sem_count(si->vertBlankSem, &blocked) == B_OK) && (blocked < 0)) { + release_sem_etc(si->vertBlankSem, -blocked, B_DO_NOT_RESCHEDULE); + handled = B_INVOKE_SCHEDULER; + } + } + return handled; +} + + +static int32 +s3_interrupt(void* data) +{ + int32 handled = B_UNHANDLED_INTERRUPT; + DeviceInfo* di = (DeviceInfo*)data; + int32* flags = &(di->flags); + + // Is someone already handling an interrupt for this device? + if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) + return B_UNHANDLED_INTERRUPT; + + if (InterruptIsVBI()) { // was interrupt a VBI? + ClearVBI(); // clear interrupt + + handled = thread_interrupt_work(di); // release semaphore + } + + atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore + + return handled; +} + + +// #pragma mark - Device Hooks + + +static status_t +open_hook(const char* name, uint32 flags, void** cookie) +{ + int32 index = 0; + SharedInfo* si; + thread_id thid; + thread_info thinfo; + status_t result = B_OK; + char sharedName[B_OS_NAME_LENGTH]; + + (void)flags; // avoid compiler warning for unused arg + + TRACE("open_hook() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie); + + // Find the device name in the list of devices. + while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0)) + index++; + + DeviceInfo* di = &(pd->di[index]); + + // Make sure no one else has write access to the common data. + AQUIRE_BEN(pd->kernel); + + if (di->openCount > 0) + goto mark_as_open; + + // Create the area for shared info with NO user-space read or write permissions, + // to prevent accidental damage. + + sprintf(sharedName, DEVICE_FORMAT " shared", + di->pcii.vendor_id, di->pcii.device_id, + di->pcii.bus, di->pcii.device, di->pcii.function); + + di->sharedArea = create_area(sharedName, (void**) &(di->si), B_ANY_KERNEL_ADDRESS, + ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), + B_FULL_LOCK, 0); + if (di->sharedArea < 0) { + result = di->sharedArea; // return error + goto done; + } + + si = di->si; + + si->vendorID = di->pcii.vendor_id; + si->deviceID = di->pcii.device_id; + si->revision = di->pcii.revision; + si->chipType = di->pChipInfo->chipType; + strcpy(si->chipName, di->pChipInfo->chipName); + + // Trio64 and Trio64V+ chips have the same ID but different revision numbers. + // Since the Trio64V+ supports MMIO, better performance can be obtained + // from it if it is distinguished from the Trio64. + + if (si->chipType == S3_TRIO64 && si->revision & 0x40) { + si->chipType = S3_TRIO64_VP; + strcpy(si->chipName, "Trio64 V+"); + } + + + result = map_device(di); + if (result < 0) + goto free_shared; + + result = B_OK; + + DisableVBI(); // disable & clear any pending interrupts + si->bInterruptAssigned = false; // indicate interrupt not assigned yet + + // Create a semaphore for vertical blank management. + si->vertBlankSem = create_sem(0, di->name); + if (si->vertBlankSem < 0) + goto mark_as_open; + + // Change the owner of the semaphores to the opener's team. + // This is required because apps can't aquire kernel semaphores. + thid = find_thread(NULL); + get_thread_info(thid, &thinfo); + set_sem_owner(si->vertBlankSem, thinfo.team); + + // If there is a valid interrupt assigned, set up interrupts. + + if ((di->pcii.u.h0.interrupt_pin == 0x00) || + (di->pcii.u.h0.interrupt_line == 0xff) || // no IRQ assigned + (di->pcii.u.h0.interrupt_line <= 0x02)) { // system IRQ assigned + // Interrupt does not exist; thus delete semaphore as it won't be used. + delete_sem(si->vertBlankSem); + si->vertBlankSem = -1; + } else { + result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, (void*)di, 0); + if (result != B_OK) { + // Delete semaphore as it won't be used. + delete_sem(si->vertBlankSem); + si->vertBlankSem = -1; + } else { + // Inform accelerant(s) we can use interrupt related functions. + si->bInterruptAssigned = true; + } + } + +mark_as_open: + di->openCount++; // mark device open + *cookie = di; // send cookie to opener + goto done; + +free_shared: + delete_area(di->sharedArea); + di->sharedArea = -1; + di->si = NULL; + +done: + // End of critical section. + RELEASE_BEN(pd->kernel); + + TRACE("open_hook() returning 0x%08lx\n", result); + return result; +} + + +static status_t +read_hook(void* dev, off_t pos, void* buf, size_t* len) +{ + // Following 3 lines of code are here to eliminate "unused parameter" warnings. + (void)dev; + (void)pos; + (void)buf; + + *len = 0; + return B_NOT_ALLOWED; +} + + +static status_t +write_hook(void* dev, off_t pos, const void* buf, size_t* len) +{ + // Following 3 lines of code are here to eliminate "unused parameter" warnings. + (void)dev; + (void)pos; + (void)buf; + + *len = 0; + return B_NOT_ALLOWED; +} + + +static status_t +close_hook(void* dev) +{ + (void)dev; // avoid compiler warning for unused arg + + TRACE("close_hook()\n"); + return B_NO_ERROR; +} + + +static status_t +free_hook(void* dev) +{ + DeviceInfo* di = (DeviceInfo*)dev; + SharedInfo* si = di->si; + + TRACE("enter free_hook()\n"); + + AQUIRE_BEN(pd->kernel); // lock driver + + // If opened multiple times, decrement the open count and exit. + if (di->openCount > 1) + goto unlock_and_exit; + + DisableVBI(); // disable & clear any pending interrupts + + if (si->bInterruptAssigned) { + remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, di); + } + + // Delete the semaphores, ignoring any errors because the owning team may have died. + if (si->vertBlankSem >= 0) + delete_sem(si->vertBlankSem); + si->vertBlankSem = -1; + + unmap_device(di); // free regs and frame buffer areas + + delete_area(di->sharedArea); + di->sharedArea = -1; + di->si = NULL; + +unlock_and_exit: + if (di->openCount > 0) + di->openCount--; // mark device available + + RELEASE_BEN(pd->kernel); // unlock driver + + TRACE("exit free_hook()\n"); + return B_OK; +} + + +static status_t +control_hook(void* dev, uint32 msg, void* buf, size_t len) +{ + DeviceInfo* di = (DeviceInfo*)dev; + + (void)len; // avoid compiler warning for unused arg + + switch (msg) { + case B_GET_ACCELERANT_SIGNATURE: + strcpy((char*)buf, "s3.accelerant"); + return B_OK; + + case S3_DEVICE_NAME: + strncpy((char*)buf, di->name, B_OS_NAME_LENGTH); + ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0'; + return B_OK; + + case S3_GET_PRIVATE_DATA: + { + S3GetPrivateData* gpd = (S3GetPrivateData*)buf; + if (gpd->magic == S3_PRIVATE_DATA_MAGIC) { + gpd->sharedInfoArea = di->sharedArea; + return B_OK; + } + break; + } + + case S3_RUN_INTERRUPTS: + { + S3SetBoolState* ri = (S3SetBoolState*)buf; + if (ri->magic == S3_PRIVATE_DATA_MAGIC) { + if (ri->bEnable) + EnableVBI(); + else + DisableVBI(); + } + return B_OK; + } + + case S3_GET_PIO: + { + S3GetSetPIO* gsp = (S3GetSetPIO*)buf; + if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { + switch (gsp->size) { + case 1: + gsp->value = pci_bus->read_io_8(gsp->offset); + break; + case 2: + gsp->value = pci_bus->read_io_16(gsp->offset); + break; + case 4: + gsp->value = pci_bus->read_io_32(gsp->offset); + break; + default: + TRACE("control_hook() S3_GET_PIO invalid size: %ld\n", gsp->size); + return B_ERROR; + } + return B_OK; + } + break; + } + + case S3_SET_PIO: + { + S3GetSetPIO* gsp = (S3GetSetPIO*)buf; + if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { + switch (gsp->size) { + case 1: + pci_bus->write_io_8(gsp->offset, gsp->value); + break; + case 2: + pci_bus->write_io_16(gsp->offset, gsp->value); + break; + case 4: + pci_bus->write_io_32(gsp->offset, gsp->value); + break; + default: + TRACE("control_hook() S3_SET_PIO invalid size: %ld\n", gsp->size); + return B_ERROR; + } + return B_OK; + } + break; + } + } + + return B_DEV_INVALID_IOCTL; +} + diff --git a/src/add-ons/kernel/drivers/graphics/s3savage/Jamfile b/src/add-ons/kernel/drivers/graphics/s3savage/Jamfile deleted file mode 100644 index 8022492a15..0000000000 --- a/src/add-ons/kernel/drivers/graphics/s3savage/Jamfile +++ /dev/null @@ -1,16 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel drivers graphics s3savage ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -UsePrivateHeaders [ FDirName graphics s3savage ] ; -UsePrivateHeaders [ FDirName graphics common ] ; -UsePrivateHeaders graphics kernel ; - -KernelAddon s3savage : - driver.c -; - -Package haiku-s3savage-cvs : - s3savage : - boot home config add-ons kernel drivers bin ; -PackageDriverSymLink haiku-s3savage-cvs : graphics s3savage ; diff --git a/src/add-ons/kernel/drivers/graphics/s3savage/driver.c b/src/add-ons/kernel/drivers/graphics/s3savage/driver.c deleted file mode 100644 index 341043ba56..0000000000 --- a/src/add-ons/kernel/drivers/graphics/s3savage/driver.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. - - Other authors: - Gerald Zajac 2006-2007 -*/ - -#include -#include -#include -#include -#include -#include - -#include "DriverInterface.h" - -/* this is for the standardized portion of the driver API */ -/* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */ -#include - - -#ifdef TRACE_S3SAVAGE -# define TRACE(a) TraceLog a -#else -# define TRACE(a) -#endif - - -#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) -#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v)) - -#define SKD_HANDLER_INSTALLED 0x80000000 - -#define MAX_DEVICES 8 - -#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" - -#define SAVAGE_NEWMMIO_REGBASE_S3 0x1000000 /* 16MB */ -#define SAVAGE_NEWMMIO_REGBASE_S4 0x0000000 -#define SAVAGE_NEWMMIO_REGSIZE 0x0080000 /* 512kb */ - -/* Tell the kernel what revision of the driver API we support */ -int32 api_version = B_CUR_DRIVER_API_VERSION; - -/* these structures are private to the kernel driver */ - -typedef struct { - uint16 chipID; // PCI device id of the chipset - uint16 chipset; // assigned chipset family identifier - char* chipName; // user recognizable name for chipset (must be < 32 chars) -} ChipInfo; - -/* This table maps a PCI device ID to a chipset family identifier and the chipset - name. */ -static ChipInfo SavageChipTable[] = { - { 0x8a20, S3_SAVAGE3D, "Savage3D" }, - { 0x8a21, S3_SAVAGE3D, "Savage3D-MV" }, - { 0x8a22, S3_SAVAGE4, "Savage4" }, - { 0x8a25, S3_PROSAVAGE, "ProSavage PM133" }, - { 0x8a26, S3_PROSAVAGE, "ProSavage KM133" }, - { 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" }, - { 0x8c11, S3_SAVAGE_MX, "Savage/MX" }, - { 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" }, - { 0x8c13, S3_SAVAGE_MX, "Savage/IX" }, - { 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" }, - { 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" }, - { 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" }, - { 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" }, - { 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" }, - { 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" }, - { 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" }, - { 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" }, - { 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" }, - { 0x8d01, S3_TWISTER, "Twister PN133" }, - { 0x8d02, S3_TWISTER, "Twister KN133" }, - { 0x8d03, S3_PROSAVAGEDDR, "ProSavage DDR" }, - { 0x8d04, S3_PROSAVAGEDDR, "ProSavage DDR-K" }, - { 0x9102, S3_SAVAGE2000, "Savage2000" }, - { 0, 0, NULL } -}; - - -#define VENDOR_ID_SAVAGE 0x5333 /* S3 Savage vendor ID */ - -static struct { - uint16 vendorID; - ChipInfo* devices; -} SupportedDevices[] = { - { VENDOR_ID_SAVAGE, SavageChipTable }, - { 0x0000, NULL } -}; - - -typedef struct { - uint32 is_open; /* a count of how many times the devices has been opened */ - area_id sharedArea; /* the area shared between the driver and all of the accelerants */ - SharedInfo *si; /* a pointer to the shared area, for convenience */ - vuint8 *regs; /* kernel's pointer to memory mapped registers */ - ChipInfo *pChipInfo; /* info about the selected chipset */ - pci_info pcii; /* a convenience copy of the pci info for this device */ - char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */ -} DeviceInfo; - - -typedef struct { - uint32 count; /* number of devices actually found */ - benaphore kernel; /* for serializing opens/closes */ - char *deviceNames[MAX_DEVICES+1]; /* device name pointer storage */ - DeviceInfo di[MAX_DEVICES]; /* device specific stuff */ -} DeviceData; - - -/* prototypes for our private functions */ -static status_t open_hook (const char* name, uint32 flags, void** cookie); -static status_t close_hook (void* dev); -static status_t free_hook (void* dev); -static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len); -static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len); -static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len); -static status_t map_device(DeviceInfo *di); -static void unmap_device(DeviceInfo *di); -static void probe_devices(void); -static int32 savage_interrupt(void *data); - -static DeviceData *pd; -static pci_module_info *pci_bus; -static device_hooks graphics_device_hooks = -{ - open_hook, - close_hook, - free_hook, - control_hook, - read_hook, - write_hook, - NULL, - NULL, - NULL, - NULL -}; - -#ifdef TRACE_S3SAVAGE -static void -TraceLog(const char *fmt, ...) -{ - char string[1024]; - va_list args; - - strcpy(string, "savage: "); - va_start(args, fmt); - vsprintf(&string[strlen(string)], fmt, args); - dprintf(string); -} -#endif - - -// Functions for dealing with Vertical Blanking Interrupts. Currently, I do -// not know the commands to handle these operations; thus, these functions -// currently do nothing. - -static bool -InterruptIsVBI() -{ - // return true only if a vertical blanking interrupt has occured - return false; -} - - -static void -ClearVBI() -{ -} - -static void -EnableVBI() -{ -} - -static void -DisableVBI() -{ -} - - - -static ChipInfo* -FindDeviceMatch(uint16 vendorID, uint16 deviceID) -{ - // Search the table of supported devices to find a chipset/device that - // matches the vendor ID and device ID passed by the caller. - // Return pointer to the struct containing the chipset info if match - // is found; else return NULL. - - int vendor = 0; - - while (SupportedDevices[vendor].vendorID != 0) { // end of table? - if (SupportedDevices[vendor].vendorID == vendorID) { - ChipInfo* pDevice = SupportedDevices[vendor].devices; - - while (pDevice->chipID != 0) { // end of table? - if (pDevice->chipID == deviceID) - return pDevice; // matching device/chipset found - - pDevice++; - } - } - vendor++; - } - - return NULL; // no match found -} - - -/* - init_hardware() - Returns B_OK if a device supported by this driver - is found; otherwise, returns B_ERROR so the driver will be unloaded. -*/ -status_t -init_hardware(void) -{ - long pci_index = 0; - pci_info pcii; - ChipInfo* pDevice = NULL; - - /* choke if we can't find the PCI bus */ - if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK) - return B_ERROR; - - /* while there are more pci devices */ - while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) { -// TRACE(("init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, pcii.vendor_id, pcii.device_id)); - pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id); - if (pDevice != NULL) - break; - - /* next pci_info struct, please */ - pci_index++; - } - - TRACE(("init_hardware - %s\n", pDevice == NULL ? "no supported devices" : "device supported")); - - /* put away the module manager */ - put_module(B_PCI_MODULE_NAME); - return (pDevice == NULL ? B_ERROR : B_OK); -} - - -status_t init_driver(void) -{ -// TRACE(("enter init_driver\n")); - - /* get a handle for the pci bus */ - if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK) - return B_ERROR; - - /* driver private data */ - pd = (DeviceData *)calloc(1, sizeof(DeviceData)); - if (NULL == pd) { - put_module(B_PCI_MODULE_NAME); - return B_ERROR; - } - - /* initialize the benaphore */ - INIT_BEN(pd->kernel); - - /* find all of our supported devices */ - probe_devices(); - -// TRACE(("exit init_driver\n")); - return B_OK; -} - - -const char** -publish_devices(void) -{ - /* return the list of supported devices */ - return (const char **)pd->deviceNames; -} - - -device_hooks* -find_device(const char *name) -{ - int index = 0; - while (pd->deviceNames[index]) { - if (strcmp(name, pd->deviceNames[index]) == 0) - return &graphics_device_hooks; - index++; - } - return NULL; -} - - -void -uninit_driver(void) -{ - /* free the driver data */ - DELETE_BEN(pd->kernel); - free(pd); - pd = NULL; - - /* put the pci module away */ - put_module(B_PCI_MODULE_NAME); -} - - -static status_t -map_device(DeviceInfo *di) -{ - /* default: frame buffer in [0], control regs in [1] */ - char buffer[B_OS_NAME_LENGTH]; - SharedInfo *si = di->si; - uint32 tmpUlong; - pci_info *pcii = &(di->pcii); - uint32 videoRamAddr = 0; - uint32 videoRamSize = 0; - uint32 regsBase = 0; - - TRACE(("enter map_device\n")); - - /* enable memory mapped IO, disable VGA I/O - this is defined in the PCI standard */ - tmpUlong = get_pci(PCI_command, 2); - tmpUlong |= PCI_command_memory; // enable PCI access - tmpUlong |= PCI_command_master; // enable busmastering - tmpUlong &= ~PCI_command_io; // disable ISA I/O access - set_pci(PCI_command, 2, tmpUlong); - - // Since we do not know at this point the actual size of the video - // memory, set it to the largest value that the respective chipset - // family can have. - - if (S3_SAVAGE3D_SERIES(di->pChipInfo->chipset)) { - regsBase = di->pcii.u.h0.base_registers[0] + SAVAGE_NEWMMIO_REGBASE_S3; - videoRamAddr = di->pcii.u.h0.base_registers[0]; - videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series - si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); - } else { - regsBase = di->pcii.u.h0.base_registers[0] + SAVAGE_NEWMMIO_REGBASE_S4; - videoRamAddr = di->pcii.u.h0.base_registers[1]; - videoRamSize = di->pcii.u.h0.base_register_sizes[1]; - si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]); - } -TRACE(("base_registers 0: 0x%08lX 0x%08lX 0x%08lX\n", di->pcii.u.h0.base_registers[0], di->pcii.u.h0.base_registers_pci[0], di->pcii.u.h0.base_register_sizes[0] )); -TRACE(("base_registers 1: 0x%08lX 0x%08lX 0x%08lX\n", di->pcii.u.h0.base_registers[1], di->pcii.u.h0.base_registers_pci[1], di->pcii.u.h0.base_register_sizes[1] )); - - /* map the areas */ - sprintf(buffer, DEVICE_FORMAT " regs", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - - si->regsArea = map_physical_memory( - buffer, - (void *)regsBase, - SAVAGE_NEWMMIO_REGSIZE, - B_ANY_KERNEL_ADDRESS, - 0, /* B_READ_AREA + B_WRITE_AREA, */ /* neither read nor write, to hide it from user space apps */ - (void **)(&(di->regs))); - - /* return the error if there was some problem */ - if (si->regsArea < 0) - return si->regsArea; - - sprintf(buffer, DEVICE_FORMAT " framebuffer", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - - si->videoMemArea = map_physical_memory( - buffer, - (void *)videoRamAddr, - videoRamSize, - B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, - B_READ_AREA + B_WRITE_AREA, - &(si->videoMemAddr)); - -// TRACE(("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si->videoMemArea, (uint32)(si->videoMemAddr), videoRamSize)); - - if (si->videoMemArea < 0) { - /* try to map this time without write combining */ - si->videoMemArea = map_physical_memory( - buffer, - (void *)videoRamAddr, - videoRamSize, - B_ANY_KERNEL_BLOCK_ADDRESS, - B_READ_AREA + B_WRITE_AREA, - &(si->videoMemAddr)); - } - -// TRACE(("Video memory, area: %ld, addr: 0x%lX\n", si->videoMemArea, (uint32)(si->videoMemAddr))); - - /* if there was an error, delete our other areas */ - if (si->videoMemArea < 0) { - delete_area(si->regsArea); - si->regsArea = -1; - } - - /* in any case, return the result */ - TRACE(("leave map_device\n")); - return si->videoMemArea; -} - - -static void -unmap_device(DeviceInfo *di) -{ - SharedInfo *si = di->si; - uint32 tmpUlong; - pci_info *pcii = &(di->pcii); - - TRACE(("enter unmap_device(%08lx)\n", (uint32)di)); -// TRACE(("regsArea: %ld\n\tvideoMemArea: %ld\n", si->regsArea, si->videoMemArea)); - - /* disable memory mapped IO */ - tmpUlong = get_pci(PCI_command, 2); - tmpUlong &= ~(PCI_command_io | PCI_command_memory); - set_pci(PCI_command, 2, tmpUlong); - - /* delete the areas */ - if (si->regsArea >= 0) - delete_area(si->regsArea); - if (si->videoMemArea >= 0) - delete_area(si->videoMemArea); - - si->regsArea = si->videoMemArea = -1; - si->videoMemAddr = NULL; - di->regs = NULL; - - TRACE(("exit unmap_device()\n")); -} - - -static void -probe_devices(void) -{ - uint32 pci_index = 0; - uint32 count = 0; - DeviceInfo *di = pd->di; - ChipInfo* pDevice; - -// TRACE(("enter probe_devices()\n")); - - /* while there are more pci devices */ - while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) { -// TRACE(("checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, di->pcii.vendor_id, di->pcii.device_id)); - - /* if we match a supported vendor & device */ - pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id); - if (pDevice != NULL) { - /* publish the device name */ - sprintf(di->name, "graphics/" DEVICE_FORMAT, - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - TRACE(("probe_devices: match found; name: %s\n", di->name)); - - pd->deviceNames[count] = di->name; - di->is_open = 0; // mark driver as available for R/W open - di->sharedArea = -1; // indicate shared area not yet created - di->si = NULL; - di->pChipInfo = pDevice; - di++; - count++; - } - - pci_index++; - } - - pd->count = count; - pd->deviceNames[pd->count] = NULL; // terminate list with null pointer - - TRACE(("probe_devices: %ld supported devices\n", pd->count)); -} - - -static uint32 -thread_interrupt_work(DeviceInfo *di) -{ - SharedInfo *si = di->si; - uint32 handled = B_HANDLED_INTERRUPT; - - /* release the vblank semaphore */ - if (si->vblank >= 0) { - int32 blocked; - if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) { - release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE); - handled = B_INVOKE_SCHEDULER; - } - } - return handled; -} - - -static int32 -savage_interrupt(void *data) -{ - int32 handled = B_UNHANDLED_INTERRUPT; - DeviceInfo *di = (DeviceInfo *)data; - int32 *flags = &(di->si->flags); - - /* is someone already handling an interrupt for this device? */ - if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) - goto exit0; - - if (InterruptIsVBI()) { // was the interrupt a VBI? - ClearVBI(); // clear the interrupt - - handled = thread_interrupt_work(di); // release the semaphore - } - - /* note that we're not in the handler any more */ - atomic_and(flags, ~SKD_HANDLER_INSTALLED); - -exit0: - return handled; -} - - -// #pragma mark - Device Hooks - - -static status_t -open_hook(const char* name, uint32 flags, void** cookie) -{ - int32 index = 0; - DeviceInfo *di; - SharedInfo *si; - thread_id thid; - thread_info thinfo; - status_t result = B_OK; - char sharedName[B_OS_NAME_LENGTH]; - - (void)flags; // avoid compiler warning for unused arg - - TRACE(("open_hook(%s, 0x%08lx)\n", name, (uint32)cookie)); - - /* find the device name in the list of devices */ - /* we're never passed a name we didn't publish */ - while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0)) - index++; - - /* for convienience */ - di = &(pd->di[index]); - - /* make sure no one else has write access to the common data */ - AQUIRE_BEN(pd->kernel); - - /* if it's already open for writing */ - if (di->is_open) { - /* mark it open another time */ - goto mark_as_open; - } - - /* create the shared area */ - sprintf(sharedName, DEVICE_FORMAT " shared", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - /* create this area with NO user-space read or write permissions, to prevent accidental dammage */ - di->sharedArea = create_area(sharedName, (void **) &(di->si), B_ANY_KERNEL_ADDRESS, - ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), - B_FULL_LOCK, 0); - if (di->sharedArea < 0) { - /* return the error */ - result = di->sharedArea; - goto done; - } - - /* save a few dereferences */ - si = di->si; - - /* save the vendor and device IDs */ - si->vendorID = di->pcii.vendor_id; - si->deviceID = di->pcii.device_id; - si->revision = di->pcii.revision; - si->chipset = di->pChipInfo->chipset; - strcpy(si->chipsetName, di->pChipInfo->chipName); - - /* map the device */ - result = map_device(di); - if (result < 0) - goto free_shared; - - result = B_OK; - - DisableVBI(); // disable & clear any pending interrupts - si->bInterruptAssigned = false; // indicate interrupt not assigned yet - - /* create a semaphore for vertical blank management */ - si->vblank = create_sem(0, di->name); - if (si->vblank < 0) - goto mark_as_open; - - /* change the owner of the semaphores to the opener's team */ - /* this is required because apps can't aquire kernel semaphores */ - thid = find_thread(NULL); - get_thread_info(thid, &thinfo); - set_sem_owner(si->vblank, thinfo.team); - - /* If there is a valid interrupt assigned, set up interrupts */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || - (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */ - (di->pcii.u.h0.interrupt_line <= 0x02)) { /* system IRQ assigned */ - /* Interrupt does not exist; thus delete semaphore as it won't be used */ - delete_sem(si->vblank); - si->vblank = -1; - } else { - /* otherwise install our interrupt handler */ - result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, (void *)di, 0); - if (result != B_OK) { - /* delete the semaphore as it won't be used */ - delete_sem(si->vblank); - si->vblank = -1; - } else { - /* inform accelerant(s) we can use interrupt related functions */ - si->bInterruptAssigned = true; - } - } - -mark_as_open: - /* mark the device open */ - di->is_open++; - - /* send the cookie to the opener */ - *cookie = di; - goto done; - -free_shared: - /* clean up our shared area */ - delete_area(di->sharedArea); - di->sharedArea = -1; - di->si = NULL; - -done: - /* end of critical section */ - RELEASE_BEN(pd->kernel); - - /* all done, return the status */ - TRACE(("open_hook returning 0x%08lx\n", result)); - return result; -} - - -static status_t -read_hook(void* dev, off_t pos, void* buf, size_t* len) -{ - // Following 3 lines of code are here to eliminate "unused parameter" warnings. - (void)dev; - (void)pos; - (void)buf; - - *len = 0; - return B_NOT_ALLOWED; -} - - -static status_t -write_hook(void* dev, off_t pos, const void* buf, size_t* len) -{ - // Following 3 lines of code are here to eliminate "unused parameter" warnings. - (void)dev; - (void)pos; - (void)buf; - - *len = 0; - return B_NOT_ALLOWED; -} - - -static status_t -close_hook(void* dev) -{ - (void)dev; // avoid compiler warning for unused arg - - TRACE(("close_hook()\n")); - /* we don't do anything on close: there might be dup'd fd */ - return B_NO_ERROR; -} - - -static status_t -free_hook(void* dev) -{ - DeviceInfo *di = (DeviceInfo*)dev; - SharedInfo *si = di->si; - - TRACE(("enter free_hook()\n")); - /* lock the driver */ - AQUIRE_BEN(pd->kernel); - - /* if opened multiple times, decrement the open count and exit */ - if (di->is_open > 1) - goto unlock_and_exit; - - DisableVBI(); // disable & clear any pending interrupts - - if (si->bInterruptAssigned) { - /* remove interrupt handler */ - remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, di); - } - - /* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */ - if (si->vblank >= 0) - delete_sem(si->vblank); - si->vblank = -1; - - /* free regs and frame buffer areas */ - unmap_device(di); - - /* clean up our shared area */ - delete_area(di->sharedArea); - di->sharedArea = -1; - di->si = NULL; - -unlock_and_exit: - /* mark the device available */ - di->is_open--; - /* unlock the driver */ - RELEASE_BEN(pd->kernel); - - TRACE(("exit free_hook()\n")); - /* all done */ - return B_OK; -} - - -static status_t -control_hook(void* dev, uint32 msg, void *buf, size_t len) -{ - DeviceInfo *di = (DeviceInfo *)dev; - status_t result = B_DEV_INVALID_IOCTL; - - (void)len; // avoid compiler warning for unused arg - - // TRACE(("control_hook; ioctl: %d, buf: 0x%08x, len: %d\n", msg, buf, len)); - - switch (msg) { - /* the only PUBLIC ioctl */ - case B_GET_ACCELERANT_SIGNATURE: - { - char *sig = (char *)buf; - strcpy(sig, "s3savage.accelerant"); - result = B_OK; - break; - } - - /* PRIVATE ioctl from here on */ - case SAVAGE_GET_PRIVATE_DATA: - { - SavageGetPrivateData *gpd = (SavageGetPrivateData *)buf; - if (gpd->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - gpd->sharedInfoArea = di->sharedArea; - result = B_OK; - } - break; - } - - case SAVAGE_GET_PCI: - { - SavageGetSetPci *gsp = (SavageGetSetPci *)buf; - if (gsp->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - pci_info *pcii = &(di->pcii); - gsp->value = get_pci(gsp->offset, gsp->size); - result = B_OK; - } - break; - } - - case SAVAGE_SET_PCI: - { - SavageGetSetPci *gsp = (SavageGetSetPci *)buf; - if (gsp->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - pci_info *pcii = &(di->pcii); - set_pci(gsp->offset, gsp->size, gsp->value); - result = B_OK; - } - break; - } - - case SAVAGE_DEVICE_NAME: - { - SavageDeviceName *dn = (SavageDeviceName *)buf; - if (dn->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - strcpy(dn->name, di->name); - result = B_OK; - } - break; - } - - case SAVAGE_RUN_INTERRUPTS: - { - SavageSetBoolState *ri = (SavageSetBoolState *)buf; - if (ri->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - if (ri->bEnable) { - EnableVBI(); - } else { - DisableVBI(); - } - } - result = B_OK; - break; - } - } - return result; -} -