add nvidia accelerant
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5450 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
SubDir OBOS_TOP src add-ons accelerants ;
|
||||
|
||||
SubInclude OBOS_TOP src add-ons accelerants nvidia ;
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
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 2/2003.
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x40000000
|
||||
|
||||
// apsed, TODO ?? change interface of nv_acc_* and use NV 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--)
|
||||
{
|
||||
nv_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++;
|
||||
}
|
||||
}
|
||||
|
||||
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
|
||||
int i;
|
||||
|
||||
/*do each blit*/
|
||||
i=0;
|
||||
while (count--)
|
||||
{
|
||||
nv_acc_video_blit
|
||||
(
|
||||
list[i].src_left,
|
||||
list[i].src_top,
|
||||
list[i].src_width,
|
||||
list[i].src_height,
|
||||
list[i].dest_left,
|
||||
list[i].dest_top,
|
||||
list[i].dest_width,
|
||||
list[i].dest_height
|
||||
);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
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--)
|
||||
{
|
||||
nv_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--)
|
||||
{
|
||||
nv_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--)
|
||||
{
|
||||
nv_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--)
|
||||
{
|
||||
nv_acc_rectangle
|
||||
(
|
||||
list[i+1],
|
||||
list[i+2]+1,
|
||||
list[i],
|
||||
1,
|
||||
colorIndex
|
||||
);
|
||||
i+=3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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 4/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x20000000
|
||||
|
||||
/*DUALHEAD notes -
|
||||
No hardware cursor possible on the secondary head :(
|
||||
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
|
||||
{
|
||||
nv_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*/
|
||||
if (si->dm.flags & DUALHEAD_BITS)
|
||||
{
|
||||
/* fixme???? Nvidia always does pixelprecise panning on sec head?? */
|
||||
switch(si->dm.space)
|
||||
{
|
||||
case B_RGB16_LITTLE:
|
||||
h_adjust = 0x1f;
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
h_adjust = 0x0f;
|
||||
break;
|
||||
default:
|
||||
h_adjust = 0x1f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* switch(si->dm.space)
|
||||
{
|
||||
case B_CMAP8:
|
||||
h_adjust = 0x07;
|
||||
break;
|
||||
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
|
||||
h_adjust = 0x03;
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
h_adjust = 0x01;
|
||||
break;
|
||||
default:
|
||||
h_adjust = 0x07;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
/* Nvidia always does pixelprecise panning on primary head */
|
||||
h_adjust = 0x00;
|
||||
}
|
||||
|
||||
/* adjust h/v_display_start to move cursor onto screen */
|
||||
switch (si->dm.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_SWITCH:
|
||||
if (x >= ((si->dm.timing.h_display * 2) + hds))
|
||||
{
|
||||
hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust;
|
||||
/* make sure we stay within the display! */
|
||||
if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width)
|
||||
hds -= (h_adjust + 1);
|
||||
}
|
||||
else if (x < hds)
|
||||
hds = x & ~h_adjust;
|
||||
break;
|
||||
default:
|
||||
if (x >= (si->dm.timing.h_display + hds))
|
||||
{
|
||||
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
|
||||
/* make sure we stay within the display! */
|
||||
if ((hds + si->dm.timing.h_display) > si->dm.virtual_width)
|
||||
hds -= (h_adjust + 1);
|
||||
}
|
||||
else if (x < hds)
|
||||
hds = x & ~h_adjust;
|
||||
break;
|
||||
}
|
||||
|
||||
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 _and_ the overlay on the display if required */
|
||||
if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
|
||||
{
|
||||
MOVE_DISPLAY(hds,vds);
|
||||
//fixme: implement:
|
||||
//move_overlay(hds,vds);
|
||||
}
|
||||
|
||||
/* put cursor in correct physical position */
|
||||
x -= hds + si->cursor.hot_x;
|
||||
y -= vds + si->cursor.hot_y;
|
||||
|
||||
/* account for switched CRTC's */
|
||||
if (si->switched_crtcs) x -= si->dm.timing.h_display;
|
||||
|
||||
/* position the cursor on the display */
|
||||
nv_crtc_cursor_position(x,y);
|
||||
}
|
||||
|
||||
void SHOW_CURSOR(bool is_visible)
|
||||
{
|
||||
/* record for our info */
|
||||
si->cursor.is_visible = is_visible;
|
||||
|
||||
if (is_visible)
|
||||
nv_crtc_cursor_show();
|
||||
else
|
||||
nv_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 nv_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 = &nv_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;
|
||||
nv_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,241 @@
|
||||
/*
|
||||
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-4/2003
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
/*
|
||||
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 CHKA(x) case B_##x: \
|
||||
if (check_acc_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
|
||||
|
||||
void * get_accelerant_hook(uint32 feature, void *data)
|
||||
{
|
||||
switch (feature)
|
||||
{
|
||||
/*
|
||||
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);
|
||||
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);
|
||||
|
||||
/*
|
||||
Depending on the engine architecture, you may choose to provide a different
|
||||
function to be used with each bit-depth for example.
|
||||
|
||||
Note: These hooks are re-acquired by the app_server after each mode switch.
|
||||
*/
|
||||
|
||||
/* 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.
|
||||
|
||||
Note: These hooks are re-acquired by the app_server after each mode switch.
|
||||
*/
|
||||
|
||||
/* only export 2D acceleration functions in modes that are capable of it */
|
||||
/* used by the app_server and applications (BWindowScreen) */
|
||||
CHKA(SCREEN_TO_SCREEN_BLIT);
|
||||
CHKA(FILL_RECTANGLE);
|
||||
CHKA(INVERT_RECTANGLE);
|
||||
CHKA(FILL_SPAN);
|
||||
/* not (yet) used by the app_server:
|
||||
* so just for application use (BWindowScreen) */
|
||||
CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);
|
||||
//CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
|
||||
}
|
||||
|
||||
/* Return a null pointer for any feature we don't understand. */
|
||||
return 0;
|
||||
}
|
||||
#undef CHKO
|
||||
#undef CHKA
|
||||
#undef HOOK
|
||||
#undef ZERO
|
||||
#undef HRDC
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//temp disabled:
|
||||
if (si->ps.card_type > G550)
|
||||
{
|
||||
/* export video overlay functions */
|
||||
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* do not export video overlay functions */
|
||||
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
status_t check_acc_capability(uint32 feature)
|
||||
{
|
||||
bool fill = false;
|
||||
char *msg = "";
|
||||
|
||||
/* setup logmessage text */
|
||||
switch (feature)
|
||||
{
|
||||
case B_SCREEN_TO_SCREEN_BLIT:
|
||||
msg = "B_SCREEN_TO_SCREEN_BLIT";
|
||||
break;
|
||||
case B_FILL_RECTANGLE:
|
||||
msg = "B_FILL_RECTANGLE";
|
||||
fill = true;
|
||||
break;
|
||||
case B_INVERT_RECTANGLE:
|
||||
msg = "B_INVERT_RECTANGLE";
|
||||
fill = true;
|
||||
break;
|
||||
case B_FILL_SPAN:
|
||||
msg = "B_FILL_SPAN";
|
||||
fill = true;
|
||||
break;
|
||||
case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT:
|
||||
msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT";
|
||||
break;
|
||||
case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT:
|
||||
msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT";
|
||||
break;
|
||||
default:
|
||||
msg = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
/* hardware acceleration is only supported in modes with upto a certain
|
||||
* memory pitch.. */
|
||||
if (si->acc_mode)
|
||||
{
|
||||
/* see if we support hardware rectangle fills in the current mode:
|
||||
* the Matrox card's acc engine can adress upto 16Mbyte memory for this cmd! */
|
||||
if (fill &&
|
||||
((si->fbc.bytes_per_row * si->dm.virtual_height) > (16 * 1024 * 1024)))
|
||||
{
|
||||
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
LOG(4, ("Acc: Exporting hook %s.\n", msg));
|
||||
return B_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -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,"NVG400");
|
||||
|
||||
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-11/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;
|
||||
uint32 min_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)
|
||||
{
|
||||
default:
|
||||
*low = ((si->ps.min_video_vco * 1000) / 16);
|
||||
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)
|
||||
{
|
||||
default:
|
||||
*low = ((si->ps.min_pixel_vco * 1000) / 16);
|
||||
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;
|
||||
}
|
||||
|
||||
/* clamp lower limit to 48Hz vertical refresh for now.
|
||||
* Apparantly the BeOS screenprefs app does limit the upper refreshrate to 90Hz,
|
||||
* while it does not limit the lower refreshrate. */
|
||||
min_pclk = ((uint32)dm->timing.h_total * (uint32)dm->timing.v_total * 48) / 1000;
|
||||
if (min_pclk > *low) *low = min_pclk;
|
||||
|
||||
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;
|
||||
|
||||
nv_get_set_pci nv_pci_access=
|
||||
{
|
||||
NV_PRIVATE_DATA_MAGIC,
|
||||
0,
|
||||
4,
|
||||
0
|
||||
};
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
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-7/2003.
|
||||
*/
|
||||
|
||||
#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;
|
||||
nv_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 = NV_PRIVATE_DATA_MAGIC;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, NV_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, greensync %d\n",
|
||||
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync));
|
||||
|
||||
/*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 = nv_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.
|
||||
Nvidia cursor is 32x32 16 color? takes up 4096 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.
|
||||
*/
|
||||
pointer_reservation = 0;
|
||||
/* Nvidia hardcursor needs 2kB space */
|
||||
if (si->settings.hardcursor) pointer_reservation = 2048;
|
||||
|
||||
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*/
|
||||
nv_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_NV_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) {
|
||||
nv_device_name dn;
|
||||
status_t result;
|
||||
|
||||
/* call the kernel driver to get the device name */
|
||||
dn.magic = NV_PRIVATE_DATA_MAGIC;
|
||||
/* store the returned info directly into the passed buffer */
|
||||
dn.name = (char *)data;
|
||||
result = ioctl(fd, NV_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 */
|
||||
LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
|
||||
|
||||
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)
|
||||
{
|
||||
if (accelerantIsClone)
|
||||
LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
|
||||
else
|
||||
LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
|
||||
|
||||
/*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,648 @@
|
||||
/* Written by Rudolf Cornelissen 05-2002/03-2003 */
|
||||
|
||||
/* 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
|
||||
|
||||
#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... */
|
||||
/* fixme: update needed for DVDmax support to adhere to CRTC2 constraints:
|
||||
* case display_mode == B_RGB16: multiple = 32
|
||||
* case display_mode == B_RGB32: multiple = 16 */
|
||||
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 nv.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 nv.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 */
|
||||
{
|
||||
|
||||
nv_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 */
|
||||
|
||||
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));
|
||||
|
||||
nv_configure_bes(ob, ow, ov, 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,447 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors for NV driver:
|
||||
Mark Watson,
|
||||
Rudolf Cornelissen 9/2002-4/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00400000
|
||||
|
||||
#include "acc_std.h"
|
||||
|
||||
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
|
||||
/* mode flags will be setup as status info by PROPOSEMODE! */
|
||||
#define MODE_FLAGS 0
|
||||
#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) */
|
||||
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
|
||||
{ { 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) */
|
||||
};
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
/* BOUNDS WARNING:
|
||||
* BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
|
||||
* returns B_BAD_VALUE. It's called by the OS with target, low and high set to
|
||||
* have the same settings for BWindowScreen!
|
||||
* Which means we should not return B_BAD_VALUE on anything except for deviations on:
|
||||
* display_mode.virtual_width;
|
||||
* display_mode.virtual_height;
|
||||
* display_mode.timing.h_display;
|
||||
* display_mode.timing.v_display;
|
||||
*/
|
||||
/* Note:
|
||||
* The target mode should be modified to correspond to the mode as it can be made. */
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
float pix_clock_found;
|
||||
uint8 m,n,p;
|
||||
status_t result;
|
||||
uint32 max_vclk, row_bytes, pointer_reservation;
|
||||
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;
|
||||
|
||||
LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
|
||||
target->virtual_width, target->virtual_height));
|
||||
|
||||
/*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;
|
||||
|
||||
LOG(1, ("PROPOSEMODE: valid mode required!\n"));
|
||||
|
||||
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*/
|
||||
{
|
||||
LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
|
||||
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 = nv_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)
|
||||
{
|
||||
LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* nail virtual size and 'subsequently' calculate rowbytes */
|
||||
result = nv_general_validate_pic_size (target, &row_bytes);
|
||||
if (result == B_ERROR)
|
||||
{
|
||||
LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*check if virtual_width is still within the requested limits*/
|
||||
if ((target->virtual_width < low->virtual_width) ||
|
||||
(target->virtual_width > high->virtual_width))
|
||||
{
|
||||
status = B_BAD_VALUE;
|
||||
LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
|
||||
}
|
||||
|
||||
/*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))
|
||||
{
|
||||
/* BWindowScreen workaround: we accept everything except h_display deviations */
|
||||
if ((target->timing.h_display < low->timing.h_display) ||
|
||||
(target->timing.h_display > high->timing.h_display))
|
||||
{
|
||||
status = B_BAD_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = B_OK;
|
||||
}
|
||||
LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
|
||||
}
|
||||
|
||||
/*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) ||
|
||||
(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)
|
||||
)
|
||||
{
|
||||
/* BWindowScreen workaround: we accept everything except v_display deviations */
|
||||
if ((target->timing.v_display < low->timing.v_display) ||
|
||||
(target->timing.v_display > high->timing.v_display))
|
||||
{
|
||||
status = B_BAD_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = B_OK;
|
||||
}
|
||||
LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
/* calculate settings, but do not actually test anything (that costs too much time!) */
|
||||
result = nv_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
|
||||
/* update the target mode */
|
||||
target->timing.pixel_clock = (pix_clock_found * 1000);
|
||||
|
||||
/* note if we fell outside the limits */
|
||||
if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
|
||||
(target->timing.pixel_clock > high->timing.pixel_clock)
|
||||
)
|
||||
{
|
||||
/* BWindowScreen workaround: we accept deviations <= 1Mhz */
|
||||
if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
|
||||
(target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
|
||||
{
|
||||
status = B_BAD_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = B_OK;
|
||||
}
|
||||
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
|
||||
}
|
||||
|
||||
/* checkout space needed for hardcursor (if any) */
|
||||
pointer_reservation = 0;
|
||||
if (si->settings.hardcursor) pointer_reservation = 2048;
|
||||
/* memory requirement for frame buffer */
|
||||
if ((row_bytes * target->virtual_height) >
|
||||
((si->ps.memory_size * 1024 * 1024) - pointer_reservation))
|
||||
{
|
||||
target->virtual_height =
|
||||
((si->ps.memory_size * 1024 * 1024) - pointer_reservation) / row_bytes;
|
||||
}
|
||||
if (target->virtual_height < target->timing.v_display)
|
||||
{
|
||||
LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
|
||||
target->virtual_width, target->virtual_height));
|
||||
|
||||
if ((target->virtual_height < low->virtual_height) ||
|
||||
(target->virtual_height > high->virtual_height))
|
||||
{
|
||||
status = B_BAD_VALUE;
|
||||
LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
|
||||
}
|
||||
|
||||
/* setup status flags */
|
||||
LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
|
||||
/* preset to singlehead card without TVout, no overlay support and no hardcursor.
|
||||
* also advice system that app_server and acc engine may touch the framebuffer
|
||||
* simultaneously (fixed). */
|
||||
target->flags &=
|
||||
~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
|
||||
/* we always allow parallel access (fixed), the DAC is always in 'enhanced'
|
||||
* mode (fixed), and all modes support DPMS (fixed);
|
||||
* We support scrolling and panning in every mode, so we 'send a signal' to
|
||||
* BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
|
||||
//fixme: secondary head does not support DPMS...
|
||||
target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* set DUALHEAD_CAPABLE if suitable */
|
||||
//fixme: update for independant secondary head use! (reserve fixed memory then)
|
||||
if (si->ps.secondary_head &&
|
||||
(((si->ps.memory_size * 1024 * 1024) - pointer_reservation) >=
|
||||
/* note: extra line for maven vblank included here! */
|
||||
(row_bytes * (target->virtual_height + 1) * 2)) &&
|
||||
((target->space == B_RGB16_LITTLE) || (target->space == B_RGB32_LITTLE)) &&
|
||||
(target->timing.pixel_clock <= (max_vclk * 1000)))
|
||||
{
|
||||
target->flags |= DUALHEAD_CAPABLE;
|
||||
}
|
||||
|
||||
/* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
|
||||
//fixme: modify for G100 and G200 TVout later on...
|
||||
if (target->flags & DUALHEAD_CAPABLE)
|
||||
{
|
||||
if (si->ps.tvout &&
|
||||
(target->timing.h_display <= 1024) &&
|
||||
(target->timing.v_display <= 768))
|
||||
{
|
||||
target->flags |= TV_CAPABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* set HARDWARE_CURSOR mode if suitable */
|
||||
if (si->settings.hardcursor)
|
||||
target->flags |= B_HARDWARE_CURSOR;
|
||||
|
||||
/* set SUPPORTS_OVERLAYS */
|
||||
target->flags |= B_SUPPORTS_OVERLAYS;
|
||||
|
||||
LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
|
||||
|
||||
/* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
|
||||
* progressive scan (fixed), and setup sync_on_green flag according to
|
||||
* nv.settings options file */
|
||||
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
|
||||
if (si->settings.greensync)
|
||||
target->timing.flags |= B_SYNC_ON_GREEN;
|
||||
/* The HSYNC and VSYNC command flags are actually executed by the driver. */
|
||||
|
||||
if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
|
||||
else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
|
||||
|
||||
return si->mode_count;
|
||||
}
|
||||
|
||||
/* Copy the list of guaranteed supported video modes to the location provided.*/
|
||||
status_t GET_MODE_LIST(display_mode *dm)
|
||||
{
|
||||
LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
|
||||
|
||||
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("NV 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':
|
||||
* Not true. They might need a wider pitch, but this is _not_ reflected in
|
||||
* virtual_width, but in fbc.bytes_per_row. */
|
||||
//So disable next line:
|
||||
//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 */
|
||||
*dst = *src;
|
||||
/* poke the specific space */
|
||||
dst->space = low.space = high.space = spaces[j];
|
||||
/* ask for a compatible mode */
|
||||
/* We have to check for B_OK, because otherwise the pix_clk_range
|
||||
* won't be taken into account!! */
|
||||
//So don't do this:
|
||||
//if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
|
||||
//Instead, do this:
|
||||
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
|
||||
/* count it, and move on to next mode */
|
||||
dst++;
|
||||
si->mode_count++;
|
||||
}
|
||||
}
|
||||
/* advance to next mode */
|
||||
src++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,633 @@
|
||||
|
||||
/*
|
||||
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 11/2002-7/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00200000
|
||||
|
||||
#include "acc_std.h"
|
||||
|
||||
/*
|
||||
Enable/Disable interrupts. Just a wrapper around the
|
||||
ioctl() to the kernel driver.
|
||||
*/
|
||||
static void interrupt_enable(bool flag) {
|
||||
status_t result;
|
||||
nv_set_bool_state sbs;
|
||||
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
sbs.magic = NV_PRIVATE_DATA_MAGIC;
|
||||
sbs.do_it = flag;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* BOUNDS WARNING:
|
||||
* It's impossible to deviate whatever small amount in a display_mode if the lower
|
||||
* and upper limits are the same!
|
||||
* Besides:
|
||||
* BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
|
||||
* returns B_BAD_VALUE!
|
||||
* Which means PROPOSEMODE should not return that on anything except on
|
||||
* deviations for:
|
||||
* display_mode.virtual_width;
|
||||
* display_mode.virtual_height;
|
||||
* display_mode.timing.h_display;
|
||||
* display_mode.timing.v_display;
|
||||
* So:
|
||||
* We don't use bounds here by making sure bounds and target are the same struct!
|
||||
* (See the call to PROPOSE_DISPLAY_MODE below) */
|
||||
display_mode /*bounds,*/ target;
|
||||
|
||||
uint8 colour_depth1 = 32;
|
||||
status_t result;
|
||||
uint32 startadd,startadd_right;
|
||||
// apsed TODO startadd is 19 bits if < g200
|
||||
|
||||
bool display, h, v;
|
||||
si->switched_crtcs = false;
|
||||
|
||||
/* Adjust mode to valid one and fail if invalid */
|
||||
target /*= bounds*/ = *mode_to_set;
|
||||
/* show the mode bits */
|
||||
LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
|
||||
LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
|
||||
LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
|
||||
target.virtual_width, target.virtual_height));
|
||||
|
||||
/* See BOUNDS WARNING above... */
|
||||
if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
|
||||
|
||||
/* if not dualhead capable card clear dualhead flags */
|
||||
if (!(target.flags & DUALHEAD_CAPABLE))
|
||||
{
|
||||
target.flags &= ~DUALHEAD_BITS;
|
||||
}
|
||||
/* if not TVout capable card clear TVout flags */
|
||||
if (!(target.flags & TV_CAPABLE))
|
||||
{
|
||||
target.flags &= ~TV_BITS;
|
||||
}
|
||||
LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
interrupt_enable(false);
|
||||
|
||||
/* find current DPMS state, then turn off screen(s) */
|
||||
nv_crtc_dpms_fetch(&display, &h, &v);
|
||||
nv_crtc_dpms(false, false, false);
|
||||
// if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
|
||||
|
||||
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
|
||||
startadd = si->fbc.frame_buffer - si->framebuffer;
|
||||
|
||||
/* calculate and set new mode bytes_per_row */
|
||||
nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row);
|
||||
|
||||
/*Perform the very long mode switch!*/
|
||||
if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
|
||||
{
|
||||
uint8 colour_depth2 = colour_depth1;
|
||||
|
||||
/* init display mode for secondary head */
|
||||
display_mode target2 = target;
|
||||
|
||||
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
|
||||
|
||||
/* validate flags for secondary TVout */
|
||||
if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
|
||||
{
|
||||
target.flags &= ~TV_BITS;//still needed for some routines...
|
||||
target2.flags &= ~TV_BITS;
|
||||
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
|
||||
}
|
||||
|
||||
/* set the pixel clock PLL(s) */
|
||||
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
|
||||
if (nv_dac_set_pix_pll(target) == B_ERROR)
|
||||
LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
|
||||
|
||||
/* we do not need to set the pixelclock here for a head that's in TVout mode */
|
||||
if (!(target2.flags & TV_BITS))
|
||||
{
|
||||
LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
|
||||
if (nv_maven_set_vid_pll(target2) == B_ERROR)
|
||||
LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
|
||||
}
|
||||
|
||||
/*set the colour depth for CRTC1 and the DAC */
|
||||
switch(target.space)
|
||||
{
|
||||
case B_RGB16_LITTLE:
|
||||
colour_depth1 = 16;
|
||||
nv_dac_mode(BPP16, 1.0);
|
||||
nv_crtc_depth(BPP16);
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
colour_depth1 = 32;
|
||||
nv_dac_mode(BPP32, 1.0);
|
||||
nv_crtc_depth(BPP32);
|
||||
break;
|
||||
}
|
||||
/*set the colour depth for CRTC2 and the MAVEN */
|
||||
switch(target2.space)
|
||||
{
|
||||
case B_RGB16_LITTLE:
|
||||
colour_depth2 = 16;
|
||||
nv_maven_mode(BPP16, 1.0);
|
||||
g400_crtc2_depth(BPP16);
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
colour_depth2 = 32;
|
||||
nv_maven_mode(BPP32DIR, 1.0);
|
||||
g400_crtc2_depth(BPP32DIR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if we are doing interlaced TVout mode */
|
||||
si->interlaced_tv_mode = false;
|
||||
/* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
|
||||
si->interlaced_tv_mode = true;
|
||||
*/
|
||||
/*set the display(s) pitches*/
|
||||
nv_crtc_set_display_pitch ();
|
||||
//fixme: seperate for real dualhead modes:
|
||||
//we need a secondary si->fbc!
|
||||
g400_crtc2_set_display_pitch ();
|
||||
|
||||
/*work out where the "right" screen starts*/
|
||||
startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3));
|
||||
|
||||
/* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */
|
||||
si->crtc_delay = 44 + 0 * (colour_depth2 == 16);
|
||||
|
||||
/* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */
|
||||
/* (extra "blanking" line for MAVEN) */
|
||||
target2.timing.v_display++;
|
||||
|
||||
/* set the outputs */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
case NV11:
|
||||
switch (target.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_CLONE:
|
||||
nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
|
||||
si->switched_crtcs = false;
|
||||
break;
|
||||
case DUALHEAD_SWITCH:
|
||||
if (i2c_sec_tv_adapter() == B_OK)
|
||||
{
|
||||
/* Don't switch CRTC's because MAVEN YUV is impossible then,
|
||||
* and primary head output will be limited to 135Mhz pixelclock. */
|
||||
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
|
||||
nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
|
||||
si->switched_crtcs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This limits the pixelclocks on both heads to 135Mhz,
|
||||
* but you can use overlay on the other output now. */
|
||||
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
|
||||
nv_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC);
|
||||
si->switched_crtcs = false;
|
||||
/* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
|
||||
si->crtc_delay = 17 + 4 * (colour_depth1 == 16);
|
||||
/* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */
|
||||
/* (extra "blanking" line for MAVEN) */
|
||||
target.timing.v_display++;
|
||||
target2.timing.v_display--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
//fixme:
|
||||
//setup crtc_delay and vertical timing adjust for G450(?)/G550,
|
||||
//and remove the '+1' in crtc2 vertical timing(?)
|
||||
case NV17:
|
||||
if (!si->ps.primary_dvi)
|
||||
/* output connector use is always 'straight-through' */
|
||||
//fixme: re-evaluate when DVI is setup...
|
||||
{
|
||||
switch (target.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_CLONE:
|
||||
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
si->switched_crtcs = false;
|
||||
break;
|
||||
case DUALHEAD_SWITCH:
|
||||
if (i2c_sec_tv_adapter() == B_OK)
|
||||
{
|
||||
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
|
||||
* and primary head output will be limited to 235Mhz pixelclock. */
|
||||
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
|
||||
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
si->switched_crtcs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This limits the pixelclocks on both heads to 235Mhz,
|
||||
* but you can use overlay on the other output now. */
|
||||
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
|
||||
nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
|
||||
si->switched_crtcs = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* output connector use is cross-linked if no TV cable connected! */
|
||||
//fixme: re-evaluate when DVI is setup...
|
||||
{
|
||||
switch (target.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_CLONE:
|
||||
if (i2c_sec_tv_adapter() == B_OK)
|
||||
{
|
||||
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
si->switched_crtcs = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This limits the pixelclocks on both heads to 235Mhz,
|
||||
* but you can use overlay on the other output now. */
|
||||
nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
|
||||
si->switched_crtcs = false;
|
||||
}
|
||||
break;
|
||||
case DUALHEAD_SWITCH:
|
||||
if (i2c_sec_tv_adapter() == B_OK)
|
||||
{
|
||||
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
|
||||
* and primary head output will be limited to 235Mhz pixelclock. */
|
||||
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
|
||||
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
si->switched_crtcs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
|
||||
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
si->switched_crtcs = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (si->switched_crtcs)
|
||||
{
|
||||
uint32 temp = startadd;
|
||||
startadd = startadd_right;
|
||||
startadd_right = temp;
|
||||
}
|
||||
|
||||
/*Tell card what memory to display*/
|
||||
switch (target.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_SWITCH:
|
||||
nv_crtc_set_display_start(startadd,colour_depth1);
|
||||
g400_crtc2_set_display_start(startadd_right,colour_depth2);
|
||||
break;
|
||||
case DUALHEAD_CLONE:
|
||||
nv_crtc_set_display_start(startadd,colour_depth1);
|
||||
g400_crtc2_set_display_start(startadd,colour_depth2);
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the timing */
|
||||
nv_crtc_set_timing(target);
|
||||
/* we do not need to setup CRTC2 here for a head that's in TVout mode */
|
||||
if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2);
|
||||
|
||||
/* TVout support: setup CRTC2 and it's pixelclock */
|
||||
if (si->ps.tvout && (target2.flags & TV_BITS))
|
||||
{
|
||||
si->crtc_delay += 5;
|
||||
maventv_init(target2);
|
||||
}
|
||||
}
|
||||
else /* single head mode */
|
||||
{
|
||||
status_t status;
|
||||
int colour_mode = BPP32;
|
||||
|
||||
switch(target.space)
|
||||
{
|
||||
case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
|
||||
case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
|
||||
case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
|
||||
case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
|
||||
default:
|
||||
LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* set the pixel clock PLL */
|
||||
status = nv_dac_set_pix_pll(target);
|
||||
|
||||
if (status==B_ERROR)
|
||||
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
|
||||
|
||||
/* set the colour depth for CRTC1 and the DAC */
|
||||
/* first set the colordepth */
|
||||
nv_crtc_depth(colour_mode);
|
||||
/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
|
||||
nv_dac_mode(colour_mode,1.0);
|
||||
|
||||
/* set the display pitch */
|
||||
nv_crtc_set_display_pitch();
|
||||
|
||||
/* tell the card what memory to display */
|
||||
nv_crtc_set_display_start(startadd,colour_depth1);
|
||||
|
||||
/* enable primary analog output */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
case NV11:
|
||||
// nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
|
||||
break;
|
||||
case NV17:
|
||||
// nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
|
||||
// gx50_general_output_select();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the timing */
|
||||
nv_crtc_set_timing(target);
|
||||
|
||||
//fixme: shut-off the videoPLL if it exists...
|
||||
}
|
||||
|
||||
/* update driver's mode store */
|
||||
si->dm = target;
|
||||
|
||||
/* turn screen one on */
|
||||
nv_crtc_dpms(display, h, v);
|
||||
/* turn screen two on if a dualhead mode is active */
|
||||
// if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v);
|
||||
|
||||
/* set up acceleration for this mode */
|
||||
si->dm.virtual_height += 1;//for clipping!
|
||||
// nv_acc_init();
|
||||
si->dm.virtual_height -= 1;
|
||||
|
||||
/* clear line at bottom of screen (for maven) if dualhead mode */
|
||||
// nv_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0);
|
||||
|
||||
MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0));
|
||||
|
||||
/* enable interrupts using the kernel driver */
|
||||
interrupt_enable(true);
|
||||
|
||||
/* optimize memory-access if needed */
|
||||
// nv_crtc_mem_priority(colour_depth1);
|
||||
|
||||
/* Tune RAM CAS-latency if needed. Must be done *here*! */
|
||||
nv_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));
|
||||
|
||||
/* reset lower bits, don't return an error! */
|
||||
//fixme: not needed in dualhead on Nvidia??? (pixelprecise panning on sec. head??)
|
||||
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
|
||||
{
|
||||
/* Nvidia always does pixelprecise panning on primary head */
|
||||
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 */
|
||||
switch (si->dm.flags & DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_SWITCH:
|
||||
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
|
||||
return B_ERROR;
|
||||
break;
|
||||
default:
|
||||
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
|
||||
return B_ERROR;
|
||||
break;
|
||||
}
|
||||
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 */
|
||||
//fixme: seperate both heads: we need a secondary si->fbc!
|
||||
startadd = v_display_start * si->fbc.bytes_per_row;
|
||||
startadd += h_display_start * (colour_depth >> 3);
|
||||
startadd += si->fbc.frame_buffer - si->framebuffer;
|
||||
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
|
||||
|
||||
/* account for switched CRTC's */
|
||||
if (si->switched_crtcs)
|
||||
{
|
||||
uint32 temp = startadd;
|
||||
startadd = startadd_right;
|
||||
startadd_right = temp;
|
||||
}
|
||||
|
||||
interrupt_enable(false);
|
||||
|
||||
switch (si->dm.flags&DUALHEAD_BITS)
|
||||
{
|
||||
case DUALHEAD_ON:
|
||||
case DUALHEAD_SWITCH:
|
||||
nv_crtc_set_display_start(startadd,colour_depth);
|
||||
g400_crtc2_set_display_start(startadd_right,colour_depth);
|
||||
break;
|
||||
case DUALHEAD_OFF:
|
||||
nv_crtc_set_display_start(startadd,colour_depth);
|
||||
break;
|
||||
case DUALHEAD_CLONE:
|
||||
nv_crtc_set_display_start(startadd,colour_depth);
|
||||
g400_crtc2_set_display_start(startadd,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++;
|
||||
}
|
||||
nv_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, display on */
|
||||
nv_crtc_dpms(true, true, true);
|
||||
if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1);
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
nv_crtc_dpms(false, false, true);
|
||||
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1);
|
||||
break;
|
||||
case B_DPMS_SUSPEND:
|
||||
nv_crtc_dpms(false, true, false);
|
||||
if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0);
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
nv_crtc_dpms(false, false, false);
|
||||
if (si->ps.secondary_head) g400_crtc2_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, display on */
|
||||
nv_crtc_dpms(true, true, true);
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
nv_crtc_dpms(false, false, true);
|
||||
break;
|
||||
case B_DPMS_SUSPEND:
|
||||
nv_crtc_dpms(false, true, false);
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
nv_crtc_dpms(false, false, false);
|
||||
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) {
|
||||
bool display, h, v;
|
||||
|
||||
interrupt_enable(false);
|
||||
nv_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 "nv_extern.h"
|
||||
#include "nv_proto.h"
|
||||
#include "be_driver_proto.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
/* NV Acceleration functions */
|
||||
/* Authors:
|
||||
Mark Watson 2/2000,
|
||||
Rudolf Cornelissen 10/2002-4/2003.
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00080000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
/*acceleration notes*/
|
||||
|
||||
/*functions Be's app_server uses:
|
||||
fill span (horizontal only)
|
||||
fill rectangle (these 2 are very similar)
|
||||
invert rectangle
|
||||
blit
|
||||
*/
|
||||
|
||||
/* G100 pre SRCORG/DSTORG registers */
|
||||
static uint32 src_dst;
|
||||
/* MIL1/2 adress linearisation does not always work */
|
||||
static uint8 y_lin;
|
||||
static uint8 depth;
|
||||
|
||||
/* needed by MIL 1/2 because of adress linearisation constraints */
|
||||
#define ACCW_YDSTLEN(dst, len) do { \
|
||||
if (y_lin) { \
|
||||
ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \
|
||||
ACCW(LEN,len); \
|
||||
} else ACCW(YDSTLEN,((dst)<<16)|(len)); \
|
||||
} while (0)
|
||||
|
||||
status_t nv_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.
|
||||
* Engine required init. */
|
||||
status_t nv_acc_init()
|
||||
{
|
||||
/* used for convenience: MACCESS is a write only register! */
|
||||
uint32 maccess = 0x00000000;
|
||||
/* if we were unable to read PINS, we have to assume something (keeping bit6 zero) */
|
||||
// if ((si->ps.card_type >= G450) && (si->ps.pins_status = B_OK))
|
||||
// {
|
||||
/* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */
|
||||
// maccess |= ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1);
|
||||
// }
|
||||
|
||||
/* preset using hardware adress linearisation */
|
||||
y_lin = 0x00;
|
||||
/* reset depth */
|
||||
depth = 0;
|
||||
|
||||
/* cleanup bitblt */
|
||||
ACCW(OPMODE,0);
|
||||
|
||||
/* Set the Z origin to the start of FB (otherwise lockup on blits) */
|
||||
ACCW(ZORG,0);
|
||||
|
||||
/* Set pixel width */
|
||||
switch(si->dm.space)
|
||||
{
|
||||
case B_CMAP8:
|
||||
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00));
|
||||
depth = 8;
|
||||
break;
|
||||
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
|
||||
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01));
|
||||
depth = 16;
|
||||
break;
|
||||
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
|
||||
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02));
|
||||
depth = 32;
|
||||
break;
|
||||
default:
|
||||
LOG(8,("ACC: init, invalid bit depth\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* setup PITCH: very cardtype specific! */
|
||||
/* switch (si->ps.card_type)
|
||||
{
|
||||
case MIL1:
|
||||
switch (si->fbc.bytes_per_row / (depth >> 3))
|
||||
{
|
||||
case 640:
|
||||
case 768:
|
||||
case 800:
|
||||
case 960:
|
||||
case 1024:
|
||||
case 1152:
|
||||
case 1280:
|
||||
case 1600:
|
||||
case 1920:
|
||||
case 2048:
|
||||
*/ /* we are using hardware adress linearisation */
|
||||
/* break;
|
||||
default:
|
||||
*/ /* we are using software adress linearisation */
|
||||
/* y_lin = 0x01;
|
||||
LOG(8,("ACC: using software adress linearisation\n"));
|
||||
break;
|
||||
}
|
||||
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
|
||||
break;
|
||||
case MIL2:
|
||||
switch (si->fbc.bytes_per_row / (depth >> 3))
|
||||
{
|
||||
case 512:
|
||||
case 640:
|
||||
case 768:
|
||||
case 800:
|
||||
case 832:
|
||||
case 960:
|
||||
case 1024:
|
||||
case 1152:
|
||||
case 1280:
|
||||
case 1600:
|
||||
case 1664:
|
||||
case 1920:
|
||||
case 2048:
|
||||
*/ /* we are using hardware adress linearisation */
|
||||
/* break;
|
||||
default:
|
||||
*/ /* we are using software adress linearisation */
|
||||
/* y_lin = 0x01;
|
||||
LOG(8,("ACC: using software adress linearisation\n"));
|
||||
break;
|
||||
}
|
||||
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
|
||||
break;
|
||||
case G100:
|
||||
*/ /* always using hardware adress linearisation, because 2D/3D
|
||||
* engine works on every pitch multiple of 32 */
|
||||
/* ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
|
||||
break;
|
||||
default:
|
||||
*/ /* G200 and up are equal.. */
|
||||
/* always using hardware adress linearisation, because 2D/3D
|
||||
* engine works on every pitch multiple of 32 */
|
||||
/* ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF));
|
||||
break;
|
||||
}
|
||||
*/
|
||||
/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
|
||||
ACCW(PLNWT,0x00000000);
|
||||
ACCW(PLNWT,0xffffffff);
|
||||
|
||||
// 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));
|
||||
// }
|
||||
|
||||
/* init YDSTORG - apsed, if not inited, BitBlts may fails on <= G200 */
|
||||
src_dst = 0;
|
||||
ACCW(YDSTORG, src_dst);
|
||||
|
||||
/* <= G100 uses this register as SRCORG/DSTORG replacement, but
|
||||
* MIL 1/2 does not need framebuffer space for the hardcursor! */
|
||||
/* 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 */
|
||||
/* i.e. highest and lowest X pixel adresses */
|
||||
ACCW(CXBNDRY,(((si->fbc.bytes_per_row / (depth >> 3)) - 1) << 16) | (0));
|
||||
|
||||
/* Y pixel addresses must be linear */
|
||||
/* lowest adress */
|
||||
ACCW(YTOP, 0 + src_dst);
|
||||
/* highest adress */
|
||||
ACCW(YBOT,((si->dm.virtual_height - 1) *
|
||||
(si->fbc.bytes_per_row / (depth >> 3))) + src_dst);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* screen to screen blit - i.e. move windows around.
|
||||
* Engine function bitblit, paragraph 4.5.7.2 */
|
||||
status_t nv_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->fbc.bytes_per_row / (depth >> 3));
|
||||
|
||||
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;
|
||||
|
||||
/* sgnzero bit _must_ be '0' before accessing SGN! */
|
||||
ACCW(DWGCTL,0x00000000);
|
||||
|
||||
/*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); // atype RSTR
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* screen to screen tranparent blit - not sure what uses this.
|
||||
* Engine function bitblit, paragraph 4.5.7.2 */
|
||||
status_t nv_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->fbc.bytes_per_row / (depth >> 3));
|
||||
|
||||
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;
|
||||
|
||||
/* sgnzero bit _must_ be '0' before accessing SGN! */
|
||||
ACCW(DWGCTL,0x00000000);
|
||||
|
||||
/*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); // atype RSTR
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* rectangle fill.
|
||||
* Engine function rectangle_fill: paragraph 4.5.5.2 */
|
||||
/*colorIndex,fill_rect_params,count*/
|
||||
status_t nv_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*/
|
||||
|
||||
//acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode
|
||||
// for other functions, and use fastblt on MIL1/2 if possible...
|
||||
//or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?)
|
||||
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.
|
||||
* Engine function rectangle_fill: paragraph 4.5.5.2 */
|
||||
/*colorIndex,fill_rect_params,count*/
|
||||
status_t nv_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*/
|
||||
|
||||
/*draw it! top nibble is c is clipping enabled*/
|
||||
ACCGO(DWGCTL,0x40057814); // atype RSTR
|
||||
|
||||
/*pseudo_dma version!*/
|
||||
//NVACC_DWGCTL =0x1C00,
|
||||
//NVACC_FCOL =0x1C24,
|
||||
//NVACC_FXBNDRY =0x1C84,
|
||||
//NVACC_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;
|
||||
}
|
||||
|
||||
/* screen to screen scaled filtered blit - i.e. scale video in memory.
|
||||
* Engine function texture mapping for video, paragraphs 4.5.5.5 - 4.5.5.9 */
|
||||
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
|
||||
uint16 xd,uint16 yd,uint16 wd,uint16 hd)
|
||||
{
|
||||
//fixme: implement. Used for G450/G550 Desktop TVout...
|
||||
//fixme: see if MIL1 - G200 support this function as well...
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,699 @@
|
||||
/* G200-G550 Back End Scaler functions */
|
||||
/* Written by Rudolf Cornelissen 05/2002-04/2003 */
|
||||
|
||||
#define MODULE_BIT 0x00000200
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
//fixme: implement: (used for virtual screens!)
|
||||
//void move_overlay(uint16 hdisp_start, uint16 vdisp_start);
|
||||
|
||||
status_t nv_configure_bes
|
||||
(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, 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 and DANO:
|
||||
* '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. */
|
||||
|
||||
/* 'ov' is the view in the source bitmap, so which part of the bitmap is actually
|
||||
* displayed on screen. This is used for the 'hardware zoom' function. */
|
||||
|
||||
/* calculated BES register values */
|
||||
uint32 hcoordv, vcoordv, hiscalv, hsrcstv, hsrcendv, hsrclstv,
|
||||
viscalv, a1orgv, v1wghtv, v1srclstv, globctlv, ctlv;
|
||||
/* misc used variables */
|
||||
uint16 temp1, temp2;
|
||||
/* interval representation, used for scaling calculations */
|
||||
uint16 intrep, crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
|
||||
/* inverse scaling factor, used for source positioning */
|
||||
uint32 ifactor;
|
||||
/* used for vertical weight starting value */
|
||||
uint32 weight;
|
||||
/* copy of overlay view which has checked valid values */
|
||||
overlay_view my_ov;
|
||||
|
||||
/* 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"));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
*** copy, check and limit if needed the user-specified view into the intput bitmap ***
|
||||
**************************************************************************************/
|
||||
my_ov = *ov;
|
||||
/* check for valid 'coordinates' */
|
||||
if (my_ov.width == 0) my_ov.width++;
|
||||
if (my_ov.height == 0) my_ov.height++;
|
||||
if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
|
||||
my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
|
||||
if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
|
||||
my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
|
||||
if (my_ov.v_start > (ob->height - 1))
|
||||
my_ov.v_start = (ob->height - 1);
|
||||
if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
|
||||
my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
|
||||
|
||||
LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
|
||||
my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
|
||||
|
||||
/* the BES does not respect virtual_workspaces, but adheres to CRTC
|
||||
* constraints only */
|
||||
crtc_hstart = si->dm.h_display_start;
|
||||
/* make dualhead switch mode with TVout enabled work while we're at it.. */
|
||||
if (si->switched_crtcs)
|
||||
{
|
||||
crtc_hstart += si->dm.timing.h_display;
|
||||
}
|
||||
/* horizontal end is the first position beyond the displayed range on the CRTC */
|
||||
crtc_hend = crtc_hstart + si->dm.timing.h_display;
|
||||
crtc_vstart = si->dm.v_display_start;
|
||||
/* vertical end is the first position beyond the displayed range on the CRTC */
|
||||
crtc_vend = crtc_vstart + si->dm.timing.v_display;
|
||||
|
||||
|
||||
/****************************************
|
||||
*** setup all edges of output window ***
|
||||
****************************************/
|
||||
|
||||
/* setup left and right edges of output window */
|
||||
hcoordv = 0;
|
||||
/* left edge coordinate of output window, must be inside desktop */
|
||||
/* clipping on the left side */
|
||||
if (ow->h_start < crtc_hstart)
|
||||
{
|
||||
temp1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clipping on the right side */
|
||||
if (ow->h_start >= (crtc_hend - 1))
|
||||
{
|
||||
/* width < 2 is not allowed */
|
||||
temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
|
||||
}
|
||||
else
|
||||
/* no clipping here */
|
||||
{
|
||||
temp1 = (ow->h_start - crtc_hstart) & 0x7ff;
|
||||
}
|
||||
}
|
||||
hcoordv |= 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) > (crtc_hend - 1))
|
||||
{
|
||||
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clipping on the left side */
|
||||
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
|
||||
{
|
||||
/* width < 2 is not allowed */
|
||||
temp2 = 1;
|
||||
}
|
||||
else
|
||||
/* no clipping here */
|
||||
{
|
||||
temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1)) & 0x7ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
hcoordv |= temp2 << 0;
|
||||
LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
|
||||
|
||||
/* setup top and bottom edges of output window */
|
||||
vcoordv = 0;
|
||||
/* top edge coordinate of output window, must be inside desktop */
|
||||
/* clipping on the top side */
|
||||
if (ow->v_start < crtc_vstart)
|
||||
{
|
||||
temp1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clipping on the bottom side */
|
||||
if (ow->v_start >= (crtc_vend - 1))
|
||||
{
|
||||
/* height < 2 is not allowed */
|
||||
temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
|
||||
}
|
||||
else
|
||||
/* no clipping here */
|
||||
{
|
||||
temp1 = (ow->v_start - crtc_vstart) & 0x7ff;
|
||||
}
|
||||
}
|
||||
vcoordv |= 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) > (crtc_vend - 1))
|
||||
{
|
||||
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clipping on the top side */
|
||||
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
|
||||
{
|
||||
/* height < 2 is not allowed */
|
||||
temp2 = 1;
|
||||
}
|
||||
else
|
||||
/* no clipping here */
|
||||
{
|
||||
temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1)) & 0x7ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
vcoordv |= temp2 << 0;
|
||||
LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
|
||||
|
||||
|
||||
/*********************************************
|
||||
*** setup horizontal scaling and clipping ***
|
||||
*********************************************/
|
||||
|
||||
LOG(6,("Overlay: total input picture width = %d, height = %d\n",
|
||||
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
|
||||
LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
|
||||
|
||||
/* do horizontal scaling... */
|
||||
/* determine interval representation value, taking zoom into account */
|
||||
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
|
||||
{
|
||||
/* horizontal filtering is ON */
|
||||
if ((my_ov.width == 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 < my_ov.width) & (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, taking zoom into account */
|
||||
/* standard scaling formula: */
|
||||
ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep);
|
||||
|
||||
/* correct factor to prevent most-right visible 'line' from distorting */
|
||||
ifactor -= (1 << 2);
|
||||
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
|
||||
|
||||
/* compensate for accelerated 2x zoom (slowdown BES if pixelclock is too high) */
|
||||
hiscalv = ifactor * acczoom;
|
||||
LOG(4,("Overlay: horizontal speed compensated factor is %f\n", (float)65536 / hiscalv));
|
||||
|
||||
/* check scaling factor (and modify if needed) to be within scaling limits */
|
||||
if (((((uint32)my_ov.width) << 16) / 16384) > hiscalv)
|
||||
{
|
||||
/* (non-inverse) factor too large, set factor to max. valid value */
|
||||
hiscalv = ((((uint32)my_ov.width) << 16) / 16384);
|
||||
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv));
|
||||
}
|
||||
if (hiscalv >= (32 << 16))
|
||||
{
|
||||
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||
hiscalv = 0x1ffffc;
|
||||
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
|
||||
}
|
||||
/* AND below is required by hardware */
|
||||
hiscalv &= 0x001ffffc;
|
||||
|
||||
|
||||
/* 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.
|
||||
* Then add the left starting position of the bitmap's view (zoom function) to get the final value needed.
|
||||
* Note: 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.! */
|
||||
hsrcstv = 0;
|
||||
/* check for destination horizontal clipping at left side */
|
||||
if (ow->h_start < crtc_hstart)
|
||||
{
|
||||
/* check if entire destination picture is clipping left:
|
||||
* (2 pixels will be clamped onscreen at least) */
|
||||
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
|
||||
{
|
||||
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
|
||||
hsrcstv += (ow->width - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
|
||||
hsrcstv += (crtc_hstart - 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! */
|
||||
hsrcstv *= ifactor;
|
||||
}
|
||||
/* take zoom into account */
|
||||
hsrcstv += ((uint32)my_ov.h_start) << 16;
|
||||
/* AND below required by hardware */
|
||||
hsrcstv &= 0x03fffffc;
|
||||
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", hsrcstv / (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.
|
||||
* Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */
|
||||
/* Note also:
|
||||
* Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
|
||||
|
||||
hsrcendv = 0;
|
||||
/* check for destination horizontal clipping at right side */
|
||||
if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
|
||||
{
|
||||
/* check if entire destination picture is clipping right:
|
||||
* (2 pixels will be clamped onscreen at least) */
|
||||
if (ow->h_start > (crtc_hend - 2))
|
||||
{
|
||||
/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
|
||||
hsrcendv += (ow->width - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
|
||||
hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 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! */
|
||||
hsrcendv *= ifactor;
|
||||
/* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */
|
||||
hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16) - hsrcendv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */
|
||||
hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16);
|
||||
}
|
||||
/* AND below required by hardware */
|
||||
hsrcendv &= 0x03fffffc;
|
||||
LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", hsrcendv / (float)65536));
|
||||
|
||||
|
||||
/* setup horizontal source last position excluding slopspace:
|
||||
* this is the last pixel that will be used for calculating interpolated pixels */
|
||||
hsrclstv = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16;
|
||||
/* AND below required by hardware */
|
||||
hsrclstv &= 0x03ff0000;
|
||||
|
||||
|
||||
/*******************************************
|
||||
*** setup vertical scaling and clipping ***
|
||||
*******************************************/
|
||||
|
||||
/* do vertical scaling... */
|
||||
/* determine interval representation value, taking zoom into account */
|
||||
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
|
||||
{
|
||||
/* vertical filtering is ON */
|
||||
if ((my_ov.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 < my_ov.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, taking zoom into account */
|
||||
/* standard scaling formula: */
|
||||
ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep);
|
||||
|
||||
/* correct factor to prevent lowest visible line from distorting */
|
||||
ifactor -= (1 << 2);
|
||||
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor));
|
||||
|
||||
/* preserve ifactor for source positioning calculations later on */
|
||||
viscalv = ifactor;
|
||||
|
||||
/* check scaling factor (and modify if needed) to be within scaling limits */
|
||||
if (((((uint32)my_ov.height) << 16) / 16384) > viscalv)
|
||||
{
|
||||
/* (non-inverse) factor too large, set factor to max. valid value */
|
||||
viscalv = ((((uint32)my_ov.height) << 16) / 16384);
|
||||
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv));
|
||||
}
|
||||
if (viscalv >= (32 << 16))
|
||||
{
|
||||
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||
viscalv = 0x1ffffc;
|
||||
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
|
||||
}
|
||||
/* AND below is required by hardware */
|
||||
viscalv &= 0x001ffffc;
|
||||
|
||||
|
||||
/* 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 (and zoom) 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.
|
||||
* Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */
|
||||
/* 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;
|
||||
a1orgv = (uint32)((vuint32 *)ob->buffer);
|
||||
a1orgv -= (uint32)((vuint32 *)si->framebuffer);
|
||||
/* calculate origin adress */
|
||||
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv));
|
||||
/* check for destination vertical clipping at top side */
|
||||
if (ow->v_start < crtc_vstart)
|
||||
{
|
||||
/* check if entire destination picture is clipping at top:
|
||||
* (2 pixels will be clamped onscreen at least) */
|
||||
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 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 */
|
||||
a1orgv += ((((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 */
|
||||
a1orgv += ((((crtc_vstart - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
|
||||
weight = (crtc_vstart - ow->v_start) * ifactor;
|
||||
}
|
||||
LOG(4,("Overlay: clipping at top...\n"));
|
||||
}
|
||||
/* take zoom into account */
|
||||
a1orgv += (my_ov.v_start * ob->bytes_per_row);
|
||||
weight += (((uint32)my_ov.v_start) << 16);
|
||||
LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n",a1orgv));
|
||||
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", weight / (float)65536));
|
||||
|
||||
/* Note:
|
||||
* Because all > G200 overlay units will ignore b0-3 of the calculated adress,
|
||||
* we do not use the above way for horizontal source positioning.
|
||||
* (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 all > G200 cards, while G200 cards
|
||||
* will have 4 source-image pixel jumps occuring. */
|
||||
|
||||
/* AND below is required by G200-G550 hardware. > G200 cards can have max. 32Mb RAM on board
|
||||
* (16Mb on G200 cards). Compatible setting used (between G200 and the rest), this has no
|
||||
* downside consequences here. */
|
||||
/* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */
|
||||
a1orgv &= 0x01fffff0;
|
||||
|
||||
/* field 1 weight: AND below required by hardware, also make sure 'sign' is always 'positive' */
|
||||
v1wghtv = weight & 0x0000fffc;
|
||||
|
||||
|
||||
/* setup field 1 (is our complete frame) vertical source last position.
|
||||
* this is the last pixel that will be used for calculating interpolated pixels */
|
||||
v1srclstv = (ob->height - 1);
|
||||
/* AND below required by hardware */
|
||||
v1srclstv &= 0x000003ff;
|
||||
|
||||
|
||||
/*****************************
|
||||
*** log color keying info ***
|
||||
*****************************/
|
||||
|
||||
LOG(6,("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(6,("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 BES control ***
|
||||
*************************/
|
||||
|
||||
/* BES global control: setup functions */
|
||||
globctlv = 0;
|
||||
|
||||
/* slowdown BES if nessesary */
|
||||
if (acczoom == 1)
|
||||
{
|
||||
/* run at full speed and resolution */
|
||||
globctlv |= 0 << 0;
|
||||
/* disable filtering for half speed interpolation */
|
||||
globctlv |= 0 << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* run at half speed and resolution */
|
||||
globctlv |= 1 << 0;
|
||||
/* enable filtering for half speed interpolation */
|
||||
globctlv |= 1 << 1;
|
||||
}
|
||||
|
||||
/* 4:2:0 specific setup: not needed here */
|
||||
globctlv |= 0 << 3;
|
||||
/* BES testregister: keep zero */
|
||||
globctlv |= 0 << 4;
|
||||
/* the following bits marked (> G200) *must* be zero on G200: */
|
||||
/* 4:2:0 specific setup: not needed here (> G200) */
|
||||
globctlv |= 0 << 5;
|
||||
/* select yuy2 byte-order to B_YCbCr422 (> G200) */
|
||||
globctlv |= 0 << 6;
|
||||
/* BES internal contrast and brighness controls are not used, disabled (> G200) */
|
||||
globctlv |= 0 << 7;
|
||||
/* RGB specific setup: not needed here, so disabled (> G200) */
|
||||
globctlv |= 0 << 8;
|
||||
globctlv |= 0 << 9;
|
||||
/* 4:2:0 specific setup: not needed here (> G200) */
|
||||
globctlv |= 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. */
|
||||
globctlv |= 0x000 << 16;
|
||||
|
||||
/* BES control: enable scaler and setup functions */
|
||||
/* pre-reset all bits */
|
||||
ctlv = 0;
|
||||
/* enable BES */
|
||||
ctlv |= 1 << 0;
|
||||
/* we start displaying at an even startline (zero) in 'field 1' (no hardware de-interlacing is used) */
|
||||
ctlv |= 0 << 6;
|
||||
/* we don't use field 2, so its startline is not important */
|
||||
ctlv |= 0 << 7;
|
||||
|
||||
LOG(6,("Overlay: ow->flags is $%08x\n",ow->flags));
|
||||
/* enable horizontal filtering on scaling if asked for: if we *are* actually scaling */
|
||||
if ((ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) && (hiscalv != (0x01 << 16)))
|
||||
{
|
||||
ctlv |= 1 << 10;
|
||||
LOG(6,("Overlay: using horizontal interpolation on scaling\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ctlv |= 0 << 10;
|
||||
LOG(6,("Overlay: using horizontal dropping or replication on scaling\n"));
|
||||
}
|
||||
/* enable vertical filtering on scaling if asked for: if we are *upscaling* only */
|
||||
if ((ow->flags & B_OVERLAY_VERTICAL_FILTERING) && (viscalv < (0x01 << 16)))
|
||||
{
|
||||
ctlv |= 1 << 11;
|
||||
LOG(6,("Overlay: using vertical interpolation on scaling\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ctlv |= 0 << 11;
|
||||
LOG(6,("Overlay: using vertical dropping or replication on scaling\n"));
|
||||
}
|
||||
|
||||
/* use actual calculated weight for horizontal interpolation */
|
||||
ctlv |= 0 << 12;
|
||||
/* use horizontal chroma interpolation upsampling on BES input picture */
|
||||
ctlv |= 1 << 16;
|
||||
/* select 4:2:2 BES input format */
|
||||
ctlv |= 0 << 17;
|
||||
/* dithering is enabled */
|
||||
ctlv |= 1 << 18;
|
||||
/* horizontal mirroring is not used */
|
||||
ctlv |= 0 << 19;
|
||||
/* BES output should be in color */
|
||||
ctlv |= 0 << 20;
|
||||
/* BES output blanking is disabled: we want a picture, no 'black box'! */
|
||||
ctlv |= 0 << 21;
|
||||
/* we do software field select (field select is not used) */
|
||||
ctlv |= 0 << 24;
|
||||
/* we always display field 1 in buffer A, this contains our full frames */
|
||||
/* select field 1 */
|
||||
ctlv |= 0 << 25;
|
||||
/* select buffer A */
|
||||
ctlv |= 0 << 26;
|
||||
|
||||
|
||||
/*************************************
|
||||
*** 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). */
|
||||
|
||||
LOG(3,("Overlay: starting register programming beyond Vcount %d\n", CR1R(VCOUNT)));
|
||||
/* Even at 1600x1200x90Hz, a single line still takes about 9uS to complete:
|
||||
* this resolution will generate about 180Mhz pixelclock while we can do
|
||||
* upto 360Mhz. So snooze about 4uS to prevent bus-congestion...
|
||||
* Appr. 200 lines time will provide enough room even on a 100Mhz CPU if it's
|
||||
* screen is set to the highest refreshrate/resolution possible. */
|
||||
while (CR1R(VCOUNT) > (si->dm.timing.v_total - 200)) snooze(4);
|
||||
|
||||
|
||||
/**************************************
|
||||
*** actually program the registers ***
|
||||
**************************************/
|
||||
|
||||
BESW(HCOORD, hcoordv);
|
||||
BESW(VCOORD, vcoordv);
|
||||
BESW(HISCAL, hiscalv);
|
||||
BESW(HSRCST, hsrcstv);
|
||||
BESW(HSRCEND, hsrcendv);
|
||||
BESW(HSRCLST, hsrclstv);
|
||||
BESW(VISCAL, viscalv);
|
||||
BESW(A1ORG, a1orgv);
|
||||
BESW(V1WGHT, v1wghtv);
|
||||
BESW(V1SRCLST, v1srclstv);
|
||||
BESW(GLOBCTL, globctlv);
|
||||
BESW(CTL, ctlv);
|
||||
|
||||
|
||||
/**************************
|
||||
*** setup color keying ***
|
||||
**************************/
|
||||
|
||||
/* 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); AND is required by hardware */
|
||||
BESW(PITCH, (ob->width & 0x00000fff));
|
||||
|
||||
/* on a 500Mhz P3 CPU just logging a line costs 400uS (18-19 vcounts at 1024x768x60Hz)!
|
||||
* programming the registers above actually costs 180uS here */
|
||||
LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_release_bes()
|
||||
{
|
||||
/* setup BES control: disable scaler */
|
||||
BESW(CTL, 0x00000000);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/* CTRC functionality */
|
||||
/* Author:
|
||||
Rudolf Cornelissen 11/2002-7/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00040000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
/*Adjust passed parameters to a valid mode line*/
|
||||
status_t nv_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 */
|
||||
*hd_e &= 0xfff8;
|
||||
*hs_s &= 0xfff8;
|
||||
*hs_e &= 0xfff8;
|
||||
*ht &= 0xfff8;
|
||||
|
||||
/* confine to required number of bits, taking logic into account */
|
||||
if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
|
||||
if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
|
||||
if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3);
|
||||
if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3);
|
||||
|
||||
/* NOTE: keep horizontal timing at multiples of 8! */
|
||||
/* confine to a reasonable width */
|
||||
if (*hd_e < 640) *hd_e = 640;
|
||||
if (si->ps.card_type > NV04)
|
||||
{
|
||||
if (*hd_e > 2048) *hd_e = 2048;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*hd_e > 1920) *hd_e = 1920;
|
||||
}
|
||||
|
||||
/* if hor. 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 - 8)) *hs_e = (*ht - 8);
|
||||
if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
|
||||
|
||||
/* correct sync pulse if it is too long:
|
||||
* there are only 5 bits available to save this in the card registers! */
|
||||
if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
|
||||
|
||||
/*vertical*/
|
||||
/* confine to required number of bits, taking logic into account */
|
||||
if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
|
||||
if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
|
||||
if (*vs_e > 0x7ff ) *vs_e = 0x7ff ;
|
||||
if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2);
|
||||
|
||||
/* confine to a reasonable height */
|
||||
if (*vd_e < 480) *vd_e = 480;
|
||||
if (si->ps.card_type > NV04)
|
||||
{
|
||||
if (*vd_e > 1536) *vd_e = 1536;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*vd_e > 1440) *vd_e = 1440;
|
||||
}
|
||||
|
||||
/*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 is 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:
|
||||
* there are only 4 bits available to save this in the card registers! */
|
||||
if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*set a mode line - inputs are in pixels*/
|
||||
status_t nv_crtc_set_timing(display_mode target)
|
||||
{
|
||||
uint8 temp;
|
||||
|
||||
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 standard VGA */
|
||||
htotal = ((target.timing.h_total >> 3) - 5);
|
||||
hdisp_e = ((target.timing.h_display >> 3) - 1);
|
||||
hblnk_s = hdisp_e;
|
||||
hblnk_e = (htotal + 4);//0;
|
||||
hsync_s = (target.timing.h_sync_start >> 3);
|
||||
hsync_e = (target.timing.h_sync_end >> 3);
|
||||
|
||||
vtotal = target.timing.v_total - 2;
|
||||
vdisp_e = target.timing.v_display - 1;
|
||||
vblnk_s = vdisp_e;
|
||||
vblnk_e = (vtotal + 1);
|
||||
vsync_s = target.timing.v_sync_start;//-1;
|
||||
vsync_e = target.timing.v_sync_end;//-1;
|
||||
|
||||
/* prevent memory adress counter from being reset (linecomp may not occur) */
|
||||
linecomp = target.timing.v_display;
|
||||
|
||||
//fixme: flatpanel 'don't touch' update needed for 'Go' cards!?!
|
||||
if (true)
|
||||
{
|
||||
LOG(4,("CRTC: CRT only mode, setting full timing...\n"));
|
||||
|
||||
/* log the mode that will be set */
|
||||
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! */
|
||||
/* unlock CRTC registers at index 0-7 */
|
||||
CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f));
|
||||
/* horizontal standard VGA regs */
|
||||
CRTCW(HTOTAL, (htotal & 0xff));
|
||||
CRTCW(HDISPE, (hdisp_e & 0xff));
|
||||
CRTCW(HBLANKS, (hblnk_s & 0xff));
|
||||
/* also unlock vertical retrace registers in advance */
|
||||
CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
|
||||
CRTCW(HSYNCS, (hsync_s & 0xff));
|
||||
CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
|
||||
|
||||
/* vertical standard VGA regs */
|
||||
CRTCW(VTOTAL, (vtotal & 0xff));
|
||||
CRTCW(OVERFLOW,
|
||||
(
|
||||
((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))
|
||||
));
|
||||
CRTCW(PRROWSCN, 0x00); /* not used */
|
||||
CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
|
||||
CRTCW(VSYNCS, (vsync_s & 0xff));
|
||||
CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
|
||||
CRTCW(VDISPE, (vdisp_e & 0xff));
|
||||
CRTCW(VBLANKS, (vblnk_s & 0xff));
|
||||
CRTCW(VBLANKE, (vblnk_e & 0xff));
|
||||
CRTCW(LINECOMP, (linecomp & 0xff));
|
||||
|
||||
/* horizontal extended regs */
|
||||
//fixme: we reset bit4. is this correct??
|
||||
CRTCW(HEB, (CRTCR(HEB) & 0xe0) |
|
||||
(
|
||||
((htotal & 0x100) >> (8 - 0)) |
|
||||
((hdisp_e & 0x100) >> (8 - 1)) |
|
||||
((hblnk_s & 0x100) >> (8 - 2)) |
|
||||
((hsync_s & 0x100) >> (8 - 3))
|
||||
));
|
||||
|
||||
/* (mostly) vertical extended regs */
|
||||
CRTCW(LSR,
|
||||
(
|
||||
((vtotal & 0x400) >> (10 - 0)) |
|
||||
((vdisp_e & 0x400) >> (10 - 1)) |
|
||||
((vsync_s & 0x400) >> (10 - 2)) |
|
||||
((vblnk_s & 0x400) >> (10 - 3)) |
|
||||
((hblnk_e & 0x040) >> (6 - 4))
|
||||
//fixme: we still miss one linecomp bit!?! is this it??
|
||||
//| ((linecomp & 0x400) >> 3)
|
||||
));
|
||||
|
||||
/* setup 'large screen' mode */
|
||||
if (target.timing.h_display >= 1280)
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb));
|
||||
else
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04));
|
||||
|
||||
/* setup HSYNC & VSYNC polarity */
|
||||
LOG(2,("CRTC: sync polarity: "));
|
||||
temp = NV_REG8(NV8_MISCR);
|
||||
if (target.timing.flags & B_POSITIVE_HSYNC)
|
||||
{
|
||||
LOG(2,("H:pos "));
|
||||
temp &= ~0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(2,("H:neg "));
|
||||
temp |= 0x40;
|
||||
}
|
||||
if (target.timing.flags & B_POSITIVE_VSYNC)
|
||||
{
|
||||
LOG(2,("V:pos "));
|
||||
temp &= ~0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(2,("V:neg "));
|
||||
temp |= 0x80;
|
||||
}
|
||||
NV_REG8(NV8_MISCW) = temp;
|
||||
|
||||
LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_depth(int mode)
|
||||
{
|
||||
uint8 viddelay = 0;
|
||||
uint32 genctrl = 0;
|
||||
|
||||
/* set VCLK scaling */
|
||||
switch(mode)
|
||||
{
|
||||
case BPP8:
|
||||
viddelay = 0x01;
|
||||
/* genctrl b4 & b5 reset: 'direct mode' */
|
||||
genctrl = 0x00101100;
|
||||
break;
|
||||
case BPP15:
|
||||
viddelay = 0x02;
|
||||
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
|
||||
genctrl = 0x00100130;
|
||||
break;
|
||||
case BPP16:
|
||||
viddelay = 0x02;
|
||||
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
|
||||
genctrl = 0x00101130;
|
||||
break;
|
||||
case BPP24:
|
||||
viddelay = 0x03;
|
||||
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
|
||||
genctrl = 0x00100130;
|
||||
break;
|
||||
case BPP32:
|
||||
viddelay = 0x03;
|
||||
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
|
||||
genctrl = 0x00101130;
|
||||
break;
|
||||
}
|
||||
CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay));
|
||||
DACW(GENCTRL, genctrl);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_dpms(bool display, bool h, bool v)
|
||||
{
|
||||
uint8 temp;
|
||||
|
||||
LOG(4,("CRTC: setting DPMS: "));
|
||||
|
||||
/* start synchronous reset: required before turning screen off! */
|
||||
SEQW(RESET, 0x01);
|
||||
|
||||
/* turn screen off */
|
||||
temp = SEQR(CLKMODE);
|
||||
if (display)
|
||||
{
|
||||
SEQW(CLKMODE, (temp & ~0x20));
|
||||
|
||||
/* end synchronous reset if display should be enabled */
|
||||
SEQW(RESET, 0x03);
|
||||
|
||||
LOG(4,("display on, "));
|
||||
}
|
||||
else
|
||||
{
|
||||
SEQW(CLKMODE, (temp | 0x20));
|
||||
|
||||
LOG(4,("display off, "));
|
||||
}
|
||||
|
||||
if (h)
|
||||
{
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f));
|
||||
LOG(4,("hsync enabled, "));
|
||||
}
|
||||
else
|
||||
{
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80));
|
||||
LOG(4,("hsync disabled, "));
|
||||
}
|
||||
if (v)
|
||||
{
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf));
|
||||
LOG(4,("vsync enabled\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40));
|
||||
LOG(4,("vsync disabled\n"));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v)
|
||||
{
|
||||
*display = !(SEQR(CLKMODE) & 0x20);
|
||||
*h = !(CRTCR(REPAINT1) & 0x80);
|
||||
*v = !(CRTCR(REPAINT1) & 0x40);
|
||||
|
||||
LOG(4,("CTRC: fetched DPMS state:"));
|
||||
if (display) LOG(4,("display on, "));
|
||||
else LOG(4,("display off, "));
|
||||
if (h) LOG(4,("hsync enabled, "));
|
||||
else LOG(4,("hsync disabled, "));
|
||||
if (v) LOG(4,("vsync enabled\n"));
|
||||
else LOG(4,("vsync disabled\n"));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_set_display_pitch()
|
||||
{
|
||||
uint32 offset;
|
||||
|
||||
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
|
||||
|
||||
/* figure out offset value hardware needs */
|
||||
offset = si->fbc.bytes_per_row / 8;
|
||||
|
||||
LOG(2,("CRTC: offset register set to: $%04x\n", offset));
|
||||
|
||||
/*program the card!*/
|
||||
CRTCW(PITCHL, (offset & 0x00ff));
|
||||
CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp)
|
||||
{
|
||||
uint8 temp;
|
||||
|
||||
LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
|
||||
|
||||
LOG(2,("CRTC: startadd: $%08x\n", startadd));
|
||||
LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer));
|
||||
LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer));
|
||||
|
||||
//fixme? on TNT1, TNT2, and GF2MX400 not needed. How about the rest??
|
||||
/* make sure we are in retrace on MIL cards (if possible), because otherwise
|
||||
* distortions might occur during our reprogramming them (no double buffering) */
|
||||
// if (si->ps.card_type < G100)
|
||||
// {
|
||||
/* we might have no retraces during setmode! */
|
||||
// uint32 timeout = 0;
|
||||
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
|
||||
// while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4)))
|
||||
// {
|
||||
// snooze(4);
|
||||
// timeout++;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (si->ps.card_arch == NV04A)
|
||||
{
|
||||
/* upto 32Mb RAM adressing: must be used this way on pre-NV10! */
|
||||
|
||||
/* set standard registers */
|
||||
/* (NVidia: startadress in 32bit words (b2 - b17) */
|
||||
CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2));
|
||||
CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10));
|
||||
|
||||
/* set extended registers */
|
||||
/* NV4 extended bits: (b18-22) */
|
||||
temp = (CRTCR(REPAINT0) & 0xe0);
|
||||
CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18)));
|
||||
/* NV4 extended bits: (b23-24) */
|
||||
temp = (CRTCR(HEB) & 0x9f);
|
||||
CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
|
||||
/* NOTE:
|
||||
* While this register also exists on pre-NV10 cards, it will
|
||||
* wrap-around at 16Mb boundaries!! */
|
||||
|
||||
/* 30bit adress in 32bit words */
|
||||
NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc);
|
||||
}
|
||||
|
||||
/* set NV4/NV10 byte adress: (b0 - 1) */
|
||||
temp = (ATBR(HORPIXPAN) & 0xf9);
|
||||
ATBW(HORPIXPAN, (temp | ((startadd & 0x00000003) << 1)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_cursor_init()
|
||||
{
|
||||
int i;
|
||||
uint32 * fb;
|
||||
/* cursor bitmap will be stored at the start of the framebuffer */
|
||||
const uint32 curadd = 0;
|
||||
|
||||
/* set cursor bitmap adress ... */
|
||||
if (si->ps.card_arch == NV04A)
|
||||
{
|
||||
/* must be used this way on pre-NV10! */
|
||||
|
||||
/* cursorbitmap must start on 2Kbyte boundary: */
|
||||
/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
|
||||
CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9));
|
||||
/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
|
||||
CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
|
||||
/* set adress bit24-31 */
|
||||
CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
|
||||
/* NOTE:
|
||||
* This register does not exist on pre-NV10 cards. */
|
||||
|
||||
/* cursorbitmap must still start on 2Kbyte boundary: */
|
||||
NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800);
|
||||
}
|
||||
|
||||
/* set cursor colour: not needed because of direct nature of cursor bitmap. */
|
||||
|
||||
/*clear cursor*/
|
||||
fb = (uint32 *) si->framebuffer + curadd;
|
||||
for (i=0;i<(2048/4);i++)
|
||||
{
|
||||
fb[i]=0;
|
||||
}
|
||||
|
||||
/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
|
||||
NV_REG32(NV32_CURCONF) = 0x02000100;
|
||||
|
||||
/* activate hardware cursor */
|
||||
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_cursor_show()
|
||||
{
|
||||
/* b0 = 1 enables cursor */
|
||||
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t nv_crtc_cursor_hide()
|
||||
{
|
||||
/* b0 = 0 disables cursor */
|
||||
CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*set up cursor shape*/
|
||||
status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask)
|
||||
{
|
||||
int x, y;
|
||||
uint8 b;
|
||||
uint16 *cursor;
|
||||
uint16 pixel;
|
||||
|
||||
/* get a pointer to the cursor */
|
||||
cursor = (uint16*) si->framebuffer;
|
||||
|
||||
/* draw the cursor */
|
||||
/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
|
||||
for (y = 0; y < 16; y++)
|
||||
{
|
||||
b = 0x80;
|
||||
for (x = 0; x < 8; x++)
|
||||
{
|
||||
/* preset transparant */
|
||||
pixel = 0x0000;
|
||||
/* set white if requested */
|
||||
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
|
||||
/* set black if requested */
|
||||
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
|
||||
/* set invert if requested */
|
||||
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
|
||||
/* place the pixel in the bitmap */
|
||||
cursor[x + (y * 32)] = pixel;
|
||||
b >>= 1;
|
||||
}
|
||||
xorMask++;
|
||||
andMask++;
|
||||
b = 0x80;
|
||||
for (; x < 16; x++)
|
||||
{
|
||||
/* preset transparant */
|
||||
pixel = 0x0000;
|
||||
/* set white if requested */
|
||||
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
|
||||
/* set black if requested */
|
||||
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
|
||||
/* set invert if requested */
|
||||
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
|
||||
/* place the pixel in the bitmap */
|
||||
cursor[x + (y * 32)] = pixel;
|
||||
b >>= 1;
|
||||
}
|
||||
xorMask++;
|
||||
andMask++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*position the cursor*/
|
||||
status_t nv_crtc_cursor_position(uint16 x ,uint16 y)
|
||||
{
|
||||
/* make sure we are not in retrace, because the register(s) might get copied
|
||||
* during our reprogramming them (double buffering feature) */
|
||||
//fixme if needed...
|
||||
/* while (ACCR(STATUS) & 0x08)
|
||||
{
|
||||
snooze(4);
|
||||
}
|
||||
*/
|
||||
|
||||
DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/* second CTRC functionality
|
||||
|
||||
Authors:
|
||||
Mark Watson 6/2000,
|
||||
Rudolf Cornelissen 12/2002 - 4/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00020000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
/*set a mode line - inputs are in pixels/scanlines*/
|
||||
status_t g400_crtc2_set_timing(display_mode target)
|
||||
{
|
||||
uint32 temp;
|
||||
|
||||
LOG(4,("CRTC2: setting timing\n"));
|
||||
|
||||
// if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX))
|
||||
{
|
||||
/* G450/G550 monitor mode, and all modes on older cards */
|
||||
|
||||
/* check horizontal timing parameters are to nearest 8 pixels */
|
||||
if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) |
|
||||
(target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07))
|
||||
{
|
||||
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* make sure NTSC clock killer circuitry is disabled */
|
||||
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
|
||||
|
||||
/* make sure CRTC2 is set to progressive scan for monitor mode */
|
||||
CR2W(CTL, (CR2R(CTL) & ~0x02001000));
|
||||
|
||||
/* program the second CRTC */
|
||||
CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) |
|
||||
((target.timing.h_total - 8) & 0x0fff)));
|
||||
CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) |
|
||||
((target.timing.h_sync_start - 8) & 0x0fff)));
|
||||
CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) |
|
||||
((target.timing.v_total - 1) & 0x0fff)));
|
||||
CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) |
|
||||
((target.timing.v_sync_start - 1) & 0x0fff)));
|
||||
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
|
||||
//CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) |
|
||||
// (target.timing.h_sync_start & 0x0fff)));
|
||||
CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) |
|
||||
((target.timing.h_sync_start - 8) & 0x0fff)));
|
||||
|
||||
temp = (0xfff << 16);
|
||||
if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
|
||||
if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
|
||||
CR2W(MISC, temp);
|
||||
|
||||
/* On <= G400MAX dualhead cards we need to send a copy to the MAVEN;
|
||||
* unless TVout is active */
|
||||
if ((si->ps.secondary_head) && (!(target.flags & TV_BITS)))
|
||||
nv_maven_set_timing(target);
|
||||
}
|
||||
// else
|
||||
{
|
||||
/* G450/G550 TVout mode */
|
||||
display_mode tv_mode = target;
|
||||
uint8 frame;
|
||||
unsigned int vcount, prev_vcount;
|
||||
|
||||
LOG(4,("CRTC2: setting up G450/G550 TVout mode\n"));
|
||||
|
||||
/* check horizontal timing parameters are to nearest 8 pixels */
|
||||
if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) |
|
||||
(tv_mode.timing.h_sync_end & 0x07))
|
||||
{
|
||||
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* disable NTSC clock killer circuitry */
|
||||
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
|
||||
|
||||
if (tv_mode.timing.h_total & 0x07)
|
||||
{
|
||||
/* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */
|
||||
LOG(4,("CRTC2: enabling clock killer circuitry\n"));
|
||||
CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010));
|
||||
}
|
||||
|
||||
/* make sure h_total is valid for TVout mode */
|
||||
tv_mode.timing.h_total &= ~0x07;
|
||||
|
||||
/* modify tv_mode for interlaced use */
|
||||
tv_mode.timing.v_display >>= 1;
|
||||
tv_mode.timing.v_sync_start >>= 1;
|
||||
tv_mode.timing.v_sync_end >>= 1;
|
||||
tv_mode.timing.v_total >>= 1;
|
||||
|
||||
/*program the second CRTC*/
|
||||
CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) |
|
||||
((tv_mode.timing.h_total - 8) & 0x0fff)));
|
||||
CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) |
|
||||
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
|
||||
CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) |
|
||||
((tv_mode.timing.v_total - 1) & 0x0fff)));
|
||||
CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) |
|
||||
((tv_mode.timing.v_sync_start - 1) & 0x0fff)));
|
||||
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
|
||||
//CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) |
|
||||
// (tv_mode.timing.h_sync_start & 0x0fff)));
|
||||
CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) |
|
||||
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
|
||||
|
||||
/* set CRTC2 to interlaced mode:
|
||||
* First enable progressive scan mode while making sure
|
||||
* CRTC2 is setup for TVout mode use... */
|
||||
CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000));
|
||||
/* now synchronize to the start of a frame... */
|
||||
prev_vcount = 0;
|
||||
for (frame = 0; frame < 2; frame++)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
vcount = (CR2R(VCOUNT) & 0x00000fff);
|
||||
if (vcount >= prev_vcount)
|
||||
prev_vcount = vcount;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* and start interlaced mode now! */
|
||||
CR2W(CTL, (CR2R(CTL) | 0x02000000));
|
||||
|
||||
temp = (0xfff << 16);
|
||||
if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
|
||||
if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
|
||||
CR2W(MISC, temp);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t g400_crtc2_depth(int mode)
|
||||
{
|
||||
/* validate bit depth and set mode */
|
||||
/* also clears TVout mode (b12) */
|
||||
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)
|
||||
{
|
||||
if (display & h & v)
|
||||
{
|
||||
/* enable CRTC2 and don't touch the rest */
|
||||
CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disable CRTC2 and don't touch the rest */
|
||||
CR2W(CTL, (CR2R(CTL) & 0xFFF0177E));
|
||||
}
|
||||
|
||||
// if (si->ps.card_type >= G450)
|
||||
// {
|
||||
//fixme:
|
||||
/* setup monitor mode DPMS: G450 and later fully support this on CRTC2 */
|
||||
//for now:
|
||||
//enable 'straight-through' sync outputs on both analog output connectors...
|
||||
// DXIW(SYNCCTRL,0x00);
|
||||
// }
|
||||
|
||||
/* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */
|
||||
if (si->ps.secondary_head) nv_maven_dpms(display, h, v);
|
||||
|
||||
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 offset;
|
||||
|
||||
LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
|
||||
|
||||
/* figure out offset value hardware needs */
|
||||
offset = si->fbc.bytes_per_row;
|
||||
if (si->interlaced_tv_mode)
|
||||
{
|
||||
LOG(4,("CRTC2: setting interlaced mode\n"));
|
||||
/* double the CRTC2 linelength so fields are displayed instead of frames */
|
||||
offset *= 2;
|
||||
}
|
||||
else
|
||||
LOG(4,("CRTC2: setting progressive scan mode\n"));
|
||||
|
||||
LOG(2,("CRTC2: offset set to %d bytes\n", offset));
|
||||
|
||||
/* program the head */
|
||||
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 for %d bits per pixel\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));
|
||||
|
||||
if (si->interlaced_tv_mode)
|
||||
{
|
||||
LOG(4,("CRTC2: setting up fields for interlaced mode\n"));
|
||||
/* program the head for interlaced use */
|
||||
//fixme: seperate both heads: we need a secondary si->fbc!
|
||||
/* setup field 0 startadress in buffer to read picture's odd lines */
|
||||
CR2W(STARTADD0, (startadd + si->fbc.bytes_per_row));
|
||||
/* setup field 1 startadress in buffer to read picture's even lines */
|
||||
CR2W(STARTADD1, startadd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("CRTC2: setting up frames for progressive scan mode\n"));
|
||||
/* program the head for non-interlaced use */
|
||||
CR2W(STARTADD0, startadd);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
/* program the DAC */
|
||||
/* Author:
|
||||
Rudolf Cornelissen 7/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00010000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
static status_t nv4_nv10_nv20_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 nv_dac_mode(int mode,float brightness)
|
||||
{
|
||||
uint8 *r,*g,*b;
|
||||
int i, ri;
|
||||
|
||||
/*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 the palette for brightness specified */
|
||||
/* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
ri = i * brightness;
|
||||
if (ri > 255) ri = 255;
|
||||
b[i] = g[i] = r[i] = ri;
|
||||
}
|
||||
|
||||
if (nv_dac_palette(r,g,b) != B_OK) return B_ERROR;
|
||||
|
||||
/*set the mode - also sets VCLK dividor*/
|
||||
// DXIW(MULCTRL, mode);
|
||||
// LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL)));
|
||||
|
||||
/* disable palette RAM adressing mask */
|
||||
NV_REG8(NV8_PALMASK) = 0xff;
|
||||
LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PALMASK)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*program the DAC palette using the given r,g,b values*/
|
||||
status_t nv_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256])
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG(4,("DAC: setting palette\n"));
|
||||
|
||||
/* select first PAL adress before starting programming */
|
||||
NV_REG8(NV8_PALINDW) = 0x00;
|
||||
|
||||
/* loop through all 256 to program DAC */
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
/* the 6 implemented bits are on b0-b5 of the bus */
|
||||
NV_REG8(NV8_PALDATA) = r[i];
|
||||
NV_REG8(NV8_PALDATA) = g[i];
|
||||
NV_REG8(NV8_PALDATA) = b[i];
|
||||
}
|
||||
if (NV_REG8(NV8_PALINDW) != 0x00)
|
||||
{
|
||||
LOG(8,("DAC: PAL write index incorrect after programming\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
if (1)
|
||||
{//reread LUT
|
||||
uint8 R, G, B;
|
||||
|
||||
/* select first PAL adress to read (modulo 3 counter) */
|
||||
NV_REG8(NV8_PALINDR) = 0x00;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
R = NV_REG8(NV8_PALDATA);
|
||||
G = NV_REG8(NV8_PALDATA);
|
||||
B = NV_REG8(NV8_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:
|
||||
* PIXPLLC is used - others should be kept as is
|
||||
* BESCLK,CRTC2 are not touched
|
||||
*/
|
||||
status_t nv_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));
|
||||
|
||||
/* signal that we actually want to set the mode */
|
||||
result = nv_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*/
|
||||
|
||||
/* select pixelPLL registerset C */
|
||||
DACW(PLLSEL, 0x10000700);
|
||||
|
||||
/* program new frequency */
|
||||
DACW(PIXPLLC, ((p << 16) | (n << 8) | m));
|
||||
|
||||
/* Wait for the PIXPLL frequency to lock until timeout occurs */
|
||||
//fixme: do NV cards have a LOCK indication bit??
|
||||
/* 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
|
||||
*/
|
||||
|
||||
//for now:
|
||||
/* Give the PIXPLL frequency some time to lock... */
|
||||
snooze(1000);
|
||||
LOG(2,("DAC: PIX PLL frequency should be locked now...\n"));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* find nearest valid pix pll */
|
||||
status_t nv_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) {
|
||||
default: return nv4_nv10_nv20_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* find nearest valid pixel PLL setting */
|
||||
static status_t nv4_nv10_nv20_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, 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;
|
||||
}
|
||||
*/
|
||||
LOG(4,("DAC: NV4/NV10/NV20 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))
|
||||
{
|
||||
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
|
||||
req_pclk, (float)(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)
|
||||
{
|
||||
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
|
||||
req_pclk, (float)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 = 7; m <= 14; m++)
|
||||
{
|
||||
/* check if phase-discriminator will be within operational limits */
|
||||
if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue;
|
||||
|
||||
/* calculate VCO postscaler setting for current setup.. */
|
||||
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
|
||||
/* ..and check for validity */
|
||||
if ((n < 1) || (n > 255)) 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];
|
||||
n = best[1];
|
||||
p = best[2];
|
||||
|
||||
/* log the VCO frequency found */
|
||||
f_vco = ((si->ps.f_ref / m) * n);
|
||||
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
|
||||
|
||||
/* return the results */
|
||||
*calc_pclk = (f_vco / p);
|
||||
*m_result = m;
|
||||
*n_result = n;
|
||||
switch(p)
|
||||
{
|
||||
case 1:
|
||||
p = 0x00;
|
||||
break;
|
||||
case 2:
|
||||
p = 0x01;
|
||||
break;
|
||||
case 4:
|
||||
p = 0x02;
|
||||
break;
|
||||
case 8:
|
||||
p = 0x03;
|
||||
break;
|
||||
case 16:
|
||||
p = 0x04;
|
||||
break;
|
||||
}
|
||||
*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))
|
||||
{
|
||||
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
|
||||
req_sclk, (float)(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)
|
||||
{
|
||||
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
|
||||
req_sclk, (float)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)
|
||||
{
|
||||
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 g400_dac_set_sys_pll()
|
||||
{
|
||||
/* values for DAC sys pll registers */
|
||||
uint8 m, n, p;
|
||||
// uint time = 0;
|
||||
float calc_sclk;
|
||||
|
||||
LOG(1,("DAC: Setting up G400/G400MAX system clock\n"));
|
||||
g100_g400max_dac_sys_pll_find((float)si->ps.std_engine_clock, &calc_sclk, &m, &n, &p);
|
||||
|
||||
/* reprogram the clock - set PCI/AGP, program, set to programmed */
|
||||
/* clear, so don't o/clock addons */
|
||||
// CFGW(OPTION2, 0);
|
||||
/* disable the SYSPLL */
|
||||
// CFGW(OPTION, CFGR(OPTION) | 0x04);
|
||||
/* select the PCI/AGP clock */
|
||||
// CFGW(OPTION3, 0);
|
||||
/* 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 Wclk divs via PINS and select SYSPLL as system clock source */
|
||||
// CFGW(OPTION3, si->ps.option3_reg);
|
||||
/* make sure the PLLs are not swapped (set default config) */
|
||||
// CFGW(OPTION, CFGR(OPTION) & 0xffffffbf);
|
||||
/* enable the SYSPLL (and make sure the SYSPLL is indeed powered up) */
|
||||
// CFGW(OPTION, (CFGR(OPTION) & 0xfffffffb) | 0x20);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,963 @@
|
||||
/* Authors:
|
||||
Mark Watson 12/1999,
|
||||
Apsed,
|
||||
Rudolf Cornelissen 10/2002-7/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00008000
|
||||
|
||||
#include "nv_std.h"
|
||||
//apsed #include "memory"
|
||||
|
||||
status_t test_ram();
|
||||
static status_t nvxx_general_powerup (void);
|
||||
static status_t nv_general_bios_to_powergraphics(void);
|
||||
|
||||
static void nv_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", \
|
||||
NVCFG_##reg, #reg, value)); \
|
||||
} while (0)
|
||||
DUMP_CFG (DEVID, 0);
|
||||
DUMP_CFG (DEVCTRL, 0);
|
||||
DUMP_CFG (CLASS, 0);
|
||||
DUMP_CFG (HEADER, 0);
|
||||
DUMP_CFG (BASE1REGS,0);
|
||||
DUMP_CFG (BASE2FB, 0);
|
||||
DUMP_CFG (BASE3, 0);
|
||||
DUMP_CFG (BASE4, 0);
|
||||
DUMP_CFG (BASE5, 0);
|
||||
DUMP_CFG (BASE6, 0);
|
||||
DUMP_CFG (BASE7, 0);
|
||||
DUMP_CFG (SUBSYSID1,0);
|
||||
DUMP_CFG (ROMBASE, 0);
|
||||
DUMP_CFG (CFG_0, 0);
|
||||
DUMP_CFG (CFG_1, 0);
|
||||
DUMP_CFG (INTERRUPT,0);
|
||||
DUMP_CFG (SUBSYSID2,0);
|
||||
DUMP_CFG (AGPREF, 0);
|
||||
DUMP_CFG (AGPSTAT, 0);
|
||||
DUMP_CFG (AGPCMD, 0);
|
||||
DUMP_CFG (ROMSHADOW,0);
|
||||
DUMP_CFG (VGA, 0);
|
||||
DUMP_CFG (SCHRATCH, 0);
|
||||
DUMP_CFG (CFG_10, 0);
|
||||
DUMP_CFG (CFG_11, 0);
|
||||
DUMP_CFG (CFG_12, 0);
|
||||
DUMP_CFG (CFG_13, 0);
|
||||
DUMP_CFG (CFG_14, 0);
|
||||
DUMP_CFG (CFG_15, 0);
|
||||
DUMP_CFG (CFG_16, 0);
|
||||
DUMP_CFG (CFG_17, 0);
|
||||
DUMP_CFG (GF2IGPU, 0);
|
||||
DUMP_CFG (CFG_19, 0);
|
||||
DUMP_CFG (GF4MXIGPU,0);
|
||||
DUMP_CFG (CFG_21, 0);
|
||||
DUMP_CFG (CFG_22, 0);
|
||||
DUMP_CFG (CFG_23, 0);
|
||||
DUMP_CFG (CFG_24, 0);
|
||||
DUMP_CFG (CFG_25, 0);
|
||||
DUMP_CFG (CFG_26, 0);
|
||||
DUMP_CFG (CFG_27, 0);
|
||||
DUMP_CFG (CFG_28, 0);
|
||||
DUMP_CFG (CFG_29, 0);
|
||||
DUMP_CFG (CFG_30, 0);
|
||||
DUMP_CFG (CFG_41, 0);
|
||||
DUMP_CFG (CFG_42, 0);
|
||||
DUMP_CFG (CFG_43, 0);
|
||||
DUMP_CFG (CFG_44, 0);
|
||||
DUMP_CFG (CFG_45, 0);
|
||||
DUMP_CFG (CFG_46, 0);
|
||||
DUMP_CFG (CFG_47, 0);
|
||||
DUMP_CFG (CFG_48, 0);
|
||||
DUMP_CFG (CFG_49, 0);
|
||||
DUMP_CFG (CFG_50, 0);
|
||||
#undef DUMP_CFG
|
||||
}
|
||||
|
||||
status_t nv_general_powerup()
|
||||
{
|
||||
status_t status;
|
||||
|
||||
LOG(1,("POWERUP: nVidia (open)BeOS Accelerant 0.02 running.\n"));
|
||||
|
||||
/* preset no laptop */
|
||||
si->ps.laptop = false;
|
||||
|
||||
/* detect card type and power it up */
|
||||
switch(CFGR(DEVID))
|
||||
{
|
||||
/* Vendor Nvidia */
|
||||
case 0x002010de: /* Nvidia TNT1 */
|
||||
si->ps.card_type = NV04;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia TNT1 (NV04)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002810de: /* Nvidia TNT2 (pro) */
|
||||
case 0x002910de: /* Nvidia TNT2 Ultra */
|
||||
case 0x002a10de: /* Nvidia TNT2 */
|
||||
case 0x002b10de: /* Nvidia TNT2 */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia TNT2 (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002c10de: /* Nvidia Vanta (Lt) */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Vanta (Lt) (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002d10de: /* Nvidia TNT2-M64 (Pro) */
|
||||
si->ps.card_type = NV05M64;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia TNT2-M64 (Pro) (NV05M64)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002e10de: /* Nvidia NV06 Vanta */
|
||||
case 0x002f10de: /* Nvidia NV06 Vanta */
|
||||
si->ps.card_type = NV06;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Vanta (NV06)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x00a010de: /* Nvidia Aladdin TNT2 */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Aladdin TNT2 (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x010010de: /* Nvidia GeForce256 SDR */
|
||||
case 0x010110de: /* Nvidia GeForce256 DDR */
|
||||
case 0x010210de: /* Nvidia GeForce256 Ultra */
|
||||
si->ps.card_type = NV10;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce256 (NV10)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x010310de: /* Nvidia Quadro */
|
||||
si->ps.card_type = NV10;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro (NV10)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x011010de: /* Nvidia GeForce2 MX/MX400 */
|
||||
case 0x011110de: /* Nvidia GeForce2 MX100/MX200 DDR */
|
||||
si->ps.card_type = NV11;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce2 MX (NV11)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x011210de: /* Nvidia GeForce2 Go */
|
||||
si->ps.card_type = NV11;
|
||||
si->ps.card_arch = NV10A;
|
||||
si->ps.laptop = true;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce2 Go (NV11)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x011310de: /* Nvidia Quadro2 MXR/EX/Go */
|
||||
si->ps.card_type = NV11;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro2 MXR/EX/Go (NV11)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x015010de: /* Nvidia GeForce2 GTS/Pro */
|
||||
case 0x015110de: /* Nvidia GeForce2 Ti DDR */
|
||||
case 0x015210de: /* Nvidia GeForce2 Ultra */
|
||||
si->ps.card_type = NV15;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce2 (NV15)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x015310de: /* Nvidia Quadro2 Pro */
|
||||
si->ps.card_type = NV15;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro2 Pro (NV15)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x017010de: /* Nvidia GeForce4 MX 460 */
|
||||
case 0x017110de: /* Nvidia GeForce4 MX 440 */
|
||||
case 0x017210de: /* Nvidia GeForce4 MX 420 */
|
||||
case 0x017310de: /* Nvidia GeForce4 MX 440SE */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX (NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x017410de: /* Nvidia GeForce4 440 Go */
|
||||
case 0x017510de: /* Nvidia GeForce4 420 Go */
|
||||
case 0x017610de: /* Nvidia GeForce4 420 Go 32M */
|
||||
case 0x017710de: /* Nvidia GeForce4 460 Go */
|
||||
case 0x017910de: /* Nvidia GeForce4 440 Go 64M */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
si->ps.laptop = true;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 Go (NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x017810de: /* Nvidia Quadro4 500 XGL/550 XGL */
|
||||
case 0x017a10de: /* Nvidia Quadro4 200 NVS/400 NVS */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro4 (NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x017c10de: /* Nvidia Quadro4 500 GoGL */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
si->ps.laptop = true;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro4 500 GoGL (NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
//fixme: three IDs below correct??
|
||||
case 0x018010de: /* Nvidia GeForce4 MX 440 AGP8X */
|
||||
case 0x018110de: /* Nvidia GeForce4 MX 440SE AGP8X */
|
||||
case 0x018210de: /* Nvidia GeForce4 MX 420 AGP8X */
|
||||
si->ps.card_type = NV18;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX AGP8X (NV18)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x018810de: /* Nvidia Quadro4 580 XGL */
|
||||
case 0x018a10de: /* Nvidia Quadro4 280 NVS */
|
||||
case 0x018b10de: /* Nvidia Quadro4 380 XGL */
|
||||
si->ps.card_type = NV18;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro4 (NV18)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */
|
||||
si->ps.card_type = NV11;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce2 Integrated GPU (CRUSH, NV11)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX Integrated GPU (NFORCE2, NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x020010de: /* Nvidia GeForce3 */
|
||||
case 0x020110de: /* Nvidia GeForce3 Ti 200 */
|
||||
case 0x020210de: /* Nvidia GeForce3 Ti 500 */
|
||||
si->ps.card_type = NV20;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce3 (NV20)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x020310de: /* Nvidia Quadro DCC */
|
||||
si->ps.card_type = NV20;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro DCC (NV20)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x025010de: /* Nvidia GeForce4 Ti 4600 */
|
||||
case 0x025110de: /* Nvidia GeForce4 Ti 4400 */
|
||||
case 0x025310de: /* Nvidia GeForce4 Ti 4200 */
|
||||
si->ps.card_type = NV25;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti (NV25)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x025810de: /* Nvidia Quadro4 900 XGL */
|
||||
case 0x025910de: /* Nvidia Quadro4 750 XGL */
|
||||
case 0x025b10de: /* Nvidia Quadro4 700 XGL */
|
||||
si->ps.card_type = NV25;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro4 XGL (NV25)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x028010de: /* Nvidia GeForce4 Ti 4600 AGP8X */
|
||||
case 0x028110de: /* Nvidia GeForce4 Ti 4200 AGP8X */
|
||||
si->ps.card_type = NV28;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti AGP8X (NV28)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x028210de: /* Nvidia GeForce4 Ti 4800SE */
|
||||
si->ps.card_type = NV28;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti 4800SE (NV28)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x028610de: /* Nvidia GeForce4 4200 Go */
|
||||
si->ps.card_type = NV28;
|
||||
si->ps.card_arch = NV20A;
|
||||
si->ps.laptop = true;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce4 4200 Go (NV28)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x028810de: /* Nvidia Quadro4 980 XGL */
|
||||
case 0x028910de: /* Nvidia Quadro4 780 XGL */
|
||||
si->ps.card_type = NV28;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro4 XGL (NV28)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x02a010de: /* Nvidia GeForce3 Integrated GPU */
|
||||
si->ps.card_type = NV20;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce3 Integrated GPU (XBOX, NV20)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x030110de: /* Nvidia GeForce FX 5800 Ultra */
|
||||
case 0x030210de: /* Nvidia GeForce FX 5800 */
|
||||
si->ps.card_type = NV30;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5800 (NV30)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x030810de: /* Nvidia Quadro FX 2000 */
|
||||
case 0x030910de: /* Nvidia Quadro FX 1000 */
|
||||
si->ps.card_type = NV30;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro FX (NV30)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x031110de: /* Nvidia GeForce FX 5600 Ultra */
|
||||
case 0x031210de: /* Nvidia GeForce FX 5600 */
|
||||
si->ps.card_type = NV31;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5600 (NV31)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x031a10de: /* Nvidia GeForce FX 5600 Go */
|
||||
si->ps.card_type = NV31;
|
||||
si->ps.card_arch = NV30A;
|
||||
si->ps.laptop = true;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5600 Go (NV31)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x032110de: /* Nvidia GeForce FX 5200 Ultra */
|
||||
case 0x032210de: /* Nvidia GeForce FX 5200 */
|
||||
si->ps.card_type = NV34;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5200 (NV34)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x032b10de: /* Nvidia Quadro FX 500 */
|
||||
si->ps.card_type = NV34;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro FX 500 (NV34)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x033010de: /* Nvidia GeForce FX 5900 Ultra */
|
||||
case 0x033110de: /* Nvidia GeForce FX 5900 */
|
||||
si->ps.card_type = NV35;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5900 (NV35)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x033810de: /* Nvidia Quadro FX 3000 */
|
||||
si->ps.card_type = NV35;
|
||||
si->ps.card_arch = NV30A;
|
||||
LOG(4,("POWERUP: Detected Nvidia Quadro FX 3000 (NV35)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
/* Vendor Elsa GmbH */
|
||||
case 0x0c601048: /* Elsa Gladiac Geforce2 MX */
|
||||
si->ps.card_type = NV11;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Elsa Gladiac Geforce2 MX (NV11)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
/* Vendor Nvidia STB/SGS-Thompson */
|
||||
case 0x002012d2: /* Nvidia STB/SGS-Thompson TNT1 */
|
||||
si->ps.card_type = NV04;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT1 (NV04)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002812d2: /* Nvidia STB/SGS-Thompson TNT2 (pro) */
|
||||
case 0x002912d2: /* Nvidia STB/SGS-Thompson TNT2 Ultra */
|
||||
case 0x002a12d2: /* Nvidia STB/SGS-Thompson TNT2 */
|
||||
case 0x002b12d2: /* Nvidia STB/SGS-Thompson TNT2 */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT2 (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002c12d2: /* Nvidia STB/SGS-Thompson Vanta (Lt) */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Vanta (Lt) (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002d12d2: /* Nvidia STB/SGS-Thompson TNT2-M64 (Pro) */
|
||||
si->ps.card_type = NV05M64;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT2-M64 (Pro) (NV05M64)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x002e12d2: /* Nvidia STB/SGS-Thompson NV06 Vanta */
|
||||
case 0x002f12d2: /* Nvidia STB/SGS-Thompson NV06 Vanta */
|
||||
si->ps.card_type = NV06;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Vanta (NV06)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x00a012d2: /* Nvidia STB/SGS-Thompson Aladdin TNT2 */
|
||||
si->ps.card_type = NV05;
|
||||
si->ps.card_arch = NV04A;
|
||||
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Aladdin TNT2 (NV05)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
/* Vendor Varisys Limited */
|
||||
case 0x35031888: /* Varisys GeForce4 MX440 */
|
||||
si->ps.card_type = NV17;
|
||||
si->ps.card_arch = NV10A;
|
||||
LOG(4,("POWERUP: Detected Varisys GeForce4 MX440 (NV17)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x35051888: /* Varisys GeForce4 Ti 4200 */
|
||||
si->ps.card_type = NV25;
|
||||
si->ps.card_arch = NV20A;
|
||||
LOG(4,("POWERUP: Detected Varisys GeForce4 Ti 4200 (NV25)\n"));
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
default:
|
||||
LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* override memory detection if requested by user */
|
||||
if (si->settings.memory != 0)
|
||||
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 NV setup on some (DRAM) boards) */
|
||||
status_t nv_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 G550:
|
||||
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;
|
||||
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 nvxx_general_powerup()
|
||||
{
|
||||
status_t result;
|
||||
|
||||
LOG(4, ("INIT: NV powerup\n"));
|
||||
if (si->settings.logmask & 0x80000000) nv_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 */
|
||||
//temp:
|
||||
return nv_general_bios_to_powergraphics();
|
||||
if (si->settings.usebios || (result != B_OK)) return nv_general_bios_to_powergraphics();
|
||||
|
||||
/*power up the PLLs,LUT,DAC*/
|
||||
LOG(2,("INIT: PLL/LUT/DAC powerup\n"));
|
||||
/* turn off both displays and the hardcursor (also disables transfers) */
|
||||
nv_crtc_dpms(false, false, false);
|
||||
nv_crtc_cursor_hide();
|
||||
/* G200 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 */
|
||||
/* set voltage reference - using DAC reference block partly */
|
||||
// DXIW(VREFCTRL,0x03);
|
||||
/* wait for 100ms for voltage reference to stabilize */
|
||||
delay(100000);
|
||||
/* power up the SYSPLL */
|
||||
// CFGW(OPTION,CFGR(OPTION)|0x20);
|
||||
/* power up the PIXPLL */
|
||||
// DXIW(PIXCLKCTRL,0x08);
|
||||
|
||||
/* disable pixelclock oscillations before switching on CLUT */
|
||||
// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
|
||||
/* disable 15bit mode CLUT-overlay function */
|
||||
// DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
|
||||
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
|
||||
// DXIW(MISCCTRL,0x1b);
|
||||
snooze(250);
|
||||
/* re-enable pixelclock oscillations */
|
||||
// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) & 0xfb));
|
||||
|
||||
/* 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"));
|
||||
g400_dac_set_sys_pll();
|
||||
|
||||
/* 'official' RAM initialisation */
|
||||
LOG(2,("INIT: RAM init\n"));
|
||||
/* disable hardware plane write mask if SDRAM card */
|
||||
// if (si->ps.sdram) CFGW(OPTION,(CFGR(OPTION) & 0xffffbfff));
|
||||
/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
|
||||
// ACCW(PLNWT,0x00000000);
|
||||
// ACCW(PLNWT,0xffffffff);
|
||||
/* program memory control waitstates */
|
||||
// ACCW(MCTLWTST,si->ps.mctlwtst_reg);
|
||||
/* set memory configuration including:
|
||||
* - SDRAM / SGRAM special functions select. */
|
||||
// CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF) | ((si->ps.v3_mem_type & 0x07) << 10));
|
||||
// if (!si->ps.sdram) CFGW(OPTION,(CFGR(OPTION) | (0x01 << 14)));
|
||||
/* set memory buffer type */
|
||||
// CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|((si->ps.v3_option2_reg & 0x03) << 12));
|
||||
/* set mode register opcode and streamer flow control */
|
||||
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0x0000FFFF)|(si->ps.memrdbk_reg & 0xffff0000));
|
||||
/* set RAM read tap delays */
|
||||
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.memrdbk_reg & 0x0000ffff));
|
||||
/* wait 200uS minimum */
|
||||
snooze(250);
|
||||
|
||||
/* reset memory (MACCESS is a write only register!) */
|
||||
// ACCW(MACCESS, 0x00000000);
|
||||
/* perform actual RAM reset */
|
||||
// ACCW(MACCESS, 0x00008000);
|
||||
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 */
|
||||
nv_crtc_dpms(true , true, true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t gx50_general_output_select()
|
||||
{
|
||||
/* make sure this call is warranted */
|
||||
if ((si->ps.card_type != NV11) && (si->ps.card_type != NV17)) return B_ERROR;
|
||||
|
||||
/* choose primary analog outputconnector */
|
||||
if ((si->ps.primary_dvi) && (si->ps.secondary_head) && (si->ps.tvout))
|
||||
{
|
||||
if (i2c_sec_tv_adapter() == B_OK)
|
||||
{
|
||||
LOG(4,("INIT: secondary TV-adapter detected, using primary connector\n"));
|
||||
// DXIW(OUTPUTCONN,0x01);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("INIT: no secondary TV-adapter detected, using secondary connector\n"));
|
||||
// DXIW(OUTPUTCONN,0x04);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("INIT: using primary connector\n"));
|
||||
// DXIW(OUTPUTCONN,0x01);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*connect CRTC1 to the specified DAC*/
|
||||
status_t nv_general_dac_select(int dac)
|
||||
{
|
||||
if (!si->ps.secondary_head)
|
||||
return B_ERROR;
|
||||
|
||||
/*MISCCTRL, clock src,...*/
|
||||
switch(dac)
|
||||
{
|
||||
/* G400 */
|
||||
case DS_CRTC1DAC_CRTC2MAVEN:
|
||||
/* connect CRTC1 to pixPLL */
|
||||
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
|
||||
/* connect CRTC2 to vidPLL, connect CRTC1 to internal DAC and
|
||||
* enable CRTC2 external video timing reset signal.
|
||||
* (Setting for MAVEN 'master mode' TVout signal generation.) */
|
||||
// CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002);
|
||||
/* disable CRTC1 external video timing reset signal */
|
||||
// VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
|
||||
/* select CRTC2 RGB24 MAFC mode: connects CRTC2 to MAVEN DAC */
|
||||
// DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
|
||||
break;
|
||||
case DS_CRTC1MAVEN_CRTC2DAC:
|
||||
/* connect CRTC1 to vidPLL */
|
||||
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2);
|
||||
/* connect CRTC2 to pixPLL and internal DAC and
|
||||
* disable CRTC2 external video timing reset signal */
|
||||
// CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20));
|
||||
/* enable CRTC1 external video timing reset signal.
|
||||
* note: this is nolonger used as G450/G550 cannot do TVout on CRTC1 */
|
||||
// VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88));
|
||||
/* select CRTC1 RGB24 MAFC mode: connects CRTC1 to MAVEN DAC */
|
||||
// DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02);
|
||||
break;
|
||||
/* G450/G550 */
|
||||
case DS_CRTC1CON1_CRTC2CON2:
|
||||
/* connect CRTC1 to pixPLL */
|
||||
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
|
||||
/* connect CRTC2 to vidPLL, connect CRTC1 to DAC1, disable CRTC2
|
||||
* external video timing reset signal, set CRTC2 progressive scan mode
|
||||
* and disable TVout mode (b12).
|
||||
* (Setting for MAVEN 'slave mode' TVout signal generation.) */
|
||||
//fixme: enable timing resets if TVout is used in master mode!
|
||||
//otherwise keep it disabled.
|
||||
// CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x0<<20));
|
||||
/* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (monitor mode) */
|
||||
// DXIW(OUTPUTCONN,0x09);
|
||||
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
|
||||
// DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
|
||||
// DXIW(GENIODATA, 0x00);
|
||||
break;
|
||||
//fixme: toggle PLL's below if possible:
|
||||
// otherwise toggle PLL's for G400 2nd case?
|
||||
case DS_CRTC1CON2_CRTC2CON1:
|
||||
/* connect CRTC1 to pixPLL */
|
||||
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
|
||||
/* connect CRTC2 to vidPLL and DAC1, disable CRTC2 external
|
||||
* video timing reset signal, and set CRTC2 progressive scan mode and
|
||||
* disable TVout mode (b12). */
|
||||
// CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x1<<20));
|
||||
/* connect DAC1 to CON2 (monitor mode), CRTC2/'DAC2' to CON1 */
|
||||
// DXIW(OUTPUTCONN,0x05);
|
||||
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
|
||||
// DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
|
||||
// DXIW(GENIODATA, 0x00);
|
||||
break;
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*busy wait until retrace!*/
|
||||
status_t nv_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 nv_general_bios_to_powergraphics()
|
||||
{
|
||||
LOG(2, ("INIT: Skipping card coldstart!\n"));
|
||||
|
||||
/* unlock card registers for R/W access */
|
||||
CRTCW(LOCK, 0x57);
|
||||
|
||||
/* turn off both displays and the hardcursor (also disables transfers) */
|
||||
nv_crtc_dpms(false, false, false);
|
||||
nv_crtc_cursor_hide();
|
||||
|
||||
/* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */
|
||||
/* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */
|
||||
// CRTCW(MODECTL, 0xc3);
|
||||
/* ... plain sequential memory use, more than 64Kb RAM installed,
|
||||
* switch to graphics mode ... */
|
||||
// SEQW(MEMMODE, 0x0e);
|
||||
/* ... disable bitplane tweaking ... */
|
||||
// GRPHW(ENSETRESET, 0x00);
|
||||
/* ... no logical function tweaking with display data, no data rotation ... */
|
||||
// GRPHW(DATAROTATE, 0x00);
|
||||
/* ... reset read map select to plane 0 ... */
|
||||
// GRPHW(READMAPSEL, 0x00);
|
||||
/* ... set standard mode ... */
|
||||
// GRPHW(MODE, 0x00);
|
||||
/* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again),
|
||||
* select standard adressing ... */
|
||||
// GRPHW(MISC, 0x05);
|
||||
/* ... disable bit masking ... */
|
||||
// GRPHW(BITMASK, 0xff);
|
||||
/* ... attributes are in color, switch to graphics mode (again) ... */
|
||||
// ATBW(MODECTL, 0x01);
|
||||
/* ... set overscan color to black ... */
|
||||
// ATBW(OSCANCOLOR, 0x00);
|
||||
/* ... enable all color planes ... */
|
||||
// ATBW(COLPLANE_EN, 0x0f);
|
||||
/* ... reset horizontal pixelpanning ... */
|
||||
// ATBW(HORPIXPAN, 0x00);
|
||||
/* ... and reset colorpalette groupselect bits. */
|
||||
// ATBW(COLSEL, 0x00);
|
||||
|
||||
/* setup sequencer clocking mode */
|
||||
// SEQW(CLKMODE, 0x21);
|
||||
|
||||
/* enable 'enhanced mode', enable Vsync & Hsync,
|
||||
* set DAC palette to 8-bit width, disable large screen */
|
||||
CRTCW(REPAINT1, 0x04);
|
||||
|
||||
/* turn on display */
|
||||
nv_crtc_dpms(true, true, true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
|
||||
* virtual_size to the nearest valid maximum for the mode on the card if not so.
|
||||
* Then: check if virtual_width adheres to the cards _multiple_ constraints, and
|
||||
* create mode slopspace if not so.
|
||||
* We use acc multiple constraints here if we expect we can use acceleration, because
|
||||
* acc constraints are worse than CRTC constraints.
|
||||
*
|
||||
* Mode slopspace is reflected in fbc->bytes_per_row BTW. */
|
||||
//fixme: seperate heads for real dualhead modes:
|
||||
//CRTC1 and 2 constraints differ!
|
||||
status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row)
|
||||
{
|
||||
/* Note:
|
||||
* This routine assumes that the CRTC memory pitch granularity is 'smaller than',
|
||||
* or 'equals' the acceleration engine memory pitch granularity! */
|
||||
|
||||
uint32 video_pitch;
|
||||
uint32 acc_mask, crtc_mask;
|
||||
uint8 depth = 8;
|
||||
|
||||
/* determine pixel multiple based on 2D/3D engine constraints */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
// case MIL2:
|
||||
/* see MIL1/2 specs:
|
||||
* these cards always use a 64bit RAMDAC (TVP3026) and interleaved memory */
|
||||
/* switch (target->space)
|
||||
{
|
||||
case B_CMAP8: acc_mask = 0x7f; depth = 8; break;
|
||||
case B_RGB15: acc_mask = 0x3f; depth = 16; break;
|
||||
case B_RGB16: acc_mask = 0x3f; depth = 16; break;
|
||||
case B_RGB24: acc_mask = 0x7f; depth = 24; break;
|
||||
case B_RGB32: acc_mask = 0x1f; depth = 32; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
*/ default:
|
||||
/* see G100 and up specs:
|
||||
* these cards can do 2D as long as multiples of 32 are used.
|
||||
* (Note: don't mix this up with adress linearisation!) */
|
||||
switch (target->space)
|
||||
{
|
||||
case B_CMAP8: depth = 8; break;
|
||||
case B_RGB15: depth = 16; break;
|
||||
case B_RGB16: depth = 16; break;
|
||||
case B_RGB24: depth = 24; break;
|
||||
case B_RGB32: depth = 32; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
acc_mask = 0x1f;
|
||||
break;
|
||||
}
|
||||
|
||||
/* determine pixel multiple based on CRTC memory pitch constraints.
|
||||
* (Note: Don't mix this up with CRTC timing contraints! Those are
|
||||
* multiples of 8 for horizontal, 1 for vertical timing.) */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
// case MIL2:
|
||||
/* see MIL1/2 specs:
|
||||
* these cards always use a 64bit RAMDAC and interleaved memory */
|
||||
/* switch (target->space)
|
||||
{
|
||||
case B_CMAP8: crtc_mask = 0x7f; break;
|
||||
case B_RGB15: crtc_mask = 0x3f; break;
|
||||
case B_RGB16: crtc_mask = 0x3f; break;
|
||||
*/ /* for B_RGB24 crtc_mask 0x7f is worst case scenario (MIL2 constraint) */
|
||||
/* case B_RGB24: crtc_mask = 0x7f; break;
|
||||
case B_RGB32: crtc_mask = 0x1f; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
*/ default:
|
||||
/* all NV cards */
|
||||
switch (target->space)
|
||||
{
|
||||
case B_CMAP8: crtc_mask = 0x07; break;
|
||||
case B_RGB15: crtc_mask = 0x03; break;
|
||||
case B_RGB16: crtc_mask = 0x03; break;
|
||||
case B_RGB24: crtc_mask = 0x07; break;
|
||||
case B_RGB32: crtc_mask = 0x01; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
/* see G400 specs: CRTC2 has different constraints */
|
||||
/* Note:
|
||||
* set for RGB and B_YCbCr422 modes. Other modes need larger multiples! */
|
||||
//fixme..
|
||||
if (target->flags & DUALHEAD_BITS)
|
||||
{
|
||||
switch (target->space)
|
||||
{
|
||||
case B_RGB16: crtc_mask = 0x1f; break;
|
||||
case B_RGB32: crtc_mask = 0x0f; break;
|
||||
default:
|
||||
LOG(8,("INIT: illegal DH color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if we can setup this mode with acceleration:
|
||||
* Max sizes need to adhere to both the acceleration engine _and_ the CRTC constraints! */
|
||||
si->acc_mode = true;
|
||||
/* check virtual_width */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
/* G200-G550 */
|
||||
/* acc constraint: */
|
||||
if (target->virtual_width > 4096) si->acc_mode = false;
|
||||
/* for 32bit mode a lower CRTC1 restriction applies! */
|
||||
if ((target->space == B_RGB32_LITTLE) && (target->virtual_width > (4092 & ~acc_mask)))
|
||||
si->acc_mode = false;
|
||||
break;
|
||||
}
|
||||
/* virtual_height */
|
||||
if (target->virtual_height > 2048) si->acc_mode = false;
|
||||
|
||||
/* now check NV virtual_size based on CRTC constraints */
|
||||
{
|
||||
/* virtual_width */
|
||||
//fixme for NV CRTC2?...:
|
||||
switch(target->space)
|
||||
{
|
||||
case B_CMAP8:
|
||||
if (target->virtual_width > 16376)
|
||||
target->virtual_width = 16376;
|
||||
break;
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGB16_LITTLE:
|
||||
if (target->virtual_width > 8188)
|
||||
target->virtual_width = 8188;
|
||||
break;
|
||||
case B_RGB24_LITTLE:
|
||||
if (target->virtual_width > 5456)
|
||||
target->virtual_width = 5456;
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
if (target->virtual_width > 4094)
|
||||
target->virtual_width = 4094;
|
||||
break;
|
||||
}
|
||||
|
||||
/* virtual_height: The only constraint here is the cards memory size which is
|
||||
* checked later on in ProposeMode: virtual_height is adjusted then if needed.
|
||||
* 'Limiting here' to the variable size that's at least available (uint16). */
|
||||
if (target->virtual_height > 65535) target->virtual_height = 65535;
|
||||
}
|
||||
|
||||
//temp disabled:
|
||||
si->acc_mode = false;
|
||||
|
||||
/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
|
||||
* it was confined above, so we can finally calculate safely if we need slopspace
|
||||
* for this mode... */
|
||||
if (si->acc_mode)
|
||||
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
|
||||
else
|
||||
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
|
||||
|
||||
LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
|
||||
video_pitch, target->space));
|
||||
if (target->virtual_width != video_pitch)
|
||||
LOG(2,("INIT: effective mode slopspace is %d pixels\n",
|
||||
(video_pitch - target->virtual_width)));
|
||||
|
||||
/* now calculate bytes_per_row for this mode */
|
||||
*bytes_per_row = video_pitch * (depth >> 3);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* i2c interface for the G400 MAVEN under BeOS
|
||||
*
|
||||
* Provides I2CR,I2CW - functions to parallel DACW,DACR
|
||||
* Bus should be run at max. 100kHz: see original Philips I2C specification
|
||||
*
|
||||
* Much help was provided by observing the Linux i2c code,
|
||||
* so thanks go to: Gerd Knorr
|
||||
*
|
||||
* Other authors:
|
||||
* Mark Watson 6/2000,
|
||||
* Rudolf Cornelissen 12/2002
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00004000
|
||||
|
||||
#include "nv_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
|
||||
|
||||
/* NV-TVO I2C for G200, G400 */
|
||||
#define I2C_CLOCK 0x20
|
||||
#define I2C_DATA 0x10
|
||||
/* primary head DDC for Mystique(?), G100, G200, G400 */
|
||||
#define DDC1_CLK 0x08
|
||||
#define DDC1_DATA 0x02
|
||||
/* primary head DDC for Millennium, Millennium II */
|
||||
#define DDC1B_CLK 0x10
|
||||
#define DDC1B_DATA 0x04
|
||||
/* secondary head DDC for G400, G450 and G550 */
|
||||
#define DDC2_CLK 0x04
|
||||
#define DDC2_DATA 0x01
|
||||
|
||||
status_t i2c_sec_tv_adapter()
|
||||
{
|
||||
status_t result = B_ERROR;
|
||||
|
||||
/* The secondary DDC channel only exist on dualhead cards */
|
||||
if (!si->ps.secondary_head) return result;
|
||||
|
||||
/* make sure the output lines will be active-low when enabled
|
||||
* (they will be pulled 'passive-high' when disabled) */
|
||||
// DXIW(GENIODATA,0x00);
|
||||
/* send out B_STOP condition on secondary head DDC channel and use it to
|
||||
* check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */
|
||||
|
||||
/* make sure SDA is low */
|
||||
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA));
|
||||
snooze(2);
|
||||
/* make sure SCL should be high */
|
||||
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK));
|
||||
snooze(2);
|
||||
/* if SCL is low then the bus is blocked by a TV adapter */
|
||||
// if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK;
|
||||
snooze(5);
|
||||
/* set SDA while SCL should be set (generates actual bus-stop condition) */
|
||||
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA));
|
||||
snooze(5);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-----------------------------
|
||||
*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 = 0;
|
||||
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,685 @@
|
||||
/* Read initialisation information from card */
|
||||
/* some bits are hacks, where PINS is not known */
|
||||
/* Author:
|
||||
Rudolf Cornelissen 7/2003
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00002000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
/* 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 5:
|
||||
result = pins5_read(pins, pins_len);
|
||||
break;
|
||||
default:
|
||||
LOG(8,("INFO: unknown PINS version\n"));
|
||||
return B_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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] == 0x01) m_factor = 8;
|
||||
if (pins[4] >= 0x02) m_factor = 10;
|
||||
|
||||
si->ps.max_system_vco = m_factor * pins[36];
|
||||
si->ps.max_video_vco = m_factor * pins[37];
|
||||
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];
|
||||
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_memory_clock = 4 * pins[92];
|
||||
|
||||
si->ps.memory_size = ((pins[114] & 0x03) + 1) * 8;
|
||||
if ((pins[114] & 0x07) > 3)
|
||||
{
|
||||
LOG(8,("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;
|
||||
|
||||
/* make sure SGRAM functions only get enabled if SGRAM mounted */
|
||||
if ((pins[114] & 0x18) == 0x08) si->ps.sdram = false;
|
||||
else si->ps.sdram = true;
|
||||
|
||||
/* various registers */
|
||||
si->ps.secondary_head = (pins[117] & 0x70);
|
||||
si->ps.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;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* fake_pins presumes the card was coldstarted by it's BIOS */
|
||||
void fake_pins(void)
|
||||
{
|
||||
LOG(8,("INFO: faking PINS\n"));
|
||||
|
||||
/* set failsave speeds */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
case NV04:
|
||||
pinsnv4_fake();
|
||||
break;
|
||||
case NV05:
|
||||
case NV05M64:
|
||||
pinsnv5_nv5m64_fake();
|
||||
break;
|
||||
case NV06:
|
||||
pinsnv6_fake();
|
||||
break;
|
||||
default:
|
||||
switch (si->ps.card_arch)
|
||||
{
|
||||
case NV10A:
|
||||
pinsnv10_arch_fake();
|
||||
break;
|
||||
case NV20A:
|
||||
pinsnv20_arch_fake();
|
||||
break;
|
||||
case NV30A:
|
||||
pinsnv30_arch_fake();
|
||||
break;
|
||||
default:
|
||||
/* 'failsafe' values... */
|
||||
pinsnv10_arch_fake();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* detect RAM amount, reference crystal frequency and dualhead */
|
||||
switch (si->ps.card_arch)
|
||||
{
|
||||
case NV04A:
|
||||
getstrap_arch_nv4();
|
||||
break;
|
||||
default:
|
||||
getstrap_arch_nv10_20();
|
||||
break;
|
||||
}
|
||||
|
||||
/* find out if the card has a tvout chip */
|
||||
si->ps.tvout = false;
|
||||
si->ps.tvout_chip_type = NONE;
|
||||
//fixme ;-)
|
||||
/* if (i2c_maven_probe() == B_OK)
|
||||
{
|
||||
si->ps.tvout = true;
|
||||
si->ps.tvout_chip_bus = ???;
|
||||
si->ps.tvout_chip_type = ???;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void pinsnv4_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 256;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 256;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 0;
|
||||
si->ps.min_video_vco = 0;
|
||||
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 = 220;
|
||||
si->ps.max_dac1_clock_32 = 180;
|
||||
si->ps.max_dac1_clock_32dh = 180;
|
||||
/* secondary head */
|
||||
si->ps.max_dac2_clock = 0;
|
||||
si->ps.max_dac2_clock_8 = 0;
|
||||
si->ps.max_dac2_clock_16 = 0;
|
||||
si->ps.max_dac2_clock_24 = 0;
|
||||
si->ps.max_dac2_clock_32 = 0;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 0;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 90;
|
||||
si->ps.std_memory_clock = 110;
|
||||
}
|
||||
|
||||
void pinsnv5_nv5m64_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 300;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 300;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 0;
|
||||
si->ps.min_video_vco = 0;
|
||||
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 = 270;
|
||||
si->ps.max_dac1_clock_32 = 230;
|
||||
si->ps.max_dac1_clock_32dh = 230;
|
||||
/* secondary head */
|
||||
si->ps.max_dac2_clock = 0;
|
||||
si->ps.max_dac2_clock_8 = 0;
|
||||
si->ps.max_dac2_clock_16 = 0;
|
||||
si->ps.max_dac2_clock_24 = 0;
|
||||
si->ps.max_dac2_clock_32 = 0;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 0;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 125;
|
||||
si->ps.std_memory_clock = 150;
|
||||
}
|
||||
|
||||
void pinsnv6_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 300;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 300;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 0;
|
||||
si->ps.min_video_vco = 0;
|
||||
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 = 270;
|
||||
si->ps.max_dac1_clock_32 = 230;
|
||||
si->ps.max_dac1_clock_32dh = 230;
|
||||
/* secondary head */
|
||||
si->ps.max_dac2_clock = 0;
|
||||
si->ps.max_dac2_clock_8 = 0;
|
||||
si->ps.max_dac2_clock_16 = 0;
|
||||
si->ps.max_dac2_clock_24 = 0;
|
||||
si->ps.max_dac2_clock_32 = 0;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 0;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 100;
|
||||
si->ps.std_memory_clock = 125;
|
||||
}
|
||||
|
||||
void pinsnv10_arch_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 350;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 350;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 350;
|
||||
si->ps.min_video_vco = 128;
|
||||
si->ps.max_dac1_clock = 350;
|
||||
si->ps.max_dac1_clock_8 = 350;
|
||||
si->ps.max_dac1_clock_16 = 350;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac1_clock_24 = 320;
|
||||
si->ps.max_dac1_clock_32 = 280;
|
||||
si->ps.max_dac1_clock_32dh = 250;
|
||||
/* secondary head */
|
||||
//fixme? assuming...
|
||||
si->ps.max_dac2_clock = 200;
|
||||
si->ps.max_dac2_clock_8 = 200;
|
||||
si->ps.max_dac2_clock_16 = 200;
|
||||
si->ps.max_dac2_clock_24 = 200;
|
||||
si->ps.max_dac2_clock_32 = 200;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 180;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 120;
|
||||
si->ps.std_memory_clock = 150;
|
||||
}
|
||||
|
||||
void pinsnv20_arch_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 350;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 350;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 350;
|
||||
si->ps.min_video_vco = 128;
|
||||
si->ps.max_dac1_clock = 350;
|
||||
si->ps.max_dac1_clock_8 = 350;
|
||||
si->ps.max_dac1_clock_16 = 350;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac1_clock_24 = 320;
|
||||
si->ps.max_dac1_clock_32 = 280;
|
||||
si->ps.max_dac1_clock_32dh = 250;
|
||||
/* secondary head */
|
||||
//fixme? assuming...
|
||||
si->ps.max_dac2_clock = 200;
|
||||
si->ps.max_dac2_clock_8 = 200;
|
||||
si->ps.max_dac2_clock_16 = 200;
|
||||
si->ps.max_dac2_clock_24 = 200;
|
||||
si->ps.max_dac2_clock_32 = 200;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 180;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 175;
|
||||
si->ps.std_memory_clock = 200;
|
||||
}
|
||||
|
||||
void pinsnv30_arch_fake(void)
|
||||
{
|
||||
/* carefull not to take to high limits, and high should be >= 2x low. */
|
||||
si->ps.max_system_vco = 350;
|
||||
si->ps.min_system_vco = 128;
|
||||
si->ps.max_pixel_vco = 350;
|
||||
si->ps.min_pixel_vco = 128;
|
||||
si->ps.max_video_vco = 350;
|
||||
si->ps.min_video_vco = 128;
|
||||
si->ps.max_dac1_clock = 350;
|
||||
si->ps.max_dac1_clock_8 = 350;
|
||||
si->ps.max_dac1_clock_16 = 350;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac1_clock_24 = 320;
|
||||
si->ps.max_dac1_clock_32 = 280;
|
||||
si->ps.max_dac1_clock_32dh = 250;
|
||||
/* secondary head */
|
||||
//fixme? assuming...
|
||||
si->ps.max_dac2_clock = 200;
|
||||
si->ps.max_dac2_clock_8 = 200;
|
||||
si->ps.max_dac2_clock_16 = 200;
|
||||
si->ps.max_dac2_clock_24 = 200;
|
||||
si->ps.max_dac2_clock_32 = 200;
|
||||
/* 'failsave' values */
|
||||
si->ps.max_dac2_clock_32dh = 180;
|
||||
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
|
||||
si->ps.primary_dvi = false;
|
||||
si->ps.secondary_dvi = false;
|
||||
//fixme: is this needed for nv acc?
|
||||
//fail-safe mode for now:
|
||||
si->ps.sdram = true;
|
||||
|
||||
/* not used (yet) because no coldstart will be attempted (yet) */
|
||||
si->ps.std_engine_clock = 190;
|
||||
si->ps.std_memory_clock = 190;
|
||||
}
|
||||
|
||||
void getstrap_arch_nv4(void)
|
||||
{
|
||||
uint32 strapinfo = NV_REG32(NV32_NV4STRAPINFO);
|
||||
|
||||
if (strapinfo & 0x00000100)
|
||||
{
|
||||
/* Unified memory architecture used */
|
||||
si->ps.memory_size =
|
||||
((((strapinfo & 0x0000f000) >> 12) * 2) + 2);
|
||||
|
||||
LOG(8,("INFO: NV4 architecture chip with UMA detected\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* private memory architecture used */
|
||||
switch (strapinfo & 0x00000003)
|
||||
{
|
||||
case 0:
|
||||
si->ps.memory_size = 32;
|
||||
break;
|
||||
case 1:
|
||||
si->ps.memory_size = 4;
|
||||
break;
|
||||
case 2:
|
||||
si->ps.memory_size = 8;
|
||||
break;
|
||||
case 3:
|
||||
si->ps.memory_size = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
|
||||
|
||||
/* determine PLL reference crystal frequency */
|
||||
if (strapinfo & 0x00000040)
|
||||
si->ps.f_ref = 14.31818;
|
||||
else
|
||||
si->ps.f_ref = 13.50000;
|
||||
|
||||
/* these cards are always singlehead */
|
||||
si->ps.secondary_head = false;
|
||||
}
|
||||
|
||||
void getstrap_arch_nv10_20(void)
|
||||
{
|
||||
uint32 dev_manID = CFGR(DEVID);
|
||||
uint32 strapinfo = NV_REG32(NV32_NV10STRAPINFO);
|
||||
|
||||
switch (dev_manID)
|
||||
{
|
||||
case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */
|
||||
si->ps.memory_size = (((CFGR(GF2IGPU) & 0x000007c0) >> 6) + 1);
|
||||
break;
|
||||
case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */
|
||||
si->ps.memory_size = (((CFGR(GF4MXIGPU) & 0x000007f0) >> 4) + 1);
|
||||
//remove this line if det. is OK: int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
|
||||
break;
|
||||
default:
|
||||
switch ((strapinfo & 0x0ff00000) >> 20)
|
||||
{
|
||||
case 2:
|
||||
si->ps.memory_size = 2;
|
||||
break;
|
||||
case 4:
|
||||
si->ps.memory_size = 4;
|
||||
break;
|
||||
case 8:
|
||||
si->ps.memory_size = 8;
|
||||
break;
|
||||
case 16:
|
||||
si->ps.memory_size = 16;
|
||||
break;
|
||||
case 32:
|
||||
si->ps.memory_size = 32;
|
||||
break;
|
||||
case 64:
|
||||
si->ps.memory_size = 64;
|
||||
break;
|
||||
case 128:
|
||||
si->ps.memory_size = 128;
|
||||
break;
|
||||
default:
|
||||
si->ps.memory_size = 16;
|
||||
|
||||
LOG(8,("INFO: NV10/20 architecture chip with unknown RAM amount detected;\n"));
|
||||
LOG(8,("INFO: Setting 16Mb\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
|
||||
|
||||
/* determine PLL reference crystal frequency: three types are used... */
|
||||
if (strapinfo & 0x00000040)
|
||||
si->ps.f_ref = 14.31818;
|
||||
else
|
||||
si->ps.f_ref = 13.50000;
|
||||
|
||||
switch (dev_manID & 0xfff0ffff)
|
||||
{
|
||||
/* Nvidia cards: */
|
||||
case 0x017010de:
|
||||
case 0x018010de:
|
||||
case 0x01f010de:
|
||||
case 0x025010de:
|
||||
case 0x028010de:
|
||||
case 0x030010de:
|
||||
case 0x031010de:
|
||||
case 0x032010de:
|
||||
case 0x033010de:
|
||||
/* Varisys cards: */
|
||||
case 0x35001888:
|
||||
if (strapinfo & 0x00400000) si->ps.f_ref = 27.00000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* determine if we have a dualhead card */
|
||||
switch (dev_manID & 0xfff0ffff)
|
||||
{
|
||||
/* Nvidia cards: */
|
||||
case 0x011010de:
|
||||
case 0x017010de:
|
||||
case 0x018010de:
|
||||
case 0x01f010de:
|
||||
case 0x025010de:
|
||||
case 0x028010de:
|
||||
case 0x030010de:
|
||||
case 0x031010de:
|
||||
case 0x032010de:
|
||||
case 0x033010de:
|
||||
/* Varisys cards: */
|
||||
case 0x35001888:
|
||||
si->ps.secondary_head = true;
|
||||
break;
|
||||
default:
|
||||
si->ps.secondary_head = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_pins(void)
|
||||
{
|
||||
char *msg = "";
|
||||
|
||||
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_memory_clock: %dMhz\n", si->ps.std_memory_clock));
|
||||
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,("tvout: "));
|
||||
if (si->ps.tvout) LOG(2,("present\n")); else LOG(2,("absent\n"));
|
||||
/* setup TVout logmessage text */
|
||||
switch (si->ps.tvout_chip_type)
|
||||
{
|
||||
case NONE:
|
||||
msg = "No";
|
||||
break;
|
||||
case CH7003:
|
||||
msg = "Chrontel CH7003";
|
||||
break;
|
||||
case CH7004:
|
||||
msg = "Chrontel CH7004";
|
||||
break;
|
||||
case CH7005:
|
||||
msg = "Chrontel CH7005";
|
||||
break;
|
||||
case CH7006:
|
||||
msg = "Chrontel CH7006";
|
||||
break;
|
||||
case CH7007:
|
||||
msg = "Chrontel CH7007";
|
||||
break;
|
||||
case SAA7102:
|
||||
msg = "Philips SAA7102";
|
||||
break;
|
||||
case SAA7108:
|
||||
msg = "Philips SAA7108";
|
||||
break;
|
||||
case BT868:
|
||||
msg = "Brooktree/Conexant BT868";
|
||||
break;
|
||||
case BT869:
|
||||
msg = "Brooktree/Conexant BT869";
|
||||
break;
|
||||
case CX25870:
|
||||
msg = "Conexant CX25870";
|
||||
break;
|
||||
case CX25871:
|
||||
msg = "Conexant CX25871";
|
||||
break;
|
||||
case NVIDIA:
|
||||
msg = "Nvidia internal";
|
||||
break;
|
||||
default:
|
||||
msg = "Unknown";
|
||||
break;
|
||||
}
|
||||
LOG(2, ("%s TVout chip detected\n", msg));
|
||||
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,("sdram: "));
|
||||
if (si->ps.sdram) LOG(2,("SDRAM card\n")); else LOG(2,("SGRAM card\n"));
|
||||
LOG(2,("laptop: "));
|
||||
if (si->ps.laptop) LOG(2,("yes\n")); else LOG(2,("no\n"));
|
||||
LOG(2,("INFO: end pinsdump.\n"));
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/* program the MAVEN in monitor mode */
|
||||
|
||||
/* Authors:
|
||||
Mark Watson 6/2000,
|
||||
Rudolf Cornelissen 1/2003-4/2003
|
||||
|
||||
Thanx to Petr Vandrovec for writing matroxfb.
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00001000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
status_t g450_g550_maven_set_vid_pll(display_mode target);
|
||||
status_t g100_g400max_maven_set_vid_pll(display_mode target);
|
||||
|
||||
status_t nv_maven_dpms(uint8 display,uint8 h,uint8 v)
|
||||
{
|
||||
/* this function is nolonger needed on G450/G550 cards */
|
||||
if (si->ps.card_type > G550) return B_OK;
|
||||
|
||||
if (display & h & v)
|
||||
{
|
||||
/* turn on screen */
|
||||
if (!(si->dm.flags & TV_BITS))
|
||||
{
|
||||
/* monitor mode */
|
||||
MAVW(MONEN, 0xb2);
|
||||
MAVW(MONSET, 0x20); /* must be set to this in monitor mode */
|
||||
MAVW(OUTMODE, 0x03); /* output: monitor mode */
|
||||
MAVW(STABLE, 0x22); /* makes picture stable? */
|
||||
MAVW(TEST, 0x00); /* turn off test signal */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TVout mode */
|
||||
MAVW(MONEN, 0xb3);
|
||||
MAVW(MONSET, 0x20);
|
||||
MAVW(OUTMODE, 0x08); /* output: SVideo/Composite */
|
||||
MAVW(STABLE, 0x02); /* makes picture stable? */
|
||||
//fixme? linux uses 0x14...
|
||||
MAVW(TEST, (MAVR(TEST) & 0x10));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* turn off screen using a few methods! */
|
||||
MAVW(STABLE, 0x6a);
|
||||
// MAVW(TEST, 0x03);
|
||||
MAVW(OUTMODE, 0x00);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*set a mode line - inputs are in pixels/scanlines*/
|
||||
status_t nv_maven_set_timing(display_mode target)
|
||||
{
|
||||
/* this function is nolonger needed on G450/G550 cards */
|
||||
if (si->ps.card_type > G550) return B_OK;
|
||||
|
||||
LOG(4,("MAVEN: setting timing\n"));
|
||||
|
||||
/*check horizontal timing parameters are to nearest 8 pixels*/
|
||||
if ((target.timing.h_display & 0x07) |
|
||||
(target.timing.h_sync_start & 0x07) |
|
||||
(target.timing.h_sync_end & 0x07) |
|
||||
(target.timing.h_total & 0x07))
|
||||
{
|
||||
LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/*program the MAVEN*/
|
||||
MAVWW(LASTLINEL, target.timing.h_total);
|
||||
MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
|
||||
MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
|
||||
MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
|
||||
target.timing.h_display));
|
||||
MAVWW(HTOTALL, (target.timing.h_total + 1));
|
||||
|
||||
MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
|
||||
MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
|
||||
MAVWW(VDISPLAYL, (target.timing.v_total - 1));
|
||||
MAVWW(VTOTALL, (target.timing.v_total - 1));
|
||||
|
||||
MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
|
||||
MAVWW(VVIDRSTL, (target.timing.v_total - 2));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
|
||||
status_t nv_maven_mode(int mode,float brightness)
|
||||
{
|
||||
uint8 luma;
|
||||
|
||||
/* this function is nolonger needed on G450/G550 cards */
|
||||
if (si->ps.card_type > G550) return B_OK;
|
||||
|
||||
/*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;
|
||||
}
|
||||
|
||||
status_t nv_maven_set_vid_pll(display_mode target)
|
||||
{
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
return g100_g400max_maven_set_vid_pll(target);
|
||||
break;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* program the video PLL in the MAVEN */
|
||||
status_t g100_g400max_maven_set_vid_pll(display_mode target)
|
||||
{
|
||||
uint8 m=0,n=0,p=0;
|
||||
|
||||
float pix_setting, req_pclk;
|
||||
status_t result;
|
||||
|
||||
req_pclk = (target.timing.pixel_clock)/1000.0;
|
||||
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
|
||||
|
||||
result = g100_g400max_maven_vid_pll_find(target,&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 enabling PLL */
|
||||
|
||||
/* Wait for the VIDPLL frequency to lock: detection is not possible it seems */
|
||||
snooze(2000);
|
||||
|
||||
LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* find nearest valid video PLL setting */
|
||||
status_t g100_g400max_maven_vid_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 */
|
||||
//fixme: check G100 and G200 m_max if possible...
|
||||
switch(si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
LOG(4,("MAVEN: G400/G400MAX restrictions apply\n"));
|
||||
m_max = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* determine the max. pixelclock for the current videomode */
|
||||
switch (target.space)
|
||||
{
|
||||
case B_RGB16_LITTLE:
|
||||
max_pclk = si->ps.max_dac2_clock_16;
|
||||
break;
|
||||
case B_RGB32_LITTLE:
|
||||
max_pclk = si->ps.max_dac2_clock_32;
|
||||
break;
|
||||
default:
|
||||
/* use fail-safe value */
|
||||
max_pclk = si->ps.max_dac2_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_dac2_clock_32dh;
|
||||
|
||||
/* Make sure the requested pixelclock is within the PLL's operational limits */
|
||||
/* lower limit is min_video_vco divided by highest postscaler-factor */
|
||||
if (req_pclk < (si->ps.min_video_vco / 8.0))
|
||||
{
|
||||
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
|
||||
req_pclk, (float)(si->ps.min_video_vco / 8.0)));
|
||||
req_pclk = (si->ps.min_video_vco / 8.0);
|
||||
}
|
||||
/* upper limit is given by pins in combination with current active mode */
|
||||
if (req_pclk > max_pclk)
|
||||
{
|
||||
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
|
||||
req_pclk, (float)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_video_vco) && (f_vco <= si->ps.max_video_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 */
|
||||
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
|
||||
LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
|
||||
|
||||
switch(si->ps.card_type)
|
||||
{
|
||||
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,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
|
||||
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 "nv_extern.h"
|
||||
#include "nv_proto.h"
|
||||
#include "nv_macros.h"
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Some commmon support functions */
|
||||
/* Mark Watson 2/2000 */
|
||||
|
||||
#define MODULE_BIT 0x00000800
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "nv_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 nv_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);
|
||||
}
|
||||
Reference in New Issue
Block a user