openBeOS_Matrox_V0.13beta1_src

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5512 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2003-12-01 05:44:13 +00:00
parent 36be333ed8
commit 091b52d5b2
33 changed files with 8473 additions and 0 deletions
@@ -0,0 +1,126 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed.
*/
#define MODULE_BIT 0x40000000
// apsed, TODO ?? change interface of gx00_acc_* and use MGA pseudo DMA
#include "acc_std.h"
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
gx00_acc_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height
);
i++;
}
}
//Not possible with G400 AFAIK (if anyone knows otherwise then please contact me)
//void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
//typedef struct {
// uint16 src_left; /* guaranteed constrained to virtual width and height */
// uint16 src_top;
// uint16 src_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */
// uint16 src_height; /* 0 to M, where zero means one line, one means two lines, etc. */
// uint16 dest_left;
// uint16 dest_top;
// uint16 dest_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */
// uint16 dest_height; /* 0 to M, where zero means one line, one means two lines, etc. */
//} scaled_blit_params;
//}
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
gx00_acc_transparent_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height,
transparent_colour
);
i++;
}
}
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) {
int i;
/*draw each rectangle*/
i=0;
while (count--)
{
gx00_acc_rectangle
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1,
colorIndex
);
i++;
}
}
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
int i;
/*draw each rectangle*/
i=0;
while (count--)
{
gx00_acc_rectangle_invert
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1,
0
);
i++;
}
}
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
int i;
/*draw each span*/
i=0;
while (count--)
{
gx00_acc_rectangle
(
list[i+1],
list[i+2]+1,
list[i],
1,
colorIndex
);
i+=3;
}
}
+112
View File
@@ -0,0 +1,112 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
*/
#define MODULE_BIT 0x20000000
/*DUALHEAD notes -
No hardware cursor possible:(
Reasons:
CRTC1 has a cursor, can be displayed on DAC or MAVEN
CRTC2 has no cursor
Can not switch CRTC in one vblank (has to resync)
CRTC2 does not support split screen
app_server does not support some modes with and some without cursor
virtual not supported, because of MAVEN blanking issues
*/
#include "acc_std.h"
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask)
{
LOG(4,("SET_CURSOR_SHAPE: width %d, height %d\n", width, height));
if ((width != 16) || (height != 16))
{
return B_ERROR;
}
else if ((hot_x >= width) || (hot_y >= height))
{
return B_ERROR;
}
else
{
gx00_crtc_cursor_define(andMask,xorMask);
/* Update cursor variables appropriately. */
si->cursor.width = width;
si->cursor.height = height;
si->cursor.hot_x = hot_x;
si->cursor.hot_y = hot_y;
}
return B_OK;
}
/* Move the cursor to the specified position on the desktop, taking account of virtual/dual issues */
void MOVE_CURSOR(uint16 x, uint16 y)
{
uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */
uint16 vds = si->dm.v_display_start; /* the current vertical starting line */
uint16 h_adjust;
/* clamp cursor to 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;
/* store, for our info */
si->cursor.x=x;
si->cursor.y=y;
/*set up minimum amount to scroll*/
switch(si->dm.space)
{
case B_CMAP8:
h_adjust=7;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
h_adjust=3;
break;
case B_RGB32_LITTLE:
h_adjust=1;
break;
default:
h_adjust=7;
}
/* 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;
else if (x < hds)
hds = x & ~h_adjust;
if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1;
else if (y < vds)
vds = y;
/* reposition the desktop on the display if required */
if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
MOVE_DISPLAY(hds,vds);
/* put cursor in correct physical position */
x -= hds + si->cursor.hot_x;
y -= vds + si->cursor.hot_y;
/* position the cursor on the display */
gx00_crtc_cursor_position(x,y);
}
void SHOW_CURSOR(bool is_visible)
{
/* record for our info */
si->cursor.is_visible = is_visible;
if (is_visible)
gx00_crtc_cursor_show();
else
gx00_crtc_cursor_hide();
}
@@ -0,0 +1,68 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
modification to call G400 functions and mess-ups - Mark Watson
*/
#define MODULE_BIT 0x10000000
#include "acc_std.h"
static engine_token gx00_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 = &gx00_engine_token;
return B_OK;
}
status_t RELEASE_ENGINE(engine_token *et, sync_token *st) {
/* update the sync token, if any */
if (st) {
GET_SYNC_TOKEN(et,st);
}
/* release the shared benaphore */
RELEASE_BEN(si->engine.lock)
return B_OK;
}
void WAIT_ENGINE_IDLE(void) {
uint32 count;
/*wait for the engine to be totally idle*/
count = si->engine.count;
gx00_acc_wait_idle();
si->engine.last_idle = count;
}
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) {
si->engine.count+=4;
st->engine_id = et->engine_id;
st->counter = si->engine.count;
return B_OK;
}
status_t SYNC_TO_TOKEN(sync_token *st) {
/* a quick out */
if (st->counter <= si->engine.last_idle) return B_OK;
/* another quick out! */
if ((st->counter >0xFFFFFFF) && (si->engine.last_idle <0xFFFF)) return B_OK; /*for when counter wraps*/
/* If not we have to wait :-(*/
WAIT_ENGINE_IDLE();
return B_OK;
}
@@ -0,0 +1,175 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x08000000
#include "acc_std.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 CHKO(x) case B_##x: \
if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed
/*
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 */
HRDC(SET_CURSOR_SHAPE); // apsed
HRDC(MOVE_CURSOR);
HRDC(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);
/* only export video overlay functions if card is capable of it */
CHKO(OVERLAY_COUNT);
CHKO(OVERLAY_SUPPORTED_SPACES);
CHKO(OVERLAY_SUPPORTED_FEATURES);
CHKO(ALLOCATE_OVERLAY_BUFFER);
CHKO(RELEASE_OVERLAY_BUFFER);
CHKO(GET_OVERLAY_CONSTRAINTS);
CHKO(ALLOCATE_OVERLAY);
CHKO(RELEASE_OVERLAY);
CHKO(CONFIGURE_OVERLAY);
/*
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);
HOOK(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);//remove for pre R5
/*HOOK(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
Does the G400 support this? I can only think of using texture mapped rectangles, but these seem to have too many restrictions to do this:( e.g. I would need to blit offscreen, into texture format...
*/
#undef HOOK
#undef ZERO
}
/*
Return a null pointer for any feature we don't understand.
*/
return 0;
}
status_t check_overlay_capability(uint32 feature)
{
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_OVERLAY_COUNT:
msg = "B_OVERLAY_COUNT";
break;
case B_OVERLAY_SUPPORTED_SPACES:
msg = "B_OVERLAY_SUPPORTED_SPACES";
break;
case B_OVERLAY_SUPPORTED_FEATURES:
msg = "B_OVERLAY_SUPPORTED_FEATURES";
break;
case B_ALLOCATE_OVERLAY_BUFFER:
msg = "B_ALLOCATE_OVERLAY_BUFFER";
break;
case B_RELEASE_OVERLAY_BUFFER:
msg = "B_RELEASE_OVERLAY_BUFFER";
break;
case B_GET_OVERLAY_CONSTRAINTS:
msg = "B_GET_OVERLAY_CONSTRAINTS";
break;
case B_ALLOCATE_OVERLAY:
msg = "B_ALLOCATE_OVERLAY";
break;
case B_RELEASE_OVERLAY:
msg = "B_RELEASE_OVERLAY";
break;
case B_CONFIGURE_OVERLAY:
msg = "B_CONFIGURE_OVERLAY";
break;
default:
msg = "UNKNOWN";
break;
}
switch(si->ps.card_type)
{
case G200:
case G400: /* is also G400MAX in accelerant for now? */
case G400MAX: /* not used in accelerant yet? */
case G450: /* is also G550 in accelerant for now */
case G550: /* not used in accelerant yet */
/* export video overlay functions */
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
return B_OK;
break;
default:
/* do not export video overlay functions */
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
return B_ERROR;
break;
}
}
@@ -0,0 +1,51 @@
/*
Authors:
Mark Watson - 21/6/00,
Apsed
*/
#define MODULE_BIT 0x04000000
#include "acc_std.h"
/* Get some info about the device */
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi)
{
/*no info on version is provided, so presumably this is for my info*/
LOG(4,("DEVICE_INFO: version 0x%08x\n", adi->version));
switch ((si->ps.secondary_head << 4)|si->ps.card_type)
{
case 0x01:
sprintf(adi->name,"Matrox G400 Plain");
break;
case 0x02:
sprintf(adi->name,"Matrox G400 MAX");
break;
case 0x11:
sprintf(adi->name,"Matrox Dualhead G400 Plain");
break;
case 0x12:
sprintf(adi->name,"Matrox Dualhead G400 MAX");
break;
}
sprintf(adi->chipset,"MGAG400");
sprintf(adi->serial_no,"01134"); /*FIXME*/
adi->memory=si->ps.memory_size * 1024 * 1024;
adi->dac_speed=si->ps.max_dac1_clock;
// apsed, TODO ?? GET_ACCELERANT_DEVICE_INFO never called and kind of cards
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "version", adi->version, adi->version));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "name", adi->name));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "chipset", adi->chipset));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "serial_no", adi->serial_no));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "memory", adi->memory, adi->memory));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %d\n", "dac_speed", adi->dac_speed));
return B_OK;
}
@@ -0,0 +1,134 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
Rudolf Cornelissen 9/2002
*/
#define MODULE_BIT 0x02000000
#include "acc_std.h"
/*
Return the current display mode. The only time you might return an
error is if a mode hasn't been set. Or if the system hands you a NULL pointer.
*/
status_t GET_DISPLAY_MODE(display_mode *current_mode)
{
/* check for NULL pointer */
if (current_mode == NULL) return B_ERROR;
*current_mode = si->dm;
return B_OK;
}
/* Return the frame buffer configuration information. */
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb)
{
/* check for NULL pointer */
if (afb == NULL) return B_ERROR;
*afb = si->fbc;
return B_OK;
}
/* Return the maximum and minium pixelclock limits for the specified mode. */
/* Rewritten / fixed by Rudolf */
/* NOTE:
* Due to BeOS constraints output for all heads will be limited to the head with
* the least capabilities. (BeOS should ask for seperate constraints for all heads.) */
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
{
uint32 max_pclk = 0;
/* check for NULL pointers */
if ((dm == NULL) || (low == NULL) || (high == NULL)) return B_ERROR;
/* specify requested info */
if (dm->flags & DUALHEAD_BITS)
{
/* dualhead mode */
/* find min. value */
switch (si->ps.card_type)
{
case G550:
case G450:
*low = ((si->ps.min_video_vco * 1000) / 16);
break;
default:
*low = ((si->ps.min_video_vco * 1000) / 8);
break;
}
/* find max. value */
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
/* specially noted because of RAM speed constraints! */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
}
/* return values in kHz */
*high = max_pclk * 1000;
}
else
{
/* singlehead mode */
/* find min. value */
switch (si->ps.card_type)
{
case G550:
case G450:
*low = ((si->ps.min_pixel_vco * 1000) / 16);
break;
default:
*low = ((si->ps.min_pixel_vco * 1000) / 8);
break;
}
/* find max. value */
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* return values in kHz */
*high = max_pclk * 1000;
}
return B_OK;
}
/* Return the semaphore id that will be used to signal a vertical sync occured. */
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
{
return si->vblank;
}
@@ -0,0 +1,30 @@
/*
Authors:
Mark Watson - 21/6/00,
Apsed
*/
#define MODULE_BIT 0x01000000
#include "acc_std.h"
/* Used to help generate mode lines */
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc)
{
// apsed, TODO, is that following card capabilities ??
LOG(4, ("GET_TIMING_CONSTRAINTS\n"));
dtc->h_res=8;
dtc->h_sync_min=8;
dtc->h_sync_max=248;
dtc->h_blank_min=8;
dtc->h_blank_max=504;
dtc->v_res=1;
dtc->v_sync_min=1;
dtc->v_sync_max=15;
dtc->v_blank_min=1;
dtc->v_blank_max=255;
return B_OK;
}
@@ -0,0 +1,26 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
*/
#include "acc_std.h"
int fd;
shared_info *si;
area_id shared_info_area;
vuint32 *regs;
area_id regs_area;
display_mode *my_mode_list;
area_id my_mode_list_area;
int accelerantIsClone;
gx00_get_set_pci gx00_pci_access=
{
GX00_PRIVATE_DATA_MAGIC,
0,
4,
0
};
@@ -0,0 +1,288 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002.
*/
#define MODULE_BIT 0x00800000
#include <string.h>
#include "acc_std.h"
/* defined in ProposeDisplayMode.c */
extern status_t create_mode_list(void);
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;
gx00_get_private_data gpd;
// LOG not available from here to next LOG: NULL si
/* memorize the file descriptor */
fd = the_fd;
/* set the magic number so the driver knows we're for real */
gpd.magic = GX00_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, GX00_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK) goto error0;
/* clone the shared area for our use */
shared_info_area = clone_area(DRIVER_PREFIX " shared", (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;
}
// LOG is now available, si !NULL
LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d\n", si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios));
/*Check for R4.5.0 and if it is running, use work around*/
{
if (si->use_clone_bugfix)
{
/*check for R4.5.0 bug and attempt to work around*/
LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
regs = si->clone_bugfix_regs;
}
else
{
/* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/
regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&regs, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, si->regs_area);
if (regs_area < 0) {
result = regs_area;
goto error1;
}
}
}
/*FIXME - print dma addresses*/
//LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area));
/* all done */
goto error0;
error1:
delete_area(shared_info_area);
error0:
return result;
}
/* Clean up code shared between primary and cloned accelrants */
static void uninit_common(void) {
/* 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;
int pointer_reservation; //mem reserved for pointer
int cnt; //used for iteration through the overlay buffers
if (1) {
time_t now = time (NULL);
// LOG not available from here to next LOG: NULL si
// MSG(("INIT_ACCELERANT: booted since %f ms %s\n", system_time()/1000.0, real_time_clock()));
MSG(("INIT_ACCELERANT: %s", ctime (&now)));
}
/* 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;
// LOG now available: !NULL si
/* call the device specific init code */
result = gx00_general_powerup();
/* 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 error1;
}
/*
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.
*/
/* Initialize the rest of the cursor information while we're here */
si->cursor.width = 16;
si->cursor.height = 16;
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.
*/
//don't reserve memory at the start of the fb, because this doesn't work on the G100 (no SRCORG/DSTORG)
pointer_reservation = si->settings.hardcursor? 1024: 0; // apsed TODO with G100, see before
si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
/* count of issued parameters or commands */
si->engine.last_idle = si->engine.count = 0;
INIT_BEN(si->engine.lock);
INIT_BEN(si->overlay.lock);
for (cnt = 0; cnt < MAXBUFFERS; cnt++)
{
/* make sure overlay buffers are 'marked' as being free */
si->overlay.myBuffer[cnt].buffer = NULL;
si->overlay.myBuffer[cnt].buffer_dma = NULL;
}
/* make sure overlay unit is 'marked' as being free */
si->overlay.myToken = NULL;
/* bail out if something failed */
if (result != B_OK) goto error1;
/* initialise various cursor stuff*/
gx00_crtc_cursor_init();
/* ensure cursor state */
SHOW_CURSOR(false);
/* a winner! */
result = B_OK;
goto error0;
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 B_OS_NAME_LENGTH; // apsed, was MAX_GX00_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) {
gx00_device_name dn;
status_t result;
/* call the kernel driver to get the device name */
dn.magic = GX00_PRIVATE_DATA_MAGIC;
/* store the returned info directly into the passed buffer */
dn.name = (char *)data;
result = ioctl(fd, GX00_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(
DRIVER_PREFIX " 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) {
/*delete benaphore*/
DELETE_BEN(si->engine.lock);
DELETE_BEN(si->overlay.lock);
/* 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);
}
+26
View File
@@ -0,0 +1,26 @@
SubDir OBOS_TOP src add-ons accelerants matrox ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics matrox ] ;
UseHeaders [ FDirName $(SUBDIR) engine ] ;
Addon mga.accelerant : accelerants :
Acceleration.c
Cursor.c
EngineManagment.c
GetAccelerantHook.c
GetDeviceInfo.c
GetModeInfo.c
GetTimingConstraints.c
GlobalData.c
InitAccelerant.c
Overlay.c
ProposeDisplayMode.c
SetDisplayMode.c
: false : libmatrox_engine.a
;
Depends mga.accelerant : mga.driver ;
SubInclude OBOS_TOP src add-ons accelerants matrox engine ;
+664
View File
@@ -0,0 +1,664 @@
/* Written by Rudolf Cornelissen 05/09-2002 V0.13 beta1 */
/* Note on 'missing features' in BeOS 5.0.3 and DANO:
* BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
* of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?)
*/
#define MODULE_BIT 0x00000400
/* Note:
* In order to enable OVERLAY logging, in file mga.settings include a line with:
*
* logmask 0x08000604 # log OVERLAY use in full
*
* Make sure you copy the resulting file to ~/config/settings/kernel/drivers/ !
*
* Beware that enabling OVERLAY logging will create a very large logfile quickly in
* your home folder (named mga.accelerant.log) if you use double buffered overlay
* playback (100Mb will be reached in 'no time', like in a few days or so.).
*
* For testing purposes, you might want to have full logging enabled though...
*/
#include "acc_std.h"
/* define the supported overlay input colorspaces */
/* Note:
* G200-G550 can all do YUV4:2:0 2-plane colorspace as well,
* G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering),
* G200 does not support YUV4:2:0 3-plane mode while > G200 do.
* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
* definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
uint32 OVERLAY_COUNT(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: count called\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
}
/* apparantly overlay count should report the number of 'overlay units' on the card */
return 1;
}
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: supported_spaces called.\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
return NULL;
}
/* interlaced VGA is not supported by G200-G550 BES */
if (dm->timing.flags && B_TIMING_INTERLACED)
{
return NULL;
}
/* return a B_NO_COLOR_SPACE terminated list */
return &overlay_colorspaces[0];
}
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported!
{
LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
/* check what features (like the keying method) are supported on the current
* Desktop colorspace */
//fixme? Or are we talking about the overlay input bitmap's colorspace?
switch (a_color_space)
{
default:
/* fixme: for now 'direct 32bit' desktop colorspace assumed */
return
( B_OVERLAY_KEYING_USES_ALPHA |
B_OVERLAY_COLOR_KEY |
B_OVERLAY_HORIZONTAL_FILTERING |
B_OVERLAY_VERTICAL_FILTERING );
}
}
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
{
int offset = 0; /* used to determine next buffer to create */
uint32 adress, adress2, temp32; /* used to calculate buffer adresses */
uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */
int cnt; /* loopcounter */
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer)));
LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci)));
LOG(4,("Overlay: cardRAM_size = %dMb\n",si->ps.memory_size));
/* find first empty slot (room for another buffer?) */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == NULL) break;
}
LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset));
if (offset < MAXBUFFERS)
/* setup new scaler input buffer */
{
switch (cs)
{
case B_YCbCr422:
/* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0003 while > G200 need ~x0007.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
if (width == (width & ~0x0007))
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8;
}
si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
/* check if the requested horizontal pitch is supported:
* G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace.
* Compatible check done, has no downside consequences here. */
if (si->overlay.myBuffer[offset].width > 4088)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
// case 0xffff://fixme: which one(s)?
//fixme: 4:2:0 2-plane supported format, should be selected only if detected
/* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0007 while > G200 need ~x001f.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
/* if (width == (width & ~0x001f))
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32;
}
*/ /* assuming Y-plane only bytes_per_row are requested here */
/* si->overlay.myBuffer[offset].bytes_per_row = si->overlay.myBuffer[offset].width;
*/
/* check if the requested horizontal pitch is supported:
* G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace.
* Compatible check done, has no real downside consequences here. */
/* if (si->overlay.myBuffer[offset].width > 4064)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n");
*/
/* release the shared benaphore */
/* RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
*/
default:
/* unsupported colorspace! */
LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
break;
}
/* check if the requested buffer width is supported */
if (si->overlay.myBuffer[offset].width > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* check if the requested buffer height is supported */
if (height > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
si->overlay.myBuffer[offset].space = cs;
si->overlay.myBuffer[offset].height = height;
/* we define the overlay buffers to reside 'in the back' of the cards RAM */
/* NOTE to app programmers:
* Beware that an app using overlay needs to track workspace switches and screenprefs
* changes. If such an action is detected, the app needs to reset it's pointers to the
* newly created overlay bitmaps, which will be assigned by BeOS automatically after such
* an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
*
* It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
* than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
* This means that the app should also check for NULL pointers returned by the bitmaps,
* and if this happens, it needs to fallback to single buffered overlay or even fallback to
* bitmap output for the new situation. */
/* Another NOTE for app programmers:
* A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
* cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
* This *greatly* simplifies tracking such errors!
* Of course such errors may lead to strange effects in the app or driver behaviour if they are
* not hunted down and removed.. */
/* calculate first free RAM adress in card:
* Driver setup is as follows:
* card base: - hardware cursor bitmap (if used),
* directly above - screen memory for both heads */
adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */
(si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */
LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
/* calculate 'preliminary' buffer size including slopspace */
oldsize = si->overlay.myBufInfo[offset].size;
si->overlay.myBufInfo[offset].size =
si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
/* calculate virtual memory adress that would be needed for a new bitmap */
/* NOTE to app programmers:
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file mga.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uint32)((uint8*)si->framebuffer)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
* 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
/* Check if we need to modify the buffers starting adress and thus the size */
/* calculate 'would be' cardRAM offset */
temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer)));
/* check if it is aligned */
if (temp32 != (temp32 & 0xfffffff0))
{
/* update the (already calculated) buffersize to get it aligned */
si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
/* update the (already calculated) adress to get it aligned */
adress -= (temp32 - (temp32 & 0xfffffff0));
}
LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
/* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
* this is done to prevent a large buffer getting created in the space a small buffer
* occupied earlier, if not all buffers created were deleted.
* Note also that the app can delete the buffers in any order desired. */
/* NOTE to app programmers:
* If you are going to delete a overlay buffer you created, you should delete them *all* and
* then re-create only the new ones needed. This way you are sure not to get unused memory-
* space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
* If you don't, you might not get a buffer at all if you are trying to set up a larger one
* than before.
* (Indeed: not all buffers *have* to be of the same type and size...) */
for (cnt = offset; cnt < MAXBUFFERS; cnt++)
{
if (si->overlay.myBuffer[cnt].buffer != NULL)
{
/* Check if the new buffer would fit into the space the single old one used here */
if (si->overlay.myBufInfo[offset].size <= oldsize)
{
/* It does, so we reset to the old size and adresses to prevent the space from shrinking
* if we get here again... */
adress -= (oldsize - si->overlay.myBufInfo[offset].size);
si->overlay.myBufInfo[offset].size = oldsize;
LOG(4,("Overlay: 'squeezing' in buffer:\n"
"Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
/* force exiting the FOR loop */
cnt = MAXBUFFERS;
}
else
{
/* nogo, sorry */
LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
"Overlay: not enough space to 'squeeze' this one in, aborted\n"));
/* Reset to the old size to prevent the space from 'growing' if we get here again... */
si->overlay.myBufInfo[offset].size = oldsize;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
}
/* check if we have enough space to setup this new bitmap
* (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
if (adress < adress2)
/* nope, sorry */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* continue buffer setup */
si->overlay.myBuffer[offset].buffer = (void *) adress;
/* calculate physical memory adress (for dma use) */
/* NOTE to app programmers:
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file mga.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uint32)((uint8*)si->framebuffer_pci)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n",
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer),
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs));
LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return &si->overlay.myBuffer[offset];
}
else
/* sorry, no more room for buffers */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
/* Note that the user can delete the buffers in any order desired! */
{
int offset = 0;
if (ob != NULL)
{
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
/* delete current buffer */
{
si->overlay.myBuffer[offset].buffer = NULL;
si->overlay.myBuffer[offset].buffer_dma = NULL;
LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
return B_ERROR;
}
}
else
/* no buffer specified! */
{
LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
return B_ERROR;
}
}
status_t GET_OVERLAY_CONSTRAINTS
(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
{
int offset = 0;
LOG(4,("Overlay: Get_overlay_constraints called\n"));
/* check for NULL pointers */
if ((dm == NULL) || (ob == NULL) || (oc == NULL))
{
LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
return B_ERROR;
}
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
/* scaler input (values are in pixels) */
oc->view.h_alignment = 0;
oc->view.v_alignment = 0;
switch (ob->space)
{
case B_YCbCr422:
/* G200 can work with 3, > G200 need 7. Compatible setting returned for now.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
oc->view.width_alignment = 7;
break;
// case 0xffff://fixme: which one(s)? (4:2:0 supported formats. Not yet used...)
/* G200 can work with 7, > G200 need 31. Compatible setting returned for now.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
/* oc->view.width_alignment = 31;
break;
*/
default:
/* we should not be here, but set the worst-case value just to be safe anyway */
oc->view.width_alignment = 31;
break;
}
oc->view.height_alignment = 0;
oc->view.width.min = 1;
oc->view.height.min = 2; /* two fields */
oc->view.width.max = ob->width;
oc->view.height.max = ob->height;
/* scaler output restrictions */
oc->window.h_alignment = 0;
oc->window.v_alignment = 0;
oc->window.width_alignment = 0;
oc->window.height_alignment = 0;
oc->window.width.min = 2;
/* G200-G550 can output upto and including 2048 pixels in width */
if (dm->virtual_width > 2048)
{
oc->window.width.max = 2048;
}
else
{
oc->window.width.max = dm->virtual_width;
}
oc->window.height.min = 2;
/* G200-G550 can output upto and including 2048 pixels in height */
if (dm->virtual_height > 2048)
{
oc->window.height.max = 2048;
}
else
{
oc->window.height.max = dm->virtual_height;
}
/* G200-G550 scaling restrictions */
/* Adjust horizontal restrictions if pixelclock is above BES max. speed! */
/* Note: If RGB32 is implemented no scaling is supported! */
if (si->dm.timing.pixel_clock > BESMAXSPEED)
{
oc->h_scale.min = (1 * 2) / (32 - (1 / (float)16384));
oc->h_scale.max = (16384 * 2)/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
else
{
oc->h_scale.min = 1 / (32 - (1 / (float)16384));
oc->h_scale.max = 16384/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
oc->v_scale.min = 1 / (32 - (1 / (float)16384));
oc->v_scale.max = 16384/(float)ob->height;
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
overlay_token ALLOCATE_OVERLAY(void)
{
uint32 tmpToken;
LOG(4,("Overlay: Allocate_overlay called: "));
/* come up with a token */
tmpToken = 0x12345678;
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
/* overlay unit already in use? */
if (si->overlay.myToken == NULL)
/* overlay unit is available */
{
LOG(4,("succesfull\n"));
si->overlay.myToken = &tmpToken;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return si->overlay.myToken;
}
else
/* sorry, overlay unit is occupied */
{
LOG(4,("failed: already in use!\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY(overlay_token ot)
{
LOG(4,("Overlay: Release_overlay called: "));
/* is this call for real? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed, not in use!\n"));
return B_ERROR;
}
else
/* call is for real */
{
gx00_release_bes();
LOG(4,("succesfull\n"));
si->overlay.myToken = NULL;
return B_OK;
}
}
status_t CONFIGURE_OVERLAY
(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
{
int offset = 0; /* used for buffer index */
/* in BeOS R5.0.3 (maybe DANO works different):
* '*ov' is the output size on the desktop: does not change if clipped.
* h_start and v_start are always 0, width and heigth are the size of the window.
* Because the width and height can also be found in '*ow', '*ov' is not used. */
LOG(4,("Overlay: Configure_overlay called: "));
/* Note:
* When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
* release all overlay buffers. The buffer currently displayed at that moment, may need some
* 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
* called one more time then, with a null pointer for overlay_window and overlay_view, while
* the currently displayed overlay_buffer is given.
* The G200-G550 do not need to do anything on such an occasion, so we simply return if we
* get called then. */
if ((ow == NULL) || (ov == NULL))
{
LOG(4,("output properties changed\n"));
return B_OK;
}
/* Note:
* If during overlay use the screen prefs are changed, or the workspace has changed, it
* may be that we were not able to re-allocate the requested overlay buffers (or only partly)
* due to lack of cardRAM. If the app does not respond properly to this, we might end up
* with a NULL pointer instead of a overlay_buffer to work with here.
* Of course, we need to abort then to prevent the system from 'going down'.
* The app will probably crash because it will want to write into this non-existant buffer
* at some point. */
if (ob == NULL)
{
LOG(4,("no overlay buffer specified\n"));
return B_ERROR;
}
/* is this call done by the app that owns us? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed\n"));
return B_ERROR;
}
else
/* call is for real */
{
/* find the buffer's offset */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
LOG(4,("succesfull, switching to buffer %d\n", offset));
gx00_configure_bes(ob, ow, offset);
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
}
@@ -0,0 +1,409 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors for MGA driver:
Mark Watson,
Rudolf Cornelissen 9/2002
*/
#define MODULE_BIT 0x00400000
#include "acc_std.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))
/*some monitors only handle a fixed set of modes*/
#include "valid_mode_list"
/*Standard VESA modes*/
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, 1550, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 120000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 120000, 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, 1680, 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) */
};
// apsed, adjust virtual width for CRTC offset constraints
// PB with MIl2 800*600 with bpp < 32
static status_t adjust_width (display_mode *target, bool want_same_width)
{
uint32 video_pitch = target->virtual_width;
uint32 multiple;
if (si->ps.card_type < G100) switch (target->space & 0x0fff) { // MIL2
case B_CMAP8: multiple = 128; break;
case B_RGB15: multiple = 64; break;
case B_RGB16: multiple = 64; break;
case B_RGB24: multiple = 128; break;
case B_RGB32: multiple = 32; break;
default:
LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
} else switch (target->space & 0x0fff) { // G100, G200, G400
case B_CMAP8: multiple = 16; break;
case B_RGB15: multiple = 8; break;
case B_RGB16: multiple = 8; break;
case B_RGB24: multiple = 16; break;
case B_RGB32: multiple = 4; break;
default:
LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
video_pitch = (video_pitch+multiple-1)/multiple;
video_pitch *= multiple;
if (target->virtual_width != video_pitch) {
LOG(2,("PROPOSEMODE: color space 0x%08x, virtual_width %d adjusted to %d \n",
target->space, target->virtual_width, video_pitch));
target->virtual_width = video_pitch;
if (want_same_width) target->timing.h_display = video_pitch;
}
return B_OK;
}
/*Check mode is between low and high limits
returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
*/
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
status_t status;
float pix_clock_found;
uint8 m,n,p;
status_t result = B_OK;
uint32 row_bytes, limit_clock, max_vclk;
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;
// // apsed, adjust virtual width for CRTC offset constraints
// status = adjust_width (target, want_same_width);
// if (status != B_OK) return status;
/*check valid list:
if (VALID_REQUIRED is set)
{
if (find modes with same size)
{
pick one with nearest pixel clock
}
else
{
pick next largest with nearest pixel clock and modify visible portion as far as possible
}
}
*/
#ifdef VALID_MODE_REQUIRED
{
int i;
int closest_mode_ptr;
uint32 closest_mode_clock;
closest_mode_ptr = 0xbad;
closest_mode_clock = 0;
for (i=0;i<VALID_MODES;i++)
{
/*check size is ok and clock is better than any found before*/
if(
target->timing.h_display==valid_mode_list[i].h_display &&
target->timing.v_display==valid_mode_list[i].v_display
)
{
if (
abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)<
abs(closest_mode_clock-target->timing.pixel_clock)
)
{
closest_mode_clock=valid_mode_list[i].pixel_clock;
closest_mode_ptr=i;
}
}
}
if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
{
return B_ERROR;
}
else
{
target->timing=valid_mode_list[closest_mode_ptr];
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
(
(double)target->timing.h_total *
(double)target->timing.v_total
);
}
}
#endif
/*find a nearby valid timing from that given*/
result = gx00_crtc_validate_timing
(
&target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
&target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
);
if (result == B_ERROR) return result;
/*check if timing found is within the requested horizontal 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;
/*check if timing found is within the requested vertical 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.v_sync_start) || // apsed
(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;
//rudolf
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
if (si->ps.card_type >= G100)
{
/* calculate settings, but do not actually test anything (that costs too much time!) */
status = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
}
else
{
//fixme: implement pixelclock limits check (and modify if needed) for target mode inside mil2_find routine!
//temp until then:
limit_clock = si->ps.max_dac1_clock * 1000;
if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock;
status = mil2_dac_pix_pll_find((float)target->timing.pixel_clock/1000.0,&pix_clock_found,&m,&n,&p);
}
target->timing.pixel_clock = pix_clock_found*1000;
//end rudolf
/* 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 > 4096)
target->virtual_width = 4096;
if (target->virtual_height > 2048)
target->virtual_height = 2048;
/* adjust virtual width for engine limitations - must be multiple of 8 */
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;
// apsed, adjust virtual width for CRTC offset constraints
status = adjust_width (target, want_same_width);
if (status != B_OK) return status;
/* calculate rowbytes after we've nailed the virtual width */
switch (target->space & 0x0fff) {
case B_CMAP8:
row_bytes = 1;
break;
case B_RGB15:
case B_RGB16:
row_bytes = 2;
break;
case B_RGB32:
row_bytes = 4;
break;
default:
/* no amount of adjusting will fix not being able to support the pixel format */
LOG(8,("PROPOSEMODE: unknown target space: 0x%08x\n", target->space));
return B_ERROR;
}
row_bytes *= target->virtual_width;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) > (si->ps.memory_size * 1024 * 1024))
target->virtual_height = (si->ps.memory_size * 1024 * 1024) / row_bytes;
if (target->virtual_height < target->timing.v_display)
{
LOG(8,("PROPOSEMODE: virtual_height required %d < %d\n", target->virtual_height, target->timing.v_display));
return B_ERROR;
}
else if (
(target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height)
) result = B_BAD_VALUE;
/* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
switch (target->space)
{
case B_CMAP8:
max_vclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_vclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_vclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
max_vclk = si->ps.max_dac2_clock_32dh;
break;
default:
/* use fail-safe value */
max_vclk = si->ps.max_dac2_clock_32dh;
break;
}
/*clear DUALHEAD_CAPABLE if any problems*/
if
(
((target->flags)& DUALHEAD_CAPABLE ) &&
(
(!si->ps.secondary_head) ||
((1024 + (row_bytes * (target->virtual_height+1) * 2)) > (si->ps.memory_size * 1024 * 1024)) || /*note: extra line for maven vblank!*/
(target->space == B_CMAP8) ||
(target->space == B_RGB15_LITTLE) ||
(target->timing.pixel_clock > (max_vclk * 1000))
)
)
{
target->flags&=~DUALHEAD_CAPABLE;
}
/*set tv capable suitable*/
if (target->flags&DUALHEAD_CAPABLE)
{
if ((target->timing.pixel_clock <= 120000 ) && (target->timing.pixel_clock >= 40000))
{
target->flags|=TV_CAPABLE;
}
}
return result;
}
/* Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff)
*/
uint32 ACCELERANT_MODE_COUNT(void) {
return si->mode_count;
}
/* Copy the list of guaranteed supported video modes to the location provided.*/
status_t GET_MODE_LIST(display_mode *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;
color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8};
/* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE*/
max_size = (((MODE_COUNT * 4) * 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("G400 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 = 4096;
/* do it once for each depth we want to support */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
{
/* set target values for single head (propose will return if capable)*/
*dst = *src;
/* poke the specific space*/
dst->space = low.space = high.space = spaces[j];
dst->flags |= DUALHEAD_CAPABLE;
dst->flags |= B_SUPPORTS_OVERLAYS;
//fixme: we need to distinquish somehow between head 1 and head 2, as overlay only works on head 1...
/* ask for a compatible mode */
if (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,577 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x00200000
#include "acc_std.h"
#include "matroxfb_maven_hack.h" //a port of the matroxfb code to do TVout - used with permission
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
*/
static void interrupt_enable(bool flag) {
status_t result;
gx00_set_bool_state sbs;
/* set the magic number so the driver knows we're for real */
sbs.magic = GX00_PRIVATE_DATA_MAGIC;
sbs.do_it = flag;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, GX00_RUN_INTERRUPTS, &sbs, sizeof(sbs));
}
// apsed TODO gx00_crtc_mem_priority() ??
// /*calculate if high priority request are needed and how many*/
// Tpix = 1000000.0/(dm->timing.pixel_clock);
// Tmclk = si->ps.mem_clk_period;
// temp = (128/colour_depth);
// HIPRILVL = 64*Tmclk + (1-46*(temp))*Tpix;
// HIPRILVL/= -8*Tpix*temp;
// gx00_crtc_mem_priority((uint8)HIPRILVL);
// /*XXX - memory priority*/
/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
display_mode bounds, target;
uint8 colour_depth=32;
status_t result;
uint32 startadd,startadd_right;
// double HIPRILVL;
// double Tmclk,Tpix,temp;
// apsed TODO startadd is 19 bits if < g200
uint8 display,h,v;
struct my_timming tv_timing;
struct mavenregs tv_regs;
bool switched_crtcs = false;
/* Adjust mode to valid one and fail if invalid */
target = bounds = *mode_to_set;
/* show the mode bits */
LOG(1, ("SetDisplayMode - initial flags: %x\n", target.flags));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "timing.pixel_clock", mode_to_set->timing.pixel_clock, mode_to_set->timing.pixel_clock));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_width", mode_to_set->virtual_width, mode_to_set->virtual_width));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_height", mode_to_set->virtual_height, mode_to_set->virtual_height));
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR)
return B_ERROR;
/* if not dualhead capable be sure mode is set to single head */
if ((!si->ps.secondary_head) || (!(target.flags&DUALHEAD_CAPABLE)))
{
target.flags&=~DUALHEAD_BITS;
target.flags&=~TV_BITS;
}
else if (!(target.flags&TV_CAPABLE))
{
target.flags&=~TV_BITS;
}
LOG(1, ("SetDisplayMode - validated flags: %x\n", target.flags));
/* disable interrupts using the kernel driver */
interrupt_enable(false);
/*find current DPMS state, then turn off screen*/
gx00_crtc_dpms_fetch(&display,&h,&v);
gx00_crtc_dpms(0,0,0);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
startadd=(si->fbc.frame_buffer)-(si->framebuffer);
/*Perform the very long mode switch!*/
LOG(1,("DUALHEAD: %d\n",target.flags&DUALHEAD_BITS));
if ((target.flags&DUALHEAD_BITS)) /*if some dualhead mode*/
{
/*set the pixel clock PLL(s)*/
if (gx00_dac_set_pix_pll(target)==B_ERROR)
LOG(8,("SET: error setting pixel clock (internal DAC)\n"));
if (si->ps.secondary_head)
{
if (gx00_maven_set_pix_pll((target.timing.pixel_clock)/1000.0)==B_ERROR)
LOG(8,("SET: error setting pixel clock (MAVEN)\n"));
}
else
{
LOG(8,("SET: not setting maven clock (G450?)\n"));
}
/*set the colour depth for CRTC1, CRTC2 and the DAC*/
switch(target.space)
{
case B_RGB16_LITTLE:
colour_depth=16;
gx00_dac_mode(BPP16,1.0);
gx00_crtc_depth(BPP16);
g400_crtc2_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth=32;
gx00_dac_mode(BPP32,1.0);
gx00_crtc_depth(BPP32);
g400_crtc2_depth(BPP32DIR);
break;
default:
LOG(8,("SET: Invalid dualhead colour depth 0x%08x - should never happen!\n", target.space));
}
/*set the display(s) pitches*/
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth);
g400_crtc2_set_display_pitch (target.virtual_width, colour_depth);
/*work out where the "right" screen starts*/
startadd_right=startadd+(target.timing.h_display*(colour_depth>>3));
/*set the output DAC*/
switch (si->ps.card_type)
{
case G450:
gx00_general_dac_select(DS_CRTCDAC_CRTC2DAC2);
switched_crtcs = false;
break;
case G400:case G400MAX:
gx00_general_dac_select(DS_CRTCMAVEN_CRTC2DAC);
switched_crtcs = false;
break;
default:
break;
}
if (switched_crtcs)
{
int temp = startadd;
startadd = startadd_right;
startadd_right = temp;
}
/*Tell card what memory to display*/
si->crtc_delay=17+4*(colour_depth==16);
switch (target.flags&DUALHEAD_BITS)
{
case DUALHEAD_ON:
gx00_crtc_set_display_start(startadd_right,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_CLONE:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_SWITCH:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth);
break;
}
/*set the timing*/
result = gx00_crtc_set_timing /*crtc1*/
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
(target.timing.v_display+1), /*extra "blanking" line for MAVEN*/
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
result = g400_crtc2_set_timing
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
(target.timing.v_display),
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
if (si->ps.secondary_head)
{
result = gx00_maven_set_timing /*maven*/
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
(target.timing.v_display+1), /*extra "blanking" line*/
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
}
/*turn screen one on and screen two on*/
gx00_crtc_dpms(display,h,v);
g400_crtc2_dpms(display,h,v);
if (si->ps.secondary_head)
gx00_maven_dpms(display,h,v);
/*TVout support*/
if (si->ps.secondary_tvout && (target.flags&TV_BITS))
{
si->crtc_delay+=5;
/*create a my tim(m)ing structure... for tvout*/
tv_timing.pixclock = target.timing.pixel_clock;
tv_timing.HDisplay = target.timing.h_display;
tv_timing.HSyncStart = target.timing.h_sync_start;
tv_timing.HSyncEnd = target.timing.h_sync_end;
tv_timing.HTotal = target.timing.h_total;
tv_timing.VDisplay = target.timing.v_display;
tv_timing.VSyncStart = target.timing.v_sync_start;
tv_timing.VSyncEnd = target.timing.v_sync_end;
tv_timing.VTotal = target.timing.v_total;
tv_timing.delay=si->crtc_delay;
if (target.flags&TV_PAL)
{
LOG(2, ("OUTMODE: PAL\n"));
maven_set_mode(2);
}
else
{
LOG(2, ("OUTMODE: NTSC\n"));
maven_set_mode(1);
}
maven_out_compute(&tv_timing, &tv_regs);
maven_out_program(&tv_regs);
maven_out_start();
}
}
else /*single head mode*/
{
status_t status;
int colour_mode = BPP32;
switch(target.space)
{
case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth = 32; colour_mode = BPP32; break;
default:
LOG(8,("SET: Invalid singlehead colour depth 0x%08x\n", target.space));
return B_ERROR;
}
/*set the pixel clock PLL*/
if (si->ps.card_type >= G100)
status = gx00_dac_set_pix_pll(target);
else status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth);
if (status==B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
/*set the colour depth for CRTC1 and the DAC*/
if (si->ps.card_type >= G100) gx00_dac_mode(colour_mode,1.0);
else mil2_dac_mode(colour_mode,1.0,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC,
target.timing.flags&B_SYNC_ON_GREEN);
gx00_crtc_depth(colour_mode);
/*set the display pitch*/
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth);
/*tell the card what memory to display*/
gx00_crtc_set_display_start(startadd,colour_depth);
if (si->ps.card_type >= G100)
gx00_general_dac_select(DS_CRTCDAC_CRTC2MAVEN);
/*set the timing*/
result = gx00_crtc_set_timing /*crtc1*/
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
target.timing.v_display,
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
/*turn screen one on and screen two off*/
gx00_crtc_dpms(display,h,v);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
}
/*update driver's mode store*/
si->dm=target;
si->fbc.bytes_per_row=target.virtual_width*(colour_depth>>3);
/*set up acceleration for this mode*/
si->dm.virtual_height+=1;//for clipping!
gx00_acc_init();
si->dm.virtual_height-=1;
/*clear line at bottom of screen (For maven) if dualhead mode*/
gx00_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0);
MSG(("INIT_ACCELERANT: booted since %f ms\n", system_time()/1000.0));
/* enable interrupts using the kernel driver */
interrupt_enable(true);
/* Tune RAM CAS-latency if needed. Must be done *here*! */
mga_set_cas_latency();
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) {
uint8 colour_depth;
uint32 startadd,startadd_right;
LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
/* G400 CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit
G400 CRTC2 handles multiples of 32 for 16-bit and 16 for 32-bit - must stoop to this in dualhead
*/
/* reset lower bits, don't return an error! */
if (si->dm.flags&DUALHEAD_BITS)
{
switch(si->dm.space)
{
case B_RGB16_LITTLE:
colour_depth=16;
h_display_start &= ~0x1f;
break;
case B_RGB32_LITTLE:
colour_depth=32;
h_display_start &= ~0x0f;
break;
default:
LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space));
return B_ERROR;
}
}
else
{
switch(si->dm.space)
{
case B_CMAP8:
colour_depth=8;
h_display_start &= ~0x07;
break;
case B_RGB15_LITTLE: case B_RGB16_LITTLE:
colour_depth=16;
h_display_start &= ~0x03;
break;
case B_RGB32_LITTLE:
colour_depth=32;
h_display_start &= ~0x01;
break;
default:
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 */
startadd=v_display_start*(si->dm.virtual_width*colour_depth)>>3;
startadd+=h_display_start;
startadd+=(si->fbc.frame_buffer)-(si->framebuffer);
startadd_right=startadd+si->dm.timing.h_display*(colour_depth>>3);
interrupt_enable(false);
switch (si->dm.flags&DUALHEAD_BITS)
{
case DUALHEAD_ON:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth);
break;
case DUALHEAD_OFF:
gx00_crtc_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_CLONE:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_SWITCH:
g400_crtc2_set_display_start(startadd,colour_depth);
gx00_crtc_set_display_start(startadd_right,colour_depth);
break;
}
interrupt_enable(true);
return B_OK;
}
/*
Set the indexed color palette.
*/
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
int i;
uint8 *r,*g,*b;
/* Protect gamma correction when not in CMAP8 */
if (si->dm.space != B_CMAP8) return;
r=si->color_data;
g=r+256;
b=g+256;
i=first;
while (count--)
{
r[i]=*color_data++;
g[i]=*color_data++;
b[i]=*color_data++;
i++;
}
if (si->ps.card_type >= G100) gx00_dac_palette(r,g,b);
else mil2_dac_palette(r,g,b);
}
/* 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) {
interrupt_enable(false);
LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
if (si->dm.flags&DUALHEAD_BITS) /*dualhead*/
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on */
gx00_crtc_dpms(1,1,1);
g400_crtc2_dpms(1,1,1);
if (si->ps.secondary_head)
gx00_maven_dpms(1,1,1);
break;
case B_DPMS_STAND_BY:
gx00_crtc_dpms(0,0,1);
g400_crtc2_dpms(0,0,1);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,1);
break;
case B_DPMS_SUSPEND:
gx00_crtc_dpms(0,1,0);
g400_crtc2_dpms(0,1,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,1,0);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
gx00_crtc_dpms(0,0,0);
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
else /*singlehead*/
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on */
gx00_crtc_dpms(1,1,1);
break;
case B_DPMS_STAND_BY:
gx00_crtc_dpms(0,0,1);
break;
case B_DPMS_SUSPEND:
gx00_crtc_dpms(0,1,0);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
gx00_crtc_dpms(0,0,0);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
interrupt_enable(true);
return B_OK;
}
/*
Report device DPMS capabilities.
*/
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) {
uint8 display,h,v;
interrupt_enable(false);
gx00_crtc_dpms_fetch(&display,&h,&v);
interrupt_enable(true);
if (display&h&v)
return B_DPMS_ON;
else if(v)
return B_DPMS_STAND_BY;
else if(h)
return B_DPMS_SUSPEND;
else
return B_DPMS_OFF;
}
+17
View File
@@ -0,0 +1,17 @@
/*
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 <stdio.h>
#include <sys/ioctl.h>
#include "DriverInterface.h"
#include "global.h"
//apsed #include "mga_extern.h"
#include "mga_proto.h"
#include "be_driver_proto.h"
#endif
@@ -0,0 +1,66 @@
/*
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>
#include "video_overlay.h"
#define DEBUG 1
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 SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, 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);
/* video_overlay */
uint32 OVERLAY_COUNT(const display_mode *dm);
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm);
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space);
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height);
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob);
status_t GET_OVERLAY_CONSTRAINTS(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc);
overlay_token ALLOCATE_OVERLAY(void);
status_t RELEASE_OVERLAY(overlay_token ot);
status_t CONFIGURE_OVERLAY(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov);
#endif
@@ -0,0 +1,20 @@
SubDir OBOS_TOP src add-ons accelerants matrox engine ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics matrox ] ;
UseHeaders [ FDirName $(SUBDIR) .. ] ;
StaticLibrary matrox_engine :
matroxfb_maven_hack.c
mga_acc.c
mga_bes.c
mga_crtc.c
mga_crtc2.c
mga_dac.c
mga_general.c
mga_i2c.c
mga_info.c
mga_maven.c
mga_support.c
tvp3026.c
;
@@ -0,0 +1,9 @@
The files in this directory (and any other files beginning with "mga_") are independent from Be's sample code
Basically, freely copy them, edit them etc. Just do not claim you wrote them.
Will think of something more official to put here later:)
Mark Watson
Notes: This excludes the maven_hack port of matroxfb's maven stuff - see notes in that file for info.
@@ -0,0 +1,879 @@
#define MODULE_BIT 0x00100000
#include "mga_std.h"
#include "matroxfb_maven_hack.h"
#define MODE_PAL 1
#define MODE_NTSC 2
#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC))
#define MODE_MONITOR 128
static int mode = MODE_PAL;
static const struct matrox_pll_features maven_pll = {
50000,
27000,
4, 127,
2, 31,
3
};
static const struct matrox_pll_features2 maven1000_pll = {
50000000,
300000000,
5, 128,
3, 32,
3
};
static const struct matrox_pll_ctl maven_PAL = {
540000,
50
};
static const struct matrox_pll_ctl maven_NTSC = {
450450, /* 27027000/60 == 27000000/59.94005994 */
60
};
int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
unsigned int* in, unsigned int* feed, unsigned int* post) {
unsigned int bestdiff = ~0;
unsigned int bestvco = 0;
unsigned int fxtal = pll->ref_freq;
unsigned int fwant;
unsigned int p;
LOG(4,("PLL_calcclock"));
fwant = freq;
for (p = 1; p <= pll->post_shift_max; p++) {
if (fwant * 2 > fmax)
break;
fwant *= 2;
}
if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min;
if (fwant > fmax) fwant = fmax;
for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
unsigned int m;
if (fwant < pll->vco_freq_min) break;
for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
unsigned int diff, fvco;
unsigned int n;
n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
if (n > pll->feed_div_max)
break;
if (n < pll->feed_div_min)
n = pll->feed_div_min;
fvco = (fxtal * (n + 1)) / (m + 1);
if (fvco < fwant)
diff = fwant - fvco;
else
diff = fvco - fwant;
if (diff < bestdiff) {
bestdiff = diff;
*post = p;
*in = m;
*feed = n;
bestvco = fvco;
}
}
}
LOG(4,("clk: %x %x %x %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant));
return bestvco;
}
int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
const struct matrox_pll_ctl* ctl,
unsigned int htotal, unsigned int vtotal,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* h2) {
unsigned int besth2 = 0;
unsigned int fxtal = ctl->ref_freq;
unsigned int fmin = pll->vco_freq_min / ctl->den;
unsigned int fwant;
unsigned int p;
unsigned int scrlen;
unsigned int fmax;
LOG(4,("PLL_calcclock"));
scrlen = htotal * (vtotal - 1);
fwant = htotal * vtotal;
fmax = pll->vco_freq_max / ctl->den;
LOG(2, ("FVMAB:want: %x, xtal: %x, h: %x, v: %x, fmax: %x\n",
fwant, fxtal, htotal, vtotal, fmax));
for (p = 1; p <= pll->post_shift_max; p++) {
if (fwant * 2 > fmax)
break;
fwant *= 2;
}
if (fwant > fmax)
return 0;
for (; p-- > 0; fwant >>= 1) {
unsigned int m;
if (fwant < fmin) break;
for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
unsigned int n;
unsigned int dvd;
unsigned int ln;
n = (fwant * m) / fxtal;
if (n < pll->feed_div_min)
continue;
if (n > pll->feed_div_max)
break;
ln = fxtal * n;
dvd = m << p;
if (ln % dvd)
continue;
ln = ln / dvd;
if (ln < scrlen + 2)
continue;
ln = ln - scrlen;
if (ln > htotal)
continue;
LOG(2,("FBMAV:Match: %x / %x / %x / %x\n", n, m, p, ln));
if (ln > besth2) {
LOG(2, ("FBMAV:Better...\n"));
*h2 = besth2 = ln;
*post = p;
*in = m;
*feed = n;
}
}
}
if (besth2 < 2)
return 0;
LOG(4,("FBMAV:clk: %x %x %x %d %d\n", *in, *feed, *post, fxtal, fwant));
return fxtal * (*feed) / (*in) * ctl->den;
}
unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
unsigned int htotal, unsigned int vtotal,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* htotal2) {
unsigned int fvco;
unsigned int p;
fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
if (!fvco)
return -EINVAL;
p = (1 << p) - 1;
if (fvco <= 100000000)
;
else if (fvco <= 140000000)
p |= 0x08;
else if (fvco <= 180000000)
p |= 0x10;
else
p |= 0x18;
*post = p;
return 0;
}
void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
unsigned int* in, unsigned int* feed, unsigned int* post) {
unsigned int fvco;
unsigned int p;
fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
p = (1 << p) - 1;
if (fvco <= 100000)
;
else if (fvco <= 140000)
p |= 0x08;
else if (fvco <= 180000)
p |= 0x10;
else
p |= 0x18;
*post = p;
return;
}
void maven_init_TVdata
(
struct mavenregs* data
)
{
static struct mavenregs palregs = { {
0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
0x00,
0x00, /* ? not written */
0x00, /* modified by code (F9 written...) */
0x00, /* ? not written */
0x7E, /* 08 */
0x44, /* 09 */
0x9C, /* 0A */
0x2E, /* 0B */
0x21, /* 0C */
0x00, /* ? not written */
0x3F, 0x03, /* 0E-0F */
0x3F, 0x03, /* 10-11 */
0x1A, /* 12 */
0x2A, /* 13 */
0x1C, 0x3D, 0x14, /* 14-16 */
0x9C, 0x01, /* 17-18 */
0x00, /* 19 */
0xFE, /* 1A */
0x7E, /* 1B */
0x60, /* 1C */
0x05, /* 1D */
0x89, 0x03, /* 1E-1F */
0x72, /* 20 */
0x07, /* 21 */
0x72, /* 22 */
0x00, /* 23 */
0x00, /* 24 */
0x00, /* 25 */
0x08, /* 26 */
0x04, /* 27 */
0x00, /* 28 */
0x1A, /* 29 */
0x55, 0x01, /* 2A-2B */
0x26, /* 2C */
0x07, 0x7E, /* 2D-2E */
0x02, 0x54, /* 2F-30 */
0xB0, 0x00, /* 31-32 */
0x14, /* 33 */
0x49, /* 34 */
0x00, /* 35 written multiple times */
0x00, /* 36 not written */
0xA3, /* 37 */
0xC8, /* 38 */
0x22, /* 39 */
0x02, /* 3A */
0x22, /* 3B */
0x3F, 0x03, /* 3C-3D */
0x00, /* 3E written multiple times */
0x00, /* 3F not written */
}, MODE_PAL, 625, 50 };
static struct mavenregs ntscregs = { {
0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0x00,
0x00, /* ? not written */
0x00, /* modified by code (F9 written...) */
0x00, /* ? not written */
0x7E, /* 08 */
0x43, /* 09 */
0x7E, /* 0A */
0x3D, /* 0B */
0x00, /* 0C */
0x00, /* ? not written */
0x41, 0x00, /* 0E-0F */
0x3C, 0x00, /* 10-11 */
0x17, /* 12 */
0x21, /* 13 */
0x1B, 0x1B, 0x24, /* 14-16 */
0x83, 0x01, /* 17-18 */
0x00, /* 19 */
0x0F, /* 1A */
0x0F, /* 1B */
0x60, /* 1C */
0x05, /* 1D */
0x89, 0x02, /* 1E-1F */
0x5F, /* 20 */
0x04, /* 21 */
0x5F, /* 22 */
0x01, /* 23 */
0x02, /* 24 */
0x00, /* 25 */
0x0A, /* 26 */
0x05, /* 27 */
0x00, /* 28 */
0x10, /* 29 */
0xFF, 0x03, /* 2A-2B */
0x24, /* 2C */
0x0F, 0x78, /* 2D-2E */
0x00, 0x00, /* 2F-30 */
0xB2, 0x04, /* 31-32 */
0x14, /* 33 */
0x02, /* 34 */
0x00, /* 35 written multiple times */
0x00, /* 36 not written */
0xA3, /* 37 */
0xC8, /* 38 */
0x15, /* 39 */
0x05, /* 3A */
0x3B, /* 3B */
0x3C, 0x00, /* 3C-3D */
0x00, /* 3E written multiple times */
0x00, /* never written */
}, MODE_NTSC, 525, 60 };
if (mode & MODE_PAL)
*data = palregs;
else
*data = ntscregs;
data->regs[0x93] = 0xA2;
/* gamma correction registers */
data->regs[0x83] = 0x00;
data->regs[0x84] = 0x00;
data->regs[0x85] = 0x00;
data->regs[0x86] = 0x1F;
data->regs[0x87] = 0x10;
data->regs[0x88] = 0x10;
data->regs[0x89] = 0x10;
data->regs[0x8A] = 0x64; /* 100 */
data->regs[0x8B] = 0xC8; /* 200 */
return;
}
#define LR(x) i2c_maven_write((x), m->regs[(x)])
#define LRP(x) MAVWWP((x), (m->regs[(x)]|m->regs[(x+1)]<<8))
void maven_init_TV
(
const struct mavenregs* m
)
{
int val;
i2c_maven_write( 0x3E, 0x01);
i2c_maven_read( 0x82); /* fetch oscillator state? */
i2c_maven_write( 0x8C, 0x00);
i2c_maven_read( 0x94); /* get 0x82 */
i2c_maven_write( 0x94, 0xA2);
/* xmiscctrl */
MAVWWP(0x8E, 0x1EFF);
i2c_maven_write( 0xC6, 0x01);
/* removed code... */
i2c_maven_read( 0x06);
i2c_maven_write( 0x06, 0xF9); /* or read |= 0xF0 ? */
/* removed code here... */
/* real code begins here? */
/* chroma subcarrier */
LR(0x00); LR(0x01); LR(0x02); LR(0x03);
LR(0x04);
LR(0x2C);
LR(0x08);
LR(0x0A);
LR(0x09);
LR(0x29);
LRP(0x31);
LRP(0x17);
LR(0x0B);
LR(0x0C);
if (m->mode & MODE_PAL) {
i2c_maven_write( 0x35, 0x10); /* ... */
} else {
i2c_maven_write( 0x35, 0x0F); /* ... */
}
LRP(0x10);
LRP(0x0E);
LRP(0x1E);
LR(0x20); /* saturation #1 */
LR(0x22); /* saturation #2 */
LR(0x25); /* hue */
LR(0x34);
LR(0x33);
LR(0x19);
LR(0x12);
LR(0x3B);
LR(0x13);
LR(0x39);
LR(0x1D);
LR(0x3A);
LR(0x24);
LR(0x14);
LR(0x15);
LR(0x16);
LRP(0x2D);
LRP(0x2F);
LR(0x1A);
LR(0x1B);
LR(0x1C);
LR(0x23);
LR(0x26);
LR(0x28);
LR(0x27);
LR(0x21);
LRP(0x2A);
if (m->mode & MODE_PAL)
i2c_maven_write( 0x35, 0x1D); /* ... */
else
i2c_maven_write( 0x35, 0x1C);
LRP(0x3C);
LR(0x37);
LR(0x38);
i2c_maven_write( 0xB3, 0x01);
i2c_maven_read( 0xB0); /* read 0x80 */
i2c_maven_write( 0xB0, 0x08); /* ugh... */
i2c_maven_read( 0xB9); /* read 0x7C */
i2c_maven_write( 0xB9, 0x78);
i2c_maven_read( 0xBF); /* read 0x00 */
i2c_maven_write( 0xBF, 0x02);
i2c_maven_read( 0x94); /* read 0x82 */
i2c_maven_write( 0x94, 0xB3);
LR(0x80); /* 04 1A 91 or 05 21 91 */
LR(0x81);
LR(0x82);
i2c_maven_write( 0x8C, 0x20);
i2c_maven_read( 0x8D);
i2c_maven_write( 0x8D, 0x10);
LR(0x90); /* 4D 50 52 or 4E 05 45 */
LR(0x91);
LR(0x92);
LRP(0x9A); /* 0049 or 004F */
LRP(0x9C); /* 0004 or 0004 */
LRP(0x9E); /* 0458 or 045E */
LRP(0xA0); /* 05DA or 051B */
LRP(0xA2); /* 00CC or 00CF */
LRP(0xA4); /* 007D or 007F */
LRP(0xA6); /* 007C or 007E */
LRP(0xA8); /* 03CB or 03CE */
LRP(0x98); /* 0000 or 0000 */
LRP(0xAE); /* 0044 or 003A */
LRP(0x96); /* 05DA or 051B */
LRP(0xAA); /* 04BC or 046A */
LRP(0xAC); /* 004D or 004E */
LR(0xBE);
LR(0xC2);
i2c_maven_read( 0x8D);
i2c_maven_write( 0x8D, 0x00);
LR(0x20); /* saturation #1 */
LR(0x22); /* saturation #2 */
LR(0x93); /* whoops */
LR(0x20); /* oh, saturation #1 again */
LR(0x22); /* oh, saturation #2 again */
LR(0x25); /* hue */
LRP(0x0E);
LRP(0x1E);
LRP(0x0E); /* problems with memory? */
LRP(0x1E); /* yes, matrox must have problems in memory area... */
/* load gamma correction stuff */
LR(0x83);
LR(0x84);
LR(0x85);
LR(0x86);
LR(0x87);
LR(0x88);
LR(0x89);
LR(0x8A);
LR(0x8B);
val = i2c_maven_read( 0x8D);
val &= 0x10; /* 0x10 or anything ored with it */
i2c_maven_write( 0x8D, val);
LR(0x33);
LR(0x19);
LR(0x12);
LR(0x3B);
LR(0x13);
LR(0x39);
LR(0x1D);
LR(0x3A);
LR(0x24);
LR(0x14);
LR(0x15);
LR(0x16);
LRP(0x2D);
LRP(0x2F);
LR(0x1A);
LR(0x1B);
LR(0x1C);
LR(0x23);
LR(0x26);
LR(0x28);
LR(0x27);
LR(0x21);
LRP(0x2A);
if (m->mode & MODE_PAL)
i2c_maven_write( 0x35, 0x1D);
else
i2c_maven_write( 0x35, 0x1C);
LRP(0x3C);
LR(0x37);
LR(0x38);
i2c_maven_read( 0xB0);
LR(0xB0); /* output mode */
LR(0x90);
LR(0xBE);
LR(0xC2);
LRP(0x9A);
LRP(0xA2);
LRP(0x9E);
LRP(0xA6);
LRP(0xAA);
LRP(0xAC);
i2c_maven_write( 0x3E, 0x00);
i2c_maven_write( 0x95, 0x20);
}
int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
struct mavenregs* m) {
unsigned int x;
unsigned int err = ~0;
/* 1:1 */
m->regs[0x80] = 0x0F;
m->regs[0x81] = 0x07;
m->regs[0x82] = 0x81;
for (x = 0; x < 8; x++) {
unsigned int a, b, c, h2;
unsigned int h = ht + 2 + x;
if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
unsigned int diff = h - h2;
if (diff < err) {
err = diff;
m->regs[0x80] = a - 1;
m->regs[0x81] = b - 1;
m->regs[0x82] = c | 0x80;
m->hcorr = h2 - 2;
m->htotal = h - 2;
}
}
}
return err != ~0U;
}
//called from main access points...
inline int maven_compute_timing
(
struct my_timming* mt,
struct mavenregs* m
)
{
unsigned int tmpi;
unsigned int a, bv, c;
m->mode = mode;
if (MODE_TV(mode)) {
unsigned int lmargin;
unsigned int umargin;
unsigned int vslen;
unsigned int hcrt;
unsigned int slen;
maven_init_TVdata(m);
if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
return -EINVAL;
lmargin = mt->HTotal - mt->HSyncEnd;
slen = mt->HSyncEnd - mt->HSyncStart;
hcrt = mt->HTotal - slen - mt->delay;
umargin = mt->VTotal - mt->VSyncEnd;
vslen = mt->VSyncEnd - mt->VSyncStart;
if (m->hcorr < mt->HTotal)
hcrt += m->hcorr;
if (hcrt > mt->HTotal)
hcrt -= mt->HTotal;
if (hcrt + 2 > mt->HTotal)
hcrt = 0; /* or issue warning? */
/* last (first? middle?) line in picture can have different length */
/* hlen - 2 */
m->regs[0x96] = m->hcorr;
m->regs[0x97] = m->hcorr >> 8;
/* ... */
m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
/* hblanking end */
m->regs[0x9A] = lmargin; /* 100% */
m->regs[0x9B] = lmargin >> 8; /* 100% */
/* who knows */
m->regs[0x9C] = 0x04;
m->regs[0x9D] = 0x00;
/* htotal - 2 */
m->regs[0xA0] = m->htotal;
m->regs[0xA1] = m->htotal >> 8;
/* vblanking end */
m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
/* something end... [A6]+1..[A8] */
m->regs[0xA4] = 0x01;
m->regs[0xA5] = 0x00;
/* something start... 0..[A4]-1 */
m->regs[0xA6] = 0x00;
m->regs[0xA7] = 0x00;
/* vertical line count - 1 */
m->regs[0xA8] = mt->VTotal - 1;
m->regs[0xA9] = (mt->VTotal - 1) >> 8;
/* horizontal vidrst pos */
m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
m->regs[0xAB] = hcrt >> 8;
/* vertical vidrst pos */
m->regs[0xAC] = mt->VTotal - 2;
m->regs[0xAD] = (mt->VTotal - 2) >> 8;
/* moves picture up/down and so on... */
m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
m->regs[0xAF] = 0x00;
{
int hdec;
int hlen;
unsigned int ibmin = 4 + lmargin + mt->HDisplay;
unsigned int ib;
int i;
/* Verify! */
/* Where 94208 came from? */
if (mt->HTotal)
hdec = 94208 / (mt->HTotal);
else
hdec = 0x81;
if (hdec > 0x81)
hdec = 0x81;
if (hdec < 0x41)
hdec = 0x41;
hdec--;
hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
if (hlen < 0)
hlen = 0;
hlen = hlen >> 8;
if (hlen > 0xFF)
hlen = 0xFF;
/* Now we have to compute input buffer length.
If you want any picture, it must be between
4 + lmargin + xres
and
94208 / hdec
If you want perfect picture even on the top
of screen, it must be also
0x3C0000 * i / hdec + Q - R / hdec
where
R Qmin Qmax
0x07000 0x5AE 0x5BF
0x08000 0x5CF 0x5FF
0x0C000 0x653 0x67F
0x10000 0x6F8 0x6FF
*/
i = 1;
do {
ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
i++;
} while (ib < ibmin);
if (ib >= m->htotal + 2) {
ib = ibmin;
}
m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
m->regs[0xC2] = hlen;
/* 'valid' input line length */
m->regs[0x9E] = ib;
m->regs[0x9F] = ib >> 8;
}
{
int vdec;
int vlen;
if (mt->VTotal) {
double f1;
uint32 a;
uint32 b;
// Unsure of how to do 64-bit integer maths on Be, so use FPU!
a = m->vlines * (m->htotal + 2);
b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
f1 = (double)a * (double)32768;
f1 /= (double) b;
vdec = (uint32) f1;
} else
vdec = 0x8000;
if (vdec > 0x8000)
vdec = 0x8000;
vlen = (vslen + umargin + mt->VDisplay) * vdec;
vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
if (vlen < 0)
vlen = 0;
if (vlen > 0xFF)
vlen = 0xFF;
vdec--;
m->regs[0x91] = vdec;
m->regs[0x92] = vdec >> 8;
m->regs[0xBE] = vlen;
}
m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
return 0;
}
DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
m->regs[0x80] = a;
m->regs[0x81] = bv;
m->regs[0x82] = c | 0x80;
m->regs[0xB3] = 0x01;
m->regs[0x94] = 0xB2;
/* htotal... */
m->regs[0x96] = mt->HTotal;
m->regs[0x97] = mt->HTotal >> 8;
/* ?? */
m->regs[0x98] = 0x00;
m->regs[0x99] = 0x00;
/* hsync len */
tmpi = mt->HSyncEnd - mt->HSyncStart;
m->regs[0x9A] = tmpi;
m->regs[0x9B] = tmpi >> 8;
/* hblank end */
tmpi = mt->HTotal - mt->HSyncStart;
m->regs[0x9C] = tmpi;
m->regs[0x9D] = tmpi >> 8;
/* hblank start */
tmpi += mt->HDisplay;
m->regs[0x9E] = tmpi;
m->regs[0x9F] = tmpi >> 8;
/* htotal + 1 */
tmpi = mt->HTotal + 1;
m->regs[0xA0] = tmpi;
m->regs[0xA1] = tmpi >> 8;
/* vsync?! */
tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
m->regs[0xA2] = tmpi;
m->regs[0xA3] = tmpi >> 8;
/* ignored? */
tmpi = mt->VTotal - mt->VSyncStart;
m->regs[0xA4] = tmpi;
m->regs[0xA5] = tmpi >> 8;
/* ignored? */
tmpi = mt->VTotal - 1;
m->regs[0xA6] = tmpi;
m->regs[0xA7] = tmpi >> 8;
/* vtotal - 1 */
m->regs[0xA8] = tmpi;
m->regs[0xA9] = tmpi >> 8;
/* hor vidrst */
tmpi = mt->HTotal - mt->delay;
m->regs[0xAA] = tmpi;
m->regs[0xAB] = tmpi >> 8;
/* vert vidrst */
tmpi = mt->VTotal - 2;
m->regs[0xAC] = tmpi;
m->regs[0xAD] = tmpi >> 8;
/* ignored? */
m->regs[0xAE] = 0x00;
m->regs[0xAF] = 0x00;
m->regs[0xB0] = 0x03; /* output: monitor */
m->regs[0xB1] = 0xA0; /* ??? */
m->regs[0x8C] = 0x20; /* must be set... */
m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */
m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
m->regs[0xBF] = 0x22; /* makes picture stable */
return 0;
}
inline int maven_program_timing
(
const struct mavenregs* m
)
{
if (m->mode & MODE_MONITOR) {
LR(0x80);
LR(0x81);
LR(0x82);
LR(0xB3);
LR(0x94);
LRP(0x96);
LRP(0x98);
LRP(0x9A);
LRP(0x9C);
LRP(0x9E);
LRP(0xA0);
LRP(0xA2);
LRP(0xA4);
LRP(0xA6);
LRP(0xA8);
LRP(0xAA);
LRP(0xAC);
LRP(0xAE);
LR(0xB0); /* output: monitor */
LR(0xB1); /* ??? */
LR(0x8C); /* must be set... */
LR(0x8D); /* defaults to 0x10: test signal */
LR(0xB9); /* defaults to 0x2C: too bright */
LR(0xBF); /* makes picture stable */
} else {
maven_init_TV(m);
}
return 0;
}
inline int maven_resync()
{
i2c_maven_write( 0x95, 0x20); /* start whole thing */
return 0;
}
/******************************************************/
///////////////////////////////////////////////////////////////////////////////////////
//Main entry points... - sequence is compute, program, start
int maven_set_mode(int mod)
{
switch (mode)
{
case MODE_NTSC:
case MODE_PAL:
case MODE_MONITOR:
mode = mod;
break;
default:
return -1;
}
return 0;
}
int maven_out_compute(struct my_timming* mt, struct mavenregs* maven)
{
return maven_compute_timing(mt, maven);
}
int maven_out_program(const struct mavenregs* maven)
{
return maven_program_timing(maven);
}
int maven_out_start()
{
return maven_resync();
}
/* ************************** */
//Used with Petr's permission (many thanks)
//Any bugs with this code contact me ([email protected]) not Petr
//-----------------------------------------------
//MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <[email protected]>");
//MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
@@ -0,0 +1,88 @@
struct matrox_pll_features {
unsigned int vco_freq_min;
unsigned int ref_freq;
unsigned int feed_div_min;
unsigned int feed_div_max;
unsigned int in_div_min;
unsigned int in_div_max;
unsigned int post_shift_max;
};
struct matrox_pll_features2 {
unsigned int vco_freq_min;
unsigned int vco_freq_max;
unsigned int feed_div_min;
unsigned int feed_div_max;
unsigned int in_div_min;
unsigned int in_div_max;
unsigned int post_shift_max;
};
struct matrox_pll_ctl {
unsigned int ref_freq;
unsigned int den;
};
struct mavenregs {
uint8 regs[256];
int mode;
int vlines;
int xtal;
int fv;
uint16 htotal;
uint16 hcorr;
};
struct my_timming {
unsigned int pixclock;
unsigned int HDisplay;
unsigned int HSyncStart;
unsigned int HSyncEnd;
unsigned int HTotal;
unsigned int VDisplay;
unsigned int VSyncStart;
unsigned int VSyncEnd;
unsigned int VTotal;
unsigned int sync;
int dblscan;
int interlaced;
unsigned int delay; /* CRTC delay */
};
int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
const struct matrox_pll_ctl* ctl,
unsigned int htotal, unsigned int vtotal,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* h2);
unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
unsigned int htotal, unsigned int vtotal,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* htotal2);
void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
unsigned int* in, unsigned int* feed, unsigned int* post);
void maven_init_TVdata ( struct mavenregs* data);
void maven_init_TV ( const struct mavenregs* m);
int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
struct mavenregs* m);
int maven_compute_timing ( struct my_timming* mt, struct mavenregs* m) ;
int maven_program_timing ( const struct mavenregs* m);
int maven_resync();
//MY INTERFACE
int maven_set_mode(int mode);
int maven_out_compute(struct my_timming* mt, struct mavenregs* mr) ;
int maven_out_program(const struct mavenregs* mr) ;
int maven_out_start() ;
@@ -0,0 +1,341 @@
/* MGA Acceleration functions */
/* Authors:
Mark Watson 2/2000,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x00080000
#include "mga_std.h"
/*acceleration notes*/
/*functions Be needs:
fill span (horizontal only)
fill rectangle (these 2 are very similar)
invert rectangle
blit
*/
/* G100 pre SRCORG/DSTORG registers */
static uint32 src_dst;
// needed by MIL2 in 800x600 8bpp
#define ACCW_YDSTLEN(dst, len) do { \
/* if (si->ylin) { */ \
if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { \
ACCW(YDST,((dst)*si->dm.virtual_width) >> 5); \
ACCW(LEN,len); \
} else ACCW(YDSTLEN,((dst)<<16)|(len)); \
} while (0)
status_t gx00_acc_wait_idle()
{
volatile int i;
while (ACCR(STATUS)&(1<<16))
{
for (i=0;i<10000;i++); /*spin in place so I do not hammer the bus*/
};
return B_OK;
}
/*AFAIK this must be done for every new screenmode*/
status_t gx00_acc_init()
{
ACCW(OPMODE,0); // cleanup bitblt
/*Set the Z origin to the start of FB (otherwise lockup on blits)*/
if (si->ps.card_type>=G100)
ACCW(ZORG,0);
/*MACCESS - for 2D, only pixel width is important > all others can be 0*/
switch(si->dm.space)
{
case B_CMAP8:
ACCW(MACCESS,0);
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
ACCW(MACCESS,1);
break;
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
ACCW(MACCESS,2);
break;
default:
LOG(8,("ACC: init, invalid bit depth\n"));
return B_ERROR;
}
/*PITCH*/
// TODO apsed 3-129 32 or 64 following depth (or 128 if MIl2)
if (si->dm.virtual_width&0x1F)
{
LOG(8,("ACC: can not accelerate, pitch is not multiple of 32 pixels\n"));
return B_ERROR;
}
if (si->ps.card_type>=G200)
ACCW(PITCH,(si->dm.virtual_width)&0x1FFF); /* use hardware Y decoding */
else
ACCW(PITCH,(si->dm.virtual_width)&0x0FFF); /* use hardware Y decoding */
if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
// ylin shall be 1 if 800x600
ACCW(PITCH, (1<<15) | (si->dm.virtual_width&0x0FFF));
}
/*PLNWT - plane write mask*/
// if (si->ps.card_type>=G200) // apsed: PLNWT exists also in MIL2, G100
ACCW(PLNWT,0xFFFFFFFF); /*all planes are written*/
if (si->ps.card_type>=G200) {
/*DSTORG - location of active screen in framebuffer*/
ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer));
/*SRCORG - init source address - same as dest*/
ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer));
}
/*YDSTORG - apsed, if not inited, BitBlts may fails on g200, see YTOP/BOT after */
/* Used for G100, included in acceleration routines also: */
src_dst = 0;
ACCW(YDSTORG, src_dst);
/* G100 uses this register as SRCORG/DSTORG replacement */
if ((si->ps.card_type == G100) && (si->settings.hardcursor))
{
switch (si->dm.space)
{
case B_CMAP8:
src_dst = 1024 / 1;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
src_dst = 1024 / 2;
break;
case B_RGB32_LITTLE:
src_dst = 1024 / 4;
break;
default:
LOG(8,("ACC: G100 hardcursor not supported for current colorspace\n"));
return B_ERROR;
}
}
ACCW(YDSTORG,src_dst);
/*clipping*/
ACCW(CXBNDRY,((si->dm.virtual_width -1)<<16)|(0)); /*i.e. highest and lowest right pixel value*/
// apsed TODO g200 shall be YDSTORG + value
// apsed TODO why -1, must be a multiple of 32 since MIl2
ACCW(YTOP,0);
ACCW(YBOT,(si->dm.virtual_height*si->dm.virtual_width)-1); /*y address must be linear*/
return B_OK;
}
/*screen to screen blit - i.e. move windows around*/
status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
{
uint32 t_start,t_end,offset;
uint32 b_start,b_end;
/*find where the top,bottom and offset are*/
offset = si->dm.virtual_width;
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
case 0: /*L->R,down*/
ACCW(SGN,0);
ACCW(AR3,t_start);
ACCW(AR0,t_end);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 1: /*L->R,up*/
ACCW(SGN,4);
ACCW(AR3,b_start);
ACCW(AR0,b_end);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
case 2: /*R->L,down*/
ACCW(SGN,1);
ACCW(AR3,t_end);
ACCW(AR0,t_start);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 3: /*R->L,up*/
ACCW(SGN,5);
ACCW(AR3,b_end);
ACCW(AR0,b_start);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
}
ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/
ACCGO(DWGCTL,0x040C4018);
return B_OK;
}
/*screen to screen tranparent blit - not sure what uses this...*/
status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
{
uint32 t_start,t_end,offset;
uint32 b_start,b_end;
return B_ERROR;
/*find where the top,bottom and offset are*/
offset = si->dm.virtual_width;
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
case 0: /*L->R,down*/
ACCW(SGN,0);
ACCW(AR3,t_start);
ACCW(AR0,t_end);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 1: /*L->R,up*/
ACCW(SGN,4);
ACCW(AR3,b_start);
ACCW(AR0,b_end);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
case 2: /*R->L,down*/
ACCW(SGN,1);
ACCW(AR3,t_end);
ACCW(AR0,t_start);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 3: /*R->L,up*/
ACCW(SGN,5);
ACCW(AR3,b_end);
ACCW(AR0,b_start);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
}
ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/
ACCW(FCOL,colour);
ACCW(BCOL,0xffffffff);
ACCGO(DWGCTL,0x440C4018);
return B_OK;
}
/*rectangle fill*/
/*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
/*
FXBNDRY - left and right coordinates a
YDSTLEN - y start and no of lines a
(or YDST and LEN)
DWGCTL - atype must be RSTR or BLK a
FCOL - foreground colour a
*/
ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
if (si->dm.space==B_CMAP8 || si->ps.sdram)
{
ACCGO(DWGCTL,0x400C7814); // atype RSTR
}
else
{
ACCGO(DWGCTL,0x400C7844); // atype BLK
}
return B_OK;
}
/*rectangle invert*/
/*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
// int i;
// uint32 * dma;
// uint32 pci;
/*
FXBNDRY - left and right coordinates a
YDSTLEN - y start and no of lines a
(or YDST and LEN)
DWGCTL - atype must be RSTR or BLK a
FCOL - foreground colour a
*/
ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
ACCGO(DWGCTL,0x40057814); /*draw it! top nibble is c is clipping enabled*/
/*pseudo_dma version!*/
//MGAACC_DWGCTL =0x1C00,
//MGAACC_FCOL =0x1C24,
//MGAACC_FXBNDRY =0x1C84,
//MGAACC_YDSTLEN =0x1C88,
//
//40,09,21,22 (ordered as registers)
// dma = (uint32 *)si->pseudo_dma;
// *dma++=0x40092221;
// *dma++=(xe<<16)|xs;
// *dma++=(ys<<16)|yl;
// *dma++=col;
// *dma++=0x40057814;
/*real dma version!*/
// dma = (vuint32 *)si->dma_buffer;
// *dma++=0x40092221;/*indices*/
// *dma++=(xe<<16)|xs;
// *dma++=(ys<<16)|yl;
// *dma++=col;
// *dma++=0x40057814;
// pci = si->dma_buffer_pci;
// ACCW(PRIMADDRESS,(pci));
// ACCW(PRIMEND,(20+pci));
// delay(100);
return B_OK;
}
@@ -0,0 +1,628 @@
/* G200-G550 Back End Scaler functions V0.13 beta1 */
/* Written by Rudolf Cornelissen 05/08-2002 */
#define MODULE_BIT 0x00000200
#include "mga_std.h"
status_t gx00_configure_bes(const overlay_buffer *ob, const overlay_window *ow, int offset)
{
/* yuy2 (4:2:2) colorspace calculations */
/* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */
/* Note:
* in BeOS R5.0.3 (maybe DANO works different):
* 'ow->offset_xxx' is always 0, so not used;
* 'ow->width' and 'ow->height' are the output window size: does not change
* if window is clipping;
* 'ow->h_start' and 'ow->v_start' are the left-top position of the output
* window. These values can be negative: this means the window is clipping
* at the left or the top of the display, respectively. */
/* misc used variables */
uint32 temp32;
uint16 temp1, temp2;
/* interval representation, used for scaling calculations */
uint16 intrep;
/* inverse scaling factor, used for source positioning */
uint32 ifactor;
/* used for vertical weight starting value */
uint32 weight;
/* Slowdown the G200-G550 BES if the pixelclock is too high for it to cope.
* This will in fact half the horizontal resolution of the BES with high
* pixelclocks (by setting a BES hardware 'zoom' = 2x).
* If you want optimal output quality better make sure you set the refreshrate/resolution
* of your monitor not too high ... */
uint16 acczoom = 1;
LOG(4,("Overlay: pixelclock is %dkHz, ", si->dm.timing.pixel_clock));
if (si->dm.timing.pixel_clock > BESMAXSPEED)
{
/* BES running at half speed and resolution */
/* This is how it works (BES slowing down):
* - Activate BES internal horizontal hardware scaling = 4x (in GLOBCTL below),
* - This also sets up BES only getting half the amount of pixels per line from
* the input picture buffer (in effect half-ing the BES pixelclock input speed).
* Now in order to get the picture back to original size, we need to also double
* the inverse horizontal scaling factor here (x4 /2 /2 = 1x again).
* Note that every other pixel is now doubled or interpolated, according to another
* GLOBCTL bit. */
acczoom = 2;
LOG(4,("slowing down BES!\n"));
}
else
{
/* BES running at full speed and resolution */
LOG(4,("BES is running at full speed\n"));
}
/*************************************
*** sync to BES (Back End Scaler) ***
*************************************/
/* Make sure reprogramming the BES completes before the next retrace occurs, to prevent
* register-update glitches (double buffer feature).
* Programming the BES needs about 50 lines with a 1600 x 1200 x 90Hz screen with
* logging mostly disabled on a P3-500. */
LOG(3,("Overlay: entering at Vcount %d\n", CR1R(VCOUNT)));
while (CR1R(VCOUNT) > (si->dm.timing.v_total - 100));
LOG(3,("Overlay: starting at Vcount %d\n", CR1R(VCOUNT)));
/****************************************
*** setup all edges of output window ***
****************************************/
/* setup left and right edges of output window */
temp32 = 0;
/* left edge coordinate of output window, must be inside desktop */
/* clipping on the left side */
if (ow->h_start < 0)
{
temp1 = 0;
}
else
{
/* clipping on the right side */
if (ow->h_start >= (si->dm.virtual_width - 1))
{
/* width < 2 is not allowed */
temp1 = (si->dm.virtual_width - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (uint16)ow->h_start & 0x7ff;
}
}
temp32 |= temp1 << 16;
/* right edge coordinate of output window, must be inside desktop */
/* width < 2 is not allowed */
if (ow->width < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the right side */
if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1))
{
temp2 = (si->dm.virtual_width - 1) & 0x7ff;
}
else
{
/* clipping on the left side */
if ((ow->h_start + ow->width - 1) < 1)
{
/* width < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(ow->h_start + ow->width - 1)) & 0x7ff;
}
}
}
temp32 |= temp2 << 0;
BESW(HCOORD, temp32);
LOG(4,("Overlay: left-edge output %d, right-edge output %d\n",temp1, temp2));
/* setup top and bottom edges of output window */
temp32 = 0;
/* top edge coordinate of output window, must be inside desktop */
/* clipping on the top side */
if (ow->v_start < 0)
{
temp1 = 0;
}
else
{
/* clipping on the bottom side */
if (ow->v_start >= (si->dm.virtual_height - 1))
{
/* height < 2 is not allowed */
temp1 = (si->dm.virtual_height - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (uint16)ow->v_start & 0x7ff;
}
}
temp32 |= temp1 << 16;
/* bottom edge coordinate of output window, must be inside desktop */
/* height < 2 is not allowed */
if (ow->height < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the bottom side */
if ((ow->v_start + ow->height - 1) > (si->dm.virtual_height - 1))
{
temp2 = (si->dm.virtual_height - 1) & 0x7ff;
}
else
{
/* clipping on the top side */
if ((ow->v_start + ow->height - 1) < 1)
{
/* height < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(ow->v_start + ow->height - 1)) & 0x7ff;
}
}
}
temp32 |= temp2 << 0;
BESW(VCOORD, temp32);
LOG(4,("Overlay: top-edge output %d, bottom-edge output %d\n",temp1, temp2));
/*********************************************
*** setup horizontal scaling and clipping ***
*********************************************/
LOG(4,("Overlay: input picture width = %d, height = %d\n",
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
LOG(4,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
/* do horizontal scaling... */
/* determine interval representation value */
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
{
/* horizontal filtering is ON */
if (((ob->width - si->overlay.myBufInfo[offset].slopspace) == ow->width) | (ow->width < 2))
{
/* no horizontal scaling used, OR destination width < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* horizontal filtering is OFF */
if ((ow->width < (ob->width - si->overlay.myBufInfo[offset].slopspace)) & (ow->width >= 2))
{
/* horizontal downscaling used AND destination width >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep));
/* calculate inverse horizontal scaling factor */
/* (using standard scaling formula: neglecting round-off var as extra error is very small..) */
ifactor = ((ob->width - si->overlay.myBufInfo[offset].slopspace - intrep) << 16) /
(ow->width - intrep);
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
/* compensate for accelerated 2x zoom (slowdown BES if pixelclock is too high) */
temp32 = ifactor * acczoom;
LOG(4,("Overlay: horizontal speed compensated factor is %f\n", (float)65536 / temp32));
/* check scaling factor (and modify if needed) to be within scaling limits */
if ((((ob->width - si->overlay.myBufInfo[offset].slopspace) << 16) / 16384) > temp32)
{
/* (non-inverse) factor too large, set factor to max. valid value */
temp32 = (((ob->width - si->overlay.myBufInfo[offset].slopspace) << 16) / 16384);
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / temp32));
}
if (temp32 >= (32 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
temp32 = 0x1ffffc;
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / temp32));
}
/* AND below is required by hardware */
temp32 &= 0x001ffffc;
BESW(HISCAL, temp32);
/* do horizontal clipping... */
/* Setup horizontal source start: first (sub)pixel contributing to output picture */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* After this is done, include the scaling factor so you get a value based on the input bitmap.
* The input bitmaps slopspace is automatically excluded from the calculations this way! */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
temp32 = 0;
/* check for destination horizontal clipping at left side */
if (ow->h_start < 0)
{
/* check if entire destination picture is clipping left:
* (2 pixels will be clamped onscreen at least) */
if ((ow->h_start + ow->width - 1) < 1)
{
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
temp32 += (ow->width - 2);
}
else
{
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
temp32 += (0 - ow->h_start);
}
LOG(4,("Overlay: clipping left...\n"));
/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
* Note that this also already takes care of aligning the value to the BES register! */
temp32 *= ifactor;
}
/* AND below required by hardware */
temp32 &= 0x03fffffc;
BESW(HSRCST, temp32);
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", temp32 / (float)65536));
/* Setup horizontal source end: last (sub)pixel contributing to output picture */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* After this is done, include the scaling factor so you get a value based on the input bitmap. */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
temp32 = 0;
/* check for destination horizontal clipping at right side */
if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1))
{
/* check if entire destination picture is clipping right:
* (2 pixels will be clamped onscreen at least) */
if (ow->h_start > (si->dm.virtual_width - 2))
{
/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
temp32 += (ow->width - 2);
}
else
{
/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
temp32 += ((ow->h_start + ow->width - 1) - (si->dm.virtual_width - 1));
}
LOG(4,("Overlay: clipping right...\n"));
/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
* Note that this also already takes care of aligning the value to the BES register! */
temp32 *= ifactor;
/* now subtract this value from the last used pixel in inputbuffer, aligned to BES */
temp32 = (((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16) - temp32;
}
else
{
/* set last contributing pixel to last used pixel in inputbuffer, aligned to BES */
temp32 = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16;
}
/* AND below required by hardware */
temp32 &= 0x03fffffc;
BESW(HSRCEND, temp32);
LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", temp32 / (float)65536));
/* setup horizontal source last position excluding slopspace */
temp32 = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16;
/* AND below required by hardware */
temp32 &= 0x03ff0000;
BESW(HSRCLST, temp32);
/*******************************************
*** setup vertical scaling and clipping ***
*******************************************/
/* do vertical scaling... */
/* determine interval representation value */
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
{
/* vertical filtering is ON */
if ((ob->height == ow->height) | (ow->height < 2))
{
/* no vertical scaling used, OR destination height < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* vertical filtering is OFF */
if ((ow->height < ob->height) & (ow->height >= 2))
{
/* vertical downscaling used AND destination height >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: vertical interval representation value is %d\n",intrep));
/* calculate inverse vertical scaling factor */
/* (using standard scaling formula: neglecting round-off var as extra error is very small..) */
ifactor = ((ob->height - intrep) << 16) / (ow->height - intrep);
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor));
/* preserve ifactor for source positioning calculations later on */
temp32 = ifactor;
/* check scaling factor (and modify if needed) to be within scaling limits */
if (((ob->height << 16) / 16384) > temp32)
{
/* (non-inverse) factor too large, set factor to max. valid value */
temp32 = ((ob->height << 16) / 16384);
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / temp32));
}
if (temp32 >= (32 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
temp32 = 0x1ffffc;
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / temp32));
}
/* AND below is required by hardware */
temp32 &= 0x001ffffc;
BESW(VISCAL, temp32);
/* do vertical clipping... */
/* Setup vertical source start: first (sub)pixel contributing to output picture.
* Note: this exists of two parts:
* 1. setup fractional part (sign is always 'positive');
* 2. setup relative base_adress, taking clipping on top into account.
* Both parts are done intertwined below. */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* 'After' this is done, include the scaling factor so you get a value based on the input bitmap. */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
/* calculate relative base_adress and 'vertical weight fractional part' */
weight = 0;
temp32 = (uint32)((vuint32 *)ob->buffer);
temp32 -= (uint32)((vuint32 *)si->framebuffer);
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",temp32));
/* calculate origin adress */
/* check for destination vertical clipping at top side */
if (ow->v_start < 0)
{
/* check if entire destination picture is clipping at top:
* (2 pixels will be clamped onscreen at least) */
if ((ow->v_start + ow->height - 1) < 1)
{
/* increase source buffer origin with 'fixed value':
* (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) *
* bytes per row source picture */
temp32 += ((((ow->height - 2) * ifactor) >> 16) * ob->bytes_per_row);
weight = (ow->height - 2) * ifactor;
}
else
{
/* increase source buffer origin with:
* (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
* bytes per row source picture */
temp32 += ((((0 - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
weight = (0 - ow->v_start) * ifactor;
}
LOG(4,("Overlay: clipping at top: buffer origin is (cardRAM offset) $%08x\n",temp32));
}
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", weight / (float)65536));
/* Note:
* Because later G200 and all > G200 overlay units will ignore b0-3 of the calculated adress,
* we do not use the above way for horizontal source positioning.
* (Early G200 cards ignore b0-2.)
* If we did, 8 source-image pixel jumps (in 4:2:2 colorspace) will occur if the picture
* is shifted horizontally during left clipping on later G200 and all > G200 cards, while
* early G200 cards will have 4 source-image pixel jumps occuring. */
/* AND below is required by G200-G550 hardware. All cards can have max. 32Mb RAM on board
* (incl. later G200 cards!). Compatible setting used (between early G200 and the rest),
* this has no downside consequences here. */
temp32 &= 0x01fffff0;
/* buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */
BESW(A1ORG, temp32);
/* field 1 weight: AND below required by hardware, also make sure 'sign' is always 'positive' */
temp32 = weight & 0x0000fffc;
BESW(V1WGHT, temp32);
/* setup field 1 (is our complete frame) vertical source contributing height - 1.
* Note:
* This value is bottom-unclipped! (as it should be according to the MGA specs...) */
temp32 = (ob->height - 1) - (weight >> 16);
/* AND below required by hardware */
temp32 &= 0x000003ff;
BESW(V1SRCLST, temp32);
LOG(4,("Overlay: input bitmap bottom-unclipped contributing height (integer part) %d\n", temp32 + 1));
/**************************
*** setup color keying ***
**************************/
LOG(4,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
LOG(4,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
/* setup colorkeying */
DXIW(COLKEY, (ow->alpha.value & ow->alpha.mask));
DXIW(COLKEY0RED, (ow->red.value & ow->red.mask));
DXIW(COLKEY0GREEN, (ow->green.value & ow->green.mask));
DXIW(COLKEY0BLUE, (ow->blue.value & ow->blue.mask));
DXIW(COLMSK, ow->alpha.mask);
DXIW(COLMSK0RED, ow->red.mask);
DXIW(COLMSK0GREEN, ow->green.mask);
DXIW(COLMSK0BLUE, ow->blue.mask);
/* enable colorkeying */
DXIW(KEYOPMODE,0x01);
/*************************
*** setup misc. stuff ***
*************************/
/* setup brightness and contrast to be 'neutral' (this is not implemented on G200) */
BESW(LUMACTL, 0x00000080);
/* setup source pitch including slopspace (in pixels) */
temp32 = ob->width;
/* AND below required by hardware */
temp32 &= 0x00000fff;
BESW(PITCH, temp32);
/*************************
*** setup BES control ***
*************************/
/* BES global control: setup functions */
temp32 = 0;
/* slowdown BES if nessesary */
if (acczoom == 1)
{
/* run at full speed and resolution */
temp32 |= 0 << 0;
/* disable filtering for half speed interpolation */
temp32 |= 0 << 1;
}
else
{
/* run at half speed and resolution */
temp32 |= 1 << 0;
/* enable filtering for half speed interpolation */
temp32 |= 1 << 1;
}
/* 4:2:0 specific setup: not needed here */
temp32 |= 0 << 3;
/* BES testregister: keep zero */
temp32 |= 0 << 4;
/* the following bits marked (> G200) *must* be zero on G200: */
/* 4:2:0 specific setup: not needed here (> G200) */
temp32 |= 0 << 5;
/* select yuy2 byte-order to B_YCbCr422 (> G200) */
temp32 |= 0 << 6;
/* BES internal contrast and brighness controls are not used, disabled (> G200) */
temp32 |= 0 << 7;
/* RGB specific setup: not needed here, so disabled (> G200) */
temp32 |= 0 << 8;
temp32 |= 0 << 9;
/* 4:2:0 specific setup: not needed here (> G200) */
temp32 |= 0 << 10;
/* Tell BES when to copy the new register values to the actual active registers.
* bits 16-27 (12 bits) are the CRTC vert. count value at which copying takes
* place.
* (This is the double buffering feature: programming must be completed *before*
* the CRTC vert count value set here!) */
/* CRTC vert count for copying = $000, so during retrace, line 0. */
temp32 |= 0x000 << 16;
BESW(GLOBCTL, temp32);
/* BES control: enable scaler and setup functions */
/* pre-reset all bits */
temp32 = 0;
/* enable BES */
temp32 |= 1 << 0;
/* we start displaying at an even startline (zero) in 'field 1' (no hardware de-interlacing is used) */
temp32 |= 0 << 6;
/* we don't use field 2, so its startline is not important */
temp32 |= 0 << 7;
LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags));
/* enable horizontal filtering on scaling if asked for */
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
{
temp32 |= 1 << 10;
LOG(4,("Overlay: using horizontal filtering\n"));
}
else
{
temp32 |= 0 << 10;
}
/* enable vertical filtering on scaling if asked for */
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
{
temp32 |= 1 << 11;
LOG(4,("Overlay: using vertical filtering\n"));
}
else
{
temp32 |= 0 << 11;
}
/* use actual calculated weight for horizontal interpolation if scaling */
temp32 |= 0 << 12;
/* use horizontal chroma interpolation upsampling on BES input picture */
temp32 |= 1 << 16;
/* select 4:2:2 BES input format */
temp32 |= 0 << 17;
/* dithering is not used */
temp32 |= 0 << 18;
/* horizontal mirroring is not used */
temp32 |= 0 << 19;
/* BES output should be in color */
temp32 |= 0 << 20;
/* BES output blanking is disabled: we want a picture, no 'black box'! */
temp32 |= 0 << 21;
/* we do software field select (field select is not used) */
temp32 |= 0 << 24;
/* we always display field 1 in buffer A, this contains our full frames */
/* select field 1 */
temp32 |= 0 << 25;
/* select buffer A */
temp32 |= 0 << 26;
BESW(CTL, temp32);
LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT)));
return B_OK;
}
status_t gx00_release_bes()
{
/* setup BES control: disable scaler */
BESW(CTL, 0x00000000);
return B_OK;
}
@@ -0,0 +1,404 @@
/* CTRC functionality */
/* Authors:
Mark Watson 2/2000,
Apsed,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x00040000
#include "mga_std.h"
/*Adjust passed parameters to a valid mode line*/
status_t gx00_crtc_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
)
{
/*horizontal*/
/*make all parameters multiples of 8 and confine to required number of bits*/
*hd_e&=0x7F8;
*hs_s&=0xFF8;
*hs_e&=0xFF8;
*ht &=0xFF8;
/*confine to a reasonable width*/
if (*hd_e<640) *hd_e=640;
if (*hd_e>2048) *hd_e=2048;
/*if horizontal total does not leave room for a sensible sync pulse, increase it!*/
if (*ht<(*hd_e+80)) *ht=*hd_e+80;
/*make sure sync pulse is not during display*/
if (*hs_e>(*ht-0x8)) *hs_e=*ht-0x8;
if (*hs_s<(*hd_e+0x8)) *hs_e=*hd_e+0x8;
/*correct sync pulse if it is too long*/
if (*hs_e>(*hs_s+0xF8)) *hs_e=*hs_s+0xF8;
/*fail if they are now outside required number of bits*/
if (
*hd_e!=(*hd_e&0x7F8) ||
*hs_s!=(*hs_s&0xFF8) ||
*hs_e!=(*hs_e&0xFF8) ||
*ht !=(*ht &0xFF8)
)
{
LOG(8,("CRTC:Horizontal timing fell out of bits\n"));
return B_ERROR;
}
/*vertical*/
/*squish to required number of bits*/
*vd_e&=0x7FF;
*vs_s&=0xFFF;
*vs_e&=0xFFF;
*vt &=0xFFF;
/*confine to a reasonable height*/
if (*vd_e<400) *vd_e=400;
if (*vd_e>2048) *vd_e=2048;
/*if vertical total does not leave room for a sync pulse, increase it!*/
if (*vt<(*vd_e+3)) *vt=*vd_e+3;
/*make sure sync pulse if not during display*/
if (*vs_e>(*vt-1)) *vs_e=*vt-1;
if (*vs_s<(*vd_e+1)) *vs_s=*vd_e+1;
/*correct sync pulse if it is too long*/
if (*vs_e>(*vs_s+0xF)) *vs_e=*vs_s+0xF;
/*fail if now outside required number of bits*/
if (
*vd_e!=(*vd_e&0x7FF) ||
*vs_s!=(*vs_s&0xFFF) ||
*vs_e!=(*vs_e&0xFFF) ||
*vt !=(*vt &0xFFF)
)
{
LOG(8,("CRTC:Vertical timing fell out of bits\n"));
return B_ERROR;
}
return B_OK;
}
/*set a mode line - inputs are in pixels*/
status_t gx00_crtc_set_timing(
uint16 hd_e,uint16 hs_s,uint16 hs_e,uint16 ht,
uint16 vd_e,uint16 vs_s,uint16 vs_e,uint16 vt,
uint8 hsync_pos,uint8 vsync_pos
)
{
uint32 htotal; /*total horizontal total VCLKs*/
uint32 hdisp_e; /*end of horizontal display (begins at 0)*/
uint32 hsync_s; /*begin of horizontal sync pulse*/
uint32 hsync_e; /*end of horizontal sync pulse*/
uint32 hblnk_s; /*begin horizontal blanking*/
uint32 hblnk_e; /*end horizontal blanking*/
uint32 vtotal; /*total vertical total scanlines*/
uint32 vdisp_e; /*end of vertical display*/
uint32 vsync_s; /*begin of vertical sync pulse*/
uint32 vsync_e; /*end of vertical sync pulse*/
uint32 vblnk_s; /*begin vertical blanking*/
uint32 vblnk_e; /*end vertical blanking*/
uint32 linecomp; /*split screen and vdisp_e interrupt*/
LOG(4,("CRTC: setting timing\n"));
/*Modify parameters as required by the G400/G200*/
htotal=(ht>>3)-5;
hdisp_e=(hd_e>>3)-1;
hsync_s=(hs_s>>3);
hsync_e=(hs_e>>3);
hblnk_s=hdisp_e;
hblnk_e=htotal+4;
vtotal=vt-2;
vdisp_e=vd_e-1;
vsync_s=vs_s-1;
vsync_e=vs_e-1;
vblnk_s=vdisp_e;
vblnk_e=vtotal+1;
linecomp=256; /*should display half the screen!*/
/*log the mode I am setting*/
LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
/*actually program the card! Note linecomp is programmed to vblnk_s for VBI*/
/*horizontal - VGA regs*/
VGAW_I(CRTC,0,htotal&0xFF);
VGAW_I(CRTC,1,hdisp_e&0xFF);
VGAW_I(CRTC,2,hblnk_s&0xFF);
VGAW_I(CRTC,3,(hblnk_e&0x1F)|0x80);
VGAW_I(CRTC,4,hsync_s&0xFF);
VGAW_I(CRTC,5,(hsync_e&0x1F)|((hblnk_e&0x20)<<2));
/*vertical - VGA regs*/
VGAW_I(CRTC,6,vtotal&0xFF);
VGAW_I(CRTC,7,
(
((vtotal&0x100)>>(8-0)) |((vtotal&0x200)>>(9-5))|
((vdisp_e&0x100)>>(8-1))|((vdisp_e&0x200)>>(9-6))|
((vsync_s&0x100)>>(8-2))|((vsync_s&0x200)>>(9-7))|
((vblnk_s&0x100)>>(8-3))|((linecomp&0x100)>>(8-4))
));
VGAW_I(CRTC,0x9,((vblnk_s&0x200)>>(9-5))|((linecomp&0x200)>>(9-6)));
VGAW_I(CRTC,0x10,vsync_s&0xFF);
VGAW_I(CRTC,0x11,((VGAR_I(CRTC,0x11))&0xF0)|(vsync_e&0xF));
VGAW_I(CRTC,0x12,vdisp_e&0xFF);
VGAW_I(CRTC,0x15,vblnk_s&0xFF);
VGAW_I(CRTC,0x16,vblnk_e&0xFF);
VGAW_I(CRTC,0x18,linecomp&0xFF);
/*horizontal - extended regs*/
VGAW_I(CRTCEXT,1,
(
((htotal&0x100)>>8)|
((hblnk_s&0x100)>>7)|
((hsync_s&0x100)>>6)|
(hblnk_e&0x40)|
(VGAR_I(CRTCEXT,1)&0xb8)
));
/*vertical - extended regs*/
VGAW_I(CRTCEXT,2,
(
((vtotal&0xC00)>>10)|
((vdisp_e&0x400)>>8)|
((vblnk_s&0xC00)>>7)|
((vsync_s&0xC00)>>5)|
((linecomp&0x400)>>3)
));
/*set up HSYNC & VSYNC polarity*/
VGAW(MISCW,(VGAR(MISCR)&0x3F)|((!vsync_pos)<<7)|((!hsync_pos)<<6));
LOG(2,("HSYNC/VSYNC pol:%x %x MISC dump:%x\n",hsync_pos,vsync_pos,VGAR(MISCR)));
return B_OK;
}
status_t gx00_crtc_depth(int mode)
{
uint8 viddelay = 0; // in CRTCEXT3, reserved if >= G100
if (si->ps.card_type < G100) do { // apsed TODO in caller
if (si->ps.memory_size <= 2) { viddelay = 1<<3; break;}
if (si->ps.memory_size <= 4) { viddelay = 0<<3; break;}
viddelay = 2<<3; // for 8 to 16Mb of memory
} while (0);
/*set VCLK scaling*/
switch(mode)
{
case BPP8:
VGAW_I(CRTCEXT,3,viddelay|0x80);
break;
case BPP15:case BPP16:
VGAW_I(CRTCEXT,3,viddelay|0x81);
break;
case BPP24:
VGAW_I(CRTCEXT,3,viddelay|0x82);
break;
case BPP32:case BPP32DIR:
VGAW_I(CRTCEXT,3,viddelay|0x83);
break;
}
return B_OK;
}
status_t gx00_crtc_dpms(uint8 display,uint8 h,uint8 v) // MIL2
{
LOG(4,("gx00_crtc_dpms (%d,%d,%d)\n", display,h,v));
VGAW_I(SEQ,1,(!display)<<5);
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0xCF)|((!v)<<5))|((!h)<<4);
VGAW_I(CRTC,0x17,0xC3);/*do not force disable all syncs and other stuff*/
VGAW_I(CRTC,0x14,0x00);
return B_OK;
}
status_t gx00_crtc_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) // MIL2
{
*display=!((VGAR_I(SEQ,1)&0x20)>>5);
*h=!((VGAR_I(CRTCEXT,1)&0x10)>>4);
*v=!((VGAR_I(CRTCEXT,1)&0x20)>>5);
LOG(4,("gx00_crtc_dpms_fetch (%d,%d,%d)\n", *display,*h,*v));
return B_OK;
}
status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp)
{
uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
/*figure out offset value hardware needs*/
offset = (pitch*bpp)/128;
LOG(2,("CRTC: offset: 0x%04x\n",offset));
/*program the card!*/
VGAW_I(CRTC,0x13,(offset&0xFF));
VGAW_I(CRTCEXT,0,(VGAR_I(CRTCEXT,0)&0xCF)|((offset&0x300)>>4));
return B_OK;
}
status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp)
{
uint32 ext0;
LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
/*figure out startadd value hardware needs*/
/*switch(bpp)
{
case 8:case 24:
startadd>>=1;
case 16:
startadd>>=1;
case 32:
startadd>>=1;
break;
}*/
startadd>>=3; // apsed, TODO doc Matrox g200 g400 4.6.5 is false?
LOG(2,("CRTC: startadd: %x\n",startadd));
LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer));
/*set standard registers*/
VGAW_I(CRTC,0xD,startadd&0xFF);
VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8);
//calculate extra bits that are standard over Gx00 series
ext0 = VGAR_I(CRTCEXT,0)&0xB0;
ext0|= (startadd&0xF0000)>>16;
//if card is a G200 or G400 then do first extension bit
if (si->ps.card_type>=G200)
ext0|=(startadd&0x100000)>>14;
//if card is a G400 then do write to its extension register
if (si->ps.card_type>=G400)
VGAW_I(CRTCEXT,8,((startadd&0x200000)>>21));
//write the extension bits
VGAW_I(CRTCEXT,0,ext0);
return B_OK;
}
status_t gx00_crtc_mem_priority(uint8 HIPRILVL)
{
if (si->ps.card_type<G100) return B_ERROR; // apsed TODO, not used, see after SetDisplayMode.c/interrupt_enable()
LOG(4,("CRTC: Setting memory priority level: %x\n",HIPRILVL));
switch (HIPRILVL)
{
case 0:
VGAW_I(CRTCEXT,6,0x00);
break;
case 1:case 2:case 3:
VGAW_I(CRTCEXT,6,0x10|HIPRILVL);
break;
case 4:case 5:case 6:case 7:
VGAW_I(CRTCEXT,6,0x20|HIPRILVL);
break;
default:
LOG(8,("CRTC: Memory priority level violation: %x\n",HIPRILVL));
return B_ERROR;
}
return B_OK;
}
status_t gx00_crtc_cursor_init()
{
int i;
uint32 * fb;
const uint32 curadd = 0; // apsed, TODO with ramaddr -> taken care off.
/*store cursor at the start of the framebuffer*/
DXIW(CURADDL,curadd >> 10); /*data at curadd in framebuffer*/
DXIW(CURADDH,curadd >> 18);
DXIW(CURCTRL,1);
/*set cursor colour*/
DXIW(CURCOL0RED,0XFF);
DXIW(CURCOL0GREEN,0xFF);
DXIW(CURCOL0BLUE,0xFF);
DXIW(CURCOL1RED,0);
DXIW(CURCOL1GREEN,0);
DXIW(CURCOL1BLUE,0);
DXIW(CURCOL2RED,0);
DXIW(CURCOL2GREEN,0);
DXIW(CURCOL2BLUE,0);
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(1024/4);i++)
{
fb[i]=0;
}
return B_OK;
}
status_t gx00_crtc_cursor_show()
{
DXIW(CURCTRL,1);
return B_OK;
}
status_t gx00_crtc_cursor_hide()
{
DXIW(CURCTRL,0);
return B_OK;
}
/*set up cursor shape*/
status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{
uint8 * cursor;
int y;
/*get a pointer to the cursor*/
cursor = (uint8*) si->framebuffer;
/*draw the cursor*/
for(y=0;y<16;y++)
{
cursor[y*16+7]=~*andMask++;
cursor[y*16+15]=*xorMask++;
cursor[y*16+6]=~*andMask++;
cursor[y*16+14]=*xorMask++;
}
return B_OK;
}
/*position the cursor*/
status_t gx00_crtc_cursor_position(uint16 x ,uint16 y)
{
int i=64;
// LOG(4,("DAC: cursor-> %d %d\n",x,y));
x+=i;
y+=i;
DACW(CURSPOSXL,x&0xFF);
DACW(CURSPOSXH,x>>8);
DACW(CURSPOSYL,y&0xFF);
DACW(CURSPOSYH,y>>8);
return B_OK;
}
@@ -0,0 +1,96 @@
/* second CTRC functionality */
/* Mark Watson 6/2000 */
#define MODULE_BIT 0x00020000
#include "mga_std.h"
/*set a mode line - inputs are in pixels/scanlines*/
status_t g400_crtc2_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
)
{
LOG(4,("CRTC2: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/
if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7))
{
LOG(8,("CRTC2:Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/*program the second CRTC*/
CR2W(HPARAM,(((hdisp_e-8)<<16) | (htotal-8)));
CR2W(HSYNC,(((hsync_e-8)<<16) | (hsync_s-8)));
CR2W(VPARAM,(((vdisp_e-1)<<16) | (vtotal-1)));
CR2W(VSYNC,(((vsync_e-1)<<16) | (vsync_s-1)));
CR2W(PRELOAD,(((vsync_s)<<16) | (hsync_s)));
CR2W(MISC,((0xfff<<16) | ((!hsync_pos)<<8) | ((!vsync_pos)<<9)));
return B_OK;
}
status_t g400_crtc2_depth(int mode)
{
/*validate bit depth and set mode*/
switch(mode)
{
case BPP16:case BPP32DIR:
CR2W(CTL,(CR2R(CTL)&0xFF10077F)|(mode<<21));
break;
case BPP8:case BPP15:case BPP24:case BPP32:default:
LOG(8,("CRTC2:Invalid bit depth\n"));
return B_ERROR;
break;
}
return B_OK;
}
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v)
{
CR2W(CTL,(CR2R(CTL)&0xFFF0077E)|(display&h&v)); /*enable second CRTC if required*/
/*ignore h,v because they are not supported*/
return B_OK;
}
status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v)
{
*display=CR2R(CTL)&1;
*h=*v=1; /*h/vsync always enabled on second CRTC, does not support other*/
return B_OK;
}
status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp)
{
uint32 offset;
LOG(4,("CRTC2: setting card pitch 0x%08x bpp %d\n", pitch, bpp));
/*figure out offset value hardware needs*/
offset = pitch*(bpp>>3);
LOG(2,("CRTC2: offset: %x\n",offset));
/*program the card!*/
CR2W(OFFSET,offset);
return B_OK;
}
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp)
{
LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
LOG(2,("CRTC2: startadd: %x\n",startadd));
LOG(2,("CRTC2: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC2: framebuffer: %x\n",si->fbc.frame_buffer));
/*program the card!*/
CR2W(STARTADD0,startadd);
return B_OK;
}
@@ -0,0 +1,837 @@
/* program the DAC */
/* Authors:
Mark Watson 2/2000,
Apsed 2002,
Rudolf Cornelissen 9/2002
*/
#define MODULE_BIT 0x00010000
#include "mga_std.h"
static status_t g100_g400max_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
static status_t g450_g550_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t gx00_dac_mode(int mode,float brightness)
{
uint8 *r,*g,*b,t[64];
int i;
/*set colour arrays to point to space reserved in shared info*/
r=si->color_data;
g=r+256;
b=g+256;
LOG(4,("DAC:Setting screen mode %d brightness %f\n", mode, brightness));
/*init a basic palette for brightness specified*/
for (i=0;i<256;i++)
{
int ri = i*brightness; // apsed
if (ri > 255) ri = 255;
r[i]=ri;
}
/*modify the palette for the specified mode (&validate mode)*/
switch(mode)
{
case BPP8:
case BPP24:case BPP32:
for (i=0;i<256;i++)
{
b[i]=g[i]=r[i];
}
break;
case BPP16:
for (i=0;i<64;i++)
{
t[i]=r[i<<2];
}
for (i=0;i<64;i++)
{
g[i]=t[i];
}
for (i=0;i<32;i++)
{
b[i]=r[i]=t[i<<1];
}
break;
case BPP15:
for (i=0;i<32;i++)
{
t[i]=r[i<<3];
}
for (i=0;i<32;i++)
{
g[i]=r[i]=b[i]=t[i];
}
break;
case BPP32DIR:
break;
default:
LOG(8,("DAC:Invalid bit depth requested\n"));
return B_ERROR;
break;
}
if (gx00_dac_palette(r,g,b)!=B_OK) return B_ERROR;
/*set the mode - also sets VCLK dividor*/
DXIW(MULCTRL,mode);
DACW(PIXRDMSK,0xff); // apsed, palette addressing not masked
LOG(2,("DAC: mulctrl=%x, pixrdmsk=%x\n",DXIR(MULCTRL), DACR(PIXRDMSK)));
return B_OK;
}
/*program the DAC palette using the given r,g,b values*/
status_t gx00_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256])
{
int i;
LOG(4,("DAC: setting palette\n"));
/*clear palwtadd to start programming*/
DACW(PALWTADD,0);
/*loop through all 256 to program DAC*/
for (i=0;i<256;i++)
{
DACW(PALDATA,r[i]);
DACW(PALDATA,g[i]);
DACW(PALDATA,b[i]);
}
if (DACR(PALWTADD)!=0)
{
LOG(8,("DAC: PALWTADD is not 0 after programming\n"));
return B_ERROR;
}
if (0) {// apsed: reread LUT
uint8 R, G, B;
DACW(PALRDADD,0);
for (i=0;i<256;i++) {
R = DACR(PALDATA);
G = DACR(PALDATA);
B = DACR(PALDATA);
if ((r[i] != R) || (g[i] != G) || (b[i] != B))
LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
}
}
return B_OK;
}
/*program the pixpll - frequency in kHz*/
/*important notes:
* MISC(clksel) = select A,B,C PIXPLL (25,28,none)
* PIXPLLC is used - others should be kept as is
* VCLK is quadword clock (max is PIXPLL/2) - set according to DEPTH
* BESCLK,CRTC2 are not touched
*/
status_t gx00_dac_set_pix_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
uint time = 0;
float pix_setting, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk));
result = gx00_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*reprogram (disable,select,wait for stability,enable)*/
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
VGAW(MISCW,((VGAR(MISCR)&0xF3)|0x8)); /*select PIXPLLC*/
DXIW(PIXPLLCM,(m)); /*set m value*/
DXIW(PIXPLLCN,(n)); /*set n value*/
DXIW(PIXPLLCP,(p)); /*set p value*/
/* Wait for the PIXPLL frequency to lock until timeout occurs */
while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: PIX PLL frequency not locked!\n"));
else
LOG(2,("DAC: PIX PLL frequency locked\n"));
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
return B_OK;
}
status_t gx50_dac_check_pix_pll(uint8 m, uint8 n, uint8 p)
{
uint time = 0, count = 0;
/*reprogram (disable,select,wait for stability,enable)*/
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
VGAW(MISCW,((VGAR(MISCR)&0xF3)|0x8)); /*select PIXPLLC*/
DXIW(PIXPLLCM,(m)); /*set m value*/
DXIW(PIXPLLCN,(n)); /*set n value*/
DXIW(PIXPLLCP,(p)); /*set p value*/
/* give the PLL 1mS at least to get a lock */
time = 0;
while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 1000))
{
time++;
snooze(1);
}
/* no lock aquired, not useable */
if (time > 1000) return B_ERROR;
/* check if lock holds for at least 90% of the time */
for (time = 0, count = 0; time <= 1000; time++)
{
if(DXIR(PIXPLLSTAT)&0x40) count++;
snooze(1);
}
/* we have a winner */
if (count >= 900) return B_OK;
/* nogo, the PLL does not stabilize */
return B_ERROR;
}
status_t gx50_dac_check_pix_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
{
uint8 s=0, p_backup = *p;
/* preset no candidate, non working setting */
*q = 0;
/* preset lowest range filter */
*p &= 0x47;
/* iterate through all possible filtersettings */
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
for (s = 0; s < 8 ;s++)
{
if (gx50_dac_check_pix_pll(m, n, *p)== B_OK)
{
/* now check 3 closest lower and higher settings */
if ((gx50_dac_check_pix_pll(m, n - 3, *p)== B_OK) &&
(gx50_dac_check_pix_pll(m, n - 2, *p)== B_OK) &&
(gx50_dac_check_pix_pll(m, n - 1, *p)== B_OK) &&
(gx50_dac_check_pix_pll(m, n + 1, *p)== B_OK) &&
(gx50_dac_check_pix_pll(m, n + 2, *p)== B_OK) &&
(gx50_dac_check_pix_pll(m, n + 3, *p)== B_OK))
{
LOG(2,("DAC: found optimal working VCO filter: #%d\n",s));
/* preset first choice setting found */
*q = 1;
/* we are done */
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
return B_OK;
}
else
{
LOG(2,("DAC: found critical but working VCO filter: #%d\n",s));
/* preset backup setting found */
*q = 2;
/* remember this setting */
p_backup = *p;
/* let's continue to see if a better filter exists */
}
}
/* new filtersetting to try */
*p += (1 << 3);
}
/* return the (last found) backup result, or the original p value */
*p = p_backup;
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
/* we found only a non-optimal value */
if (*q == 2) return B_OK;
/* nothing worked at all */
LOG(2,("DAC: no working VCO filter found!\n"));
return B_ERROR;
}
/* find nearest valid pix pll */
status_t gx00_dac_pix_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
switch (si->ps.card_type) {
case G550:
case G450: return g450_g550_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result);
}
return B_ERROR;
}
/* find nearest valid pixel PLL setting: rewritten by rudolf */
static status_t g100_g400max_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
switch(si->ps.card_type)
{
case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac1_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 8.0))
req_pclk = (si->ps.min_pixel_vco / 8.0);
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk) req_pclk = max_pclk;
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
/* calc the needed PLL loopbackfilter setting belonging to current VCO speed,
* for the current card (see G100, G200 and G400 specs). */
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
switch(si->ps.card_type)
{
case G100:
case G200:
for(;;)
{
if (f_vco >= 180) {p |= (0x03 << 3); break;};
if (f_vco >= 140) {p |= (0x02 << 3); break;};
if (f_vco >= 100) {p |= (0x01 << 3); break;};
break;
}
break;
default:
for(;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
/* return the results */
*calc_pclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
/* find nearest valid pixel PLL setting: rewritten by rudolf */
static status_t g450_g550_dac_pix_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0;
uint8 p = 0, q = 0;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
LOG(4,("DAC: G450/G550 restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac1_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 16.0))
req_pclk = (si->ps.min_pixel_vco / 16.0);
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk) req_pclk = max_pclk;
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= 32; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5);
/* ..and check for validity, BUT:
* Keep in mind that we need to be able to test n-3 ... n+3! */
if ((n < (8 + 3)) || (n > (128 - 3))) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
switch(best[2])
{
case 1:
p = 0x40;
break;
case 2:
p = 0x00;
break;
case 4:
p = 0x01;
break;
case 8:
p = 0x02;
break;
case 16:
p = 0x03;
break;
}
/* log the closest VCO speed found */
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1);
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing.
* for now we assume this routine succeeds to get us a stable setting */
if (test)
gx50_dac_check_pix_pll_range(m, n, &p, &q);
else
LOG(2,("DAC: Not testing G450/G550 VCO feedback filters\n"));
/* return the results */
*calc_pclk = f_vco / best[2];
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
/* find nearest valid system PLL setting */
static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
int best[3];
float f_vco;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
switch(si->ps.card_type)
{
case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/* Make sure the requested systemclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 8.0))
req_sclk = (si->ps.min_system_vco / 8.0);
/* upper limit is max_system_vco */
if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco;
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_sclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
/* calc the needed PLL loopbackfilter setting belonging to current VCO speed,
* for the current card (see G100, G200 and G400 specs). */
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
switch(si->ps.card_type)
{
case G100:
case G200:
for(;;)
{
if (f_vco >= 180) {p |= (0x03 << 3); break;};
if (f_vco >= 140) {p |= (0x02 << 3); break;};
if (f_vco >= 100) {p |= (0x01 << 3); break;};
break;
}
break;
default:
for(;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
/* return the results */
*calc_sclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_sclk, *calc_sclk, *m_result, *n_result, *p_result));
return B_OK;
}
/*set up system pll - NB mclk is memory clock, */
status_t g100_dac_set_sys_pll()
{
/* values for DAC sys pll registers */
uint8 m, n, p;
uint time = 0;
uint32 temp;
float calc_sclk;
LOG(1,("DAC: Setting up G100 system clock\n"));
//zodra gclk, mclk en fmclk DIV ingesteld is via PINS en hieronder:
g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p);
/* reprogram the clock - set PCI/AGP, program, set to programmed */
/* disable the SYSPLL */
CFGW(OPTION, CFGR(OPTION) | 0x04);
/* select the PCI/AGP clock */
CFGW(OPTION, CFGR(OPTION) & 0xfffffffc);
/* enable the SYSPLL */
CFGW(OPTION, CFGR(OPTION) & 0xfffffffb);
/* program the new clock */
DXIW(SYSPLLM, m);
DXIW(SYSPLLN, n);
DXIW(SYSPLLP, p);
/* Wait for the SYSPLL frequency to lock until timeout occurs */
while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: sys PLL frequency not locked!\n"));
else
LOG(2,("DAC: sys PLL frequency locked\n"));
/* disable the SYSPLL */
CFGW(OPTION, CFGR(OPTION) | 0x04);
/* setup Gclk, Mclk and FMclk divisors according to PINS */
temp = (CFGR(OPTION) & 0xffffff27);
if (si->ps.v3_clk_div & 0x01) temp |= 0x08;
if (si->ps.v3_clk_div & 0x02) temp |= 0x10;
if (si->ps.v3_clk_div & 0x04) temp |= 0x80;
/* fixme: swapPLL can only be done when the rest of the driver respects this also! */
//never used AFAIK:
//if (si->ps.v3_clk_div & 0x08) temp |= 0x40;
/* select the SYSPLL as system clock source */
temp |= 0x01;
CFGW(OPTION, temp);
/* enable the SYSPLL (and make sure the SYSPLL is indeed powered up) */
CFGW(OPTION, (CFGR(OPTION) & 0xfffffffb) | 0x20);
return B_OK;
}
/*set up system pll - NB mclk is memory clock, */
status_t g200_dac_set_sys_pll()
{
uint8 m, n, p;/*values for DAC sys pll registers*/
uint time = 0;
float calc_sclk;
LOG(1,("DAC: Setting up G200 system clock\n"));
//zodra gclk, mclk en fmclk DIV ingesteld is via PINS !EN OPTION2! en hieronder:
//g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p);
//voor nu:
g100_g400max_dac_sys_pll_find(124.2, &calc_sclk, &m, &n, &p);
/*reprogram the clock - set PCI/AGP, program, set to programmed*/
//fixme: PINS..
CFGW(OPTION2,0x8000); /*no memory clock divider (pinced from win)*/
CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/
CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFC); /*select the PCI/AGP clock*/
CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/
DXIW(SYSPLLM,m);
DXIW(SYSPLLN,n);
DXIW(SYSPLLP,p);
/* Wait for the SYSPLL frequency to lock until timeout occurs */
while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: sys PLL frequency not locked!\n"));
else
LOG(2,("DAC: sys PLL frequency locked\n"));
CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/
//fixme: PINS..
CFGW(OPTION,(CFGR(OPTION)&0xFFFFFF27)|0x1); /*select the SYSPLLs chosen*/
CFGW(OPTION,(CFGR(OPTION)&0xFFFFFFFB)|0x20); /*enable the SYSPLL*/
return B_OK;
}
/*set up system pll - NB mclk is memory clock, */
status_t g400_dac_set_sys_pll()
{
uint32 scalers; /*value for option 3*/
uint8 m, n, p;/*values for DAC sys pll registers*/
uint8 mclk_duty,oclk_duty;
uint time = 0;
float mclk,oclk;
float temp_f;
float calc_sclk;
/* fixme? get from PINS */
int mclk_div = 4;
int oclk_div = 3;
float div[8]={0.3333,0.4,0.4444,0.5,0.6666,0,0,0};
LOG(1,("DAC: Setting up G400/G400MAX system clock\n"));
g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p);
/* calculate the real clock speeds derivated from SYSPLL */
mclk = div[mclk_div] * calc_sclk;
oclk = div[oclk_div] * calc_sclk;
/*work out the duty cycle correction*/
temp_f=1/(float)oclk;
temp_f*=1000;
LOG(2,("DAC:oclk correction ns: %f\n",temp_f));
temp_f-=2.25;
temp_f/=0.5;
oclk_duty=(uint8)temp_f;
temp_f=1/(float)mclk;
temp_f*=1000;
LOG(2,("DAC:mclk correction ns: %f\n",temp_f));
temp_f-=2.25;
temp_f/=0.5;
mclk_duty=(uint8)temp_f;
/*calculate OPTION3*/
scalers=(0x1<<0)|(0x1<<10)|(0x1<<20);
scalers|=(oclk_div<<3)|(mclk_div<<13)|(oclk_div<<23);
scalers|=(oclk_duty<<6)|(mclk_duty<<16)|(oclk_duty<<26);
/*print out the results*/
LOG(2,("DAC: MCLK:%f\tOCLK:%f\n",mclk,oclk));
LOG(2,("DAC: mclk_div:0x%x mclk_duty:0x%x\noclk_div:0x%x oclk_duty:0x%x\nOPTION3: 0x%x\n",
mclk_div,mclk_duty,oclk_div,oclk_duty,scalers));
/*reprogram the clock - set PCI/AGP, program, set to programmed*/
CFGW(OPTION2,0); /*clear so don't o/clock add ons*/
CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/
CFGW(OPTION3,0); /*select the PCI/AGP clock*/
CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/
DXIW(SYSPLLM,m);
DXIW(SYSPLLN,n);
DXIW(SYSPLLP,p);
/* Wait for the SYSPLL frequency to lock until timeout occurs */
while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: sys PLL frequency not locked!\n"));
else
LOG(2,("DAC: sys PLL frequency locked\n"));
CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/
CFGW(OPTION3,scalers); /*select the SYSPLLs chosen*/
CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/
return B_OK;
}
/*set up system pll - NB mclk is memory clock, */
//fixme: implement this routine for coldstart:
//status_t g450_dac_set_sys_pll(int m,int n,int mclk_div,int oclk_div)
@@ -0,0 +1,735 @@
/* Authors:
Mark Watson 12/1999,
Apsed,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x00008000
#include "mga_std.h"
//apsed #include "memory"
//#include "mga_init.c" //Nicole's test stuff.
status_t test_ram();
static status_t mil2_general_powerup (void);
static status_t g100_general_powerup (void);
static status_t g200_general_powerup (void);
static status_t g400_general_powerup (void);
static status_t g450_general_powerup (void);
static status_t gx00_general_bios_to_powergraphics(void);
static void mga_dump_configuration_space (void)
{
#define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \
uint32 value = CFGR(reg); \
MSG(("configuration_space 0x%02x %20s 0x%08x\n", \
MGACFG_##reg, #reg, value)); \
} while (0)
DUMP_CFG (DEVID, 0);
DUMP_CFG (DEVCTRL, 0);
DUMP_CFG (CLASS, 0);
DUMP_CFG (HEADER, 0);
DUMP_CFG (MGABASE2, 0);
DUMP_CFG (MGABASE1, 0);
DUMP_CFG (MGABASE3, MYST);
DUMP_CFG (SUBSYSIDR, MYST);
DUMP_CFG (ROMBASE, 0);
DUMP_CFG (CAP_PTR, MIL2);
DUMP_CFG (INTCTRL, 0);
DUMP_CFG (OPTION, 0);
DUMP_CFG (MGA_INDEX, 0);
DUMP_CFG (MGA_DATA, 0);
DUMP_CFG (SUBSYSIDW, MYST);
DUMP_CFG (OPTION2, G100);
DUMP_CFG (OPTION3, G400);
DUMP_CFG (OPTION4, G400);
DUMP_CFG (PM_IDENT, G100);
DUMP_CFG (PM_CSR, G100);
DUMP_CFG (AGP_IDENT, MIL2);
DUMP_CFG (AGP_STS, MIL2);
DUMP_CFG (AGP_CMD, MIL2);
#undef DUMP_CFG
}
status_t gx00_general_powerup()
{
status_t status;
uint32 class;
//detect card type and powerup
switch(CFGR(DEVID))
{
case 0x0519102b: //MGA-2064 Millenium PCI
case 0x051a102b: //MGA-1064 Mystic PCI
LOG(8,("POWERUP: unimplemented Matrox device %08x\n",CFGR(DEVID)));
return B_ERROR;
case 0x051b102b:case 0x051f102b: //MGA-2164 Millenium 2 PCI/AGP
si->ps.card_type=MIL2;
LOG(4,("POWERUP:Detected MGA-2164 Millennium 2\n"));
status = mil2_general_powerup();
break;
case 0x1000102b:case 0x1001102b: //G100
si->ps.card_type=G100;
LOG(4,("POWERUP:Detected G100\n"));
status = g100_general_powerup();
break;
case 0x0520102b:case 0x0521102b: //G200
si->ps.card_type=G200;
LOG(4,("POWERUP:Detected G200\n"));
status = g200_general_powerup();
break;
case 0x0525102b: //G400
LOG(4,("POWERUP:Detected G4"));
//Check if it is a G450...
class = 0xff&CFGR(CLASS);
if (class & 0x80) //G450
{
si->ps.card_type=G450;
LOG(4, ("50 revision %x\n", class&0x7f));
status = g450_general_powerup();
}
else //G400
{
si->ps.card_type=G400;
LOG(4, ("00 revision %x\n", class&0x7f));
status = g400_general_powerup();
}
break;
case 0x2527102b://G550 patch from Jean-Michel Batto
si->ps.card_type=G450;
LOG(4,("POWERUP:Detected G550\n"));
status = g450_general_powerup();
break;
default:
LOG(8,("POWERUP:Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
return B_ERROR;
}
/*override memory if requested by user*/
// even if detection works on the G400
if (si->settings.memory != 0) // apsed
si->ps.memory_size = si->settings.memory;
return status;
}
status_t test_ram()
{
uint32 value, offset;
status_t result = B_OK;
/* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */
if (si->fbc.frame_buffer == NULL)
{
LOG(8,("INIT: test_ram detected NULL pointer.\n"));
return B_ERROR;
}
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
{
/* write testpattern to cardRAM */
((uint32 *)si->fbc.frame_buffer)[offset] = value;
/* toggle testpattern */
value = 0xffffffff - value;
}
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
{
/* readback and verify testpattern from cardRAM */
if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
/* toggle testpattern */
value = 0xffffffff - value;
}
return result;
}
/* NOTE:
* This routine *has* to be done *after* SetDispplayMode has been executed,
* or test results will not be representative!
* (CAS latency is dependant on MGA setup on some (DRAM) boards) */
status_t mga_set_cas_latency()
{
status_t result = B_ERROR;
uint8 latency = 0;
/* check current RAM access to see if we need to change anything */
if (test_ram() == B_OK)
{
LOG(4,("INIT: RAM access OK.\n"));
return B_OK;
}
/* check if we read PINS at starttime so we have valid registersettings at our disposal */
if (si->ps.pins_status != B_OK)
{
LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n"));
return B_ERROR;
}
/* OK. We might have a problem, try to fix it now.. */
LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n"));
switch(si->ps.card_type)
{
case G100:
if (!si->ps.sdram)
{
LOG(4,("INIT: G100 SGRAM CAS tuning not permitted, aborting.\n"));
return B_OK;
}
/* SDRAM card */
for (latency = 4; latency >= 2; latency-- )
{
/* MCTLWTST is a write-only register! */
ACCW(MCTLWTST, ((si->ps.mctlwtst_reg & 0xfffffffc) | (latency - 2)));
result = test_ram();
if (result == B_OK) break;
}
break;
case G200:
/* fixme: implement this */
LOG(4,("INIT: G200 RAM CAS tuning not implemented, aborting.\n"));
return B_OK;
break;
case G400:
case G400MAX:
/* fixme: implement this if needed */
LOG(4,("INIT: G400/G400MAX RAM CAS tuning not implemented, aborting.\n"));
return B_OK;
break;
case G450:
case G550:
/* G450 and G550 tune CAS latency via a predefined table at powerup time */
LOG(4,("INIT: G450/G550 RAM CAS tuning not implemented, aborting.\n"));
return B_OK;
break;
default:
/* fixme: Millenium2 and others if needed */
LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n"));
return B_OK;
break;
}
if (result == B_OK)
LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency));
else
LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency));
return result;
}
static
status_t mil2_general_powerup()
{
status_t result;
LOG(4, ("INIT: Millenium II powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
//remove this:
// various sensible defaults for MIL2
si->ps.sdram = true;
si->ps.memory_size = 2; //can override
si->ps.memory_size = 4; //can override my mil2
// apsed TODO MIL2 TVP 3026 may be 135, 175, 220 or 250MHz
// chip on my Millenium2 is TVP3026-250CPCE, 250MHz
// rudolf: works in Mhz now
si->ps.max_dac1_clock=250; // TVP3026
//end remove this.
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
//restore this line:
// if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics();
//set to powergraphics etc.
LOG(2, ("INIT: Skipping card coldstart!\n"));
mil2_dac_init();
VGAW_I(SEQ,1,0x00);
/*enable screen*/
return B_OK;
return B_ERROR; // apsed TODO MIL2 taken from G100, avoid DXIR/W DACR/W
/*power up the PLLs,LUT,DAC*/
/*this bit should not be needed if BIOS has initialised it*/
LOG(2,("INIT:PLL/LUT/DAC powerup\n"));
DXIW(VREFCTRL,0x3F); /*set voltage reference - using DAC reference block*/
delay(100000); /*wait for 100ms for voltage reference to stabalise*/
CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/
while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/
LOG(2,("INIT: SYS PLL locked\n"));
DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/
while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/
LOG(2,("INIT: PIX PLL locked\n"));
DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
/* setup i2c bus */
i2c_init();
/*make sure card is in powergraphics mode*/
VGAW_I(CRTCEXT,3,0x80);
/*set the system clocks to powergraphics speed*/
LOG(2,("INIT:Setting SYS/PIX plls to powergraphics speeds\n"));
g100_dac_set_sys_pll();
/*RAM initialisation*/
LOG(2,("INIT:RAM init\n"));
gx00_crtc_dpms(0,0,0); /*turn off both displays*/
ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/
CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/
CFGW(OPTION2,(CFGR(OPTION2)&0xC100)|(si->ps.mem_rd)); /*set MEMRDCLK*/
CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|(si->ps.membuf<<12)); /*set the memory buffer type*/
delay(250); /*wait for 250microseconds*/
ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/
delay(250);
ACCW(MACCESS,ACCR(MACCESS)|0xC000); /*sets JEDEC as well*/
delay(250); /*wait for 250microseconds*/
ACCW(MACCESS,ACCR(MACCESS)&0xFFFF3FFF);
delay(250);
ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/
/*Bus parameters*/
CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/
/*enable writing to crtc registers*/
VGAW_I(CRTC,0x11,0);
/*turn on display one*/
gx00_crtc_dpms(1,1,1);
return B_OK;
}
static
status_t g100_general_powerup()
{
status_t result;
LOG(4, ("INIT: G100 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics();
/*power up the PLLs,LUT,DAC*/
/*this bit should not be needed if BIOS has initialised it*/
LOG(2,("INIT: PLL/LUT/DAC powerup\n"));
/* G100 SGRAM and SDRAM use external pix and dac refs, do *not* activate internals!
* (this would create electrical shortcuts,
* resulting in extra chip heat and distortions visible on screen */
DXIW(VREFCTRL,0x03); /*set voltage reference - using DAC reference block partly */
delay(100000); /*wait for 100ms for voltage reference to stabalise*/
CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/
while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/
LOG(2,("INIT: SYS PLL locked\n"));
DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/
while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/
LOG(2,("INIT: PIX PLL locked\n"));
DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
/* setup i2c bus */
i2c_init();
/*make sure card is in powergraphics mode*/
VGAW_I(CRTCEXT,3,0x80);
/*set the system clocks to powergraphics speed*/
LOG(2,("INIT: Setting system PLL to powergraphics speeds\n"));
g100_dac_set_sys_pll();
/* 'official' RAM initialisation */
LOG(2,("INIT: RAM init\n"));
/* turn off both displays (also disables transfers) */
gx00_crtc_dpms(0,0,0);
/* disable plane write mask (needed for SDRAM) */
ACCW(PLNWT,0xffffffff);
/* program memory control waitstates */
ACCW(MCTLWTST,si->ps.mctlwtst_reg);
/* set memory configuration:
* - no split framebuffer,
* - Mark says b14 (G200) should be done also though not defined for G100 in spec,
* - b3 v3_mem_type was included by Mark for memconfig setup: but looks like not defined */
CFGW(OPTION,(CFGR(OPTION)&0xFFFF8FFF) | ((si->ps.v3_mem_type & 0x04) << 10));
/* set memory buffer type:
* - Mark says: if((v3_mem_type & 0x03) == 0x03) then do not or-in bits in option2;
* but looks like v3_mem_type b1 is not defined,
* - Mark also says: place v3_mem_type b1 in option2 bit13 (if not 0x03) but b13 = reserved. */
CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|((si->ps.v3_mem_type & 0x01) << 12));
/* set mode register opcode to $0 */
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xE1FFFFFF)); /* G200 only */
/* set RAM read tap delay G100 */
CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFFFF0) | ((si->ps.v3_mem_type & 0xf0) >> 4));
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|the_setting); /* G200 version */
/* wait 200uS minimum */
snooze(250);
/* reset memory */
ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF);
/* select JEDEC reset method */
ACCW(MACCESS,ACCR(MACCESS)|0x4000);
/* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
snooze(250);
/* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
/* set memory control waitstate again AFTER the RAM reset */
ACCW(MCTLWTST,si->ps.mctlwtst_reg);
/* end 'official' RAM initialisation. */
/* Bus parameters: enable retries, use advanced read */
CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29)));
/*enable writing to crtc registers*/
VGAW_I(CRTC,0x11,0);
/*turn on display one*/
gx00_crtc_dpms(1,1,1);
return B_OK;
}
static
status_t g200_general_powerup()
{
status_t result;
LOG(4, ("INIT: G200 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics();
/*power up the PLLs,LUT,DAC*/
/*this bit should not be needed if BIOS has initialised it*/
LOG(2,("INIT: PLL/LUT/DAC powerup\n"));
//rudolf: check from here on:
DXIW(VREFCTRL,0x3f); /*set voltage reference - using DAC reference block*/
delay(100000); /*wait for 100ms for voltage reference to stabalise*/
CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/
while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/
LOG(2,("INIT: SYS PLL locked\n"));
DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/
while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/
LOG(2,("INIT: PIX PLL locked\n"));
DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
//until here
/* setup i2c bus */
i2c_init();
//rudolf: remove:
/*read the PINS and other stuff*/
if (g200_card_info()==B_ERROR)
return B_ERROR;
//until here
/*make sure card is in powergraphics mode*/
VGAW_I(CRTCEXT,3,0x80);
/*set the system clocks to powergraphics speed*/
LOG(2,("INIT: Setting SYS/PIX plls to powergraphics speeds\n"));
g200_dac_set_sys_pll();
/*RAM initialisation*/
LOG(2,("INIT:RAM init\n"));
gx00_crtc_dpms(0,0,0); /*turn off both displays*/
ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/
CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/
ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF)|(si->ps.mem_rd&0xFFFF0000));/*set MEMRDBK - mrsopcode*/
CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|(si->ps.membuf<<12)); /*set the memory buffer type*/
delay(250); /*wait for 250microseconds*/
ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
delay(250); /*wait for 250microseconds*/
ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/
/*Bus parameters*/
CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/
/*enable writing to crtc registers*/
VGAW_I(CRTC,0x11,0);
/*turn on display one*/
gx00_crtc_dpms(1,1,1);
return B_OK;
}
static
status_t g400_general_powerup()
{
status_t result;
//fully functional G400 powerup -> uses settings from my card if no PINS
LOG(4, ("INIT: G400 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics();
/*power up the PLLs,LUT,DAC*/
/*this bit should not be needed if BIOS has initialised it*/
LOG(4,("INIT: G400 PLL/LUT/DAC powerup\n"));
DXIW(VREFCTRL,0x30); /*set voltage reference - using DAC reference block*/
delay(100000); /*wait for 100ms for voltage reference to stabalise*/
CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/
while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/
LOG(2,("INIT: SYS PLL locked\n"));
DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/
while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/
LOG(2,("INIT: PIX PLL locked\n"));
DXIW(MISCCTRL,0x9b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
DXIW(MAFCDEL,0x2); /*makes CRTC2 stable! Matrox specify 8, but use 4 - grrrr!*/
DXIW(PANELMODE,0x00); /*eclipse panellink*/
/* setup i2c bus */
i2c_init();
//rudolf: remove
/*read the PINS and other stuff*/
if (g400_card_info()==B_ERROR)
return B_ERROR;
//end remove
/*make sure card is in powergraphics mode*/
VGAW_I(CRTCEXT,3,0x80);
/*set the system clocks to powergraphics speed*/
LOG(2,("INIT: Setting SYS/PIX plls to powergraphics speeds\n"));
g400_dac_set_sys_pll();
/*RAM initialisation*/
LOG(2,("INIT:RAM init\n"));
gx00_crtc_dpms(0,0,0); /*turn off both displays*/
g400_crtc2_dpms(0,0,0);
ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/
CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/
ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF)|(si->ps.mem_rd&0xFFFF0000));/*set MEMRDBK - mrsopcode*/
delay(250); /*wait for 250microseconds*/
ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
delay(250); /*wait for 250microseconds*/
ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/
/*Bus parameters*/
CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/
/*enable writing to crtc registers*/
VGAW_I(CRTC,0x11,0);
if (si->ps.secondary_head)
{
MAVW(LOCK,0x01);
CR2W(DATACTL,0x00000000);
}
/*turn on display one*/
gx00_crtc_dpms(1,1,1);
return B_OK;
}
static
status_t g450_general_powerup()
{
uint32 temp;
status_t result;
LOG(4, ("INIT: G450 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
//rudolf: remove if impl in PINS above:
// various sensible defaults for G450
si->ps.sdram = true;
//end remove
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics();
/*power up the PLLs,LUT,DAC*/
//rudolf: checkout coldstart from here:
//In case you are interested here is some of the G450 powerup stuff -> nonfunction as yet
//These are the values of OPTION->OPTION4 used in Linux
//rudolf: get from PINS...
CFGW(OPTION, 0x400a1160);
CFGW(OPTION2, 0x100ac00);
CFGW(OPTION3, 0x90a409);
CFGW(OPTION4, 0x80000004);
//rudolf: remove
/*read the PINS and other stuff*/
if (g450_card_info()==B_ERROR)
return B_ERROR;
//end remove
//various init (as bios)
CFGW(OPTION, ((CFGR(OPTION)&0xf8404164) | (si->ps.option&0x207e00)) );
CFGW(OPTION2, (CFGR(OPTION2) | (0xfc00&si->ps.option2)));
ACCW(MCTLWTST, si->ps.mem_ctl);
CFGW(OPTION4, (si->ps.option4&0x6000000f));
ACCW(MEMRDBK, si->ps.mem_rd);
ACCW(MACCESS, ((si->ps.maccess&0x80)>>1) );
CFGW(OPTION4,((si->ps.option4&0x60000004)|0x80000000));
delay(250);
if
(
((si->ps.option&0x200000) == 0) &&
((si->ps.maccess&0x200) == 0)
)
{
ACCW(MEMRDBK, ((si->ps.mem_rd)&0xffffefff));
if ((si->ps.maccess&0x100) == 0)
{
ACCW(MACCESS, ACCR(MACCESS)&0xffff00ff);
}
}
temp = ACCR(MACCESS);
temp &=0xffff80ff;
temp = temp|((temp&0x8000)>>1)|0x8000;
ACCW(MACCESS, temp);
temp &= 0xffff7fff;
ACCW(MACCESS, temp);
delay(250);
if ((si->ps.maccess&0x400) == 0)
{
temp = si->ps.mem_ctl;
temp = (temp &0x7) + 3;
temp |= si->ps.mem_ctl &0xfffffff8;
ACCW(MCTLWTST, temp);
}
temp = CFGR(OPTION);
temp &=0xffe07fff;
temp |= si->ps.option&0x1f8000;
CFGW(OPTION, temp);
return B_OK;
}
/*connect CRTC1 to the specified DAC*/
status_t gx00_general_dac_select(int dac)
{
if (!si->ps.secondary_head)
return B_ERROR;
/*MISCCTRL, clock src,...*/
switch(dac)
{
case DS_CRTCDAC_CRTC2MAVEN: /*CRTC->DAC,CRTC2->MAFC*/
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); /*external clk*/
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
break;
case DS_CRTCMAVEN_CRTC2DAC: /*CRTC->MAVEN,CRTC2->DAC*/
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); /*external clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk*/
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88));
DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02);
break;
case DS_CRTCDAC_CRTC2DAC2:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk - gets DAC*/
//FIXME VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
//FIXME DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
break;
case DS_CRTCDAC_CRTCDAC2:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x0<<20)); /*internal clk - no DAC PTR*/
break;
default:
return B_ERROR;
}
return B_OK;
}
/*busy wait until retrace!*/
status_t gx00_general_wait_retrace()
{
while (!(ACCR(STATUS)&0x8));
return B_OK;
}
/* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/
static
status_t gx00_general_bios_to_powergraphics()
{
LOG(2, ("INIT: Skipping card coldstart!\n"));
//set to powergraphics etc.
CFGW(DEVCTRL,(2|CFGR(DEVCTRL)));
/*enable device response (already enabled here!)*/
VGAW_I(CRTC,0x11,0);
/*allow me to change CRTC*/
VGAW_I(CRTCEXT,3,0x80);
/*use powergraphix (+ trash other bits, they are set later)*/
VGAW(MISCW,0x08);
/*set only MGA pixel clock in MISC - I don't want to map VGA stuff under this OS*/
if (si->ps.card_type >= G100) {
DXIW(MISCCTRL,0x9b);
/*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
DXIW(MULCTRL,0x4);
/*RGBA direct mode*/
} else {
LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR)));
} // apsed TODO MIL2
VGAW_I(SEQ,1,0x00);
/*enable screen*/
return B_OK;
}
@@ -0,0 +1,291 @@
/*
* i2c interface for the G400 MAVEN under BeOS
* Mark Watson 06/2000
*
* Provides I2CR,I2CW - functions to parallel DACW,DACR
* Bus is run slowly because I do not know how fast the MAVEN is!
*
* Much help was provided by observing the Linux i2c code,
* so thanks go to: Gerd Knorr
*/
#define MODULE_BIT 0x00004000
#include "mga_std.h"
/*which device on the bus is the MAVEN?*/
#define MAVEN_WRITE (0x1B<<1)
#define MAVEN_READ ((0x1B<<1)|1)
#define I2C_CLOCK 0x20
#define I2C_DATA 0x10
/*-----------------------------
*low level hardware access
*/
#define I2C_DELAY 2
#define I2C_TIMEOUT 100
int i2c_set_lines(int clock,int data)
{
int count=0;
int program;
int required;
/*work out which bits to zero*/
program =
(clock ? 0 : I2C_CLOCK)|
(data ? 0 : I2C_DATA);
/*what value do I require on data lines*/
required =
(clock ? I2C_CLOCK : 0);
/*set the bits to zero*/
DXIW(GENIOCTRL,program); /*drive these bits*/
DXIW(GENIODATA,0x00); /*to zero*/
/*wait a bit*/
delay(I2C_DELAY);
/*loop until the clock is as required*/
while ((DXIR(GENIODATA)&I2C_CLOCK)!=required)
{
delay(I2C_DELAY);
count++;
if (count>I2C_TIMEOUT)
{
LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA)));
return -1;
}
}
return 0;
}
int i2c_get_data()
{
int data;
int clock;
int count=0;
do
{
/*read the data and clock lines*/
data = DXIR(GENIODATA);
clock = (data&I2C_CLOCK) ? 1 : 0;
data = (data&I2C_DATA) ? 1 : 0;
/*manage timeout*/
count++;
if (count>I2C_TIMEOUT)
{
return -1;
}
/*wait a bit, so not hammering bus*/
delay(I2C_DELAY);
}while (!clock); /*wait for high clock*/
return data;
}
/*-----------------------
*Standard I2C operations
*/
void i2c_start()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: start - %d\n",error));
}
}
void i2c_stop()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: stop - %d\n",error));
}
}
void i2c_high()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: high - %d\n",error));
}
}
void i2c_low()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: low - %d\n",error));
}
}
int i2c_get_ack()
{
int error=0;
int ack;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
ack = i2c_get_data();
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: get_ack - %d value:%x\n",error,ack));
}
return ack;
}
void i2c_send_ack()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: send_ack - %d\n",error));
}
}
/*------------------------------
*use above functions to send and receive bytes
*/
int i2c_sendbyte(unsigned char data)
{
int i;
for (i=7; i>=0; i--)
{
if (data&(1<<i))
{
i2c_high();
}
else
{
i2c_low();
}
}
return i2c_get_ack();
}
unsigned char i2c_readbyte(int ack_required)
{
int i;
unsigned char data=0;
/*read data*/
i2c_set_lines(0,1);
for (i=7; i>=0; i--)
{
i2c_set_lines(1,1);
if (i2c_get_data()==1)
data |= (1<<i);
i2c_set_lines(0,1);
}
/*send acknowledge*/
if (ack_required) i2c_send_ack();
return data;
}
/*-------------------------------------------
*PUBLIC functions
*/
int i2c_maven_read(unsigned char address)
{
int error=0;
int data;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_READ);
error+=i2c_sendbyte(address);
data = i2c_readbyte(0);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVR ERROR - %x\n",error));
return data;
}
void i2c_maven_write(unsigned char address, unsigned char data)
{
int error=0;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_WRITE);
error+=i2c_sendbyte(address);
error+=i2c_sendbyte(data);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVW ERROR - %x\n",error));
}
status_t i2c_init(void)
{
/*init g400 i2c*/
DXIW(GENIODATA,0x00); /*to zero*/
DXIW(GENIOCTRL,0x30); /*drive clock and data*/
DXIW(GENIOCTRL,0x00); /*stop driving*/
return B_OK;
}
status_t i2c_maven_probe(void)
{
int ack;
/*scan the bus for the MAVEN*/
i2c_start();
{
ack = i2c_sendbyte(MAVEN_READ);
}
i2c_stop();
if (ack==0)
{
return B_OK;
}
else
{
return B_ERROR;
}
}
@@ -0,0 +1,990 @@
/* Read initialisation information from card */
/* some bits are hacks, where PINS is not known */
/* Authors:
Mark Watson 2/2000,
Rudolf Cornelissen 10/2002
*/
#define MODULE_BIT 0x00002000
#include "mga_std.h"
//general pins stuff!
enum {
id=0x00,
length=0x02,
version=0x04,
location=0x7FFC
};
//pins v5(!) (as used by G450)
enum {
p5_option=0x30,
p5_option2=0x34,
p5_memctl=0x3e,
p5_option4=0x42,
p5_memrd=0x46,
p5_maccess=0x72
};
//pins v4 (as used by G400)
enum {
p4_memtype=0x35,
p4_memctl=0x3d,
p4_memrd=0x56,
p4_sdram=0x5c,
};
//pins v3 (as used by G200/G100?)
enum {
p3_memtype=0x36,
p3_memctl=0x30,
p3_memrd=0x38,
p3_sdram=0x34,
p3_membuf=0x3a //G200 extra?
};
static void dump_card_infos (void)
{
MSG(("g200_card_info:Memory control word: 0x%08x\n",si->ps.mem_ctl));
if (si->ps.sdram) MSG(("g200_card_info:is SDRAM card: 1\n"));
else MSG(("g200_card_info:is SDRAM card: 0\n"));
MSG(("g200_card_info:Memory config: 0x%08x\n",si->ps.mem_type));
MSG(("g200_card_info:MEMRDBK setting: 0x%08x\n",si->ps.mem_rd));
MSG(("g200_card_info:Membuftype: 0x%08x\n",si->ps.membuf));
MSG(("g200_card_info:mem_rfhcnt: %d\n", si->ps.mem_rfhcnt));
}
/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/
status_t g200_card_info()
{
uint8 * rom;
uint8 * pins;
int i;
int chksum = 0;
/*check the validity of PINS*/
LOG(4,("g200_card_info: Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
//check sig
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("g200_card_info:BIOS bad signiture: 0x%02x%02x, expected 0x55aa\n",rom[0],rom[1]));
}
LOG(2,("g200_card_info: BIOS signiture $AA55 found OK\n"));
pins = rom + (rom[location]|(rom[location+1]<<8));
LOG(2,("g200_card_info: Using PINS v%d.%d structure at 0x%04x\n",pins[version+1],pins[version],pins-rom));
//check valid
for (i=0;i<pins[length];i++)
{
chksum+=pins[i];
}
if(chksum%256)
{
si->ps.mem_ctl=0x4244ca1;
si->ps.mem_type=(4<<10)|(0<<14); //SDRAM memory config 4
si->ps.mem_rd=0x108;
si->ps.membuf=0;
}
else
{
LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n"));
/*read memory control word*/
si->ps.mem_ctl=*((uint32 *)(pins + p3_memctl));
/*read memory config*/
si->ps.mem_type=(pins[p3_memtype]&0x7)<<10;
if (!si->ps.sdram) si->ps.mem_type|= (0x01<<14);
/*figure out memrdbk settings*/
si->ps.mem_rd=((pins[p3_memrd+1]&0xf0)>>3)<<24|((pins[p3_memrd+1]&0x03)>>2)<<16; //FIXME - ROR
si->ps.mem_rd|=((pins[p3_memrd]&0xf0)<<1)|(pins[p3_memrd]&0x0f);
//memory buffer type setting
si->ps.membuf=pins[p3_membuf]&0x3;
}
/*FIXME hardcode a few required values, i.e. ones not found in PINS*/
/*memory refresh settings (values pinched from windows)*/
si->ps.mem_rfhcnt=0x78000>>15;
if (si->settings.logmask & 0x80000000) dump_card_infos();
return B_OK;
}
/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/
status_t g400_card_info()
{
uint8 * rom;
uint8 * pins;
int i;
int chksum = 0;
LOG(4,("INFO:Getting G400 card info\n"));
/*check the validity of PINS*/
LOG(2,("INFO:Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
//check sig
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("INFO:BIOS signiture not found\n"));
}
LOG(2,("INFO:BIOS signiture $AA55 found OK\n"));
pins = rom + (rom[location]|(rom[location+1]<<8));
LOG(2,("INFO:Using PINS v%d.%d structure at: %x\n",pins[version+1],pins[version],pins-rom));
//check valid
for (i=0;i<pins[length];i++)
{
chksum+=pins[i];
}
if((chksum%256)) //if pins is invalid make up some stuff
{
LOG(8,("INFO:PINS checksum is incorrect - using default values\n"));
LOG(8,("INFO:AFAIK these should work with most G400s, but they are untested\n"));
si->ps.mem_ctl=0x24045491;
si->ps.mem_type=1<<14; //SDRAM memory config 0
si->ps.mem_rd=0x108;
si->ps.sdram=true;
}
else
{
LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n"));
/*read memory control word*/
si->ps.mem_ctl=*((uint32 *)(pins + p4_memctl));
LOG(2,("INFO:Memory control word: %x\n",si->ps.mem_ctl));
/*read memory config*/
si->ps.sdram = (pins[p4_sdram]&0x10);
si->ps.mem_type=(pins[p4_memtype]&0x38)<<7;
if (!si->ps.sdram) si->ps.mem_type |= (0x01 << 14);
LOG(2,("INFO:Memory config: %x\n",si->ps.mem_type));
/*figure out memrdbk settings*/
si->ps.mem_rd=((pins[p4_memrd+1]&0xf0)>>3)<<24|((pins[p4_memrd+1]&0x03)>>2)<<16; //FIXME - ROR
si->ps.mem_rd|=((pins[p4_memrd]&0xf0)<<1)|(pins[p4_memrd]&0x0f);
LOG(2,("INFO:MEMRDBK setting: %x\n",si->ps.mem_rd));
/*figure out if it is a G400MAX*/
/*FIXME, use the correct ID method!*/
if (si->ps.mem_ctl==0x20049911)
{
LOG(2,("INFO:MAX\n"));
si->ps.card_type=G400MAX;
}
}
/*FIXME hardcode a few required values, i.e. ones not found in PINS*/
/*memory refresh settings (values pinched from windows)*/
if (si->ps.card_type==G400)
{
si->ps.mem_rfhcnt=0x27;
}
else if (si->ps.card_type==G400MAX)
{
si->ps.mem_rfhcnt=0x2e;
}
if (si->settings.logmask & 0x80000000) dump_card_infos();
return B_OK;
}
/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/
status_t g450_card_info()
{
uint8 * rom;
uint8 * pins;
int i;
int chksum = 0;
LOG(4,("INFO:Getting G450 card info\n"));
/*check the validity of PINS*/
LOG(2,("INFO:Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
//check sig
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("INFO:BIOS signiture not found\n"));
}
LOG(2,("INFO:BIOS signiture $AA55 found OK\n"));
pins = rom + (rom[location]|(rom[location+1]<<8));
LOG(2,("INFO:Using PINS v%d.%d structure at: %x\n",pins[version+1],pins[version],pins-rom));
//check valid
for (i=0;i<pins[length];i++)
{
chksum+=pins[i];
}
if((chksum%256)) //if pins is invalid make up some stuff
{
LOG(8,("INFO:PINS checksum is incorrect - using default values\n"));
LOG(8,("INFO:AFAIK these should work with most G450s, but they are untested\n"));
//FIXME
si->ps.mem_ctl=0x24045491;
si->ps.mem_type=1<<14; //SDRAM memory config 0
si->ps.mem_rd=0x108;
si->ps.sdram=true;
}
else
{
LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n"));
/*read memory control word*/
si->ps.mem_ctl=*((uint32 *)(pins + p5_memctl));
LOG(2,("INFO:Memory control word: %x\n",si->ps.mem_ctl));
/*read useful registers*/
si->ps.option=*((uint32 *)(pins + p5_option));
si->ps.option2=*((uint32 *)(pins + p5_option2));
si->ps.option4=*((uint32 *)(pins + p5_option4));
si->ps.maccess=*((uint32 *)(pins + p5_maccess));
/*figure out memrdbk settings*/
si->ps.mem_rd=*((uint32 *)(pins + p5_memrd));
}
if (si->settings.logmask & 0x80000000) dump_card_infos();
return B_OK;
}
/* Parse the BIOS PINS structure if there */
status_t parse_pins ()
{
uint8 pins_len = 0;
uint8 *rom;
uint8 *pins;
uint8 chksum = 0;
int i;
status_t result = B_ERROR;
/* preset PINS read status to failed */
si->ps.pins_status = B_ERROR;
/* check the validity of PINS */
LOG(2,("INFO: Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
/* check BIOS signature */
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("INFO: BIOS signiture not found\n"));
return B_ERROR;
}
LOG(2,("INFO: BIOS signiture $AA55 found OK\n"));
/* check for a valid PINS struct adress */
pins = rom + (rom[0x7FFC]|(rom[0x7FFD]<<8));
if ((pins - rom) > 0x7F80)
{
LOG(8,("INFO: invalid PINS adress\n"));
return B_ERROR;
}
/* checkout new PINS struct version if there */
if ((pins[0] == 0x2E) && (pins[1] == 0x41))
{
pins_len = pins[2];
if (pins_len < 3 || pins_len > 128)
{
LOG(8,("INFO: invalid PINS size\n"));
return B_ERROR;
}
/* calculate PINS checksum */
for (i = 0; i < pins_len; i++)
{
chksum += pins[i];
}
if (chksum)
{
LOG(8,("INFO: PINS checksum error\n"));
return B_ERROR;
}
LOG(2,("INFO: new PINS, version %u.%u, length %u\n", pins[5], pins[4], pins[2]));
/* fill out the si->ps struct if possible */
switch (pins[5])
{
case 2:
result = pins2_read(pins, pins_len);
break;
case 3:
result = pins3_read(pins, pins_len);
break;
case 4:
result = pins4_read(pins, pins_len);
break;
case 5:
result = pins5_read(pins, pins_len);
break;
default:
LOG(8,("INFO: unknown PINS version\n"));
return B_ERROR;
break;
}
}
/* checkout old 64 byte PINS struct version if there */
else if ((pins[0] == 0x40) && (pins[1] == 0x00))
{
pins_len = 0x40;
/* this PINS version has no checksum */
LOG(2,("INFO: old PINS found\n"));
/* fill out the si->ps struct */
result = pins1_read(pins, pins_len);
}
/* no valid PINS signature found */
else
{
LOG(8,("INFO: no PINS signature found\n"));
return B_ERROR;
}
/* check PINS read result */
if (result == B_ERROR)
{
LOG(8,("INFO: PINS read/decode error\n"));
return B_ERROR;
}
/* PINS scan succeeded */
si->ps.pins_status = B_OK;
LOG(2,("INFO: PINS scan completed succesfully\n"));
return B_OK;
}
status_t pins1_read(uint8 *pins, uint8 length)
{
//remove later on here:
// float f_ref; /* PLL reference-oscillator frequency */
// uint32 max_system_vco; /* graphics engine PLL VCO limits */
// uint32 min_system_vco;
// uint32 max_pixel_vco; /* dac1 PLL VCO limits */
// uint32 min_pixel_vco;
// uint32 max_video_vco; /* dac2, maven PLL VCO limits */
// uint32 min_video_vco;
// uint32 std_engine_clock; /* graphics engine clock speed needed */
// uint32 std_engine_clock_dh;
// uint32 max_dac1_clock; /* dac1 limits */
// uint32 max_dac1_clock_8; /* dac1 limits correlated to RAMspeed limits */
// uint32 max_dac1_clock_16;
// uint32 max_dac1_clock_24;
// uint32 max_dac1_clock_32;
// uint32 max_dac1_clock_32dh;
// uint32 max_dac2_clock; /* dac2 limits */
// uint32 max_dac2_clock_8; /* dac2, maven limits correlated to RAMspeed limits */
// uint32 max_dac2_clock_16;
// uint32 max_dac2_clock_24;
// uint32 max_dac2_clock_32;
// uint32 max_dac2_clock_32dh;
// bool secondary_head; /* presence of functions */
// bool secondary_tvout;
// bool primary_dvi;
// bool secondary_dvi;
// uint32 memory_size; /* memory in Mb */
// uint32 mctlwtst_reg; /* memory control waitstate register */
// uint32 option_reg; /* option register */
// uint8 v3_clk_div; /* pins v3 memory and system clock division factors */
// uint8 v3_mem_type; /* pins v3 memory type info */
// bool sdram;
//end remove later on here.
//fixme: implement this..
return B_ERROR;
}
status_t pins2_read(uint8 *pins, uint8 length)
{
LOG(2,("INFO: PINS version 2 details not yet known\n"));
return B_ERROR;
}
/* pins v3 is used by G100 and G200. */
status_t pins3_read(uint8 *pins, uint8 length)
{
/* used to calculate RAM refreshrate */
float mclk_period;
uint32 rfhcnt;
if (length != 64)
{
LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length));
return B_ERROR;
}
/* fill out the shared info si->ps struct */
si->ps.max_pixel_vco = pins[36] + 100;
si->ps.max_dac1_clock_8 = pins[37] + 100;
si->ps.max_dac1_clock_16 = pins[38] + 100;
si->ps.max_dac1_clock_24 = pins[39] + 100;
si->ps.max_dac1_clock_32 = pins[40] + 100;
si->ps.std_engine_clock = pins[44];
if (pins [45] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[45];
if (pins [46] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[46];
if (pins [47] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[47];
if (pins[52] & 0x01)
si->ps.std_engine_clock *= 3;
else
si->ps.std_engine_clock *= 2;
if (pins[52] & 0x20) si->ps.f_ref = 14.31818;
else si->ps.f_ref = 27.00000;
/* G100 and G200 support 2-16Mb RAM */
si->ps.memory_size = 2 << ((pins[55] & 0xc0) >> 6);
/* more memory specifics */
si->ps.mctlwtst_reg = (pins[51] << 24) | (pins[50] << 16) | (pins[49] << 8) | pins [48];
si->ps.v3_clk_div = pins[52];
si->ps.v3_mem_type = pins[54];
/* for cards using this version of PINS both functions are in maven */
si->ps.secondary_head = !(pins[59] & 0x01);
si->ps.secondary_tvout = !(pins[59] & 0x01);
/* setup via gathered info from pins with some fixed values added which are not in pins */
si->ps.option_reg = 0;
/* calculate refresh timer info-bits for 15uS interval (or shorter). See G100/G200 specs */
/* calculate std memory clock period (nS) */
if (pins[52] & 0x02)
/* only used on G200, not on G100 */
mclk_period = 3000.0 / si->ps.std_engine_clock;
else
mclk_period = 2000.0 / si->ps.std_engine_clock;
/* calculate needed setting, 'round-down' result! */
rfhcnt = (uint32)(((15000 / mclk_period) - 1) / 64);
/* check for register limit */
if (rfhcnt > 0x3f) rfhcnt = 0x3f;
/* add to option register */
si->ps.option_reg |= (rfhcnt << 15);
/* the rest of the OPTION info currently comes via 'v3_clk_div' and 'v3_mem_type'. */
/* assuming the only possible panellink will be on the first head */
si->ps.primary_dvi = !(pins[59] & 0x40);
/* logical consequence of the above */
si->ps.secondary_dvi = false;
/* indirect logical consequences, see also G100 and G200 specs */
si->ps.max_system_vco = si->ps.max_pixel_vco;
si->ps.max_dac1_clock = si->ps.max_dac1_clock_8;
si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32;
si->ps.std_engine_clock_dh = si->ps.std_engine_clock;
si->ps.sdram = (si->ps.v3_clk_div & 0x10);
/* not supported: */
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_24 = 0;
/* see G100, G200 and G400 specs */
si->ps.min_system_vco = 50;
si->ps.min_pixel_vco = 50;
/* fixme: ehhh, no specs: confirm/tune these by testing?! */
si->ps.max_video_vco = si->ps.max_pixel_vco;
si->ps.min_video_vco = 50;
/* assuming G100, G200 MAVEN has same specs as G400 MAVEN */
si->ps.max_dac2_clock = 136;
si->ps.max_dac2_clock_16 = 136;
si->ps.max_dac2_clock_32dh = 136;
si->ps.max_dac2_clock_32 = 136;
return B_OK;
}
/* pins v4 is used by G400 */
status_t pins4_read(uint8 *pins, uint8 length)
{
if (length != 128)
{
LOG(8,("INFO: wrong PINS length, expected 128, got %d\n", length));
return B_ERROR;
}
/* fill out the shared info si->ps struct */
if (pins[39] == 0xff) si->ps.max_pixel_vco = 230;
else si->ps.max_pixel_vco = 4 * pins[39];
if (pins[38] == 0xff) si->ps.max_system_vco = si->ps.max_pixel_vco;
else si->ps.max_system_vco = 4 * pins[38];
if (pins[40] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco;
else si->ps.max_dac1_clock_8 = 4 * pins[40];
if (pins[41] == 0xff) si->ps.max_dac1_clock_16 = si->ps.max_dac1_clock_8;
else si->ps.max_dac1_clock_16 = 4 * pins[41];
if (pins[42] == 0xff) si->ps.max_dac1_clock_24 = si->ps.max_dac1_clock_16;
else si->ps.max_dac1_clock_24 = 4 * pins[42];
if (pins[43] == 0xff) si->ps.max_dac1_clock_32 = si->ps.max_dac1_clock_24;
else si->ps.max_dac1_clock_32 = 4 * pins[43];
if (pins[44] == 0xff) si->ps.max_dac2_clock_16 = si->ps.max_pixel_vco;
else si->ps.max_dac2_clock_16 = 4 * pins[44];
if (pins[45] == 0xff) si->ps.max_dac2_clock_32 = si->ps.max_dac2_clock_16;
else si->ps.max_dac2_clock_32 = 4 * pins[45];
/* verified against windows driver: */
si->ps.std_engine_clock = 2 * pins[65];
if (pins[92] & 0x01) si->ps.f_ref = 14.31818;
else si->ps.f_ref = 27.00000;
si->ps.memory_size = 4 << ((pins[92] >> 2) & 0x03);
/* for cards using this version of PINS both functions are in maven */
si->ps.secondary_head = !(pins[91] & 0x01);
si->ps.secondary_tvout = !(pins[91] & 0x01);
/* assuming the only possible panellink will be on the first head */
si->ps.primary_dvi = !(pins[91] & 0x40);
/* logical consequence of the above */
si->ps.secondary_dvi = false;
/* indirect logical consequences, see also G100, G200 and G400 specs */
si->ps.max_dac1_clock = si->ps.max_dac1_clock_8;
si->ps.max_dac2_clock = si->ps.max_dac2_clock_16;
si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32;
si->ps.max_dac2_clock_32dh = si->ps.max_dac2_clock_32;
si->ps.std_engine_clock_dh = si->ps.std_engine_clock;
/* not supported: */
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_24 = 0;
/* see G100, G200 and G400 specs */
si->ps.min_system_vco = 50;
si->ps.min_pixel_vco = 50;
/* fixme: ehhh, no specs: confirm/tune these by testing?! */
si->ps.max_video_vco = si->ps.max_pixel_vco;
si->ps.min_video_vco = 50;
//todo:
// uint32 mctlwtst_reg;
// uint32 option_reg;
// bool sdram;
/* not used here: */
si->ps.v3_clk_div = 0;
si->ps.v3_mem_type = 0;
return B_OK;
}
/* pins v5 is used by G450 and G550 */
status_t pins5_read(uint8 *pins, uint8 length)
{
unsigned int m_factor = 6;
if (length != 128)
{
LOG(8,("INFO: wrong PINS length, expected 128, got %d\n", length));
return B_ERROR;
}
/* fill out the shared info si->ps struct */
if (pins[4]) m_factor = 8;
si->ps.max_system_vco = m_factor * pins[36];
si->ps.max_video_vco = m_factor * pins[37];
/* pixelVCO multiplier is 10 if pins V5.2 */
if (pins[4] == 0x02) si->ps.max_pixel_vco = 10 * pins[38];
else si->ps.max_pixel_vco = m_factor * pins[38];
si->ps.min_system_vco = m_factor * pins[121];
si->ps.min_video_vco = m_factor * pins[122];
/* pixelVCO multiplier is 10 if pins V5.2 */
if (pins[4] == 0x02) si->ps.min_pixel_vco = 10 * pins[123];
else si->ps.min_pixel_vco = m_factor * pins[123];
if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco;
else si->ps.max_dac1_clock_8 = 4 * pins[39];
if (pins[40] == 0xff) si->ps.max_dac1_clock_16 = si->ps.max_dac1_clock_8;
else si->ps.max_dac1_clock_16 = 4 * pins[40];
if (pins[41] == 0xff) si->ps.max_dac1_clock_24 = si->ps.max_dac1_clock_16;
else si->ps.max_dac1_clock_24 = 4 * pins[41];
if (pins[42] == 0xff) si->ps.max_dac1_clock_32 = si->ps.max_dac1_clock_24;
else si->ps.max_dac1_clock_32 = 4 * pins[42];
if (pins[124] == 0xff) si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32;
else si->ps.max_dac1_clock_32dh = 4 * pins[124];
if (pins[43] == 0xff) si->ps.max_dac2_clock_16 = si->ps.max_video_vco;
else si->ps.max_dac2_clock_16 = 4 * pins[43];
if (pins[44] == 0xff) si->ps.max_dac2_clock_32 = si->ps.max_dac2_clock_16;
else si->ps.max_dac2_clock_32 = 4 * pins[44];
if (pins[125] == 0xff) si->ps.max_dac2_clock_32dh = si->ps.max_dac2_clock_32;
else si->ps.max_dac2_clock_32dh = 4 * pins[125];
if (pins[118] == 0xff) si->ps.max_dac1_clock = si->ps.max_dac1_clock_8;
else si->ps.max_dac1_clock = 4 * pins[118];
if (pins[119] == 0xff) si->ps.max_dac2_clock = si->ps.max_dac1_clock;
else si->ps.max_dac2_clock = 4 * pins[119];
si->ps.std_engine_clock = 4 * pins[74];
si->ps.std_engine_clock_dh = 4 * pins[92];
si->ps.memory_size = ((pins[114] & 0x03) + 1) * 8;
if ((pins[114] & 0x07) > 3)
{
LOG(2,("INFO: unknown RAM size, defaulting to 8Mb\n"));
si->ps.memory_size = 8;
}
if (pins[110] & 0x01) si->ps.f_ref = 14.31818;
else si->ps.f_ref = 27.00000;
si->ps.secondary_head = (pins[117] & 0x70);
si->ps.secondary_tvout = (pins[117] & 0x40);
si->ps.primary_dvi = (pins[117] & 0x02);
si->ps.secondary_dvi = (pins[117] & 0x20);
/* not supported: */
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_24 = 0;
//todo:
// uint32 mctlwtst_reg;
// uint32 option_reg;
// bool sdram;
/* not used here: */
si->ps.v3_clk_div = 0;
si->ps.v3_mem_type = 0;
return B_OK;
}
/* fake_pins presumes the card was coldstarted by it's BIOS */
void fake_pins(void)
{
LOG(8,("INFO: faking PINS\n"));
switch (si->ps.card_type)
{
case MIL2:
pinsmil2_fake();
break;
case G100:
pinsg100_fake();
break;
case G200:
pinsg200_fake();
break;
case G400:
pinsg400_fake();
break;
case G400MAX:
pinsg400max_fake();
break;
case G450:
pinsg450_fake();
break;
case G550:
pinsg550_fake();
break;
}
/* find out if the card has a maven */
if (i2c_maven_probe() == B_OK)
{
si->ps.secondary_tvout = true;
si->ps.secondary_head = true;
}
else
{
si->ps.secondary_tvout = false;
si->ps.secondary_head = false;
}
/* not used because no coldstart will be attempted */
si->ps.std_engine_clock = 0;
si->ps.std_engine_clock_dh = 0;
si->ps.mctlwtst_reg = 0;
si->ps.option_reg = 0;
si->ps.v3_clk_div = 0;
si->ps.v3_mem_type = 0;
}
void pinsmil2_fake(void)
{
}
void pinsg100_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G100 specs */
si->ps.max_system_vco = 230;
si->ps.min_system_vco = 50;
si->ps.max_pixel_vco = 230;
si->ps.min_pixel_vco = 50;
/* no specs, assuming these */
si->ps.max_video_vco = 230;
si->ps.min_video_vco = 50;
/* see G100 specs */
si->ps.max_dac1_clock = 230;
si->ps.max_dac1_clock_8 = 230;
si->ps.max_dac1_clock_16 = 230;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 180;
si->ps.max_dac1_clock_32 = 136;
si->ps.max_dac1_clock_32dh = 136;
/* see specs */
si->ps.max_dac2_clock = 136;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 136;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 136;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 136;
/* assuming the only possible panellink will be on the first head */
//fixme: primary_dvi should be overrule-able via mga.settings for G100.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 2Mb RAM mounted */
si->ps.memory_size = 2;
//fixme: should be overrule-able via mga.settings for G100.
si->ps.sdram = true;
}
void pinsg200_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G200 specs */
si->ps.max_system_vco = 250;
si->ps.min_system_vco = 50;
si->ps.max_pixel_vco = 250;
si->ps.min_pixel_vco = 50;
/* no specs, assuming these */
si->ps.max_video_vco = 250;
si->ps.min_video_vco = 50;
/* see G200 specs */
si->ps.max_dac1_clock = 250;
si->ps.max_dac1_clock_8 = 250;
si->ps.max_dac1_clock_16 = 250;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 180;
si->ps.max_dac1_clock_32 = 136;
si->ps.max_dac1_clock_32dh = 136;
/* see specs */
si->ps.max_dac2_clock = 136;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 136;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 136;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 136;
/* assuming the only possible panellink will be on the first head */
//fixme: primary_dvi should be overrule-able via mga.settings for G100.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 2Mb RAM mounted */
si->ps.memory_size = 2;
/* ask the G200 what type of RAM it has been set to by it's BIOS */
si->ps.sdram = !(CFGR(OPTION) & 0x00004000);
}
void pinsg400_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G400 specs */
si->ps.max_system_vco = 300;
si->ps.min_system_vco = 50;
si->ps.max_pixel_vco = 300;
si->ps.min_pixel_vco = 50;
/* no specs, assuming these */
si->ps.max_video_vco = 300;
si->ps.min_video_vco = 50;
/* see G400 specs */
si->ps.max_dac1_clock = 300;
si->ps.max_dac1_clock_8 = 300;
si->ps.max_dac1_clock_16 = 300;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 230;
si->ps.max_dac1_clock_32 = 180;
si->ps.max_dac1_clock_32dh = 136;
/* see specs */
si->ps.max_dac2_clock = 136;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 136;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 136;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 136;
/* assuming the only possible panellink will be on the first head */
//fixme: primary_dvi should be overrule-able via mga.settings for G400.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 4Mb RAM mounted */
si->ps.memory_size = 4;
/* ask the G400 what type of RAM it has been set to by it's BIOS */
//todo:
// si->ps.sdram = !(CFGR(OPTION) & 0x00004000);
//end todo.
}
void pinsg400max_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G400MAX specs */
si->ps.max_system_vco = 360;
si->ps.min_system_vco = 50;
si->ps.max_pixel_vco = 360;
si->ps.min_pixel_vco = 50;
/* no specs, assuming these */
si->ps.max_video_vco = 360;
si->ps.min_video_vco = 50;
/* see G400MAX specs */
si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 280;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 136;
/* see specs */
si->ps.max_dac2_clock = 136;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 136;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 136;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 136;
/* assuming the only possible panellink will be on the first head */
//fixme: primary_dvi should be overrule-able via mga.settings for G400MAX.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 4Mb RAM mounted */
si->ps.memory_size = 4;
/* ask the G400MAX what type of RAM it has been set to by it's BIOS */
//todo:
// si->ps.sdram = !(CFGR(OPTION) & 0x00004000);
}
void pinsg450_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G450 pins readouts for max ranges, then use a bit smaller ones */
/* carefull not to take to high lower limits, and high should be >= 2x low. */
si->ps.max_system_vco = 600;
si->ps.min_system_vco = 256;
si->ps.max_pixel_vco = 640;
si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600;
si->ps.min_video_vco = 256;
si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 280;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 180;
/* see G450 pins readouts */
si->ps.max_dac2_clock = 232;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 232;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 232;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 180;
//fixme: primary & secondary_dvi should be overrule-able via mga.settings for G450.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 8Mb RAM mounted */
si->ps.memory_size = 8;
/* ask the G450 what type of RAM it has been set to by it's BIOS */
//todo:
// si->ps.sdram = !(CFGR(OPTION) & 0x00004000);
}
void pinsg550_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
//fixme: should be overrule-able via mga.settings.
si->ps.f_ref = 27.000;
/* see G550 pins readouts for max ranges, then use a bit smaller ones */
/* carefull not to take to high lower limits, and high should be >= 2x low. */
si->ps.max_system_vco = 768;
si->ps.min_system_vco = 384;
si->ps.max_pixel_vco = 960;
si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600;
si->ps.min_video_vco = 256;
si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 280;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 180;
/* see G550 pins readouts */
si->ps.max_dac2_clock = 232;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 232;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 232;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 180;
//fixme: primary & secondary_dvi should be overrule-able via mga.settings for G550.
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 8Mb RAM mounted */
si->ps.memory_size = 8;
/* ask the G550 what type of RAM it has been set to by it's BIOS */
//todo:
// si->ps.sdram = !(CFGR(OPTION) & 0x00004000);
}
void dump_pins(void)
{
LOG(2,("INFO: pinsdump follows:\n"));
LOG(2,("f_ref: %fMhz\n", si->ps.f_ref));
LOG(2,("max_system_vco: %dMhz\n", si->ps.max_system_vco));
LOG(2,("min_system_vco: %dMhz\n", si->ps.min_system_vco));
LOG(2,("max_pixel_vco: %dMhz\n", si->ps.max_pixel_vco));
LOG(2,("min_pixel_vco: %dMhz\n", si->ps.min_pixel_vco));
LOG(2,("max_video_vco: %dMhz\n", si->ps.max_video_vco));
LOG(2,("min_video_vco: %dMhz\n", si->ps.min_video_vco));
LOG(2,("std_engine_clock: %dMhz\n", si->ps.std_engine_clock));
LOG(2,("std_engine_clock_dh: %dMhz\n", si->ps.std_engine_clock_dh));
LOG(2,("max_dac1_clock: %dMhz\n", si->ps.max_dac1_clock));
LOG(2,("max_dac1_clock_8: %dMhz\n", si->ps.max_dac1_clock_8));
LOG(2,("max_dac1_clock_16: %dMhz\n", si->ps.max_dac1_clock_16));
LOG(2,("max_dac1_clock_24: %dMhz\n", si->ps.max_dac1_clock_24));
LOG(2,("max_dac1_clock_32: %dMhz\n", si->ps.max_dac1_clock_32));
LOG(2,("max_dac1_clock_32dh: %dMhz\n", si->ps.max_dac1_clock_32dh));
LOG(2,("max_dac2_clock: %dMhz\n", si->ps.max_dac2_clock));
LOG(2,("max_dac2_clock_8: %dMhz\n", si->ps.max_dac2_clock_8));
LOG(2,("max_dac2_clock_16: %dMhz\n", si->ps.max_dac2_clock_16));
LOG(2,("max_dac2_clock_24: %dMhz\n", si->ps.max_dac2_clock_24));
LOG(2,("max_dac2_clock_32: %dMhz\n", si->ps.max_dac2_clock_32));
LOG(2,("max_dac2_clock_32dh: %dMhz\n", si->ps.max_dac2_clock_32dh));
LOG(2,("secondary_head: "));
if (si->ps.secondary_head) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("secondary_tvout: "));
if (si->ps.secondary_tvout) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("primary_dvi: "));
if (si->ps.primary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("secondary_dvi: "));
if (si->ps.secondary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("card memory_size: %dMb\n", si->ps.memory_size));
LOG(2,("mctlwtst register: $%08x\n", si->ps.mctlwtst_reg));
LOG(2,("option register: $%08x\n", si->ps.option_reg));
LOG(2,("v3_clock_div: $%02x\n", si->ps.v3_clk_div));
LOG(2,("v3_mem_type: $%02x\n", si->ps.v3_mem_type));
LOG(2,("sdram: "));
if (si->ps.sdram) LOG(2,("SDRAM card\n")); else LOG(2,("SGRAM card\n"));
LOG(2,("INFO: end pinsdump.\n"));
}
@@ -0,0 +1,172 @@
/* program the MAVEN in monitor mode */
/* Thanx to Petr Vandrovec for info on the MAVEN */
/* Mark Watson 6/2000 */
#define MODULE_BIT 0x00001000
#include "mga_std.h"
status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v)
{
if (display&h&v)
{
MAVW(MONEN,0xb2);
MAVW(MONSET,0x20); /*must be set to this in monitor mode*/
MAVW(OUTMODE,3); /*monitor mode*/
MAVW(STABLE,0x22); /*makes picture stable?*/
MAVW(TEST,0x00); /*turn off test signal*/
}
else
{
/*turn off screen using a few methods!*/
MAVW(STABLE,0x6a);
// MAVW(TEST,0x3);
MAVW(OUTMODE,0x00);
}
return B_OK;
}
/*set a mode line - inputs are in pixels/scanlines*/
status_t gx00_maven_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
)
{
LOG(4,("MAVEN: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/
if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7))
{
LOG(8,("MAVEN:Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/*program the MAVEN*/
MAVWW(LASTLINEL,htotal);
MAVWW(HSYNCLENL,(hsync_e-hsync_s));
MAVWW(HSYNCSTRL,(htotal-hsync_s));
MAVWW(HDISPLAYL,(htotal-hsync_s+hdisp_e));
MAVWW(HTOTALL,(htotal+1));
MAVWW(VSYNCLENL,(vsync_e-vsync_s-1));
MAVWW(VSYNCSTRL,(vtotal-vsync_s));
MAVWW(VDISPLAYL,(vtotal-1));
MAVWW(VTOTALL,(vtotal-1));
MAVWW(HVIDRSTL,(htotal-si->crtc_delay));
MAVWW(VVIDRSTL,(vtotal-2));
return B_OK;
}
void gx00_maven_delay(int number)
{
MAVWW(HVIDRSTL,(si->dm.timing.h_total-number));
}
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t gx00_maven_mode(int mode,float brightness)
{
uint8 luma;
/*set luma to a suitable value for brightness*/
/*assuming 1A is a sensible value*/
luma = (uint8)(0x1a * brightness);
MAVW(LUMA,luma);
LOG(4,("MAVEN: LUMA setting - %x\n",luma));
return B_OK;
}
/*program the pixpll on the maven - frequency in kHz*/
status_t gx00_maven_set_pix_pll(float f_vco)
{
uint8 m=0,n=0,p=0;
float pix_setting;
status_t result;
LOG(4,("MAVEN:Setting PIX PLL %fMHz\n", f_vco));
result = gx00_maven_pix_pll_find(f_vco,&pix_setting,&m,&n,&p);
if (result != B_OK)
{
return result;
}
/*reprogram (select,wait for stability)*/
MAVW(PIXPLLM,(m)); /*set m value*/
MAVW(PIXPLLN,(n)); /*set n value*/
MAVW(PIXPLLP,(p|0x80)); /*set p value*/
LOG(2,("MAVEN: Clocks found: %x %x %x\n",m,n,p));
delay(1000); /*wait 1000us for PIXPLL to lock (no way of knowing)*/
LOG(2,("MAVEN: PIX PLL frequency locked\n"));
return B_OK;
}
/*find nearest valid pix pll*/
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
float f_ref=27.000;
int n_min=4;
int n_max=127;
int m_min=2;
int m_max=31;
int m=0,n=0,p=0;
float error;
float error_best;
int best[3];
float f_rat;
LOG(4,("MAVEN:Checking PIX PLL %fMHz\n", f_vco));
/*f_rat.m/p=n where m=M+1,n=N+1,p=P+1,f_rat=f_vco/f_ref*/
f_rat = f_vco/f_ref;
error_best = 999999999;
for (p=0x2 -1*(f_vco>80.0);p<0x10;p=p<<1)
{
for (m=m_min;m<m_max;m++)
{
/*calculate n for this m & p (and check for validity)*/
n=(int)((f_rat*m*p)+0.5);
if (n>n_max || n<n_min)
continue;
/*find error in frequency this gives*/
error=fabs(((f_ref*n)/(m*p))-f_vco);
if (error<error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
m=best[0];
n=best[1];
p=best[2];
/*calculate value of s for fvco, not sure if these are correct*/
for(;;)/*set loop filter bandwidth -> spot the Perl coder :-)*/
{
if(f_vco>180) {p|=0x18;break;};
if(f_vco>140) {p|=0x10;break;};
if(f_vco>100) {p|=0x08;break;};
break;
}
/*set the result*/
*result = (float) (f_ref*n)/(m*(p&0x7));
*m_result = m-1;
*n_result = n-1;
*p_result = p-1;
/*display the found value*/
LOG(4,("MAVEN: pixpllcheck - requested %fMHz got %fMHz\n",(double)f_vco,*result));
return B_OK;
}
@@ -0,0 +1,131 @@
/*general card functions*/
status_t gx00_general_powerup();
status_t mga_set_cas_latency();
status_t gx00_general_dac_select(int);
status_t gx00_general_wait_retrace();
//status_t gx00_general_bios_to_powergraphics();
/* apsed: logging macros */
#define MSG(args) do { /* if needed or si->settings with si NULL */ \
mga_log args; \
} while (0)
#define LOG(level_bit, args) do { \
uint32 mod = (si->settings.logmask & 0xfffffff0) & MODULE_BIT; \
uint32 lev = (si->settings.logmask & ~0xfffffff0) & level_bit; \
if (mod && lev) mga_log args; \
} while (0)
/*support functions*/
void delay(bigtime_t i);
void mga_log(char *format, ...);
/*i2c maven functions*/
int i2c_maven_read(unsigned char address);
void i2c_maven_write(unsigned char address, unsigned char data);
status_t i2c_init(void);
status_t i2c_maven_probe(void);
/*card info functions*/
status_t g450_card_info();
status_t g400_card_info();
status_t g200_card_info();
status_t parse_pins(void);
status_t pins1_read(uint8 *pins, uint8 length);
status_t pins2_read(uint8 *pins, uint8 length);
status_t pins3_read(uint8 *pins, uint8 length);
status_t pins4_read(uint8 *pins, uint8 length);
status_t pins5_read(uint8 *pins, uint8 length);
void fake_pins(void);
void pinsmil2_fake(void);
void pinsg100_fake(void);
void pinsg200_fake(void);
void pinsg400_fake(void);
void pinsg400max_fake(void);
void pinsg450_fake(void);
void pinsg550_fake(void);
void dump_pins(void);
/*DAC functions*/
status_t gx00_dac_mode(int,float);
status_t gx00_dac_palette(uint8*,uint8*,uint8*);
status_t gx00_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8);
status_t gx00_dac_set_pix_pll(display_mode target);
status_t g400_dac_set_sys_pll();
status_t g200_dac_set_sys_pll();
status_t g100_dac_set_sys_pll();
status_t mil2_dac_init(void);
status_t mil2_dac_mode(int,float, int hsync_pos,int vsync_pos, int sync_green);
status_t mil2_dac_palette(uint8*,uint8*,uint8*);
status_t mil2_dac_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *);
status_t mil2_dac_set_pix_pll(float f_vco,int bpp);
/*MAVEN functions*/
status_t gx00_maven_dpms(uint8,uint8,uint8);
status_t gx00_maven_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t gx00_maven_mode(int,float);
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *);
status_t gx00_maven_set_pix_pll(float f_vco);
/*CRTC1 functions*/
status_t gx00_crtc_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
);
status_t gx00_crtc_set_timing(
uint16 hd_e,uint16 hs_s,uint16 hs_e,uint16 ht,
uint16 vd_e,uint16 vs_s,uint16 vs_e,uint16 vt,
uint8 hsync_pos,uint8 vsync_pos
);
status_t gx00_crtc_depth(int mode);
status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp);
status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp);
status_t gx00_crtc_dpms(uint8,uint8,uint8);
status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*);
status_t gx00_crtc_mem_priority(uint8);
status_t gx00_crtc_cursor_init(); /*Yes, cursor follows CRTC1 - not the DAC!*/
status_t gx00_crtc_cursor_define(uint8*,uint8*);
status_t gx00_crtc_cursor_position(uint16 x ,uint16 y);
status_t gx00_crtc_cursor_show();
status_t gx00_crtc_cursor_hide();
/*CRTC2 functions*/
/*XXX - validate_timing*/
status_t g400_crtc2_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t g400_crtc2_depth(int mode);
status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp);
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp);
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v);
status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v);
/*acceleration functions*/
status_t gx00_acc_init();
status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col);
status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col);
status_t gx00_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 );
status_t gx00_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32);
status_t gx00_acc_wait_idle();
/*backend scaler functions*/
status_t check_overlay_capability(uint32 feature);
status_t gx00_configure_bes(const overlay_buffer *ob, const overlay_window *ow, int offset);
status_t gx00_release_bes();
/*driver structures and enums*/
enum{BPP8=0,BPP15=1,BPP16=2,BPP24=3,BPP32DIR=4,BPP32=7};
enum{DS_CRTCDAC_CRTC2MAVEN, DS_CRTCMAVEN_CRTC2DAC, DS_CRTCDAC_CRTC2DAC2, DS_CRTCDAC_CRTCDAC2};
@@ -0,0 +1,9 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <math.h>
#include <OS.h>
#include "DriverInterface.h"
#include "global.h"
//apsed #include "mga_extern.h"
#include "mga_proto.h"
#include "mga_macros.h"
@@ -0,0 +1,30 @@
/* Some commmon support functions */
/* Mark Watson 2/2000 */
#define MODULE_BIT 0x00000800
#include <stdarg.h>
#include "mga_std.h"
/*delays in multiple of microseconds*/
void delay(bigtime_t i)
{
bigtime_t start=system_time();
while(system_time()-start<i);
}
/*debug logging*/
void mga_log(char *fmt, ...)
{
char buffer[1024];
FILE *myhand;
va_list args;
myhand=fopen("/boot/home/" DRIVER_PREFIX ".accelerant.log","a+");
if (myhand == NULL) return;
va_start(args,fmt);
vsprintf (buffer, fmt, args);
fprintf(myhand, "%s", buffer);
fclose(myhand);
}
+10
View File
@@ -0,0 +1,10 @@
extern int fd;
extern shared_info *si;
extern area_id shared_info_area;
extern area_id regs_area;
extern vuint32 *regs;
extern display_mode *my_mode_list;
extern area_id my_mode_list_area;
extern int accelerantIsClone;
extern gx00_get_set_pci gx00_pci_access;
@@ -0,0 +1,34 @@
/*This file can be used to define custom timing for your monitor
* The format of each line is:
* {
* pixel clock frequency (kHz)
* width
* h-sync pulse start
* h-sync pulse end
* total pixels in line
* height
* v-sync pulse start
* v-sync pulse end
* total lines in frame
* sync polarity (0 is -ve,B_POSITIVE_HYSNC,B_POSITIVE_VSYNC)
* }
*
*To use this you must:
* Uncomment VALID MODE REQUIRED
* Fill in a number of modes that work with your display
* Change VALID MODES from three to the no. you defined
* run these commands:
* touch ProposeDisplayMode.c
* make install
*/
//#define VALID_MODE_REQUIRED 1
#define VALID_MODES 3
/*note colour depth and mode flags are ignored*/
static const display_timing valid_mode_list[] = {
{31500,640,648,744,840,480,481,500,500,0},
{49500,800,808,888,1056,600,601,620,625,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC},
{78750,1024,1032,1128,1312,768,769,788,800,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC}
};