Added the S3 Savage driver from BeBits - accoring to Siarzhuk it doesn't work yet

under Haiku, though. If someone has access to this card, feel free to fix this :-)
I renamed the driver to s3savage (from BeSavage), and added the license text
separately (dunno if that's really needed, though).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18978 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-09-29 13:44:54 +00:00
parent 8d9e5a451e
commit b9ecaef57a
26 changed files with 4951 additions and 0 deletions
@@ -0,0 +1,197 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef DRIVERINTERFACE_H
#define DRIVERINTERFACE_H
#include <Accelerant.h>
#include <Drivers.h>
#include <PCI.h>
#include <OS.h>
/*
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
typedef struct
{
sem_id sem;
int32 ben;
} benaphore;
#define INIT_BEN(x) x.sem = create_sem(0, "SAVAGE "#x" benaphore"); x.ben = 0;
#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem);
#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem);
#define DELETE_BEN(x) delete_sem(x.sem);
#define SAVAGE_PRIVATE_DATA_MAGIC 0x1234 /* 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
};
typedef struct
{
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)
};
enum
{
/* 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 */
/* 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] */
/* 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 */
};
#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)
#if defined(__cplusplus)
}
#endif
#endif
+1
View File
@@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src add-ons accelerants matrox ;
SubInclude HAIKU_TOP src add-ons accelerants neomagic ;
SubInclude HAIKU_TOP src add-ons accelerants nvidia ;
SubInclude HAIKU_TOP src add-ons accelerants radeon ;
SubInclude HAIKU_TOP src add-ons accelerants s3savage ;
SubInclude HAIKU_TOP src add-ons accelerants tdfx ;
SubInclude HAIKU_TOP src add-ons accelerants skeleton ;
SubInclude HAIKU_TOP src add-ons accelerants vesa ;
@@ -0,0 +1,121 @@
/*
* Copyright 1999 Erdi Chen
*/
#include "GlobalData.h"
#include "generic.h"
#include "s3accel.h"
#include "s3mmio.h"
void
SCREEN_TO_SCREEN_BLIT (
engine_token *et, blit_params *list, 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 ++;
}
s3accel_wait_for_fifo (3);
UpdateGEReg16 (FRGD_MIX, 0x0027);
}
void
FILL_RECTANGLE (
engine_token *et, uint32 color, fill_rect_params *list, 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;
s3accel_wait_for_fifo (2);
UpdateGEReg (ALT_CURXY, (x<<16)|y);
UpdateGEReg (ALT_PCNT, (w<<16)|h);
UpdateGEReg (CMD, 0x000040b1);
list++;
}
s3accel_wait_for_fifo(3);
}
void
INVERT_RECTANGLE (
engine_token *et, fill_rect_params *list, 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;
s3accel_wait_for_fifo (2);
UpdateGEReg (ALT_CURXY, (x<<16)|y);
UpdateGEReg (ALT_PCNT, (w<<16)|h);
UpdateGEReg (CMD, 0x000040b1);
list++;
}
s3accel_wait_for_fifo (3);
UpdateGEReg16 (FRGD_MIX, 0x0027);
}
void
FILL_SPAN (
engine_token *et, uint32 color, uint16 *list, uint32 count)
{
s3accel_wait_for_fifo (1);
UpdateGEReg (FRGD_COLOR, color);
UpdateGEReg16 (FRGD_MIX, 0x0027);
while (count--)
{
int y = *list ++;
int x = *list ++;
int w = *list - x; list ++;
s3accel_wait_for_fifo (2);
UpdateGEReg (ALT_CURXY, (x<<16)|y);
UpdateGEReg (ALT_PCNT, (w<<16)|1);
UpdateGEReg (CMD, 0x000040b1);
}
}
+113
View File
@@ -0,0 +1,113 @@
/*
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 "GlobalData.h"
#include "generic.h"
#include "s3drv.h"
void set_cursor_colors(void)
{
/* it's only called by the INIT_ACCELERANT() */
s3drv_set_cursor_color (0, ~0);
}
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;
s3drv_load_cursor ((byte_t*)framebuffer, 0,
width, height, andMask, xorMask);
}
return B_OK;
}
/*
Move the cursor to the specified position on the desktop. If we're
using some kind of virtual desktop, adjust the display start position
accordingly and position the cursor in the proper "virtual" location.
*/
void MOVE_CURSOR (uint16 x_p, uint16 y_p)
{
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;
/* Need to set this value for 32 bit */
uint16 h_adjust = 3;
/* 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;
}
/* reposition the desktop on the display if required */
if (move_screen) MOVE_DISPLAY(hds,vds);
/* put cursor in correct physical position */
x -= hds;
y -= vds;
x -= si->cursor.hot_x;
y -= si->cursor.hot_y;
/* position the cursor on the display */
s3drv_move_cursor (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;
}
@@ -0,0 +1,70 @@
/*
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 "GlobalData.h"
#include "generic.h"
#include "s3drv.h"
static engine_token savage_engine_token = { 1, B_2D_ACCELERATION, NULL };
uint32 ACCELERANT_ENGINE_COUNT(void)
{
return 1;
}
status_t
ACQUIRE_ENGINE (
uint32 capabilities, uint32 max_wait,
sync_token *st, engine_token **et)
{
/* 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;
}
void WAIT_ENGINE_IDLE(void)
{
s3drv_wait_for_idle ();
// note our current possition
si->engine.last_idle = si->engine.count;
}
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;
}
status_t SYNC_TO_TOKEN(sync_token *st)
{
s3drv_wait_for_idle ();
si->engine.last_idle = st->counter;
return B_OK;
}
@@ -0,0 +1,94 @@
/*
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"
/*
The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper
function. The extra information (which is specific to the feature) is
pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be
noted on a case by case below.
*/
void * get_accelerant_hook(uint32 feature, void *data) {
switch (feature) {
/*
These definitions are out of pure lazyness.
*/
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
/* initialization */
HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT);
HOOK(ACCELERANT_CLONE_INFO_SIZE);
HOOK(GET_ACCELERANT_CLONE_INFO);
HOOK(UNINIT_ACCELERANT);
HOOK(GET_ACCELERANT_DEVICE_INFO);
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
/* mode configuration */
HOOK(ACCELERANT_MODE_COUNT);
HOOK(GET_MODE_LIST);
HOOK(PROPOSE_DISPLAY_MODE);
HOOK(SET_DISPLAY_MODE);
HOOK(GET_DISPLAY_MODE);
HOOK(GET_FRAME_BUFFER_CONFIG);
HOOK(GET_PIXEL_CLOCK_LIMITS);
HOOK(MOVE_DISPLAY);
HOOK(SET_INDEXED_COLORS);
HOOK(GET_TIMING_CONSTRAINTS);
HOOK(DPMS_CAPABILITIES);
HOOK(DPMS_MODE);
HOOK(SET_DPMS_MODE);
/* cursor managment */
HOOK(SET_CURSOR_SHAPE);
HOOK(MOVE_CURSOR);
HOOK(SHOW_CURSOR);
/* synchronization */
HOOK(ACCELERANT_ENGINE_COUNT);
HOOK(ACQUIRE_ENGINE);
HOOK(RELEASE_ENGINE);
HOOK(WAIT_ENGINE_IDLE);
HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_TOKEN);
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
*/
/* 2D acceleration */
HOOK(SCREEN_TO_SCREEN_BLIT);
HOOK(FILL_RECTANGLE);
HOOK(INVERT_RECTANGLE);
HOOK(FILL_SPAN);
#undef HOOK
#undef ZERO
}
/*
Return a null pointer for any feature we don't understand.
*/
return 0;
}
@@ -0,0 +1,96 @@
/*
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 "GlobalData.h"
#include "generic.h"
/*
Return the current display mode. The only time you might return an
error is if a mode hasn't been set.
*/
status_t GET_DISPLAY_MODE (display_mode *current_mode)
{
/* easy for us, we return the last mode we set */
*current_mode = si->dm;
return B_OK;
}
/*
Return the frame buffer configuration information.
*/
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb)
{
/* easy again, as the last mode set stored the info in a convienient form */
*afb = si->fbc;
return B_OK;
}
/*
Return the maximum and minium pixel clock limits for the specified mode.
*/
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
{
/*
Note that we're not making any guarantees about the ability of the attached
display to handle pixel clocks within the limits we return. A future monitor
capablilities database will post-process this information.
*/
uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total;
uint32 clock_limit;
/* max pixel clock is pixel depth dependant */
switch (dm->space & ~0x3000)
{
case B_RGB32: clock_limit = si->pix_clk_max32; break;
case B_RGB15:
case B_RGB16: clock_limit = si->pix_clk_max16; break;
case B_CMAP8: clock_limit = si->pix_clk_max8; break;
default:
clock_limit = 0;
}
/* lower limit of about 48Hz vertical refresh */
*low = (total_pix * 48L) / 1000L;
if (*low > clock_limit) return B_ERROR;
*high = clock_limit;
return B_OK;
}
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.
*/
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;
}
@@ -0,0 +1,33 @@
/*
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 "GlobalData.h"
#include <stdarg.h>
#include <stdio.h>
#include <sys/ioctl.h>
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;
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);
}
@@ -0,0 +1,25 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#if !defined(GLOBALDATA_H)
#define GLOBALDATA_H
#include "DriverInterface.h"
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, ...);
#endif
@@ -0,0 +1,494 @@
/*
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 "GlobalData.h"
#include "generic.h"
#include "s3drv.h"
#include "s3mmio.h"
#include "s3accel.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include <sys/ioctl.h>
/* defined in ProposeDisplayMode.c */
extern status_t create_mode_list(void);
/* defined in Cursor.c */
extern void set_cursor_colors(void);
/* 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;
}
// 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;
}
static status_t init_common(int the_fd);
/* Initialization code shared between primary and cloned accelerants */
static status_t init_common(int the_fd)
{
status_t result;
savage_get_private_data gpd;
/* memorize the file descriptor */
fd = the_fd;
dpf ("init_common begin\n");
/* set the magic number so the driver knows we're for real */
gpd.magic = SAVAGE_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, SAVAGE_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK) goto error0;
/* 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)
{
result = shared_info_area;
goto error0;
}
/* clone the memory mapped registers for our use */
regs_area = clone_area (
"SAVAGE regs area", (void **)&regs, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, si->regs_area);
if (regs_area < 0)
{
result = regs_area;
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 */
goto error0;
error2:
delete_area(regs_area);
error1:
delete_area(shared_info_area);
error0:
dpf ("init_common done\n");
return result;
}
/* 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;
}
/*
Initialize the accelerant. the_fd is the file handle of the device (in
/dev/graphics) that has been opened by the app_server (or some test harness).
We need to determine if the kernel driver and the accelerant are compatible.
If they are, get the accelerant ready to handle other hook functions and
report success or failure.
*/
status_t INIT_ACCELERANT(int the_fd)
{
status_t result;
/* note that we're the primary accelerant (accelerantIsClone is global) */
accelerantIsClone = 0;
/* do the initialization common to both the primary and the clones */
result = init_common(the_fd);
/* bail out if the common initialization failed */
if (result != B_OK) goto error0;
/*
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.
*/
/*
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 ();
}
si->pix_clk_max8 = 250000;
si->pix_clk_max16 = 250000;
si->pix_clk_max32 = 250000;
/* bail out if it failed */
if (result != B_OK) 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;
/*
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;
/* init the shared semaphore */
INIT_BEN(si->engine.lock);
/* initialize the engine synchronization variables */
/* count of issued parameters or commands */
si->engine.last_idle = si->engine.count = 0;
/* bail out if something failed */
if (result != B_OK) goto error3;
/* set the cursor colors. You may or may not have to do this, depending
on the device. */
set_cursor_colors();
/* ensure cursor state */
SHOW_CURSOR(false);
/* a winner! */
result = B_OK;
goto error0;
error3:
/* free up the benaphore */
DELETE_BEN(si->engine.lock);
error2:
/*
Clean up any resources allocated in your device specific initialization
code.
*/
error1:
/*
Initialization failed after init_common() succeeded, so we need to clean
up before quiting.
*/
uninit_common();
error0:
return result;
}
/*
Return the number of bytes required to hold the information required
to clone the device.
*/
ssize_t ACCELERANT_CLONE_INFO_SIZE(void)
{
/*
Since we're passing the name of the device as the only required
info, return the size of the name buffer
*/
return MAX_SAVAGE_DEVICE_NAME_LENGTH;
}
/*
Return the info required to clone the device. void *data points to
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
*/
void GET_ACCELERANT_CLONE_INFO(void *data)
{
savage_device_name 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));
}
/*
Initialize a copy of the accelerant as a clone. void *data points to
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
*/
status_t CLONE_ACCELERANT(void *data)
{
status_t result;
char path[MAXPATHLEN];
/* the data is the device name */
strcpy(path, "/dev");
strcat(path, (const char *)data);
/* open the device, the permissions aren't important */
fd = open(path, B_READ_WRITE);
if (fd < 0)
{
result = fd;
goto error0;
}
/* note that we're a clone accelerant */
accelerantIsClone = 1;
/* call the shared initialization code */
result = init_common(fd);
/* 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
);
if (result < B_OK) goto error2;
/* all done */
result = B_OK;
goto error0;
error2:
/* free up the areas we cloned */
uninit_common();
error1:
/* close the device we opened */
close(fd);
error0:
return result;
}
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);
}
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi)
{
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" };
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;
}
+30
View File
@@ -0,0 +1,30 @@
SubDir HAIKU_TOP src add-ons accelerants s3savage ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics s3savage ] ;
Addon s3savage.accelerant : accelerants :
Acceleration.c
Cursor.c
EngineManagement.c
GetAccelerantHook.c
GetModeInfo.c
GlobalData.c
InitAccelerant.c
ProposeDisplayMode.c
SetDisplayMode.c
s3accel.c
s3drv.c
s3vga.c
: false
: be
;
Package haiku-s3savage-cvs :
s3savage.accelerant :
boot home config add-ons accelerants ;
+27
View File
@@ -0,0 +1,27 @@
This is a modified version of the XFree86 license.
The binary and source form of this software is covered by the
following copyright/license.
Copyright (C) 1999 Erdi Chen. All Rights Reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,384 @@
/*
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 "GlobalData.h"
#include "generic.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
#define MODE_FLAGS (B_SCROLL|B_8_BIT_DAC|B_HARDWARE_CURSOR|B_PARALLEL_ACCESS)
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
static const display_mode mode_list[] = {
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 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) */
};
/* 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"
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.
*/
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,
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.
*/
/* validate horizontal timings */
{
/* for most devices, horizontal parameters must be multiples of 8 */
uint16 h_display = target->timing.h_display >> 3;
uint16 h_sync_start = target->timing.h_sync_start >> 3;
uint16 h_sync_end = target->timing.h_sync_end >> 3;
uint16 h_total = target->timing.h_total >> 3;
/* ensure reasonable minium display and sequential order of parms */
if (h_display < (320 >> 3)) h_display = 320 >> 3;
if (h_display > (2048 >> 3)) h_display = 2048 >> 3;
if (h_sync_start < (h_display + 2)) h_sync_start = h_display + 2;
if (h_sync_end < (h_sync_start + 3))
h_sync_end = h_sync_start + 3; /*(0x001f >> 2);*/
if (h_total < (h_sync_end + 1)) h_total = h_sync_end + 1;
/* adjust for register limitations: */
/* h_total is 9 bits */
if (h_total > h_total_bits) h_total = h_total_bits;
/* h_display is 8 bits - handled above */
/* h_sync_start is 9 bits */
/* h_sync_width is 5 bits */
if ((h_sync_end - h_sync_start) > h_sync_bits)
h_sync_end = h_sync_start + h_sync_bits;
/* shift back to the full width values */
target->timing.h_display = h_display << 3;
target->timing.h_sync_start = h_sync_start << 3;
target->timing.h_sync_end = h_sync_end << 3;
target->timing.h_total = h_total << 3;
}
/* did we fall out of one of the limits? */
if (
(target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total)
) result = B_BAD_VALUE;
/* validate vertical timings */
{
uint16 v_display = target->timing.v_display;
uint16 v_sync_start = target->timing.v_sync_start;
uint16 v_sync_end = target->timing.v_sync_end;
uint16 v_total = target->timing.v_total;
/* ensure reasonable minium display and sequential order of parms */
/* v_display is 11 bits */
/* v_total is 11 bits */
/* v_sync_start is 11 bits */
/* v_sync_width is 5 bits */
if (v_display < 200) v_display = 200;
if (v_display > (v_display_bits - 5)) v_display = (v_display_bits - 5); /* leave room for the sync pulse */
if (v_sync_start < (v_display + 1)) v_sync_start = v_display + 1;
if (v_sync_end < v_sync_start) v_sync_end = v_sync_start + 3;
if (v_total < (v_sync_end + 1)) v_total = v_sync_end + 1;
/* adjust for register limitations */
if ((v_sync_end - v_sync_start) > v_sync_bits)
v_sync_end = v_sync_start + v_sync_bits;
target->timing.v_display = v_display;
target->timing.v_sync_start = v_sync_start;
target->timing.v_sync_end = v_sync_end;
target->timing.v_total = v_total;
}
/* did we fall out of one of the limits? */
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.h_sync_start) ||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
) result = B_BAD_VALUE;
/* adjust pixel clock for DAC limits and target refresh rate */
/*
We're re-calcuating the pixel_clock here because we might have
changed the h/v totals above. If we didn't change anything
the calculation is wasted, but it's no big deal.
*/
target->timing.pixel_clock = target_refresh
* ((double)target->timing.h_total)
* ((double)target->timing.v_total) / 1000.0;
/*
Select the maximum pixel clock based on the color space. Your
device may have other constraints. In this sample driver, we
calculated the maximum pixel clock for this device in the
initialization code.
This is also a convienient place to determine the number of bytes
per pixel for a later display pitch calculation.
*/
switch (target->space & 0x0fff)
{
case B_CMAP8:
limit_clock = si->pix_clk_max8;
row_bytes = 1;
break;
//case B_RGB15:
case B_RGB16:
limit_clock = si->pix_clk_max16;
row_bytes = 2;
break;
case B_RGB32:
limit_clock = si->pix_clk_max32;
row_bytes = 4;
break;
default:
/* no amount of adjusting will fix not being able to support
the pixel format */
return B_ERROR;
}
/* make sure we don't generate more pixel bandwidth than the device
can handle */
if (target->timing.pixel_clock > limit_clock)
target->timing.pixel_clock = limit_clock;
/* we probably ought to check against too low of a pixel rate,
but I'm lazy */
/* note if we fell outside the limits */
if (
(target->timing.pixel_clock < low->timing.pixel_clock) ||
(target->timing.pixel_clock > high->timing.pixel_clock)
) result = B_BAD_VALUE;
/* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
if (target->virtual_width > 2048)
target->virtual_width = 2048;
/* adjust virtual width for engine limitations */
target->virtual_width = (target->virtual_width + 7) & ~7;
if (
(target->virtual_width < low->virtual_width) ||
(target->virtual_width > high->virtual_width)
) result = B_BAD_VALUE;
/* calculate rowbytes after we've nailed the virtual width */
row_bytes *= target->virtual_width;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) > si->mem_size)
target->virtual_height = si->mem_size / row_bytes;
if (target->virtual_height > 2048)
target->virtual_height = 2048;
if (target->virtual_height < target->timing.v_display)
/* not enough frame buffer memory for the mode */
return B_ERROR;
else if (
(target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height)
) result = B_BAD_VALUE;
/*
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 the number of modes this device will return from GET_MODE_LIST().
*/
uint32 ACCELERANT_MODE_COUNT(void)
{
/* return the number of 'built-in' display modes */
return si->mode_count;
}
/*
Copy the list of guaranteed supported video modes to the location
provided.
*/
status_t GET_MODE_LIST(display_mode *dm)
{
/* copy them to the buffer pointed at by *dm */
memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK;
}
/*
Create a list of display_modes to pass back to the caller.
*/
status_t create_mode_list(void)
{
size_t max_size;
uint32
i, j,
pix_clk_range;
const display_mode
*src;
display_mode
*dst,
low,
high;
/*
We prefer frame buffers to have the same endianness as the host
CPU, but it's not required. You can even return both, although
there isn't a way for the current Screen preferences panel to
allow the user to choose which one to use.
*/
#if defined(__INTEL__)
color_space spaces[] =
// {B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE};
{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};
#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);
/* 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;
/* walk through our predefined list and see which modes fit this device */
src = mode_list;
dst = my_mode_list;
si->mode_count = 0;
for (i = 0; i < MODE_COUNT; i++)
{
/* 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;
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++) {
/* 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;
/* 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++;
}
}
/* advance to next mode */
src++;
}
return B_OK;
}
@@ -0,0 +1,309 @@
/*
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 "GlobalData.h"
#include "generic.h"
#include "s3drv.h"
#include "s3accel.h"
#include "s3mmio.h"
#include <stdio.h>
#include <sys/ioctl.h>
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
*/
static void interrupt_enable(bool flag)
{
status_t result;
savage_set_bool_state 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));
}
/*
Calculates the number of bits for a given color_space.
Usefull for mode setup routines, etc.
*/
static uint32 calcBitsPerPixel(uint32 cs)
{
uint32 bpp = 0;
switch (cs)
{
case B_RGB32_BIG:
case B_RGBA32_BIG:
case B_RGB32_LITTLE:
case B_RGBA32_LITTLE:
bpp = 32; break;
case B_RGB24_BIG:
case B_RGB24_LITTLE:
bpp = 24; break;
case B_RGB16_BIG:
case B_RGB16_LITTLE:
bpp = 16; break;
case B_RGB15_BIG:
case B_RGBA15_BIG:
case B_RGB15_LITTLE:
case B_RGBA15_LITTLE:
bpp = 15; break;
case B_CMAP8:
bpp = 8; break;
}
return bpp;
}
/*
The code to actually configure the display.
Do all of the error checking in PROPOSE_DISPLAY_MODE(),
and just assume that the values I get here are acceptable.
*/
static void 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;
}
/*
Return the current DPMS mode.
*/
uint32 DPMS_MODE (void)
{
uint32 LTemp;
uint32 mode = B_DPMS_ON;
/* 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;
}
+100
View File
@@ -0,0 +1,100 @@
/*
* 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__ */
+148
View File
@@ -0,0 +1,148 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#if !defined(GENERIC_H)
#define GENERIC_H
#include <Accelerant.h>
status_t INIT_ACCELERANT(int fd);
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
void GET_ACCELERANT_CLONE_INFO(void *data);
status_t CLONE_ACCELERANT(void *data);
void UNINIT_ACCELERANT(void);
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
uint32 ACCELERANT_MODE_COUNT(void);
status_t GET_MODE_LIST(display_mode *dm);
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
status_t GET_DISPLAY_MODE(display_mode *current_mode);
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
uint32 DPMS_CAPABILITIES(void);
uint32 DPMS_MODE(void);
status_t SET_DPMS_MODE(uint32 dpms_flags);
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
void MOVE_CURSOR(uint16 x, uint16 y);
void SHOW_CURSOR(bool is_visible);
uint32 ACCELERANT_ENGINE_COUNT(void);
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
void WAIT_ENGINE_IDLE(void);
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
status_t SYNC_TO_TOKEN(sync_token *st);
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
#endif
#if 0
typedef enum
{
B_NO_COLOR_SPACE = 0x0000, /* byte in memory order, high bit first */
/* linear color space (little endian is the default) */
B_RGB32 = 0x0008, /* B[7:0] G[7:0] R[7:0] -[7:0] */
B_RGBA32 = 0x2008, /* B[7:0] G[7:0] R[7:0] A[7:0] */
B_RGB24 = 0x0003, /* B[7:0] G[7:0] R[7:0] */
B_RGB16 = 0x0005, /* G[2:0],B[4:0] R[4:0],G[5:3] */
B_RGB15 = 0x0010, /* G[2:0],B[4:0] -[0],R[4:0],G[4:3] */
B_RGBA15 = 0x2010, /* G[2:0],B[4:0] A[0],R[4:0],G[4:3] */
B_CMAP8 = 0x0004, /* D[7:0] */
B_GRAY8 = 0x0002, /* Y[7:0] */
B_GRAY1 = 0x0001, /* Y0[0],Y1[0],Y2[0],Y3[0],Y4[0],Y5[0],Y6[0],Y7[0] */
/* big endian version, when the encoding is not endianess independant */
B_RGB32_BIG = 0x1008, /* -[7:0] R[7:0] G[7:0] B[7:0] */
B_RGBA32_BIG = 0x3008, /* A[7:0] R[7:0] G[7:0] B[7:0] */
B_RGB24_BIG = 0x1003, /* R[7:0] G[7:0] B[7:0] */
B_RGB16_BIG = 0x1005, /* R[4:0],G[5:3] G[2:0],B[4:0] */
B_RGB15_BIG = 0x1010, /* -[0],R[4:0],G[4:3] G[2:0],B[4:0] */
B_RGBA15_BIG = 0x3010, /* A[0],R[4:0],G[4:3] G[2:0],B[4:0] */
/* little-endian declarations, for completness */
B_RGB32_LITTLE = B_RGB32,
B_RGBA32_LITTLE = B_RGBA32,
B_RGB24_LITTLE = B_RGB24,
B_RGB16_LITTLE = B_RGB16,
B_RGB15_LITTLE = B_RGB15,
B_RGBA15_LITTLE = B_RGBA15,
/* non linear color space -- note that these are here for exchange purposes; */
/* a BBitmap or BView may not necessarily support all these color spaces. */
/* Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128) */
B_YCbCr422 = 0x4000, /* Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0]... */
/* Cb2[7:0] Y3[7:0] Cr2[7:0] */
B_YCbCr411 = 0x4001, /* Cb0[7:0] Y0[7:0] Cr0[7:0] Y1[7:0] Cb4[7:0]...*/
/* Y2[7:0] Cr4[7:0] Y3[7:0] Y4[7:0] Y5[7:0]... */
/* Y6[7:0] Y7[7:0] */
B_YCbCr444 = 0x4003, /* Y0[7:0] Cb0[7:0] Cr0[7:0] */
B_YCbCr420 = 0x4004, /* Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ... */
/* Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines */
/* Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128) */
/* note that YUV byte order is different from YCbCr */
/* USE YCbCr, not YUV, when that's what you mean! */
B_YUV422 = 0x4020, /* U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] ... */
/* U2[7:0] Y2[7:0] V2[7:0] Y3[7:0] */
B_YUV411 = 0x4021, /* U0[7:0] Y0[7:0] Y1[7:0] V0[7:0] Y2[7:0] Y3[7:0] */
/* U4[7:0] Y4[7:0] Y5[7:0] V4[7:0] Y6[7:0] Y7[7:0] */
B_YUV444 = 0x4023, /* U0[7:0] Y0[7:0] V0[7:0] U1[7:0] Y1[7:0] V1[7:0] */
B_YUV420 = 0x4024, /* Non-interlaced only, U0 Y0 Y1 U2 Y2 Y3 on even scan lines ... */
/* V0 Y0 Y1 V2 Y2 Y3 on odd scan lines */
B_YUV9 = 0x402C, /* planar? 410? */
B_YUV12 = 0x402D, /* planar? 420? */
B_UVL24 = 0x4030, /* U0[7:0] V0[7:0] L0[7:0] ... */
B_UVL32 = 0x4031, /* U0[7:0] V0[7:0] L0[7:0] X0[7:0]... */
B_UVLA32 = 0x6031, /* U0[7:0] V0[7:0] L0[7:0] A0[7:0]... */
B_LAB24 = 0x4032, /* L0[7:0] a0[7:0] b0[7:0] ... (a is not alpha!) */
B_LAB32 = 0x4033, /* L0[7:0] a0[7:0] b0[7:0] X0[7:0] ... (b is not alpha!) */
B_LABA32 = 0x6033, /* L0[7:0] a0[7:0] b0[7:0] A0[7:0] ... (A is alpha) */
/* red is at hue = 0 */
B_HSI24 = 0x4040, /* H[7:0] S[7:0] I[7:0] */
B_HSI32 = 0x4041, /* H[7:0] S[7:0] I[7:0] X[7:0] */
B_HSIA32 = 0x6041, /* H[7:0] S[7:0] I[7:0] A[7:0] */
B_HSV24 = 0x4042, /* H[7:0] S[7:0] V[7:0] */
B_HSV32 = 0x4043, /* H[7:0] S[7:0] V[7:0] X[7:0] */
B_HSVA32 = 0x6043, /* H[7:0] S[7:0] V[7:0] A[7:0] */
B_HLS24 = 0x4044, /* H[7:0] L[7:0] S[7:0] */
B_HLS32 = 0x4045, /* H[7:0] L[7:0] S[7:0] X[7:0] */
B_HLSA32 = 0x6045, /* H[7:0] L[7:0] S[7:0] A[7:0] */
B_CMY24 = 0xC001, /* C[7:0] M[7:0] Y[7:0] No gray removal done */
B_CMY32 = 0xC002, /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
B_CMYA32 = 0xE002, /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
B_CMYK32 = 0xC003, /* C[7:0] M[7:0] Y[7:0] K[7:0] */
/* compatibility declarations */
B_MONOCHROME_1_BIT = B_GRAY1,
B_GRAYSCALE_8_BIT = B_GRAY8,
B_COLOR_8_BIT = B_CMAP8,
B_RGB_32_BIT = B_RGB32,
B_RGB_16_BIT = B_RGB15,
B_BIG_RGB_32_BIT = B_RGB32_BIG,
B_BIG_RGB_16_BIT = B_RGB15_BIG
} color_space;
#endif
+337
View File
@@ -0,0 +1,337 @@
/*
* 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 */
+112
View File
@@ -0,0 +1,112 @@
/*
* 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__ */
+683
View File
@@ -0,0 +1,683 @@
/*
* Copyright 1999 Erdi Chen
*/
#include "s3mmio.h"
#include "s3drv.h"
#include "DriverInterface.h"
#include <stdarg.h>
#include <stdio.h>
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;
}
+118
View File
@@ -0,0 +1,118 @@
/*
* 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__ */
+133
View File
@@ -0,0 +1,133 @@
/*
* 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__ */
+271
View File
@@ -0,0 +1,271 @@
/*
* 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<<max_r))
{
ffreq = ffreq_min / (1<<max_r);
}
if (ffreq > ffreq_max / (1<<min_r))
{
ffreq = ffreq_max / (1 << min_r);
}
best_diff = ffreq;
for (r = min_r; r <= max_r; r ++)
{
for (n = min_n + 2; n <= max_n + 2; n ++)
{
m = (int)(ffreq * n * (1 << r) + 0.5);
if (m < min_m + 2 || m > 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;
}
@@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3savage ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics tdfx ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ;
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vesa ;
@@ -0,0 +1,16 @@
SubDir HAIKU_TOP src add-ons kernel drivers graphics s3savage ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders [ FDirName graphics s3savage ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
UsePrivateHeaders graphics kernel ;
KernelAddon s3savage :
driver.c
;
Package haiku-s3savage-cvs :
s3savage :
boot home config add-ons kernel drivers bin ;
PackageDriverSymLink haiku-s3savage-cvs : graphics s3savage ;
@@ -0,0 +1,27 @@
This is a modified version of the XFree86 license.
The binary and source form of this software is covered by the
following copyright/license.
Copyright (C) 1999 Erdi Chen. All Rights Reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
File diff suppressed because it is too large Load Diff