initial import of skeleton graphics accelerant (not yet working/stripped)
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9783 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
|
||||||
|
Other authors:
|
||||||
|
Rudolf Cornelissen 9/2003.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x40000000
|
||||||
|
|
||||||
|
#include "acc_std.h"
|
||||||
|
|
||||||
|
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* init acc engine for blit function */
|
||||||
|
nv_acc_setup_blit();
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* init acc engine for fill function */
|
||||||
|
nv_acc_setup_rectangle(colorIndex);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* init acc engine for invert function */
|
||||||
|
nv_acc_setup_rect_invert();
|
||||||
|
|
||||||
|
/* invert 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
|
||||||
|
);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* init acc engine for fill function */
|
||||||
|
nv_acc_setup_rectangle(colorIndex);
|
||||||
|
|
||||||
|
/* draw each span */
|
||||||
|
i=0;
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
nv_acc_rectangle
|
||||||
|
(
|
||||||
|
list[i+1],
|
||||||
|
list[i+2]+1,
|
||||||
|
list[i],
|
||||||
|
1
|
||||||
|
);
|
||||||
|
i+=3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
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-5/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x20000000
|
||||||
|
|
||||||
|
#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, hot_x %d, hot_y %d\n",
|
||||||
|
width, height, hot_x, hot_y));
|
||||||
|
|
||||||
|
if ((width != 16) || (height != 16))
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
else if ((hot_x >= width) || (hot_y >= height))
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head1_cursor_define(andMask,xorMask);
|
||||||
|
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_OFF)
|
||||||
|
head2_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;
|
||||||
|
|
||||||
|
/* setting up minimum amount to scroll not needed:
|
||||||
|
* Nvidia cards can always do pixelprecise panning on both heads */
|
||||||
|
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);
|
||||||
|
nv_bes_move_overlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put cursor in correct physical position, so stay onscreen (rel. to CRTC) */
|
||||||
|
if (x > (hds + si->cursor.hot_x)) x -= (hds + si->cursor.hot_x);
|
||||||
|
else x = 0;
|
||||||
|
if (y > (vds + si->cursor.hot_y)) y -= (vds + si->cursor.hot_y);
|
||||||
|
else y = 0;
|
||||||
|
|
||||||
|
/* position the cursor on the display */
|
||||||
|
switch (si->dm.flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_CLONE:
|
||||||
|
head1_cursor_position(x,y);
|
||||||
|
head2_cursor_position(x,y);
|
||||||
|
break;
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
if (x < si->dm.timing.h_display)
|
||||||
|
{
|
||||||
|
if (si->cursor.dh_right)
|
||||||
|
{
|
||||||
|
LOG(4,("MOVE_CURSOR: now on left side\n"));
|
||||||
|
head2_cursor_hide();
|
||||||
|
head1_cursor_show();
|
||||||
|
si->cursor.dh_right = false;
|
||||||
|
}
|
||||||
|
head1_cursor_position(x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!si->cursor.dh_right)
|
||||||
|
{
|
||||||
|
LOG(4,("MOVE_CURSOR: now on right side\n"));
|
||||||
|
head1_cursor_hide();
|
||||||
|
head2_cursor_show();
|
||||||
|
si->cursor.dh_right = true;
|
||||||
|
}
|
||||||
|
head2_cursor_position((x - si->dm.timing.h_display), y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* singlehead mode */
|
||||||
|
head1_cursor_position(x,y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHOW_CURSOR(bool is_visible)
|
||||||
|
{
|
||||||
|
/* record for our info */
|
||||||
|
si->cursor.is_visible = is_visible;
|
||||||
|
|
||||||
|
switch (si->dm.flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_CLONE:
|
||||||
|
if (is_visible)
|
||||||
|
{
|
||||||
|
head1_cursor_show();
|
||||||
|
head2_cursor_show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head1_cursor_hide();
|
||||||
|
head2_cursor_hide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
if (is_visible)
|
||||||
|
{
|
||||||
|
if (!si->cursor.dh_right)
|
||||||
|
{
|
||||||
|
head1_cursor_show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head2_cursor_show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head1_cursor_hide();
|
||||||
|
head2_cursor_hide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* singlehead mode */
|
||||||
|
if (is_visible)
|
||||||
|
{
|
||||||
|
head1_cursor_show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head1_cursor_hide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
|
||||||
|
other authors:
|
||||||
|
Mark Watson
|
||||||
|
Rudolf Cornelissen 3/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x10000000
|
||||||
|
|
||||||
|
#include "acc_std.h"
|
||||||
|
|
||||||
|
|
||||||
|
static engine_token nv_engine_token = { 1, B_2D_ACCELERATION, NULL };
|
||||||
|
|
||||||
|
uint32 ACCELERANT_ENGINE_COUNT(void)
|
||||||
|
{
|
||||||
|
/* we have one acceleration engine */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/*wait for the engine to be totally idle*/
|
||||||
|
nv_acc_wait_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st)
|
||||||
|
{
|
||||||
|
/* engine count will always be zero: we don't support syncing to token (yet) */
|
||||||
|
st->engine_id = et->engine_id;
|
||||||
|
st->counter = si->engine.count;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t SYNC_TO_TOKEN(sync_token *st)
|
||||||
|
{
|
||||||
|
/* wait until the engine is totally idle: we don't support syncing to token (yet) */
|
||||||
|
/* note:
|
||||||
|
* AFAIK in order to be able to setup sync_to_token, we'd need a circular fifo
|
||||||
|
* buffer in (main) memory instead of directly programming the GPU fifo so we
|
||||||
|
* can tell (via a hardware maintained pointer into this circular fifo) where
|
||||||
|
* the acc engine is with executing commands! */
|
||||||
|
WAIT_ENGINE_IDLE();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
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/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all supported cards have a bes */
|
||||||
|
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t check_acc_capability(uint32 feature)
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
break;
|
||||||
|
case B_INVERT_RECTANGLE:
|
||||||
|
msg = "B_INVERT_RECTANGLE";
|
||||||
|
break;
|
||||||
|
case B_FILL_SPAN:
|
||||||
|
msg = "B_FILL_SPAN";
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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,99 @@
|
|||||||
|
/*
|
||||||
|
Author:
|
||||||
|
Rudolf Cornelissen 7/2004-11/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x04000000
|
||||||
|
|
||||||
|
#include "acc_std.h"
|
||||||
|
|
||||||
|
/* Get some info about the device */
|
||||||
|
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi)
|
||||||
|
{
|
||||||
|
LOG(4,("GET_ACCELERANT_DEVICE_INFO: returning info\n"));
|
||||||
|
|
||||||
|
/* no info on version is provided, so presumably this is for my info */
|
||||||
|
adi->version = 1;
|
||||||
|
|
||||||
|
sprintf(adi->name, "nVidia chipset");
|
||||||
|
switch (si->ps.card_type)
|
||||||
|
{
|
||||||
|
case NV04:
|
||||||
|
sprintf(adi->chipset, "NV04");
|
||||||
|
break;
|
||||||
|
case NV05:
|
||||||
|
sprintf(adi->chipset, "NV05");
|
||||||
|
break;
|
||||||
|
case NV05M64:
|
||||||
|
sprintf(adi->chipset, "NV05 model 64");
|
||||||
|
break;
|
||||||
|
case NV06:
|
||||||
|
sprintf(adi->chipset, "NV06");
|
||||||
|
break;
|
||||||
|
case NV10:
|
||||||
|
sprintf(adi->chipset, "NV10");
|
||||||
|
break;
|
||||||
|
case NV11:
|
||||||
|
case NV11M:
|
||||||
|
sprintf(adi->chipset, "NV11");
|
||||||
|
break;
|
||||||
|
case NV15:
|
||||||
|
sprintf(adi->chipset, "NV15");
|
||||||
|
break;
|
||||||
|
case NV17:
|
||||||
|
case NV17M:
|
||||||
|
sprintf(adi->chipset, "NV17");
|
||||||
|
break;
|
||||||
|
case NV18:
|
||||||
|
case NV18M:
|
||||||
|
sprintf(adi->chipset, "NV18");
|
||||||
|
break;
|
||||||
|
case NV20:
|
||||||
|
sprintf(adi->chipset, "NV20");
|
||||||
|
break;
|
||||||
|
case NV25:
|
||||||
|
sprintf(adi->chipset, "NV25");
|
||||||
|
break;
|
||||||
|
case NV28:
|
||||||
|
sprintf(adi->chipset, "NV28");
|
||||||
|
break;
|
||||||
|
case NV30:
|
||||||
|
sprintf(adi->chipset, "NV30");
|
||||||
|
break;
|
||||||
|
case NV31:
|
||||||
|
sprintf(adi->chipset, "NV31");
|
||||||
|
break;
|
||||||
|
case NV34:
|
||||||
|
sprintf(adi->chipset, "NV34");
|
||||||
|
break;
|
||||||
|
case NV35:
|
||||||
|
sprintf(adi->chipset, "NV35");
|
||||||
|
break;
|
||||||
|
case NV36:
|
||||||
|
sprintf(adi->chipset, "NV36");
|
||||||
|
break;
|
||||||
|
case NV38:
|
||||||
|
sprintf(adi->chipset, "NV38");
|
||||||
|
break;
|
||||||
|
case NV40:
|
||||||
|
sprintf(adi->chipset, "NV40");
|
||||||
|
break;
|
||||||
|
case NV41:
|
||||||
|
sprintf(adi->chipset, "NV41");
|
||||||
|
break;
|
||||||
|
case NV43:
|
||||||
|
sprintf(adi->chipset, "NV43");
|
||||||
|
break;
|
||||||
|
case NV45:
|
||||||
|
sprintf(adi->chipset, "NV45");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprintf(adi->chipset, "unknown");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sprintf(adi->serial_no, "unknown");
|
||||||
|
adi->memory = si->ps.memory_size;
|
||||||
|
adi->dac_speed = si->ps.max_dac1_clock;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
|
||||||
|
Other authors:
|
||||||
|
Mark Watson
|
||||||
|
Rudolf Cornelissen 9/2002-5/2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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. */
|
||||||
|
/* NOTE:
|
||||||
|
* Due to BeOS constraints output for all heads will be limited to the head with
|
||||||
|
* the least capabilities. */
|
||||||
|
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:
|
||||||
|
* using decondary DAC specs because they could be narrower (twinview) */
|
||||||
|
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: depends on which head is used as primary head */
|
||||||
|
if (!si->ps.crtc2_prim)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
max_pclk = si->ps.max_dac2_clock_32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* use fail-safe value */
|
||||||
|
max_pclk = si->ps.max_dac2_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,33 @@
|
|||||||
|
/*
|
||||||
|
Author:
|
||||||
|
Rudolf Cornelissen 7/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x01000000
|
||||||
|
|
||||||
|
#include "acc_std.h"
|
||||||
|
|
||||||
|
/* Used to help generate mode lines */
|
||||||
|
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc)
|
||||||
|
{
|
||||||
|
LOG(4, ("GET_TIMING_CONSTRAINTS: returning info\n"));
|
||||||
|
|
||||||
|
/* specs are identical for all nVidia cards */
|
||||||
|
dtc->h_res = 8;
|
||||||
|
dtc->h_sync_min = 8;
|
||||||
|
dtc->h_sync_max = 248;
|
||||||
|
/* Note:
|
||||||
|
* h_blank info is used to determine the max. diff. between h_total and h_display! */
|
||||||
|
dtc->h_blank_min = 8;
|
||||||
|
dtc->h_blank_max = 1016;
|
||||||
|
|
||||||
|
dtc->v_res = 1;
|
||||||
|
dtc->v_sync_min = 1;
|
||||||
|
dtc->v_sync_max = 15;
|
||||||
|
/* Note:
|
||||||
|
* v_blank info is used to determine the max. diff. between v_total and v_display! */
|
||||||
|
dtc->v_blank_min = 1;
|
||||||
|
dtc->v_blank_max = 255;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
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/2004.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00800000
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "acc_std.h"
|
||||||
|
|
||||||
|
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, switchhead %d, force_pci %d\n",
|
||||||
|
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead, si->settings.force_pci));
|
||||||
|
LOG(4,("init_common: dumprom %d, unhide_fw %d, pgm_panel %d\n",
|
||||||
|
si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel));
|
||||||
|
|
||||||
|
/*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 (0) {
|
||||||
|
time_t now = time (NULL);
|
||||||
|
// LOG not available from here to next LOG: NULL si
|
||||||
|
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;
|
||||||
|
si->cursor.dh_right = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* note that overlay is not in use (for nv_bes_move_overlay()) */
|
||||||
|
si->overlay.active = false;
|
||||||
|
|
||||||
|
/* bail out if something failed */
|
||||||
|
if (result != B_OK) goto error1;
|
||||||
|
|
||||||
|
/* initialise various cursor stuff */
|
||||||
|
head1_cursor_init();
|
||||||
|
if (si->ps.secondary_head) head2_cursor_init();
|
||||||
|
|
||||||
|
/* ensure cursor state */
|
||||||
|
head1_cursor_hide();
|
||||||
|
if (si->ps.secondary_head) head2_cursor_hide();
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* we can't use LOG because we didn't get the shared_info struct.. */
|
||||||
|
char fname[64];
|
||||||
|
FILE *myhand = NULL;
|
||||||
|
|
||||||
|
sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
|
||||||
|
myhand=fopen(fname,"a+");
|
||||||
|
fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
|
||||||
|
fclose(myhand);
|
||||||
|
|
||||||
|
/* abort with resultcode from open attempt on kerneldriver */
|
||||||
|
result = fd;
|
||||||
|
goto error0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* note that we're a clone accelerant */
|
||||||
|
accelerantIsClone = 1;
|
||||||
|
|
||||||
|
/* call the shared initialization code */
|
||||||
|
result = init_common(fd);
|
||||||
|
|
||||||
|
/* setup CRTC and DAC functions access */
|
||||||
|
setup_virtualized_heads(si->crtc_switch_mode);
|
||||||
|
|
||||||
|
/* 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 benaphores ONLY if we are the primary accelerant */
|
||||||
|
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,29 @@
|
|||||||
|
SubDir OBOS_TOP src add-ons accelerants skeleton ;
|
||||||
|
|
||||||
|
UsePrivateHeaders graphics ;
|
||||||
|
UsePrivateHeaders [ FDirName graphics skeleton ] ;
|
||||||
|
UseHeaders [ FDirName $(SUBDIR) engine ] ;
|
||||||
|
|
||||||
|
|
||||||
|
Addon skel.accelerant : accelerants :
|
||||||
|
Acceleration.c
|
||||||
|
Cursor.c
|
||||||
|
EngineManagment.c
|
||||||
|
GetAccelerantHook.c
|
||||||
|
GetDeviceInfo.c
|
||||||
|
GetModeInfo.c
|
||||||
|
GetTimingConstraints.c
|
||||||
|
InitAccelerant.c
|
||||||
|
Overlay.c
|
||||||
|
ProposeDisplayMode.c
|
||||||
|
SetDisplayMode.c
|
||||||
|
: false : libnvidia_engine.a
|
||||||
|
;
|
||||||
|
|
||||||
|
Package haiku-skeleton-cvs :
|
||||||
|
skel.accelerant :
|
||||||
|
boot home config add-ons accelerants ;
|
||||||
|
|
||||||
|
Depends skel.accelerant : skel.driver ;
|
||||||
|
|
||||||
|
SubInclude OBOS_TOP src add-ons accelerants skeleton engine ;
|
||||||
@@ -0,0 +1,612 @@
|
|||||||
|
/* Written by Rudolf Cornelissen 05/2002-9/2004 */
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assuming interlaced VGA is not supported */
|
||||||
|
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 are supported for the current overlaybitmap colorspace */
|
||||||
|
switch (a_color_space)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
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 = %3.3fMb\n",(si->ps.memory_size / (1024.0 * 1024.0))));
|
||||||
|
|
||||||
|
/* 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:
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* check if slopspace is needed: RIVA128 and TNT need ~0x000f. */
|
||||||
|
si->overlay.myBuffer[offset].width = ((width + 0x000f) & ~0x000f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* check if slopspace is needed: GeForce need ~0x001f. */
|
||||||
|
/* fixme:
|
||||||
|
* update needed for GF DVDmax support to adhere to CRTC2 constraints?? */
|
||||||
|
si->overlay.myBuffer[offset].width = ((width + 0x001f) & ~0x001f);
|
||||||
|
}
|
||||||
|
si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
|
||||||
|
|
||||||
|
/* check if the requested horizontal pitch is supported: */
|
||||||
|
//fixme: tune for GF and TNT...
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
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) */
|
||||||
|
adress = (((uint32)((uint8*)si->framebuffer_pci)) + si->ps.memory_size);
|
||||||
|
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:
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* RIVA128 and TNT need 15.
|
||||||
|
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
|
||||||
|
oc->view.width_alignment = 15;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* GeForce need 31.
|
||||||
|
* 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;
|
||||||
|
/* GeForce cards can output upto and including 2046 pixels in width */
|
||||||
|
//fixme: how about TNT?
|
||||||
|
if (dm->virtual_width > 2046)
|
||||||
|
{
|
||||||
|
oc->window.width.max = 2046;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oc->window.width.max = dm->virtual_width;
|
||||||
|
}
|
||||||
|
oc->window.height.min = 2;
|
||||||
|
/* GeForce cards can output upto and including 2046 pixels in height */
|
||||||
|
//fixme: how about TNT?
|
||||||
|
if (dm->virtual_height > 2046)
|
||||||
|
{
|
||||||
|
oc->window.height.max = 2046;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oc->window.height.max = dm->virtual_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GeForce scaling restrictions */
|
||||||
|
switch (si->ps.card_arch)
|
||||||
|
{
|
||||||
|
case NV04A:
|
||||||
|
/* Riva128-TNT2 series have an old BES engine... */
|
||||||
|
oc->h_scale.min = 1.0;
|
||||||
|
oc->v_scale.min = 1.0;
|
||||||
|
break;
|
||||||
|
case NV30A:
|
||||||
|
case NV40A:
|
||||||
|
/* GeForceFX series and up have a new BES engine... */
|
||||||
|
oc->h_scale.min = 0.5;
|
||||||
|
oc->v_scale.min = 0.5;
|
||||||
|
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
|
||||||
|
* So let it fall through... */
|
||||||
|
if (si->ps.card_type != NV31) break;
|
||||||
|
default:
|
||||||
|
/* the rest in between... */
|
||||||
|
oc->h_scale.min = 0.125;
|
||||||
|
oc->v_scale.min = 0.125;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
|
||||||
|
oc->h_scale.max = 8.0;
|
||||||
|
oc->v_scale.max = 8.0;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* program overlay hardware */
|
||||||
|
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,597 @@
|
|||||||
|
/*
|
||||||
|
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-10/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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,
|
||||||
|
* plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
|
||||||
|
* panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
|
||||||
|
static const display_mode mode_list[] = {
|
||||||
|
/* 4:3 modes; 307.2k pixels */
|
||||||
|
{ { 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) */
|
||||||
|
/* 4:3 modes; 480k pixels */
|
||||||
|
{ { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) from Be, Inc. driver + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
/* 4:3 modes; 786.432k pixels */
|
||||||
|
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */
|
||||||
|
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
/* 4:3 modes; 995.328k pixels */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
|
||||||
|
/* 5:4 modes; 1.311M pixels */
|
||||||
|
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024) from Be, Inc. driver + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
/* 4:3 panel mode; 1.47M pixels */
|
||||||
|
{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
|
||||||
|
/* 4:3 modes; 1.92M pixels */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
/* identical lines to above one, apart from refreshrate.. */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
{ { 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) + XFree86 */
|
||||||
|
/* end identical lines. */
|
||||||
|
/* 4:3 modes; 2.408M pixels */
|
||||||
|
{ { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) from Be, Inc. driver + XFree86 */
|
||||||
|
{ { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) from Be, Inc. driver + XFree86 */
|
||||||
|
/* 4:3 modes; 2.584M pixels */
|
||||||
|
{ { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) from Be, Inc. driver + XFree86 */
|
||||||
|
{ { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) from Be, Inc. driver + XFree86 */
|
||||||
|
/* 4:3 modes; 2.765M pixels */
|
||||||
|
{ { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1440) from Be, Inc. driver + XFree86 */
|
||||||
|
{ { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1920X1440) from Be, Inc. driver + XFree86 */
|
||||||
|
/* 4:3 modes; 3.146M pixels */
|
||||||
|
{ { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* From XFree86 posting @60Hz + XFree86 */
|
||||||
|
/* 16:10 panel mode; 400k pixels */
|
||||||
|
{ { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X500) */
|
||||||
|
/* 16:10 panel mode; 655.36k pixels */
|
||||||
|
{ { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X640) */
|
||||||
|
/* 16:10 panel-TV mode; 983.04k pixels */
|
||||||
|
{ { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X768) */
|
||||||
|
/* 16:10 panel mode; 1.024M pixels */
|
||||||
|
{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */
|
||||||
|
/* 16:10 panel mode; 1.296M pixels */
|
||||||
|
{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
|
||||||
|
/* 16:10 panel mode; 1.764M pixels */
|
||||||
|
{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
|
||||||
|
/* 16:10 panel mode; 2.304M pixels */
|
||||||
|
{ { 193200, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
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, target_aspect;
|
||||||
|
uint8 m,n,p, bpp;
|
||||||
|
status_t result;
|
||||||
|
uint32 max_vclk, row_bytes, pointer_reservation;
|
||||||
|
bool acc_mode;
|
||||||
|
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 = head1_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if all connected output devices can display the requested mode's aspect: */
|
||||||
|
/* calculate display mode aspect */
|
||||||
|
target_aspect = (target->timing.h_display / ((float)target->timing.v_display));
|
||||||
|
/* NOTE:
|
||||||
|
* allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
|
||||||
|
switch (si->ps.monitors)
|
||||||
|
{
|
||||||
|
case 0x01: /* digital panel on head 1, nothing on head 2 */
|
||||||
|
if (si->ps.panel1_aspect < (target_aspect - 0.10))
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: connected panel1 is not widescreen type, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x10: /* nothing on head 1, digital panel on head 2 */
|
||||||
|
if (si->ps.panel2_aspect < (target_aspect - 0.10))
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: connected panel2 is not widescreen type, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x11: /* digital panels on both heads */
|
||||||
|
if ((si->ps.panel1_aspect < (target_aspect - 0.10)) ||
|
||||||
|
(si->ps.panel2_aspect < (target_aspect - 0.10)))
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: not all connected panels are widescreen type, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* at least one analog monitor is connected, or nothing detected at all */
|
||||||
|
if (target_aspect > 1.34)
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only export widescreen panel-TV modes when an exact resolution match exists,
|
||||||
|
* to prevent the modelist from becoming too crowded */
|
||||||
|
if (target_aspect > 1.61)
|
||||||
|
{
|
||||||
|
status_t panel_TV_stat = B_ERROR;
|
||||||
|
|
||||||
|
if (si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
if ((target->timing.h_display == si->ps.p1_timing.h_display) &&
|
||||||
|
(target->timing.v_display == si->ps.p1_timing.v_display))
|
||||||
|
{
|
||||||
|
panel_TV_stat = B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
if ((target->timing.h_display == si->ps.p2_timing.h_display) &&
|
||||||
|
(target->timing.v_display == si->ps.p2_timing.v_display))
|
||||||
|
{
|
||||||
|
panel_TV_stat = B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (panel_TV_stat != B_OK)
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: WS panel_TV mode requested but no such TV here, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if panel(s) can display the requested resolution (if connected) */
|
||||||
|
if (si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
if ((target->timing.h_display > si->ps.p1_timing.h_display) ||
|
||||||
|
(target->timing.v_display > si->ps.p1_timing.v_display))
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: panel1 can't display requested resolution, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
if ((target->timing.h_display > si->ps.p2_timing.h_display) ||
|
||||||
|
(target->timing.v_display > si->ps.p2_timing.v_display))
|
||||||
|
{
|
||||||
|
LOG(4, ("PROPOSEMODE: panel2 can't display requested resolution, aborted.\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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, &acc_mode);
|
||||||
|
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 = head1_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 - pointer_reservation))
|
||||||
|
{
|
||||||
|
target->virtual_height =
|
||||||
|
(si->ps.memory_size - 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. */
|
||||||
|
/* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables
|
||||||
|
* BDirectWindow windowed modes. */
|
||||||
|
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;
|
||||||
|
bpp = 1;
|
||||||
|
break;
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
max_vclk = si->ps.max_dac2_clock_16;
|
||||||
|
bpp = 2;
|
||||||
|
break;
|
||||||
|
case B_RGB24_LITTLE:
|
||||||
|
max_vclk = si->ps.max_dac2_clock_24;
|
||||||
|
bpp = 3;
|
||||||
|
break;
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
max_vclk = si->ps.max_dac2_clock_32dh;
|
||||||
|
bpp = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* use fail-safe value */
|
||||||
|
max_vclk = si->ps.max_dac2_clock_32dh;
|
||||||
|
bpp = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set DUALHEAD_CAPABLE if suitable */
|
||||||
|
//fixme: update for independant secondary head use! (reserve fixed memory then)
|
||||||
|
if (si->ps.secondary_head && (target->timing.pixel_clock <= (max_vclk * 1000)))
|
||||||
|
{
|
||||||
|
switch (target->flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
if (((si->ps.memory_size - pointer_reservation) >=
|
||||||
|
(row_bytes * target->virtual_height)) &&
|
||||||
|
((uint16)(row_bytes / bpp) >= (target->timing.h_display * 2)))
|
||||||
|
{
|
||||||
|
target->flags |= DUALHEAD_CAPABLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DUALHEAD_CLONE:
|
||||||
|
if ((si->ps.memory_size - pointer_reservation) >=
|
||||||
|
(row_bytes * target->virtual_height))
|
||||||
|
{
|
||||||
|
target->flags |= DUALHEAD_CAPABLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DUALHEAD_OFF:
|
||||||
|
if ((si->ps.memory_size - pointer_reservation) >=
|
||||||
|
(row_bytes * target->virtual_height * 2))
|
||||||
|
{
|
||||||
|
target->flags |= DUALHEAD_CAPABLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 sync_on_green not avaible. */
|
||||||
|
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | 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,517 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
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-4/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
bool display, h, v;
|
||||||
|
// bool crt1, crt2, cross;
|
||||||
|
|
||||||
|
/* 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) */
|
||||||
|
head1_dpms_fetch(&display, &h, &v);
|
||||||
|
head1_dpms(false, false, false);
|
||||||
|
if (si->ps.secondary_head) head2_dpms(false, false, false);
|
||||||
|
|
||||||
|
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
|
||||||
|
startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
|
||||||
|
|
||||||
|
/* calculate and set new mode bytes_per_row */
|
||||||
|
nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
|
||||||
|
|
||||||
|
/*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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* detect which connectors have a CRT connected */
|
||||||
|
//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
|
||||||
|
//or make it work with digital panels connected as well.
|
||||||
|
// crt1 = nv_dac_crt_connected();
|
||||||
|
// crt2 = nv_dac2_crt_connected();
|
||||||
|
/* connect outputs 'straight-through' */
|
||||||
|
// if (crt1)
|
||||||
|
// {
|
||||||
|
/* connector1 is used as primary output */
|
||||||
|
// cross = false;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (crt2)
|
||||||
|
/* connector2 is used as primary output */
|
||||||
|
// cross = true;
|
||||||
|
// else
|
||||||
|
/* no CRT detected: assume connector1 is used as primary output */
|
||||||
|
// cross = false;
|
||||||
|
// }
|
||||||
|
/* set output connectors assignment if possible */
|
||||||
|
if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
|
||||||
|
/* invert output assignment in switch mode */
|
||||||
|
nv_general_head_select(true);
|
||||||
|
else
|
||||||
|
nv_general_head_select(false);
|
||||||
|
|
||||||
|
/* set the pixel clock PLL(s) */
|
||||||
|
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
|
||||||
|
if (head1_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 (head2_set_pix_pll(target2) == B_ERROR)
|
||||||
|
LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set the colour depth for CRTC1 and the DAC */
|
||||||
|
switch(target.space)
|
||||||
|
{
|
||||||
|
case B_CMAP8:
|
||||||
|
colour_depth1 = 8;
|
||||||
|
head1_mode(BPP8, 1.0);
|
||||||
|
head1_depth(BPP8);
|
||||||
|
break;
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
colour_depth1 = 16;
|
||||||
|
head1_mode(BPP15, 1.0);
|
||||||
|
head1_depth(BPP15);
|
||||||
|
break;
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
colour_depth1 = 16;
|
||||||
|
head1_mode(BPP16, 1.0);
|
||||||
|
head1_depth(BPP16);
|
||||||
|
break;
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
colour_depth1 = 32;
|
||||||
|
head1_mode(BPP32, 1.0);
|
||||||
|
head1_depth(BPP32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*set the colour depth for CRTC2 and DAC2 */
|
||||||
|
switch(target2.space)
|
||||||
|
{
|
||||||
|
case B_CMAP8:
|
||||||
|
colour_depth2 = 8;
|
||||||
|
head2_mode(BPP8, 1.0);
|
||||||
|
head2_depth(BPP8);
|
||||||
|
break;
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
colour_depth2 = 16;
|
||||||
|
head2_mode(BPP15, 1.0);
|
||||||
|
head2_depth(BPP15);
|
||||||
|
break;
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
colour_depth2 = 16;
|
||||||
|
head2_mode(BPP16, 1.0);
|
||||||
|
head2_depth(BPP16);
|
||||||
|
break;
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
colour_depth2 = 32;
|
||||||
|
head2_mode(BPP32, 1.0);
|
||||||
|
head2_depth(BPP32);
|
||||||
|
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*/
|
||||||
|
head1_set_display_pitch ();
|
||||||
|
//fixme: seperate for real dualhead modes:
|
||||||
|
//we need a secondary si->fbc!
|
||||||
|
head2_set_display_pitch ();
|
||||||
|
|
||||||
|
/*work out where the "right" screen starts*/
|
||||||
|
startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
|
||||||
|
|
||||||
|
/* Tell card what memory to display */
|
||||||
|
switch (target.flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
head1_set_display_start(startadd,colour_depth1);
|
||||||
|
head2_set_display_start(startadd_right,colour_depth2);
|
||||||
|
break;
|
||||||
|
case DUALHEAD_CLONE:
|
||||||
|
head1_set_display_start(startadd,colour_depth1);
|
||||||
|
head2_set_display_start(startadd,colour_depth2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the timing */
|
||||||
|
head1_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 = head2_set_timing(target2);
|
||||||
|
|
||||||
|
/* TVout support: setup CRTC2 and it's pixelclock */
|
||||||
|
if (si->ps.tvout && (target2.flags & TV_BITS)) maventv_init(target2);
|
||||||
|
}
|
||||||
|
else /* single head mode */
|
||||||
|
{
|
||||||
|
status_t status;
|
||||||
|
int colour_mode = BPP32;
|
||||||
|
|
||||||
|
/* connect output */
|
||||||
|
if (si->ps.secondary_head)
|
||||||
|
{
|
||||||
|
/* detect which connectors have a CRT connected */
|
||||||
|
//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
|
||||||
|
//or make it work with digital panels connected as well.
|
||||||
|
// crt1 = nv_dac_crt_connected();
|
||||||
|
// crt2 = nv_dac2_crt_connected();
|
||||||
|
/* connect outputs 'straight-through' */
|
||||||
|
// if (crt1)
|
||||||
|
// {
|
||||||
|
/* connector1 is used as primary output */
|
||||||
|
// cross = false;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (crt2)
|
||||||
|
/* connector2 is used as primary output */
|
||||||
|
// cross = true;
|
||||||
|
// else
|
||||||
|
/* no CRT detected: assume connector1 is used as primary output */
|
||||||
|
// cross = false;
|
||||||
|
// }
|
||||||
|
/* set output connectors assignment if possible */
|
||||||
|
nv_general_head_select(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = head1_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 */
|
||||||
|
head1_depth(colour_mode);
|
||||||
|
/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
|
||||||
|
head1_mode(colour_mode,1.0);
|
||||||
|
|
||||||
|
/* set the display pitch */
|
||||||
|
head1_set_display_pitch();
|
||||||
|
|
||||||
|
/* tell the card what memory to display */
|
||||||
|
head1_set_display_start(startadd,colour_depth1);
|
||||||
|
|
||||||
|
/* set the timing */
|
||||||
|
head1_set_timing(target);
|
||||||
|
|
||||||
|
//fixme: shut-off the videoPLL if it exists...
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update driver's mode store */
|
||||||
|
si->dm = target;
|
||||||
|
|
||||||
|
/* turn screen one on */
|
||||||
|
head1_dpms(display, h, v);
|
||||||
|
/* turn screen two on if a dualhead mode is active */
|
||||||
|
if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v);
|
||||||
|
|
||||||
|
/* set up acceleration for this mode */
|
||||||
|
nv_acc_init();
|
||||||
|
/* set up overlay unit for this mode */
|
||||||
|
nv_bes_init();
|
||||||
|
|
||||||
|
LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
|
||||||
|
|
||||||
|
/* enable interrupts using the kernel driver */
|
||||||
|
interrupt_enable(true);
|
||||||
|
|
||||||
|
/* optimize memory-access if needed */
|
||||||
|
// head1_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));
|
||||||
|
|
||||||
|
/* nVidia cards support pixelprecise panning on both heads in all modes:
|
||||||
|
* No stepping granularity needed! */
|
||||||
|
|
||||||
|
/* determine bits used for the colordepth */
|
||||||
|
switch(si->dm.space)
|
||||||
|
{
|
||||||
|
case B_CMAP8:
|
||||||
|
colour_depth=8;
|
||||||
|
break;
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
colour_depth=16;
|
||||||
|
break;
|
||||||
|
case B_RGB24_LITTLE:
|
||||||
|
colour_depth=24;
|
||||||
|
break;
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
colour_depth=32;
|
||||||
|
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 += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
|
||||||
|
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
|
||||||
|
|
||||||
|
interrupt_enable(false);
|
||||||
|
|
||||||
|
switch (si->dm.flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
head1_set_display_start(startadd,colour_depth);
|
||||||
|
head2_set_display_start(startadd_right,colour_depth);
|
||||||
|
break;
|
||||||
|
case DUALHEAD_OFF:
|
||||||
|
head1_set_display_start(startadd,colour_depth);
|
||||||
|
break;
|
||||||
|
case DUALHEAD_CLONE:
|
||||||
|
head1_set_display_start(startadd,colour_depth);
|
||||||
|
head2_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++;
|
||||||
|
}
|
||||||
|
head1_palette(r,g,b);
|
||||||
|
if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
head1_dpms(true, true, true);
|
||||||
|
if (si->ps.secondary_head) head2_dpms(true, true, true);
|
||||||
|
break;
|
||||||
|
case B_DPMS_STAND_BY:
|
||||||
|
head1_dpms(false, false, true);
|
||||||
|
if (si->ps.secondary_head) head2_dpms(false, false, true);
|
||||||
|
break;
|
||||||
|
case B_DPMS_SUSPEND:
|
||||||
|
head1_dpms(false, true, false);
|
||||||
|
if (si->ps.secondary_head) head2_dpms(false, true, false);
|
||||||
|
break;
|
||||||
|
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||||
|
head1_dpms(false, false, false);
|
||||||
|
if (si->ps.secondary_head) head2_dpms(false, false, false);
|
||||||
|
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 */
|
||||||
|
head1_dpms(true, true, true);
|
||||||
|
break;
|
||||||
|
case B_DPMS_STAND_BY:
|
||||||
|
head1_dpms(false, false, true);
|
||||||
|
break;
|
||||||
|
case B_DPMS_SUSPEND:
|
||||||
|
head1_dpms(false, true, false);
|
||||||
|
break;
|
||||||
|
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||||
|
head1_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);
|
||||||
|
head1_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 "nv_globals.h"
|
||||||
|
//apsed #include "nv_extern.h"
|
||||||
|
#include "nv_proto.h"
|
||||||
|
#include "be_driver_proto.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(GENERIC_H)
|
||||||
|
#define GENERIC_H
|
||||||
|
|
||||||
|
#include <Accelerant.h>
|
||||||
|
#include "video_overlay.h"
|
||||||
|
|
||||||
|
#define DEBUG 1
|
||||||
|
|
||||||
|
status_t INIT_ACCELERANT(int fd);
|
||||||
|
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
|
||||||
|
void GET_ACCELERANT_CLONE_INFO(void *data);
|
||||||
|
status_t CLONE_ACCELERANT(void *data);
|
||||||
|
void UNINIT_ACCELERANT(void);
|
||||||
|
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
|
||||||
|
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
|
||||||
|
|
||||||
|
uint32 ACCELERANT_MODE_COUNT(void);
|
||||||
|
status_t GET_MODE_LIST(display_mode *dm);
|
||||||
|
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
|
||||||
|
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
|
||||||
|
status_t GET_DISPLAY_MODE(display_mode *current_mode);
|
||||||
|
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
|
||||||
|
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
|
||||||
|
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
|
||||||
|
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
|
||||||
|
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
|
||||||
|
|
||||||
|
uint32 DPMS_CAPABILITIES(void);
|
||||||
|
uint32 DPMS_MODE(void);
|
||||||
|
status_t SET_DPMS_MODE(uint32 dpms_flags);
|
||||||
|
|
||||||
|
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
|
||||||
|
void MOVE_CURSOR(uint16 x, uint16 y);
|
||||||
|
void SHOW_CURSOR(bool is_visible);
|
||||||
|
|
||||||
|
uint32 ACCELERANT_ENGINE_COUNT(void);
|
||||||
|
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
|
||||||
|
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
|
||||||
|
void WAIT_ENGINE_IDLE(void);
|
||||||
|
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
|
||||||
|
status_t SYNC_TO_TOKEN(sync_token *st);
|
||||||
|
|
||||||
|
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
|
||||||
|
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count);
|
||||||
|
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count);
|
||||||
|
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||||
|
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
|
||||||
|
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
|
||||||
|
|
||||||
|
/* video_overlay */
|
||||||
|
uint32 OVERLAY_COUNT(const display_mode *dm);
|
||||||
|
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm);
|
||||||
|
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space);
|
||||||
|
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height);
|
||||||
|
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob);
|
||||||
|
status_t GET_OVERLAY_CONSTRAINTS(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc);
|
||||||
|
overlay_token ALLOCATE_OVERLAY(void);
|
||||||
|
status_t RELEASE_OVERLAY(overlay_token ot);
|
||||||
|
status_t CONFIGURE_OVERLAY(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov);
|
||||||
|
|
||||||
|
status_t create_mode_list(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
SubDir OBOS_TOP src add-ons accelerants skeleton engine ;
|
||||||
|
|
||||||
|
UsePrivateHeaders graphics ;
|
||||||
|
UsePrivateHeaders [ FDirName graphics skeleton ] ;
|
||||||
|
|
||||||
|
StaticLibrary skeleton_engine :
|
||||||
|
acc.c
|
||||||
|
bes.c
|
||||||
|
brooktreetv.c
|
||||||
|
crtc.c
|
||||||
|
crtc2.c
|
||||||
|
dac.c
|
||||||
|
dac2.c
|
||||||
|
general.c
|
||||||
|
agp.c
|
||||||
|
globals.c
|
||||||
|
i2c.c
|
||||||
|
info.c
|
||||||
|
support.c
|
||||||
|
;
|
||||||
@@ -0,0 +1,888 @@
|
|||||||
|
/* NV Acceleration functions */
|
||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 8/2003-9/2004.
|
||||||
|
|
||||||
|
This code was possible thanks to the Linux NV driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t nv_acc_wait_idle()
|
||||||
|
{
|
||||||
|
/* wait until engine completely idle */
|
||||||
|
while (ACCR(STATUS))
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AFAIK this must be done for every new screenmode.
|
||||||
|
* Engine required init. */
|
||||||
|
status_t nv_acc_init()
|
||||||
|
{
|
||||||
|
uint16 cnt;
|
||||||
|
|
||||||
|
/* setup PTIMER: */
|
||||||
|
//fixme? how about NV28 setup as just after coldstarting? (see nv_info.c)
|
||||||
|
/* set timer numerator to 8 (in b0-15) */
|
||||||
|
ACCW(PT_NUMERATOR, 0x00000008);
|
||||||
|
/* set timer denominator to 3 (in b0-15) */
|
||||||
|
ACCW(PT_DENOMINATR, 0x00000003);
|
||||||
|
|
||||||
|
/* disable timer-alarm INT requests (b0) */
|
||||||
|
ACCW(PT_INTEN, 0x00000000);
|
||||||
|
/* reset timer-alarm INT status bit (b0) */
|
||||||
|
ACCW(PT_INTSTAT, 0xffffffff);
|
||||||
|
|
||||||
|
/* enable PRAMIN write access on pre NV10 before programming it! */
|
||||||
|
if (si->ps.card_arch == NV04A)
|
||||||
|
{
|
||||||
|
/* set framebuffer config: type = notiling, PRAMIN write access enabled */
|
||||||
|
NV_REG32(NV32_PFB_CONFIG_0) = 0x00001114;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** PFIFO ***/
|
||||||
|
/* (setup caches) */
|
||||||
|
/* disable caches reassign */
|
||||||
|
ACCW(PF_CACHES, 0x00000000);
|
||||||
|
/* cache1 push0 access disabled */
|
||||||
|
ACCW(PF_CACH1_PSH0, 0x00000000);
|
||||||
|
/* cache1 pull0 access disabled */
|
||||||
|
ACCW(PF_CACH1_PUL0, 0x00000000);
|
||||||
|
/* cache1 push1 mode = pio */
|
||||||
|
ACCW(PF_CACH1_PSH1, 0x00000000);
|
||||||
|
/* cache1 DMA instance adress = 0 (b0-15) */
|
||||||
|
ACCW(PF_CACH1_DMAI, 0x00000000);
|
||||||
|
/* cache0 push0 access disabled */
|
||||||
|
ACCW(PF_CACH0_PSH0, 0x00000000);
|
||||||
|
/* cache0 pull0 access disabled */
|
||||||
|
ACCW(PF_CACH0_PUL0, 0x00000000);
|
||||||
|
/* RAM HT (hash table(?)) baseadress = $10000 (b4-8), size = 4k,
|
||||||
|
* search = 128 (byte offset between hash 'sets'(?)) */
|
||||||
|
/* (note: so(?) HT base is $00710000, last is $00710fff) */
|
||||||
|
ACCW(PF_RAMHT, 0x03000100);
|
||||||
|
/* RAM FC baseadress = $11000 (b3-8) (size is fixed to 0.5k(?)) */
|
||||||
|
/* (note: so(?) FC base is $00711000, last is $007111ff) */
|
||||||
|
ACCW(PF_RAMFC, 0x00000110);
|
||||||
|
/* RAM RO baseadress = $11200 (b1-8), size = 0.5k */
|
||||||
|
/* (note: so(?) RO base is $00711200, last is $007113ff) */
|
||||||
|
/* (note also:
|
||||||
|
* This means(?) the PRAMIN CTX registers are accessible from base $00711400) */
|
||||||
|
ACCW(PF_RAMRO, 0x00000112);
|
||||||
|
/* PFIFO size: ch0-15 = 512 bytes, ch16-31 = 124 bytes */
|
||||||
|
ACCW(PF_SIZE, 0x0000ffff);
|
||||||
|
/* cache1 hash instance = $ffff (b0-15) */
|
||||||
|
ACCW(PF_CACH1_HASH, 0x0000ffff);
|
||||||
|
/* disable all PFIFO INTs */
|
||||||
|
ACCW(PF_INTEN, 0x00000000);
|
||||||
|
/* reset all PFIFO INT status bits */
|
||||||
|
ACCW(PF_INTSTAT, 0xffffffff);
|
||||||
|
/* cache0 pull0 engine = acceleration engine (graphics) */
|
||||||
|
ACCW(PF_CACH0_PUL1, 0x00000001);
|
||||||
|
/* cache1 push0 access enabled */
|
||||||
|
ACCW(PF_CACH1_PSH0, 0x00000001);
|
||||||
|
/* cache1 pull0 access enabled */
|
||||||
|
ACCW(PF_CACH1_PUL0, 0x00000001);
|
||||||
|
/* cache1 pull1 engine = acceleration engine (graphics) */
|
||||||
|
ACCW(PF_CACH1_PUL1, 0x00000001);
|
||||||
|
/* enable PFIFO caches reassign */
|
||||||
|
ACCW(PF_CACHES, 0x00000001);
|
||||||
|
|
||||||
|
/*** PRAMIN ***/
|
||||||
|
/* RAMHT space (hash-table(?)) */
|
||||||
|
/* (first set) */
|
||||||
|
ACCW(HT_HANDL_00, 0x80000010); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_00, 0x80011145); /* instance $1145, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_01, 0x80000011); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_01, 0x80011146); /* instance $1146, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_02, 0x80000012); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_02, 0x80011147); /* instance $1147, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_03, 0x80000013); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_03, 0x80011148); /* instance $1148, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_04, 0x80000014); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_04, 0x80011149); /* instance $1149, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_05, 0x80000015); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_05, 0x8001114a); /* instance $114a, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_06, 0x80000016); /* 32bit handle */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(HT_VALUE_06, 0x80011150); /* instance $1150, engine = acc engine, CHID = $00 */
|
||||||
|
else
|
||||||
|
ACCW(HT_VALUE_06, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */
|
||||||
|
/* (second set) */
|
||||||
|
ACCW(HT_HANDL_10, 0x80000000); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_10, 0x80011142); /* instance $1142, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_11, 0x80000001); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_11, 0x80011143); /* instance $1143, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_12, 0x80000002); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_12, 0x80011144); /* instance $1144, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_13, 0x80000003); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_13, 0x8001114b); /* instance $114b, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_14, 0x80000004); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_14, 0x8001114c); /* instance $114c, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_15, 0x80000005); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_15, 0x8001114d); /* instance $114d, engine = acc engine, CHID = $00 */
|
||||||
|
ACCW(HT_HANDL_16, 0x80000006); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_16, 0x8001114e); /* instance $114e, engine = acc engine, CHID = $00 */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
ACCW(HT_HANDL_17, 0x80000007); /* 32bit handle */
|
||||||
|
ACCW(HT_VALUE_17, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */
|
||||||
|
}
|
||||||
|
/* program CTX registers: CTX1 is mostly done later (colorspace dependant) */
|
||||||
|
/* (setup 'root' set first) */
|
||||||
|
ACCW(PR_CTX0_R, 0x00003000); /* NVclass = NVroot, chromakey and userclip enabled */
|
||||||
|
/* fixme: CTX1_R should reflect RAM amount? (no influence on current used functions) */
|
||||||
|
ACCW(PR_CTX1_R, 0x01ffffff); /* cardmemory mask(?) */
|
||||||
|
ACCW(PR_CTX2_R, 0x00000002); /* ??? */
|
||||||
|
ACCW(PR_CTX3_R, 0x00000002); /* ??? */
|
||||||
|
/* (setup set '0') */
|
||||||
|
ACCW(PR_CTX0_0, 0x01008043); /* NVclass $043, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_0, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_0, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '1') */
|
||||||
|
ACCW(PR_CTX0_1, 0x01008019); /* NVclass $019, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_1, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_1, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '2') */
|
||||||
|
ACCW(PR_CTX0_2, 0x01008018); /* NVclass $018, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_2, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_2, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '3') */
|
||||||
|
ACCW(PR_CTX0_3, 0x01008021); /* NVclass $021, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_3, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_3, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '4') */
|
||||||
|
ACCW(PR_CTX0_4, 0x0100805f); /* NVclass $05f, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_4, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_4, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '5') */
|
||||||
|
ACCW(PR_CTX0_5, 0x0100804b); /* NVclass $04b, patchcfg ROP_AND, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_5, 0x00000000); /* DMA0 and DMA1 instance invalid */
|
||||||
|
ACCW(PR_CTX3_5, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '6') */
|
||||||
|
ACCW(PR_CTX0_6, 0x0100a048); /* NVclass $048, patchcfg ROP_AND, userclip enable,
|
||||||
|
* nv10+: little endian */
|
||||||
|
ACCW(PR_CTX1_6, 0x00000d01); /* format is A8RGB24, MSB mono */
|
||||||
|
ACCW(PR_CTX2_6, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_6, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '7') */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(PR_CTX0_7, 0x0300a094); /* NVclass $094, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid, nv10+: little endian */
|
||||||
|
else
|
||||||
|
ACCW(PR_CTX0_7, 0x0300a054); /* NVclass $054, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid */
|
||||||
|
ACCW(PR_CTX1_7, 0x00000d01); /* format is A8RGB24, MSB mono */
|
||||||
|
ACCW(PR_CTX2_7, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_7, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '8') */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(PR_CTX0_8, 0x0300a095); /* NVclass $095, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid, nv10+: little endian */
|
||||||
|
else
|
||||||
|
ACCW(PR_CTX0_8, 0x0300a055); /* NVclass $055, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid */
|
||||||
|
ACCW(PR_CTX1_8, 0x00000d01); /* format is A8RGB24, MSB mono */
|
||||||
|
ACCW(PR_CTX2_8, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_8, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set '9') */
|
||||||
|
ACCW(PR_CTX0_9, 0x00000058); /* NVclass $058, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_9, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_9, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set 'A') */
|
||||||
|
ACCW(PR_CTX0_A, 0x00000059); /* NVclass $059, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_A, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_A, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set 'B') */
|
||||||
|
ACCW(PR_CTX0_B, 0x0000005a); /* NVclass $05a, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_B, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_B, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set 'C') */
|
||||||
|
ACCW(PR_CTX0_C, 0x0000005b); /* NVclass $05b, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_C, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_C, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set 'D') */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(PR_CTX0_D, 0x00000093); /* NVclass $093, nv10+: little endian */
|
||||||
|
else
|
||||||
|
ACCW(PR_CTX0_D, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid */
|
||||||
|
ACCW(PR_CTX2_D, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_D, 0x00000000); /* method traps disabled */
|
||||||
|
/* (setup set 'E' if needed) */
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX0_E, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable,
|
||||||
|
* context surface0 valid, nv10+: little endian */
|
||||||
|
ACCW(PR_CTX2_E, 0x11401140); /* DMA0, DMA1 instance = $1140 */
|
||||||
|
ACCW(PR_CTX3_E, 0x00000000); /* method traps disabled */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** PGRAPH ***/
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
/* set resetstate for most function blocks */
|
||||||
|
ACCW(DEBUG0, 0x0003ffff);
|
||||||
|
/* init some function blocks */
|
||||||
|
ACCW(DEBUG1, 0x00118701);
|
||||||
|
ACCW(DEBUG2, 0x24f82ad9);
|
||||||
|
ACCW(DEBUG3, 0x55de0030);
|
||||||
|
/* end resetstate for the function blocks */
|
||||||
|
ACCW(DEBUG0, 0x00000000);
|
||||||
|
/* disable specific functions */
|
||||||
|
ACCW(NV10_DEBUG4, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* init some function blocks */
|
||||||
|
ACCW(DEBUG0, 0x1231c001);
|
||||||
|
ACCW(DEBUG1, 0x72111101);
|
||||||
|
ACCW(DEBUG2, 0x11d5f071);
|
||||||
|
ACCW(DEBUG3, 0x10d4ff31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset all cache sets */
|
||||||
|
ACCW(CACHE1_1, 0);
|
||||||
|
ACCW(CACHE1_2, 0);
|
||||||
|
ACCW(CACHE1_3, 0);
|
||||||
|
ACCW(CACHE1_4, 0);
|
||||||
|
ACCW(CACHE1_5, 0);
|
||||||
|
ACCW(CACHE2_1, 0);
|
||||||
|
ACCW(CACHE2_2, 0);
|
||||||
|
ACCW(CACHE2_3, 0);
|
||||||
|
ACCW(CACHE2_4, 0);
|
||||||
|
ACCW(CACHE2_5, 0);
|
||||||
|
ACCW(CACHE3_1, 0);
|
||||||
|
ACCW(CACHE3_2, 0);
|
||||||
|
ACCW(CACHE3_3, 0);
|
||||||
|
ACCW(CACHE3_4, 0);
|
||||||
|
ACCW(CACHE3_5, 0);
|
||||||
|
ACCW(CACHE4_1, 0);
|
||||||
|
ACCW(CACHE4_2, 0);
|
||||||
|
ACCW(CACHE4_3, 0);
|
||||||
|
ACCW(CACHE4_4, 0);
|
||||||
|
ACCW(CACHE4_5, 0);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(NV10_CACHE5_1, 0);
|
||||||
|
ACCW(CACHE5_2, 0);
|
||||||
|
ACCW(CACHE5_3, 0);
|
||||||
|
ACCW(CACHE5_4, 0);
|
||||||
|
ACCW(CACHE5_5, 0);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(NV10_CACHE6_1, 0);
|
||||||
|
ACCW(CACHE6_2, 0);
|
||||||
|
ACCW(CACHE6_3, 0);
|
||||||
|
ACCW(CACHE6_4, 0);
|
||||||
|
ACCW(CACHE6_5, 0);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(NV10_CACHE7_1, 0);
|
||||||
|
ACCW(CACHE7_2, 0);
|
||||||
|
ACCW(CACHE7_3, 0);
|
||||||
|
ACCW(CACHE7_4, 0);
|
||||||
|
ACCW(CACHE7_5, 0);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
ACCW(NV10_CACHE8_1, 0);
|
||||||
|
ACCW(CACHE8_2, 0);
|
||||||
|
ACCW(CACHE8_3, 0);
|
||||||
|
ACCW(CACHE8_4, 0);
|
||||||
|
ACCW(CACHE8_5, 0);
|
||||||
|
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
/* reset (disable) context switch stuff */
|
||||||
|
ACCW(NV10_CTX_SW1, 0);
|
||||||
|
ACCW(NV10_CTX_SW2, 0);
|
||||||
|
ACCW(NV10_CTX_SW3, 0);
|
||||||
|
ACCW(NV10_CTX_SW4, 0);
|
||||||
|
ACCW(NV10_CTX_SW5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup accesible card memory range for acc engine */
|
||||||
|
ACCW(BBASE0, 0x00000000);
|
||||||
|
ACCW(BBASE1, 0x00000000);
|
||||||
|
ACCW(BBASE2, 0x00000000);
|
||||||
|
ACCW(BBASE3, 0x00000000);
|
||||||
|
ACCW(BLIMIT0, (si->ps.memory_size - 1));
|
||||||
|
ACCW(BLIMIT1, (si->ps.memory_size - 1));
|
||||||
|
ACCW(BLIMIT2, (si->ps.memory_size - 1));
|
||||||
|
ACCW(BLIMIT3, (si->ps.memory_size - 1));
|
||||||
|
if (si->ps.card_arch >= NV10A)
|
||||||
|
{
|
||||||
|
ACCW(NV10_BBASE4, 0x00000000);
|
||||||
|
ACCW(NV10_BBASE5, 0x00000000);
|
||||||
|
ACCW(NV10_BLIMIT4, (si->ps.memory_size - 1));
|
||||||
|
ACCW(NV10_BLIMIT5, (si->ps.memory_size - 1));
|
||||||
|
}
|
||||||
|
if (si->ps.card_arch >= NV20A)
|
||||||
|
{
|
||||||
|
/* fixme(?): assuming more BLIMIT registers here: Then how about BBASE6-9?
|
||||||
|
* (linux fixed value 'BLIMIT6-9' 0x01ffffff) */
|
||||||
|
ACCW(NV20_BLIMIT6, (si->ps.memory_size - 1));
|
||||||
|
ACCW(NV20_BLIMIT7, (si->ps.memory_size - 1));
|
||||||
|
ACCW(NV20_BLIMIT8, (si->ps.memory_size - 1));
|
||||||
|
ACCW(NV20_BLIMIT9, (si->ps.memory_size - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable all acceleration engine INT reguests */
|
||||||
|
ACCW(ACC_INTE, 0x00000000);
|
||||||
|
|
||||||
|
/* reset all acceration engine INT status bits */
|
||||||
|
ACCW(ACC_INTS, 0xffffffff);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
/* context control enabled */
|
||||||
|
ACCW(NV10_CTX_CTRL, 0x10010100);
|
||||||
|
/* all acceleration buffers, pitches and colors are valid */
|
||||||
|
ACCW(NV10_ACC_STAT, 0xffffffff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* context control enabled */
|
||||||
|
ACCW(NV04_CTX_CTRL, 0x10010100);
|
||||||
|
/* all acceleration buffers, pitches and colors are valid */
|
||||||
|
ACCW(NV04_ACC_STAT, 0xffffffff);
|
||||||
|
}
|
||||||
|
/* enable acceleration engine command FIFO */
|
||||||
|
ACCW(FIFO_EN, 0x00000001);
|
||||||
|
/* pattern shape value = 8x8, 2 color */
|
||||||
|
ACCW(PAT_SHP, 0x00000000);
|
||||||
|
if (si->ps.card_arch != NV04A)
|
||||||
|
{
|
||||||
|
/* surface type is non-swizzle */
|
||||||
|
ACCW(NV10_SURF_TYP, 0x00000001);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* surface type is non-swizzle */
|
||||||
|
ACCW(NV04_SURF_TYP, 0x00000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Set pixel width and format ***/
|
||||||
|
switch(si->dm.space)
|
||||||
|
{
|
||||||
|
case B_CMAP8:
|
||||||
|
/* acc engine */
|
||||||
|
ACCW(FORMATS, 0x00001010);
|
||||||
|
if (si->ps.card_arch < NV30A)
|
||||||
|
ACCW(BPIXEL, 0x00111111); /* set depth 0-5: 4 bits per color */
|
||||||
|
else
|
||||||
|
ACCW(BPIXEL, 0x00000021); /* set depth 0-1: 5 bits per color */
|
||||||
|
ACCW(STRD_FMT, 0x03020202);
|
||||||
|
/* PRAMIN */
|
||||||
|
ACCW(PR_CTX1_0, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_1, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_2, 0x00000202); /* format is X16A8Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_3, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_4, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_5, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX1_9, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
ACCW(PR_CTX2_9, 0x00000302); /* dma_instance 0 valid, instance 1 invalid */
|
||||||
|
ACCW(PR_CTX1_B, 0x00000000); /* format is invalid */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000000); /* format is invalid */
|
||||||
|
if (si->ps.card_arch == NV04A)
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_D, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_D, 0x00000000); /* format is invalid */
|
||||||
|
ACCW(PR_CTX1_E, 0x00000302); /* format is X24Y8, LSB mono */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
/* acc engine */
|
||||||
|
ACCW(FORMATS, 0x00002071);
|
||||||
|
if (si->ps.card_arch < NV30A)
|
||||||
|
ACCW(BPIXEL, 0x00226222); /* set depth 0-5: 4 bits per color */
|
||||||
|
else
|
||||||
|
ACCW(BPIXEL, 0x00000042); /* set depth 0-1: 5 bits per color */
|
||||||
|
ACCW(STRD_FMT, 0x09080808);
|
||||||
|
/* PRAMIN */
|
||||||
|
ACCW(PR_CTX1_0, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_1, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_2, 0x00000802); /* format is X16A1RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_3, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_4, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_5, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_9, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX2_9, 0x00000902); /* dma_instance 0 valid, instance 1 invalid */
|
||||||
|
if (si->ps.card_arch == NV04A)
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_B, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_E, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
}
|
||||||
|
ACCW(PR_CTX1_D, 0x00000902); /* format is X17RGB15, LSB mono */
|
||||||
|
break;
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
/* acc engine */
|
||||||
|
ACCW(FORMATS, 0x000050C2);
|
||||||
|
if (si->ps.card_arch < NV30A)
|
||||||
|
ACCW(BPIXEL, 0x00556555); /* set depth 0-5: 4 bits per color */
|
||||||
|
else
|
||||||
|
ACCW(BPIXEL, 0x000000a5); /* set depth 0-1: 5 bits per color */
|
||||||
|
if (si->ps.card_arch == NV04A)
|
||||||
|
ACCW(STRD_FMT, 0x0c0b0b0b);
|
||||||
|
else
|
||||||
|
ACCW(STRD_FMT, 0x000b0b0c);
|
||||||
|
/* PRAMIN */
|
||||||
|
ACCW(PR_CTX1_0, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_1, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_2, 0x00000b02); /* format is A16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_3, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_4, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_5, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_9, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX2_9, 0x00000c02); /* dma_instance 0 valid, instance 1 invalid */
|
||||||
|
if (si->ps.card_arch == NV04A)
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ACCW(PR_CTX1_B, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
ACCW(PR_CTX1_E, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
}
|
||||||
|
ACCW(PR_CTX1_D, 0x00000c02); /* format is X16RGB16, LSB mono */
|
||||||
|
break;
|
||||||
|
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
|
||||||
|
/* acc engine */
|
||||||
|
ACCW(FORMATS, 0x000070e5);
|
||||||
|
if (si->ps.card_arch < NV30A)
|
||||||
|
ACCW(BPIXEL, 0x0077d777); /* set depth 0-5: 4 bits per color */
|
||||||
|
else
|
||||||
|
ACCW(BPIXEL, 0x000000e7); /* set depth 0-1: 5 bits per color */
|
||||||
|
ACCW(STRD_FMT, 0x0e0d0d0d);
|
||||||
|
/* PRAMIN */
|
||||||
|
ACCW(PR_CTX1_0, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_1, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_2, 0x00000d02); /* format is A8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_3, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_4, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_5, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_9, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX2_9, 0x00000e02); /* dma_instance 0 valid, instance 1 invalid */
|
||||||
|
ACCW(PR_CTX1_B, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_C, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
ACCW(PR_CTX1_D, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
if (si->ps.card_arch >= NV10A)
|
||||||
|
ACCW(PR_CTX1_E, 0x00000e02); /* format is X8RGB24, LSB mono */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(8,("ACC: init, invalid bit depth\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup some extra stuff for NV30A and later */
|
||||||
|
if (si->ps.card_arch >= NV30A)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
fixme: Does not belong here (and not needed?)
|
||||||
|
if(!chip->flatPanel)
|
||||||
|
{
|
||||||
|
chip->PRAMDAC0[0x0578/4] = state->vpllB; //0x00680578 = ??? never modified!
|
||||||
|
chip->PRAMDAC0[0x057C/4] = state->vpll2B; //0x0068057c = ??? never modified!
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* activate Zcullflush(?) */
|
||||||
|
ACCW(DEBUG3, (ACCR(DEBUG3) | 0x00000001));
|
||||||
|
/* unknown */
|
||||||
|
ACCW(NV30_WHAT, (ACCR(NV30_WHAT) | 0x00040000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** setup screen location and pitch ***/
|
||||||
|
switch (si->ps.card_arch)
|
||||||
|
{
|
||||||
|
case NV04A:
|
||||||
|
case NV10A:
|
||||||
|
/* location of active screen in framebuffer */
|
||||||
|
ACCW(OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(OFFSET4, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(OFFSET5, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
|
||||||
|
/* setup buffer pitch */
|
||||||
|
ACCW(PITCH0, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(PITCH1, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(PITCH2, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(PITCH3, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(PITCH4, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
break;
|
||||||
|
case NV20A:
|
||||||
|
case NV30A:
|
||||||
|
case NV40A:
|
||||||
|
/* location of active screen in framebuffer */
|
||||||
|
ACCW(NV20_OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(NV20_OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(NV20_OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
ACCW(NV20_OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
|
||||||
|
|
||||||
|
/* setup buffer pitch */
|
||||||
|
ACCW(NV20_PITCH0, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(NV20_PITCH1, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(NV20_PITCH2, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
ACCW(NV20_PITCH3, (si->fbc.bytes_per_row & 0x0000ffff));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** setup tile and pipe stuff ***/
|
||||||
|
if (si->ps.card_arch >= NV10A)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
fixme: setup elsewhere (does not belong here):
|
||||||
|
chip->PRAMDAC[0x00000404/4] |= (1 << 25);//0x00680404 = ???
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* setup acc engine tile stuff: */
|
||||||
|
/* reset tile adresses */
|
||||||
|
ACCW(NV10_FBTIL0AD, 0);
|
||||||
|
ACCW(NV10_FBTIL1AD, 0);
|
||||||
|
ACCW(NV10_FBTIL2AD, 0);
|
||||||
|
ACCW(NV10_FBTIL3AD, 0);
|
||||||
|
ACCW(NV10_FBTIL4AD, 0);
|
||||||
|
ACCW(NV10_FBTIL5AD, 0);
|
||||||
|
ACCW(NV10_FBTIL6AD, 0);
|
||||||
|
ACCW(NV10_FBTIL7AD, 0);
|
||||||
|
/* copy tile setup stuff from 'source' to acc engine */
|
||||||
|
if (si->ps.card_arch >= NV20A)
|
||||||
|
{
|
||||||
|
/* unknown: */
|
||||||
|
ACCW(NV20_WHAT0, ACCR(NV20_FBWHAT0));
|
||||||
|
ACCW(NV20_WHAT1, ACCR(NV20_FBWHAT1));
|
||||||
|
}
|
||||||
|
/* tile 0: */
|
||||||
|
/* tile invalid, tile adress = $00000 (18bit) */
|
||||||
|
ACCW(NV10_TIL0AD, ACCR(NV10_FBTIL0AD));
|
||||||
|
/* set tile end adress (18bit) */
|
||||||
|
ACCW(NV10_TIL0ED, ACCR(NV10_FBTIL0ED));
|
||||||
|
/* set tile size pitch (8bit: b8-15) */
|
||||||
|
ACCW(NV10_TIL0PT, ACCR(NV10_FBTIL0PT));
|
||||||
|
/* set tile status */
|
||||||
|
ACCW(NV10_TIL0ST, ACCR(NV10_FBTIL0ST));
|
||||||
|
/* tile 1: */
|
||||||
|
ACCW(NV10_TIL1AD, ACCR(NV10_FBTIL1AD));
|
||||||
|
ACCW(NV10_TIL1ED, ACCR(NV10_FBTIL1ED));
|
||||||
|
ACCW(NV10_TIL1PT, ACCR(NV10_FBTIL1PT));
|
||||||
|
ACCW(NV10_TIL1ST, ACCR(NV10_FBTIL1ST));
|
||||||
|
/* tile 2: */
|
||||||
|
ACCW(NV10_TIL2AD, ACCR(NV10_FBTIL2AD));
|
||||||
|
ACCW(NV10_TIL2ED, ACCR(NV10_FBTIL2ED));
|
||||||
|
ACCW(NV10_TIL2PT, ACCR(NV10_FBTIL2PT));
|
||||||
|
ACCW(NV10_TIL2ST, ACCR(NV10_FBTIL2ST));
|
||||||
|
/* tile 3: */
|
||||||
|
ACCW(NV10_TIL3AD, ACCR(NV10_FBTIL3AD));
|
||||||
|
ACCW(NV10_TIL3ED, ACCR(NV10_FBTIL3ED));
|
||||||
|
ACCW(NV10_TIL3PT, ACCR(NV10_FBTIL3PT));
|
||||||
|
ACCW(NV10_TIL3ST, ACCR(NV10_FBTIL3ST));
|
||||||
|
/* tile 4: */
|
||||||
|
ACCW(NV10_TIL4AD, ACCR(NV10_FBTIL4AD));
|
||||||
|
ACCW(NV10_TIL4ED, ACCR(NV10_FBTIL4ED));
|
||||||
|
ACCW(NV10_TIL4PT, ACCR(NV10_FBTIL4PT));
|
||||||
|
ACCW(NV10_TIL4ST, ACCR(NV10_FBTIL4ST));
|
||||||
|
/* tile 5: */
|
||||||
|
ACCW(NV10_TIL5AD, ACCR(NV10_FBTIL5AD));
|
||||||
|
ACCW(NV10_TIL5ED, ACCR(NV10_FBTIL5ED));
|
||||||
|
ACCW(NV10_TIL5PT, ACCR(NV10_FBTIL5PT));
|
||||||
|
ACCW(NV10_TIL5ST, ACCR(NV10_FBTIL5ST));
|
||||||
|
/* tile 6: */
|
||||||
|
ACCW(NV10_TIL6AD, ACCR(NV10_FBTIL6AD));
|
||||||
|
ACCW(NV10_TIL6ED, ACCR(NV10_FBTIL6ED));
|
||||||
|
ACCW(NV10_TIL6PT, ACCR(NV10_FBTIL6PT));
|
||||||
|
ACCW(NV10_TIL6ST, ACCR(NV10_FBTIL6ST));
|
||||||
|
/* tile 7: */
|
||||||
|
ACCW(NV10_TIL7AD, ACCR(NV10_FBTIL7AD));
|
||||||
|
ACCW(NV10_TIL7ED, ACCR(NV10_FBTIL7ED));
|
||||||
|
ACCW(NV10_TIL7PT, ACCR(NV10_FBTIL7PT));
|
||||||
|
ACCW(NV10_TIL7ST, ACCR(NV10_FBTIL7ST));
|
||||||
|
|
||||||
|
/* setup pipe */
|
||||||
|
/* set eyetype to local, lightning is off */
|
||||||
|
ACCW(NV10_XFMOD0, 0x10000000);
|
||||||
|
/* disable all lights */
|
||||||
|
ACCW(NV10_XFMOD1, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000040);
|
||||||
|
ACCW(NV10_PIPEDAT, 0x00000008);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000200);
|
||||||
|
for (cnt = 0; cnt < (3 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000040);
|
||||||
|
ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000800);
|
||||||
|
for (cnt = 0; cnt < (16 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
/* turn lightning on */
|
||||||
|
ACCW(NV10_XFMOD0, 0x30000000);
|
||||||
|
/* set light 1 to infinite type, other lights remain off */
|
||||||
|
ACCW(NV10_XFMOD1, 0x00000004);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00006400);
|
||||||
|
for (cnt = 0; cnt < (59 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00006800);
|
||||||
|
for (cnt = 0; cnt < (47 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00006c00);
|
||||||
|
for (cnt = 0; cnt < (3 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00007000);
|
||||||
|
for (cnt = 0; cnt < (19 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00007400);
|
||||||
|
for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00007800);
|
||||||
|
for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00004400);
|
||||||
|
for (cnt = 0; cnt < (8 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000000);
|
||||||
|
for (cnt = 0; cnt < 16; cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
|
||||||
|
ACCW(NV10_PIPEADR, 0x00000040);
|
||||||
|
for (cnt = 0; cnt < 4; cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** setup acceleration engine command shortcuts (so via fifo) ***/
|
||||||
|
/* (b31 = 1 selects 'config' function?) */
|
||||||
|
ACCW(FIFO_00800000, 0x80000000); /* Raster OPeration */
|
||||||
|
ACCW(FIFO_00802000, 0x80000001); /* Clip */
|
||||||
|
ACCW(FIFO_00804000, 0x80000002); /* Pattern */
|
||||||
|
ACCW(FIFO_00806000, 0x80000010); /* Pixmap (not used) */
|
||||||
|
ACCW(FIFO_00808000, 0x80000011); /* Blit */
|
||||||
|
ACCW(FIFO_0080a000, 0x80000012); /* Bitmap */
|
||||||
|
ACCW(FIFO_0080c000, 0x80000016); /* Line (not used) */
|
||||||
|
ACCW(FIFO_0080e000, 0x80000014); /* ??? (not used) */
|
||||||
|
|
||||||
|
/* do first actual acceleration engine command:
|
||||||
|
* setup clipping region (workspace size) to 32768 x 32768 pixels:
|
||||||
|
* wait for room in fifo for clipping cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_CLP_FIFOFREE)) >> 2) < 2)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup clipping (writing 2 32bit words) */
|
||||||
|
ACCW(CLP_TOPLEFT, 0x00000000);
|
||||||
|
ACCW(CLP_WIDHEIGHT, 0x80008000);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* screen to screen blit - i.e. move windows around and scroll within them. */
|
||||||
|
status_t nv_acc_setup_blit()
|
||||||
|
{
|
||||||
|
/* setup solid pattern:
|
||||||
|
* wait for room in fifo for pattern cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup pattern (writing 5 32bit words) */
|
||||||
|
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
|
||||||
|
ACCW(PAT_COLOR0, 0xffffffff);
|
||||||
|
ACCW(PAT_COLOR1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO2, 0xffffffff);
|
||||||
|
|
||||||
|
/* ROP3 registers (Raster OPeration):
|
||||||
|
* wait for room in fifo for ROP cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup ROP (writing 1 32bit word) */
|
||||||
|
ACCW(ROP_ROP3, 0xcc);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
|
||||||
|
{
|
||||||
|
/* Note: blit-copy direction is determined inside riva hardware: no setup needed */
|
||||||
|
|
||||||
|
/* instruct engine what to blit:
|
||||||
|
* wait for room in fifo for blit cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_BLT_FIFOFREE)) >> 2) < 3)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup blit (writing 3 32bit words) */
|
||||||
|
ACCW(BLT_TOPLFTSRC, ((ys << 16) | xs));
|
||||||
|
ACCW(BLT_TOPLFTDST, ((yd << 16) | xd));
|
||||||
|
ACCW(BLT_SIZE, (((h + 1) << 16) | (w + 1)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rectangle fill - i.e. workspace and window background color */
|
||||||
|
/* span fill - i.e. (selected) menuitem background color (Dano) */
|
||||||
|
status_t nv_acc_setup_rectangle(uint32 color)
|
||||||
|
{
|
||||||
|
/* setup solid pattern:
|
||||||
|
* wait for room in fifo for pattern cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup pattern (writing 5 32bit words) */
|
||||||
|
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
|
||||||
|
ACCW(PAT_COLOR0, 0xffffffff);
|
||||||
|
ACCW(PAT_COLOR1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO2, 0xffffffff);
|
||||||
|
|
||||||
|
/* ROP3 registers (Raster OPeration):
|
||||||
|
* wait for room in fifo for ROP cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup ROP (writing 1 32bit word) for GXcopy */
|
||||||
|
ACCW(ROP_ROP3, 0xcc);
|
||||||
|
|
||||||
|
/* setup fill color:
|
||||||
|
* wait for room in fifo for bitmap cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup color (writing 1 32bit word) */
|
||||||
|
ACCW(BMP_COLOR1A, color);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
|
||||||
|
{
|
||||||
|
/* instruct engine what to fill:
|
||||||
|
* wait for room in fifo for bitmap cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup fill (writing 2 32bit words) */
|
||||||
|
ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff)));
|
||||||
|
ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rectangle invert - i.e. text cursor and text selection */
|
||||||
|
status_t nv_acc_setup_rect_invert()
|
||||||
|
{
|
||||||
|
/* setup solid pattern:
|
||||||
|
* wait for room in fifo for pattern cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup pattern (writing 5 32bit words) */
|
||||||
|
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
|
||||||
|
ACCW(PAT_COLOR0, 0xffffffff);
|
||||||
|
ACCW(PAT_COLOR1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO1, 0xffffffff);
|
||||||
|
ACCW(PAT_MONO2, 0xffffffff);
|
||||||
|
|
||||||
|
/* ROP3 registers (Raster OPeration):
|
||||||
|
* wait for room in fifo for ROP cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup ROP (writing 1 32bit word) for GXinvert */
|
||||||
|
ACCW(ROP_ROP3, 0x55);
|
||||||
|
|
||||||
|
/* reset fill color:
|
||||||
|
* wait for room in fifo for bitmap cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now reset color (writing 1 32bit word) */
|
||||||
|
ACCW(BMP_COLOR1A, 0);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
|
||||||
|
{
|
||||||
|
/* instruct engine what to invert:
|
||||||
|
* wait for room in fifo for bitmap cmd if needed.
|
||||||
|
* (fifo holds 256 32bit words: count those, not bytes) */
|
||||||
|
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2)
|
||||||
|
{
|
||||||
|
/* snooze a bit so I do not hammer the bus */
|
||||||
|
snooze (10);
|
||||||
|
}
|
||||||
|
/* now setup invert (writing 2 32bit words) */
|
||||||
|
ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff)));
|
||||||
|
ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* screen to screen tranparent blit */
|
||||||
|
status_t nv_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
|
||||||
|
{
|
||||||
|
//fixme: implement.
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* screen to screen scaled filtered blit - i.e. scale video in memory */
|
||||||
|
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
|
||||||
|
uint16 xd,uint16 yd,uint16 wd,uint16 hd)
|
||||||
|
{
|
||||||
|
//fixme: implement.
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 6/2004-9/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00000100
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "nv_std.h"
|
||||||
|
|
||||||
|
static void nv_agp_list_info(agp_info ai);
|
||||||
|
static void nv_agp_list_active(uint32 cmd);
|
||||||
|
|
||||||
|
status_t nv_agp_setup(void)
|
||||||
|
{
|
||||||
|
nv_nth_agp_info nai;
|
||||||
|
nv_cmd_agp nca;
|
||||||
|
uint8 index;
|
||||||
|
agp_info nv_ai;
|
||||||
|
bool agp = false;
|
||||||
|
|
||||||
|
/* first try to enable FW support on our card if user requested this
|
||||||
|
* ('unsupported' tweak!)
|
||||||
|
* This has no effect on PCI cards. */
|
||||||
|
if (si->settings.unhide_fw)
|
||||||
|
{
|
||||||
|
uint32 reg;
|
||||||
|
|
||||||
|
LOG(4, ("AGP: STRAPINFO2 contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2)));
|
||||||
|
|
||||||
|
LOG(4, ("AGP: attempting to enable fastwrite support..\n"));
|
||||||
|
/* 'force' FW support */
|
||||||
|
reg = (NV_REG32(NV32_NVSTRAPINFO2) & ~0x00000800);
|
||||||
|
/* enable strapinfo overwrite */
|
||||||
|
NV_REG32(NV32_NVSTRAPINFO2) = (reg | 0x80000000);
|
||||||
|
|
||||||
|
LOG(4, ("AGP: STRAPINFO2 now contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the magic number so the nvidia kerneldriver knows we're for real */
|
||||||
|
nca.magic = nai.magic = NV_PRIVATE_DATA_MAGIC;
|
||||||
|
|
||||||
|
/* contact driver and get a pointer to the registers and shared data */
|
||||||
|
for (index = 0; index < 8; index++)
|
||||||
|
{
|
||||||
|
/* get nth AGP device info */
|
||||||
|
nai.index = index;
|
||||||
|
ioctl(fd, NV_GET_NTH_AGP_INFO, &nai, sizeof(nai));
|
||||||
|
|
||||||
|
/* abort if no agp busmanager found */
|
||||||
|
if (!nai.agp_bus)
|
||||||
|
{
|
||||||
|
LOG(4,("AGP: no AGP busmanager found.\n"));
|
||||||
|
/* don't touch AGP command register, we don't know what has been setup:
|
||||||
|
* touching it anyway might 'hang' the graphics card! */
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exit if we didn't get device info for this index */
|
||||||
|
if (!nai.exist)
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
LOG(4,("AGP: end of AGP capable devices list.\n"));
|
||||||
|
else
|
||||||
|
LOG(4,("AGP: no AGP capable devices found.\n"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4,("AGP: AGP capable device #%d:\n", (index + 1)));
|
||||||
|
|
||||||
|
/* see if we are this one */
|
||||||
|
if ((nai.agpi.device_id == si->device_id) &&
|
||||||
|
(nai.agpi.vendor_id == si->vendor_id) &&
|
||||||
|
(nai.agpi.bus == si->bus) &&
|
||||||
|
(nai.agpi.device == si->device) &&
|
||||||
|
(nai.agpi.function == si->function))
|
||||||
|
{
|
||||||
|
LOG(4,("AGP: (this is the device this accelerant controls)\n"));
|
||||||
|
agp = true;
|
||||||
|
/* remember our info */
|
||||||
|
nv_ai = nai.agpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* log capabilities */
|
||||||
|
nv_agp_list_info(nai.agpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if our card is not an AGP type, abort here */
|
||||||
|
/* Note:
|
||||||
|
* We have to iterate through the capability list as specified in the PCI spec
|
||||||
|
* one way or the other, otherwise we cannot distinquish between nVidia PCI and
|
||||||
|
* AGP type cards as nVidia PCI cards still have AGP registers that pretend to
|
||||||
|
* support AGP.
|
||||||
|
* We rely on the AGP busmanager to iterate trough this list for us. */
|
||||||
|
if (!agp)
|
||||||
|
{
|
||||||
|
LOG(4,("AGP: the graphicscard this accelerant controls is PCI type.\n"));
|
||||||
|
|
||||||
|
/* make sure card is set for PCI access */
|
||||||
|
CFGW(AGPCMD, 0x00000000);
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (si->settings.force_pci)
|
||||||
|
{
|
||||||
|
/* set PCI mode if specified by user in nv.settings */
|
||||||
|
LOG(4,("AGP: forcing PCI mode (specified in nv.settings)\n"));
|
||||||
|
|
||||||
|
/* let the AGP busmanager setup PCI mode.
|
||||||
|
* (the AGP speed scheme is of no consequence now) */
|
||||||
|
nca.cmd = 0x00000000;
|
||||||
|
ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* activate AGP mode */
|
||||||
|
LOG(4,("AGP: activating AGP mode...\n"));
|
||||||
|
|
||||||
|
/* let the AGP busmanager worry about what mode to set.. */
|
||||||
|
nca.cmd = 0xfffffff7;
|
||||||
|
/* ..but we do need to select the right speed scheme fetched from our card */
|
||||||
|
if (nv_ai.interface.agp_stat & AGP_rate_rev) nca.cmd |= AGP_rate_rev;
|
||||||
|
ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* list mode now activated,
|
||||||
|
* make sure we have the correct speed scheme for logging */
|
||||||
|
nv_agp_list_active(nca.cmd | (nv_ai.interface.agp_stat & AGP_rate_rev));
|
||||||
|
|
||||||
|
/* extra check */
|
||||||
|
LOG(4,("AGP: graphics card AGPCMD register readback $%08x\n", CFGR(AGPCMD)));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nv_agp_list_info(agp_info ai)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
list device
|
||||||
|
*/
|
||||||
|
if (ai.class_base == PCI_display)
|
||||||
|
LOG(4,("AGP: device is a graphicscard, subclass ID is $%02x\n", ai.class_sub));
|
||||||
|
else
|
||||||
|
LOG(4,("AGP: device is a hostbridge, subclass ID is $%02x\n", ai.class_sub));
|
||||||
|
LOG(4,("AGP: vendor ID $%04x\n", ai.vendor_id));
|
||||||
|
LOG(4,("AGP: device ID $%04x\n", ai.device_id));
|
||||||
|
LOG(4,("AGP: bus %d, device %d, function %d\n", ai.bus, ai.device, ai.function));
|
||||||
|
|
||||||
|
/*
|
||||||
|
list capabilities
|
||||||
|
*/
|
||||||
|
LOG(4,("AGP: this device supports AGP specification %d.%d;\n",
|
||||||
|
((ai.interface.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift),
|
||||||
|
((ai.interface.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift)));
|
||||||
|
|
||||||
|
/* the AGP devices determine AGP speed scheme version used on power-up/reset */
|
||||||
|
if (!(ai.interface.agp_stat & AGP_rate_rev))
|
||||||
|
{
|
||||||
|
/* AGP 2.0 scheme applies */
|
||||||
|
if (ai.interface.agp_stat & AGP_2_1x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 1x mode is available\n"));
|
||||||
|
if (ai.interface.agp_stat & AGP_2_2x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 2x mode is available\n"));
|
||||||
|
if (ai.interface.agp_stat & AGP_2_4x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 4x mode is available\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* AGP 3.0 scheme applies */
|
||||||
|
if (ai.interface.agp_stat & AGP_3_4x)
|
||||||
|
LOG(4,("AGP: AGP 3.0 4x mode is available\n"));
|
||||||
|
if (ai.interface.agp_stat & AGP_3_8x)
|
||||||
|
LOG(4,("AGP: AGP 3.0 8x mode is available\n"));
|
||||||
|
}
|
||||||
|
if (ai.interface.agp_stat & AGP_FW) LOG(4,("AGP: fastwrite transfers are supported\n"));
|
||||||
|
if (ai.interface.agp_stat & AGP_SBA) LOG(4,("AGP: sideband adressing is supported\n"));
|
||||||
|
LOG(4,("AGP: %d queued AGP requests can be handled.\n",
|
||||||
|
(((ai.interface.agp_stat & AGP_RQ) >> AGP_RQ_shift) + 1)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
list current settings,
|
||||||
|
make sure we have the correct speed scheme for logging
|
||||||
|
*/
|
||||||
|
nv_agp_list_active(ai.interface.agp_cmd | (ai.interface.agp_stat & AGP_rate_rev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nv_agp_list_active(uint32 cmd)
|
||||||
|
{
|
||||||
|
LOG(4,("AGP: listing settings now in use:\n"));
|
||||||
|
if (!(cmd & AGP_rate_rev))
|
||||||
|
{
|
||||||
|
/* AGP 2.0 scheme applies */
|
||||||
|
if (cmd & AGP_2_1x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 1x mode is set\n"));
|
||||||
|
if (cmd & AGP_2_2x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 2x mode is set\n"));
|
||||||
|
if (cmd & AGP_2_4x)
|
||||||
|
LOG(4,("AGP: AGP 2.0 4x mode is set\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* AGP 3.0 scheme applies */
|
||||||
|
if (cmd & AGP_3_4x)
|
||||||
|
LOG(4,("AGP: AGP 3.0 4x mode is set\n"));
|
||||||
|
if (cmd & AGP_3_8x)
|
||||||
|
LOG(4,("AGP: AGP 3.0 8x mode is set\n"));
|
||||||
|
}
|
||||||
|
if (cmd & AGP_FW) LOG(4,("AGP: fastwrite transfers are enabled\n"));
|
||||||
|
if (cmd & AGP_SBA) LOG(4,("AGP: sideband adressing is enabled\n"));
|
||||||
|
LOG(4,("AGP: max. AGP queued request depth is set to %d\n",
|
||||||
|
(((cmd & AGP_RQ) >> AGP_RQ_shift) + 1)));
|
||||||
|
if (cmd & AGP_enable)
|
||||||
|
LOG(4,("AGP: the AGP interface is enabled.\n"));
|
||||||
|
else
|
||||||
|
LOG(4,("AGP: the AGP interface is disabled.\n"));
|
||||||
|
}
|
||||||
@@ -0,0 +1,868 @@
|
|||||||
|
/* Nvidia TNT and GeForce Back End Scaler functions */
|
||||||
|
/* Written by Rudolf Cornelissen 05/2002-9/2004 */
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00000200
|
||||||
|
|
||||||
|
#include "nv_std.h"
|
||||||
|
|
||||||
|
typedef struct move_overlay_info move_overlay_info;
|
||||||
|
|
||||||
|
struct move_overlay_info
|
||||||
|
{
|
||||||
|
uint32 hcoordv; /* left and right edges of video output window */
|
||||||
|
uint32 vcoordv; /* top and bottom edges of video output window */
|
||||||
|
uint32 hsrcstv; /* horizontal source start in source buffer (clipping) */
|
||||||
|
uint32 v1srcstv; /* vertical source start in source buffer (clipping) */
|
||||||
|
uint32 a1orgv; /* alternate source clipping via startadress of source buffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nv_bes_calc_move_overlay(move_overlay_info *moi);
|
||||||
|
static void nv_bes_program_move_overlay(move_overlay_info moi);
|
||||||
|
|
||||||
|
/* move the overlay output window in virtualscreens */
|
||||||
|
/* Note:
|
||||||
|
* si->dm.h_display_start and si->dm.v_display_start determine where the new
|
||||||
|
* output window is located! */
|
||||||
|
void nv_bes_move_overlay()
|
||||||
|
{
|
||||||
|
move_overlay_info moi;
|
||||||
|
|
||||||
|
/* abort if overlay is not active */
|
||||||
|
if (!si->overlay.active) return;
|
||||||
|
|
||||||
|
nv_bes_calc_move_overlay(&moi);
|
||||||
|
nv_bes_program_move_overlay(moi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nv_bes_calc_move_overlay(move_overlay_info *moi)
|
||||||
|
{
|
||||||
|
/* misc used variables */
|
||||||
|
uint16 temp1, temp2;
|
||||||
|
/* visible screen window in virtual workspaces */
|
||||||
|
uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
|
||||||
|
|
||||||
|
/* do 'overlay follow head' in dualhead modes on dualhead cards */
|
||||||
|
if (si->ps.secondary_head)
|
||||||
|
{
|
||||||
|
switch (si->dm.flags & DUALHEAD_BITS)
|
||||||
|
{
|
||||||
|
case DUALHEAD_ON:
|
||||||
|
case DUALHEAD_SWITCH:
|
||||||
|
if ((si->overlay.ow.h_start + (si->overlay.ow.width / 2)) <
|
||||||
|
(si->dm.h_display_start + si->dm.timing.h_display))
|
||||||
|
nv_bes_to_crtc(si->crtc_switch_mode);
|
||||||
|
else
|
||||||
|
nv_bes_to_crtc(!si->crtc_switch_mode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nv_bes_to_crtc(si->crtc_switch_mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the BES does not respect virtual_workspaces, but adheres to CRTC
|
||||||
|
* constraints only */
|
||||||
|
crtc_hstart = si->dm.h_display_start;
|
||||||
|
/* make dualhead stretch and switch mode work while we're at it.. */
|
||||||
|
if (si->overlay.crtc)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
moi->hcoordv = 0;
|
||||||
|
/* left edge coordinate of output window, must be inside desktop */
|
||||||
|
/* clipping on the left side */
|
||||||
|
if (si->overlay.ow.h_start < crtc_hstart)
|
||||||
|
{
|
||||||
|
temp1 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the right side */
|
||||||
|
if (si->overlay.ow.h_start >= (crtc_hend - 1))
|
||||||
|
{
|
||||||
|
/* width < 2 is not allowed */
|
||||||
|
temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* no clipping here */
|
||||||
|
{
|
||||||
|
temp1 = (si->overlay.ow.h_start - crtc_hstart) & 0x7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moi->hcoordv |= temp1 << 16;
|
||||||
|
/* right edge coordinate of output window, must be inside desktop */
|
||||||
|
/* width < 2 is not allowed */
|
||||||
|
if (si->overlay.ow.width < 2)
|
||||||
|
{
|
||||||
|
temp2 = (temp1 + 1) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the right side */
|
||||||
|
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
|
||||||
|
{
|
||||||
|
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the left side */
|
||||||
|
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
|
||||||
|
{
|
||||||
|
/* width < 2 is not allowed */
|
||||||
|
temp2 = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* no clipping here */
|
||||||
|
{
|
||||||
|
temp2 = ((uint16)(si->overlay.ow.h_start + si->overlay.ow.width - crtc_hstart - 1)) & 0x7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moi->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 */
|
||||||
|
moi->vcoordv = 0;
|
||||||
|
/* top edge coordinate of output window, must be inside desktop */
|
||||||
|
/* clipping on the top side */
|
||||||
|
if (si->overlay.ow.v_start < crtc_vstart)
|
||||||
|
{
|
||||||
|
temp1 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the bottom side */
|
||||||
|
if (si->overlay.ow.v_start >= (crtc_vend - 1))
|
||||||
|
{
|
||||||
|
/* height < 2 is not allowed */
|
||||||
|
temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* no clipping here */
|
||||||
|
{
|
||||||
|
temp1 = (si->overlay.ow.v_start - crtc_vstart) & 0x7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moi->vcoordv |= temp1 << 16;
|
||||||
|
/* bottom edge coordinate of output window, must be inside desktop */
|
||||||
|
/* height < 2 is not allowed */
|
||||||
|
if (si->overlay.ow.height < 2)
|
||||||
|
{
|
||||||
|
temp2 = (temp1 + 1) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the bottom side */
|
||||||
|
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1))
|
||||||
|
{
|
||||||
|
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clipping on the top side */
|
||||||
|
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
|
||||||
|
{
|
||||||
|
/* height < 2 is not allowed */
|
||||||
|
temp2 = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* no clipping here */
|
||||||
|
{
|
||||||
|
temp2 = ((uint16)(si->overlay.ow.v_start + si->overlay.ow.height - crtc_vstart - 1)) & 0x7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moi->vcoordv |= temp2 << 0;
|
||||||
|
LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
*** setup 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.! */
|
||||||
|
moi->hsrcstv = 0;
|
||||||
|
/* check for destination horizontal clipping at left side */
|
||||||
|
if (si->overlay.ow.h_start < crtc_hstart)
|
||||||
|
{
|
||||||
|
/* check if entire destination picture is clipping left:
|
||||||
|
* (2 pixels will be clamped onscreen at least) */
|
||||||
|
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
|
||||||
|
{
|
||||||
|
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
|
||||||
|
moi->hsrcstv += (si->overlay.ow.width - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
|
||||||
|
moi->hsrcstv += (crtc_hstart - si->overlay.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! */
|
||||||
|
moi->hsrcstv *= si->overlay.h_ifactor;
|
||||||
|
}
|
||||||
|
/* take zoom into account */
|
||||||
|
moi->hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16;
|
||||||
|
/* AND below required by hardware */
|
||||||
|
moi->hsrcstv &= 0x03fffffc;
|
||||||
|
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", moi->hsrcstv / (float)65536));
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
*** setup vertical clipping ***
|
||||||
|
*******************************/
|
||||||
|
|
||||||
|
/* calculate inputbitmap origin adress */
|
||||||
|
moi->a1orgv = (uint32)((vuint32 *)si->overlay.ob.buffer);
|
||||||
|
moi->a1orgv -= (uint32)((vuint32 *)si->framebuffer);
|
||||||
|
|
||||||
|
/* Setup vertical 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 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.! */
|
||||||
|
|
||||||
|
moi->v1srcstv = 0;
|
||||||
|
/* check for destination vertical clipping at top side */
|
||||||
|
if (si->overlay.ow.v_start < crtc_vstart)
|
||||||
|
{
|
||||||
|
/* check if entire destination picture is clipping at top:
|
||||||
|
* (2 pixels will be clamped onscreen at least) */
|
||||||
|
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
|
||||||
|
{
|
||||||
|
/* increase 'number of clipping pixels' with 'fixed value':
|
||||||
|
* 'total height - 2' of dest. picture in pixels * inverse scaling factor */
|
||||||
|
moi->v1srcstv = (si->overlay.ow.height - 2) * si->overlay.v_ifactor;
|
||||||
|
/* on pre-NV10 we need to do clipping in the source
|
||||||
|
* bitmap because no seperate clipping registers exist... */
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* increase 'first contributing pixel' with:
|
||||||
|
* number of destination picture clipping pixels * inverse scaling factor */
|
||||||
|
moi->v1srcstv = (crtc_vstart - si->overlay.ow.v_start) * si->overlay.v_ifactor;
|
||||||
|
/* on pre-NV10 we need to do clipping in the source
|
||||||
|
* bitmap because no seperate clipping registers exist... */
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
|
||||||
|
}
|
||||||
|
LOG(4,("Overlay: clipping at top...\n"));
|
||||||
|
}
|
||||||
|
/* take zoom into account */
|
||||||
|
moi->v1srcstv += (((uint32)si->overlay.my_ov.v_start) << 16);
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row);
|
||||||
|
LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv));
|
||||||
|
}
|
||||||
|
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", moi->v1srcstv / (float)65536));
|
||||||
|
|
||||||
|
/* AND below is probably required by hardware. */
|
||||||
|
/* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */
|
||||||
|
moi->a1orgv &= 0xfffffff0;
|
||||||
|
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nv_bes_program_move_overlay(move_overlay_info moi)
|
||||||
|
{
|
||||||
|
/*************************************
|
||||||
|
*** sync to BES (Back End Scaler) ***
|
||||||
|
*************************************/
|
||||||
|
|
||||||
|
/* Done in card hardware:
|
||||||
|
* double buffered registers + trigger if programming complete feature. */
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
*** actually program the registers ***
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* unknown, but needed (otherwise high-res distortions and only half the frames */
|
||||||
|
BESW(NV04_OE_STATE, 0x00000000);
|
||||||
|
/* select buffer 0 as active (b16) */
|
||||||
|
BESW(NV04_SU_STATE, 0x00000000);
|
||||||
|
/* unknown (no effect?) */
|
||||||
|
BESW(NV04_RM_STATE, 0x00000000);
|
||||||
|
/* setup clipped(!) buffer startadress in RAM */
|
||||||
|
/* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping
|
||||||
|
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
|
||||||
|
/* (program both buffers to prevent sync distortions) */
|
||||||
|
/* first include 'pixel precise' left clipping... (top clipping was already included) */
|
||||||
|
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
|
||||||
|
/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
|
||||||
|
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
|
||||||
|
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
|
||||||
|
/* setup output window position */
|
||||||
|
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
|
||||||
|
/* setup output window size */
|
||||||
|
BESW(NV04_DSTSIZE, (
|
||||||
|
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
|
||||||
|
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
|
||||||
|
));
|
||||||
|
/* select buffer 1 as active (b16) */
|
||||||
|
BESW(NV04_SU_STATE, 0x00010000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* >= NV10A */
|
||||||
|
|
||||||
|
/* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */
|
||||||
|
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
|
||||||
|
/* setup output window position */
|
||||||
|
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
|
||||||
|
/* setup output window size */
|
||||||
|
BESW(NV10_0DSTSIZE, (
|
||||||
|
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
|
||||||
|
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
|
||||||
|
));
|
||||||
|
/* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */
|
||||||
|
/* This also triggers activation of programmed values (double buffered registers feature) */
|
||||||
|
BESW(NV10_BUFSEL, 0x00000001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_bes_to_crtc(bool crtc)
|
||||||
|
{
|
||||||
|
if (si->ps.secondary_head)
|
||||||
|
{
|
||||||
|
if (crtc)
|
||||||
|
{
|
||||||
|
LOG(4,("Overlay: switching overlay to CRTC2\n"));
|
||||||
|
/* switch overlay engine to CRTC2 */
|
||||||
|
NV_REG32(NV32_FUNCSEL) &= ~0x00001000;
|
||||||
|
NV_REG32(NV32_2FUNCSEL) |= 0x00001000;
|
||||||
|
si->overlay.crtc = !si->crtc_switch_mode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(4,("Overlay: switching overlay to CRTC1\n"));
|
||||||
|
/* switch overlay engine to CRTC1 */
|
||||||
|
NV_REG32(NV32_2FUNCSEL) &= ~0x00001000;
|
||||||
|
NV_REG32(NV32_FUNCSEL) |= 0x00001000;
|
||||||
|
si->overlay.crtc = si->crtc_switch_mode;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_bes_init()
|
||||||
|
{
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */
|
||||||
|
BESW(NV04_INTE, 0x00000000);
|
||||||
|
|
||||||
|
/* setup saturation to be 'neutral' */
|
||||||
|
BESW(NV04_SAT, 0x00000000);
|
||||||
|
/* setup RGB brightness to be 'neutral' */
|
||||||
|
BESW(NV04_RED_AMP, 0x00000069);
|
||||||
|
BESW(NV04_GRN_AMP, 0x0000003e);
|
||||||
|
BESW(NV04_BLU_AMP, 0x00000089);
|
||||||
|
|
||||||
|
/* setup fifo for fetching data */
|
||||||
|
BESW(NV04_FIFOBURL, 0x00000003);
|
||||||
|
BESW(NV04_FIFOTHRS, 0x00000038);
|
||||||
|
|
||||||
|
/* unknown, but needed (registers only have b0 implemented) */
|
||||||
|
/* (program both buffers to prevent sync distortions) */
|
||||||
|
BESW(NV04_0OFFSET, 0x00000000);
|
||||||
|
BESW(NV04_1OFFSET, 0x00000000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* >= NV10A */
|
||||||
|
|
||||||
|
/* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */
|
||||||
|
BESW(NV10_INTE, 0x00000000);
|
||||||
|
/* shut off GeForce4MX MPEG2 decoder */
|
||||||
|
BESW(DEC_GENCTRL, 0x00000000);
|
||||||
|
/* setup BES memory-range mask */
|
||||||
|
BESW(NV10_0MEMMASK, (si->ps.memory_size - 1));
|
||||||
|
/* unknown, but needed */
|
||||||
|
BESW(NV10_0OFFSET, 0x00000000);
|
||||||
|
|
||||||
|
/* setup brightness, contrast and saturation to be 'neutral' */
|
||||||
|
BESW(NV10_0BRICON, ((0x1000 << 16) | 0x1000));
|
||||||
|
BESW(NV10_0SAT, ((0x0000 << 16) | 0x1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
* 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. */
|
||||||
|
|
||||||
|
/* output window position and clipping info for source buffer */
|
||||||
|
move_overlay_info moi;
|
||||||
|
/* calculated BES register values */
|
||||||
|
uint32 hiscalv, viscalv;
|
||||||
|
/* interval representation, used for scaling calculations */
|
||||||
|
uint16 intrep;
|
||||||
|
/* inverse scaling factor, used for source positioning */
|
||||||
|
uint32 ifactor;
|
||||||
|
/* copy of overlay view which has checked valid values */
|
||||||
|
overlay_view my_ov;
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************************
|
||||||
|
*** 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(4,("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));
|
||||||
|
|
||||||
|
/* save for nv_bes_calc_move_overlay() */
|
||||||
|
si->overlay.ow = *ow;
|
||||||
|
si->overlay.ob = *ob;
|
||||||
|
si->overlay.my_ov = my_ov;
|
||||||
|
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
*** setup horizontal scaling ***
|
||||||
|
********************************/
|
||||||
|
LOG(4,("Overlay: total input picture width = %d, height = %d\n",
|
||||||
|
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
|
||||||
|
LOG(4,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
hiscalv = ifactor;
|
||||||
|
/* save for nv_bes_calc_move_overlay() */
|
||||||
|
si->overlay.h_ifactor = ifactor;
|
||||||
|
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
|
||||||
|
|
||||||
|
/* check scaling factor (and modify if needed) to be within scaling limits */
|
||||||
|
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
|
||||||
|
if (hiscalv < 0x00002000)
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too large, set factor to max. valid value */
|
||||||
|
hiscalv = 0x00002000;
|
||||||
|
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv));
|
||||||
|
}
|
||||||
|
switch (si->ps.card_arch)
|
||||||
|
{
|
||||||
|
case NV04A:
|
||||||
|
/* Riva128-TNT2 series have a 'downscaling' limit of 1.000489
|
||||||
|
* (16bit register with 0.11 format value) */
|
||||||
|
if (hiscalv > 0x0000ffff)
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
hiscalv = 0x0000ffff;
|
||||||
|
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)2048 / (hiscalv >> 5)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NV30A:
|
||||||
|
case NV40A:
|
||||||
|
/* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */
|
||||||
|
if ((hiscalv > (2 << 16)) && (si->ps.card_type != NV31))
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
hiscalv = (2 << 16);
|
||||||
|
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
|
||||||
|
}
|
||||||
|
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
|
||||||
|
* So let it fall through... */
|
||||||
|
if (si->ps.card_type != NV31) break;
|
||||||
|
default:
|
||||||
|
/* the rest has a downscaling limit of 0.125 */
|
||||||
|
if (hiscalv > (8 << 16))
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
hiscalv = (8 << 16);
|
||||||
|
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* AND below is required by hardware */
|
||||||
|
hiscalv &= 0x001ffffc;
|
||||||
|
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
*** setup 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;
|
||||||
|
/* save for nv_bes_calc_move_overlay() */
|
||||||
|
si->overlay.v_ifactor = ifactor;
|
||||||
|
|
||||||
|
/* check scaling factor (and modify if needed) to be within scaling limits */
|
||||||
|
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
|
||||||
|
if (viscalv < 0x00002000)
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too large, set factor to max. valid value */
|
||||||
|
viscalv = 0x00002000;
|
||||||
|
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv));
|
||||||
|
}
|
||||||
|
switch (si->ps.card_arch)
|
||||||
|
{
|
||||||
|
case NV04A:
|
||||||
|
/* Riva128-TNT2 series have a 'downscaling' limit of 1.000489
|
||||||
|
* (16bit register with 0.11 format value) */
|
||||||
|
if (viscalv > 0x0000ffff)
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
viscalv = 0x0000ffff;
|
||||||
|
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)2048 / (viscalv >> 5)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NV30A:
|
||||||
|
case NV40A:
|
||||||
|
/* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */
|
||||||
|
if ((viscalv > (2 << 16)) && (si->ps.card_type != NV31))
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
viscalv = (2 << 16);
|
||||||
|
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
|
||||||
|
}
|
||||||
|
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
|
||||||
|
* So let it fall through... */
|
||||||
|
if (si->ps.card_type != NV31) break;
|
||||||
|
default:
|
||||||
|
/* the rest has a downscaling limit of 0.125 */
|
||||||
|
if (viscalv > (8 << 16))
|
||||||
|
{
|
||||||
|
/* (non-inverse) factor too small, set factor to min. valid value */
|
||||||
|
viscalv = (8 << 16);
|
||||||
|
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* AND below is required by hardware */
|
||||||
|
viscalv &= 0x001ffffc;
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
*** setup all edges of output window, setup horizontal and vertical clipping ***
|
||||||
|
********************************************************************************/
|
||||||
|
nv_bes_calc_move_overlay(&moi);
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
*** log color keying info ***
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
LOG(4,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
|
||||||
|
ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
|
||||||
|
LOG(4,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
|
||||||
|
ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
|
||||||
|
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
*** log flags ***
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags));
|
||||||
|
/* BTW: horizontal and vertical filtering are fixed and turned on for GeForce overlay. */
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************
|
||||||
|
*** sync to BES (Back End Scaler) ***
|
||||||
|
*************************************/
|
||||||
|
|
||||||
|
/* Done in card hardware:
|
||||||
|
* double buffered registers + trigger if programming complete feature. */
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
*** actually program the registers ***
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* unknown, but needed (otherwise high-res distortions and only half the frames */
|
||||||
|
BESW(NV04_OE_STATE, 0x00000000);
|
||||||
|
/* select buffer 0 as active (b16) */
|
||||||
|
BESW(NV04_SU_STATE, 0x00000000);
|
||||||
|
/* unknown (no effect?) */
|
||||||
|
BESW(NV04_RM_STATE, 0x00000000);
|
||||||
|
/* setup clipped(!) buffer startadress in RAM */
|
||||||
|
/* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping
|
||||||
|
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
|
||||||
|
/* (program both buffers to prevent sync distortions) */
|
||||||
|
/* first include 'pixel precise' left clipping... (top clipping was already included) */
|
||||||
|
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
|
||||||
|
/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
|
||||||
|
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
|
||||||
|
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
|
||||||
|
/* setup buffer source pitch including slopspace (in bytes).
|
||||||
|
* Note:
|
||||||
|
* source pitch granularity = 16 pixels on the RIVA128 - TNT (so pre-NV10) bes */
|
||||||
|
/* (program both buffers to prevent sync distortions) */
|
||||||
|
BESW(NV04_0SRCPTCH, (ob->width * 2));
|
||||||
|
BESW(NV04_1SRCPTCH, (ob->width * 2));
|
||||||
|
/* setup output window position */
|
||||||
|
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
|
||||||
|
/* setup output window size */
|
||||||
|
BESW(NV04_DSTSIZE, (
|
||||||
|
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
|
||||||
|
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
|
||||||
|
));
|
||||||
|
/* setup horizontal and vertical scaling */
|
||||||
|
BESW(NV04_ISCALVH, (((viscalv << 16) >> 5) | (hiscalv >> 5)));
|
||||||
|
/* enable vertical filtering (b0) */
|
||||||
|
BESW(NV04_CTRL_V, 0x00000001);
|
||||||
|
/* enable horizontal filtering (no effect?) */
|
||||||
|
BESW(NV04_CTRL_H, 0x00000111);
|
||||||
|
|
||||||
|
/* enable BES (b0), enable colorkeying (b4), format yuy2 (b8: 0 = ccir) */
|
||||||
|
BESW(NV04_GENCTRL, 0x00000111);
|
||||||
|
/* select buffer 1 as active (b16) */
|
||||||
|
BESW(NV04_SU_STATE, 0x00010000);
|
||||||
|
|
||||||
|
/**************************
|
||||||
|
*** setup color keying ***
|
||||||
|
**************************/
|
||||||
|
|
||||||
|
/* setup colorkeying */
|
||||||
|
switch(si->dm.space)
|
||||||
|
{
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
BESW(NV04_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 5) |
|
||||||
|
((ow->red.value & ow->red.mask) << 10) |
|
||||||
|
((ow->alpha.value & ow->alpha.mask) << 15)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
BESW(NV04_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 5) |
|
||||||
|
((ow->red.value & ow->red.mask) << 11)
|
||||||
|
/* this space has no alpha bits */
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case B_CMAP8:
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
default:
|
||||||
|
BESW(NV04_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 8) |
|
||||||
|
((ow->red.value & ow->red.mask) << 16) |
|
||||||
|
((ow->alpha.value & ow->alpha.mask) << 24)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* >= NV10A */
|
||||||
|
|
||||||
|
/* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */
|
||||||
|
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
|
||||||
|
/* setup buffersize */
|
||||||
|
//fixme if needed: width must be even officially...
|
||||||
|
BESW(NV10_0SRCSIZE, ((ob->height << 16) | ob->width));
|
||||||
|
/* setup source pitch including slopspace (in bytes),
|
||||||
|
* b16: select YUY2 (0 = YV12), b20: use colorkey, b24: no iturbt_709 (do iturbt_601) */
|
||||||
|
/* Note:
|
||||||
|
* source pitch granularity = 32 pixels on GeForce cards!! */
|
||||||
|
BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (1 << 20) | (0 << 24)));
|
||||||
|
/* setup output window position */
|
||||||
|
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
|
||||||
|
/* setup output window size */
|
||||||
|
BESW(NV10_0DSTSIZE, (
|
||||||
|
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
|
||||||
|
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
|
||||||
|
));
|
||||||
|
/* setup horizontal scaling */
|
||||||
|
BESW(NV10_0ISCALH, (hiscalv << 4));
|
||||||
|
/* setup vertical scaling */
|
||||||
|
BESW(NV10_0ISCALV, (viscalv << 4));
|
||||||
|
/* setup (unclipped!) buffer startadress in RAM */
|
||||||
|
BESW(NV10_0BUFADR, moi.a1orgv);
|
||||||
|
/* enable BES (b0 = 0) */
|
||||||
|
BESW(NV10_GENCTRL, 0x00000000);
|
||||||
|
/* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */
|
||||||
|
/* This also triggers activation of programmed values (double buffered registers feature) */
|
||||||
|
BESW(NV10_BUFSEL, 0x00000001);
|
||||||
|
|
||||||
|
/**************************
|
||||||
|
*** setup color keying ***
|
||||||
|
**************************/
|
||||||
|
|
||||||
|
/* setup colorkeying */
|
||||||
|
switch(si->dm.space)
|
||||||
|
{
|
||||||
|
case B_RGB15_LITTLE:
|
||||||
|
BESW(NV10_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 5) |
|
||||||
|
((ow->red.value & ow->red.mask) << 10) |
|
||||||
|
((ow->alpha.value & ow->alpha.mask) << 15)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case B_RGB16_LITTLE:
|
||||||
|
BESW(NV10_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 5) |
|
||||||
|
((ow->red.value & ow->red.mask) << 11)
|
||||||
|
/* this space has no alpha bits */
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case B_CMAP8:
|
||||||
|
case B_RGB32_LITTLE:
|
||||||
|
default:
|
||||||
|
BESW(NV10_COLKEY, (
|
||||||
|
((ow->blue.value & ow->blue.mask) << 0) |
|
||||||
|
((ow->green.value & ow->green.mask) << 8) |
|
||||||
|
((ow->red.value & ow->red.mask) << 16) |
|
||||||
|
((ow->alpha.value & ow->alpha.mask) << 24)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* note that overlay is in use (for nv_bes_move_overlay()) */
|
||||||
|
si->overlay.active = true;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_release_bes()
|
||||||
|
{
|
||||||
|
if (si->ps.card_arch < NV10A)
|
||||||
|
{
|
||||||
|
/* setup BES control: disable scaler (b0 = 0) */
|
||||||
|
BESW(NV04_GENCTRL, 0x00000000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* setup BES control: disable scaler (b0 = 1) */
|
||||||
|
BESW(NV10_GENCTRL, 0x00000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* note that overlay is not in use (for nv_bes_move_overlay()) */
|
||||||
|
si->overlay.active = false;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,829 @@
|
|||||||
|
/* CTRC functionality */
|
||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 11/2002-9/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
/* if hor. total does not adhere to max. blanking pulse width, decrease it! */
|
||||||
|
if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* if vert. total does not adhere to max. blanking pulse width, decrease it! */
|
||||||
|
if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
|
||||||
|
|
||||||
|
/* 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"));
|
||||||
|
|
||||||
|
/* setup tuned internal modeline for flatpanel if connected and active */
|
||||||
|
/* notes:
|
||||||
|
* - the CRTC modeline must end earlier than the panel modeline to keep correct
|
||||||
|
* sync going;
|
||||||
|
* - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel
|
||||||
|
* wide horizontal stripes. This can be observed earliest on fullscreen overlay,
|
||||||
|
* and if it gets worse, also normal desktop output will suffer. The stripes
|
||||||
|
* are mainly visible at the left of the screen, over the entire screen height. */
|
||||||
|
if (si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC: DFP active: tuning modeline\n"));
|
||||||
|
|
||||||
|
/* horizontal timing */
|
||||||
|
target.timing.h_sync_start =
|
||||||
|
((uint16)((si->ps.p1_timing.h_sync_start / ((float)si->ps.p1_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8;
|
||||||
|
|
||||||
|
target.timing.h_sync_end =
|
||||||
|
((uint16)((si->ps.p1_timing.h_sync_end / ((float)si->ps.p1_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8;
|
||||||
|
|
||||||
|
target.timing.h_total =
|
||||||
|
(((uint16)((si->ps.p1_timing.h_total / ((float)si->ps.p1_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8) - 8;
|
||||||
|
|
||||||
|
/* in native mode the CRTC needs some extra time to keep synced correctly;
|
||||||
|
* OTOH the overlay unit distorts if we reserve too much time! */
|
||||||
|
if (target.timing.h_display == si->ps.p1_timing.h_display)
|
||||||
|
{
|
||||||
|
/* NV11 timing has different constraints than later cards */
|
||||||
|
if (si->ps.card_type == NV11)
|
||||||
|
target.timing.h_total -= 56;
|
||||||
|
else
|
||||||
|
/* confirmed NV34 with 1680x1050 panel */
|
||||||
|
target.timing.h_total -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.timing.h_sync_start == target.timing.h_display)
|
||||||
|
target.timing.h_sync_start += 8;
|
||||||
|
if (target.timing.h_sync_end == target.timing.h_total)
|
||||||
|
target.timing.h_sync_end -= 8;
|
||||||
|
|
||||||
|
/* vertical timing */
|
||||||
|
target.timing.v_sync_start =
|
||||||
|
((uint16)((si->ps.p1_timing.v_sync_start / ((float)si->ps.p1_timing.v_display)) *
|
||||||
|
target.timing.v_display));
|
||||||
|
|
||||||
|
target.timing.v_sync_end =
|
||||||
|
((uint16)((si->ps.p1_timing.v_sync_end / ((float)si->ps.p1_timing.v_display)) *
|
||||||
|
target.timing.v_display));
|
||||||
|
|
||||||
|
target.timing.v_total =
|
||||||
|
((uint16)((si->ps.p1_timing.v_total / ((float)si->ps.p1_timing.v_display)) *
|
||||||
|
target.timing.v_display)) - 1;
|
||||||
|
|
||||||
|
if (target.timing.v_sync_start == target.timing.v_display)
|
||||||
|
target.timing.v_sync_start += 1;
|
||||||
|
if (target.timing.v_sync_end == target.timing.v_total)
|
||||||
|
target.timing.v_sync_end -= 1;
|
||||||
|
|
||||||
|
/* disable GPU scaling testmode so automatic scaling will be done */
|
||||||
|
DACW(FP_DEBUG1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* Note for laptop and DVI flatpanels:
|
||||||
|
* CRTC timing has a seperate set of registers from flatpanel timing.
|
||||||
|
* The flatpanel timing registers have scaling registers that are used to match
|
||||||
|
* these two modelines. */
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC: 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)
|
||||||
|
));
|
||||||
|
|
||||||
|
/* more vertical extended regs (on GeForce cards only) */
|
||||||
|
if (si->ps.card_arch >= NV10A)
|
||||||
|
{
|
||||||
|
CRTCW(EXTRA,
|
||||||
|
(
|
||||||
|
((vtotal & 0x800) >> (11 - 0)) |
|
||||||
|
((vdisp_e & 0x800) >> (11 - 2)) |
|
||||||
|
((vsync_s & 0x800) >> (11 - 4)) |
|
||||||
|
((vblnk_s & 0x800) >> (11 - 6))
|
||||||
|
//fixme: do we miss another linecomp bit!?!
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always disable interlaced operation */
|
||||||
|
/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
|
||||||
|
CRTCW(INTERLACE, 0xff);
|
||||||
|
|
||||||
|
/* disable CRTC slaved mode unless a panel is in use */
|
||||||
|
// fixme: this kills TVout when it was in use...
|
||||||
|
if (!si->ps.tmds1_active) CRTCW(PIXEL, (CRTCR(PIXEL) & 0x7f));
|
||||||
|
|
||||||
|
/* setup flatpanel if connected and active */
|
||||||
|
if (si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
uint32 iscale_x, iscale_y;
|
||||||
|
|
||||||
|
/* calculate inverse scaling factors used by hardware in 20.12 format */
|
||||||
|
iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p1_timing.h_display);
|
||||||
|
iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p1_timing.v_display);
|
||||||
|
|
||||||
|
/* unblock flatpanel timing programming (or something like that..) */
|
||||||
|
CRTCW(FP_HTIMING, 0);
|
||||||
|
CRTCW(FP_VTIMING, 0);
|
||||||
|
LOG(2,("CRTC: FP_HTIMING reg readback: $%02x\n", CRTCR(FP_HTIMING)));
|
||||||
|
LOG(2,("CRTC: FP_VTIMING reg readback: $%02x\n", CRTCR(FP_VTIMING)));
|
||||||
|
|
||||||
|
/* enable full width visibility on flatpanel */
|
||||||
|
DACW(FP_HVALID_S, 0);
|
||||||
|
DACW(FP_HVALID_E, (si->ps.p1_timing.h_display - 1));
|
||||||
|
/* enable full height visibility on flatpanel */
|
||||||
|
DACW(FP_VVALID_S, 0);
|
||||||
|
DACW(FP_VVALID_E, (si->ps.p1_timing.v_display - 1));
|
||||||
|
|
||||||
|
/* nVidia cards support upscaling except on ??? */
|
||||||
|
/* NV11 cards can upscale after all! */
|
||||||
|
if (0)//si->ps.card_type == NV11)
|
||||||
|
{
|
||||||
|
/* disable last fetched line limiting */
|
||||||
|
DACW(FP_DEBUG2, 0x00000000);
|
||||||
|
/* inform panel to scale if needed */
|
||||||
|
if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12)))
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC: DFP needs to do scaling\n"));
|
||||||
|
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) | 0x00000100));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC: no scaling for DFP needed\n"));
|
||||||
|
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float dm_aspect;
|
||||||
|
|
||||||
|
LOG(2,("CRTC: GPU scales for DFP if needed\n"));
|
||||||
|
|
||||||
|
/* calculate display mode aspect */
|
||||||
|
dm_aspect = (target.timing.h_display / ((float)target.timing.v_display));
|
||||||
|
|
||||||
|
/* limit last fetched line if vertical scaling is done */
|
||||||
|
if (iscale_y != (1 << 12))
|
||||||
|
DACW(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16)));
|
||||||
|
else
|
||||||
|
DACW(FP_DEBUG2, 0x00000000);
|
||||||
|
|
||||||
|
/* inform panel not to scale */
|
||||||
|
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff));
|
||||||
|
|
||||||
|
/* GPU scaling is automatically setup by hardware, so only modify this
|
||||||
|
* scalingfactor for non 4:3 (1.33) aspect panels;
|
||||||
|
* let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */
|
||||||
|
|
||||||
|
/* correct for widescreen panels relative to mode...
|
||||||
|
* (so if panel is more widescreen than mode being set) */
|
||||||
|
/* BTW: known widescreen panels:
|
||||||
|
* 1280 x 800 (1.60),
|
||||||
|
* 1440 x 900 (1.60),
|
||||||
|
* 1680 x 1050 (1.60),
|
||||||
|
* 1920 x 1200 (1.60). */
|
||||||
|
/* known 4:3 aspect non-standard resolution panels:
|
||||||
|
* 1400 x 1050 (1.33). */
|
||||||
|
/* NOTE:
|
||||||
|
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
|
||||||
|
if ((iscale_x != (1 << 12)) && (si->ps.panel1_aspect > (dm_aspect + 0.10)))
|
||||||
|
{
|
||||||
|
uint16 diff;
|
||||||
|
|
||||||
|
LOG(2,("CRTC: (relative) widescreen panel: tuning horizontal scaling\n"));
|
||||||
|
|
||||||
|
/* X-scaling should be the same as Y-scaling */
|
||||||
|
iscale_x = iscale_y;
|
||||||
|
/* enable testmode (b12) and program modified X-scaling factor */
|
||||||
|
DACW(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12)));
|
||||||
|
/* center/cut-off left and right side of screen */
|
||||||
|
diff = ((si->ps.p1_timing.h_display -
|
||||||
|
(target.timing.h_display * ((1 << 12) / ((float)iscale_x))))
|
||||||
|
/ 2);
|
||||||
|
DACW(FP_HVALID_S, diff);
|
||||||
|
DACW(FP_HVALID_E, ((si->ps.p1_timing.h_display - diff) - 1));
|
||||||
|
}
|
||||||
|
/* correct for portrait panels... */
|
||||||
|
/* NOTE:
|
||||||
|
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
|
||||||
|
if ((iscale_y != (1 << 12)) && (si->ps.panel1_aspect < (dm_aspect - 0.10)))
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n"));
|
||||||
|
/* fixme: implement if this kind of portrait panels exist on nVidia... */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do some logging.. */
|
||||||
|
LOG(2,("CRTC: FP_HVALID_S reg readback: $%08x\n", DACR(FP_HVALID_S)));
|
||||||
|
LOG(2,("CRTC: FP_HVALID_E reg readback: $%08x\n", DACR(FP_HVALID_E)));
|
||||||
|
LOG(2,("CRTC: FP_VVALID_S reg readback: $%08x\n", DACR(FP_VVALID_S)));
|
||||||
|
LOG(2,("CRTC: FP_VVALID_E reg readback: $%08x\n", DACR(FP_VVALID_E)));
|
||||||
|
LOG(2,("CRTC: FP_DEBUG0 reg readback: $%08x\n", DACR(FP_DEBUG0)));
|
||||||
|
LOG(2,("CRTC: FP_DEBUG1 reg readback: $%08x\n", DACR(FP_DEBUG1)));
|
||||||
|
LOG(2,("CRTC: FP_DEBUG2 reg readback: $%08x\n", DACR(FP_DEBUG2)));
|
||||||
|
LOG(2,("CRTC: FP_DEBUG3 reg readback: $%08x\n", DACR(FP_DEBUG3)));
|
||||||
|
LOG(2,("CRTC: FP_TG_CTRL reg readback: $%08x\n", DACR(FP_TG_CTRL)));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
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: "));
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
//'safe mode' test! feedback needed with this 'setting'!
|
||||||
|
if (0)//si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
/* powerup both LVDS (laptop panellink) and TMDS (DVI panellink)
|
||||||
|
* internal transmitters... */
|
||||||
|
/* note:
|
||||||
|
* the powerbits in this register are hardwired to the DVI connectors,
|
||||||
|
* instead of to the DACs! (confirmed NV34) */
|
||||||
|
//fixme...
|
||||||
|
DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff));
|
||||||
|
/* ... and powerup external TMDS transmitter if it exists */
|
||||||
|
/* (confirmed OK on NV28 and NV34) */
|
||||||
|
CRTCW(0x59, (CRTCR(0x59) | 0x01));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4,("display on, "));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SEQW(CLKMODE, (temp | 0x20));
|
||||||
|
|
||||||
|
//'safe mode' test! feedback needed with this 'setting'!
|
||||||
|
if (0)//si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
/* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink)
|
||||||
|
* internal transmitters... */
|
||||||
|
/* note:
|
||||||
|
* the powerbits in this register are hardwired to the DVI connectors,
|
||||||
|
* instead of to the DACs! (confirmed NV34) */
|
||||||
|
//fixme...
|
||||||
|
DACW(FP_DEBUG0, (DACR(FP_DEBUG0) | 0x30000000));
|
||||||
|
/* ... and powerdown external TMDS transmitter if it exists */
|
||||||
|
/* (confirmed OK on NV28 and NV34) */
|
||||||
|
CRTCW(0x59, (CRTCR(0x59) & 0xfe));
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
*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));
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
uint32 timeout = 0;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* we might have no retraces during setmode! */
|
||||||
|
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
|
||||||
|
while (((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) &&
|
||||||
|
(timeout < (25000/10)))
|
||||||
|
{
|
||||||
|
/* don't snooze much longer or retrace might get missed! */
|
||||||
|
snooze(10);
|
||||||
|
timeout++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
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) */
|
||||||
|
ATBW(HORPIXPAN, ((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;
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* set cursor bitmap adress ... */
|
||||||
|
if ((si->ps.card_arch == NV04A) || (si->ps.laptop))
|
||||||
|
{
|
||||||
|
/* must be used this way on pre-NV10 and on all 'Go' cards! */
|
||||||
|
|
||||||
|
/* 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:
|
||||||
|
* can be used on NV10 and later (except for 'Go' cards)! */
|
||||||
|
/* NOTE:
|
||||||
|
* This register does not exist on pre-NV10 and 'Go' 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 */
|
||||||
|
nv_crtc_cursor_show();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc_cursor_show()
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC: enabling cursor\n"));
|
||||||
|
|
||||||
|
/* enable access to CRTC1 on dualhead cards */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* b0 = 1 enables cursor */
|
||||||
|
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc_cursor_hide()
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC: disabling cursor\n"));
|
||||||
|
|
||||||
|
/* enable access to primary head */
|
||||||
|
set_crtc_owner(0);
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
uint16 yhigh;
|
||||||
|
|
||||||
|
/* make sure we are beyond the first line of the cursorbitmap being drawn during
|
||||||
|
* updating the position to prevent distortions: no double buffering feature */
|
||||||
|
/* Note:
|
||||||
|
* we need to return as quick as possible or some apps will exhibit lagging.. */
|
||||||
|
|
||||||
|
/* read the old cursor Y position */
|
||||||
|
yhigh = ((DACR(CURPOS) & 0x0fff0000) >> 16);
|
||||||
|
/* make sure we will wait until we are below both the old and new Y position:
|
||||||
|
* visible cursorbitmap drawing needs to be done at least... */
|
||||||
|
if (y > yhigh) yhigh = y;
|
||||||
|
|
||||||
|
if (yhigh < (si->dm.timing.v_display - 16))
|
||||||
|
{
|
||||||
|
/* we have vertical lines below old and new cursorposition to spare. So we
|
||||||
|
* update the cursor postion 'mid-screen', but below that area. */
|
||||||
|
while (((uint16)(NV_REG32(NV32_RASTER) & 0x000007ff)) < (yhigh + 16))
|
||||||
|
{
|
||||||
|
snooze(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no room to spare, just wait for retrace (is relatively slow) */
|
||||||
|
while ((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display)
|
||||||
|
{
|
||||||
|
/* don't snooze much longer or retrace might get missed! */
|
||||||
|
snooze(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update cursorposition */
|
||||||
|
DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,791 @@
|
|||||||
|
/* second CTRC functionality for GeForce cards */
|
||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 11/2002-9/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00020000
|
||||||
|
|
||||||
|
#include "nv_std.h"
|
||||||
|
|
||||||
|
/*Adjust passed parameters to a valid mode line*/
|
||||||
|
status_t nv_crtc2_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 (*hd_e > 2048) *hd_e = 2048;
|
||||||
|
|
||||||
|
/* if hor. total does not leave room for a sensible sync pulse, increase it! */
|
||||||
|
if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
|
||||||
|
|
||||||
|
/* if hor. total does not adhere to max. blanking pulse width, decrease it! */
|
||||||
|
if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
|
||||||
|
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 (*vd_e > 1536) *vd_e = 1536;
|
||||||
|
|
||||||
|
/*if vertical total does not leave room for a sync pulse, increase it!*/
|
||||||
|
if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
|
||||||
|
|
||||||
|
/* if vert. total does not adhere to max. blanking pulse width, decrease it! */
|
||||||
|
if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
|
||||||
|
|
||||||
|
/* 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_crtc2_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,("CRTC2: setting timing\n"));
|
||||||
|
|
||||||
|
/* setup tuned internal modeline for flatpanel if connected and active */
|
||||||
|
/* notes:
|
||||||
|
* - the CRTC modeline must end earlier than the panel modeline to keep correct
|
||||||
|
* sync going;
|
||||||
|
* - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel
|
||||||
|
* wide horizontal stripes. This can be observed earliest on fullscreen overlay,
|
||||||
|
* and if it gets worse, also normal desktop output will suffer. The stripes
|
||||||
|
* are mainly visible at the left of the screen, over the entire screen height. */
|
||||||
|
if (si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC2: DFP active: tuning modeline\n"));
|
||||||
|
|
||||||
|
/* horizontal timing */
|
||||||
|
target.timing.h_sync_start =
|
||||||
|
((uint16)((si->ps.p2_timing.h_sync_start / ((float)si->ps.p2_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8;
|
||||||
|
|
||||||
|
target.timing.h_sync_end =
|
||||||
|
((uint16)((si->ps.p2_timing.h_sync_end / ((float)si->ps.p2_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8;
|
||||||
|
|
||||||
|
target.timing.h_total =
|
||||||
|
(((uint16)((si->ps.p2_timing.h_total / ((float)si->ps.p2_timing.h_display)) *
|
||||||
|
target.timing.h_display)) & 0xfff8) - 8;
|
||||||
|
|
||||||
|
/* in native mode the CRTC needs some extra time to keep synced correctly;
|
||||||
|
* OTOH the overlay unit distorts if we reserve too much time! */
|
||||||
|
if (target.timing.h_display == si->ps.p2_timing.h_display)
|
||||||
|
{
|
||||||
|
/* NV11 timing has different constraints than later cards */
|
||||||
|
if (si->ps.card_type == NV11)
|
||||||
|
target.timing.h_total -= 56;
|
||||||
|
else
|
||||||
|
/* confirmed NV34 with 1680x1050 panel */
|
||||||
|
target.timing.h_total -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.timing.h_sync_start == target.timing.h_display)
|
||||||
|
target.timing.h_sync_start += 8;
|
||||||
|
if (target.timing.h_sync_end == target.timing.h_total)
|
||||||
|
target.timing.h_sync_end -= 8;
|
||||||
|
|
||||||
|
/* vertical timing */
|
||||||
|
target.timing.v_sync_start =
|
||||||
|
((uint16)((si->ps.p2_timing.v_sync_start / ((float)si->ps.p2_timing.v_display)) *
|
||||||
|
target.timing.v_display));
|
||||||
|
|
||||||
|
target.timing.v_sync_end =
|
||||||
|
((uint16)((si->ps.p2_timing.v_sync_end / ((float)si->ps.p2_timing.v_display)) *
|
||||||
|
target.timing.v_display));
|
||||||
|
|
||||||
|
target.timing.v_total =
|
||||||
|
((uint16)((si->ps.p2_timing.v_total / ((float)si->ps.p2_timing.v_display)) *
|
||||||
|
target.timing.v_display)) - 1;
|
||||||
|
|
||||||
|
if (target.timing.v_sync_start == target.timing.v_display)
|
||||||
|
target.timing.v_sync_start += 1;
|
||||||
|
if (target.timing.v_sync_end == target.timing.v_total)
|
||||||
|
target.timing.v_sync_end -= 1;
|
||||||
|
|
||||||
|
/* disable GPU scaling testmode so automatic scaling will be done */
|
||||||
|
DAC2W(FP_DEBUG1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* Note for laptop and DVI flatpanels:
|
||||||
|
* CRTC timing has a seperate set of registers from flatpanel timing.
|
||||||
|
* The flatpanel timing registers have scaling registers that are used to match
|
||||||
|
* these two modelines. */
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC2: Setting full timing...\n"));
|
||||||
|
|
||||||
|
/* log the mode that will be set */
|
||||||
|
LOG(2,("CRTC2:\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 */
|
||||||
|
CRTC2W(VSYNCE, (CRTC2R(VSYNCE) & 0x7f));
|
||||||
|
/* horizontal standard VGA regs */
|
||||||
|
CRTC2W(HTOTAL, (htotal & 0xff));
|
||||||
|
CRTC2W(HDISPE, (hdisp_e & 0xff));
|
||||||
|
CRTC2W(HBLANKS, (hblnk_s & 0xff));
|
||||||
|
/* also unlock vertical retrace registers in advance */
|
||||||
|
CRTC2W(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
|
||||||
|
CRTC2W(HSYNCS, (hsync_s & 0xff));
|
||||||
|
CRTC2W(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
|
||||||
|
|
||||||
|
/* vertical standard VGA regs */
|
||||||
|
CRTC2W(VTOTAL, (vtotal & 0xff));
|
||||||
|
CRTC2W(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))
|
||||||
|
));
|
||||||
|
CRTC2W(PRROWSCN, 0x00); /* not used */
|
||||||
|
CRTC2W(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
|
||||||
|
CRTC2W(VSYNCS, (vsync_s & 0xff));
|
||||||
|
CRTC2W(VSYNCE, ((CRTC2R(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
|
||||||
|
CRTC2W(VDISPE, (vdisp_e & 0xff));
|
||||||
|
CRTC2W(VBLANKS, (vblnk_s & 0xff));
|
||||||
|
CRTC2W(VBLANKE, (vblnk_e & 0xff));
|
||||||
|
CRTC2W(LINECOMP, (linecomp & 0xff));
|
||||||
|
|
||||||
|
/* horizontal extended regs */
|
||||||
|
//fixme: we reset bit4. is this correct??
|
||||||
|
CRTC2W(HEB, (CRTC2R(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 */
|
||||||
|
CRTC2W(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)
|
||||||
|
));
|
||||||
|
|
||||||
|
/* more vertical extended regs */
|
||||||
|
CRTC2W(EXTRA,
|
||||||
|
(
|
||||||
|
((vtotal & 0x800) >> (11 - 0)) |
|
||||||
|
((vdisp_e & 0x800) >> (11 - 2)) |
|
||||||
|
((vsync_s & 0x800) >> (11 - 4)) |
|
||||||
|
((vblnk_s & 0x800) >> (11 - 6))
|
||||||
|
//fixme: do we miss another linecomp bit!?!
|
||||||
|
));
|
||||||
|
|
||||||
|
/* setup 'large screen' mode */
|
||||||
|
if (target.timing.h_display >= 1280)
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xfb));
|
||||||
|
else
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x04));
|
||||||
|
|
||||||
|
/* setup HSYNC & VSYNC polarity */
|
||||||
|
LOG(2,("CRTC2: 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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always disable interlaced operation */
|
||||||
|
/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
|
||||||
|
CRTC2W(INTERLACE, 0xff);
|
||||||
|
|
||||||
|
/* disable CRTC slaved mode unless a panel is in use */
|
||||||
|
// fixme: this kills TVout when it was in use...
|
||||||
|
if (!si->ps.tmds2_active) CRTC2W(PIXEL, (CRTC2R(PIXEL) & 0x7f));
|
||||||
|
|
||||||
|
/* setup flatpanel if connected and active */
|
||||||
|
if (si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
uint32 iscale_x, iscale_y;
|
||||||
|
|
||||||
|
/* calculate inverse scaling factors used by hardware in 20.12 format */
|
||||||
|
iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p2_timing.h_display);
|
||||||
|
iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p2_timing.v_display);
|
||||||
|
|
||||||
|
/* unblock flatpanel timing programming (or something like that..) */
|
||||||
|
CRTC2W(FP_HTIMING, 0);
|
||||||
|
CRTC2W(FP_VTIMING, 0);
|
||||||
|
LOG(2,("CRTC2: FP_HTIMING reg readback: $%02x\n", CRTC2R(FP_HTIMING)));
|
||||||
|
LOG(2,("CRTC2: FP_VTIMING reg readback: $%02x\n", CRTC2R(FP_VTIMING)));
|
||||||
|
|
||||||
|
/* enable full width visibility on flatpanel */
|
||||||
|
DAC2W(FP_HVALID_S, 0);
|
||||||
|
DAC2W(FP_HVALID_E, (si->ps.p2_timing.h_display - 1));
|
||||||
|
/* enable full height visibility on flatpanel */
|
||||||
|
DAC2W(FP_VVALID_S, 0);
|
||||||
|
DAC2W(FP_VVALID_E, (si->ps.p2_timing.v_display - 1));
|
||||||
|
|
||||||
|
/* nVidia cards support upscaling except on ??? */
|
||||||
|
/* NV11 cards can upscale after all! */
|
||||||
|
if (0)//si->ps.card_type == NV11)
|
||||||
|
{
|
||||||
|
/* disable last fetched line limiting */
|
||||||
|
DAC2W(FP_DEBUG2, 0x00000000);
|
||||||
|
/* inform panel to scale if needed */
|
||||||
|
if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12)))
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC2: DFP needs to do scaling\n"));
|
||||||
|
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) | 0x00000100));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC2: no scaling for DFP needed\n"));
|
||||||
|
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float dm_aspect;
|
||||||
|
|
||||||
|
LOG(2,("CRTC2: GPU scales for DFP if needed\n"));
|
||||||
|
|
||||||
|
/* calculate display mode aspect */
|
||||||
|
dm_aspect = (target.timing.h_display / ((float)target.timing.v_display));
|
||||||
|
|
||||||
|
/* limit last fetched line if vertical scaling is done */
|
||||||
|
if (iscale_y != (1 << 12))
|
||||||
|
DAC2W(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16)));
|
||||||
|
else
|
||||||
|
DAC2W(FP_DEBUG2, 0x00000000);
|
||||||
|
|
||||||
|
/* inform panel not to scale */
|
||||||
|
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
|
||||||
|
|
||||||
|
/* GPU scaling is automatically setup by hardware, so only modify this
|
||||||
|
* scalingfactor for non 4:3 (1.33) aspect panels;
|
||||||
|
* let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */
|
||||||
|
|
||||||
|
/* correct for widescreen panels relative to mode...
|
||||||
|
* (so if panel is more widescreen than mode being set) */
|
||||||
|
/* BTW: known widescreen panels:
|
||||||
|
* 1280 x 800 (1.60),
|
||||||
|
* 1440 x 900 (1.60),
|
||||||
|
* 1680 x 1050 (1.60),
|
||||||
|
* 1920 x 1200 (1.60). */
|
||||||
|
/* known 4:3 aspect non-standard resolution panels:
|
||||||
|
* 1400 x 1050 (1.33). */
|
||||||
|
/* NOTE:
|
||||||
|
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
|
||||||
|
if ((iscale_x != (1 << 12)) && (si->ps.panel2_aspect > (dm_aspect + 0.10)))
|
||||||
|
{
|
||||||
|
uint16 diff;
|
||||||
|
|
||||||
|
LOG(2,("CRTC2: (relative) widescreen panel: tuning horizontal scaling\n"));
|
||||||
|
|
||||||
|
/* X-scaling should be the same as Y-scaling */
|
||||||
|
iscale_x = iscale_y;
|
||||||
|
/* enable testmode (b12) and program new X-scaling factor */
|
||||||
|
DAC2W(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12)));
|
||||||
|
/* center/cut-off left and right side of screen */
|
||||||
|
diff = ((si->ps.p2_timing.h_display -
|
||||||
|
(target.timing.h_display * ((1 << 12) / ((float)iscale_x))))
|
||||||
|
/ 2);
|
||||||
|
DAC2W(FP_HVALID_S, diff);
|
||||||
|
DAC2W(FP_HVALID_E, ((si->ps.p2_timing.h_display - diff) - 1));
|
||||||
|
}
|
||||||
|
/* correct for portrait panels... */
|
||||||
|
/* NOTE:
|
||||||
|
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
|
||||||
|
if ((iscale_y != (1 << 12)) && (si->ps.panel2_aspect < (dm_aspect - 0.10)))
|
||||||
|
{
|
||||||
|
LOG(2,("CRTC2: (relative) portrait panel: should tune vertical scaling\n"));
|
||||||
|
/* fixme: implement if this kind of portrait panels exist on nVidia... */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do some logging.. */
|
||||||
|
LOG(2,("CRTC2: FP_HVALID_S reg readback: $%08x\n", DAC2R(FP_HVALID_S)));
|
||||||
|
LOG(2,("CRTC2: FP_HVALID_E reg readback: $%08x\n", DAC2R(FP_HVALID_E)));
|
||||||
|
LOG(2,("CRTC2: FP_VVALID_S reg readback: $%08x\n", DAC2R(FP_VVALID_S)));
|
||||||
|
LOG(2,("CRTC2: FP_VVALID_E reg readback: $%08x\n", DAC2R(FP_VVALID_E)));
|
||||||
|
LOG(2,("CRTC2: FP_DEBUG0 reg readback: $%08x\n", DAC2R(FP_DEBUG0)));
|
||||||
|
LOG(2,("CRTC2: FP_DEBUG1 reg readback: $%08x\n", DAC2R(FP_DEBUG1)));
|
||||||
|
LOG(2,("CRTC2: FP_DEBUG2 reg readback: $%08x\n", DAC2R(FP_DEBUG2)));
|
||||||
|
LOG(2,("CRTC2: FP_DEBUG3 reg readback: $%08x\n", DAC2R(FP_DEBUG3)));
|
||||||
|
LOG(2,("CRTC2: FP_TG_CTRL reg readback: $%08x\n", DAC2R(FP_TG_CTRL)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_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;
|
||||||
|
}
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
CRTC2W(PIXEL, ((CRTC2R(PIXEL) & 0xfc) | viddelay));
|
||||||
|
DAC2W(GENCTRL, genctrl);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_dpms(bool display, bool h, bool v)
|
||||||
|
{
|
||||||
|
uint8 temp;
|
||||||
|
|
||||||
|
LOG(4,("CRTC2: setting DPMS: "));
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
//'safe mode' test! feedback needed with this 'setting'!
|
||||||
|
if (0)//si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
/* powerup both LVDS (laptop panellink) and TMDS (DVI panellink)
|
||||||
|
* internal transmitters... */
|
||||||
|
/* note:
|
||||||
|
* the powerbits in this register are hardwired to the DVI connectors,
|
||||||
|
* instead of to the DACs! (confirmed NV34) */
|
||||||
|
//fixme...
|
||||||
|
DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) & 0xcfffffff));
|
||||||
|
/* ... and powerup external TMDS transmitter if it exists */
|
||||||
|
/* (confirmed OK on NV28 and NV34) */
|
||||||
|
CRTC2W(0x59, (CRTC2R(0x59) | 0x01));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4,("display on, "));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SEQW(CLKMODE, (temp | 0x20));
|
||||||
|
|
||||||
|
//'safe mode' test! feedback needed with this 'setting'!
|
||||||
|
if (0)//si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
/* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink)
|
||||||
|
* internal transmitters... */
|
||||||
|
/* note:
|
||||||
|
* the powerbits in this register are hardwired to the DVI connectors,
|
||||||
|
* instead of to the DACs! (confirmed NV34) */
|
||||||
|
//fixme...
|
||||||
|
DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) | 0x30000000));
|
||||||
|
/* ... and powerdown external TMDS transmitter if it exists */
|
||||||
|
/* (confirmed OK on NV28 and NV34) */
|
||||||
|
CRTC2W(0x59, (CRTC2R(0x59) & 0xfe));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4,("display off, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0x7f));
|
||||||
|
LOG(4,("hsync enabled, "));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x80));
|
||||||
|
LOG(4,("hsync disabled, "));
|
||||||
|
}
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xbf));
|
||||||
|
LOG(4,("vsync enabled\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x40));
|
||||||
|
LOG(4,("vsync disabled\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_dpms_fetch(bool *display, bool *h, bool *v)
|
||||||
|
{
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
*display = !(SEQR(CLKMODE) & 0x20);
|
||||||
|
*h = !(CRTC2R(REPAINT1) & 0x80);
|
||||||
|
*v = !(CRTC2R(REPAINT1) & 0x40);
|
||||||
|
|
||||||
|
LOG(4,("CTRC2: 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_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 / 8;
|
||||||
|
|
||||||
|
LOG(2,("CRTC2: offset register set to: $%04x\n", offset));
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* program the card */
|
||||||
|
CRTC2W(PITCHL, (offset & 0x00ff));
|
||||||
|
CRTC2W(REPAINT0, ((CRTC2R(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp)
|
||||||
|
{
|
||||||
|
uint32 timeout = 0;
|
||||||
|
|
||||||
|
LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
|
||||||
|
|
||||||
|
LOG(2,("CRTC2: startadd: $%08x\n", startadd));
|
||||||
|
LOG(2,("CRTC2: frameRAM: $%08x\n", si->framebuffer));
|
||||||
|
LOG(2,("CRTC2: framebuffer: $%08x\n", si->fbc.frame_buffer));
|
||||||
|
|
||||||
|
/* we might have no retraces during setmode! */
|
||||||
|
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
|
||||||
|
while (((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) &&
|
||||||
|
(timeout < (25000/10)))
|
||||||
|
{
|
||||||
|
/* don't snooze much longer or retrace might get missed! */
|
||||||
|
snooze(10);
|
||||||
|
timeout++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* 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_NV10FB2STADD32) = (startadd & 0xfffffffc);
|
||||||
|
|
||||||
|
/* set byte adress: (b0 - 1) */
|
||||||
|
ATB2W(HORPIXPAN, ((startadd & 0x00000003) << 1));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_cursor_init()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32 * fb;
|
||||||
|
/* cursor bitmap will be stored at the start of the framebuffer */
|
||||||
|
const uint32 curadd = 0;
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* set cursor bitmap adress ... */
|
||||||
|
if (si->ps.laptop)
|
||||||
|
{
|
||||||
|
/* must be used this way on pre-NV10 and on all 'Go' cards! */
|
||||||
|
|
||||||
|
/* cursorbitmap must start on 2Kbyte boundary: */
|
||||||
|
/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
|
||||||
|
CRTC2W(CURCTL0, ((curadd & 0x0001f800) >> 9));
|
||||||
|
/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
|
||||||
|
CRTC2W(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
|
||||||
|
/* set adress bit24-31 */
|
||||||
|
CRTC2W(CURCTL2, ((curadd & 0xff000000) >> 24));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* upto 4Gb RAM adressing:
|
||||||
|
* can be used on NV10 and later (except for 'Go' cards)! */
|
||||||
|
/* NOTE:
|
||||||
|
* This register does not exist on pre-NV10 and 'Go' cards. */
|
||||||
|
|
||||||
|
/* cursorbitmap must still start on 2Kbyte boundary: */
|
||||||
|
NV_REG32(NV32_NV10CUR2ADD32) = (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_2CURCONF) = 0x02000100;
|
||||||
|
|
||||||
|
/* activate hardware cursor */
|
||||||
|
nv_crtc2_cursor_show();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_cursor_show()
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC2: enabling cursor\n"));
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* b0 = 1 enables cursor */
|
||||||
|
CRTC2W(CURCTL0, (CRTC2R(CURCTL0) | 0x01));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t nv_crtc2_cursor_hide()
|
||||||
|
{
|
||||||
|
LOG(4,("CRTC2: disabling cursor\n"));
|
||||||
|
|
||||||
|
/* enable access to secondary head */
|
||||||
|
set_crtc_owner(1);
|
||||||
|
|
||||||
|
/* b0 = 0 disables cursor */
|
||||||
|
CRTC2W(CURCTL0, (CRTC2R(CURCTL0) & 0xfe));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set up cursor shape*/
|
||||||
|
status_t nv_crtc2_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_crtc2_cursor_position(uint16 x, uint16 y)
|
||||||
|
{
|
||||||
|
uint16 yhigh;
|
||||||
|
|
||||||
|
/* make sure we are beyond the first line of the cursorbitmap being drawn during
|
||||||
|
* updating the position to prevent distortions: no double buffering feature */
|
||||||
|
/* Note:
|
||||||
|
* we need to return as quick as possible or some apps will exhibit lagging.. */
|
||||||
|
|
||||||
|
/* read the old cursor Y position */
|
||||||
|
yhigh = ((DAC2R(CURPOS) & 0x0fff0000) >> 16);
|
||||||
|
/* make sure we will wait until we are below both the old and new Y position:
|
||||||
|
* visible cursorbitmap drawing needs to be done at least... */
|
||||||
|
if (y > yhigh) yhigh = y;
|
||||||
|
|
||||||
|
if (yhigh < (si->dm.timing.v_display - 16))
|
||||||
|
{
|
||||||
|
/* we have vertical lines below old and new cursorposition to spare. So we
|
||||||
|
* update the cursor postion 'mid-screen', but below that area. */
|
||||||
|
while (((uint16)(NV_REG32(NV32_RASTER2) & 0x000007ff)) < (yhigh + 16))
|
||||||
|
{
|
||||||
|
snooze(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no room to spare, just wait for retrace (is relatively slow) */
|
||||||
|
while ((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display)
|
||||||
|
{
|
||||||
|
/* don't snooze much longer or retrace might get missed! */
|
||||||
|
snooze(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update cursorposition */
|
||||||
|
DAC2W(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,561 @@
|
|||||||
|
/* program the DAC */
|
||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 12/2003-10/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
/* see if an analog VGA monitor is connected to connector #1 */
|
||||||
|
bool nv_dac_crt_connected(void)
|
||||||
|
{
|
||||||
|
uint32 output, dac;
|
||||||
|
bool present;
|
||||||
|
|
||||||
|
/* save output connector setting */
|
||||||
|
output = DACR(OUTPUT);
|
||||||
|
/* save DAC state */
|
||||||
|
dac = DACR(TSTCTRL);
|
||||||
|
|
||||||
|
/* turn on DAC */
|
||||||
|
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeffff));
|
||||||
|
/* select primary head and turn off CRT (and DVI?) outputs */
|
||||||
|
DACW(OUTPUT, (output & 0x0000feee));
|
||||||
|
/* wait for signal lines to stabilize */
|
||||||
|
snooze(1000);
|
||||||
|
/* re-enable CRT output */
|
||||||
|
DACW(OUTPUT, (DACR(OUTPUT) | 0x00000001));
|
||||||
|
|
||||||
|
/* setup RGB test signal levels to approx 30% of DAC range and enable them */
|
||||||
|
DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0)));
|
||||||
|
/* route test signals to output */
|
||||||
|
DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000));
|
||||||
|
/* wait for signal lines to stabilize */
|
||||||
|
snooze(1000);
|
||||||
|
|
||||||
|
/* do actual detection: all signals paths high == CRT connected */
|
||||||
|
if (DACR(TSTCTRL) & 0x10000000)
|
||||||
|
{
|
||||||
|
present = true;
|
||||||
|
LOG(4,("DAC: CRT detected on connector #1\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
present = false;
|
||||||
|
LOG(4,("DAC: no CRT detected on connector #1\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kill test signal routing */
|
||||||
|
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff));
|
||||||
|
|
||||||
|
/* restore output connector setting */
|
||||||
|
DACW(OUTPUT, output);
|
||||||
|
/* restore DAC state */
|
||||||
|
DACW(TSTCTRL, dac);
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*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;
|
||||||
|
|
||||||
|
/* 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*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* we offer this option because some panels have very tight restrictions,
|
||||||
|
* and there's no overlapping settings range that makes them all work.
|
||||||
|
* note:
|
||||||
|
* this assumes the cards BIOS correctly programmed the panel (is likely) */
|
||||||
|
//fixme: when VESA DDC EDID stuff is implemented, this option can be deleted...
|
||||||
|
if (si->ps.tmds1_active && !si->settings.pgm_panel)
|
||||||
|
{
|
||||||
|
LOG(4,("DAC: Not programming DFP refresh (specified in nv.settings)\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fix a DVI or laptop flatpanel to 60Hz refresh! */
|
||||||
|
/* Note:
|
||||||
|
* The pixelclock drives the flatpanel modeline, not the CRTC modeline. */
|
||||||
|
if (si->ps.tmds1_active)
|
||||||
|
{
|
||||||
|
LOG(4,("DAC: Fixing DFP refresh to 60Hz!\n"));
|
||||||
|
|
||||||
|
/* use the panel's modeline to determine the needed pixelclock */
|
||||||
|
target.timing.pixel_clock = si->ps.p1_timing.pixel_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
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*/
|
||||||
|
|
||||||
|
/* program new frequency */
|
||||||
|
DACW(PIXPLLC, ((p << 16) | (n << 8) | m));
|
||||||
|
|
||||||
|
/* program 2nd set N and M scalers if they exist (b31=1 enables them) */
|
||||||
|
if (si->ps.ext_pll) DACW(PIXPLLC2, 0x80000401);
|
||||||
|
|
||||||
|
/* 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))
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco /= 4;
|
||||||
|
|
||||||
|
/* iterate trough all valid reference-frequency postscaler settings */
|
||||||
|
for (m = 7; m <= 14; m++)
|
||||||
|
{
|
||||||
|
/* check if phase-discriminator will be within operational limits */
|
||||||
|
//fixme: PLL calcs will be resetup/splitup/updated...
|
||||||
|
if (si->ps.card_type == NV36)
|
||||||
|
{
|
||||||
|
if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
if (si->ps.ext_pll)
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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);
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco *= 4;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
status_t nv_dac_sys_pll_find(
|
||||||
|
float req_sclk, float* calc_sclk, uint8* m_result, uint8* n_result, uint8* p_result, uint8 test)
|
||||||
|
{
|
||||||
|
int m = 0, n = 0, p = 0, m_max, p_max;
|
||||||
|
float error, error_best = 999999999;
|
||||||
|
int best[3];
|
||||||
|
float f_vco, discr_low, discr_high;
|
||||||
|
|
||||||
|
/* determine the max. reference-frequency postscaler setting for the
|
||||||
|
* current requested clock */
|
||||||
|
switch (si->ps.card_arch)
|
||||||
|
{
|
||||||
|
case NV04A:
|
||||||
|
LOG(4,("DAC: NV04 restrictions apply\n"));
|
||||||
|
/* set phase-discriminator frequency range (Mhz) (verified) */
|
||||||
|
discr_low = 1.0;
|
||||||
|
discr_high = 2.0;
|
||||||
|
/* set max. useable reference frequency postscaler divider factor */
|
||||||
|
m_max = 14;
|
||||||
|
/* set max. useable VCO output postscaler divider factor */
|
||||||
|
p_max = 16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
switch (si->ps.card_type)
|
||||||
|
{
|
||||||
|
case NV28:
|
||||||
|
//fixme: how about some other cards???
|
||||||
|
LOG(4,("DAC: NV28 restrictions apply\n"));
|
||||||
|
/* set max. useable reference frequency postscaler divider factor;
|
||||||
|
* apparantly we would get distortions on high PLL output frequencies if
|
||||||
|
* we use the phase-discriminator at low frequencies */
|
||||||
|
if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */
|
||||||
|
else if (req_sclk > 200.0) m_max = 4; /* 200Mhz < Fpll <= 340Mhz */
|
||||||
|
else if (req_sclk > 150.0) m_max = 6; /* 150Mhz < Fpll <= 200Mhz */
|
||||||
|
else m_max = 14; /* Fpll < 150Mhz */
|
||||||
|
|
||||||
|
/* set max. useable VCO output postscaler divider factor */
|
||||||
|
p_max = 32;
|
||||||
|
/* set phase-discriminator frequency range (Mhz) (verified) */
|
||||||
|
discr_low = 1.0;
|
||||||
|
discr_high = 27.0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(4,("DAC: NV10/NV20/NV30 restrictions apply\n"));
|
||||||
|
/* set max. useable reference frequency postscaler divider factor;
|
||||||
|
* apparantly we would get distortions on high PLL output frequencies if
|
||||||
|
* we use the phase-discriminator at low frequencies */
|
||||||
|
if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */
|
||||||
|
else if (req_sclk > 250.0) m_max = 6; /* 250Mhz < Fpll <= 340Mhz */
|
||||||
|
else m_max = 14; /* Fpll < 250Mhz */
|
||||||
|
|
||||||
|
/* set max. useable VCO output postscaler divider factor */
|
||||||
|
p_max = 16;
|
||||||
|
/* set phase-discriminator frequency range (Mhz) (verified) */
|
||||||
|
if (si->ps.card_type == NV36) discr_low = 3.2;
|
||||||
|
else discr_low = 1.0;
|
||||||
|
/* (high discriminator spec is failsafe) */
|
||||||
|
discr_high = 14.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(4,("DAC: PLL reference frequency postscaler divider range is 1 - %d\n", m_max));
|
||||||
|
LOG(4,("DAC: PLL VCO output postscaler divider range is 1 - %d\n", p_max));
|
||||||
|
LOG(4,("DAC: PLL discriminator input frequency range is %2.2fMhz - %2.2fMhz\n",
|
||||||
|
discr_low, discr_high));
|
||||||
|
|
||||||
|
/* Make sure the requested clock 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 / ((float)p_max)))
|
||||||
|
{
|
||||||
|
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
|
||||||
|
req_sclk, (si->ps.min_system_vco / ((float)p_max))));
|
||||||
|
req_sclk = (si->ps.min_system_vco / ((float)p_max));
|
||||||
|
}
|
||||||
|
/* upper limit is given by pins */
|
||||||
|
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 <= p_max; 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))
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco /= 4;
|
||||||
|
|
||||||
|
/* iterate trough all valid reference-frequency postscaler settings */
|
||||||
|
for (m = 1; m <= m_max; m++)
|
||||||
|
{
|
||||||
|
/* check if phase-discriminator will be within operational limits */
|
||||||
|
if (((si->ps.f_ref / m) < discr_low) || ((si->ps.f_ref / m) > discr_high))
|
||||||
|
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 */
|
||||||
|
if (si->ps.ext_pll)
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
error = fabs((req_sclk / 4) - (((si->ps.f_ref / m) * n) / p));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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];
|
||||||
|
n = best[1];
|
||||||
|
p = best[2];
|
||||||
|
|
||||||
|
/* log the VCO frequency found */
|
||||||
|
f_vco = ((si->ps.f_ref / m) * n);
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco *= 4;
|
||||||
|
|
||||||
|
LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
|
||||||
|
|
||||||
|
/* return the results */
|
||||||
|
*calc_sclk = (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;
|
||||||
|
case 32:
|
||||||
|
p = 0x05;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
/* program the secondary DAC */
|
||||||
|
/* Author:
|
||||||
|
Rudolf Cornelissen 12/2003-9/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00001000
|
||||||
|
|
||||||
|
#include "nv_std.h"
|
||||||
|
|
||||||
|
static status_t nv10_nv20_dac2_pix_pll_find(
|
||||||
|
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
|
||||||
|
|
||||||
|
/* see if an analog VGA monitor is connected to connector #2 */
|
||||||
|
bool nv_dac2_crt_connected()
|
||||||
|
{
|
||||||
|
uint32 output, dac;
|
||||||
|
bool present;
|
||||||
|
|
||||||
|
/* NOTE:
|
||||||
|
* NV11 can't do this: It will report DAC1 status instead because it HAS no
|
||||||
|
* actual secondary DAC function. */
|
||||||
|
/* (It DOES have a secondary palette RAM and pixelclock PLL though.) */
|
||||||
|
|
||||||
|
/* save output connector setting */
|
||||||
|
output = DAC2R(OUTPUT);
|
||||||
|
/* save DAC state */
|
||||||
|
dac = DAC2R(TSTCTRL);
|
||||||
|
|
||||||
|
/* turn on DAC2 */
|
||||||
|
DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeffff));
|
||||||
|
/* select primary head and turn off CRT (and DVI?) outputs */
|
||||||
|
DAC2W(OUTPUT, (output & 0x0000feee));
|
||||||
|
/* wait for signal lines to stabilize */
|
||||||
|
snooze(1000);
|
||||||
|
/* re-enable CRT output */
|
||||||
|
DAC2W(OUTPUT, (DAC2R(OUTPUT) | 0x00000001));
|
||||||
|
|
||||||
|
/* setup RGB test signal levels to approx 30% of DAC range and enable them
|
||||||
|
* (NOTE: testsignal function block resides in DAC1 only (!)) */
|
||||||
|
DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0)));
|
||||||
|
/* route test signals to output
|
||||||
|
* (NOTE: testsignal function block resides in DAC1 only (!)) */
|
||||||
|
DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000));
|
||||||
|
/* wait for signal lines to stabilize */
|
||||||
|
snooze(1000);
|
||||||
|
|
||||||
|
/* do actual detection: all signals paths high == CRT connected */
|
||||||
|
if (DAC2R(TSTCTRL) & 0x10000000)
|
||||||
|
{
|
||||||
|
present = true;
|
||||||
|
LOG(4,("DAC2: CRT detected on connector #2\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
present = false;
|
||||||
|
LOG(4,("DAC2: no CRT detected on connector #2\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kill test signal routing
|
||||||
|
* (NOTE: testsignal function block resides in DAC1 only (!)) */
|
||||||
|
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff));
|
||||||
|
|
||||||
|
/* restore output connector setting */
|
||||||
|
DAC2W(OUTPUT, output);
|
||||||
|
/* restore DAC state */
|
||||||
|
DAC2W(TSTCTRL, dac);
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
|
||||||
|
status_t nv_dac2_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,("DAC2: 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_dac2_palette(r,g,b) != B_OK) return B_ERROR;
|
||||||
|
|
||||||
|
/* disable palette RAM adressing mask */
|
||||||
|
NV_REG8(NV8_PAL2MASK) = 0xff;
|
||||||
|
LOG(2,("DAC2: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PAL2MASK)));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*program the DAC palette using the given r,g,b values*/
|
||||||
|
status_t nv_dac2_palette(uint8 r[256],uint8 g[256],uint8 b[256])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
LOG(4,("DAC2: setting palette\n"));
|
||||||
|
|
||||||
|
/* select first PAL adress before starting programming */
|
||||||
|
NV_REG8(NV8_PAL2INDW) = 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_PAL2DATA) = r[i];
|
||||||
|
NV_REG8(NV8_PAL2DATA) = g[i];
|
||||||
|
NV_REG8(NV8_PAL2DATA) = b[i];
|
||||||
|
}
|
||||||
|
if (NV_REG8(NV8_PAL2INDW) != 0x00)
|
||||||
|
{
|
||||||
|
LOG(8,("DAC2: 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_PAL2INDR) = 0x00;
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
R = NV_REG8(NV8_PAL2DATA);
|
||||||
|
G = NV_REG8(NV8_PAL2DATA);
|
||||||
|
B = NV_REG8(NV8_PAL2DATA);
|
||||||
|
if ((r[i] != R) || (g[i] != G) || (b[i] != B))
|
||||||
|
LOG(1,("DAC2 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*/
|
||||||
|
status_t nv_dac2_set_pix_pll(display_mode target)
|
||||||
|
{
|
||||||
|
uint8 m=0,n=0,p=0;
|
||||||
|
// uint time = 0;
|
||||||
|
|
||||||
|
float pix_setting, req_pclk;
|
||||||
|
status_t result;
|
||||||
|
|
||||||
|
/* we offer this option because some panels have very tight restrictions,
|
||||||
|
* and there's no overlapping settings range that makes them all work.
|
||||||
|
* note:
|
||||||
|
* this assumes the cards BIOS correctly programmed the panel (is likely) */
|
||||||
|
//fixme: when VESA DDC EDID stuff is implemented, this option can be deleted...
|
||||||
|
if (si->ps.tmds2_active && !si->settings.pgm_panel)
|
||||||
|
{
|
||||||
|
LOG(4,("DAC2: Not programming DFP refresh (specified in nv.settings)\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fix a DVI or laptop flatpanel to 60Hz refresh! */
|
||||||
|
/* Note:
|
||||||
|
* The pixelclock drives the flatpanel modeline, not the CRTC modeline. */
|
||||||
|
if (si->ps.tmds2_active)
|
||||||
|
{
|
||||||
|
LOG(4,("DAC2: Fixing DFP refresh to 60Hz!\n"));
|
||||||
|
|
||||||
|
/* use the panel's modeline to determine the needed pixelclock */
|
||||||
|
target.timing.pixel_clock = si->ps.p2_timing.pixel_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
req_pclk = (target.timing.pixel_clock)/1000.0;
|
||||||
|
LOG(4,("DAC2: Setting PIX PLL for pixelclock %f\n", req_pclk));
|
||||||
|
|
||||||
|
/* signal that we actually want to set the mode */
|
||||||
|
result = nv_dac2_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*/
|
||||||
|
|
||||||
|
/* program new frequency */
|
||||||
|
DAC2W(PIXPLLC, ((p << 16) | (n << 8) | m));
|
||||||
|
|
||||||
|
/* program 2nd set N and M scalers if they exist (b31=1 enables them) */
|
||||||
|
if (si->ps.ext_pll) DAC2W(PIXPLLC2, 0x80000401);
|
||||||
|
|
||||||
|
/* 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,("DAC2: PIX PLL frequency should be locked now...\n"));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find nearest valid pix pll */
|
||||||
|
status_t nv_dac2_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 nv10_nv20_dac2_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 nv10_nv20_dac2_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,("DAC2: NV10/NV20 restrictions apply\n"));
|
||||||
|
|
||||||
|
/* determine the max. pixelclock for the current videomode */
|
||||||
|
switch (target.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:
|
||||||
|
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_pixel_vco divided by highest postscaler-factor */
|
||||||
|
if (req_pclk < (si->ps.min_video_vco / 16.0))
|
||||||
|
{
|
||||||
|
LOG(4,("DAC2: clamping pixclock: requested %fMHz, set to %fMHz\n",
|
||||||
|
req_pclk, (float)(si->ps.min_video_vco / 16.0)));
|
||||||
|
req_pclk = (si->ps.min_video_vco / 16.0);
|
||||||
|
}
|
||||||
|
/* upper limit is given by pins in combination with current active mode */
|
||||||
|
if (req_pclk > max_pclk)
|
||||||
|
{
|
||||||
|
LOG(4,("DAC2: 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_video_vco) && (f_vco <= si->ps.max_video_vco))
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco /= 4;
|
||||||
|
|
||||||
|
/* iterate trough all valid reference-frequency postscaler settings */
|
||||||
|
for (m = 7; m <= 14; m++)
|
||||||
|
{
|
||||||
|
/* check if phase-discriminator will be within operational limits */
|
||||||
|
//fixme: PLL calcs will be resetup/splitup/updated...
|
||||||
|
if (si->ps.card_type == NV36)
|
||||||
|
{
|
||||||
|
if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
if (si->ps.ext_pll)
|
||||||
|
{
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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);
|
||||||
|
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
|
||||||
|
if (si->ps.ext_pll) f_vco *= 4;
|
||||||
|
|
||||||
|
LOG(2,("DAC2: 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,("DAC2: 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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
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 8/2004
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nv_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
|
||||||
|
};
|
||||||
|
|
||||||
|
nv_in_out_isa nv_isa_access=
|
||||||
|
{
|
||||||
|
NV_PRIVATE_DATA_MAGIC,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
};
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
extern int fd;
|
||||||
|
extern shared_info *si;
|
||||||
|
extern area_id shared_info_area;
|
||||||
|
extern area_id regs_area;
|
||||||
|
extern vuint32 *regs;
|
||||||
|
extern display_mode *my_mode_list;
|
||||||
|
extern area_id my_mode_list_area;
|
||||||
|
extern int accelerantIsClone;
|
||||||
|
|
||||||
|
extern nv_get_set_pci nv_pci_access;
|
||||||
|
extern nv_in_out_isa nv_isa_access;
|
||||||
|
|
||||||
|
|
||||||
|
typedef status_t (*crtc_validate_timing)(uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*);
|
||||||
|
typedef status_t (*crtc_set_timing)(display_mode);
|
||||||
|
typedef status_t (*crtc_depth)(int);
|
||||||
|
typedef status_t (*crtc_dpms)(bool, bool, bool);
|
||||||
|
typedef status_t (*crtc_dpms_fetch)(bool*, bool*, bool*);
|
||||||
|
typedef status_t (*crtc_set_display_pitch)(void);
|
||||||
|
typedef status_t (*crtc_set_display_start)(uint32, uint8);
|
||||||
|
typedef status_t (*crtc_cursor_init)(void);
|
||||||
|
typedef status_t (*crtc_cursor_show)(void);
|
||||||
|
typedef status_t (*crtc_cursor_hide)(void);
|
||||||
|
typedef status_t (*crtc_cursor_define)(uint8*, uint8*);
|
||||||
|
typedef status_t (*crtc_cursor_position)(uint16, uint16);
|
||||||
|
|
||||||
|
typedef status_t (*dac_mode)(int, float);
|
||||||
|
typedef status_t (*dac_palette)(uint8[256], uint8[256], uint8[256]);
|
||||||
|
typedef status_t (*dac_set_pix_pll)(display_mode);
|
||||||
|
typedef status_t (*dac_pix_pll_find)(display_mode, float*, uint8*, uint8*, uint8*, uint8);
|
||||||
|
|
||||||
|
crtc_validate_timing head1_validate_timing;
|
||||||
|
crtc_set_timing head1_set_timing;
|
||||||
|
crtc_depth head1_depth;
|
||||||
|
crtc_dpms head1_dpms;
|
||||||
|
crtc_dpms_fetch head1_dpms_fetch;
|
||||||
|
crtc_set_display_pitch head1_set_display_pitch;
|
||||||
|
crtc_set_display_start head1_set_display_start;
|
||||||
|
crtc_cursor_init head1_cursor_init;
|
||||||
|
crtc_cursor_show head1_cursor_show;
|
||||||
|
crtc_cursor_hide head1_cursor_hide;
|
||||||
|
crtc_cursor_define head1_cursor_define;
|
||||||
|
crtc_cursor_position head1_cursor_position;
|
||||||
|
|
||||||
|
crtc_validate_timing head2_validate_timing;
|
||||||
|
crtc_set_timing head2_set_timing;
|
||||||
|
crtc_depth head2_depth;
|
||||||
|
crtc_dpms head2_dpms;
|
||||||
|
crtc_dpms_fetch head2_dpms_fetch;
|
||||||
|
crtc_set_display_pitch head2_set_display_pitch;
|
||||||
|
crtc_set_display_start head2_set_display_start;
|
||||||
|
crtc_cursor_init head2_cursor_init;
|
||||||
|
crtc_cursor_show head2_cursor_show;
|
||||||
|
crtc_cursor_hide head2_cursor_hide;
|
||||||
|
crtc_cursor_define head2_cursor_define;
|
||||||
|
crtc_cursor_position head2_cursor_position;
|
||||||
|
|
||||||
|
dac_mode head1_mode;
|
||||||
|
dac_palette head1_palette;
|
||||||
|
dac_set_pix_pll head1_set_pix_pll;
|
||||||
|
dac_pix_pll_find head1_pix_pll_find;
|
||||||
|
|
||||||
|
dac_mode head2_mode;
|
||||||
|
dac_palette head2_palette;
|
||||||
|
dac_set_pix_pll head2_set_pix_pll;
|
||||||
|
dac_pix_pll_find head2_pix_pll_find;
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* 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-12/2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODULE_BIT 0x00004000
|
||||||
|
|
||||||
|
#include "nv_std.h"
|
||||||
|
|
||||||
|
int i2c_set_lines(int clock, int data);
|
||||||
|
int i2c_get_data(void);
|
||||||
|
void i2c_start(void);
|
||||||
|
void i2c_stop(void);
|
||||||
|
void i2c_high(void);
|
||||||
|
void i2c_low(void);
|
||||||
|
int i2c_get_ack(void);
|
||||||
|
void i2c_send_ack(void);
|
||||||
|
int i2c_sendbyte(unsigned char data);
|
||||||
|
unsigned char i2c_readbyte(int ack_required);
|
||||||
|
|
||||||
|
/*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;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
|||||||
|
/* general card functions */
|
||||||
|
status_t nv_general_powerup(void);
|
||||||
|
status_t nv_set_cas_latency(void);
|
||||||
|
void setup_virtualized_heads(bool);
|
||||||
|
void set_crtc_owner(bool);
|
||||||
|
status_t nv_general_output_select(bool);
|
||||||
|
status_t nv_general_head_select(bool);
|
||||||
|
status_t nv_general_wait_retrace(void);
|
||||||
|
status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode);
|
||||||
|
|
||||||
|
/* AGP functions */
|
||||||
|
status_t nv_agp_setup(void);
|
||||||
|
|
||||||
|
/* apsed: logging macros */
|
||||||
|
#define MSG(args) do { /* if needed or si->settings with si NULL */ \
|
||||||
|
nv_log args; \
|
||||||
|
} while (0)
|
||||||
|
#define LOG(level_bit, args) do { \
|
||||||
|
uint32 mod = (si->settings.logmask & 0xfffffff0) & MODULE_BIT; \
|
||||||
|
uint32 lev = (si->settings.logmask & ~0xfffffff0) & level_bit; \
|
||||||
|
if (mod && lev) nv_log args; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* support functions */
|
||||||
|
void delay(bigtime_t i);
|
||||||
|
void nv_log(char *format, ...);
|
||||||
|
|
||||||
|
/* i2c functions */
|
||||||
|
int i2c_maven_read(unsigned char address);
|
||||||
|
void i2c_maven_write(unsigned char address, unsigned char data);
|
||||||
|
status_t i2c_init(void);
|
||||||
|
status_t i2c_maven_probe(void);
|
||||||
|
|
||||||
|
/* card info functions */
|
||||||
|
status_t parse_pins(void);
|
||||||
|
void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2);
|
||||||
|
void fake_panel_start(void);
|
||||||
|
void set_specs(void);
|
||||||
|
void dump_pins(void);
|
||||||
|
|
||||||
|
/* DAC functions */
|
||||||
|
bool nv_dac_crt_connected(void);
|
||||||
|
status_t nv_dac_mode(int,float);
|
||||||
|
status_t nv_dac_palette(uint8*,uint8*,uint8*);
|
||||||
|
status_t nv_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8);
|
||||||
|
status_t nv_dac_set_pix_pll(display_mode target);
|
||||||
|
status_t nv_dac_sys_pll_find(float, float*, uint8*, uint8*, uint8*, uint8);
|
||||||
|
|
||||||
|
/* DAC2 functions */
|
||||||
|
bool nv_dac2_crt_connected(void);
|
||||||
|
status_t nv_dac2_mode(int,float);
|
||||||
|
status_t nv_dac2_palette(uint8*,uint8*,uint8*);
|
||||||
|
status_t nv_dac2_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8);
|
||||||
|
status_t nv_dac2_set_pix_pll(display_mode target);
|
||||||
|
|
||||||
|
/*MAVENTV functions*/
|
||||||
|
status_t g100_g400max_maventv_vid_pll_find(
|
||||||
|
display_mode target, unsigned int * ht_new, unsigned int * ht_last_line,
|
||||||
|
uint8 * m_result, uint8 * n_result, uint8 * p_result);
|
||||||
|
int maventv_init(display_mode target);
|
||||||
|
|
||||||
|
/* CRTC1 functions */
|
||||||
|
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
|
||||||
|
);
|
||||||
|
status_t nv_crtc_set_timing(display_mode target);
|
||||||
|
status_t nv_crtc_depth(int mode);
|
||||||
|
status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp);
|
||||||
|
status_t nv_crtc_set_display_pitch(void);
|
||||||
|
|
||||||
|
status_t nv_crtc_dpms(bool, bool, bool);
|
||||||
|
status_t nv_crtc_dpms_fetch(bool*, bool*, bool*);
|
||||||
|
status_t nv_crtc_mem_priority(uint8);
|
||||||
|
|
||||||
|
status_t nv_crtc_cursor_init(void); /*Yes, cursor follows CRTC1 - not the DAC!*/
|
||||||
|
status_t nv_crtc_cursor_define(uint8*,uint8*);
|
||||||
|
status_t nv_crtc_cursor_position(uint16 x ,uint16 y);
|
||||||
|
status_t nv_crtc_cursor_show(void);
|
||||||
|
status_t nv_crtc_cursor_hide(void);
|
||||||
|
|
||||||
|
/* CRTC2 functions */
|
||||||
|
status_t nv_crtc2_validate_timing(
|
||||||
|
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
|
||||||
|
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
|
||||||
|
);
|
||||||
|
status_t nv_crtc2_set_timing(display_mode target);
|
||||||
|
status_t nv_crtc2_depth(int mode);
|
||||||
|
status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp);
|
||||||
|
status_t nv_crtc2_set_display_pitch(void);
|
||||||
|
|
||||||
|
status_t nv_crtc2_dpms(bool, bool, bool);
|
||||||
|
status_t nv_crtc2_dpms_fetch(bool*, bool*, bool*);
|
||||||
|
status_t nv_crtc2_mem_priority(uint8);
|
||||||
|
|
||||||
|
status_t nv_crtc2_cursor_init(void);
|
||||||
|
status_t nv_crtc2_cursor_define(uint8*,uint8*);
|
||||||
|
status_t nv_crtc2_cursor_position(uint16 x ,uint16 y);
|
||||||
|
status_t nv_crtc2_cursor_show(void);
|
||||||
|
status_t nv_crtc2_cursor_hide(void);
|
||||||
|
|
||||||
|
/* acceleration functions */
|
||||||
|
status_t check_acc_capability(uint32 feature);
|
||||||
|
status_t nv_acc_init(void);
|
||||||
|
status_t nv_acc_setup_blit(void);
|
||||||
|
status_t nv_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 );
|
||||||
|
status_t nv_acc_setup_rectangle(uint32 color);
|
||||||
|
status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl);
|
||||||
|
status_t nv_acc_setup_rect_invert(void);
|
||||||
|
status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl);
|
||||||
|
status_t nv_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32);
|
||||||
|
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
|
||||||
|
uint16 xd,uint16 yd,uint16 wd,uint16 hd);
|
||||||
|
status_t nv_acc_wait_idle(void);
|
||||||
|
|
||||||
|
/* backend scaler functions */
|
||||||
|
status_t check_overlay_capability(uint32 feature);
|
||||||
|
void nv_bes_move_overlay(void);
|
||||||
|
status_t nv_bes_to_crtc(bool crtc);
|
||||||
|
status_t nv_bes_init(void);
|
||||||
|
status_t nv_configure_bes
|
||||||
|
(const overlay_buffer *ob, const overlay_window *ow,const overlay_view *ov, int offset);
|
||||||
|
status_t nv_release_bes(void);
|
||||||
|
|
||||||
|
/* I2C functions */
|
||||||
|
status_t i2c_sec_tv_adapter(void);
|
||||||
|
|
||||||
|
/* driver structures and enums */
|
||||||
|
enum{BPP8 = 0, BPP15 = 1, BPP16 = 2, BPP24 = 3, BPP32 = 4};
|
||||||
|
enum{DS_CRTC1DAC_CRTC2MAVEN, DS_CRTC1MAVEN_CRTC2DAC, DS_CRTC1CON1_CRTC2CON2, DS_CRTC1CON2_CRTC2CON1};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <OS.h>
|
||||||
|
#include "DriverInterface.h"
|
||||||
|
#include "nv_globals.h"
|
||||||
|
//apsed #include "nv_extern.h"
|
||||||
|
#include "nv_proto.h"
|
||||||
|
#include "nv_macros.h"
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/* Some commmon support functions */
|
||||||
|
/* Mark Watson 2/2000;
|
||||||
|
* Rudolf Cornelissen 1/2004 */
|
||||||
|
|
||||||
|
#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];
|
||||||
|
char fname[64];
|
||||||
|
FILE *myhand;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.%d.log", accelerantIsClone);
|
||||||
|
myhand=fopen(fname,"a+");
|
||||||
|
|
||||||
|
if (myhand == NULL) return;
|
||||||
|
|
||||||
|
va_start(args,fmt);
|
||||||
|
vsprintf (buffer, fmt, args);
|
||||||
|
fprintf(myhand, "%s", buffer);
|
||||||
|
fclose(myhand);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
|||||||
|
/*This file can be used to define custom timing for your monitor
|
||||||
|
* The format of each line is:
|
||||||
|
* {
|
||||||
|
* pixel clock frequency (kHz)
|
||||||
|
* width
|
||||||
|
* h-sync pulse start
|
||||||
|
* h-sync pulse end
|
||||||
|
* total pixels in line
|
||||||
|
* height
|
||||||
|
* v-sync pulse start
|
||||||
|
* v-sync pulse end
|
||||||
|
* total lines in frame
|
||||||
|
* sync polarity (0 is -ve,B_POSITIVE_HYSNC,B_POSITIVE_VSYNC)
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*To use this you must:
|
||||||
|
* Uncomment VALID MODE REQUIRED
|
||||||
|
* Fill in a number of modes that work with your display
|
||||||
|
* Change VALID MODES from three to the no. you defined
|
||||||
|
* run these commands:
|
||||||
|
* touch ProposeDisplayMode.c
|
||||||
|
* make install
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define VALID_MODE_REQUIRED 1
|
||||||
|
|
||||||
|
#define VALID_MODES 3
|
||||||
|
|
||||||
|
/*note colour depth and mode flags are ignored*/
|
||||||
|
static const display_timing valid_mode_list[] = {
|
||||||
|
{31500,640,648,744,840,480,481,500,500,0},
|
||||||
|
{49500,800,808,888,1056,600,601,620,625,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC},
|
||||||
|
{78750,1024,1032,1128,1312,768,769,788,800,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user