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:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 **)®s, 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);
|
||||
}
|
||||
@@ -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 ;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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}
|
||||
};
|
||||
Reference in New Issue
Block a user