copied nvidia driver over to nvidia_gpgpu driver. Does nothing but compile. I hope to be fidding around with a EN8500GT soon. If for some reason I shouldn't be creating these folders, feel free to remove it again, and let me know :)
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25873 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,6 +5,7 @@ SubInclude HAIKU_TOP src add-ons accelerants et6x00 ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants intel_extreme ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants matrox ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants neomagic ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants nvidia_gpgpu ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants nvidia ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants radeon ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants s3 ;
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
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-2/2005.
|
||||
*/
|
||||
|
||||
/*
|
||||
note:
|
||||
moved DMA acceleration 'top-level' routines to be integrated in the engine:
|
||||
it is costly to call the engine for every single function within a loop!
|
||||
(measured with BeRoMeter 1.2.6: upto 15% speed increase on all CPU's.)
|
||||
Leaving PIO acceleration as it is for now, for the purpose of benchmarking :-)
|
||||
|
||||
note also:
|
||||
attempting DMA on NV40 and higher because without it I can't get them going ATM.
|
||||
Maybe later we can forget about PIO mode acceleration totally (depends on 3D
|
||||
acceleration attempts).
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x40000000
|
||||
|
||||
#include "acc_std.h"
|
||||
|
||||
void SCREEN_TO_SCREEN_BLIT_PIO(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_PIO(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_PIO(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_PIO(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_PIO(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_PIO(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,98 @@
|
||||
/*
|
||||
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-2/2005
|
||||
*/
|
||||
|
||||
/*
|
||||
note:
|
||||
attempting DMA on NV40 and higher because without it I can't get it going ATM.
|
||||
Later on this can become a nv.settings switch, and maybe later we can even
|
||||
forget about non-DMA completely (depends on 3D acceleration attempts).
|
||||
*/
|
||||
|
||||
#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_PIO(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);
|
||||
|
||||
/* make sure all needed engine cmd's are mapped to the FIFO */
|
||||
nv_acc_assert_fifo();
|
||||
|
||||
/* return an engine token */
|
||||
*et = &nv_engine_token;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t ACQUIRE_ENGINE_DMA(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);
|
||||
|
||||
/* make sure all needed engine cmd's are mapped to the FIFO */
|
||||
nv_acc_assert_fifo_dma();
|
||||
|
||||
/* 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*/
|
||||
if (!si->settings.dma_acc)
|
||||
nv_acc_wait_idle();
|
||||
else
|
||||
nv_acc_wait_idle_dma();
|
||||
}
|
||||
|
||||
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,241 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Mark Watson,
|
||||
Rudolf Cornelissen 10/2002-6/2008
|
||||
*/
|
||||
|
||||
#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) \
|
||||
{if(!si->settings.dma_acc) return (void *)x##_PIO; else return (void *)x##_DMA;} \
|
||||
else return (void *)0
|
||||
#define CHKS(x) case B_##x: \
|
||||
if(!si->settings.dma_acc) return (void *)x##_PIO; else return (void *)x##_DMA
|
||||
#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);
|
||||
CHKS(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 CHKD
|
||||
#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 older cards have a supported bes */
|
||||
if ((si->ps.card_type <= NV40) || (si->ps.card_type == NV45))
|
||||
{
|
||||
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* all newer NV40 architecture cards have a new HDTV capable bes except for
|
||||
* GeForce 6800's. Unfortunately we have no info about the new bes yet. */
|
||||
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
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";
|
||||
/* this function is only defined for DMA acceleration,
|
||||
* but doesn't support the B_CMAP8 colorspace */
|
||||
//fixme: checkout B_CMAP8 support sometime, as some cards seem to support it?
|
||||
if (!si->settings.dma_acc || (si->dm.space == B_CMAP8))
|
||||
{
|
||||
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
|
||||
return B_ERROR;
|
||||
}
|
||||
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,25 @@
|
||||
/*
|
||||
Author:
|
||||
Rudolf Cornelissen 7/2004-01/2006
|
||||
*/
|
||||
|
||||
#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, si->adi.name);
|
||||
sprintf(adi->chipset, si->adi.chipset);
|
||||
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,163 @@
|
||||
/*
|
||||
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-10/2005
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
if (si->ps.int_assigned)
|
||||
return si->vblank;
|
||||
else
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -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,369 @@
|
||||
/*
|
||||
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/2006.
|
||||
*/
|
||||
|
||||
#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\n",
|
||||
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead));
|
||||
LOG(4,("init_common: dumprom %d, pgm_panel %d, dma_acc %d, tv_output %d, vga_on_tv %d\n",
|
||||
si->settings.dumprom, si->settings.pgm_panel, si->settings.dma_acc, si->settings.tv_output, si->settings.vga_on_tv));
|
||||
LOG(4,("init_common: force_sync %d, gpu_clk %dMhz, ram_clk %dMhz, force_ws %d\n",
|
||||
si->settings.force_sync, si->settings.gpu_clk, si->settings.ram_clk, si->settings.force_ws));
|
||||
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
/* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */
|
||||
if (si->accelerant_in_use)
|
||||
{
|
||||
result = B_NOT_ALLOWED;
|
||||
goto error1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* no 3D clones are currently loaded */
|
||||
si->engine.threeD.clones = 0;
|
||||
/* tell 3D add-ons that they should reload their rendering states and surfaces */
|
||||
si->engine.threeD.reload = 0xffffffff;
|
||||
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();
|
||||
|
||||
/* ensure DPMS state */
|
||||
si->dpms_flags = B_DPMS_ON;
|
||||
|
||||
/* ensure TVout state:
|
||||
* TVencoder is on head to be assigned primary, no dualhead switch mode active. */
|
||||
//fixme: actually check on what CRTC TVout was active during boot (if any)...
|
||||
si->dm.flags = TV_PRIMARY;
|
||||
|
||||
/* make sure a possible 3D add-on will block rendering and re-initialize itself.
|
||||
* note: update in _this_ order only */
|
||||
/* SET_DISPLAY_MODE will reset this flag when it's done. */
|
||||
si->engine.threeD.mode_changing = true;
|
||||
/* every 3D add-on will reset this bit-flag when it's done. */
|
||||
si->engine.threeD.newmode = 0xffffffff;
|
||||
|
||||
/* a winner! */
|
||||
result = B_OK;
|
||||
/* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */
|
||||
si->accelerant_in_use = true;
|
||||
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);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/* ensure that INIT_ACCELERANT is executed first (i.e. primary accelerant exists) */
|
||||
if (!(si->accelerant_in_use))
|
||||
{
|
||||
result = B_NOT_ALLOWED;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
/* setup CRTC and DAC functions access */
|
||||
//fixme: setup_virtualized_heads is a problem for clones: needs to be run
|
||||
//for each clone if the mode is changed!
|
||||
if (si->ps.secondary_head)
|
||||
setup_virtualized_heads(si->crtc_switch_mode);
|
||||
else
|
||||
setup_virtualized_heads(si->ps.crtc2_prim);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* ensure that INIT_ACCELERANT can be executed again */
|
||||
si->accelerant_in_use = false;
|
||||
}
|
||||
|
||||
/* 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,30 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants nvidia_gpgpu ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics nvidia_gpgpu ] ;
|
||||
UseHeaders [ FDirName $(SUBDIR) engine ] ;
|
||||
|
||||
Addon nvidia_gpgpu.accelerant :
|
||||
Acceleration.c
|
||||
Cursor.c
|
||||
EngineManagment.c
|
||||
GetAccelerantHook.c
|
||||
GetDeviceInfo.c
|
||||
GetModeInfo.c
|
||||
GetTimingConstraints.c
|
||||
InitAccelerant.c
|
||||
Overlay.c
|
||||
ProposeDisplayMode.c
|
||||
SetDisplayMode.c
|
||||
: libnvidia_gpgpu_engine.a
|
||||
;
|
||||
|
||||
Package haiku-nvidia_gpgpu-cvs :
|
||||
nvidia_gpgpu.accelerant :
|
||||
boot home config add-ons accelerants ;
|
||||
|
||||
Depends nvidia_gpgpu.accelerant : nvidia_gpgpu ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons accelerants nvidia_gpgpu engine ;
|
||||
@@ -0,0 +1,626 @@
|
||||
/* Written by Rudolf Cornelissen 05/2002-4/2006 */
|
||||
|
||||
/* 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);
|
||||
/* Keep some extra distance as a workaround for certain bugs (see
|
||||
* DriverInterface.h for an explanation). */
|
||||
if (si->ps.card_arch < NV40A)
|
||||
adress -= PRE_NV40_OFFSET;
|
||||
else
|
||||
adress -= NV40_PLUS_OFFSET;
|
||||
|
||||
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);
|
||||
/* Keep some extra distance as a workaround for certain bugs (see
|
||||
* DriverInterface.h for an explanation). */
|
||||
if (si->ps.card_arch < NV40A)
|
||||
adress -= PRE_NV40_OFFSET;
|
||||
else
|
||||
adress -= NV40_PLUS_OFFSET;
|
||||
|
||||
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,571 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors for NV driver:
|
||||
Mark Watson,
|
||||
Rudolf Cornelissen 9/2002-4/2006
|
||||
*/
|
||||
|
||||
#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 */
|
||||
{ { 160000, 1920, 2010, 2060, 2110, 1200, 1202, 1208, 1235, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
|
||||
/* 16:9 panel mode; 1280x720 */
|
||||
{ { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X720) */
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
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, mem_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;
|
||||
bool 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];
|
||||
/* I require this refresh */
|
||||
target_refresh = ((double)target->timing.pixel_clock * 1000.0)
|
||||
/ ((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;
|
||||
}
|
||||
|
||||
/* disable aspect checks for a requested TVout mode when mode is TVout capable */
|
||||
if (!si->ps.tvout
|
||||
|| !(BT_check_tvmode(*target) && (target->flags & TV_BITS))) {
|
||||
/* 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:
|
||||
#if 0
|
||||
/* at least one analog monitor is connected, or nothing detected at all */
|
||||
/* (if forcing widescreen type was requested don't block mode) */
|
||||
if (target_aspect > 1.34 && !si->settings.force_ws) {
|
||||
LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
// Wide screen modes are pretty common these days... - better use EDID!
|
||||
#if 0
|
||||
/* 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 && !si->settings.force_ws) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
|
||||
}
|
||||
|
||||
mem_reservation = 0;
|
||||
/* checkout space needed for hardcursor (if any) */
|
||||
if (si->settings.hardcursor)
|
||||
mem_reservation = 2048;
|
||||
|
||||
/* Reserve extra space as a workaround for certain bugs (see DriverInterface.h
|
||||
* for an explanation). */
|
||||
if (si->ps.card_arch < NV40A)
|
||||
mem_reservation += PRE_NV40_OFFSET;
|
||||
else
|
||||
mem_reservation += NV40_PLUS_OFFSET;
|
||||
|
||||
/* memory requirement for frame buffer */
|
||||
if (row_bytes * target->virtual_height > si->ps.memory_size - mem_reservation) {
|
||||
target->virtual_height = (si->ps.memory_size - mem_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 - mem_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 - mem_reservation
|
||||
>= row_bytes * target->virtual_height)
|
||||
target->flags |= DUALHEAD_CAPABLE;
|
||||
break;
|
||||
case DUALHEAD_OFF:
|
||||
if (si->ps.memory_size - mem_reservation
|
||||
>= row_bytes * target->virtual_height * 2)
|
||||
target->flags |= DUALHEAD_CAPABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if not dualhead capable card clear dualhead flags */
|
||||
if (!(target->flags & DUALHEAD_CAPABLE))
|
||||
target->flags &= ~DUALHEAD_BITS;
|
||||
|
||||
/* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
|
||||
if (si->ps.tvout && BT_check_tvmode(*target))
|
||||
target->flags |= TV_CAPABLE;
|
||||
|
||||
/* if not TVout capable card clear TVout flags */
|
||||
if (!(target->flags & TV_CAPABLE))
|
||||
target->flags &= ~TV_BITS;
|
||||
|
||||
/* make sure TV head assignment is sane */
|
||||
if (target->flags & TV_BITS) {
|
||||
if (!si->ps.secondary_head)
|
||||
target->flags |= TV_PRIMARY;
|
||||
else if ((target->flags & DUALHEAD_BITS) == DUALHEAD_OFF)
|
||||
target->flags |= TV_PRIMARY;
|
||||
} else
|
||||
target->flags &= ~TV_PRIMARY;
|
||||
|
||||
/* set HARDWARE_CURSOR mode if suitable */
|
||||
if (si->settings.hardcursor)
|
||||
target->flags |= B_HARDWARE_CURSOR;
|
||||
|
||||
/* set SUPPORTS_OVERLAYS if suitable */
|
||||
if (si->ps.card_type <= NV40 || si->ps.card_type == NV45)
|
||||
target->flags |= B_SUPPORTS_OVERLAYS;
|
||||
|
||||
LOG(1, ("PROPOSEMODE: validated 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,611 @@
|
||||
|
||||
/*
|
||||
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-10/2007
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00200000
|
||||
|
||||
#include "acc_std.h"
|
||||
|
||||
/* 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;
|
||||
uint32 startadd,startadd_right;
|
||||
// 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;
|
||||
|
||||
/* make sure a possible 3D add-on will block rendering and re-initialize itself.
|
||||
* note: update in _this_ order only */
|
||||
/* SET_DISPLAY_MODE will reset this flag when it's done. */
|
||||
si->engine.threeD.mode_changing = true;
|
||||
/* every 3D add-on will reset this bit-flag when it's done. */
|
||||
si->engine.threeD.newmode = 0xffffffff;
|
||||
/* every 3D clone needs to reclaim a slot.
|
||||
* note: this also cleans up reserved channels for killed 3D clones.. */
|
||||
si->engine.threeD.clones = 0x00000000;
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
// head1_interrupt_enable(false);
|
||||
// if (si->ps.secondary_head) head2_interrupt_enable(false);
|
||||
|
||||
/* disable TVout if supported */
|
||||
// if (si->ps.tvout) BT_stop_tvout();
|
||||
|
||||
/* turn off screen(s) _after_ TVout is disabled (if applicable) */
|
||||
// head1_dpms(false, false, false, true);
|
||||
// if (si->ps.secondary_head) head2_dpms(false, false, false, true);
|
||||
// if (si->ps.tvout) BT_dpms(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 */
|
||||
//fixme: remove or block on autodetect fail. (is now shutoff)
|
||||
if ((0) && (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"));
|
||||
|
||||
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 */
|
||||
//fixme: we don't support interlaced mode?
|
||||
si->interlaced_tv_mode = false;
|
||||
|
||||
/*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);
|
||||
// head2_set_timing(target2);
|
||||
|
||||
/* TVout support: program TVout encoder and modify CRTC timing */
|
||||
// if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2);
|
||||
}
|
||||
else /* single head mode */
|
||||
{
|
||||
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 */
|
||||
// if (head1_set_pix_pll(target) == 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);
|
||||
|
||||
/* TVout support: program TVout encoder and modify CRTC timing */
|
||||
// if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target);
|
||||
|
||||
//fixme: shut-off the videoPLL if it exists...
|
||||
}
|
||||
|
||||
/* update driver's mode store */
|
||||
si->dm = target;
|
||||
|
||||
/* update FIFO data fetching according to mode */
|
||||
// nv_crtc_update_fifo();
|
||||
// if (si->ps.secondary_head) nv_crtc2_update_fifo();
|
||||
|
||||
/* set up acceleration for this mode */
|
||||
/* note:
|
||||
* Maybe later we can forget about non-DMA mode (depends on 3D acceleration
|
||||
* attempts). */
|
||||
//no acc support for G8x yet!
|
||||
if (si->ps.card_arch < NV50A)
|
||||
{
|
||||
if (!si->settings.dma_acc)
|
||||
nv_acc_init();
|
||||
else
|
||||
nv_acc_init_dma();
|
||||
}
|
||||
/* set up overlay unit for this mode */
|
||||
// nv_bes_init();
|
||||
|
||||
/* note freemem range */
|
||||
/* first free adress follows hardcursor and workspace */
|
||||
si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
|
||||
if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
|
||||
/* last free adress is end-of-ram minus max space needed for overlay bitmaps */
|
||||
//fixme possible:
|
||||
//if overlay buffers are allocated subtract buffersize from mem_high;
|
||||
//only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
|
||||
si->engine.threeD.mem_high = si->ps.memory_size - 1;
|
||||
/* Keep some extra distance as a workaround for certain bugs (see
|
||||
* DriverInterface.h for an explanation). */
|
||||
if (si->ps.card_arch < NV40A)
|
||||
si->engine.threeD.mem_high -= PRE_NV40_OFFSET;
|
||||
else
|
||||
si->engine.threeD.mem_high -= NV40_PLUS_OFFSET;
|
||||
|
||||
si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2); /* see overlay.c file */
|
||||
|
||||
/* restore screen(s) output state(s) */
|
||||
// SET_DPMS_MODE(si->dpms_flags);
|
||||
|
||||
/* enable interrupts using the kernel driver */
|
||||
//fixme:
|
||||
//add head2 once we use one driver instance 'per head' (instead of 'per card')
|
||||
// head1_interrupt_enable(true);
|
||||
|
||||
/* make sure a possible 3D add-on will re-initialize itself by signalling ready */
|
||||
si->engine.threeD.mode_changing = false;
|
||||
|
||||
/* optimize memory-access if needed */
|
||||
// head1_mem_priority(colour_depth1);
|
||||
|
||||
/* Tune RAM CAS-latency if needed. Must be done *here*! */
|
||||
// nv_set_cas_latency();
|
||||
|
||||
LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
|
||||
|
||||
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);
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
head1_interrupt_enable(false);
|
||||
if (si->ps.secondary_head) head2_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;
|
||||
}
|
||||
|
||||
//fixme:
|
||||
//add head2 once we use one driver instance 'per head' (instead of 'per card')
|
||||
head1_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)
|
||||
{
|
||||
bool display, h1h, h1v, h2h, h2v, do_p1, do_p2;
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
head1_interrupt_enable(false);
|
||||
if (si->ps.secondary_head) head2_interrupt_enable(false);
|
||||
|
||||
LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags));
|
||||
|
||||
/* note current DPMS state for our reference */
|
||||
si->dpms_flags = dpms_flags;
|
||||
|
||||
/* preset: DPMS for panels should be executed */
|
||||
do_p1 = do_p2 = true;
|
||||
|
||||
/* determine signals to send to head(s) */
|
||||
display = h1h = h1v = h2h = h2v = true;
|
||||
switch(dpms_flags)
|
||||
{
|
||||
case B_DPMS_ON: /* H: on, V: on, display on */
|
||||
break;
|
||||
case B_DPMS_STAND_BY:
|
||||
display = h1h = h2h = false;
|
||||
break;
|
||||
case B_DPMS_SUSPEND:
|
||||
display = h1v = h2v = false;
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
display = h1h = h1v = h2h = h2v = false;
|
||||
break;
|
||||
default:
|
||||
LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags));
|
||||
//fixme:
|
||||
//add head2 once we use one driver instance 'per head' (instead of 'per card')
|
||||
head1_interrupt_enable(true);
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* CRTC used for TVout needs specific DPMS programming */
|
||||
if (si->dm.flags & TV_BITS)
|
||||
{
|
||||
/* TV_PRIMARY tells us that the head to be used with TVout is the head that's
|
||||
* actually assigned as being the primary head at powerup:
|
||||
* so non dualhead-mode-dependant, and not 'fixed' CRTC1! */
|
||||
if (si->dm.flags & TV_PRIMARY)
|
||||
{
|
||||
LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n"));
|
||||
|
||||
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
|
||||
{
|
||||
if (!(si->settings.vga_on_tv))
|
||||
{
|
||||
/* block VGA output on head displaying on TV */
|
||||
/* Note:
|
||||
* this specific sync setting is required: Vsync is used to keep TVout
|
||||
* synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
|
||||
* This leaves Hsync only for shutting off the VGA screen. */
|
||||
h1h = false;
|
||||
h1v = true;
|
||||
/* block panel DPMS updates */
|
||||
do_p1 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* when concurrent VGA is used alongside TVout on a head, DPMS is safest
|
||||
* applied this way: Vsync is needed for stopping TVout successfully when
|
||||
* a (new) modeswitch occurs.
|
||||
* (see routine BT_stop_tvout() in nv_brooktreetv.c) */
|
||||
/* Note:
|
||||
* applying 'normal' DPMS here and forcing Vsync on in the above mentioned
|
||||
* routine seems to not always be enough: sometimes image generation will
|
||||
* not resume in that case. */
|
||||
h1h = display;
|
||||
h1v = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(si->settings.vga_on_tv))
|
||||
{
|
||||
h2h = false;
|
||||
h2v = true;
|
||||
do_p2 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
h2h = display;
|
||||
h2v = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n"));
|
||||
|
||||
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
|
||||
{
|
||||
if (!(si->settings.vga_on_tv))
|
||||
{
|
||||
h2h = false;
|
||||
h2v = true;
|
||||
do_p2 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
h2h = display;
|
||||
h2v = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(si->settings.vga_on_tv))
|
||||
{
|
||||
h1h = false;
|
||||
h1v = true;
|
||||
do_p1 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
h1h = display;
|
||||
h1v = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* issue actual DPMS commands as far as applicable */
|
||||
head1_dpms(display, h1h, h1v, do_p1);
|
||||
if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS))
|
||||
head2_dpms(display, h2h, h2v, do_p2);
|
||||
if (si->dm.flags & TV_BITS)
|
||||
BT_dpms(display);
|
||||
|
||||
//fixme:
|
||||
//add head2 once we use one driver instance 'per head' (instead of 'per card')
|
||||
head1_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)
|
||||
{
|
||||
return si->dpms_flags;
|
||||
}
|
||||
@@ -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,72 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Modified by Rudolf Cornelissen 2/2005.
|
||||
*/
|
||||
|
||||
#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_PIO(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
|
||||
status_t ACQUIRE_ENGINE_DMA(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);
|
||||
|
||||
/* PIO acceleration */
|
||||
void SCREEN_TO_SCREEN_BLIT_PIO(engine_token *et, blit_params *list, uint32 count);
|
||||
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT_PIO(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count);
|
||||
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT_PIO(engine_token *et, scaled_blit_params *list, uint32 count);
|
||||
void FILL_RECTANGLE_PIO(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||
void INVERT_RECTANGLE_PIO(engine_token *et, fill_rect_params *list, uint32 count);
|
||||
void FILL_SPAN_PIO(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,22 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants nvidia_gpgpu engine ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics nvidia_gpgpu ] ;
|
||||
|
||||
StaticLibrary libnvidia_gpgpu_engine.a :
|
||||
nv_acc.c
|
||||
nv_acc_dma.c
|
||||
nv_bes.c
|
||||
nv_brooktreetv.c
|
||||
nv_crtc.c
|
||||
nv_crtc2.c
|
||||
nv_dac.c
|
||||
nv_dac2.c
|
||||
nv_general.c
|
||||
nv_globals.c
|
||||
nv_i2c.c
|
||||
nv_info.c
|
||||
nv_support.c
|
||||
;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,222 @@
|
||||
/* Author:
|
||||
Rudolf Cornelissen 6/2004-4/2006
|
||||
*/
|
||||
|
||||
#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(bool enable_agp)
|
||||
{
|
||||
nv_nth_agp_info nai;
|
||||
nv_cmd_agp nca;
|
||||
uint8 index;
|
||||
agp_info nv_ai;
|
||||
bool agp = false;
|
||||
|
||||
/* preset we are running in PCI mode: so acc engine may not use AGP transfers */
|
||||
si->engine.agp_mode = 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 || !enable_agp) {
|
||||
/* set PCI mode if specified by user in nv.settings */
|
||||
if (enable_agp)
|
||||
LOG(4,("AGP: forcing PCI mode (specified in nv.settings)\n"));
|
||||
else
|
||||
LOG(4,("AGP: forcing PCI mode during coldstart (required)\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.status & AGP_3_MODE)
|
||||
nca.cmd |= AGP_3_MODE;
|
||||
ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca));
|
||||
/* tell the engine in may use AGP transfers if AGP is up and running */
|
||||
if (nca.cmd & AGP_ENABLE)
|
||||
si->engine.agp_mode = true;
|
||||
}
|
||||
|
||||
/* list mode now activated,
|
||||
* make sure we have the correct speed scheme for logging */
|
||||
nv_agp_list_active(nca.cmd | (nv_ai.interface.status & AGP_3_MODE));
|
||||
|
||||
/* 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.capability_id & AGP_REV_MAJOR) >> AGP_REV_MAJOR_SHIFT),
|
||||
((ai.interface.capability_id & AGP_REV_MINOR) >> AGP_REV_MINOR_SHIFT)));
|
||||
|
||||
/* the AGP devices determine AGP speed scheme version used on power-up/reset */
|
||||
if (!(ai.interface.status & AGP_3_MODE)) {
|
||||
/* AGP 2.0 scheme applies */
|
||||
if (ai.interface.status & AGP_2_1x)
|
||||
LOG(4,("AGP: AGP 2.0 1x mode is available\n"));
|
||||
if (ai.interface.status & AGP_2_2x)
|
||||
LOG(4,("AGP: AGP 2.0 2x mode is available\n"));
|
||||
if (ai.interface.status & AGP_2_4x)
|
||||
LOG(4,("AGP: AGP 2.0 4x mode is available\n"));
|
||||
} else {
|
||||
/* AGP 3.0 scheme applies */
|
||||
if (ai.interface.status & AGP_3_4x)
|
||||
LOG(4,("AGP: AGP 3.0 4x mode is available\n"));
|
||||
if (ai.interface.status & AGP_3_8x)
|
||||
LOG(4,("AGP: AGP 3.0 8x mode is available\n"));
|
||||
}
|
||||
if (ai.interface.status & AGP_FAST_WRITE)
|
||||
LOG(4,("AGP: fastwrite transfers are supported\n"));
|
||||
if (ai.interface.status & AGP_SBA)
|
||||
LOG(4,("AGP: sideband adressing is supported\n"));
|
||||
LOG(4,("AGP: %d queued AGP requests can be handled.\n",
|
||||
(((ai.interface.status & AGP_REQUEST) >> AGP_REQUEST_SHIFT) + 1)));
|
||||
|
||||
/*
|
||||
list current settings,
|
||||
make sure we have the correct speed scheme for logging
|
||||
*/
|
||||
nv_agp_list_active(ai.interface.command
|
||||
| (ai.interface.status & AGP_3_MODE));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nv_agp_list_active(uint32 cmd)
|
||||
{
|
||||
LOG(4,("AGP: listing settings now in use:\n"));
|
||||
if (!(cmd & AGP_3_MODE)) {
|
||||
/* 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_FAST_WRITE)
|
||||
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_REQUEST) >> AGP_REQUEST_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,876 @@
|
||||
/* Nvidia TNT and GeForce Back End Scaler functions */
|
||||
/* Written by Rudolf Cornelissen 05/2002-12/2005 */
|
||||
|
||||
#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);
|
||||
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv));
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/* make sure the engine is disabled. */
|
||||
nv_release_bes();
|
||||
|
||||
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), set colorkeying (b4), format yuy2 (b8: 0 = ccir) */
|
||||
if (ow->flags & B_OVERLAY_COLOR_KEY)
|
||||
BESW(NV04_GENCTRL, 0x00000111);
|
||||
else
|
||||
BESW(NV04_GENCTRL, 0x00000101);
|
||||
/* 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: set colorkeying, b24: no iturbt_709 (do iturbt_601) */
|
||||
/* Note:
|
||||
* source pitch granularity = 32 pixels on GeForce cards!! */
|
||||
if (ow->flags & B_OVERLAY_COLOR_KEY)
|
||||
BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (1 << 20) | (0 << 24)));
|
||||
else
|
||||
BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (0 << 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,573 @@
|
||||
/* 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));
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* select primary CRTC (head) and turn off CRT (and DVI?) outputs */
|
||||
DACW(OUTPUT, (output & 0x0000feee));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* turn off CRT (and DVI?) outputs */
|
||||
/* note:
|
||||
* Don't touch the CRTC (head) assignment bit, as that would have undefined
|
||||
* results. Confirmed NV15 cards getting into lasting RAM access trouble
|
||||
* otherwise!! (goes for both system gfx RAM access and CRTC/DAC RAM access.) */
|
||||
DACW(OUTPUT, (output & 0x0000ffee));
|
||||
}
|
||||
/* 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,392 @@
|
||||
/* 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 */
|
||||
//fixme if possible: on NV40 arch (confirmed NV43) this routine always find a monitor!
|
||||
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 CRTC (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;
|
||||
}
|
||||
@@ -0,0 +1,961 @@
|
||||
/* Authors:
|
||||
Mark Watson 12/1999,
|
||||
Apsed,
|
||||
Rudolf Cornelissen 10/2002-6/2008
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00008000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
static status_t test_ram(void);
|
||||
static status_t nvxx_general_powerup (void);
|
||||
static void unlock_card(void);
|
||||
static status_t nv_general_bios_to_powergraphics(void);
|
||||
|
||||
static void nv_dump_configuration_space (void)
|
||||
{
|
||||
#define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \
|
||||
uint32 value = CFGR(reg); \
|
||||
MSG(("configuration_space 0x%02x %20s 0x%08x\n", \
|
||||
NVCFG_##reg, #reg, value)); \
|
||||
} while (0)
|
||||
DUMP_CFG (DEVID, 0);
|
||||
DUMP_CFG (DEVCTRL, 0);
|
||||
DUMP_CFG (CLASS, 0);
|
||||
DUMP_CFG (HEADER, 0);
|
||||
DUMP_CFG (BASE1REGS,0);
|
||||
DUMP_CFG (BASE2FB, 0);
|
||||
DUMP_CFG (BASE3, 0);
|
||||
DUMP_CFG (BASE4, 0);
|
||||
DUMP_CFG (BASE5, 0);
|
||||
DUMP_CFG (BASE6, 0);
|
||||
DUMP_CFG (BASE7, 0);
|
||||
DUMP_CFG (SUBSYSID1,0);
|
||||
DUMP_CFG (ROMBASE, 0);
|
||||
DUMP_CFG (CAPPTR, 0);
|
||||
DUMP_CFG (CFG_1, 0);
|
||||
DUMP_CFG (INTERRUPT,0);
|
||||
DUMP_CFG (SUBSYSID2,0);
|
||||
DUMP_CFG (AGPREF, 0);
|
||||
DUMP_CFG (AGPSTAT, 0);
|
||||
DUMP_CFG (AGPCMD, 0);
|
||||
DUMP_CFG (ROMSHADOW,0);
|
||||
DUMP_CFG (VGA, 0);
|
||||
DUMP_CFG (SCHRATCH, 0);
|
||||
DUMP_CFG (CFG_10, 0);
|
||||
DUMP_CFG (CFG_11, 0);
|
||||
DUMP_CFG (CFG_12, 0);
|
||||
DUMP_CFG (CFG_13, 0);
|
||||
DUMP_CFG (CFG_14, 0);
|
||||
DUMP_CFG (CFG_15, 0);
|
||||
DUMP_CFG (CFG_16, 0);
|
||||
DUMP_CFG (PCIEREF, 0);
|
||||
DUMP_CFG (PCIEDCAP, 0);
|
||||
DUMP_CFG (PCIEDCTST,0);
|
||||
DUMP_CFG (PCIELCAP, 0);
|
||||
DUMP_CFG (PCIELCTST,0);
|
||||
DUMP_CFG (CFG_22, 0);
|
||||
DUMP_CFG (CFG_23, 0);
|
||||
DUMP_CFG (CFG_24, 0);
|
||||
DUMP_CFG (CFG_25, 0);
|
||||
DUMP_CFG (CFG_26, 0);
|
||||
DUMP_CFG (CFG_27, 0);
|
||||
DUMP_CFG (CFG_28, 0);
|
||||
DUMP_CFG (CFG_29, 0);
|
||||
DUMP_CFG (CFG_30, 0);
|
||||
DUMP_CFG (CFG_31, 0);
|
||||
DUMP_CFG (CFG_32, 0);
|
||||
DUMP_CFG (CFG_33, 0);
|
||||
DUMP_CFG (CFG_34, 0);
|
||||
DUMP_CFG (CFG_35, 0);
|
||||
DUMP_CFG (CFG_36, 0);
|
||||
DUMP_CFG (CFG_37, 0);
|
||||
DUMP_CFG (CFG_38, 0);
|
||||
DUMP_CFG (CFG_39, 0);
|
||||
DUMP_CFG (CFG_40, 0);
|
||||
DUMP_CFG (CFG_41, 0);
|
||||
DUMP_CFG (CFG_42, 0);
|
||||
DUMP_CFG (CFG_43, 0);
|
||||
DUMP_CFG (CFG_44, 0);
|
||||
DUMP_CFG (CFG_45, 0);
|
||||
DUMP_CFG (CFG_46, 0);
|
||||
DUMP_CFG (CFG_47, 0);
|
||||
DUMP_CFG (CFG_48, 0);
|
||||
DUMP_CFG (CFG_49, 0);
|
||||
DUMP_CFG (CFG_50, 0);
|
||||
#undef DUMP_CFG
|
||||
}
|
||||
|
||||
status_t nv_general_powerup()
|
||||
{
|
||||
status_t status;
|
||||
|
||||
LOG(1,("POWERUP: Haiku nVidia-gpgpu Accelerant 0.00 running.\n"));
|
||||
|
||||
/* log VBLANK INT usability status */
|
||||
if (si->ps.int_assigned)
|
||||
LOG(4,("POWERUP: Usable INT assigned to HW; Vblank semaphore enabled\n"));
|
||||
else
|
||||
LOG(4,("POWERUP: No (usable) INT assigned to HW; Vblank semaphore disabled\n"));
|
||||
|
||||
/* preset no laptop */
|
||||
si->ps.laptop = false;
|
||||
|
||||
/* WARNING:
|
||||
* _adi.name_ and _adi.chipset_ can contain 31 readable characters max.!!! */
|
||||
|
||||
/* detect card type and power it up */
|
||||
switch(CFGR(DEVID))
|
||||
{
|
||||
/* Vendor Nvidia */
|
||||
case 0x019110de: /* Nvidia GeForce 8800 GTX */
|
||||
case 0x019310de: /* Nvidia GeForce 8800 GTS */
|
||||
si->ps.card_type = G80;
|
||||
si->ps.card_arch = NV50A;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8800");
|
||||
sprintf(si->adi.chipset, "G80");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x040010de: /* Nvidia GeForce 8600 GTS */
|
||||
case 0x040210de: /* Nvidia GeForce 8600 GT */
|
||||
si->ps.card_type = G84;
|
||||
si->ps.card_arch = NV50A;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8600");
|
||||
sprintf(si->adi.chipset, "G84");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x040710de: /* Nvidia GeForce 8600M GT */
|
||||
si->ps.card_type = G86;
|
||||
si->ps.card_arch = NV50A;
|
||||
si->ps.laptop = true;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8600M GT");
|
||||
sprintf(si->adi.chipset, "G86");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x042110de: /* Nvidia GeForce 8500 GT */
|
||||
si->ps.card_type = G86;
|
||||
si->ps.card_arch = NV50A;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8500 GT");
|
||||
sprintf(si->adi.chipset, "G86");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x042210de: /* Nvidia GeForce 8400 GS */
|
||||
si->ps.card_type = G86;
|
||||
si->ps.card_arch = NV50A;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8400 GS");
|
||||
sprintf(si->adi.chipset, "G86");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
case 0x042310de: /* Nvidia GeForce 8300 GS */
|
||||
si->ps.card_type = G86;
|
||||
si->ps.card_arch = NV50A;
|
||||
sprintf(si->adi.name, "Nvidia GeForce 8300 GS");
|
||||
sprintf(si->adi.chipset, "G86");
|
||||
status = nvxx_general_powerup();
|
||||
break;
|
||||
default:
|
||||
LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static status_t test_ram()
|
||||
{
|
||||
uint32 value, offset;
|
||||
status_t result = B_OK;
|
||||
|
||||
/* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */
|
||||
if (si->fbc.frame_buffer == NULL)
|
||||
{
|
||||
LOG(8,("INIT: test_ram detected NULL pointer.\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
|
||||
{
|
||||
/* write testpattern to cardRAM */
|
||||
((uint32 *)si->fbc.frame_buffer)[offset] = value;
|
||||
/* toggle testpattern */
|
||||
value = 0xffffffff - value;
|
||||
}
|
||||
|
||||
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
|
||||
{
|
||||
/* readback and verify testpattern from cardRAM */
|
||||
if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
|
||||
/* toggle testpattern */
|
||||
value = 0xffffffff - value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* NOTE:
|
||||
* This routine *has* to be done *after* SetDispplayMode has been executed,
|
||||
* or test results will not be representative!
|
||||
* (CAS latency is dependant on NV setup on some (DRAM) boards) */
|
||||
status_t nv_set_cas_latency()
|
||||
{
|
||||
status_t result = B_ERROR;
|
||||
uint8 latency = 0;
|
||||
|
||||
/* check current RAM access to see if we need to change anything */
|
||||
if (test_ram() == B_OK)
|
||||
{
|
||||
LOG(4,("INIT: RAM access OK.\n"));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* check if we read PINS at starttime so we have valid registersettings at our disposal */
|
||||
if (si->ps.pins_status != B_OK)
|
||||
{
|
||||
LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* OK. We might have a problem, try to fix it now.. */
|
||||
LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n"));
|
||||
|
||||
switch(si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n"));
|
||||
return B_OK;
|
||||
break;
|
||||
}
|
||||
if (result == B_OK)
|
||||
LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency));
|
||||
else
|
||||
LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void setup_virtualized_heads(bool cross)
|
||||
{
|
||||
if (cross)
|
||||
{
|
||||
head1_interrupt_enable = (crtc_interrupt_enable) nv_crtc2_interrupt_enable;
|
||||
head1_update_fifo = (crtc_update_fifo) nv_crtc2_update_fifo;
|
||||
head1_validate_timing = (crtc_validate_timing) nv_crtc2_validate_timing;
|
||||
head1_set_timing = (crtc_set_timing) nv_crtc2_set_timing;
|
||||
head1_depth = (crtc_depth) nv_crtc2_depth;
|
||||
head1_dpms = (crtc_dpms) nv_crtc2_dpms;
|
||||
head1_set_display_pitch = (crtc_set_display_pitch) nv_crtc2_set_display_pitch;
|
||||
head1_set_display_start = (crtc_set_display_start) nv_crtc2_set_display_start;
|
||||
head1_cursor_init = (crtc_cursor_init) nv_crtc2_cursor_init;
|
||||
head1_cursor_show = (crtc_cursor_show) nv_crtc2_cursor_show;
|
||||
head1_cursor_hide = (crtc_cursor_hide) nv_crtc2_cursor_hide;
|
||||
head1_cursor_define = (crtc_cursor_define) nv_crtc2_cursor_define;
|
||||
head1_cursor_position = (crtc_cursor_position) nv_crtc2_cursor_position;
|
||||
head1_stop_tvout = (crtc_stop_tvout) nv_crtc2_stop_tvout;
|
||||
head1_start_tvout = (crtc_start_tvout) nv_crtc2_start_tvout;
|
||||
|
||||
head1_mode = (dac_mode) nv_dac2_mode;
|
||||
head1_palette = (dac_palette) nv_dac2_palette;
|
||||
head1_set_pix_pll = (dac_set_pix_pll) nv_dac2_set_pix_pll;
|
||||
head1_pix_pll_find = (dac_pix_pll_find) nv_dac2_pix_pll_find;
|
||||
|
||||
head2_interrupt_enable = (crtc_interrupt_enable) nv_crtc_interrupt_enable;
|
||||
head2_update_fifo = (crtc_update_fifo) nv_crtc_update_fifo;
|
||||
head2_validate_timing = (crtc_validate_timing) nv_crtc_validate_timing;
|
||||
head2_set_timing = (crtc_set_timing) nv_crtc_set_timing;
|
||||
head2_depth = (crtc_depth) nv_crtc_depth;
|
||||
head2_dpms = (crtc_dpms) nv_crtc_dpms;
|
||||
head2_set_display_pitch = (crtc_set_display_pitch) nv_crtc_set_display_pitch;
|
||||
head2_set_display_start = (crtc_set_display_start) nv_crtc_set_display_start;
|
||||
head2_cursor_init = (crtc_cursor_init) nv_crtc_cursor_init;
|
||||
head2_cursor_show = (crtc_cursor_show) nv_crtc_cursor_show;
|
||||
head2_cursor_hide = (crtc_cursor_hide) nv_crtc_cursor_hide;
|
||||
head2_cursor_define = (crtc_cursor_define) nv_crtc_cursor_define;
|
||||
head2_cursor_position = (crtc_cursor_position) nv_crtc_cursor_position;
|
||||
head2_stop_tvout = (crtc_stop_tvout) nv_crtc_stop_tvout;
|
||||
head2_start_tvout = (crtc_start_tvout) nv_crtc_start_tvout;
|
||||
|
||||
head2_mode = (dac_mode) nv_dac_mode;
|
||||
head2_palette = (dac_palette) nv_dac_palette;
|
||||
head2_set_pix_pll = (dac_set_pix_pll) nv_dac_set_pix_pll;
|
||||
head2_pix_pll_find = (dac_pix_pll_find) nv_dac_pix_pll_find;
|
||||
}
|
||||
else
|
||||
{
|
||||
head1_interrupt_enable = (crtc_interrupt_enable) nv_crtc_interrupt_enable;
|
||||
head1_update_fifo = (crtc_update_fifo) nv_crtc_update_fifo;
|
||||
head1_validate_timing = (crtc_validate_timing) nv_crtc_validate_timing;
|
||||
head1_set_timing = (crtc_set_timing) nv_crtc_set_timing;
|
||||
head1_depth = (crtc_depth) nv_crtc_depth;
|
||||
head1_dpms = (crtc_dpms) nv_crtc_dpms;
|
||||
head1_set_display_pitch = (crtc_set_display_pitch) nv_crtc_set_display_pitch;
|
||||
head1_set_display_start = (crtc_set_display_start) nv_crtc_set_display_start;
|
||||
head1_cursor_init = (crtc_cursor_init) nv_crtc_cursor_init;
|
||||
head1_cursor_show = (crtc_cursor_show) nv_crtc_cursor_show;
|
||||
head1_cursor_hide = (crtc_cursor_hide) nv_crtc_cursor_hide;
|
||||
head1_cursor_define = (crtc_cursor_define) nv_crtc_cursor_define;
|
||||
head1_cursor_position = (crtc_cursor_position) nv_crtc_cursor_position;
|
||||
head1_stop_tvout = (crtc_stop_tvout) nv_crtc_stop_tvout;
|
||||
head1_start_tvout = (crtc_start_tvout) nv_crtc_start_tvout;
|
||||
|
||||
head1_mode = (dac_mode) nv_dac_mode;
|
||||
head1_palette = (dac_palette) nv_dac_palette;
|
||||
head1_set_pix_pll = (dac_set_pix_pll) nv_dac_set_pix_pll;
|
||||
head1_pix_pll_find = (dac_pix_pll_find) nv_dac_pix_pll_find;
|
||||
|
||||
head2_interrupt_enable = (crtc_interrupt_enable) nv_crtc2_interrupt_enable;
|
||||
head2_update_fifo = (crtc_update_fifo) nv_crtc2_update_fifo;
|
||||
head2_validate_timing = (crtc_validate_timing) nv_crtc2_validate_timing;
|
||||
head2_set_timing = (crtc_set_timing) nv_crtc2_set_timing;
|
||||
head2_depth = (crtc_depth) nv_crtc2_depth;
|
||||
head2_dpms = (crtc_dpms) nv_crtc2_dpms;
|
||||
head2_set_display_pitch = (crtc_set_display_pitch) nv_crtc2_set_display_pitch;
|
||||
head2_set_display_start = (crtc_set_display_start) nv_crtc2_set_display_start;
|
||||
head2_cursor_init = (crtc_cursor_init) nv_crtc2_cursor_init;
|
||||
head2_cursor_show = (crtc_cursor_show) nv_crtc2_cursor_show;
|
||||
head2_cursor_hide = (crtc_cursor_hide) nv_crtc2_cursor_hide;
|
||||
head2_cursor_define = (crtc_cursor_define) nv_crtc2_cursor_define;
|
||||
head2_cursor_position = (crtc_cursor_position) nv_crtc2_cursor_position;
|
||||
head2_stop_tvout = (crtc_stop_tvout) nv_crtc2_stop_tvout;
|
||||
head2_start_tvout = (crtc_start_tvout) nv_crtc2_start_tvout;
|
||||
|
||||
head2_mode = (dac_mode) nv_dac2_mode;
|
||||
head2_palette = (dac_palette) nv_dac2_palette;
|
||||
head2_set_pix_pll = (dac_set_pix_pll) nv_dac2_set_pix_pll;
|
||||
head2_pix_pll_find = (dac_pix_pll_find) nv_dac2_pix_pll_find;
|
||||
}
|
||||
}
|
||||
|
||||
void set_crtc_owner(bool head)
|
||||
{
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
if (!head)
|
||||
{
|
||||
/* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's,
|
||||
* while non-NV11 cards behave normally.
|
||||
*
|
||||
* Double-write action needed on those strange NV11 cards: */
|
||||
/* RESET: needed on NV11 */
|
||||
CRTCW(OWNER, 0xff);
|
||||
/* enable access to CRTC1, SEQ1, GRPH1, ATB1, ??? */
|
||||
CRTCW(OWNER, 0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's,
|
||||
* while non-NV11 cards behave normally.
|
||||
*
|
||||
* Double-write action needed on those strange NV11 cards: */
|
||||
/* RESET: needed on NV11 */
|
||||
CRTC2W(OWNER, 0xff);
|
||||
/* enable access to CRTC2, SEQ2, GRPH2, ATB2, ??? */
|
||||
CRTC2W(OWNER, 0x03);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static status_t nvxx_general_powerup()
|
||||
{
|
||||
LOG(4, ("INIT: NV powerup\n"));
|
||||
LOG(4,("POWERUP: Detected %s (%s)\n", si->adi.name, si->adi.chipset));
|
||||
|
||||
//for now keeping it (need to get a system up and running to test..
|
||||
if (si->ps.card_arch >= NV50A)
|
||||
{
|
||||
LOG(8,("POWERUP: G80 and higher support not implemented: different architecture!\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* setup cardspecs */
|
||||
/* note:
|
||||
* this MUST be done before the driver attempts a card coldstart */
|
||||
set_specs();
|
||||
|
||||
/* only process BIOS for finetuning specs and coldstarting card if requested
|
||||
* by the user;
|
||||
* note:
|
||||
* this in fact frees the driver from relying on the BIOS to be executed
|
||||
* at system power-up POST time. */
|
||||
if (!si->settings.usebios)
|
||||
{
|
||||
LOG(2, ("INIT: Attempting card coldstart!\n"));
|
||||
/* update the cardspecs in the shared_info PINS struct according to reported
|
||||
* specs as much as is possible;
|
||||
* this also coldstarts the card if possible (executes BIOS CMD script(s)) */
|
||||
// parse_pins();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(2, ("INIT: Skipping card coldstart!\n"));
|
||||
}
|
||||
|
||||
// unlock_card();
|
||||
|
||||
/* get RAM size, detect TV encoder and do fake panel startup (panel init code
|
||||
* is still missing). */
|
||||
// fake_panel_start();
|
||||
|
||||
/* log the final card specifications */
|
||||
dump_pins();
|
||||
|
||||
/* dump config space as it is after a possible coldstart attempt */
|
||||
if (si->settings.logmask & 0x80000000) nv_dump_configuration_space();
|
||||
|
||||
/* setup CRTC and DAC functions access: determined in fake_panel_start */
|
||||
setup_virtualized_heads(si->ps.crtc2_prim);
|
||||
|
||||
/* do powerup needed from pre-inited card state as done by system POST cardBIOS
|
||||
* execution or driver coldstart above */
|
||||
return nv_general_bios_to_powergraphics();
|
||||
}
|
||||
|
||||
/* this routine switches the CRTC/DAC sets to 'connectors', but only for analog
|
||||
* outputs. We need this to make sure the analog 'switch' is set in the same way the
|
||||
* digital 'switch' is set by the BIOS or we might not be able to use dualhead. */
|
||||
status_t nv_general_output_select(bool cross)
|
||||
{
|
||||
/* make sure this call is warranted */
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* NV11 cards can't switch heads (confirmed) */
|
||||
if (si->ps.card_type != NV11)
|
||||
{
|
||||
if (cross)
|
||||
{
|
||||
LOG(4,("INIT: switching analog outputs to be cross-connected\n"));
|
||||
|
||||
/* enable head 2 on connector 1 */
|
||||
/* (b8 = select CRTC (head) for output,
|
||||
* b4 = ??? (confirmed not to be a FP switch),
|
||||
* b0 = enable CRT) */
|
||||
DACW(OUTPUT, 0x00000101);
|
||||
/* enable head 1 on connector 2 */
|
||||
DAC2W(OUTPUT, 0x00000001);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("INIT: switching analog outputs to be straight-through\n"));
|
||||
|
||||
/* enable head 1 on connector 1 */
|
||||
DACW(OUTPUT, 0x00000001);
|
||||
/* enable head 2 on connector 2 */
|
||||
DAC2W(OUTPUT, 0x00000101);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("INIT: NV11 analog outputs are hardwired to be straight-through\n"));
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* this routine switches CRTC/DAC set use. We need this because it's unknown howto
|
||||
* switch digital panels to/from a specific CRTC/DAC set. */
|
||||
status_t nv_general_head_select(bool cross)
|
||||
{
|
||||
/* make sure this call is warranted */
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* invert CRTC/DAC use to do switching */
|
||||
if (cross)
|
||||
{
|
||||
LOG(4,("INIT: switching CRTC/DAC use to be cross-connected\n"));
|
||||
si->crtc_switch_mode = !si->ps.crtc2_prim;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(4,("INIT: switching CRTC/DAC use to be straight-through\n"));
|
||||
si->crtc_switch_mode = si->ps.crtc2_prim;
|
||||
}
|
||||
/* update CRTC and DAC functions access */
|
||||
setup_virtualized_heads(si->crtc_switch_mode);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void unlock_card(void)
|
||||
{
|
||||
/* power-up all nvidia hardware function blocks */
|
||||
/* bit 28: OVERLAY ENGINE (BES),
|
||||
* bit 25: CRTC2, (> NV04A)
|
||||
* bit 24: CRTC1,
|
||||
* bit 20: framebuffer,
|
||||
* bit 16: PPMI,
|
||||
* bit 12: PGRAPH,
|
||||
* bit 8: PFIFO,
|
||||
* bit 4: PMEDIA,
|
||||
* bit 0: TVOUT. (> NV04A) */
|
||||
NV_REG32(NV32_PWRUPCTRL) = 0x13111111;
|
||||
|
||||
/* select colormode CRTC registers base adresses */
|
||||
NV_REG8(NV8_MISCW) = 0xcb;
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
/* unlock head's registers for R/W access */
|
||||
CRTCW(LOCK, 0x57);
|
||||
CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* enable access to secondary head */
|
||||
set_crtc_owner(1);
|
||||
/* unlock head's registers for R/W access */
|
||||
CRTC2W(LOCK, 0x57);
|
||||
CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f));
|
||||
}
|
||||
}
|
||||
|
||||
/* basic change of card state from VGA to enhanced mode:
|
||||
* Should work from VGA BIOS POST init state. */
|
||||
static status_t nv_general_bios_to_powergraphics()
|
||||
{
|
||||
return B_OK;
|
||||
/* let acc engine make power off/power on cycle to start 'fresh' */
|
||||
NV_REG32(NV32_PWRUPCTRL) = 0x13110011;
|
||||
snooze(1000);
|
||||
NV_REG32(NV32_PWRUPCTRL) = 0x13111111;
|
||||
|
||||
unlock_card();
|
||||
|
||||
/* turn off both displays and the hardcursors (also disables transfers) */
|
||||
head1_dpms(false, false, false, true);
|
||||
head1_cursor_hide();
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
head2_dpms(false, false, false, true);
|
||||
head2_cursor_hide();
|
||||
}
|
||||
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* switch overlay engine and TV encoder to CRTC1 */
|
||||
/* bit 17: GPU FP port #1 (confirmed NV25, NV28, confirmed not on NV34),
|
||||
* bit 16: GPU FP port #2 (confirmed NV25, NV28, NV34),
|
||||
* bit 12: overlay engine (all cards),
|
||||
* bit 9: TVout chip #2 (confirmed on NV18, NV25, NV28),
|
||||
* bit 8: TVout chip #1 (all cards),
|
||||
* bit 4: both I2C busses (all cards) */
|
||||
NV_REG32(NV32_2FUNCSEL) &= ~0x00001100;
|
||||
NV_REG32(NV32_FUNCSEL) |= 0x00001100;
|
||||
}
|
||||
si->overlay.crtc = false;
|
||||
|
||||
/* enable 'enhanced' mode on primary head: */
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
/* note: 'BUFFER' is a non-standard register in behaviour(!) on most
|
||||
* NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards
|
||||
* behave normally.
|
||||
* Also readback is not nessesarily what was written before!
|
||||
*
|
||||
* Double-write action needed on those strange NV11 cards: */
|
||||
/* RESET: don't doublebuffer CRTC access: set programmed values immediately... */
|
||||
CRTCW(BUFFER, 0xff);
|
||||
/* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */
|
||||
/* note: this has no effect on possible bandwidth issues. */
|
||||
CRTCW(BUFFER, 0xfb);
|
||||
/* select VGA mode (old VGA register) */
|
||||
CRTCW(MODECTL, 0xc3);
|
||||
/* select graphics mode (old VGA register) */
|
||||
SEQW(MEMMODE, 0x0e);
|
||||
/* select 8 dots character clocks (old VGA register) */
|
||||
SEQW(CLKMODE, 0x21);
|
||||
/* select VGA mode (old VGA register) */
|
||||
GRPHW(MODE, 0x00);
|
||||
/* select graphics mode (old VGA register) */
|
||||
GRPHW(MISC, 0x01);
|
||||
/* select graphics mode (old VGA register) */
|
||||
ATBW(MODECTL, 0x01);
|
||||
/* enable 'enhanced mode', enable Vsync & Hsync,
|
||||
* set DAC palette to 8-bit width, disable large screen */
|
||||
CRTCW(REPAINT1, 0x04);
|
||||
|
||||
/* enable 'enhanced' mode on secondary head: */
|
||||
if (si->ps.secondary_head)
|
||||
{
|
||||
/* enable access to secondary head */
|
||||
set_crtc_owner(1);
|
||||
/* select colormode CRTC2 registers base adresses */
|
||||
NV_REG8(NV8_MISCW) = 0xcb;
|
||||
/* note: 'BUFFER' is a non-standard register in behaviour(!) on most
|
||||
* NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards
|
||||
* behave normally.
|
||||
* Also readback is not nessesarily what was written before!
|
||||
*
|
||||
* Double-write action needed on those strange NV11 cards: */
|
||||
/* RESET: don't doublebuffer CRTC2 access: set programmed values immediately... */
|
||||
CRTC2W(BUFFER, 0xff);
|
||||
/* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */
|
||||
/* note: this has no effect on possible bandwidth issues. */
|
||||
CRTC2W(BUFFER, 0xfb);
|
||||
/* select VGA mode (old VGA register) */
|
||||
CRTC2W(MODECTL, 0xc3);
|
||||
/* select graphics mode (old VGA register) */
|
||||
SEQW(MEMMODE, 0x0e);
|
||||
/* select 8 dots character clocks (old VGA register) */
|
||||
SEQW(CLKMODE, 0x21);
|
||||
/* select VGA mode (old VGA register) */
|
||||
GRPHW(MODE, 0x00);
|
||||
/* select graphics mode (old VGA register) */
|
||||
GRPHW(MISC, 0x01);
|
||||
/* select graphics mode (old VGA register) */
|
||||
ATB2W(MODECTL, 0x01);
|
||||
/* enable 'enhanced mode', enable Vsync & Hsync,
|
||||
* set DAC palette to 8-bit width, disable large screen */
|
||||
CRTC2W(REPAINT1, 0x04);
|
||||
}
|
||||
|
||||
/* enable palettes */
|
||||
DACW(GENCTRL, 0x00100100);
|
||||
if (si->ps.secondary_head) DAC2W(GENCTRL, 0x00100100);
|
||||
|
||||
/* enable programmable PLLs */
|
||||
/* (confirmed PLLSEL to be a write-only register on NV04 and NV11!) */
|
||||
if (si->ps.secondary_head)
|
||||
DACW(PLLSEL, 0x30000f00);
|
||||
else
|
||||
DACW(PLLSEL, 0x10000700);
|
||||
|
||||
/* turn on DAC and make sure detection testsignal routing is disabled
|
||||
* (b16 = disable DAC,
|
||||
* b12 = enable testsignal output */
|
||||
//fixme note: b20 ('DACTM_TEST') when set apparantly blocks a DAC's video output
|
||||
//(confirmed NV43), while it's timing remains operational (black screen).
|
||||
//It feels like in some screen configurations it can move the output to the other
|
||||
//output connector as well...
|
||||
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeefff));
|
||||
/* turn on DAC2 if it exists
|
||||
* (NOTE: testsignal function block resides in DAC1 only (!)) */
|
||||
if (si->ps.secondary_head) DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeefff));
|
||||
|
||||
/* NV40 and NV45 need a 'tweak' to make sure the CRTC FIFO's/shiftregisters get
|
||||
* their data in time (otherwise momentarily ghost images of windows or such
|
||||
* may appear on heavy acceleration engine use for instance, especially in 32-bit
|
||||
* colordepth) */
|
||||
if ((si->ps.card_type == NV40) || (si->ps.card_type == NV45))
|
||||
{
|
||||
/* clear b15: some framebuffer config item (unknown) */
|
||||
NV_REG32(NV32_PFB_CLS_PAGE2) &= 0xffff7fff;
|
||||
}
|
||||
|
||||
/* tweak card GPU-core and RAM speeds if requested (hoping we'll survive)... */
|
||||
if (si->settings.gpu_clk)
|
||||
{
|
||||
LOG(2,("INIT: tweaking GPU clock!\n"));
|
||||
|
||||
set_pll(NV32_COREPLL, si->settings.gpu_clk);
|
||||
snooze(1000);
|
||||
}
|
||||
if (si->settings.ram_clk)
|
||||
{
|
||||
LOG(2,("INIT: tweaking cardRAM clock!\n"));
|
||||
|
||||
set_pll(NV32_MEMPLL, si->settings.ram_clk);
|
||||
snooze(1000);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
|
||||
* virtual_size to the nearest valid maximum for the mode on the card if not so.
|
||||
* Also: check if virtual_width adheres to the cards granularity constraints, and
|
||||
* create mode slopspace if not so.
|
||||
* We use acc or crtc granularity constraints based on the 'worst case' scenario.
|
||||
*
|
||||
* Mode slopspace is reflected in fbc->bytes_per_row BTW. */
|
||||
status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode)
|
||||
{
|
||||
uint32 video_pitch;
|
||||
uint32 acc_mask, crtc_mask;
|
||||
uint32 max_crtc_width, max_acc_width;
|
||||
uint8 depth = 8;
|
||||
|
||||
/* determine pixel multiple based on acceleration engine constraints */
|
||||
/* note:
|
||||
* because of the seemingly 'random' variations in these constraints we take
|
||||
* a reasonable 'lowest common denominator' instead of always true constraints. */
|
||||
switch (si->ps.card_arch)
|
||||
{
|
||||
case NV04A:
|
||||
/* confirmed for:
|
||||
* TNT1 (NV04), TNT2 (NV05), TNT2-M64 (NV05M64), GeForce2 MX400 (NV11),
|
||||
* GeForce4 MX440 (NV18), GeForceFX 5200 (NV34) in PIO acc mode;
|
||||
* confirmed for:
|
||||
* TNT1 (NV04), TNT2 (NV05), TNT2-M64 (NV05M64), GeForce4 Ti4200 (NV28),
|
||||
* GeForceFX 5200 (NV34) in DMA acc mode. */
|
||||
switch (target->space)
|
||||
{
|
||||
case B_CMAP8: acc_mask = 0x0f; depth = 8; break;
|
||||
case B_RGB15: acc_mask = 0x07; depth = 16; break;
|
||||
case B_RGB16: acc_mask = 0x07; depth = 16; break;
|
||||
case B_RGB24: acc_mask = 0x0f; depth = 24; break;
|
||||
case B_RGB32: acc_mask = 0x03; depth = 32; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* confirmed for:
|
||||
* GeForce4 Ti4200 (NV28), GeForceFX 5600 (NV31) in PIO acc mode;
|
||||
* confirmed for:
|
||||
* GeForce2 MX400 (NV11), GeForce4 MX440 (NV18), GeForcePCX 5750 (NV36),
|
||||
* GeForcePCX 6600 GT (NV43) in DMA acc mode. */
|
||||
switch (target->space)
|
||||
{
|
||||
case B_CMAP8: acc_mask = 0x3f; depth = 8; break;
|
||||
case B_RGB15: acc_mask = 0x1f; depth = 16; break;
|
||||
case B_RGB16: acc_mask = 0x1f; depth = 16; break;
|
||||
case B_RGB24: acc_mask = 0x3f; depth = 24; break;
|
||||
case B_RGB32: acc_mask = 0x0f; depth = 32; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* determine pixel multiple based on CRTC memory pitch constraints:
|
||||
* -> all NV cards have same granularity constraints on CRTC1 and CRTC2,
|
||||
* provided that the CRTC1 and CRTC2 BUFFER register b2 = 0;
|
||||
*
|
||||
* (Note: Don't mix this up with CRTC timing contraints! Those are
|
||||
* multiples of 8 for horizontal, 1 for vertical timing.) */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
// case NV04:
|
||||
/* confirmed for:
|
||||
* TNT1 always;
|
||||
* TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200,
|
||||
* GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */
|
||||
/* NOTE:
|
||||
* Unfortunately older cards have a hardware fault that prevents use.
|
||||
* We need doubled granularity on those to prevent the single top line
|
||||
* from shifting to the left!
|
||||
* This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400.
|
||||
* Confirmed OK are:
|
||||
* GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */
|
||||
switch (target->space)
|
||||
{
|
||||
case B_CMAP8: crtc_mask = 0x0f; break; /* 0x07 */
|
||||
case B_RGB15: crtc_mask = 0x07; break; /* 0x03 */
|
||||
case B_RGB16: crtc_mask = 0x07; break; /* 0x03 */
|
||||
case B_RGB24: crtc_mask = 0x0f; break; /* 0x07 */
|
||||
case B_RGB32: crtc_mask = 0x03; break; /* 0x01 */
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
// default:
|
||||
/* confirmed for:
|
||||
* TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200,
|
||||
* GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */
|
||||
/* switch (target->space)
|
||||
{
|
||||
case B_CMAP8: crtc_mask = 0x1f; break;
|
||||
case B_RGB15: crtc_mask = 0x0f; break;
|
||||
case B_RGB16: crtc_mask = 0x0f; break;
|
||||
case B_RGB24: crtc_mask = 0x1f; break;
|
||||
case B_RGB32: crtc_mask = 0x07; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
*/ }
|
||||
|
||||
/* set virtual_width limit for accelerated modes */
|
||||
/* note:
|
||||
* because of the seemingly 'random' variations in these constraints we take
|
||||
* a reasonable 'lowest common denominator' instead of always true constraints. */
|
||||
switch (si->ps.card_arch)
|
||||
{
|
||||
case NV04A:
|
||||
/* confirmed for:
|
||||
* TNT1 (NV04), TNT2 (NV05), TNT2-M64 (NV05M64) in both PIO and DMA acc mode. */
|
||||
switch(target->space)
|
||||
{
|
||||
case B_CMAP8: max_acc_width = 8176; break;
|
||||
case B_RGB15: max_acc_width = 4088; break;
|
||||
case B_RGB16: max_acc_width = 4088; break;
|
||||
case B_RGB24: max_acc_width = 2720; break;
|
||||
case B_RGB32: max_acc_width = 2044; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* confirmed for:
|
||||
* GeForce4 Ti4200 (NV28), GeForceFX 5600 (NV31) in PIO acc mode;
|
||||
* GeForce2 MX400 (NV11), GeForce4 MX440 (NV18), GeForceFX 5200 (NV34) can do
|
||||
* 16368/8184/8184/5456/4092, so a bit better in PIO acc mode;
|
||||
* confirmed for:
|
||||
* GeForce2 MX400 (NV11), GeForce4 MX440 (NV18), GeForcePCX 5750 (NV36),
|
||||
* GeForcePCX 6600 GT (NV43) in DMA acc mode;
|
||||
* GeForce4 Ti4200 (NV28), GeForceFX 5200 (NV34) can do
|
||||
* 16368/8184/8184/5456/4092, so a bit better in DMA acc mode. */
|
||||
switch(target->space)
|
||||
{
|
||||
case B_CMAP8: max_acc_width = 16320; break;
|
||||
case B_RGB15: max_acc_width = 8160; break;
|
||||
case B_RGB16: max_acc_width = 8160; break;
|
||||
case B_RGB24: max_acc_width = 5440; break;
|
||||
case B_RGB32: max_acc_width = 4080; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* set virtual_width limit for unaccelerated modes */
|
||||
switch (si->ps.card_type)
|
||||
{
|
||||
default:
|
||||
// case NV04:
|
||||
/* confirmed for:
|
||||
* TNT1 always;
|
||||
* TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200,
|
||||
* GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */
|
||||
/* NOTE:
|
||||
* Unfortunately older cards have a hardware fault that prevents use.
|
||||
* We need doubled granularity on those to prevent the single top line
|
||||
* from shifting to the left!
|
||||
* This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400.
|
||||
* Confirmed OK are:
|
||||
* GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */
|
||||
switch(target->space)
|
||||
{
|
||||
case B_CMAP8: max_crtc_width = 16368; break; /* 16376 */
|
||||
case B_RGB15: max_crtc_width = 8184; break; /* 8188 */
|
||||
case B_RGB16: max_crtc_width = 8184; break; /* 8188 */
|
||||
case B_RGB24: max_crtc_width = 5456; break; /* 5456 */
|
||||
case B_RGB32: max_crtc_width = 4092; break; /* 4094 */
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
// default:
|
||||
/* confirmed for:
|
||||
* TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200,
|
||||
* GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */
|
||||
/* switch(target->space)
|
||||
{
|
||||
case B_CMAP8: max_crtc_width = 16352; break;
|
||||
case B_RGB15: max_crtc_width = 8176; break;
|
||||
case B_RGB16: max_crtc_width = 8176; break;
|
||||
case B_RGB24: max_crtc_width = 5440; break;
|
||||
case B_RGB32: max_crtc_width = 4088; break;
|
||||
default:
|
||||
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
|
||||
return B_ERROR;
|
||||
}
|
||||
break;
|
||||
*/ }
|
||||
|
||||
/* check for acc capability, and adjust mode to adhere to hardware constraints */
|
||||
if (max_acc_width <= max_crtc_width)
|
||||
{
|
||||
/* check if we can setup this mode with acceleration */
|
||||
*acc_mode = true;
|
||||
//no acc support for G8x yet!
|
||||
if (si->ps.card_arch >= NV50A) *acc_mode = false;
|
||||
|
||||
/* virtual_width */
|
||||
if (target->virtual_width > max_acc_width) *acc_mode = false;
|
||||
/* virtual_height */
|
||||
/* (NV cards can even do more than this(?)...
|
||||
* but 4096 is confirmed on all cards at max. accelerated width.) */
|
||||
if (target->virtual_height > 4096) *acc_mode = false;
|
||||
|
||||
/* now check virtual_size based on CRTC constraints */
|
||||
if (target->virtual_width > max_crtc_width) target->virtual_width = max_crtc_width;
|
||||
/* virtual_height: The only constraint here is the cards memory size which is
|
||||
* checked later on in ProposeMode: virtual_height is adjusted then if needed.
|
||||
* 'Limiting here' to the variable size that's at least available (uint16). */
|
||||
if (target->virtual_height > 65535) target->virtual_height = 65535;
|
||||
|
||||
/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
|
||||
* it was confined above, so we can finally calculate safely if we need slopspace
|
||||
* for this mode... */
|
||||
if (*acc_mode)
|
||||
{
|
||||
/* the mode needs to adhere to the largest granularity imposed... */
|
||||
if (acc_mask < crtc_mask)
|
||||
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
|
||||
else
|
||||
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
|
||||
}
|
||||
else /* unaccelerated mode */
|
||||
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
|
||||
}
|
||||
else /* max_acc_width > max_crtc_width */
|
||||
{
|
||||
/* check if we can setup this mode with acceleration */
|
||||
*acc_mode = true;
|
||||
//no acc support for G8x yet!
|
||||
if (si->ps.card_arch >= NV50A) *acc_mode = false;
|
||||
/* (we already know virtual_width will be no problem) */
|
||||
/* virtual_height */
|
||||
/* (NV cards can even do more than this(?)...
|
||||
* but 4096 is confirmed on all cards at max. accelerated width.) */
|
||||
if (target->virtual_height > 4096) *acc_mode = false;
|
||||
|
||||
/* now check virtual_size based on CRTC constraints */
|
||||
if (*acc_mode)
|
||||
{
|
||||
/* note that max_crtc_width already adheres to crtc_mask */
|
||||
if (target->virtual_width > (max_crtc_width & ~acc_mask))
|
||||
target->virtual_width = (max_crtc_width & ~acc_mask);
|
||||
}
|
||||
else /* unaccelerated mode */
|
||||
{
|
||||
if (target->virtual_width > max_crtc_width)
|
||||
target->virtual_width = max_crtc_width;
|
||||
}
|
||||
/* virtual_height: The only constraint here is the cards memory size which is
|
||||
* checked later on in ProposeMode: virtual_height is adjusted then if needed.
|
||||
* 'Limiting here' to the variable size that's at least available (uint16). */
|
||||
if (target->virtual_height > 65535) target->virtual_height = 65535;
|
||||
|
||||
/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
|
||||
* it was confined above, so we can finally calculate safely if we need slopspace
|
||||
* for this mode... */
|
||||
if (*acc_mode)
|
||||
{
|
||||
/* the mode needs to adhere to the largest granularity imposed... */
|
||||
if (acc_mask < crtc_mask)
|
||||
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
|
||||
else
|
||||
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
|
||||
}
|
||||
else /* unaccelerated mode */
|
||||
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
|
||||
}
|
||||
|
||||
LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
|
||||
video_pitch, target->space));
|
||||
if (target->virtual_width != video_pitch)
|
||||
LOG(2,("INIT: effective mode slopspace is %d pixels\n",
|
||||
(video_pitch - target->virtual_width)));
|
||||
|
||||
/* now calculate bytes_per_row for this mode */
|
||||
*bytes_per_row = video_pitch * (depth >> 3);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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-5/2005
|
||||
*/
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
int fd;
|
||||
shared_info *si;
|
||||
area_id shared_info_area;
|
||||
area_id dma_cmd_buf_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,75 @@
|
||||
extern int fd;
|
||||
extern shared_info *si;
|
||||
extern area_id shared_info_area;
|
||||
extern area_id dma_cmd_buf_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_interrupt_enable)(bool);
|
||||
typedef status_t (*crtc_update_fifo)(void);
|
||||
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, 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 (*crtc_stop_tvout)(void);
|
||||
typedef status_t (*crtc_start_tvout)(void);
|
||||
|
||||
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_interrupt_enable head1_interrupt_enable;
|
||||
crtc_update_fifo head1_update_fifo;
|
||||
crtc_validate_timing head1_validate_timing;
|
||||
crtc_set_timing head1_set_timing;
|
||||
crtc_depth head1_depth;
|
||||
crtc_dpms head1_dpms;
|
||||
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_stop_tvout head1_stop_tvout;
|
||||
crtc_start_tvout head1_start_tvout;
|
||||
|
||||
crtc_interrupt_enable head2_interrupt_enable;
|
||||
crtc_update_fifo head2_update_fifo;
|
||||
crtc_validate_timing head2_validate_timing;
|
||||
crtc_set_timing head2_set_timing;
|
||||
crtc_depth head2_depth;
|
||||
crtc_dpms head2_dpms;
|
||||
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;
|
||||
crtc_stop_tvout head2_stop_tvout;
|
||||
crtc_start_tvout head2_start_tvout;
|
||||
|
||||
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,344 @@
|
||||
/*
|
||||
* i2c interface.
|
||||
* Bus should be run at max. 100kHz: see original Philips I2C specification
|
||||
*
|
||||
* Rudolf Cornelissen 12/2002-10/2005
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00004000
|
||||
|
||||
#include "nv_std.h"
|
||||
|
||||
char i2c_flag_error (char ErrNo)
|
||||
//error code list:
|
||||
//0 - OK status
|
||||
//1 - SCL locked low by device (bus is still busy)
|
||||
//2 - SDA locked low by device (bus is still busy)
|
||||
//3 - No Acknowledge from device (no handshake)
|
||||
//4 - SDA not released for master to generate STOP bit
|
||||
{
|
||||
static char I2CError = 0;
|
||||
|
||||
if (!I2CError) I2CError = ErrNo;
|
||||
if (ErrNo == -1) I2CError = 0;
|
||||
return I2CError;
|
||||
}
|
||||
|
||||
static void i2c_select_bus_set(bool set)
|
||||
{
|
||||
/* I/O pins set selection is only valid on dualhead cards */
|
||||
if (!si->ps.secondary_head) return;
|
||||
|
||||
/* select GPU I/O pins set to connect to I2C 'registers' */
|
||||
if (set)
|
||||
{
|
||||
NV_REG32(NV32_FUNCSEL) &= ~0x00000010;
|
||||
NV_REG32(NV32_2FUNCSEL) |= 0x00000010;
|
||||
}
|
||||
else
|
||||
{
|
||||
NV_REG32(NV32_2FUNCSEL) &= ~0x00000010;
|
||||
NV_REG32(NV32_FUNCSEL) |= 0x00000010;
|
||||
}
|
||||
}
|
||||
|
||||
static void OutSCL(uint8 BusNR, bool Bit)
|
||||
{
|
||||
uint8 data;
|
||||
|
||||
if (BusNR & 0x01)
|
||||
{
|
||||
data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
|
||||
if (Bit)
|
||||
CRTCW(WR_I2CBUS_1, (data | 0x20));
|
||||
else
|
||||
CRTCW(WR_I2CBUS_1, (data & ~0x20));
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
|
||||
if (Bit)
|
||||
CRTCW(WR_I2CBUS_0, (data | 0x20));
|
||||
else
|
||||
CRTCW(WR_I2CBUS_0, (data & ~0x20));
|
||||
}
|
||||
}
|
||||
|
||||
static void OutSDA(uint8 BusNR, bool Bit)
|
||||
{
|
||||
uint8 data;
|
||||
|
||||
if (BusNR & 0x01)
|
||||
{
|
||||
data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01;
|
||||
if (Bit)
|
||||
CRTCW(WR_I2CBUS_1, (data | 0x10));
|
||||
else
|
||||
CRTCW(WR_I2CBUS_1, (data & ~0x10));
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01;
|
||||
if (Bit)
|
||||
CRTCW(WR_I2CBUS_0, (data | 0x10));
|
||||
else
|
||||
CRTCW(WR_I2CBUS_0, (data & ~0x10));
|
||||
}
|
||||
}
|
||||
|
||||
static bool InSCL(uint8 BusNR)
|
||||
{
|
||||
if (BusNR & 0x01)
|
||||
{
|
||||
if ((CRTCR(RD_I2CBUS_1) & 0x04)) return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((CRTCR(RD_I2CBUS_0) & 0x04)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool InSDA(uint8 BusNR)
|
||||
{
|
||||
if (BusNR & 0x01)
|
||||
{
|
||||
if ((CRTCR(RD_I2CBUS_1) & 0x08)) return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((CRTCR(RD_I2CBUS_0) & 0x08)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void TXBit (uint8 BusNR, bool Bit)
|
||||
{
|
||||
/* send out databit */
|
||||
if (Bit)
|
||||
{
|
||||
OutSDA(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSDA(BusNR)) i2c_flag_error (2);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutSDA(BusNR, false);
|
||||
}
|
||||
/* generate clock pulse */
|
||||
snooze(6);
|
||||
OutSCL(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSCL(BusNR)) i2c_flag_error (1);
|
||||
snooze(6);
|
||||
OutSCL(BusNR, false);
|
||||
snooze(6);
|
||||
}
|
||||
|
||||
static uint8 RXBit (uint8 BusNR)
|
||||
{
|
||||
uint8 Bit = 0;
|
||||
|
||||
/* set SDA so input is possible */
|
||||
OutSDA(BusNR, true);
|
||||
/* generate clock pulse */
|
||||
snooze(6);
|
||||
OutSCL(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSCL(BusNR)) i2c_flag_error (1);
|
||||
snooze(3);
|
||||
/* read databit */
|
||||
if (InSDA(BusNR)) Bit = 1;
|
||||
/* finish clockpulse */
|
||||
OutSCL(BusNR, false);
|
||||
snooze(6);
|
||||
|
||||
return Bit;
|
||||
}
|
||||
|
||||
void i2c_bstart (uint8 BusNR)
|
||||
{
|
||||
/* select GPU I/O pins set */
|
||||
i2c_select_bus_set(BusNR & 0x02);
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
|
||||
/* make sure SDA is high */
|
||||
OutSDA(BusNR, true);
|
||||
snooze(3);
|
||||
OutSCL(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSCL(BusNR)) i2c_flag_error (1);
|
||||
snooze(6);
|
||||
/* clear SDA while SCL set (bus-start condition) */
|
||||
OutSDA(BusNR, false);
|
||||
snooze(6);
|
||||
OutSCL(BusNR, false);
|
||||
snooze(6);
|
||||
|
||||
LOG(4,("I2C: START condition generated on bus %d; status is %d\n",
|
||||
BusNR, i2c_flag_error (0)));
|
||||
}
|
||||
|
||||
void i2c_bstop (uint8 BusNR)
|
||||
{
|
||||
/* select GPU I/O pins set */
|
||||
i2c_select_bus_set(BusNR & 0x02);
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
|
||||
/* make sure SDA is low */
|
||||
OutSDA(BusNR, false);
|
||||
snooze(3);
|
||||
OutSCL(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSCL(BusNR)) i2c_flag_error (1);
|
||||
snooze(6);
|
||||
/* set SDA while SCL set (bus-stop condition) */
|
||||
OutSDA(BusNR, true);
|
||||
snooze(3);
|
||||
if (!InSDA(BusNR)) i2c_flag_error (4);
|
||||
snooze(3);
|
||||
|
||||
LOG(4,("I2C: STOP condition generated on bus %d; status is %d\n",
|
||||
BusNR, i2c_flag_error (0)));
|
||||
}
|
||||
|
||||
uint8 i2c_readbyte(uint8 BusNR, bool Ack)
|
||||
{
|
||||
uint8 cnt, bit, byte = 0;
|
||||
|
||||
/* select GPU I/O pins set */
|
||||
i2c_select_bus_set(BusNR & 0x02);
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
|
||||
/* read data */
|
||||
for (cnt = 8; cnt > 0; cnt--)
|
||||
{
|
||||
byte <<= 1;
|
||||
bit = RXBit (BusNR);
|
||||
byte += bit;
|
||||
}
|
||||
/* send acknowledge */
|
||||
TXBit (BusNR, Ack);
|
||||
|
||||
LOG(4,("I2C: read byte ($%02x) from bus #%d; status is %d\n",
|
||||
byte, BusNR, i2c_flag_error(0)));
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool i2c_writebyte (uint8 BusNR, uint8 byte)
|
||||
{
|
||||
uint8 cnt;
|
||||
bool bit;
|
||||
uint8 tmp = byte;
|
||||
|
||||
/* select GPU I/O pins set */
|
||||
i2c_select_bus_set(BusNR & 0x02);
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
|
||||
/* write data */
|
||||
for (cnt = 8; cnt > 0; cnt--)
|
||||
{
|
||||
bit = (tmp & 0x80);
|
||||
TXBit (BusNR, bit);
|
||||
tmp <<= 1;
|
||||
}
|
||||
/* read acknowledge */
|
||||
bit = RXBit (BusNR);
|
||||
if (bit) i2c_flag_error (3);
|
||||
|
||||
LOG(4,("I2C: written byte ($%02x) to bus #%d; status is %d\n",
|
||||
byte, BusNR, i2c_flag_error(0)));
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size)
|
||||
{
|
||||
uint8 cnt;
|
||||
|
||||
for (cnt = 0; cnt < size; cnt++)
|
||||
{
|
||||
buf[cnt] = i2c_readbyte(BusNR, buf[cnt]);
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size)
|
||||
{
|
||||
uint8 cnt;
|
||||
|
||||
for (cnt = 0; cnt < size; cnt++)
|
||||
{
|
||||
i2c_writebyte(BusNR, buf[cnt]);
|
||||
}
|
||||
}
|
||||
|
||||
status_t i2c_init(void)
|
||||
{
|
||||
uint8 bus, buses;
|
||||
bool *i2c_bus = &(si->ps.i2c_bus0);
|
||||
status_t result = B_ERROR;
|
||||
|
||||
LOG(4,("I2C: searching for wired I2C buses...\n"));
|
||||
|
||||
/* enable access to primary head */
|
||||
set_crtc_owner(0);
|
||||
|
||||
/* preset no board wired buses */
|
||||
si->ps.i2c_bus0 = false;
|
||||
si->ps.i2c_bus1 = false;
|
||||
si->ps.i2c_bus2 = false;
|
||||
si->ps.i2c_bus3 = false;
|
||||
|
||||
/* set number of buses to test for */
|
||||
buses = 2;
|
||||
if (si->ps.secondary_head) buses = 4;
|
||||
|
||||
/* find existing buses */
|
||||
for (bus = 0; bus < buses; bus++)
|
||||
{
|
||||
/* reset status */
|
||||
i2c_flag_error (-1);
|
||||
snooze(6);
|
||||
/* init and/or stop I2C bus */
|
||||
i2c_bstop(bus);
|
||||
/* check for hardware coupling of SCL and SDA -out and -in lines */
|
||||
snooze(6);
|
||||
OutSCL(bus, false);
|
||||
OutSDA(bus, true);
|
||||
snooze(3);
|
||||
if (InSCL(bus) || !InSDA(bus)) continue;
|
||||
snooze(3);
|
||||
OutSCL(bus, true);
|
||||
OutSDA(bus, false);
|
||||
snooze(3);
|
||||
if (!InSCL(bus) || InSDA(bus)) continue;
|
||||
i2c_bus[bus] = true;
|
||||
snooze(3);
|
||||
/* re-init bus */
|
||||
i2c_bstop(bus);
|
||||
}
|
||||
|
||||
for (bus = 0; bus < buses; bus++)
|
||||
{
|
||||
if (i2c_bus[bus])
|
||||
{
|
||||
LOG(4,("I2C: bus #%d wiring check: passed\n", bus));
|
||||
result = B_OK;
|
||||
}
|
||||
else
|
||||
LOG(4,("I2C: bus #%d wiring check: failed\n", bus));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
||||
/* 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_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode);
|
||||
|
||||
/* 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 */
|
||||
status_t i2c_sec_tv_adapter(void);
|
||||
char i2c_flag_error (char ErrNo);
|
||||
void i2c_bstart (uint8 BusNR);
|
||||
void i2c_bstop (uint8 BusNR);
|
||||
uint8 i2c_readbyte(uint8 BusNR, bool Ack);
|
||||
bool i2c_writebyte (uint8 BusNR, uint8 byte);
|
||||
void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size);
|
||||
void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size);
|
||||
status_t i2c_init(void);
|
||||
|
||||
/* card info functions */
|
||||
status_t parse_pins(void);
|
||||
void set_pll(uint32 reg, uint32 clk);
|
||||
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);
|
||||
|
||||
/* Brooktree TV functions */
|
||||
bool BT_probe(void);
|
||||
uint8 BT_dpms(bool display);
|
||||
uint8 BT_check_tvmode(display_mode target);
|
||||
status_t BT_stop_tvout(void);
|
||||
status_t BT_setmode(display_mode target);
|
||||
|
||||
/* CRTC1 functions */
|
||||
status_t nv_crtc_interrupt_enable(bool);
|
||||
status_t nv_crtc_update_fifo(void);
|
||||
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, bool);
|
||||
status_t nv_crtc_mem_priority(uint8);
|
||||
status_t nv_crtc_cursor_init(void);
|
||||
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);
|
||||
status_t nv_crtc_stop_tvout(void);
|
||||
status_t nv_crtc_start_tvout(void);
|
||||
|
||||
/* CRTC2 functions */
|
||||
status_t nv_crtc2_interrupt_enable(bool);
|
||||
status_t nv_crtc2_update_fifo(void);
|
||||
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, 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);
|
||||
status_t nv_crtc2_stop_tvout(void);
|
||||
status_t nv_crtc2_start_tvout(void);
|
||||
|
||||
/* acceleration functions */
|
||||
status_t check_acc_capability(uint32 feature);
|
||||
status_t nv_acc_init(void);
|
||||
void nv_acc_assert_fifo(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);
|
||||
/* DMA versions */
|
||||
status_t nv_acc_wait_idle_dma(void);
|
||||
status_t nv_acc_init_dma(void);
|
||||
void nv_acc_assert_fifo_dma(void);
|
||||
void SCREEN_TO_SCREEN_BLIT_DMA(engine_token *et, blit_params *list, uint32 count);
|
||||
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT_DMA(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count);
|
||||
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT_DMA(engine_token *et, scaled_blit_params *list, uint32 count);
|
||||
void FILL_RECTANGLE_DMA(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||
void INVERT_RECTANGLE_DMA(engine_token *et, fill_rect_params *list, uint32 count);
|
||||
void FILL_SPAN_DMA(engine_token *et, uint32 color, uint16 *list, uint32 count);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* driver structures and enums */
|
||||
enum{BPP8 = 0, BPP15 = 1, BPP16 = 2, BPP24 = 3, BPP32 = 4};
|
||||
@@ -0,0 +1,10 @@
|
||||
#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"
|
||||
#include "nv_acc.h"
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Some commmon support functions */
|
||||
/* Mark Watson 2/2000;
|
||||
* Rudolf Cornelissen 1/2004-11/2005 */
|
||||
|
||||
#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;
|
||||
|
||||
/* determine the logfile name:
|
||||
* we need split-up logging per card and instance of the accelerant */
|
||||
sprintf (fname, "/boot/home/" DRIVER_PREFIX "." DEVICE_FORMAT ".%d.log",
|
||||
si->vendor_id, si->device_id, si->bus, si->device, si->function,
|
||||
accelerantIsClone);
|
||||
myhand=fopen(fname,"a+");
|
||||
|
||||
if (myhand == NULL) return;
|
||||
|
||||
va_start(args,fmt);
|
||||
vsprintf (buffer, fmt, args);
|
||||
fprintf(myhand, "%s", buffer);
|
||||
fclose(myhand);
|
||||
}
|
||||
@@ -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