diff --git a/headers/private/graphics/s3savage/DriverInterface.h b/headers/private/graphics/s3savage/DriverInterface.h index 16933cb87a..575870c4e9 100644 --- a/headers/private/graphics/s3savage/DriverInterface.h +++ b/headers/private/graphics/s3savage/DriverInterface.h @@ -1,192 +1,239 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + 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. + 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 NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array + typedef struct { - sem_id sem; - int32 ben; + 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 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 0x1234 /* a private driver rev, of sorts */ +#define SAVAGE_PRIVATE_DATA_MAGIC 0x5791 // a private driver rev, of sorts -#define MAX_SAVAGE_DEVICE_NAME_LENGTH 32 - -#define SKD_MOVE_CURSOR 0x00000001 -#define SKD_PROGRAM_CLUT 0x00000002 -#define SKD_SET_START_ADDR 0x00000004 -#define SKD_SET_CURSOR 0x00000008 -#define SKD_HANDLER_INSTALLED 0x80000000 enum { - SAVAGE_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, - SAVAGE_GET_PCI, - SAVAGE_SET_PCI, - SAVAGE_DEVICE_NAME, - SAVAGE_RUN_INTERRUPTS, - SAVAGE_DPRINTF + SAVAGE_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, + SAVAGE_GET_PCI, + SAVAGE_SET_PCI, + SAVAGE_DEVICE_NAME, + SAVAGE_RUN_INTERRUPTS, }; -typedef struct + +// Chip tags. These are used to group the adapters into related +// families. See table SavageChipsetTable in driver.c + +enum S3ChipTags { - uint16 vendor_id; /* PCI vendor ID, from pci_info */ - uint16 device_id; /* PCI device ID, from pci_info */ - uint8 revision; /* PCI device revsion, from pci_info */ - area_id regs_area; /* Kernel's area_id for the memory mapped registers. - It will be cloned into the accelerant's address - space. */ - area_id fb_area; /* Frame buffer's area_id. The addresses are shared - with all teams. */ - void *framebuffer; /* As viewed from virtual memory */ - void *framebuffer_pci; /* As viewed from the PCI bus (for DMA) */ - area_id rom_area; /* Mapped ROM's area_id */ - void *rom; /* As viewed from virtual memory. Shared by all teams */ - area_id mode_area; /* Contains the list of display modes the driver supports */ - uint32 mode_count; /* Number of display modes in the list */ - sem_id vblank; /* The vertical blank semaphore. Ownership will be - transfered to the team opening the device first */ - int32 flags; - int32 start_addr; - - struct - { - uint8* data; /* Pointer into the frame buffer to where the - cursor data starts */ - 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 is_visible; /* Is the cursor currently displayed? */ - } cursor; - uint16 first_color; - uint16 color_count; - bigtime_t refresh_period; /* Duration of one frame (ie 1/refresh rate) */ - bigtime_t blank_period; /* Duration of the blanking period. These are - usefull when faking vertical blanking - interrupts. */ - uint8 color_data[3 * 256]; /* */ - uint8 cursor0[64*64/8]; /* AND mask for a 64x64 cursor */ - uint8 cursor1[512]; /* XOR mask for a 64x64 cursor */ - display_mode dm; /* current display mode configuration */ - frame_buffer_config - fbc; /* bytes_per_row and start of frame buffer */ - struct - { - uint64 count; /* last fifo slot used */ - uint64 last_idle; /* last fifo slot we *know* the engine was idle after */ - benaphore lock; /* for serializing access to the acceleration engine */ - } engine; - - 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. */ - uint32 mem_size; /* Frame buffer memory, in bytes. */ -} shared_info; - -/* 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 */ -} savage_get_set_pci; - -/* Set some boolean condition (like enabling or disabling interrupts) */ -typedef struct -{ - uint32 magic; /* magic number to make sure the caller groks us */ - bool do_it; /* state to set */ -} savage_set_bool_state; - -/* 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 shared_info_area; /* area_id containing the shared information */ -} savage_get_private_data; - -/* 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 */ -} savage_device_name; - -enum -{ - SAVAGE_WAIT_FOR_VBLANK = (0 << 0) + S3_UNKNOWN = 0, + S3_SAVAGE3D, + S3_SAVAGE_MX, + S3_SAVAGE4, + S3_PROSAVAGE, + S3_TWISTER, + S3_PROSAVAGEDDR, + S3_SUPERSAVAGE, + S3_SAVAGE2000, }; -enum +#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 { - /* Savage3D series */ - PCI_PID_SAVAGE3D = 0x8a20, /* Savage3D */ - PCI_PID_SAVAGE3DMV = 0x8a21, /* Savage3D/MV */ - PCI_PID_SAVAGEMXMV = 0x8c10, /* Savage/MX-MV */ - PCI_PID_SAVAGEMX = 0x8c11, /* Savage/MX */ - PCI_PID_SAVAGEIXMV = 0x8c12, /* Savage/IX-MV */ - PCI_PID_SAVAGEIX = 0x8c13, /* Savage/IX */ + // 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 - /* Savage4 series */ - PCI_PID_SAVAGE4_2 = 0x8a22, /* Savage4 */ - PCI_PID_SAVAGE4_3 = 0x8a23, /* Savage4 */ - PCI_PID_SAVAGE2000 = 0x9102, /* Savage2000 */ - PCI_PID_PM133 = 0x8a25, /* ProSavage PM133 */ - PCI_PID_KM133 = 0x8a26, /* ProSavage KM133 */ - PCI_PID_PN133 = 0x8d01, /* ProSavage PN133, 86C380 [ProSavageDDR K4M266] */ - PCI_PID_KN133 = 0x8d02, /* ProSavage KN133/TwisterK AGP4X VT8636A */ - PCI_PID_KM266 = 0x8d04, /* ProSavage8 KM266/KL266 VT8375 */ - PCI_PID_PN266 = 0x8d03, /* VT8751 [ProSavageDDR P4M266] */ + bool bAccelerantInUse; // true = accelerant has been initialized + bool bInterruptAssigned; // card has a useable interrupt assigned to it - /* SuperSavage series (unsupported) */ - PCI_PID_SUPERSAVAGE_MX128 = 0x8c22, /* SuperSavage MX/128 */ - PCI_PID_SUPERSAVAGE_MX64 = 0x8c24, /* SuperSavage MX/64 */ - PCI_PID_SUPERSAVAGE_MX64C = 0x8c26, /* SuperSavage MX/64C */ - PCI_PID_SUPERSAVAGE_IX128_SDR = 0x8c2a, /* SuperSavage IX/128 SDR */ - PCI_PID_SUPERSAVAGE_IX128_DDR = 0x8c2b, /* SuperSavage IX/128 DDR */ - PCI_PID_SUPERSAVAGE_IX64_SDR = 0x8c2c, /* SuperSavage IX/64 SDR */ - PCI_PID_SUPERSAVAGE_IX64_DDR = 0x8c2d, /* SuperSavage IX/64 DDR */ - PCI_PID_SUPERSAVAGE_IXC_SDR = 0x8c2e, /* SuperSavage IX/C SDR */ - PCI_PID_SUPERSAVAGE_IXC_DDR = 0x8c2f, /* SuperSavage IX/C DDR */ -}; + // 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. -#define isSavage4Family(p) \ - ((p) == PCI_PID_SAVAGE4_2 || \ - (p) == PCI_PID_SAVAGE4_3 || \ - (p) == PCI_PID_SAVAGE2000 || \ - (p) == PCI_PID_PM133 || \ - (p) == PCI_PID_KM133 || \ - (p) == PCI_PID_PN133 || \ - (p) == PCI_PID_KN133 || \ - (p) == PCI_PID_KM266) + 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) diff --git a/src/add-ons/accelerants/s3savage/generic.h b/src/add-ons/accelerants/s3savage/AccelerantPrototypes.h similarity index 91% rename from src/add-ons/accelerants/s3savage/generic.h rename to src/add-ons/accelerants/s3savage/AccelerantPrototypes.h index bae3998fad..f8bbf350c4 100644 --- a/src/add-ons/accelerants/s3savage/generic.h +++ b/src/add-ons/accelerants/s3savage/AccelerantPrototypes.h @@ -2,13 +2,12 @@ Copyright 1999, Be Incorporated. All Rights Reserved. This file may be used under the terms of the Be Sample Code License. */ -#ifndef GENERIC_H -#define GENERIC_H +#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); @@ -49,4 +48,9 @@ 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/Acceleration.c b/src/add-ons/accelerants/s3savage/Acceleration.c index 14f86a297a..4177b4edbd 100644 --- a/src/add-ons/accelerants/s3savage/Acceleration.c +++ b/src/add-ons/accelerants/s3savage/Acceleration.c @@ -1,121 +1,182 @@ /* - * Copyright 1999 Erdi Chen - */ + 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 "generic.h" -#include "s3accel.h" -#include "s3mmio.h" +#include "AccelerantPrototypes.h" +#include "savage.h" -void -SCREEN_TO_SCREEN_BLIT ( - engine_token *et, blit_params *list, uint32 count) + + +void +FILL_RECTANGLE (engine_token *et, uint32 color, fill_rect_params *pList, uint32 count) { - s3accel_wait_for_fifo (1); - UpdateGEReg16 (FRGD_MIX, 0x0067); - - while (count--) - { - int cmd = 0xc0b1; - int src_x = list->src_left; - int src_y = list->src_top; - int dest_x = list->dest_left; - int dest_y = list->dest_top; - int width = list->width; - int height = list->height; - - if (src_x < dest_x) - { - src_x += width; dest_x += width; - cmd ^=32; - } - - if (src_y < dest_y) - { - src_y += height; dest_y += height; - cmd ^=128; - } - - UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y); - UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y); - UpdateGEReg (ALT_PCNT, (width<<16)|height); - UpdateGEReg (CMD, cmd); - - list ++; - } + 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; - s3accel_wait_for_fifo (3); - UpdateGEReg16 (FRGD_MIX, 0x0027); + (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--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x + 1; + int h = pList->bottom - y + 1; + + BCI_GET_PTR; + + si->WaitQueue(7); + + BCI_SEND(cmd); + BCI_SEND(si->GlobalBD.bd2.LoPart); + BCI_SEND(si->GlobalBD.bd2.HiPart); + + BCI_SEND(color); + BCI_SEND(BCI_X_Y(x, y)); + BCI_SEND(BCI_W_H(w, h)); + + pList++; + } } -void -FILL_RECTANGLE ( - engine_token *et, uint32 color, fill_rect_params *list, uint32 count) + +void +FILL_SPAN(engine_token *et, uint32 color, uint16 *pList, uint32 count) { - s3accel_wait_for_fifo (1); - UpdateGEReg (FRGD_COLOR, color); - UpdateGEReg16 (FRGD_MIX, 0x0027); - - while (count--) - { - int x = list->left; - int y = list->top; - int w = list->right - x; - int h = list->bottom - y; + 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; - s3accel_wait_for_fifo (2); - UpdateGEReg (ALT_CURXY, (x<<16)|y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, 0x000040b1); + (void)et; // avoid compiler warning for unused arg - list++; - } - s3accel_wait_for_fifo(3); +// TRACE(("FILL_SPAN, count: %d\n", count)); + + BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop + + while (count--) { + int y = *pList++; + int x = *pList++; + int w = *pList++ - x + 1; + + BCI_GET_PTR; + + // The MediaPlayer in Zeta 1.21 displays a window which has 2 zero width + // 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); + + BCI_SEND(cmd); + BCI_SEND(si->GlobalBD.bd2.LoPart); + BCI_SEND(si->GlobalBD.bd2.HiPart); + + BCI_SEND(color); + BCI_SEND(BCI_X_Y(x, y)); + BCI_SEND(BCI_W_H(w, 1)); + } } -void -INVERT_RECTANGLE ( - engine_token *et, fill_rect_params *list, uint32 count) + +void +INVERT_RECTANGLE(engine_token *et, fill_rect_params *pList, uint32 count) { - s3accel_wait_for_fifo (1); - UpdateGEReg16 (FRGD_MIX, 0x0020); - - while (count--) - { - int x = list->left; - int y = list->top; - int w = list->right - x; - int h = list->bottom - y; + int cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP + | BCI_CMD_DEST_PBD_NEW; - s3accel_wait_for_fifo (2); - UpdateGEReg (ALT_CURXY, (x<<16)|y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, 0x000040b1); + (void)et; // avoid compiler warning for unused arg - list++; - } +// TRACE(("INVERT_RECTANGLE, count: %d\n", count)); - s3accel_wait_for_fifo (3); - UpdateGEReg16 (FRGD_MIX, 0x0027); + BCI_CMD_SET_ROP(cmd, 0x55); // use GXinvert for rop + + while (count--) { + int x = pList->left; + int y = pList->top; + int w = pList->right - x + 1; + int h = pList->bottom - y + 1; + + BCI_GET_PTR; + + si->WaitQueue(7); + + BCI_SEND(cmd); + BCI_SEND(si->GlobalBD.bd2.LoPart); + BCI_SEND(si->GlobalBD.bd2.HiPart); + + BCI_SEND(BCI_X_Y(x, y)); + BCI_SEND(BCI_W_H(w, h)); + + pList++; + } } -void -FILL_SPAN ( - engine_token *et, uint32 color, uint16 *list, uint32 count) + +void +SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *pList, uint32 count) { - s3accel_wait_for_fifo (1); - UpdateGEReg (FRGD_COLOR, color); - UpdateGEReg16 (FRGD_MIX, 0x0027); +// TRACE(("SCREEN_TO_SCREEN_BLIT\n")); - while (count--) - { - int y = *list ++; - int x = *list ++; - int w = *list - x; list ++; + (void)et; // avoid compiler warning for unused arg - s3accel_wait_for_fifo (2); - UpdateGEReg (ALT_CURXY, (x<<16)|y); - UpdateGEReg (ALT_PCNT, (w<<16)|1); - UpdateGEReg (CMD, 0x000040b1); - } + while (count--) { + int cmd; + 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; + + BCI_GET_PTR; + + cmd = BCI_CMD_RECT | BCI_CMD_DEST_PBD_NEW | BCI_CMD_SRC_SBD_COLOR_NEW; + BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop + + if (dest_x <= src_x) { + cmd |= BCI_CMD_RECT_XP; + } else { + src_x += width; + dest_x += width; + } + + if (dest_y <= src_y) { + cmd |= BCI_CMD_RECT_YP; + } else { + src_y += height; + dest_y += height; + } + + si->WaitQueue(9); + + BCI_SEND(cmd); + + BCI_SEND(si->GlobalBD.bd2.LoPart); + BCI_SEND(si->GlobalBD.bd2.HiPart); + + BCI_SEND(si->GlobalBD.bd2.LoPart); + BCI_SEND(si->GlobalBD.bd2.HiPart); + + BCI_SEND(BCI_X_Y(src_x, src_y)); + BCI_SEND(BCI_X_Y(dest_x, dest_y)); + BCI_SEND(BCI_W_H(width + 1, height + 1)); + + pList ++; + } } + diff --git a/src/add-ons/accelerants/s3savage/Cursor.c b/src/add-ons/accelerants/s3savage/Cursor.c index c21af8e985..825cb79178 100644 --- a/src/add-ons/accelerants/s3savage/Cursor.c +++ b/src/add-ons/accelerants/s3savage/Cursor.c @@ -1,48 +1,38 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.h" -#include "s3drv.h" +#include "AccelerantPrototypes.h" +#include "savage.h" -void set_cursor_colors(void) + +status_t +SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, + uint8* andMask, uint8* xorMask) { - /* it's only called by the INIT_ACCELERANT() */ - s3drv_set_cursor_color (0, ~0); -} + /* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */ -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 ((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; - s3drv_load_cursor ((byte_t*)framebuffer, 0, - width, height, andMask, xorMask); - } + if (!SavageLoadCursorImage(width, height, andMask, xorMask)) + return B_ERROR; + } - return B_OK; + return B_OK; } /* @@ -50,64 +40,51 @@ 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 x_p, uint16 y_p) +void +MOVE_CURSOR(uint16 xPos, uint16 yPos) { - int x = x_p, y = y_p; - bool move_screen = false; - /* the current horizontal starting pixel */ - uint16 hds = si->dm.h_display_start; - /* the current vertical starting line */ - uint16 vds = si->dm.v_display_start; + int x = xPos; // use signed int's since SavageSetCursorPosition() + int y = yPos; // needs signed int to determine if cursor off screen - /* Need to set this value for 32 bit */ - uint16 h_adjust = 3; + 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; + /* 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 + h_adjust) & ~h_adjust; - move_screen = true; - } - else if (x < hds) - { - hds = x & ~h_adjust; - move_screen = true; - } - if (y >= (si->dm.timing.v_display + vds)) - { - vds = y - si->dm.timing.v_display + 1; - move_screen = true; - } - else if (y < vds) - { - vds = y; - move_screen = true; - } + /* 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; - /* reposition the desktop on the display if required */ - if (move_screen) MOVE_DISPLAY(hds,vds); + if (y >= (si->dm.timing.v_display + vds)) + vds = y - si->dm.timing.v_display + 1; + else if (y < vds) + vds = y; - /* put cursor in correct physical position */ - x -= hds; - y -= vds; - x -= si->cursor.hot_x; - y -= si->cursor.hot_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); - /* position the cursor on the display */ - s3drv_move_cursor (x, y); + /* 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 is_visible) -{ - if (is_visible) - s3drv_show_cursor (); - else - s3drv_hide_cursor (); - /* record for our info */ - si->cursor.is_visible = is_visible; +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 index d362be1211..54684986eb 100644 --- a/src/add-ons/accelerants/s3savage/EngineManagement.c +++ b/src/add-ons/accelerants/s3savage/EngineManagement.c @@ -1,70 +1,80 @@ /* 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.h" -#include "s3drv.h" +#include "AccelerantPrototypes.h" static engine_token savage_engine_token = { 1, B_2D_ACCELERATION, NULL }; -uint32 ACCELERANT_ENGINE_COUNT(void) + +uint32 +ACCELERANT_ENGINE_COUNT(void) { - return 1; + return 1; } -status_t -ACQUIRE_ENGINE ( - uint32 capabilities, uint32 max_wait, - sync_token *st, engine_token **et) -{ - /* 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 +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) - { - st->engine_id = et->engine_id; - st->counter = si->engine.count; - } - /* release the shared benaphore */ - RELEASE_BEN(si->engine.lock) - 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) + +void +WAIT_ENGINE_IDLE(void) { - s3drv_wait_for_idle (); - // note our current possition - si->engine.last_idle = si->engine.count; + si->WaitIdleEmpty(); // wait until engine is completely idle } -status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) + +status_t +GET_SYNC_TOKEN(engine_token *et, sync_token *st) { - st->engine_id = et->engine_id; - st->counter = si->engine.count; - return B_OK; + /* 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) + +status_t +SYNC_TO_TOKEN(sync_token *st) { - s3drv_wait_for_idle (); - si->engine.last_idle = st->counter; - return B_OK; + (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 index 48d1833b1a..01bc3d60f5 100644 --- a/src/add-ons/accelerants/s3savage/GetAccelerantHook.c +++ b/src/add-ons/accelerants/s3savage/GetAccelerantHook.c @@ -1,12 +1,12 @@ /* Copyright 1999, Be Incorporated. All Rights Reserved. This file may be used under the terms of the Be Sample Code License. -*/ -/* - * Copyright 1999 Erdi Chen - */ -#include "generic.h" + Other authors: + Gerald Zajac 2006-2007 +*/ + +#include "AccelerantPrototypes.h" /* @@ -19,20 +19,24 @@ 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 * +get_accelerant_hook(uint32 feature, void *data) +{ + (void)data; // avoid compiler warning for unused arg + switch (feature) { -/* -These definitions are out of pure lazyness. -*/ + /* + 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. -*/ + /* + 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); @@ -53,7 +57,7 @@ initialization process. HOOK(GET_PIXEL_CLOCK_LIMITS); HOOK(MOVE_DISPLAY); HOOK(SET_INDEXED_COLORS); - HOOK(GET_TIMING_CONSTRAINTS); + //HOOK(GET_TIMING_CONSTRAINTS); HOOK(DPMS_CAPABILITIES); HOOK(DPMS_MODE); @@ -72,13 +76,13 @@ initialization process. 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. -*/ + /* + 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); @@ -86,9 +90,11 @@ the same function all the time. HOOK(FILL_SPAN); #undef HOOK #undef ZERO + } -/* -Return a null pointer for any feature we don't understand. -*/ + /* + 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 new file mode 100644 index 0000000000..8fbb5f03c8 --- /dev/null +++ b/src/add-ons/accelerants/s3savage/GetDeviceInfo.c @@ -0,0 +1,28 @@ +/* + 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 index 8374255a5d..8ea53f4ad9 100644 --- a/src/add-ons/accelerants/s3savage/GetModeInfo.c +++ b/src/add-ons/accelerants/s3savage/GetModeInfo.c @@ -1,96 +1,90 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.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. + 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) +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; + /* easy for us, we return the last mode we set */ + *current_mode = si->dm; + return B_OK; } + /* - Return the frame buffer configuration information. + Return the frame buffer configuration information. */ -status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) +status_t +GET_FRAME_BUFFER_CONFIG(frame_buffer_config *pFBC) { - /* easy again, as the last mode set stored the info in a convienient form */ - *afb = si->fbc; - return B_OK; +// 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. + 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) +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; + /* + 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; + /* 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; } -status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc) -{ - status_t retval; - - dtc->h_res = 8; - dtc->h_sync_min = 2*8; - dtc->h_sync_max = 32*8 - 1; - dtc->h_blank_min = 0; - dtc->h_blank_max = 64*8 - 1; - dtc->v_res = 1; - dtc->v_sync_min = 2; - dtc->v_sync_max = 15; - dtc->v_blank_min = 0; - dtc->v_blank_max = 255; - - retval = B_OK; - return retval; -} /* - Return the semaphore id that will be used to signal a vertical retrace - occured. + Return the semaphore id that will be used to signal a vertical retrace + occured. */ -sem_id ACCELERANT_RETRACE_SEMAPHORE(void) +sem_id +ACCELERANT_RETRACE_SEMAPHORE(void) { - /* - NOTE: - The kernel driver created this for us. We don't know if the system is - using real interrupts, or if we're faking it, and we don't care. - If we choose not to support this at all, we'd just return B_ERROR here, - and the user wouldn't get any kind of vertical retrace support. - */ - return si->vblank; +// 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 index 138953bf93..b4a3fdbc53 100644 --- a/src/add-ons/accelerants/s3savage/GlobalData.c +++ b/src/add-ons/accelerants/s3savage/GlobalData.c @@ -1,33 +1,19 @@ /* 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include -#include -#include -int fd; -shared_info *si; -area_id shared_info_area; -vuint32 *regs; -area_id regs_area; -vuint32 *framebuffer; -area_id fb_area; -display_mode *my_mode_list; -area_id my_mode_list_area; -int accelerantIsClone; +int driverFileDesc; +SharedInfo* si; +area_id sharedInfoArea; +uint8* regs; +area_id regsArea; +display_mode* modeList; +area_id modeListArea; +bool bAccelerantIsClone; -void dpf (const char * format, ...) -{ - char buffer[4096] = "SAVAGE: "; - va_list args; - va_start (args, format); - vsprintf (buffer + 8, format, args); - ioctl (fd, SAVAGE_DPRINTF, buffer, 0); - va_end (args); -} diff --git a/src/add-ons/accelerants/s3savage/GlobalData.h b/src/add-ons/accelerants/s3savage/GlobalData.h index 94894d0a91..c7df830178 100644 --- a/src/add-ons/accelerants/s3savage/GlobalData.h +++ b/src/add-ons/accelerants/s3savage/GlobalData.h @@ -1,32 +1,32 @@ /* 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 -extern int fd; -extern shared_info *si; -extern area_id shared_info_area; -extern vuint32 *regs; -extern area_id regs_area; -extern vuint32 *framebuffer; -extern area_id fb_area; -extern display_mode *my_mode_list; -extern area_id my_mode_list_area; -extern int accelerantIsClone; -/* Print debug message through kernel driver. Should move to other location later. */ -extern void dpf (const char * format, ...); - -/* ProposeDisplayMode.c */ -extern status_t create_mode_list(void); - -/* Cursor.c */ -extern void set_cursor_colors(void); +void TraceLog(const char* fmt, ...); +#ifdef DEBUG +#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 index 66262959c4..4905e55a56 100644 --- a/src/add-ons/accelerants/s3savage/InitAccelerant.c +++ b/src/add-ons/accelerants/s3savage/InitAccelerant.c @@ -1,19 +1,18 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.h" -#include "s3drv.h" -#include "s3mmio.h" -#include "s3accel.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" @@ -21,464 +20,270 @@ #include -/*! - Get the linear address of an area. Workaround for BeOS bug that - returns invalid pointer from clone_area. -*/ -static void * -get_area_address(area_id area) -{ - area_info ai; - get_area_info(area, &ai); - return ai.address; -} - - -#if 0 -// unused! -// Determines the amount of card memory available by seeing how far up -// the frame buffer data can be written and read back reliably. Does a -// paranoia check to make sure that it isn't just wrapping, either. -unsigned long -Get_Card_Mem_Size() -{ - // Allowed sizes actually go up to 16 megs, but clip at the - // register window for now. - const unsigned long AllowedSizes[] = - { 0x00080000, 0x00100000, 0x00180000, 0x00200000, - 0x00280000, 0x00300000, 0x00380000, 0x00400000, - 0x00500000, 0x00600000, 0x00700000, 0x007FF800, - 0x0 }; - - unsigned long MaxMem; - unsigned long RWIndex; - int iMaxIndex, iTestIndex, iX; - unsigned long LTemp; - int IsOk; - uint32 *VramBase; - - VramBase = (uint32 *)framebuffer; - MaxMem = 0; // Default. - IsOk = 1; - // Step through ever-larger memory sizes, recording size if passes test and - // ignoring otherwise. - for (iMaxIndex = 0; (AllowedSizes[iMaxIndex] != 0) && IsOk; iMaxIndex++) - { - // Write test values to the linear aperature. - // Only need to do this for the farthest location, as previous - // locations already have been written to in previous passes. - RWIndex = AllowedSizes[iMaxIndex]; - RWIndex = (RWIndex - 16384) >> 2; - for (iX = 0; iX < 4096; iX++) - { - LTemp = RWIndex; - // Hash LTemp. As the parameters for the hash are prime, it should - // be extremely unlikely to get these values through a glitch, and - // the pattern only repeats at prime intervals, so aliasing - // shouldn't fool the test either. - LTemp = (263 * (LTemp % 65521) + 29) % 65521; - // Extend this to 32 bits. - LTemp |= (LTemp ^ 0x0000FFFFul) << 16; - VramBase[RWIndex] = LTemp; - RWIndex++; - } - - // Verify that all test patterns are still intact. If values written - // past the end of memory drop off the face of the frame buffer, the - // farthest pattern(s) will not be what they should be. If values - // written past the end of memory wrap, then previous patterns will - // be overwritten (or partly overwritten, as the test location at - // 8 megs is actually at 8 megs - 2k). - // As soon as an invalid value is detected, IsOk is set to 0, which - // should quickly terminate the test loops. - for (iTestIndex = 0; (iTestIndex <= iMaxIndex) && IsOk; iTestIndex++) - { - RWIndex = AllowedSizes[iTestIndex]; - RWIndex = (RWIndex - 16384) >> 2; - for (iX = 0; (iX < 4096) && IsOk; iX++) - { - LTemp = RWIndex; - // Hash LTemp. As the parameters for the hash are prime, it - // should be extremely unlikely to get these values through - // a glitch, and the pattern only repeats at prime intervals, - // so aliasing shouldn't fool the test either. - LTemp = (263 * (LTemp % 65521) + 29) % 65521; - // Extend this to 32 bits. - LTemp |= (LTemp ^ 0x0000FFFFul) << 16; - // Test against the value read from the frame buffer. - if (VramBase[RWIndex] != LTemp) - IsOk = 0; - RWIndex++; - } - } - - // If the test patterns check out, update MaxMem accordingly. - if (IsOk) - MaxMem = AllowedSizes[iMaxIndex]; - } - - return MaxMem; -} -#endif - - /* Initialization code shared between primary and cloned accelerants */ -static status_t + +static status_t init_common(int the_fd) { status_t result; - savage_get_private_data gpd; + SavageGetPrivateData gpd; /* memorize the file descriptor */ - fd = the_fd; - dpf ("init_common begin\n"); + 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 */ - if (ioctl(fd, SAVAGE_GET_PRIVATE_DATA, &gpd, sizeof(gpd)) != 0) - return errno; - /* clone the shared area for our use */ - shared_info_area = clone_area("SAVAGE shared info", (void **)&si, - B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area); - if (shared_info_area < 0) - return shared_info_area; + /* 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 */ - regs_area = clone_area("SAVAGE regs area", (void **)®s, B_ANY_ADDRESS, - B_READ_AREA | B_WRITE_AREA, si->regs_area); - if (regs_area < 0) { - result = regs_area; + 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; } - regs = get_area_address(regs_area); - - dpf("PCI VENDOR_ID = 0x%4X, DEVICE_ID = 0x%4X\n", - read16((byte_t*)regs + 0x8000), - read16((byte_t*)regs + 0x8002)); - - /* clone the framebuffer buffer for our use */ - fb_area = clone_area("SAVAGE fb area", (void **)&framebuffer, - B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, si->fb_area); - if (fb_area < 0) { - result = regs_area; - goto error2; - } - framebuffer = get_area_address(fb_area); - - s3drv_init((byte_t*)regs); - dpf ("s3drv_init called\n"); - s3accel_init(s3drv_get_context()); - dpf ("s3accel_init called\n"); - s3drv_unlock_regs(); /* all done */ - return B_OK; + goto error0; -error2: - delete_area(regs_area); error1: - delete_area(shared_info_area); + delete_area(sharedInfoArea); +error0: return result; } -/*! Clean up code shared between primary and cloned accelerants */ -static void +/* Clean up code shared between primary and cloned accelrants */ +static void uninit_common(void) { - /* release framebuffer area */ - delete_area (fb_area); - /* release the memory mapped registers */ - delete_area(regs_area); - /* a little cheap paranoia */ - regs = 0; - /* release our copy of the shared info from the kernel driver */ - delete_area(shared_info_area); - /* more cheap paranoia */ - si = 0; + /* 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. + +/* +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 +status_t INIT_ACCELERANT(int the_fd) { - status_t result; - /* note that we're the primary accelerant (accelerantIsClone is global) */ - accelerantIsClone = 0; + status_t result; - /* do the initialization common to both the primary and the clones */ - result = init_common(the_fd); - if (result != B_OK) - goto error0; + TRACE(("Enter INIT_ACCELERANT\n")); - /* - If there is a possiblity that the kernel driver will recognize a card that - the accelerant can't support, you should check for that here. Perhaps some - odd memory configuration or some such. - */ + /* note that we're the primary accelerant (bAccelerantIsClone is global) */ + bAccelerantIsClone = false; - /* - This is a good place to go and initialize your card. The details are so - device specific, we're not even going to pretend to provide you with sample - code. If this fails, we'll have to bail out, cleaning up the resources - we've already allocated. - */ - /* call the device specific init code */ - { - SVGAMode orig, newmode; - PixelTiming timing = - { 0, { 640, 656, 752, 800, 0 }, { 480, 490, 492, 525, 0 } }; - s3drv_unlock_regs (); - s3drv_get_mode (&timing, 32, (byte_t*)&newmode, sizeof (newmode)); - s3drv_save_mode ((byte_t*)&orig, sizeof (orig)); - s3drv_restore_mode ((byte_t*)&newmode, sizeof (newmode), 1); - s3accel_init (s3drv_get_context ()); - //si->mem_size = s3drv_detect_vram_mb_size ((byte_t*)framebuffer, 32); - //dpf ("si->mem_size = %dMB\n", si->mem_size); - si->mem_size = s3drv_detect_vram_mb_size (NULL, 2); - dpf ("si->mem_size = %dMB\n", si->mem_size); - si->mem_size *= 1024*1024; - s3drv_restore_mode ((byte_t*)&orig, sizeof (orig), 1); - s3drv_lock_regs (); - } + /* 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 - si->pix_clk_max8 = 250000; - si->pix_clk_max16 = 250000; - si->pix_clk_max32 = 250000; + TRACE(("Vendor ID: 0x%X, Device ID: 0x%X\n", si->vendorID, si->deviceID)); - /* bail out if it failed */ - if (result != B_OK) goto error1; + /* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */ + if (si->bAccelerantInUse) { + result = B_NOT_ALLOWED; + 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. - */ + /* 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 error2; + goto error1; - /* - Initialize the frame buffer and cursor pointers. Most newer video cards - have integrated the DAC into the graphics engine, and so the cursor shape - is stored in the frame buffer RAM. Also, newer cards tend not to have as - many restrictions about the placement of the start of the frame buffer in - frame buffer RAM. If you're supporting an older card with frame buffer - positioning restrictions, or one without an integrated DAC, you'll have to - change this accordingly. - */ - /* - Put the cursor at the start of the frame buffer. The typical 64x64 4 color - (black, white, transparent, inverse) takes up 1024 bytes of RAM. - */ - si->cursor.data = (uint8 *)si->framebuffer; - /* Initialize the rest of the cursor information while we're here */ - 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; - /* - Put the frame buffer immediately following the cursor data. We store this - info in a frame_buffer_config structure to make it convienient to return - to the app_server later. - */ - si->fbc.frame_buffer = (void *)(((char *)si->framebuffer) + 1024); - si->fbc.frame_buffer_dma = (void *)(((char *)si->framebuffer_pci) + 1024); - si->start_addr = 1024; + /* 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; - /* init the shared semaphore */ - INIT_BEN(si->engine.lock); + si->fbc.frame_buffer = (void *)((addr_t)si->videoMemAddr + si->frameBufferOffset); + si->fbc.frame_buffer_dma = (void *)((addr_t)si->videoMemPCI + si->frameBufferOffset); - /* initialize the engine synchronization variables */ - - /* count of issued parameters or commands */ - si->engine.last_idle = si->engine.count = 0; + /* init the shared semaphore */ + INIT_BEN(si->engine.lock); - /* bail out if something failed */ - if (result != B_OK) goto error3; + /* initialize the engine synchronization variables */ + /* count of issued parameters or commands */ + si->engine.lastIdle = si->engine.count = 0; - /* set the cursor colors. You may or may not have to do this, depending - on the device. */ - set_cursor_colors(); + /* set the cursor colors. You may or may not have to do this, depending + on the device. */ + SavageSetCursorColors(~0, 0); - /* ensure cursor state */ - SHOW_CURSOR(false); - /* a winner! */ - result = B_OK; - goto error0; + /* ensure cursor state */ + SHOW_CURSOR(false); -error3: - /* free up the benaphore */ - DELETE_BEN(si->engine.lock); + /* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */ + si->bAccelerantInUse = true; -error2: - /* - Clean up any resources allocated in your device specific initialization - code. - */ + result = B_OK; + goto error0; error1: - /* - Initialization failed after init_common() succeeded, so we need to clean - up before quiting. - */ - uninit_common(); + /* + Initialization failed after init_common() succeeded, so we need to clean + up before quiting. + */ + uninit_common(); error0: - return result; + 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. +/* +Return the number of bytes required to hold the information required +to clone the device. */ -ssize_t +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 MAX_SAVAGE_DEVICE_NAME_LENGTH; + /* + 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. +/* +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) +void +GET_ACCELERANT_CLONE_INFO(void* data) { - savage_device_name dn; - status_t result; + 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(fd, SAVAGE_DEVICE_NAME, &dn, sizeof(dn)); + /* 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(). +/* +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 +CLONE_ACCELERANT(void* data) { status_t result; char path[MAXPATHLEN]; /* the data is the device name */ strcpy(path, "/dev/"); - strcat(path, (const char *)data); + strcat(path, (const char*)data); /* open the device, the permissions aren't important */ - fd = open(path, B_READ_WRITE); - if (fd < 0) + driverFileDesc = open(path, B_READ_WRITE); + if (driverFileDesc < 0) return errno; /* note that we're a clone accelerant */ - accelerantIsClone = 1; + bAccelerantIsClone = true; /* call the shared initialization code */ - result = init_common(fd); + result = init_common(driverFileDesc); + + /* bail out if the common initialization failed */ if (result != B_OK) goto error1; /* get shared area for display modes */ - result = my_mode_list_area = clone_area("SAVAGE cloned display_modes", - (void **)&my_mode_list, B_ANY_ADDRESS, B_READ_AREA, si->mode_area); + 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 */ - return B_OK; + result = B_OK; + goto error0; error2: /* free up the areas we cloned */ uninit_common(); error1: /* close the device we opened */ - close(fd); + close(driverFileDesc); +error0: return result; } -void +void UNINIT_ACCELERANT(void) { - /* free our mode list area */ - delete_area(my_mode_list_area); - /* paranoia */ - my_mode_list = 0; - /* release our cloned data */ - uninit_common(); - /* close the file handle ONLY if we're the clone */ - if (accelerantIsClone) - close(fd); + /* 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); } -status_t -GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi) + +// 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, ...) { - status_t retval; - static const char * names1[] = - { "Savage3D", "Savage3D/MV", "Savage4", "Savage4", - "Savage4", "ProSavage PM133", "ProSavage KM133" }; - static const char * names2[] = - { "Savage/MX-MV", "Savage/MX", "Savage/IX-MV", "Savage/IX" }; - static const char * names3[] = - { "ProSavage PN133", "ProSavage KN133", "ProSavage P4M266", "ProSavage8 KM266" }; + char string[1024]; + va_list args; - adi->version = 0x10000; - if (si->device_id == PCI_PID_SAVAGE2000) { - strcpy (adi->name, "Savage2000"); - strcpy (adi->chipset, "Savage2000"); - } else { - const char ** names = NULL; - int offset = 0; - switch (si->device_id & 0xFFF0) { - case 0x8a20: - names = names1; - offset = si->device_id - PCI_PID_SAVAGE3D; - break; - case 0x8c10: - names = names2; - offset = si->device_id - PCI_PID_SAVAGEMXMV; - break; - case 0x8d00: - names = names3; - offset = si->device_id - PCI_PID_PN133; - break; - } - if (names != NULL) { - strcpy (adi->name, names[offset]); - strcpy (adi->chipset, names[offset]); - } else { - strcpy (adi->name, "not supported"); - strcpy (adi->chipset, "Savage"); - } - } - strcpy (adi->serial_no, "0"); - adi->memory = si->mem_size; - adi->dac_speed = 250; - - retval = B_OK; - return retval; + 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 index 728b13d0e7..7e59acc6b2 100644 --- a/src/add-ons/accelerants/s3savage/Jamfile +++ b/src/add-ons/accelerants/s3savage/Jamfile @@ -10,15 +10,17 @@ Addon s3savage.accelerant : Cursor.c EngineManagement.c GetAccelerantHook.c + GetDeviceInfo.c GetModeInfo.c GlobalData.c InitAccelerant.c ProposeDisplayMode.c SetDisplayMode.c - - s3accel.c - s3drv.c - s3vga.c + + savage_accel.c + savage_cursor.c + savage_dpms.c + savage_driver.c : be ; diff --git a/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c b/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c index 55007fec15..d2f8eefcb4 100644 --- a/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c +++ b/src/add-ons/accelerants/s3savage/ProposeDisplayMode.c @@ -1,102 +1,127 @@ /* 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.h" +#include "AccelerantPrototypes.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_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) */ -{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ -{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ -{ { 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) */ -{ { 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) */ -{ { 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) */ -{ { 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) */ -{ { 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) */ + { { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ + { { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ + { { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ + { { 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) */ + + { { 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) */ + + { { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1440) */ + { { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1920X1440) */ + { { 341350, 1920, 2072, 2288, 2656, 1440, 1441, 1444, 1512, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1920X1440) */ + + { { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(2048x1536) */ + { { 340480, 2048, 2216, 2440, 2832, 1536, 1537, 1540, 1603, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(2048x1536) */ + { { 388040, 2048, 2216, 2440, 2832, 1536, 1537, 1540, 1612, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(2048x1536) */ }; /* 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" + a) a valid display mode for this device and + b) falls between the contraints imposed by "low" and "high" - If the mode is not (or cannot) be made valid for this device, return B_ERROR. - If a valid mode can be constructed, but it does not fall within the limits, - return B_BAD_VALUE. - If the mode is both valid AND falls within the limits, return B_OK. + 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) +status_t +PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) { - //const uint16 h_display_bits = MASKFROMWIDTH(8); 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); - //const uint16 v_total_bits = MASKFROMWIDTH(11); - 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; + 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. - */ + /* + 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. + */ - /* validate horizontal timings */ +// 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; @@ -104,7 +129,7 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, uint16 h_sync_end = target->timing.h_sync_end >> 3; uint16 h_total = target->timing.h_total >> 3; - /* ensure reasonable minium display and sequential order of parms */ + /* ensure reasonable minimum display and sequential order of parms */ if (h_display < (320 >> 3)) h_display = 320 >> 3; if (h_display > (2048 >> 3)) @@ -115,7 +140,6 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, 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) @@ -132,18 +156,19 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, 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) + + /* 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; @@ -166,7 +191,6 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, 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; @@ -177,205 +201,195 @@ PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, 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) + /* 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; - - /* 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) + // If the video is connected directly to an LCD display (ie, notebook + // computer), restrict the display mode to the resolution 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) + 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) + 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) + 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->mem_size) - target->virtual_height = si->mem_size / row_bytes; + 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) { + 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) + else if ((target->virtual_height < low->virtual_height) + || (target->virtual_height > high->virtual_height)) result = B_BAD_VALUE; - /* - Bit Flag Encoding - - The way the bit flags works is as follows: - - low high meaning - --- ---- ------- - 0 0 Feature must NOT be enabled - 0 1 Feature MAY be enabled, prefered enabled - 1 0 Feature MAY be enabled, prefered disabled - 1 1 Feature MUST be enabled - */ - /* MORE WORK REQUIRED HERE. Current drivers mostly ignore the flags */ - return result; + return result; } - -/*! +/* Return the number of modes this device will return from GET_MODE_LIST(). */ -uint32 +uint32 ACCELERANT_MODE_COUNT(void) { /* return the number of 'built-in' display modes */ - return si->mode_count; + return si->modeCount; } - -/*! +/* Copy the list of guaranteed supported video modes to the location provided. */ -status_t +status_t GET_MODE_LIST(display_mode *dm) { /* copy them to the buffer pointed at by *dm */ - memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode)); + memcpy(dm, modeList, si->modeCount * sizeof(display_mode)); return B_OK; } -/*! - Create a list of display_modes to pass back to the caller. +/* + Create a list of display_modes to pass back to the caller. */ -status_t +status_t create_mode_list(void) { - size_t max_size; - uint32 i, j, pix_clk_range; - const display_mode *src; - display_mode *dst, low, high; + 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. - */ + /* + 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 spaces[] = -// {B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE}; - {B_CMAP8, B_RGB16_LITTLE, B_RGB32_LITTLE}; + color_space colorSpaces[] = { B_CMAP8, B_RGB16_LITTLE, B_RGB32_LITTLE }; #else - color_space spaces[] = -// {B_CMAP8, B_RGB15_BIG, B_RGB16_BIG, B_RGB32_BIG}; - {B_CMAP8, B_RGB16_BIG, B_RGB32_BIG}; + color_space colorSpaces[] = { B_CMAP8, B_RGB16_BIG, B_RGB32_BIG }; #endif - /* figure out how big the list could be, and adjust up to nearest - multiple of B_PAGE_SIZE */ - max_size = (((MODE_COUNT * sizeof (spaces) / sizeof (color_space)) - * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1); + 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->mode_area = my_mode_list_area = - create_area("SAVAGE accelerant mode info", (void **)&my_mode_list, - B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); - if (my_mode_list_area < B_OK) - return my_mode_list_area; + 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 = my_mode_list; - si->mode_count = 0; + dst = modeList; + si->modeCount = 0; + for (i = 0; i < MODE_COUNT; i++) { + int j; + /* set ranges for acceptable values */ low = high = *src; - - /* range is 6.25% of default clock: arbitrarily picked */ - pix_clk_range = low.timing.pixel_clock >> 5; + /* 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; - /* some cards need wider virtual widths for certain modes */ - high.virtual_width = 2048; /* do it once for each depth we want to support */ - for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) { + for (j = 0; j < numColorSpaces; j++) { /* set target values */ *dst = *src; /* poke the specific space */ - dst->space = low.space = high.space = spaces[j]; - if (spaces[j] != B_CMAP8) - dst->flags &= ~B_8_BIT_DAC; + dst->space = low.space = high.space = colorSpaces[j]; /* ask for a compatible mode */ - if (1 || PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) { - /* count it, and move on to next mode */ - dst++; - si->mode_count++; + if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) { + /* count it, and move on to next mode */ + dst++; + si->modeCount++; } } /* advance to next mode */ @@ -384,3 +398,4 @@ create_mode_list(void) return B_OK; } + diff --git a/src/add-ons/accelerants/s3savage/SetDisplayMode.c b/src/add-ons/accelerants/s3savage/SetDisplayMode.c index 9fd4703899..f44540a26b 100644 --- a/src/add-ons/accelerants/s3savage/SetDisplayMode.c +++ b/src/add-ons/accelerants/s3savage/SetDisplayMode.c @@ -1,309 +1,204 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + 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 */ -/* - * Copyright 1999 Erdi Chen - */ #include "GlobalData.h" -#include "generic.h" -#include "s3drv.h" -#include "s3accel.h" -#include "s3mmio.h" - -#include +#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 flag) + Enable/Disable interrupts. Just a wrapper around the + ioctl() to the kernel driver. + */ +static void +interrupt_enable(bool bEnable) { - status_t result; - savage_set_bool_state sbs; + status_t result; + SavageSetBoolState sbs; - /* set the magic number so the driver knows we're for real */ - sbs.magic = SAVAGE_PRIVATE_DATA_MAGIC; - sbs.do_it = flag; - /* contact driver and get a pointer to the registers and shared data */ - result = ioctl(fd, SAVAGE_RUN_INTERRUPTS, &sbs, sizeof(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) + Calculates the number of bits for a given color_space. + Usefull for mode setup routines, etc. + */ +static uint32 +CalcBitsPerPixel(uint32 cs) { - uint32 bpp = 0; + 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 do_set_display_mode(display_mode *dm) -{ - uint bpp; - SVGAMode s3mode; - PixelTiming timing; - status_t result; - - dpf ("do_set_display_mode begin\n"); - /* disable interrupts using the kernel driver */ - interrupt_enable(false); - - bpp = calcBitsPerPixel (dm->space); - - timing.dot_clock_khz = dm->timing.pixel_clock; - timing.x.disp = dm->timing.h_display; - timing.x.sync_start = dm->timing.h_sync_start; - timing.x.sync_end = dm->timing.h_sync_end; - timing.x.total = dm->timing.h_total; - timing.x.polarity = (dm->timing.flags & B_POSITIVE_HSYNC) ? 1 : 0; - timing.y.disp = dm->timing.v_display; - timing.y.sync_start = dm->timing.v_sync_start; - timing.y.sync_end = dm->timing.v_sync_end; - timing.y.total = dm->timing.v_total; - timing.y.polarity = (dm->timing.flags & B_POSITIVE_VSYNC) ? 1 : 0; - dpf ("TIMING = { %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d }\n", - timing.dot_clock_khz, - timing.x.disp, timing.x.sync_start, timing.x.sync_end, - timing.x.total, timing.x.polarity, - timing.y.disp, timing.y.sync_start, timing.y.sync_end, - timing.y.total, timing.y.polarity); - - s3drv_unlock_regs (); - memset (&s3mode, 0, sizeof (s3mode)); - result = s3drv_get_mode (&timing, bpp, (byte_t*)&s3mode, sizeof (s3mode)); - if (result > 0) dpf ("s3drv_get_mode succeeded\n"); - else dpf ("s3drv_get_mode failed\n"); - dpf ("depth = %d, width = %d, height = %d\n", - s3mode.pixel_size, s3mode.pixel_width, s3mode.pixel_height); - result = s3drv_restore_mode ((byte_t*)&s3mode, sizeof (s3mode), true); - if (result > 0) dpf ("s3drv_set_mode succeeded\n"); - else dpf ("s3drv_set_mode failed\n"); - - /* enable interrupts using the kernel driver */ - interrupt_enable(true); - - dpf ("si->start_addr = %d\n", si->start_addr); - s3drv_set_display_start (si->start_addr); - s3drv_set_logical_width (dm->virtual_width); - si->fbc.bytes_per_row = (dm->virtual_width * bpp + 7) / 8; - s3accel_init (s3drv_get_context ()); - dpf ("s3accel_init called\n"); - - //s3drv_lock_regs (); - dpf ("do_set_display_mode done\n"); -} - -/* - The exported mode setting routine. First validate the mode, - then call our private routine to hammer the registers. - */ -status_t SET_DISPLAY_MODE (display_mode *mode_to_set) -{ - 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; - do_set_display_mode(&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 */ - s3drv_adjust_viewport (h_display_start, v_display_start); - - return B_OK; -} - -/* - Set the indexed color palette. - */ -void SET_INDEXED_COLORS ( - uint count, uint8 first, uint8 *color_data, uint32 flags) -{ - /* - 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. - */ - s3drv_unlock_regs (); - write_sr ((byte_t*)regs + 0x8000, 0x1B, 0x10); - while (count--) - { - s3drv_set_palette ( - first++, color_data[0], color_data[1], color_data[2]); - color_data += 3; - } - s3drv_lock_regs (); -} - - -/* masks for DPMS control bits */ -enum -{ - H_SYNC_OFF = 0x01, - V_SYNC_OFF = 0x02, - DISPLAY_OFF = 0x04, - BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF -}; - -/* - Put the display into one of the Display Power Management modes. - */ -status_t SET_DPMS_MODE(uint32 dpms_flags) -{ - uint32 LTemp; - - /* - The register containing the horizontal and vertical sync control bits - usually contains other control bits, so do a read-modify-write. - */ - /* FIXME - read the bits */ - LTemp = *regs; - /* this mask is device dependant */ - LTemp &= ~BITSMASK; /* clear all disable bits (including display disable) */ - - /* now pick one of the DPMS configurations */ - switch(dpms_flags) - { - case B_DPMS_ON: /* H: on, V: on */ - /* do nothing, bits already clear */ - /* usually, but it may be different for your device */ - break; - case B_DPMS_STAND_BY: /* H: off, V: on, display off */ - LTemp |= H_SYNC_OFF | DISPLAY_OFF; - break; - case B_DPMS_SUSPEND: /* H: on, V: off, display off */ - LTemp |= V_SYNC_OFF | DISPLAY_OFF; - break; - case B_DPMS_OFF: /* H: off, V: off, display off */ - LTemp |= H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF; - break; - default: - return B_ERROR; - } - /* FIXME - write the bits */ - *regs = LTemp; - - /* - NOTE: if you're driving a device with a backlight (like a digital - LCD), you may want to turn off the backlight here when in a DPMS - power saving mode. - - if (dpms_flags == B_DPMS_ON) - // turn on the back light - ; - else - // turn off the back light - ; - */ - - return B_OK; -} - -/* - Report device DPMS capabilities. Most newer cards can do it all. - I've only seen one older card that can do a subset (ON and OFF). - Very early cards may not be able to do this at all. - */ -uint32 DPMS_CAPABILITIES (void) -{ - return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; + 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; } /* - Return the current DPMS mode. + 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. */ -uint32 DPMS_MODE (void) +static void +SetDisplayMode(display_mode* dm) { - uint32 LTemp; - uint32 mode = B_DPMS_ON; + // 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. - /* read the control bits from the device */ - /* FIXME - read the bits */ - LTemp = *regs; - - /* what mode is set? */ - switch (LTemp & (H_SYNC_OFF | V_SYNC_OFF)) - { - case 0: /* H: on, V: on */ - mode = B_DPMS_ON; - break; - case H_SYNC_OFF: /* H: off, V: on */ - mode = B_DPMS_STAND_BY; - break; - case V_SYNC_OFF: /* H: on, V: off */ - mode = B_DPMS_SUSPEND; - break; - case (H_SYNC_OFF | V_SYNC_OFF): /* H: off, V: off */ - mode = B_DPMS_OFF; - break; - } - return mode; + 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/datatype.h b/src/add-ons/accelerants/s3savage/datatype.h deleted file mode 100644 index 5f19d90304..0000000000 --- a/src/add-ons/accelerants/s3savage/datatype.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - -#ifndef __DATA_TYPES_H__ -#define __DATA_TYPES_H__ - - -#define TEXT_MODE_SIZE 256*1024 -#define TEXT_FONT_SIZE 32*1024 -#define DISPLAY_START 1024*0 - -#define CRTC_INDEX 0x3d4 -#define CRTC_DATA 0x3d5 -#define SEQ_INDEX 0x3c4 -#define SEQ_DATA 0x3c5 - -typedef unsigned char byte_t; -typedef unsigned short word_t; -typedef unsigned long dword_t; - -extern byte_t vga_mode_numbers[]; - -typedef struct -{ - byte_t col; - byte_t row; - byte_t height; - byte_t buf_size0; - byte_t buf_size1; - byte_t seq_regs[0x04]; - byte_t misc_output; - byte_t crtc_regs[0x19]; - byte_t attr_regs[0x14]; - byte_t graph_regs[0x09]; -} VGAMode; - -typedef struct -{ - byte_t col; - byte_t row; - byte_t height; - byte_t buf_size0; - byte_t buf_size1; - byte_t seq_regs[0x04]; - byte_t misc_output; - byte_t crtc_regs[0x19]; - byte_t attr_regs[0x14]; - byte_t graph_regs[0x09]; - byte_t refresh_rate; - word_t pixel_size; - word_t pixel_width; - word_t pixel_height; - byte_t sr12; - byte_t sr13; - byte_t sr29; - byte_t misc_ctrl; - byte_t cr43; - byte_t cr50; - byte_t cr51; - byte_t cr5d; - byte_t cr5e; - byte_t cr5f; - byte_t cr66; - byte_t cr67; - byte_t cr31; - byte_t cr58; - byte_t cr69; -} SVGAMode; - -typedef struct -{ - byte_t s3mode; - byte_t mode_tab0; - byte_t mode_tab1; - byte_t mode_attr; - byte_t cr66; - byte_t cr67; - byte_t seq4; - byte_t patch0; - byte_t patch1; -} SVGAModeInfo; - -typedef struct -{ - byte_t crtc0; - byte_t crtc1; - byte_t rate_attr; - byte_t rate_freq; - byte_t sr13; - byte_t sr12; - byte_t sr29; - byte_t misc_ctrl; - byte_t cr50; - byte_t cr5d; - byte_t cr5e; -} SVGAPatchTable; - - -#endif /* __DATA_TYPES_H__ */ diff --git a/src/add-ons/accelerants/s3savage/s3accel.c b/src/add-ons/accelerants/s3savage/s3accel.c deleted file mode 100644 index bec24c537b..0000000000 --- a/src/add-ons/accelerants/s3savage/s3accel.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#include "datatype.h" -#include "s3mmio.h" -#include "s3accel.h" -#include "s3drv.h" - - -#define MIX_MASK 0x000f - -#define MIX_NOT_DST 0x0000 -#define MIX_0 0x0001 -#define MIX_1 0x0002 -#define MIX_DST 0x0003 -#define MIX_NOT_SRC 0x0004 -#define MIX_XOR 0x0005 -#define MIX_XNOR 0x0006 -#define MIX_SRC 0x0007 -#define MIX_NAND 0x0008 -#define MIX_NOT_SRC_OR_DST 0x0009 -#define MIX_SRC_OR_NOT_DST 0x000a -#define MIX_OR 0x000b -#define MIX_AND 0x000c -#define MIX_SRC_AND_NOT_DST 0x000d -#define MIX_NOT_SRC_AND_DST 0x000e -#define MIX_NOR 0x000f - - -byte_t s3alu[16] = -{ - MIX_0, - MIX_AND, - MIX_SRC_AND_NOT_DST, - MIX_SRC, - MIX_NOT_SRC_AND_DST, - MIX_DST, - MIX_XOR, - MIX_OR, - MIX_NOR, - MIX_XNOR, - MIX_NOT_DST, - MIX_SRC_OR_NOT_DST, - MIX_NOT_SRC, - MIX_NOT_SRC_OR_DST, - MIX_NAND, - MIX_1 -}; - - -byte_t * __vga_base = 0; -byte_t * __mmio_base = 0; -dword_t s3accelCmd = 0; - - -typedef struct -{ - S3DriverContext * s3dc; - byte_t * mmio_base; - byte_t * vga_base; - byte_t * bci_base; - byte_t * fb_base; - int fb_size; - word_t device_id; - dword_t global_bd; - dword_t primary_bd; - dword_t secondary_bd; - int bpp; - int logical_width; - int logical_height; -} S3AccelContext; - -static S3AccelContext S3AC = { 0 }; - - -int s3accel_init (S3DriverContext * s3dc) -{ - byte_t sr1; - int stride; - int display_start; - - if (!s3dc) return 0; - S3AC.s3dc = s3dc; - S3AC.mmio_base = __mmio_base = S3AC.s3dc->mmio_base; - S3AC.vga_base = __vga_base = S3AC.s3dc->vga_base; - S3AC.fb_base = S3AC.s3dc->fb_base; - S3AC.fb_size = S3AC.s3dc->fb_size; - S3AC.bpp = S3AC.s3dc->bpp; - S3AC.logical_width = S3AC.s3dc->logical_width; - - s3drv_unlock_regs (); - write32 (S3AC.mmio_base + 0x850C, 0x11); - write32 (S3AC.mmio_base + 0x850C, 0x11); - S3AC.device_id = read16 (__vga_base + 2); - sr1 = read_sr (__vga_base, 1); - write_sr (__vga_base, 1, sr1 | 0x20); - - UpdateGEReg (ALT_CURXY, 0); - UpdateGEReg (ALT_STEP, 0); - UpdateGEReg (ERR_TERM, 0); - UpdateGEReg (SHORT_STROKE,0); - UpdateGEReg (BKGD_COLOR, 0x00000000); - UpdateGEReg (FRGD_COLOR, 0xffffffff); - UpdateGEReg (WRT_MASK, 0xffffffff); - UpdateGEReg (RD_MASK, 0xffffffff); - UpdateGEReg (COLOR_CMP, 0x00000000); - UpdateGEReg (ALT_MIX, 0x00270007); - UpdateGEReg (SCISSORS_LT, 0x20001000); - UpdateGEReg (SCISSORS_RB, 0x4fff3fff); - UpdateGEReg (PIX_CNTL, 0xd000a000); - UpdateGEReg (MULT_MISC, 0xf000e200); - UpdateGEReg (ALT_PCNT, 0); - - display_start = S3AC.s3dc->display_start; - s3drv_dpf ("display_start = %d\n", display_start); - write32 (__mmio_base + 0x81c0, display_start); - stride = (S3AC.logical_width * S3AC.bpp + 7) >> 3; - write32 (__mmio_base + 0x81c8, stride); /* set stride */ - write32 (__mmio_base + 0x8168, display_start); - S3AC.global_bd = (S3AC.logical_width & 0x1ff0)|(S3AC.bpp<<16)|0x10000001; - /* Need to write GBD twice after an engine reset */ - write32 (__mmio_base + 0x816c, S3AC.global_bd); - write32 (__mmio_base + 0x816c, S3AC.global_bd); - S3AC.s3dc->global_bd = S3AC.global_bd; - write_sr (__vga_base, 1, sr1); - s3drv_lock_regs (); - return 1; -} - -int s3accel_wait_for_idle () -{ - s3drv_wait_for_idle (); - UpdateGEReg (WRT_MASK, 0xffffffff); - UpdateGEReg (RD_MASK, 0xffffffff); - UpdateGEReg (ALT_MIX, 0x00270007); - UpdateGEReg (SCISSORS_LT, 0x20001000); - UpdateGEReg (SCISSORS_RB, 0x4fff3fff); - UpdateGEReg (PIX_CNTL, 0xd000a000); - - return 1; -} - -int s3accel_wait_for_fifo (int count) -{ - int i; - s3drv_wait_for_idle (); - i = 0; - return i; -} - -__inline__ void s3accel_set_fg_color (dword_t color) -{ - s3accel_wait_for_fifo (1); - UpdateGEReg (FRGD_COLOR, color); -} - -__inline__ void s3accel_set_bg_color (dword_t color) -{ - s3accel_wait_for_fifo (1); - UpdateGEReg (BKGD_COLOR, color); -} - -void s3accel_set_clip_rect (int x1, int y1, int x2, int y2) -{ - s3accel_wait_for_fifo (2); - UpdateGEReg (SCISSORS_LT, (y1 << 16) | (x1 & 0xffff)); - UpdateGEReg (SCISSORS_RB, (y2 << 16) | (x2 & 0xffff)); -} - -#if S3ACCEL_NEED_FUNCTIONS - -void s3accel_setup_fill_rect (int color, int rop, dword_t planemask) -{ - s3accel_wait_for_fifo (2); - UpdateGEReg (WRT_MASK, planemask); - UpdateGEReg16 (FRGD_MIX, 0x0020 | s3alu[rop]); - s3drv_dpf ("FRGD_MIX is 0x%4X\n", 0x0020 | s3alu[rop]); - UpdateGEReg (FRGD_COLOR, color); - s3accelCmd = 0x40b1; -} - -void s3accel_repeat_fill_rect (int x, int y, int w, int h) -{ - w--; h--; - s3accel_wait_for_fifo (2); - UpdateGEReg (ALT_CURXY, (x<<16)|y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, 0x000040b1); -} - -void s3accel_fill_rect (int x, int y, int w, int h) -{ - w--; h--; - UpdateGEReg16 (FRGD_MIX, 0x0027); - write32 (__mmio_base + ALT_CURXY, (x<<16)|y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, 0x000040b1); -} - -__inline__ void s3accel_setup_copy_rect ( - int xdir, int ydir, int rop, dword_t planemask, - int transparency_color) -{ - s3accelCmd = 0xc011; - if (xdir == 1) s3accelCmd |= 0x20; - if (ydir == 1) s3accelCmd |= 0x80; - s3accel_wait_for_fifo (2); - UpdateGEReg (WRT_MASK, planemask); - if (transparency_color != -1) - { - UpdateGEReg (COLOR_CMP, transparency_color); - UpdateGEReg16 (PIX_CNTL, 0xa100); - } - UpdateGEReg16 (FRGD_MIX, 0x0060 | s3alu[rop]); -} - -__inline__ void s3accel_repeat_copy_rect ( - int src_x, int src_y, int dest_x, int dest_y, int w, int h) -{ - w--; h--; - if (!(s3accelCmd & 0x20)) - { - src_x += w; dest_x += w; - } - if (!(s3accelCmd & 0x80)) - { - src_y += h; dest_y += h; - } - - s3accel_wait_for_fifo (4); - UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y); - UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, s3accelCmd); -} - -void s3accel_copy_rect (int is_patterned, int src_x, int src_y, - int dest_x, int dest_y, int w, int h) -{ - int cmd = 0xc0b1; - - w--; h--; - if (is_patterned) - cmd |= 0x4000; - else - { - if ((src_x < dest_x) )//&& (src_x + w) > dest_x) - { - src_x += w; dest_x += w; - cmd ^= 32; - } - if ((src_y < dest_y) )//&& (src_y + h) > dest_y) - { - src_y += h; dest_y += h; - cmd ^= 128; - } - } - - UpdateGEReg16 (FRGD_MIX, 0x0067); - UpdateGEReg (ALT_CURXY, (src_x<<16)|src_y); - UpdateGEReg (ALT_STEP, (dest_x<<16)|dest_y); - UpdateGEReg (ALT_PCNT, (w<<16)|h); - UpdateGEReg (CMD, cmd); -} - -void s3accel_draw_line (int x1, int y1, int x2, int y2, int no_endpoint) -{ - int cmd = 0x20b1; - int min, max, err_term, *tmp=&max; - - /* - max = max(abs(x2-x1),abs(y2-y1)); - min = min(abs(x2-x1),abs(y2-y1)); - */ - - max = x2 - x1; - min = y2 - y1; - - if (max < 0) - { - max = -max; - cmd ^= 32; - } - - if (min < 0) - { - min = -min; - cmd ^= 128; - } - - if (max < min) - { - max = min; - min = &tmp; - cmd |= 0x40; - } - - err_term = 2 * min - max; - if (!(cmd & 0x20)) err_term --; - if (no_endpoint) cmd |= 4; - - s3accel_wait_for_idle (); - UpdateGEReg16 (FRGD_MIX, 0x0027); - UpdateGEReg (ALT_CURXY, (x1<<16)|y1); - /* Databook says MAJ_AXIS_PCNT = max - 1, - but MAJ_AXIS_PCNT = max seems to produce correct result. */ - UpdateGEReg16 (MAJ_AXIS_PCNT, max); - UpdateGEReg (ALT_STEP, ((2*(min-max))<<16)|(2*min)); - UpdateGEReg (ERR_TERM, err_term); - UpdateGEReg (CMD, cmd); -} - - -void s3accel_repeat_draw_line ( - int x1, int y1, int x2, int y2, dword_t bias) -{ - s3accel_draw_line (x1, y1, x2, y2, bias & 0x100); -} - - -void s3accel_write_image (int x, int y, int w, int h) -{ - int count; - - count = (((w * S3AC.bpp) + 31) >> 5) * h; - w--; h--; - s3accel_wait_for_idle (); - UpdateGEReg16 (FRGD_MIX, 0x0047); - UpdateGEReg (ALT_CURXY, (x<<16)|y); /* destination */ - UpdateGEReg (ALT_PCNT, (w<<16)|h); /* width/height */ - UpdateGEReg (CMD, 0x55b1); - - while (count --) { write32 (__mmio_base, ~0); } -} -#endif /* S3ACCEL_NEED_FUNCTIONS */ diff --git a/src/add-ons/accelerants/s3savage/s3accel.h b/src/add-ons/accelerants/s3savage/s3accel.h deleted file mode 100644 index 99dff9fe88..0000000000 --- a/src/add-ons/accelerants/s3savage/s3accel.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#ifndef __S3ACCEL_H__ -#define __S3ACCEL_H__ - - -#include "s3drv.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum -{ - ALT_CURXY = 0x8100, - CUR_Y = 0x8100, - CUR_X = 0x8102, - ALT_STEP = 0x8108, - DESTY_AXSTP = 0x8108, - DESTX_DIASTP = 0x810a, - ERR_TERM = 0x8110, - CMD = 0x8118, - SHORT_STROKE = 0x811c, - BKGD_COLOR = 0x8120, - FRGD_COLOR = 0x8124, - WRT_MASK = 0x8128, - RD_MASK = 0x812c, - COLOR_CMP = 0x8130, - ALT_MIX = 0x8134, - BKGD_MIX = 0x8134, - FRGD_MIX = 0x8136, - SCISSORS_LT = 0x8138, - SCISSORS_T = 0x8138, - SCISSORS_L = 0x813a, - SCISSORS_RB = 0x813c, - SCISSORS_B = 0x813c, - SCISSORS_R = 0x813e, - PIX_CNTL = 0x8140, - MULT_MISC2 = 0x8142, - MULT_MISC = 0x8144, - READ_SEL = 0x8144, - ALT_PCNT = 0x8148, - MIN_AXIS_PCNT = 0x8148, - MAJ_AXIS_PCNT = 0x814a -} S3GERegister; - -extern byte_t s3alu[16]; -extern byte_t * __vga_base; -extern byte_t * __mmio_base; - - -#define UpdateGEReg(reg, val)\ - write32 (__mmio_base + reg, val);\ - -#define UpdateGEReg16(reg, val)\ - write16 (__mmio_base + reg, val);\ - - -/* - * Function prototypes. - */ -extern int s3accel_init (S3DriverContext * s3dc); -extern int s3accel_wait_for_idle (); -extern int s3accel_wait_for_fifo (int count); -extern void s3accel_set_pattern (); -extern void s3accel_set_fg_color (dword_t fg_color); -extern void s3accel_set_bg_color (dword_t bg_color); -extern void s3accel_set_clip_rect (int x1, int y1, int x2, int y2); - -extern void s3accel_setup_copy_rect ( - int xdir, int ydir, int rop, - dword_t planemask, int transparency_color); -extern void s3accel_repeat_copy_rect ( - int x1, int y1, int x2, int y2, int w, int h); -extern void s3accel_copy_rect (int is_patterned, int src_x, int src_y, - int dest_x, int dest_y, int w, int h); - -extern void s3accel_setup_fill_rect (int color, int rop, dword_t planemask); -extern void s3accel_repeat_fill_rect (int x, int y, int w, int h); -extern void s3accel_fill_rect (int x, int y, int w, int h); - -extern void s3accel_fill_polygon (); -extern void s3accel_setup_fill_polygon (); -extern void s3accel_repeat_fill_polygon (int count, short * xw); - -extern void s3accel_draw_line (int x1, int y1, int x2, int y2, - int no_endpoint); -extern void s3accel_draw_polyline (int count, short * xy); -extern void s3accel_draw_segments (int count, short * xy); -extern void s3accel_setup_draw_line (); -extern void s3accel_repeat_draw_line (int x1, int y1, int x2, int y2, - dword_t bias); - -extern void s3accel_draw_scanline (); -extern void s3accel_setup_draw_scanline (); -extern void s3accel_repeat_draw_scanline (int x, int width); -extern void s3accel_draw_multi_scanlines (int count, int starty, short * xw); - -extern void s3accel_write_image (int x, int y, int w, int h); -extern void s3accel_write_bitmap (); - - -#ifdef __cplusplus -} -#endif - - -#endif /* __S3ACCEL_H__ */ diff --git a/src/add-ons/accelerants/s3savage/s3drv.c b/src/add-ons/accelerants/s3savage/s3drv.c deleted file mode 100644 index 2f2e950376..0000000000 --- a/src/add-ons/accelerants/s3savage/s3drv.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#include "s3mmio.h" -#include "s3drv.h" -#include "DriverInterface.h" - -#include -#include - - -extern int __s3drv_get_svga_mode ( - SVGAMode * svgamode, PixelTiming * pixel_timing); - -static S3DriverContext S3DC = -{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -void s3drv_dpf (const char * format, ...) -{ -#if DEBUG > 0 - va_list args; - char buffer[4096]; - - va_start (args, format); - vsprintf (buffer, format, args); - fputs (buffer, stderr); - va_end (args); -#endif -} - -S3DriverContext * s3drv_get_context () -{ - return &S3DC; -} - -int s3drv_init (byte_t * mb) -{ - if (!mb) return 0; - S3DC.mmio_base = mb; - S3DC.vga_base = mb + 0x8000; - S3DC.device_id = read16 (S3DC.vga_base + 2); - S3DC.viewport_x = 0; - S3DC.viewport_y = 0; - S3DC.display_start = DISPLAY_START; - write32 (mb + 0x8510, 1); - return 1; -} - - -static int __reg_unlock_count = 0; - -void s3drv_lock_regs () -{ - __reg_unlock_count --; - if (__reg_unlock_count < 1) - { - __reg_unlock_count = 0; - s3_lock_regs (S3DC.vga_base); - } -} - -void s3drv_unlock_regs () -{ - s3_unlock_regs (S3DC.vga_base); - __reg_unlock_count ++; -} - -int s3drv_detect_vram_mb_size (byte_t * vram_start, int max_mb) -{ - int ram_size_mb; - byte_t * vga_base = S3DC.vga_base; - - s3drv_unlock_regs (); - - if (vram_start) - { - byte_t cr58, cr66; - byte_t * magic_spot; - - if (!vga_base) return 2; - if (!vram_start) return 2; - - magic_spot = vram_start + 1024*1024; - cr58 = read_cr (vga_base, 0x58); - write_cr (vga_base, 0x58, 0x13); - cr66 = read_cr (vga_base, 0x66); - write_cr (vga_base, 0x66, cr66 | 1); - for (ram_size_mb = 1; ram_size_mb < max_mb; ram_size_mb ++) - { - read32 (vga_base); - write32 (magic_spot, 0xC55CC55C); - if (read32 (magic_spot) != 0xC55CC55C) break; - write32 (vram_start, 0); - write32 (magic_spot, 0xFFFFFFFF); - if (read32 (vram_start) == 0xFFFFFFFF) break; - magic_spot += 1024*1024; - } - write_cr (vga_base, 0x58, cr58); - write_cr (vga_base, 0x66, cr66); - } - else - { - byte_t cr36; - word_t device; - - device = (read_cr (vga_base, 0x2d) << 8) | read_cr (vga_base, 0x2e); - cr36 = read_cr (vga_base, 0x36); - ram_size_mb = 2; - if (isSavage4Family(device)) - { - switch (cr36 >> 5) - { - case 0: - ram_size_mb = 2; - break; - case 1: - ram_size_mb = 4; - case 2: - ram_size_mb = 8; - break; - case 3: - ram_size_mb = 12; - break; - case 4: - ram_size_mb = 16; - break; - case 5: - ram_size_mb = 32; - break; - case 6: - ram_size_mb = 64; - break; - case 7: - ram_size_mb = 128; - break; - case 8: - ram_size_mb = 256; - break; - } - } - else - { - switch (cr36 >> 6) - { - case 0: - ram_size_mb = 8; - break; - case 1: - case 2: - ram_size_mb = 4; - break; - case 3: - ram_size_mb = 2; - break; - } - } - } - - s3drv_lock_regs (); - - return ram_size_mb; -} - -int s3drv_is_text_mode () -{ - return !(read_gr (S3DC.vga_base, 0x06) & 1); -} - -int s3drv_save_font (byte_t * vram, byte_t * font_buf, int buf_size) -{ - int i; - byte_t * font; - byte_t * plane2; - if (!font_buf) return 0; - font = font_buf; - plane2 = vram + 2; - *font = *plane2; - for (i = 0; i < buf_size; i ++) *(font++) = *(plane2+=4); - return 1; -} - -int s3drv_restore_font (byte_t * vram, byte_t * font_buf, int buf_size) -{ - int i; - byte_t * font; - byte_t * plane2; - if (!font_buf) return 0; - plane2 = vram + 2; - font = font_buf; - *plane2 = *font; - for (i = 0; i < buf_size; i ++) *(plane2+=4) = *(font++); - return 1; -} - -int s3drv_get_mode (PixelTiming * timing, int bpp, - byte_t * mode_buf, int buf_size) -{ - SVGAMode * s3mode; - if (!timing || !mode_buf) return 0; - if (buf_size < sizeof (SVGAMode)) return - sizeof (SVGAMode); - - s3mode = (SVGAMode*) mode_buf; - - __s3drv_get_svga_mode(s3mode, timing); - s3mode->pixel_size = bpp; - s3mode->pixel_width = timing->x.disp; - s3mode->pixel_height = timing->y.disp; - s3mode->seq_regs[0] = 0x01; - s3mode->seq_regs[1] = 0x0F; - s3mode->seq_regs[2] = 0x00; - s3mode->seq_regs[3] = 0x0E; - s3mode->attr_regs[0x10] = 0x01; - s3mode->attr_regs[0x11] = 0x00; - s3mode->attr_regs[0x12] = 0x0F; - s3mode->attr_regs[0x13] = 0x00; - s3mode->graph_regs[0] = 0x00; - s3mode->graph_regs[1] = 0x00; - s3mode->graph_regs[2] = 0x00; - s3mode->graph_regs[3] = 0x00; - s3mode->graph_regs[4] = 0x00; - s3mode->graph_regs[5] = 0x00; - s3mode->graph_regs[6] = 0x05; - s3mode->graph_regs[7] = 0x0F; - s3mode->graph_regs[8] = 0xFF; - s3mode->misc_ctrl = s3mode->misc_output & 0xc0; - s3mode->cr31 = 0x0d; - /* Savage3D and Savage/MX need double horizontal timing for 16bpp */ - s3mode->cr43 = (!isSavage4Family(S3DC.device_id) && - (((bpp + 7)/8) == 2) ) ? 0x80 : 0; - s3mode->cr50 = 0xC1 | ((((bpp+7)>>3) - 1) << 4); - s3mode->cr51 = - (((s3mode->pixel_width * s3mode->pixel_size + 31) >> 6) & 0x300) >> 4; - s3mode->cr58 = 0x13; - s3mode->cr66 = 0x89; - - switch (bpp) - { - case 8: - s3mode->cr67 = 0x00; - break; - case 15: - s3mode->cr67 = 0x20; - break; - case 16: - s3mode->cr67 = 0x40; - break; - case 32: - s3mode->cr67 = 0xd0; - break; - default: - s3mode->cr67 = 0x00; - } - s3mode->cr69 = 0x80; - return 1; -} - -int s3drv_display_is_off () -{ - return read_sr (S3DC.vga_base, 0x01) & 0x20; -} - -void s3drv_turn_display_off () -{ - write_sr (S3DC.vga_base, 0x01, read_sr (S3DC.vga_base, 0x01) | 0x20); -} - -void s3drv_turn_display_on () -{ - byte_t sr1 = read_sr (S3DC.vga_base, 0x01) & ~0x20; - s3drv_wait_for_vsync (); - write_sr (S3DC.vga_base, 0x01, sr1); -} - -int s3drv_set_logical_width (int width) -{ - if (width >= S3DC.width) - { - int stride; - width += 15; - width &= ~15; - stride = (width * S3DC.bpp + 7) >> 3; - S3DC.logical_width = width; - write32 (S3DC.mmio_base + 0x81c8, stride); /* set stride */ - if (S3DC.global_bd) - { - S3DC.global_bd = (S3DC.global_bd & 0xffffe00f) | stride; - write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd); - write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd); - } - } - - return S3DC.logical_width; -} - -int s3drv_adjust_viewport (int x, int y) -{ - int viewport_start; - - if (x < 0 || y < 0) return 0; - S3DC.viewport_x = x; - S3DC.viewport_y = y; - viewport_start = ((y * S3DC.logical_width + x) * S3DC.bpp + 7) / 8; - viewport_start += S3DC.display_start; - if (S3DC.bpp == 32) - { - S3DC.cursor_adjustment = (viewport_start & 15) / 4; - viewport_start &= ~15; - } - write32 (S3DC.mmio_base + 0x81c0, viewport_start); - return 1; -} - -int s3drv_set_display_start (int offset) -{ - if (offset > -1) - { - S3DC.display_start = offset + DISPLAY_START; - write32 (S3DC.mmio_base + 0x8168, S3DC.display_start); - s3drv_adjust_viewport (S3DC.viewport_x, S3DC.viewport_y); - } - return offset; -} - -void s3drv_wait_for_vsync () -{ - int i; - if (!s3drv_display_is_off ()) - for (i = 0; i < 1000; i ++) - if ( (read8 (S3DC.vga_base + 0x3da) & 9) == 9) break; -} - -void s3drv_wait_for_idle () -{ - int i; - if (isSavage4Family(S3DC.device_id)) for (i = 0; i < 10000000; i ++) - { - if ( (read32 (S3DC.mmio_base + 0x48c00) & 0x5e01ffff) == 0x5e000000) - break; - } - else for (i = 0; i < 10000000; i ++) - { - if ( (read32 (S3DC.mmio_base + 0x48c00) & 0x005fffff) == 0x005e0000) - break; - } -} - -int s3drv_set_cursor_color (dword_t fg_color, dword_t bg_color) -{ - read_cr (S3DC.vga_base, 0x45); - if (S3DC.bpp != 8) - { - write_cr (S3DC.vga_base, 0x4a, fg_color >> 16); - write_cr (S3DC.vga_base, 0x4a, fg_color >> 8); - } - write_cr (S3DC.vga_base, 0x4a, fg_color); - - read_cr (S3DC.vga_base, 0x45); - if (S3DC.bpp != 8) - { - write_cr (S3DC.vga_base, 0x4b, bg_color >> 16); - write_cr (S3DC.vga_base, 0x4b, bg_color >> 8); - } - write_cr (S3DC.vga_base, 0x4b, bg_color); - - return 1; -} - -/* Assume width and height are byte-aligned. */ - -int s3drv_load_cursor ( - byte_t * lfb, int offset, int width, int height, - byte_t * and_mask, byte_t * xor_mask) -{ - int i, x, y, bit_shift; - byte_t and_buf[512]; - byte_t xor_buf[512]; - byte_t * and_ptr = (byte_t*)and_mask; - byte_t * xor_ptr = (byte_t*)xor_mask; - - if (!lfb || !and_mask || !xor_mask) return 0; - - bit_shift = width & 7; - width /= 8; - - if (width != 64 || height != 64) - { - and_ptr = (byte_t*)and_buf; - xor_ptr = (byte_t*)xor_buf; - - for (y = 0; y < height; y ++) - { - for (x = 0; x < width; x ++) - { - *and_ptr ++ = *and_mask ++; - *xor_ptr ++ = *xor_mask ++; - } - - if (bit_shift) - { - x ++; - *and_ptr ++ = 0xFF ^ ((*and_mask ++) & (~(0xFF >> bit_shift))); - *xor_ptr ++ = (*xor_mask ++) & (~(0xFF >> bit_shift)); - } - - for ( ; x < 8; x ++) - { - *and_ptr ++ = 0xFF; - *xor_ptr ++ = 0x00; - } - } - - for ( ; y < 64; y ++) - { - *(dword_t*)and_ptr = ~0; and_ptr += 4; - *(dword_t*)and_ptr = ~0; and_ptr += 4; - *(dword_t*)xor_ptr = 0; xor_ptr += 4; - *(dword_t*)xor_ptr = 0; xor_ptr += 4; - } - - and_ptr = (byte_t*)and_buf; - xor_ptr = (byte_t*)xor_buf; - } - - lfb += offset * 1024; - write_cr (S3DC.vga_base, 0x4d, offset); - write_cr (S3DC.vga_base, 0x4c, offset >> 8); - - for (i = 0; i < 256; i ++) - { -#if 0 - dword_t tmp = (*(word_t*)and_ptr << 16) | *(word_t*)xor_ptr; - *(dword_t*)lfb = tmp; lfb += 4; -#else - write16 (lfb, *(word_t*)and_ptr); - lfb += 2; - write16 (lfb, *(word_t*)xor_ptr); - lfb += 2; -#endif - and_ptr += 2; xor_ptr += 2; - } - - return 1; -} - -void s3drv_move_cursor (int x, int y) -{ - int xoff = 0, yoff = 0; - - x += S3DC.cursor_adjustment; - if (x < 0) - { - xoff = (x < -63) ? 63 : -x; - x = 0; - } - if (y < 0) - { - yoff = (y < -63) ? 63 : -y; - y = 0; - } - - write_cr (S3DC.vga_base, 0x46, (x & 0xff00) >> 8); - write_cr (S3DC.vga_base, 0x47, (x & 0xff)); - write_cr (S3DC.vga_base, 0x49, (y & 0xff)); - write_cr (S3DC.vga_base, 0x4e, (xoff)); - write_cr (S3DC.vga_base, 0x4f, (yoff)); - write_cr (S3DC.vga_base, 0x48, (y & 0xff00) >> 8); -} - -void s3drv_show_cursor () -{ - write_cr (S3DC.vga_base, 0x45, read_cr (S3DC.vga_base, 0x45) | 1); -} - -void s3drv_hide_cursor () -{ - write_cr (S3DC.vga_base, 0x45, read_cr (S3DC.vga_base, 0x45) & ~1); -} - -void s3drv_set_palette (int index, int red, int green, int blue) -{ - byte_t * vga_base = S3DC.vga_base; - write8 (vga_base + 0x3c8, index); - write8 (vga_base + 0x3c9, red); - write8 (vga_base + 0x3c9, green); - write8 (vga_base + 0x3c9, blue); -} - -void s3drv_get_palette (int index, int *red, int *green, int *blue) -{ - byte_t * vga_base = S3DC.vga_base; - write8 (vga_base + 0x3c7, index); - *red = read8 (vga_base + 0x3c9); - *green = read8 (vga_base + 0x3c9); - *blue = read8 (vga_base + 0x3c9); -} - -int s3drv_save_mode (byte_t * mode_buf, int buf_size) -{ - int i; - byte_t * vga_base = S3DC.vga_base; - SVGAMode * mode = (SVGAMode*)(mode_buf); - - if (!mode_buf || buf_size < sizeof (SVGAMode)) - { - return - sizeof (SVGAMode); - } - - s3drv_unlock_regs (); - for (i = 0; i < 4; i ++) mode->seq_regs[i] = read_sr (vga_base, i+1); - mode->misc_output = read8 (vga_base + 0x3cc); - for (i = 0; i < 0x19; i ++) mode->crtc_regs[i] = read_cr (vga_base, i); - for (i = 0; i < 0x14; i ++) mode->attr_regs[i] = read_ar (vga_base, i); - for (i = 0; i < 0x09; i ++) mode->graph_regs[i] = read_gr (vga_base, i); - mode->refresh_rate = 0xff; - mode->sr12 = read_sr (vga_base, 0x12); - mode->sr13 = read_sr (vga_base, 0x13); - mode->sr29 = read_sr (vga_base, 0x29); - mode->misc_ctrl = mode->misc_output & 0xc0; - mode->cr43 = read_cr (vga_base, 0x43); - mode->cr50 = read_cr (vga_base, 0x50); - mode->cr51 = read_cr (vga_base, 0x51); - mode->cr5d = read_cr (vga_base, 0x5d); - mode->cr5e = read_cr (vga_base, 0x5e); - mode->cr5f = read_cr (vga_base, 0x5f); - mode->cr66 = read_cr (vga_base, 0x66); - mode->cr67 = read_cr (vga_base, 0x67); - mode->cr31 = read_cr (vga_base, 0x31); - mode->cr58 = read_cr (vga_base, 0x58); - mode->cr69 = read_cr (vga_base, 0x69); - mode->pixel_width = - ( ( ((mode->cr5f & 0x0c) << 7) | - ((mode->cr5d & 0x02) << 7) | - ( mode->crtc_regs[1] ) ) + 1 ) * 8; - mode->pixel_height = 1 + - ( ((mode->cr5e & 0x02) << 9) | - ((mode->crtc_regs[0x07] & 0x40) << 3) | - ((mode->crtc_regs[0x07] & 0x02) << 7) | - ( mode->crtc_regs[0x12] ) ); - - switch ( (mode->cr67 & 0xf0) >> 4) - { - case 0: - case 1: - mode->pixel_size = (read_cr (vga_base, 0x3a) & 0x10) ? 8 : 4; - break; - case 2: - case 3: - mode->pixel_size = 15; - break; - case 4: - case 5: - mode->pixel_size = 16; - break; - case 0xd: - mode->pixel_size = 32; - break; - default: - mode->pixel_size = 8; - } - s3drv_lock_regs (); - - return sizeof (SVGAMode); -} - -static word_t crtc_reg_defaults[] = -{ - 0x4838, 0xa539, 0x0531, 0x4032, 0x0833, 0x0034, 0x0035, 0x053a, - 0x103c, 0x0040, 0x0042, 0x0043, 0x0045, 0x0050, 0x0051, 0x0053, - 0x0055, 0x0058, 0x005d, 0x005e, 0x005f, 0x005b, 0x0066, 0x0067, - 0x0069, 0x006a, 0xc071, 0x0090, - 0x0087, 0x3070, 0xc071, 0x0772, 0x1f73, 0x1f74, 0x1f75, 0x0f76, - 0x1f77, 0x0178, 0x0179, 0x1f7a, 0x1f7b, 0x171c, 0x177d, 0x177e, - 0x0060, - 0x0000 -}; - -static word_t seq_reg_defaults[] = -{ - 0x0608, 0x0014, 0x4018, 0x0029, 0x601c, - 0x0000 -}; - -int s3drv_restore_mode (byte_t * mode_buf, int buf_size, int restore_vga) -{ - int i; - byte_t cr3a; - byte_t * vga_base = S3DC.vga_base; - SVGAMode * mode = (SVGAMode*)(mode_buf); - if (!mode || buf_size < sizeof (SVGAMode)) - { - return - sizeof (SVGAMode); - } - - if (mode->pixel_size) S3DC.bpp = mode->pixel_size; - if (mode->pixel_width) S3DC.width = mode->pixel_width; - if (mode->pixel_height) S3DC.height = mode->pixel_height; - if (!S3DC.logical_width) S3DC.logical_width = mode->pixel_width; - S3DC.display_start = 0; - - s3drv_unlock_regs (); - write_sr (vga_base, 0x01, read_sr (vga_base, 0x01) | 0x20); - for (i = 0; crtc_reg_defaults[i] != 0; i ++) - write16 (vga_base + CRTC_INDEX, crtc_reg_defaults[i]); - for (i = 0; seq_reg_defaults[i] != 0; i ++) - write16 (vga_base + SEQ_INDEX, seq_reg_defaults[i]); - if (restore_vga > 0) - { - write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) & 0x7f); - for (i = 1; i < 4; i ++) - write_sr (vga_base, i+1, mode->seq_regs[i]); - for (i = 0; i < 0x0c; i ++) - write_cr (vga_base, i, mode->crtc_regs[i]); - for (i = 0x10; i < 0x19; i ++) - write_cr (vga_base, i, mode->crtc_regs[i]); - for (i = 0; i < 0x14; i ++) - write_ar (vga_base, i, mode->attr_regs[i]); - for (i = 0; i < 0x09; i ++) - write_gr (vga_base, i, mode->graph_regs[i]); - } - - write8 (vga_base + 0x3c2, 0x23); - write_sr (vga_base, 0x15, (mode->misc_ctrl & 0x10) | 2); - write8 (vga_base + 0x3c2, - ((mode->misc_output & 0x3f) | - (mode->misc_ctrl & 0xc0))); - if ((mode->misc_output & 0x0c) == 0x0c) - { - write_sr (vga_base, 0x12, mode->sr12); - write_sr (vga_base, 0x13, mode->sr13); - write_sr (vga_base, 0x29, mode->sr29); - } - - if (mode->refresh_rate != 0) - { - write_cr (vga_base, 0x43, mode->cr43); - write_cr (vga_base, 0x50, mode->cr50); - write_cr (vga_base, 0x51, mode->cr51); - write_cr (vga_base, 0x5d, mode->cr5d); - write_cr (vga_base, 0x5e, mode->cr5e); - write_cr (vga_base, 0x5e, mode->cr5f); - write_cr (vga_base, 0x66, mode->cr66); - write_cr (vga_base, 0x67, mode->cr67); - write_cr (vga_base, 0x31, mode->cr31); - write_cr (vga_base, 0x58, mode->cr58); - write_cr (vga_base, 0x69, mode->cr69); - } - - /* Turn off hardware graphics cursor */ - - write_cr (vga_base, 0x45, read_cr (vga_base, 0x45) & ~1); - cr3a = read_cr (vga_base, 0x3a); - - /* Set attribute controller for enhanced mode */ - if (mode->pixel_size < 8) cr3a &= ~0x10; - else cr3a |= 0x10; - write_cr (vga_base, 0x3a, cr3a); - - /* RAMDAC mask */ - write8 (vga_base + 0x3c6, 0xff); - - write_sr (vga_base, 0x01, mode->seq_regs[0]); - s3drv_lock_regs (); - - if (mode->cr66 & 1) - { - write32 (S3DC.mmio_base + 0x81c0, S3DC.display_start); - write32 (S3DC.mmio_base + 0x81c8, /* set stride */ - (S3DC.logical_width * S3DC.bpp + 7) >> 3); - write32 (S3DC.mmio_base + 0x8168, S3DC.display_start); - /* Need to write GBD twice after an engine reset */ - if (S3DC.global_bd) - { - write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd); - write32 (S3DC.mmio_base + 0x816c, S3DC.global_bd); - } - } - - return 1; -} - - diff --git a/src/add-ons/accelerants/s3savage/s3drv.h b/src/add-ons/accelerants/s3savage/s3drv.h deleted file mode 100644 index f10dc1d255..0000000000 --- a/src/add-ons/accelerants/s3savage/s3drv.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#ifndef __S3DRV_H__ -#define __S3DRV_H__ - - -#include "datatype.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - word_t disp; - word_t sync_start; - word_t sync_end; - word_t total; - word_t polarity; -} CrtcTiming; - -typedef struct -{ - dword_t dot_clock_khz; - CrtcTiming x; - CrtcTiming y; -} PixelTiming; - -typedef struct -{ - byte_t * mmio_base; - byte_t * vga_base; - byte_t * rom_base; - byte_t * fb_base; - word_t device_id; - int fb_size; - int vram_size; - dword_t bpp; - dword_t width; - dword_t height; - dword_t logical_width; - dword_t display_start; - dword_t global_bd; - word_t viewport_x; - word_t viewport_y; - int cursor_adjustment; -} S3DriverContext; - - -extern void s3drv_dpf (const char * format, ...); -extern S3DriverContext * s3drv_get_context (); -extern int s3drv_init (byte_t * mmio_base); -extern void s3drv_lock_regs (); -extern void s3drv_unlock_regs (); -extern int s3drv_detect_vram_mb_size ( - byte_t * vram_start, int max_mb); - -extern int s3drv_is_text_mode (); -extern int s3drv_save_font ( - byte_t * vram, byte_t * font_buf, int buf_size); -extern int s3drv_restore_font ( - byte_t * vram, byte_t * font_buf, int buf_size); -extern int s3drv_get_mode ( - PixelTiming * timing, int bpp, - byte_t * mode_buf, int buf_size); -#if 0 -extern int s3drv_get_gtf_mode ( - int width, int height, int depth, - int rrate, byte_t * mode_buf, - int buf_size); -#endif -extern int s3drv_get_bios_mode ( - int vesamode, int refresh_rate, - byte_t * mode_buf, int buf_size, - byte_t * rom); -extern int s3drv_save_mode ( - byte_t * mode_buf, int buf_size); -extern int s3drv_restore_mode ( - byte_t * mode_buf, int buf_size, - int restore_vga); - -extern int s3drv_display_is_off (); -extern void s3drv_turn_display_off (); -extern void s3drv_turn_display_on (); - -extern int s3drv_set_logical_width (int width); -extern int s3drv_adjust_viewport (int x, int y); -extern int s3drv_set_display_start (int offset); - -extern void s3drv_wait_for_vsync (); -extern void s3drv_wait_for_idle (); - -extern int s3drv_set_cursor_color ( - dword_t foreground, dword_t background); -extern int s3drv_load_cursor ( - byte_t * lfb, int offset, int width, int height, - byte_t * image, byte_t * mask); -extern void s3drv_move_cursor (int x, int y); -extern void s3drv_show_cursor (); -extern void s3drv_hide_cursor (); - -extern void s3drv_set_palette ( - int index, int red, - int green, int blue); -extern void s3drv_get_palette ( - int index, int *red, - int *green, int *blue); - -#ifdef __cplusplus -} -#endif - - -#endif /* __S3DRV_H__ */ diff --git a/src/add-ons/accelerants/s3savage/s3mmio.h b/src/add-ons/accelerants/s3savage/s3mmio.h deleted file mode 100644 index 541f8c980b..0000000000 --- a/src/add-ons/accelerants/s3savage/s3mmio.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#ifndef __S3MMIO_H__ -#define __S3MMIO_H__ - -#include "datatype.h" - -#ifdef __STRICT_ANSI__ - -#undef __inline__ -#define __inline__ -#define read8(addr) (*(volatile byte_t*) (addr)) -#define read16(addr) (*(volatile word_t*) (addr)) -#define read32(addr) (*(volatile dword_t*) (addr)) -#define write8(addr, val) ((*(volatile byte_t*) (addr)) = (byte_t) (val)) -#define write16(addr, val) ((*(volatile word_t*) (addr)) = (word_t) (val)) -#define write32(addr, val) ((*(volatile dword_t*) (addr)) = (dword_t) (val)) - -#else - -static __inline__ byte_t read8 (byte_t * addr) -{ - return *(volatile byte_t*) addr; -} - -static __inline__ word_t read16 (byte_t * addr) -{ - return *(volatile word_t*) addr; -} - -static __inline__ dword_t read32 (byte_t *addr) -{ - return *(volatile dword_t*) addr; -} - -static __inline__ void write8 (byte_t * addr, byte_t val) -{ - *(volatile byte_t*) addr = val; -} - -static __inline__ void write16 (byte_t * addr, word_t val) -{ - *(volatile word_t*) addr = val; -} - -static __inline__ void write32 (byte_t * addr, dword_t val) -{ - *(volatile dword_t*) addr = val; -} - -#endif /* __STRICT_ANSI__ */ - - -static __inline__ byte_t read_sr (byte_t * vga_base, byte_t reg) -{ - write8 (vga_base + SEQ_INDEX, reg); - return read8 (vga_base + SEQ_DATA); -} - -static __inline__ void write_sr (byte_t * vga_base, byte_t reg, byte_t val) -{ - write16 (vga_base + SEQ_INDEX, (val << 8) | reg); -} - -static __inline__ byte_t read_cr (byte_t * vga_base, byte_t reg) -{ - write8 (vga_base + CRTC_INDEX, reg); - return read8 (vga_base + CRTC_DATA); -} - -static __inline__ void write_cr (byte_t * vga_base, byte_t reg, byte_t val) -{ - write16 (vga_base + CRTC_INDEX, (val << 8) | reg); -} - -static __inline__ byte_t read_gr (byte_t * vga_base, byte_t reg) -{ - write8 (vga_base + 0x3ce, reg); - return read8 (vga_base + 0x3cf); -} - -static __inline__ void write_gr (byte_t * vga_base, byte_t reg, byte_t val) -{ - write16 (vga_base + 0x3ce, (val << 8) | reg); -} - -static __inline__ byte_t read_ar (byte_t * vga_base, byte_t reg) -{ - byte_t value, index; - read8 (vga_base + 0x3da); - index = read8 (vga_base + 0x3c0); - write8 (vga_base + 0x3c0, reg); - value = read8 (vga_base + 0x3c1); - read8 (vga_base + 0x3da); - write8 (vga_base + 0x3c0, index); - return value; -} - -static __inline__ void write_ar (byte_t * vga_base, byte_t reg, byte_t val) -{ - byte_t index; - read8 (vga_base + 0x3da); - index = read8 (vga_base + 0x3c0); - write8 (vga_base + 0x3c0, reg); - write8 (vga_base + 0x3c0, val); - write8 (vga_base + 0x3c0, index); -} - -static __inline__ void s3_lock_regs (byte_t * vga_base) -{ - write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) | 0x80); - write_cr (vga_base, 0x33, (0x50 | read_cr (vga_base, 0x33)) & ~2); - write_cr (vga_base, 0x38, 0x00); - write_cr (vga_base, 0x39, 0x00); - write_sr (vga_base, 0x08, 0x00); -} - -static __inline__ void s3_unlock_regs (byte_t * vga_base) -{ - write_sr (vga_base, 0x08, 0x06); - write_cr (vga_base, 0x38, 0x48); - write_cr (vga_base, 0x39, 0xa0); - write_cr (vga_base, 0x40, 0x01); - write_cr (vga_base, 0x11, read_cr (vga_base, 0x11) & 0x7f); - write_cr (vga_base, 0x33, (~0x50 & read_cr (vga_base, 0x33)) | 2); - write_cr (vga_base, 0x35, 0x00); -} - - -#endif /* __S3MMIO_H__ */ diff --git a/src/add-ons/accelerants/s3savage/s3vga.c b/src/add-ons/accelerants/s3savage/s3vga.c deleted file mode 100644 index 62bb5d75bd..0000000000 --- a/src/add-ons/accelerants/s3savage/s3vga.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 1999 Erdi Chen - */ - - -#include "datatype.h" -#include "s3drv.h" - -#define BASE_FREQ 14.318 - -static int pll_limits[] = -{ - 1, 511, /* min M, max M */ - 1, 127, /* min N, max N */ - 0, 4, /* min R, max R */ - 317500, 635000 /* min VCO, max VCO */ -}; - -typedef struct -{ - word_t h_display_end; - word_t h_sync_start; - word_t h_sync_end; - word_t h_total; - word_t h_polarity; - word_t v_display_end; - word_t v_sync_start; - word_t v_sync_end; - word_t v_total; - word_t v_polarity; - word_t h_blank_start; - word_t h_blank_end; - word_t v_blank_start; - word_t v_blank_end; -} CharTiming; - - -static int vga_convert_timing(int pixel_per_char, - CharTiming * char_timing, - PixelTiming * pixel_timing) -{ - int i, blank_offset; - char_timing->h_total = pixel_timing->x.total / pixel_per_char; - char_timing->h_sync_start = pixel_timing->x.sync_start / pixel_per_char; - char_timing->h_sync_end = pixel_timing->x.sync_end / pixel_per_char; - char_timing->h_display_end = pixel_timing->x.disp / pixel_per_char; -#if 0 - char_timing->h_blank_start = char_timing->h_display_end; - char_timing->h_blank_end = char_timing->h_sync_end + 1; -#else - blank_offset = (pixel_timing->x.disp * 3 + 100) / 200; - if (blank_offset < 2) blank_offset = 2; - char_timing->h_blank_start = char_timing->h_display_end + blank_offset; - char_timing->h_blank_end = char_timing->h_total - blank_offset; - i = char_timing->h_blank_end - char_timing->h_blank_start - 127; - if (i > 0) - { - char_timing->h_blank_start += (i + 1) / 2; - char_timing->h_blank_end -= i / 2; - } - char_timing->h_blank_end ++; -#endif - char_timing->v_total = pixel_timing->y.total; - char_timing->v_sync_start = pixel_timing->y.sync_start; - char_timing->v_sync_end = pixel_timing->y.sync_end; - char_timing->v_display_end = pixel_timing->y.disp; - char_timing->v_blank_start = char_timing->v_display_end + 7; - char_timing->v_blank_end = (char_timing->v_total + 7) - 0x10; - - char_timing->h_polarity = (pixel_timing->x.polarity ? 1 : 0) << 6; - char_timing->v_polarity = (pixel_timing->y.polarity ? 1 : 0) << 7; - - return 1; -} - -static int vga_get_mode (VGAMode * vgamode, - CharTiming * char_timing, - PixelTiming * pixel_timing) -{ - word_t line_compare; - word_t double_scan; - word_t row_width; - word_t mem_addr_size; - word_t pixel_per_addr; - - if (!vgamode || !pixel_timing) return 0; - - double_scan = 0; - line_compare = 0x3ff; - mem_addr_size = 4; - pixel_per_addr = 1; - row_width = 2 * pixel_timing->x.disp / (pixel_per_addr * mem_addr_size); - - char_timing->h_total -= 5; - char_timing->h_display_end --; - char_timing->v_total -= 2; - char_timing->v_display_end --; - char_timing->v_sync_start --; - char_timing->v_sync_end --; - - vgamode->misc_output = 3 | - (!char_timing->h_polarity) << 6 | - (!char_timing->v_polarity) << 7; - - vgamode->crtc_regs[0x00] = char_timing->h_total & 0xff; - vgamode->crtc_regs[0x01] = char_timing->h_display_end & 0xff; - vgamode->crtc_regs[0x02] = char_timing->h_blank_start & 0xff; - vgamode->crtc_regs[0x03] = 0x80 | (char_timing->h_blank_end & 0x1f); - vgamode->crtc_regs[0x04] = char_timing->h_sync_start & 0xff; - vgamode->crtc_regs[0x05] = ((char_timing->h_blank_end & 0x20) << 2) | - (char_timing->h_sync_end & 0x1f); - vgamode->crtc_regs[0x06] = char_timing->v_total & 0xff; - vgamode->crtc_regs[0x07] = ((char_timing->v_total & 0x100) >> 8) | - ((char_timing->v_display_end & 0x100) >> 7) | - ((char_timing->v_sync_start & 0x100) >> 6) | - ((char_timing->v_blank_start & 0x100) >> 5) | - ((line_compare & 0x100) >> 4) | - ((char_timing->v_total & 0x200) >> 4) | - ((char_timing->v_display_end & 0x200) >> 3) | - ((char_timing->v_sync_start & 0x200) >> 2); - vgamode->crtc_regs[0x08] = 0; - vgamode->crtc_regs[0x09] = (double_scan & 0x80) | - ((char_timing->v_blank_start & 0x200) >> 4) | - ((line_compare & 0x200) >> 3); - vgamode->crtc_regs[0x2a] = 0; - vgamode->crtc_regs[0x0b] = 0; - vgamode->crtc_regs[0x0c] = 0; - vgamode->crtc_regs[0x0d] = 0; - vgamode->crtc_regs[0x0e] = 0xff; - vgamode->crtc_regs[0x0f] = 0; - vgamode->crtc_regs[0x10] = char_timing->v_sync_start & 0xff; - vgamode->crtc_regs[0x11] = (char_timing->v_sync_end & 0x0f) | 0x80; - vgamode->crtc_regs[0x12] = char_timing->v_display_end & 0xff; - vgamode->crtc_regs[0x13] = row_width & 0xff; - vgamode->crtc_regs[0x14] = ((mem_addr_size > 3) ? 0x60 : 0); - vgamode->crtc_regs[0x15] = char_timing->v_blank_start & 0xff; - vgamode->crtc_regs[0x16] = char_timing->v_blank_end & 0xff; - vgamode->crtc_regs[0x17] = ((mem_addr_size == 1) ? 0x40 : 0x08) | 0xa3; - vgamode->crtc_regs[0x18] = line_compare & 0xff; - - return 1; -} - -/* -------------------------------------------------------------- - * 1, 511, min M, max M - * 1, 127, min N, max N - * 0, 4, min R, max R - * 317500, 635000 min VCO, max VCO - * --------------------------------------------------------------*/ -void __s3drv_encode_clock (long freq, int * pll_limits, - int * mdiv, int * ndiv, int * pll_r) -{ - double ffreq, ffreq_min, ffreq_max; - double div, diff, best_diff; - int m; - int n, r; - int best_n = 16 + 2; - int best_r = 2; - int best_m = 125 + 2; - - int min_m, max_m; - int min_n, max_n; - int min_r, max_r; - long freq_min, freq_max; - - min_m = pll_limits[0]; max_m = pll_limits[1]; - min_n = pll_limits[2]; max_n = pll_limits[3]; - min_r = pll_limits[4]; max_r = pll_limits[5]; - freq_min = pll_limits[6]; freq_max = pll_limits[7]; - - ffreq = freq / 1000.0 / BASE_FREQ; - ffreq_min = freq_min / 1000.0 / BASE_FREQ; - ffreq_max = freq_max / 1000.0 / BASE_FREQ; - - if (ffreq < ffreq_min / (1< ffreq_max / (1< max_m + 2) - continue; - div = (double)(m) / (double)(n); - - if ((div >= ffreq_min) && - (div <= ffreq_max)) - { - diff = ffreq - div / (1 << r); - if (diff < 0.0) - diff = -diff; - if (diff < best_diff) - { - best_diff = diff; - best_m = m; - best_n = n; - best_r = r; - } - } - } - } - - *ndiv = best_n - 2; - *pll_r = best_r; - *mdiv = best_m - 2; -} - -static void __s3drv_convert_clock (SVGAMode * svgamode, dword_t dot_clock_khz) -{ - int m, n, r; - - __s3drv_encode_clock (dot_clock_khz, & pll_limits[0], &m, &n, &r); - svgamode->sr12 = (n & 0x3f) | ((r & 0x3) << 6); - svgamode->sr13 = (m & 0xff); - svgamode->sr29 = (r & 0x04) | ((m & 0x100) >> 5) | ((n & 0x40) >> 2); -} - -int __s3drv_get_svga_mode(SVGAMode * svgamode, - PixelTiming * pixel_timing) -{ - int blank_width, sync_width; - dword_t dot_clock; - CharTiming char_timing; - - if (!svgamode || !pixel_timing) return 0; - - vga_convert_timing (8, & char_timing, pixel_timing); - vga_get_mode ((VGAMode*) svgamode, & char_timing, pixel_timing); - svgamode->misc_output |= 0x0c; - dot_clock = pixel_timing->dot_clock_khz; - if (!dot_clock) - { - svgamode->refresh_rate = 60; - dot_clock = pixel_timing->x.total * pixel_timing->y.total * 60 / 1000; - } - else - svgamode->refresh_rate = dot_clock * 1000 / - (pixel_timing->x.total * pixel_timing->y.total); - __s3drv_convert_clock (svgamode, dot_clock); - - blank_width = char_timing.h_blank_end - char_timing.h_blank_start; - sync_width = char_timing.h_sync_end - char_timing.h_sync_start; - svgamode->cr5d |= (char_timing.h_total & 0x100) >> 8 | - (char_timing.h_display_end & 0x100) >> 7 | - (char_timing.h_blank_start & 0x100) >> 6 | - (char_timing.h_sync_start & 0x100) >> 4; - if (blank_width > 32) svgamode->cr5d |= 0x20; - if (sync_width > 64) svgamode->cr5d |= 0x04; - - svgamode->cr5e = (char_timing.v_total & 0x400) >> 10 | - (char_timing.v_display_end & 0x400) >> 9 | - (char_timing.v_blank_start & 0x400) >> 8 | - (char_timing.v_sync_start & 0x400) >> 6; - - svgamode->cr5f |= (char_timing.h_total & 0x600) >> 9 | - (char_timing.h_display_end & 0x600) >> 7 | - (char_timing.h_blank_start & 0x600) >> 5 | - (char_timing.h_sync_start & 0x600) >> 3; - - return 1; -} diff --git a/src/add-ons/accelerants/s3savage/savage.h b/src/add-ons/accelerants/s3savage/savage.h new file mode 100644 index 0000000000..fbb5b3b936 --- /dev/null +++ b/src/add-ons/accelerants/s3savage/savage.h @@ -0,0 +1,263 @@ +/* + 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 SavageLoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); +void SavageSetCursorColors(int bg, int fg); +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 new file mode 100644 index 0000000000..9be90d5452 --- /dev/null +++ b/src/add-ons/accelerants/s3savage/savage_accel.c @@ -0,0 +1,768 @@ +/* + 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 new file mode 100644 index 0000000000..9842021479 --- /dev/null +++ b/src/add-ons/accelerants/s3savage/savage_cursor.c @@ -0,0 +1,209 @@ +/* + Haiku S3 Savage driver adapted from the original BeSavage driver by + Erdi Chen and the X.org Savage driver. + + Copyright 1999 Erdi Chen + 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 ); +} + + +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* and_mask, uint8* xor_mask) +{ + int i, x, y, bit_shift; + uint8 and_buf[64*64 / 8]; + uint8 xor_buf[64*64 / 8]; + uint8* and_ptr = and_mask; + uint8* xor_ptr = xor_mask; + uint16* pFB; + +//@ TRACE(("SavageLoadCursorImage\n")); + + if ( ! and_mask || ! xor_mask) + return false; + + bit_shift = width & 7; + width /= 8; + + if (width != 64 || height != 64) { + and_ptr = (uint8*)and_buf; + xor_ptr = (uint8*)xor_buf; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + *and_ptr++ = *and_mask++; + *xor_ptr++ = *xor_mask++; + } + + if (bit_shift) { + x++; + *and_ptr++ = 0xFF ^ ((*and_mask++) & (~(0xFF >> bit_shift))); + *xor_ptr++ = (*xor_mask++) & (~(0xFF >> bit_shift)); + } + + for (; x < 8; x++) { + *and_ptr++ = 0xFF; + *xor_ptr++ = 0x00; + } + } + + for (; y < 64; y++) { + *(uint32 *)and_ptr = ~0; + and_ptr += 4; + *(uint32 *)and_ptr = ~0; + and_ptr += 4; + *(uint32 *)xor_ptr = 0; + xor_ptr += 4; + *(uint32 *)xor_ptr = 0; + xor_ptr += 4; + } + + and_ptr = (uint8 *)and_buf; + xor_ptr = (uint8 *)xor_buf; + } + + /* Set cursor location in video memory. */ + WriteCrtc(0x4d, (0xff & si->cursorOffset / 1024)); + WriteCrtc(0x4c, (0xff00 & si->cursorOffset / 1024) >> 8); + + pFB = (void *)((addr_t)si->videoMemAddr + si->cursorOffset); + + for (i = 0; i < 64 * 64 / 16; i++) { + *pFB++ = *(uint16*)and_ptr; + *pFB++ = *(uint16*)xor_ptr; + + and_ptr += 2; + xor_ptr += 2; + } + + 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 new file mode 100644 index 0000000000..abe6d7ba57 --- /dev/null +++ b/src/add-ons/accelerants/s3savage/savage_dpms.c @@ -0,0 +1,133 @@ +/* + 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 new file mode 100644 index 0000000000..e83b788b0f --- /dev/null +++ b/src/add-ons/accelerants/s3savage/savage_driver.c @@ -0,0 +1,1253 @@ +/* + 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; + + /* OK, I admit it. I don't know how to limit the max dot clock + * for LCD panels of various sizes. I thought I copied the formula + * from the BIOS, but many users have informed me of my folly. + * + * Instead, I'll abandon any attempt to automatically limit the + * clock, and add an LCDClock option to XF86Config. Some day, + * I should come back to this. + */ + + 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 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/s3savage/driver.c b/src/add-ons/kernel/drivers/graphics/s3savage/driver.c index 6f3e7a1136..38e7331b9f 100644 --- a/src/add-ons/kernel/drivers/graphics/s3savage/driver.c +++ b/src/add-ons/kernel/drivers/graphics/s3savage/driver.c @@ -1,85 +1,123 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. -*/ -/* - * Copyright 1999 Erdi Chen - */ + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. -#include "DriverInterface.h" + 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 -#include -#include -#include -#define DEBUG 0 -#if DEBUG > 0 -#define ddprintf(a) dprintf a + +#ifdef DEBUG +#define TRACE(a) TraceLog a #else -#define ddprintf(a) +#define TRACE(a) #endif -#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) + +#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 MAX_DEVICES 8 +#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 = 2; +int32 api_version = B_CUR_DRIVER_API_VERSION; /* these structures are private to the kernel driver */ -typedef struct device_info device_info; -#if defined(POST_R4_0) typedef struct { - timer te; /* timer entry for add_timer() */ - device_info *di; /* pointer to the owning device */ - bigtime_t when_target; /* when we're supposed to wake up */ -} timer_info; -#endif + 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; -struct device_info +/* This table maps a PCI device ID to a chipset family identifier and the chipset + name. */ +static ChipInfo SavageChipTable[] = { - uint32 is_open; /* a count of how many times the devices has been opened */ - area_id shared_area; /* the area shared between the driver and all of the accelerants */ - shared_info *si; /* a pointer to the shared area, for convenience */ - vuint32 *regs; /* kernel's pointer to memory mapped registers */ - int32 can_interrupt; /* when we're faking interrupts, let's us know if we should generate one */ -#if defined(POST_R4_0) - timer_info ti_a; /* a pool of two timer managment buffers */ - timer_info ti_b; - timer_info *current_timer; /* the timer buffer that's currently in use */ -#else - thread_id tid; -#endif -#if DEBUG > 0 - uint32 interrupt_count; /* if we're debugging, a count of how many times the interrupt handler has - been called for this device */ -#endif - 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 */ + { 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 { -#if DEBUG > 0 - uint32 total_interrupts; /* total number of interrupts seen by our handler */ -#endif - uint32 count; /* number of devices actually found */ - benaphore kernel; /* for serializing opens/closes */ - char *device_names[MAX_DEVICES+1]; /* device name pointer storage */ - device_info di[MAX_DEVICES]; /* device specific stuff */ + 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); @@ -87,925 +125,693 @@ 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(device_info *di); -static void unmap_device(device_info *di); +static status_t map_device(DeviceInfo *di); +static void unmap_device(DeviceInfo *di); static void probe_devices(void); static int32 savage_interrupt(void *data); -#if DEBUG > 0 -static int savagedump(int argc, char **argv); +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 DEBUG +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 + -static DeviceData *pd; -static pci_module_info *pci_bus; -static device_hooks graphics_device_hooks = +// 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() { - open_hook, - close_hook, - free_hook, - control_hook, - read_hook, - write_hook, - NULL, - NULL, - NULL, - NULL -}; + // return true only if a vertical blanking interrupt has occured + return false; +} -#define VENDOR_ID 0x5333 /* S3 Incorporated, S3 Graphics */ -static uint16 savage_device_list[] = +static void +ClearVBI() { - PCI_PID_SAVAGE3D, - PCI_PID_SAVAGE3DMV, - PCI_PID_SAVAGE4_2, - PCI_PID_SAVAGEMXMV, - PCI_PID_SAVAGEMX, - PCI_PID_SAVAGEIXMV, - PCI_PID_SAVAGEIX, +} - PCI_PID_SAVAGE4_3, - PCI_PID_SAVAGE2000, - PCI_PID_PM133, - PCI_PID_KM133, - PCI_PID_PN133, - PCI_PID_KN133, - PCI_PID_KM266, - PCI_PID_PN266, - 0 -}; +static void +EnableVBI() +{ +} -static struct +static void +DisableVBI() { - uint16 vendor; - uint16 *devices; -} SupportedDevices[] = +} + + + +static ChipInfo* +FindDeviceMatch(uint16 vendorID, uint16 deviceID) { - {VENDOR_ID, savage_device_list}, - {0x0000, NULL} -}; + // 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 one is - found, otherwise returns B_ERROR so the driver will be unloaded. + 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 +status_t init_hardware(void) { - long pci_index = 0; - pci_info pcii; - bool found_one = FALSE; - - /* 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; + long pci_index = 0; + pci_info pcii; + ChipInfo* pDevice = NULL; - /* while there are more pci devices */ - while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) - { - int vendor = 0; - - ddprintf(("SKD: init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, pcii.vendor_id, pcii.device_id)); - /* if we match a supported vendor */ - while (SupportedDevices[vendor].vendor) - { - if (SupportedDevices[vendor].vendor == pcii.vendor_id) - { - uint16 *devices = SupportedDevices[vendor].devices; - /* while there are more supported devices */ - while (*devices) - { - /* if we match a supported device */ - if (*devices == pcii.device_id ) - { - - ddprintf(("SKD: we support this device\n")); - found_one = TRUE; - goto done; - } - /* next supported device */ - devices++; - } - } - vendor++; - } - /* next pci_info struct, please */ - pci_index++; - } - ddprintf(("SKD: init_hardware - no supported devices\n")); + /* 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; -done: - /* put away the module manager */ - put_module(B_PCI_MODULE_NAME); - return (found_one ? B_OK : 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) + +status_t init_driver(void) { - ddprintf(("SKD: 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; +// TRACE(("enter init_driver\n")); - /* driver private data */ - pd = (DeviceData *)calloc(1, sizeof(DeviceData)); - if (!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(); -#if DEBUG > 0 - add_debugger_command("savagedump", savagedump, "dump SAVAGE kernel driver persistant data"); -#endif - ddprintf(("SKD: leave init_driver\n")); - return B_OK; + /* 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 ** + +const char** publish_devices(void) { - /* return the list of supported devices */ - return (const char **)pd->device_names; + /* return the list of supported devices */ + return (const char **)pd->deviceNames; } -device_hooks * + +device_hooks* find_device(const char *name) { - int index = 0; - while (pd->device_names[index]) - { - if (strcmp(name, pd->device_names[index]) == 0) - return &graphics_device_hooks; - index++; - } - return NULL; - + 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) + +void + uninit_driver(void) { -#if DEBUG > 0 - remove_debugger_command("savagedump", savagedump); -#endif + /* free the driver data */ + DELETE_BEN(pd->kernel); + free(pd); + pd = NULL; - /* free the driver data */ - DELETE_BEN(pd->kernel); - free(pd); - pd = NULL; - - /* put the pci module away */ - put_module(B_PCI_MODULE_NAME); + /* put the pci module away */ + put_module(B_PCI_MODULE_NAME); } -static status_t map_device(device_info *di) + +static status_t +map_device(DeviceInfo *di) { - /* default: frame buffer in [0], control regs in [1] */ - char buffer[B_OS_NAME_LENGTH]; - shared_info *si = di->si; - uint32 tmpUlong; - pci_info *pcii = &(di->pcii); - uint32 fb_base = 0; - uint32 regs_base = 0; - uint fb_size = 0; - uint regs_size = 0; + /* 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; - ddprintf(("SKD: enter map_device\n")); - /* enable memory mapped IO, disable VGA I/O */ - tmpUlong = get_pci(PCI_command, 4); - tmpUlong |= 0x00000002; - tmpUlong &= 0xfffffffe; - set_pci(PCI_command, 4, tmpUlong); + TRACE(("enter map_device\n")); - /* enable ROM decoding */ - tmpUlong = get_pci(PCI_rom_base, 4); - tmpUlong |= 0x00000001; - set_pci(PCI_rom_base, 4, tmpUlong); + /* 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); - switch (pcii->device_id) - { - case PCI_PID_SAVAGE3D: - case PCI_PID_SAVAGE3DMV: - case PCI_PID_SAVAGE4_2: - case PCI_PID_SAVAGEMXMV: - case PCI_PID_SAVAGEMX: - case PCI_PID_SAVAGEIXMV: - case PCI_PID_SAVAGEIX: - fb_base = di->pcii.u.h0.base_registers[0]; - fb_size = 16*1024*1024; - regs_base = di->pcii.u.h0.base_registers[0] + 0x1000000; - regs_size = 1024*1024; - break; - case PCI_PID_SAVAGE4_3: - case PCI_PID_SAVAGE2000: - case PCI_PID_PM133: - case PCI_PID_KM133: - case PCI_PID_PN133: - case PCI_PID_PN266: - case PCI_PID_KN133: - case PCI_PID_KM266: - fb_base = di->pcii.u.h0.base_registers[1]; - fb_size = 32*1024*1024; - regs_base = di->pcii.u.h0.base_registers[0]; - regs_size = 1024*1024; - break; - } + // 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. - /* map the areas */ - sprintf(buffer, "%04X_%04X_%02X%02X%02X regs", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - si->regs_area = map_physical_memory( - buffer, - (void *) regs_base, - regs_size, - 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->regs_area < 0) return si->regs_area; + 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] )); - sprintf(buffer, "%04X_%04X_%02X%02X%02X rom", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - si->rom_area = map_physical_memory( - buffer, - (void *)di->pcii.u.h0.rom_base, - di->pcii.u.h0.rom_size, - B_ANY_KERNEL_ADDRESS, - B_READ_AREA, - (void **)&(si->rom)); - /* return the error if there was some problem */ -#if 0 - if (si->rom_area < 0) - { - delete_area(si->regs_area); - si->regs_area = -1; - return si->rom_area; - } -#endif + /* 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); - sprintf(buffer, "%04X_%04X_%02X%02X%02X framebuffer", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - si->fb_area = map_physical_memory( - buffer, - (void *) fb_base, - fb_size, -#if defined(__INTEL__) -#if defined(POST_R4_0) - B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, -#else - B_ANY_KERNEL_ADDRESS | B_MTR_WC, -#endif -#else - B_ANY_KERNEL_BLOCK_ADDRESS, -#endif - B_READ_AREA + B_WRITE_AREA, - &(si->framebuffer)); + 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))); -#if defined(__INTEL__) - if (si->fb_area < 0) { - /* try to map this time without write combining */ - /* - After R4.0 (Intel), map_physical_memory() will try B_ANY_KERNEL_ADDRESS if - a call with B_ANY_KERNEL_BLOCK_ADDRESS would fail. It always worked this way - under PPC. - */ - si->fb_area = map_physical_memory( - buffer, - (void *) fb_base, - fb_size, -#if defined(POST_R4_0) - B_ANY_KERNEL_BLOCK_ADDRESS, -#else - B_ANY_KERNEL_ADDRESS, -#endif - B_READ_AREA + B_WRITE_AREA, - &(si->framebuffer)); - } -#endif - - /* if there was an error, delete our other areas */ - if (si->fb_area < 0) { - delete_area(si->regs_area); - si->regs_area = -1; - delete_area(si->rom_area); - si->rom_area = -1; - } - /* remember the DMA address of the frame buffer for BDirectWindow purposes */ - si->framebuffer_pci = (void *) fb_base; - /* in any case, return the result */ - ddprintf(("SKD: leave map_device\n")); - return si->fb_area; + /* 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(device_info *di) + +static void +unmap_device(DeviceInfo *di) { - shared_info *si = di->si; - uint32 tmpUlong; - pci_info *pcii = &(di->pcii); + SharedInfo *si = di->si; + uint32 tmpUlong; + pci_info *pcii = &(di->pcii); - ddprintf(("SKD: unmap_device(%08lx) begins...\n", (uint32)di)); - ddprintf(("\tregs_area: %ld\n\tfb_area: %ld\n", si->regs_area, si->fb_area)); - - /* disable memory mapped IO */ - tmpUlong = get_pci(PCI_command, 4); - tmpUlong &= 0xfffffffc; - set_pci(PCI_command, 4, tmpUlong); - /* disable ROM decoding */ - tmpUlong = get_pci(PCI_rom_base, 4); - tmpUlong &= 0xfffffffe; - set_pci(PCI_rom_base, 4, tmpUlong); - /* delete the areas */ - if (si->rom_area >= 0) delete_area(si->rom_area); - if (si->regs_area >= 0) delete_area(si->regs_area); - if (si->fb_area >= 0) delete_area(si->fb_area); - si->rom_area = si->regs_area = si->fb_area = -1; - si->framebuffer = NULL; - di->regs = NULL; - si->rom = NULL; - ddprintf(("SKD: unmap_device() ends.\n")); + 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) + +static void +probe_devices(void) { - uint32 pci_index = 0; - uint32 count = 0; - device_info *di = pd->di; + uint32 pci_index = 0; + uint32 count = 0; + DeviceInfo *di = pd->di; + ChipInfo* pDevice; - ddprintf(("SKD: 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)) - { - int vendor = 0; - - ddprintf(("SKD: 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 */ - while (SupportedDevices[vendor].vendor) - { - if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) - { - uint16 *devices = SupportedDevices[vendor].devices; - /* while there are more supported devices */ - while (*devices) - { - /* if we match a supported device */ - if (*devices == di->pcii.device_id ) - { - /* publish the device name */ - sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - ddprintf(("SKD: making /dev/%s\n", di->name)); - /* remember the name */ - pd->device_names[count] = di->name; - /* mark the driver as available for R/W open */ - di->is_open = 0; - /* mark areas as not yet created */ - di->shared_area = -1; - /* mark pointer to shared data as invalid */ - di->si = NULL; - /* inc pointer to device info */ - di++; - /* inc count */ - count++; - /* break out of these while loops */ - goto next_device; - } - /* next supported device */ - devices++; - } - } - vendor++; - } -next_device: - /* next pci_info struct, please */ - pci_index++; - } - /* propagate count */ - pd->count = count; - /* terminate list of device names with a null pointer */ - pd->device_names[pd->count] = NULL; - ddprintf(("SKD: probe_devices: %ld supported devices\n", pd->count)); +// 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(int32 *flags, vuint32 *regs, shared_info *si) + +static uint32 +thread_interrupt_work(DeviceInfo *di) { - 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; + 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 + +static int32 savage_interrupt(void *data) { - int32 handled = B_UNHANDLED_INTERRUPT; - device_info *di = (device_info *)data; - shared_info *si = di->si; - int32 *flags = &(si->flags); - vuint32 *regs; + int32 handled = B_UNHANDLED_INTERRUPT; + DeviceInfo *di = (DeviceInfo *)data; + int32 *flags = &(di->si->flags); -#if DEBUG > 0 - pd->total_interrupts++; -#endif + /* is someone already handling an interrupt for this device? */ + if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) + goto exit0; - /* is someone already handling an interrupt for this device? */ - if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) - { -#if DEBUG > 0 - kprintf("SKD: Already in handler!\n"); -#endif - goto exit0; - } - /* get regs */ - regs = di->regs; + if (InterruptIsVBI()) { // was the interrupt a VBI? + ClearVBI(); // clear the interrupt - /* read the interrrupt status register */ + handled = thread_interrupt_work(di); // release the semaphore + } - /* did this card cause an interrupt */ - if (1 /* replace this expression */) - { - /* do our stuff */ - handled = thread_interrupt_work(flags, regs, si); -#if DEBUG > 0 - /* increment the counter for this device */ - di->interrupt_count++; -#endif - /* clear the interrupt status */ - } - - /* note that we're not in the handler any more */ - atomic_and(flags, ~SKD_HANDLER_INSTALLED); + /* note that we're not in the handler any more */ + atomic_and(flags, ~SKD_HANDLER_INSTALLED); exit0: - return handled; + return handled; } -#if defined(POST_R4_0) -static int32 timer_interrupt_func(timer *te, uint32 pc) + +static status_t +open_hook (const char* name, uint32 flags, void** cookie) { - bigtime_t now = system_time(); - /* get the pointer to the device we're handling this time */ - device_info *di = ((timer_info *)te)->di; - shared_info *si = di->si; - int32 *flags = &(si->flags); - vuint32 *regs = di->regs; - uint32 vbl_status = 0 /* read vertical blank status */; - int32 result = B_HANDLED_INTERRUPT; + int32 index = 0; + DeviceInfo *di; + SharedInfo *si; + thread_id thid; + thread_info thinfo; + status_t result = B_OK; + char sharedName[B_OS_NAME_LENGTH]; - /* are we supposed to handle interrupts still? */ - if (atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) { - /* reschedule with same period by default */ - bigtime_t when = si->refresh_period; - timer *to; + (void)flags; // avoid compiler warning for unused arg - /* if interrupts are "enabled", do our job */ - if (di->can_interrupt) { - /* insert code to sync to interrupts here */ - if (!vbl_status) { - when -= si->blank_period - 4; - } - /* do the things we do when we notice a vertical retrace */ - result = thread_interrupt_work(flags, regs, si); + 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++; - /* pick the "other" timer */ - to = (timer *)&(di->ti_a); - if (to == te) to = (timer *)&(di->ti_b); - /* our guess when we should be back */ - ((timer_info *)to)->when_target = now + when; - /* reschedule the interrupt */ - add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, B_ONE_SHOT_ABSOLUTE_TIMER); - /* remember the currently active timer */ - di->current_timer = (timer_info *)to; - } + /* for convienience */ + di = &(pd->di[index]); - return result; -} -#else -static int32 fake_interrupt_thread_func(void *_di) -{ - device_info *di = (device_info *)_di; - shared_info *si = di->si; - int32 *flags = &(si->flags); - vuint32 *regs = di->regs; - - bigtime_t last_sync; - bigtime_t this_sync; - bigtime_t diff_sync; - - uint32 counter = 1; - - /* a lie, but we have to start somewhen */ - - last_sync = system_time() - 8333; - - ddprintf(("SKD: fake_interrupt_thread_func begins\ndi: 0x%08lx\nsi: 0x%08lx\nflags: 0x%08lx\n", (uint32)di, (uint32)si, (uint32)flags)); - - /* loop until notified */ - - while(atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) { - /* see if "interrupts" are enabled */ - - if((volatile int32)(di->can_interrupt)) { - /* poll the retrace flag until set */ - - /* YOUR CODE HERE */ - - /* get the system_time */ - this_sync = system_time(); - - /* do our stuff */ - thread_interrupt_work(flags, regs, si); - } else { - /* get the system_time */ - this_sync = system_time(); - } - - /* find out how long it took */ - diff_sync = this_sync - last_sync; - - /* back off a little so we're sure to catch the retrace */ - diff_sync -= diff_sync / 10; - - /* - impose some limits so we can recover from refresh rate changes - Supported refresh rates are 48 Hz - 120 Hz, so these limits should - be slightly wider. - */ - if(diff_sync < 8000) { - diff_sync = 8000; /* not less than 1/125th of sec */ - } - - if(diff_sync > 16666) { - diff_sync = 20000; /* not more than 1/40th of sec */ - } - - if((counter++ & 0x01ff) == 0) { - diff_sync >>= 2; /* periodically quarter the wait to resync */ - } - - /* update for next go-around */ - last_sync = this_sync; - - /* snooze until our next retrace */ - - snooze_until(this_sync + diff_sync, B_SYSTEM_TIMEBASE); - } - - ddprintf(("SKD: fake_interrupt_thread_func ends with flags = 0x%08lx\n", *flags)); - - /* gotta return something */ - - return B_OK; -} -#endif + /* make sure no one else has write access to the common data */ + AQUIRE_BEN(pd->kernel); -#if DEBUG > 0 -static int savagedump(int argc, char **argv) { - int i; + /* if it's already open for writing */ + if (di->is_open) { + /* mark it open another time */ + goto mark_as_open; + } - kprintf("SAVAGE Kernel Driver Persistant Data\n\nThere are %ld card(s)\n", pd->count); - kprintf("Driver wide benahpore: %ld/%ld\n", pd->kernel.ben, pd->kernel.sem); + /* 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; + } - kprintf("Total seen interrupts: %ld\n", pd->total_interrupts); - for (i = 0; i < pd->count; i++) { - device_info *di = &(pd->di[i]); - uint16 device_id = di->pcii.device_id; - shared_info *si = di->si; - kprintf(" device_id: 0x%04x\n", device_id); - kprintf(" interrupt count: %ld\n", di->interrupt_count); - if (si) { - kprintf(" cursor: %d,%d\n", si->cursor.x, si->cursor.y); - kprintf(" flags:"); - if (si->flags & SKD_MOVE_CURSOR) kprintf(" SKD_MOVE_CURSOR"); - if (si->flags & SKD_PROGRAM_CLUT) kprintf(" SKD_PROGRAM_CLUT"); - if (si->flags & SKD_SET_START_ADDR) kprintf(" SKD_SET_START_ADDR"); - kprintf(" vblank semaphore id: %ld\n", si->vblank); - } - kprintf("\n"); - } - return 1; /* the magic number for success */ -} -#endif + /* save a few dereferences */ + si = di->si; -static status_t open_hook (const char* name, uint32 flags, void** cookie) -{ - int32 index = 0; - device_info *di; - shared_info *si; - thread_id thid; - thread_info thinfo; - status_t result = B_OK; - vuint32 *regs; - char shared_name[B_OS_NAME_LENGTH]; + /* 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); - ddprintf(("SKD: open_hook(%s, %ld, 0x%08lx)\n", name, flags, (uint32)cookie)); + /* map the device */ + result = map_device(di); + if (result < 0) + goto free_shared; - /* find the device name in the list of devices */ - /* we're never passed a name we didn't publish */ - while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++; + result = B_OK; - /* for convienience */ - di = &(pd->di[index]); + DisableVBI(); // disable & clear any pending interrupts + si->bInterruptAssigned = false; // indicate interrupt not assigned yet - /* make sure no one else has write access to the common data */ - AQUIRE_BEN(pd->kernel); + /* create a semaphore for vertical blank management */ + si->vblank = create_sem(0, di->name); + if (si->vblank < 0) + goto mark_as_open; - /* 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(shared_name, "%04X_%04X_%02X%02X%02X 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->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 0); - if (di->shared_area < 0) { - /* return the error */ - result = di->shared_area; - goto done; - } + /* 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); - /* save a few dereferences */ - si = di->si; - - /* save the vendor and device IDs */ - si->vendor_id = di->pcii.vendor_id; - si->device_id = di->pcii.device_id; - si->revision = di->pcii.revision; - - /* map the device */ - result = map_device(di); - if (result < 0) goto free_shared; - result = B_OK; - - /* create a semaphore for vertical blank management */ - si->vblank = create_sem(0, di->name); - if (si->vblank < 0) { - result = si->vblank; - goto unmap; - } - - /* 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); - - /* assign local regs pointer for SAVAGExx() macros */ - regs = di->regs; - - /* disable and clear any pending interrupts */ - - /* if we're faking interrupts */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ - /* fake some kind of interrupt with a timer */ - di->can_interrupt = FALSE; - si->flags = SKD_HANDLER_INSTALLED; - si->refresh_period = 16666; /* fake 60Hz to start */ - si->blank_period = si->refresh_period / 20; -#if defined(POST_R4_0) - di->ti_a.di = di; /* refer to ourself */ - di->ti_b.di = di; - di->current_timer = &(di->ti_a); - /* program the first timer interrupt, and it will handle the rest */ - result = add_timer((timer *)(di->current_timer), timer_interrupt_func, si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER); - /* bail if we can't add the timer */ - if (result != B_OK) goto delete_the_sem; -#else - /* fake some kind of interrupt with a thread */ - result = di->tid = spawn_kernel_thread(fake_interrupt_thread_func, "SKD fake interrupt", B_REAL_TIME_DISPLAY_PRIORITY, di); - /* bail if we can't spawn the thread */ - if(result < 0) goto delete_the_sem; - /* start up the thread */ - resume_thread(di->tid); -#endif - } else { - /* otherwise install our interrupt handler */ - result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, (void *)di, 0); - /* bail if we couldn't install the handler */ - if (result != B_OK) goto delete_the_sem; - } + /* 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++; + /* mark the device open */ + di->is_open++; - /* send the cookie to the opener */ - *cookie = di; - - goto done; - - -delete_the_sem: - delete_sem(si->vblank); - -unmap: - unmap_device(di); + /* send the cookie to the opener */ + *cookie = di; + goto done; free_shared: - /* clean up our shared area */ - delete_area(di->shared_area); - di->shared_area = -1; - di->si = NULL; + /* clean up our shared area */ + delete_area(di->sharedArea); + di->sharedArea = -1; + di->si = NULL; done: - /* end of critical section */ - RELEASE_BEN(pd->kernel); + /* end of critical section */ + RELEASE_BEN(pd->kernel); - /* all done, return the status */ - ddprintf(("SKD: open_hook returning 0x%08lx\n", result)); - return result; -} - -/* ---------- - read_hook - does nothing, gracefully ------ */ -static status_t -read_hook (void* dev, off_t pos, void* buf, size_t* len) -{ - *len = 0; - return B_NOT_ALLOWED; + /* all done, return the status */ + TRACE(("open_hook returning 0x%08lx\n", result)); + return result; } /* ---------- - write_hook - does nothing, gracefully + read_hook - does nothing, gracefully ----- */ -static status_t -write_hook (void* dev, off_t pos, const void* buf, size_t* len) +static status_t +read_hook(void* dev, off_t pos, void* buf, size_t* len) { - *len = 0; - return B_NOT_ALLOWED; + // Following 3 lines of code are here to eliminate "unused parameter" warnings. + (void)dev; + (void)pos; + (void)buf; + + *len = 0; + return B_NOT_ALLOWED; } + + /* ---------- - close_hook - does nothing, gracefully + write_hook - does nothing, gracefully ----- */ -static status_t -close_hook (void* dev) +static status_t +write_hook(void* dev, off_t pos, const void* buf, size_t* len) { - ddprintf(("SKD: close_hook(%08lx)\n", (uint32)dev)); - /* we don't do anything on close: there might be dup'd fd */ - return B_NO_ERROR; + // Following 3 lines of code are here to eliminate "unused parameter" warnings. + (void)dev; + (void)pos; + (void)buf; + + *len = 0; + return B_NOT_ALLOWED; } + +/* ---------- + close_hook - does nothing, gracefully +----- */ +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; +} + + /* ----------- - free_hook - close down the device + free_hook - close down the device ----------- */ -static status_t -free_hook (void* dev) { - device_info *di = (device_info *)dev; - shared_info *si = di->si; - vuint32 *regs = di->regs; +static status_t +free_hook(void* dev) +{ + DeviceInfo *di = (DeviceInfo*)dev; + SharedInfo *si = di->si; - ddprintf(("SKD: free_hook() begins...\n")); - /* lock the driver */ - AQUIRE_BEN(pd->kernel); + 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; + /* if opened multiple times, decrement the open count and exit */ + if (di->is_open > 1) + goto unlock_and_exit; - /* disable and clear any pending interrupts */ - *regs = *regs; /* CHANGE ME */ - - /* if we were faking the interrupts */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ - /* stop our interrupt faking thread */ - si->flags = 0; - di->can_interrupt = FALSE; -#if defined(POST_R4_0) - /* cancel the timer */ - /* we don't know which one is current, so cancel them both and ignore any error */ - cancel_timer((timer *)&(di->ti_a)); - cancel_timer((timer *)&(di->ti_b)); -#else - /* we don't do anything here, as the R4 kernel reaps its own threads */ - /* After R4.0 we can do it ourselves, but we'd rather use timers */ -#endif - /* otherwise */ - } else { - /* remove interrupt handler */ - remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, di); - } + DisableVBI(); // disable & clear any pending interrupts - /* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */ - delete_sem(si->vblank); - si->vblank = -1; + if (si->bInterruptAssigned) { + /* remove interrupt handler */ + remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, savage_interrupt, di); + } - /* free regs and framebuffer areas */ - unmap_device(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; - /* clean up our shared area */ - delete_area(di->shared_area); - di->shared_area = -1; - di->si = NULL; + /* 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); - ddprintf(("SKD: free_hook() ends.\n")); - /* all done */ - return B_OK; + /* mark the device available */ + di->is_open--; + /* unlock the driver */ + RELEASE_BEN(pd->kernel); + + TRACE(("exit free_hook()\n")); + /* all done */ + return B_OK; } + /* ----------- - control_hook - where the real work is done + control_hook - where the real work is done ----------- */ -static status_t +static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len) { - device_info *di = (device_info *)dev; - status_t result = B_DEV_INVALID_IOCTL; + DeviceInfo *di = (DeviceInfo *)dev; + status_t result = B_DEV_INVALID_IOCTL; - /* ddprintf(("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: - { - savage_get_private_data *gpd = (savage_get_private_data *)buf; - if (gpd->magic == SAVAGE_PRIVATE_DATA_MAGIC) - { - gpd->shared_info_area = di->shared_area; - result = B_OK; - } - } - break; - case SAVAGE_GET_PCI: - { - savage_get_set_pci *gsp = (savage_get_set_pci *)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: - { - savage_get_set_pci *gsp = (savage_get_set_pci *)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_RUN_INTERRUPTS: - { - savage_set_bool_state *ri = (savage_set_bool_state *)buf; - if (ri->magic == SAVAGE_PRIVATE_DATA_MAGIC) { - /* are we faking interrupts? */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ - di->can_interrupt = ri->do_it; - } else { - vuint32 *regs = di->regs; - if (ri->do_it) { - /* resume interrupts */ - *regs = *regs; /* CHANGE ME */ - } else { - /* disable interrupts */ - *regs = *regs; /* CHANGE ME */ - } - } - result = B_OK; - } - } - break; - case SAVAGE_DPRINTF: - dprintf ((char*)buf); - break; - } - return result; + (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, "savage.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; } +