initial import of skeleton graphics accelerant (not yet working/stripped)

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9783 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Rudolf Cornelissen
2004-11-04 12:30:26 +00:00
parent a2fab5626d
commit 6835336864
32 changed files with 14097 additions and 0 deletions
@@ -0,0 +1,140 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Rudolf Cornelissen 9/2003.
*/
#define MODULE_BIT 0x40000000
#include "acc_std.h"
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
int i;
/* init acc engine for blit function */
nv_acc_setup_blit();
/* do each blit */
i=0;
while (count--)
{
nv_acc_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height
);
i++;
}
}
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
int i;
/* do each blit */
i=0;
while (count--)
{
nv_acc_video_blit
(
list[i].src_left,
list[i].src_top,
list[i].src_width,
list[i].src_height,
list[i].dest_left,
list[i].dest_top,
list[i].dest_width,
list[i].dest_height
);
i++;
}
}
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) {
int i;
/* do each blit */
i=0;
while (count--)
{
nv_acc_transparent_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height,
transparent_colour
);
i++;
}
}
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) {
int i;
/* init acc engine for fill function */
nv_acc_setup_rectangle(colorIndex);
/* draw each rectangle */
i=0;
while (count--)
{
nv_acc_rectangle
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1
);
i++;
}
}
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
int i;
/* init acc engine for invert function */
nv_acc_setup_rect_invert();
/* invert each rectangle */
i=0;
while (count--)
{
nv_acc_rectangle_invert
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1
);
i++;
}
}
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
int i;
/* init acc engine for fill function */
nv_acc_setup_rectangle(colorIndex);
/* draw each span */
i=0;
while (count--)
{
nv_acc_rectangle
(
list[i+1],
list[i+2]+1,
list[i],
1
);
i+=3;
}
}
+195
View File
@@ -0,0 +1,195 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 4/2003-5/2004
*/
#define MODULE_BIT 0x20000000
#include "acc_std.h"
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask)
{
LOG(4,("SET_CURSOR_SHAPE: width %d, height %d, hot_x %d, hot_y %d\n",
width, height, hot_x, hot_y));
if ((width != 16) || (height != 16))
{
return B_ERROR;
}
else if ((hot_x >= width) || (hot_y >= height))
{
return B_ERROR;
}
else
{
head1_cursor_define(andMask,xorMask);
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_OFF)
head2_cursor_define(andMask,xorMask);
/* Update cursor variables appropriately. */
si->cursor.width = width;
si->cursor.height = height;
si->cursor.hot_x = hot_x;
si->cursor.hot_y = hot_y;
}
return B_OK;
}
/* Move the cursor to the specified position on the desktop, taking account of virtual/dual issues */
void MOVE_CURSOR(uint16 x, uint16 y)
{
uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */
uint16 vds = si->dm.v_display_start; /* the current vertical starting line */
uint16 h_adjust;
/* clamp cursor to display */
if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1;
if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1;
/* store, for our info */
si->cursor.x = x;
si->cursor.y = y;
/* setting up minimum amount to scroll not needed:
* Nvidia cards can always do pixelprecise panning on both heads */
h_adjust = 0x00;
/* adjust h/v_display_start to move cursor onto screen */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (x >= ((si->dm.timing.h_display * 2) + hds))
{
hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
default:
if (x >= (si->dm.timing.h_display + hds))
{
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + si->dm.timing.h_display) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
}
if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1;
else if (y < vds)
vds = y;
/* reposition the desktop _and_ the overlay on the display if required */
if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
{
MOVE_DISPLAY(hds,vds);
nv_bes_move_overlay();
}
/* put cursor in correct physical position, so stay onscreen (rel. to CRTC) */
if (x > (hds + si->cursor.hot_x)) x -= (hds + si->cursor.hot_x);
else x = 0;
if (y > (vds + si->cursor.hot_y)) y -= (vds + si->cursor.hot_y);
else y = 0;
/* position the cursor on the display */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_CLONE:
head1_cursor_position(x,y);
head2_cursor_position(x,y);
break;
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (x < si->dm.timing.h_display)
{
if (si->cursor.dh_right)
{
LOG(4,("MOVE_CURSOR: now on left side\n"));
head2_cursor_hide();
head1_cursor_show();
si->cursor.dh_right = false;
}
head1_cursor_position(x, y);
}
else
{
if (!si->cursor.dh_right)
{
LOG(4,("MOVE_CURSOR: now on right side\n"));
head1_cursor_hide();
head2_cursor_show();
si->cursor.dh_right = true;
}
head2_cursor_position((x - si->dm.timing.h_display), y);
}
break;
default: /* singlehead mode */
head1_cursor_position(x,y);
break;
}
}
void SHOW_CURSOR(bool is_visible)
{
/* record for our info */
si->cursor.is_visible = is_visible;
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_CLONE:
if (is_visible)
{
head1_cursor_show();
head2_cursor_show();
}
else
{
head1_cursor_hide();
head2_cursor_hide();
}
break;
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (is_visible)
{
if (!si->cursor.dh_right)
{
head1_cursor_show();
}
else
{
head2_cursor_show();
}
}
else
{
head1_cursor_hide();
head2_cursor_hide();
}
break;
default: /* singlehead mode */
if (is_visible)
{
head1_cursor_show();
}
else
{
head1_cursor_hide();
}
break;
}
}
@@ -0,0 +1,70 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
other authors:
Mark Watson
Rudolf Cornelissen 3/2004
*/
#define MODULE_BIT 0x10000000
#include "acc_std.h"
static engine_token nv_engine_token = { 1, B_2D_ACCELERATION, NULL };
uint32 ACCELERANT_ENGINE_COUNT(void)
{
/* we have one acceleration engine */
return 1;
}
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et)
{
/* acquire the shared benaphore */
AQUIRE_BEN(si->engine.lock)
/* sync if required */
if (st) SYNC_TO_TOKEN(st);
/* return an engine token */
*et = &nv_engine_token;
return B_OK;
}
status_t RELEASE_ENGINE(engine_token *et, sync_token *st)
{
/* update the sync token, if any */
if (st) GET_SYNC_TOKEN(et,st);
/* release the shared benaphore */
RELEASE_BEN(si->engine.lock)
return B_OK;
}
void WAIT_ENGINE_IDLE(void)
{
/*wait for the engine to be totally idle*/
nv_acc_wait_idle();
}
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st)
{
/* engine count will always be zero: we don't support syncing to token (yet) */
st->engine_id = et->engine_id;
st->counter = si->engine.count;
return B_OK;
}
status_t SYNC_TO_TOKEN(sync_token *st)
{
/* wait until the engine is totally idle: we don't support syncing to token (yet) */
/* note:
* AFAIK in order to be able to setup sync_to_token, we'd need a circular fifo
* buffer in (main) memory instead of directly programming the GPU fifo so we
* can tell (via a hardware maintained pointer into this circular fifo) where
* the acc engine is with executing commands! */
WAIT_ENGINE_IDLE();
return B_OK;
}
@@ -0,0 +1,221 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002-4/2004
*/
#define MODULE_BIT 0x08000000
#include "acc_std.h"
/*
The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper
function. The extra information (which is specific to the feature) is
pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be
noted on a case by case below.
*/
/*
These definitions are out of pure lazyness.
*/
#define CHKO(x) case B_##x: \
if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define CHKA(x) case B_##x: \
if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed
void * get_accelerant_hook(uint32 feature, void *data)
{
switch (feature)
{
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
/* initialization */
HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT);
HOOK(ACCELERANT_CLONE_INFO_SIZE);
HOOK(GET_ACCELERANT_CLONE_INFO);
HOOK(UNINIT_ACCELERANT);
HOOK(GET_ACCELERANT_DEVICE_INFO);
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
/* mode configuration */
HOOK(ACCELERANT_MODE_COUNT);
HOOK(GET_MODE_LIST);
HOOK(PROPOSE_DISPLAY_MODE);
HOOK(SET_DISPLAY_MODE);
HOOK(GET_DISPLAY_MODE);
HOOK(GET_FRAME_BUFFER_CONFIG);
HOOK(GET_PIXEL_CLOCK_LIMITS);
HOOK(MOVE_DISPLAY);
HOOK(SET_INDEXED_COLORS);
HOOK(GET_TIMING_CONSTRAINTS);
HOOK(DPMS_CAPABILITIES);
HOOK(DPMS_MODE);
HOOK(SET_DPMS_MODE);
/* cursor managment */
HRDC(SET_CURSOR_SHAPE);
HRDC(MOVE_CURSOR);
HRDC(SHOW_CURSOR);
/* synchronization */
HOOK(ACCELERANT_ENGINE_COUNT);
HOOK(ACQUIRE_ENGINE);
HOOK(RELEASE_ENGINE);
HOOK(WAIT_ENGINE_IDLE);
HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_TOKEN);
/*
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth for example.
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export video overlay functions if card is capable of it */
CHKO(OVERLAY_COUNT);
CHKO(OVERLAY_SUPPORTED_SPACES);
CHKO(OVERLAY_SUPPORTED_FEATURES);
CHKO(ALLOCATE_OVERLAY_BUFFER);
CHKO(RELEASE_OVERLAY_BUFFER);
CHKO(GET_OVERLAY_CONSTRAINTS);
CHKO(ALLOCATE_OVERLAY);
CHKO(RELEASE_OVERLAY);
CHKO(CONFIGURE_OVERLAY);
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export 2D acceleration functions in modes that are capable of it */
/* used by the app_server and applications (BWindowScreen) */
CHKA(SCREEN_TO_SCREEN_BLIT);
CHKA(FILL_RECTANGLE);
CHKA(INVERT_RECTANGLE);
CHKA(FILL_SPAN);
/* not (yet) used by the app_server:
* so just for application use (BWindowScreen) */
// CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);
// CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
}
/* Return a null pointer for any feature we don't understand. */
return 0;
}
#undef CHKO
#undef CHKA
#undef HOOK
#undef ZERO
#undef HRDC
status_t check_overlay_capability(uint32 feature)
{
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_OVERLAY_COUNT:
msg = "B_OVERLAY_COUNT";
break;
case B_OVERLAY_SUPPORTED_SPACES:
msg = "B_OVERLAY_SUPPORTED_SPACES";
break;
case B_OVERLAY_SUPPORTED_FEATURES:
msg = "B_OVERLAY_SUPPORTED_FEATURES";
break;
case B_ALLOCATE_OVERLAY_BUFFER:
msg = "B_ALLOCATE_OVERLAY_BUFFER";
break;
case B_RELEASE_OVERLAY_BUFFER:
msg = "B_RELEASE_OVERLAY_BUFFER";
break;
case B_GET_OVERLAY_CONSTRAINTS:
msg = "B_GET_OVERLAY_CONSTRAINTS";
break;
case B_ALLOCATE_OVERLAY:
msg = "B_ALLOCATE_OVERLAY";
break;
case B_RELEASE_OVERLAY:
msg = "B_RELEASE_OVERLAY";
break;
case B_CONFIGURE_OVERLAY:
msg = "B_CONFIGURE_OVERLAY";
break;
default:
msg = "UNKNOWN";
break;
}
/* all supported cards have a bes */
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
return B_OK;
}
status_t check_acc_capability(uint32 feature)
{
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_SCREEN_TO_SCREEN_BLIT:
msg = "B_SCREEN_TO_SCREEN_BLIT";
break;
case B_FILL_RECTANGLE:
msg = "B_FILL_RECTANGLE";
break;
case B_INVERT_RECTANGLE:
msg = "B_INVERT_RECTANGLE";
break;
case B_FILL_SPAN:
msg = "B_FILL_SPAN";
break;
case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT:
msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT";
break;
case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT:
msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT";
break;
default:
msg = "UNKNOWN";
break;
}
/* hardware acceleration is only supported in modes with upto a certain
* memory pitch.. */
if (si->acc_mode)
{
LOG(4, ("Acc: Exporting hook %s.\n", msg));
return B_OK;
}
else
{
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
return B_ERROR;
}
}
@@ -0,0 +1,99 @@
/*
Author:
Rudolf Cornelissen 7/2004-11/2004
*/
#define MODULE_BIT 0x04000000
#include "acc_std.h"
/* Get some info about the device */
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi)
{
LOG(4,("GET_ACCELERANT_DEVICE_INFO: returning info\n"));
/* no info on version is provided, so presumably this is for my info */
adi->version = 1;
sprintf(adi->name, "nVidia chipset");
switch (si->ps.card_type)
{
case NV04:
sprintf(adi->chipset, "NV04");
break;
case NV05:
sprintf(adi->chipset, "NV05");
break;
case NV05M64:
sprintf(adi->chipset, "NV05 model 64");
break;
case NV06:
sprintf(adi->chipset, "NV06");
break;
case NV10:
sprintf(adi->chipset, "NV10");
break;
case NV11:
case NV11M:
sprintf(adi->chipset, "NV11");
break;
case NV15:
sprintf(adi->chipset, "NV15");
break;
case NV17:
case NV17M:
sprintf(adi->chipset, "NV17");
break;
case NV18:
case NV18M:
sprintf(adi->chipset, "NV18");
break;
case NV20:
sprintf(adi->chipset, "NV20");
break;
case NV25:
sprintf(adi->chipset, "NV25");
break;
case NV28:
sprintf(adi->chipset, "NV28");
break;
case NV30:
sprintf(adi->chipset, "NV30");
break;
case NV31:
sprintf(adi->chipset, "NV31");
break;
case NV34:
sprintf(adi->chipset, "NV34");
break;
case NV35:
sprintf(adi->chipset, "NV35");
break;
case NV36:
sprintf(adi->chipset, "NV36");
break;
case NV38:
sprintf(adi->chipset, "NV38");
break;
case NV40:
sprintf(adi->chipset, "NV40");
break;
case NV41:
sprintf(adi->chipset, "NV41");
break;
case NV43:
sprintf(adi->chipset, "NV43");
break;
case NV45:
sprintf(adi->chipset, "NV45");
break;
default:
sprintf(adi->chipset, "unknown");
break;
}
sprintf(adi->serial_no, "unknown");
adi->memory = si->ps.memory_size;
adi->dac_speed = si->ps.max_dac1_clock;
return B_OK;
}
@@ -0,0 +1,160 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
Rudolf Cornelissen 9/2002-5/2003
*/
#define MODULE_BIT 0x02000000
#include "acc_std.h"
/*
Return the current display mode. The only time you might return an
error is if a mode hasn't been set. Or if the system hands you a NULL pointer.
*/
status_t GET_DISPLAY_MODE(display_mode *current_mode)
{
/* check for NULL pointer */
if (current_mode == NULL) return B_ERROR;
*current_mode = si->dm;
return B_OK;
}
/* Return the frame buffer configuration information. */
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb)
{
/* check for NULL pointer */
if (afb == NULL) return B_ERROR;
*afb = si->fbc;
return B_OK;
}
/* Return the maximum and minium pixelclock limits for the specified mode. */
/* NOTE:
* Due to BeOS constraints output for all heads will be limited to the head with
* the least capabilities. */
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
{
uint32 max_pclk = 0;
uint32 min_pclk = 0;
/* check for NULL pointers */
if ((dm == NULL) || (low == NULL) || (high == NULL)) return B_ERROR;
/* specify requested info */
if (dm->flags & DUALHEAD_BITS)
{
/* dualhead mode */
/* find min. value */
switch (si->ps.card_type)
{
default:
*low = ((si->ps.min_video_vco * 1000) / 16);
break;
}
/* find max. value:
* using decondary DAC specs because they could be narrower (twinview) */
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
/* specially noted because of RAM speed constraints! */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
}
/* return values in kHz */
*high = max_pclk * 1000;
}
else
{
/* singlehead mode */
/* find min. value */
switch (si->ps.card_type)
{
default:
*low = ((si->ps.min_pixel_vco * 1000) / 16);
break;
}
/* find max. value: depends on which head is used as primary head */
if (!si->ps.crtc2_prim)
{
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
}
else
{
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
}
/* return values in kHz */
*high = max_pclk * 1000;
}
/* clamp lower limit to 48Hz vertical refresh for now.
* Apparantly the BeOS screenprefs app does limit the upper refreshrate to 90Hz,
* while it does not limit the lower refreshrate. */
min_pclk = ((uint32)dm->timing.h_total * (uint32)dm->timing.v_total * 48) / 1000;
if (min_pclk > *low) *low = min_pclk;
return B_OK;
}
/* Return the semaphore id that will be used to signal a vertical sync occured. */
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
{
return si->vblank;
}
@@ -0,0 +1,33 @@
/*
Author:
Rudolf Cornelissen 7/2004
*/
#define MODULE_BIT 0x01000000
#include "acc_std.h"
/* Used to help generate mode lines */
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc)
{
LOG(4, ("GET_TIMING_CONSTRAINTS: returning info\n"));
/* specs are identical for all nVidia cards */
dtc->h_res = 8;
dtc->h_sync_min = 8;
dtc->h_sync_max = 248;
/* Note:
* h_blank info is used to determine the max. diff. between h_total and h_display! */
dtc->h_blank_min = 8;
dtc->h_blank_max = 1016;
dtc->v_res = 1;
dtc->v_sync_min = 1;
dtc->v_sync_max = 15;
/* Note:
* v_blank info is used to determine the max. diff. between v_total and v_display! */
dtc->v_blank_min = 1;
dtc->v_blank_max = 255;
return B_OK;
}
@@ -0,0 +1,324 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002-7/2004.
*/
#define MODULE_BIT 0x00800000
#include <string.h>
#include <unistd.h>
#include "acc_std.h"
static status_t init_common(int the_fd);
/* Initialization code shared between primary and cloned accelerants */
static status_t init_common(int the_fd) {
status_t result;
nv_get_private_data gpd;
// LOG not available from here to next LOG: NULL si
/* memorize the file descriptor */
fd = the_fd;
/* set the magic number so the driver knows we're for real */
gpd.magic = NV_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, NV_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK) goto error0;
/* clone the shared area for our use */
shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
if (shared_info_area < 0) {
result = shared_info_area;
goto error0;
}
// LOG is now available, si !NULL
LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, switchhead %d, force_pci %d\n",
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead, si->settings.force_pci));
LOG(4,("init_common: dumprom %d, unhide_fw %d, pgm_panel %d\n",
si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel));
/*Check for R4.5.0 and if it is running, use work around*/
{
if (si->use_clone_bugfix)
{
/*check for R4.5.0 bug and attempt to work around*/
LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
regs = si->clone_bugfix_regs;
}
else
{
/* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/
regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&regs, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, si->regs_area);
if (regs_area < 0) {
result = regs_area;
goto error1;
}
}
}
/*FIXME - print dma addresses*/
//LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area));
/* all done */
goto error0;
error1:
delete_area(shared_info_area);
error0:
return result;
}
/* Clean up code shared between primary and cloned accelrants */
static void uninit_common(void) {
/* release the memory mapped registers */
delete_area(regs_area);
/* a little cheap paranoia */
regs = 0;
/* release our copy of the shared info from the kernel driver */
delete_area(shared_info_area);
/* more cheap paranoia */
si = 0;
}
/*
Initialize the accelerant. the_fd is the file handle of the device (in
/dev/graphics) that has been opened by the app_server (or some test harness).
We need to determine if the kernel driver and the accelerant are compatible.
If they are, get the accelerant ready to handle other hook functions and
report success or failure.
*/
status_t INIT_ACCELERANT(int the_fd) {
status_t result;
int pointer_reservation; //mem reserved for pointer
int cnt; //used for iteration through the overlay buffers
if (0) {
time_t now = time (NULL);
// LOG not available from here to next LOG: NULL si
MSG(("INIT_ACCELERANT: %s", ctime (&now)));
}
/* note that we're the primary accelerant (accelerantIsClone is global) */
accelerantIsClone = 0;
/* do the initialization common to both the primary and the clones */
result = init_common(the_fd);
/* bail out if the common initialization failed */
if (result != B_OK) goto error0;
// LOG now available: !NULL si
/* call the device specific init code */
result = nv_general_powerup();
/* bail out if it failed */
if (result != B_OK) goto error1;
/*
Now would be a good time to figure out what video modes your card supports.
We'll place the list of modes in another shared area so all of the copies
of the driver can see them. The primary copy of the accelerant (ie the one
initialized with this routine) will own the "one true copy" of the list.
Everybody else get's a read-only clone.
*/
result = create_mode_list();
if (result != B_OK)
{
goto error1;
}
/*
Put the cursor at the start of the frame buffer.
Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM.
*/
/* Initialize the rest of the cursor information while we're here */
si->cursor.width = 16;
si->cursor.height = 16;
si->cursor.hot_x = 0;
si->cursor.hot_y = 0;
si->cursor.x = 0;
si->cursor.y = 0;
si->cursor.dh_right = false;
/*
Put the frame buffer immediately following the cursor data. We store this
info in a frame_buffer_config structure to make it convienient to return
to the app_server later.
*/
pointer_reservation = 0;
/* Nvidia hardcursor needs 2kB space */
if (si->settings.hardcursor) pointer_reservation = 2048;
si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
/* count of issued parameters or commands */
si->engine.last_idle = si->engine.count = 0;
INIT_BEN(si->engine.lock);
INIT_BEN(si->overlay.lock);
for (cnt = 0; cnt < MAXBUFFERS; cnt++)
{
/* make sure overlay buffers are 'marked' as being free */
si->overlay.myBuffer[cnt].buffer = NULL;
si->overlay.myBuffer[cnt].buffer_dma = NULL;
}
/* make sure overlay unit is 'marked' as being free */
si->overlay.myToken = NULL;
/* note that overlay is not in use (for nv_bes_move_overlay()) */
si->overlay.active = false;
/* bail out if something failed */
if (result != B_OK) goto error1;
/* initialise various cursor stuff */
head1_cursor_init();
if (si->ps.secondary_head) head2_cursor_init();
/* ensure cursor state */
head1_cursor_hide();
if (si->ps.secondary_head) head2_cursor_hide();
/* a winner! */
result = B_OK;
goto error0;
error1:
/*
Initialization failed after init_common() succeeded, so we need to clean
up before quiting.
*/
uninit_common();
error0:
return result;
}
/*
Return the number of bytes required to hold the information required
to clone the device.
*/
ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
/*
Since we're passing the name of the device as the only required
info, return the size of the name buffer
*/
return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH;
}
/*
Return the info required to clone the device. void *data points to
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
*/
void GET_ACCELERANT_CLONE_INFO(void *data) {
nv_device_name dn;
status_t result;
/* call the kernel driver to get the device name */
dn.magic = NV_PRIVATE_DATA_MAGIC;
/* store the returned info directly into the passed buffer */
dn.name = (char *)data;
result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn));
}
/*
Initialize a copy of the accelerant as a clone. void *data points to
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
*/
status_t CLONE_ACCELERANT(void *data) {
status_t result;
char path[MAXPATHLEN];
/* the data is the device name */
/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
strcpy(path, "/dev/");
strcat(path, (const char *)data);
/* open the device, the permissions aren't important */
fd = open(path, B_READ_WRITE);
if (fd < 0)
{
/* we can't use LOG because we didn't get the shared_info struct.. */
char fname[64];
FILE *myhand = NULL;
sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
myhand=fopen(fname,"a+");
fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
fclose(myhand);
/* abort with resultcode from open attempt on kerneldriver */
result = fd;
goto error0;
}
/* note that we're a clone accelerant */
accelerantIsClone = 1;
/* call the shared initialization code */
result = init_common(fd);
/* setup CRTC and DAC functions access */
setup_virtualized_heads(si->crtc_switch_mode);
/* bail out if the common initialization failed */
if (result != B_OK) goto error1;
/* get shared area for display modes */
result = my_mode_list_area = clone_area(
DRIVER_PREFIX " cloned display_modes",
(void **)&my_mode_list,
B_ANY_ADDRESS,
B_READ_AREA,
si->mode_area
);
if (result < B_OK) goto error2;
/* all done */
LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
result = B_OK;
goto error0;
error2:
/* free up the areas we cloned */
uninit_common();
error1:
/* close the device we opened */
close(fd);
error0:
return result;
}
void UNINIT_ACCELERANT(void)
{
if (accelerantIsClone)
{
LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
}
else
{
LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
/* delete benaphores ONLY if we are the primary accelerant */
DELETE_BEN(si->engine.lock);
DELETE_BEN(si->overlay.lock);
}
/* free our mode list area */
delete_area(my_mode_list_area);
/* paranoia */
my_mode_list = 0;
/* release our cloned data */
uninit_common();
/* close the file handle ONLY if we're the clone */
if (accelerantIsClone) close(fd);
}
+29
View File
@@ -0,0 +1,29 @@
SubDir OBOS_TOP src add-ons accelerants skeleton ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics skeleton ] ;
UseHeaders [ FDirName $(SUBDIR) engine ] ;
Addon skel.accelerant : accelerants :
Acceleration.c
Cursor.c
EngineManagment.c
GetAccelerantHook.c
GetDeviceInfo.c
GetModeInfo.c
GetTimingConstraints.c
InitAccelerant.c
Overlay.c
ProposeDisplayMode.c
SetDisplayMode.c
: false : libnvidia_engine.a
;
Package haiku-skeleton-cvs :
skel.accelerant :
boot home config add-ons accelerants ;
Depends skel.accelerant : skel.driver ;
SubInclude OBOS_TOP src add-ons accelerants skeleton engine ;
+612
View File
@@ -0,0 +1,612 @@
/* Written by Rudolf Cornelissen 05/2002-9/2004 */
/* Note on 'missing features' in BeOS 5.0.3 and DANO:
* BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
* of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?)
*/
#define MODULE_BIT 0x00000400
#include "acc_std.h"
/* define the supported overlay input colorspaces */
/* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
* definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
uint32 OVERLAY_COUNT(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: count called\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
}
/* apparantly overlay count should report the number of 'overlay units' on the card */
return 1;
}
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: supported_spaces called.\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
return NULL;
}
/* assuming interlaced VGA is not supported */
if (dm->timing.flags && B_TIMING_INTERLACED)
{
return NULL;
}
/* return a B_NO_COLOR_SPACE terminated list */
return &overlay_colorspaces[0];
}
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported!
{
LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
/* check what features are supported for the current overlaybitmap colorspace */
switch (a_color_space)
{
default:
return
( B_OVERLAY_KEYING_USES_ALPHA |
B_OVERLAY_COLOR_KEY |
B_OVERLAY_HORIZONTAL_FILTERING |
B_OVERLAY_VERTICAL_FILTERING );
}
}
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
{
int offset = 0; /* used to determine next buffer to create */
uint32 adress, adress2, temp32; /* used to calculate buffer adresses */
uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */
int cnt; /* loopcounter */
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer)));
LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci)));
LOG(4,("Overlay: cardRAM_size = %3.3fMb\n",(si->ps.memory_size / (1024.0 * 1024.0))));
/* find first empty slot (room for another buffer?) */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == NULL) break;
}
LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset));
if (offset < MAXBUFFERS)
/* setup new scaler input buffer */
{
switch (cs)
{
case B_YCbCr422:
if (si->ps.card_arch < NV10A)
{
/* check if slopspace is needed: RIVA128 and TNT need ~0x000f. */
si->overlay.myBuffer[offset].width = ((width + 0x000f) & ~0x000f);
}
else
{
/* check if slopspace is needed: GeForce need ~0x001f. */
/* fixme:
* update needed for GF DVDmax support to adhere to CRTC2 constraints?? */
si->overlay.myBuffer[offset].width = ((width + 0x001f) & ~0x001f);
}
si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
/* check if the requested horizontal pitch is supported: */
//fixme: tune for GF and TNT...
if (si->overlay.myBuffer[offset].width > 4088)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
default:
/* unsupported colorspace! */
LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
break;
}
/* check if the requested buffer width is supported */
if (si->overlay.myBuffer[offset].width > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* check if the requested buffer height is supported */
if (height > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
si->overlay.myBuffer[offset].space = cs;
si->overlay.myBuffer[offset].height = height;
/* we define the overlay buffers to reside 'in the back' of the cards RAM */
/* NOTE to app programmers:
* Beware that an app using overlay needs to track workspace switches and screenprefs
* changes. If such an action is detected, the app needs to reset it's pointers to the
* newly created overlay bitmaps, which will be assigned by BeOS automatically after such
* an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
*
* It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
* than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
* This means that the app should also check for NULL pointers returned by the bitmaps,
* and if this happens, it needs to fallback to single buffered overlay or even fallback to
* bitmap output for the new situation. */
/* Another NOTE for app programmers:
* A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
* cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
* This *greatly* simplifies tracking such errors!
* Of course such errors may lead to strange effects in the app or driver behaviour if they are
* not hunted down and removed.. */
/* calculate first free RAM adress in card:
* Driver setup is as follows:
* card base: - hardware cursor bitmap (if used),
* directly above - screen memory for both heads */
adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */
(si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */
LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
/* calculate 'preliminary' buffer size including slopspace */
oldsize = si->overlay.myBufInfo[offset].size;
si->overlay.myBufInfo[offset].size =
si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
/* calculate virtual memory adress that would be needed for a new bitmap */
/* NOTE to app programmers:
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file nv.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uint32)((uint8*)si->framebuffer)) + si->ps.memory_size);
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
* 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
/* Check if we need to modify the buffers starting adress and thus the size */
/* calculate 'would be' cardRAM offset */
temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer)));
/* check if it is aligned */
if (temp32 != (temp32 & 0xfffffff0))
{
/* update the (already calculated) buffersize to get it aligned */
si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
/* update the (already calculated) adress to get it aligned */
adress -= (temp32 - (temp32 & 0xfffffff0));
}
LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
/* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
* this is done to prevent a large buffer getting created in the space a small buffer
* occupied earlier, if not all buffers created were deleted.
* Note also that the app can delete the buffers in any order desired. */
/* NOTE to app programmers:
* If you are going to delete a overlay buffer you created, you should delete them *all* and
* then re-create only the new ones needed. This way you are sure not to get unused memory-
* space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
* If you don't, you might not get a buffer at all if you are trying to set up a larger one
* than before.
* (Indeed: not all buffers *have* to be of the same type and size...) */
for (cnt = offset; cnt < MAXBUFFERS; cnt++)
{
if (si->overlay.myBuffer[cnt].buffer != NULL)
{
/* Check if the new buffer would fit into the space the single old one used here */
if (si->overlay.myBufInfo[offset].size <= oldsize)
{
/* It does, so we reset to the old size and adresses to prevent the space from shrinking
* if we get here again... */
adress -= (oldsize - si->overlay.myBufInfo[offset].size);
si->overlay.myBufInfo[offset].size = oldsize;
LOG(4,("Overlay: 'squeezing' in buffer:\n"
"Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
/* force exiting the FOR loop */
cnt = MAXBUFFERS;
}
else
{
/* nogo, sorry */
LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
"Overlay: not enough space to 'squeeze' this one in, aborted\n"));
/* Reset to the old size to prevent the space from 'growing' if we get here again... */
si->overlay.myBufInfo[offset].size = oldsize;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
}
/* check if we have enough space to setup this new bitmap
* (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
if (adress < adress2)
/* nope, sorry */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* continue buffer setup */
si->overlay.myBuffer[offset].buffer = (void *) adress;
/* calculate physical memory adress (for dma use) */
adress = (((uint32)((uint8*)si->framebuffer_pci)) + si->ps.memory_size);
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n",
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer),
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs));
LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return &si->overlay.myBuffer[offset];
}
else
/* sorry, no more room for buffers */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
/* Note that the user can delete the buffers in any order desired! */
{
int offset = 0;
if (ob != NULL)
{
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
/* delete current buffer */
{
si->overlay.myBuffer[offset].buffer = NULL;
si->overlay.myBuffer[offset].buffer_dma = NULL;
LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
return B_ERROR;
}
}
else
/* no buffer specified! */
{
LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
return B_ERROR;
}
}
status_t GET_OVERLAY_CONSTRAINTS
(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
{
int offset = 0;
LOG(4,("Overlay: Get_overlay_constraints called\n"));
/* check for NULL pointers */
if ((dm == NULL) || (ob == NULL) || (oc == NULL))
{
LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
return B_ERROR;
}
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
/* scaler input (values are in pixels) */
oc->view.h_alignment = 0;
oc->view.v_alignment = 0;
switch (ob->space)
{
case B_YCbCr422:
if (si->ps.card_arch < NV10A)
{
/* RIVA128 and TNT need 15.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
oc->view.width_alignment = 15;
}
else
{
/* GeForce need 31.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
oc->view.width_alignment = 31;
}
break;
default:
/* we should not be here, but set the worst-case value just to be safe anyway */
oc->view.width_alignment = 31;
break;
}
oc->view.height_alignment = 0;
oc->view.width.min = 1;
oc->view.height.min = 2; /* two fields */
oc->view.width.max = ob->width;
oc->view.height.max = ob->height;
/* scaler output restrictions */
oc->window.h_alignment = 0;
oc->window.v_alignment = 0;
oc->window.width_alignment = 0;
oc->window.height_alignment = 0;
oc->window.width.min = 2;
/* GeForce cards can output upto and including 2046 pixels in width */
//fixme: how about TNT?
if (dm->virtual_width > 2046)
{
oc->window.width.max = 2046;
}
else
{
oc->window.width.max = dm->virtual_width;
}
oc->window.height.min = 2;
/* GeForce cards can output upto and including 2046 pixels in height */
//fixme: how about TNT?
if (dm->virtual_height > 2046)
{
oc->window.height.max = 2046;
}
else
{
oc->window.height.max = dm->virtual_height;
}
/* GeForce scaling restrictions */
switch (si->ps.card_arch)
{
case NV04A:
/* Riva128-TNT2 series have an old BES engine... */
oc->h_scale.min = 1.0;
oc->v_scale.min = 1.0;
break;
case NV30A:
case NV40A:
/* GeForceFX series and up have a new BES engine... */
oc->h_scale.min = 0.5;
oc->v_scale.min = 0.5;
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
* So let it fall through... */
if (si->ps.card_type != NV31) break;
default:
/* the rest in between... */
oc->h_scale.min = 0.125;
oc->v_scale.min = 0.125;
break;
}
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
oc->h_scale.max = 8.0;
oc->v_scale.max = 8.0;
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
overlay_token ALLOCATE_OVERLAY(void)
{
uint32 tmpToken;
LOG(4,("Overlay: Allocate_overlay called: "));
/* come up with a token */
tmpToken = 0x12345678;
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
/* overlay unit already in use? */
if (si->overlay.myToken == NULL)
/* overlay unit is available */
{
LOG(4,("succesfull\n"));
si->overlay.myToken = &tmpToken;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return si->overlay.myToken;
}
else
/* sorry, overlay unit is occupied */
{
LOG(4,("failed: already in use!\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY(overlay_token ot)
{
LOG(4,("Overlay: Release_overlay called: "));
/* is this call for real? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed, not in use!\n"));
return B_ERROR;
}
else
/* call is for real */
{
nv_release_bes();
LOG(4,("succesfull\n"));
si->overlay.myToken = NULL;
return B_OK;
}
}
status_t CONFIGURE_OVERLAY
(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
{
int offset = 0; /* used for buffer index */
LOG(4,("Overlay: Configure_overlay called: "));
/* Note:
* When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
* release all overlay buffers. The buffer currently displayed at that moment, may need some
* 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
* called one more time then, with a null pointer for overlay_window and overlay_view, while
* the currently displayed overlay_buffer is given.
* The G200-G550 do not need to do anything on such an occasion, so we simply return if we
* get called then. */
if ((ow == NULL) || (ov == NULL))
{
LOG(4,("output properties changed\n"));
return B_OK;
}
/* Note:
* If during overlay use the screen prefs are changed, or the workspace has changed, it
* may be that we were not able to re-allocate the requested overlay buffers (or only partly)
* due to lack of cardRAM. If the app does not respond properly to this, we might end up
* with a NULL pointer instead of a overlay_buffer to work with here.
* Of course, we need to abort then to prevent the system from 'going down'.
* The app will probably crash because it will want to write into this non-existant buffer
* at some point. */
if (ob == NULL)
{
LOG(4,("no overlay buffer specified\n"));
return B_ERROR;
}
/* is this call done by the app that owns us? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed\n"));
return B_ERROR;
}
else
/* call is for real */
{
/* find the buffer's offset */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
LOG(4,("succesfull, switching to buffer %d\n", offset));
/* program overlay hardware */
nv_configure_bes(ob, ow, ov, offset);
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
}
@@ -0,0 +1,597 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors for NV driver:
Mark Watson,
Rudolf Cornelissen 9/2002-10/2004
*/
#define MODULE_BIT 0x00400000
#include "acc_std.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
/* mode flags will be setup as status info by PROPOSEMODE! */
#define MODE_FLAGS 0
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
/*some monitors only handle a fixed set of modes*/
#include "valid_mode_list"
/* Standard VESA modes,
* plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
* panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
static const display_mode mode_list[] = {
/* 4:3 modes; 307.2k pixels */
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
/* 4:3 modes; 480k pixels */
{ { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) from Be, Inc. driver + XFree86 */
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) + XFree86 */
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) + XFree86 */
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) + XFree86 */
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) + XFree86 */
/* 4:3 modes; 786.432k pixels */
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) + XFree86 */
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) + XFree86 */
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) + XFree86 */
/* 4:3 modes; 995.328k pixels */
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) + XFree86 */
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
/* 5:4 modes; 1.311M pixels */
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024) from Be, Inc. driver + XFree86 */
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) + XFree86 */
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) + XFree86 */
/* 4:3 panel mode; 1.47M pixels */
{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
/* 4:3 modes; 1.92M pixels */
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) + XFree86 */
/* identical lines to above one, apart from refreshrate.. */
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) + XFree86 */
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) + XFree86 */
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) + XFree86 */
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) + XFree86 */
/* end identical lines. */
/* 4:3 modes; 2.408M pixels */
{ { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) from Be, Inc. driver + XFree86 */
{ { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) from Be, Inc. driver + XFree86 */
/* 4:3 modes; 2.584M pixels */
{ { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) from Be, Inc. driver + XFree86 */
{ { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) from Be, Inc. driver + XFree86 */
/* 4:3 modes; 2.765M pixels */
{ { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1440) from Be, Inc. driver + XFree86 */
{ { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1920X1440) from Be, Inc. driver + XFree86 */
/* 4:3 modes; 3.146M pixels */
{ { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* From XFree86 posting @60Hz + XFree86 */
/* 16:10 panel mode; 400k pixels */
{ { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X500) */
/* 16:10 panel mode; 655.36k pixels */
{ { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X640) */
/* 16:10 panel-TV mode; 983.04k pixels */
{ { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X768) */
/* 16:10 panel mode; 1.024M pixels */
{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */
/* 16:10 panel mode; 1.296M pixels */
{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
/* 16:10 panel mode; 1.764M pixels */
{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
/* 16:10 panel mode; 2.304M pixels */
{ { 193200, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
};
/*
Check mode is between low and high limits
returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
*/
/* BOUNDS WARNING:
* BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE. It's called by the OS with target, low and high set to
* have the same settings for BWindowScreen!
* Which means we should not return B_BAD_VALUE on anything except for deviations on:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
*/
/* Note:
* The target mode should be modified to correspond to the mode as it can be made. */
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
status_t status = B_OK;
float pix_clock_found, target_aspect;
uint8 m,n,p, bpp;
status_t result;
uint32 max_vclk, row_bytes, pointer_reservation;
bool acc_mode;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
(
(double)target->timing.h_total *
(double)target->timing.v_total
);
bool
want_same_width = target->timing.h_display == target->virtual_width,
want_same_height = target->timing.v_display == target->virtual_height;
LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
target->virtual_width, target->virtual_height));
/*check valid list:
if (VALID_REQUIRED is set)
{
if (find modes with same size)
{
pick one with nearest pixel clock
}
else
{
pick next largest with nearest pixel clock and modify visible portion as far as possible
}
}
*/
#ifdef VALID_MODE_REQUIRED
{
int i;
int closest_mode_ptr;
uint32 closest_mode_clock;
LOG(1, ("PROPOSEMODE: valid mode required!\n"));
closest_mode_ptr = 0xbad;
closest_mode_clock = 0;
for (i=0;i<VALID_MODES;i++)
{
/*check size is ok and clock is better than any found before*/
if(
target->timing.h_display==valid_mode_list[i].h_display &&
target->timing.v_display==valid_mode_list[i].v_display
)
{
if (
abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)<
abs(closest_mode_clock-target->timing.pixel_clock)
)
{
closest_mode_clock=valid_mode_list[i].pixel_clock;
closest_mode_ptr=i;
}
}
}
if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
{
LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
return B_ERROR;
}
else
{
target->timing=valid_mode_list[closest_mode_ptr];
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
((double)target->timing.h_total * (double)target->timing.v_total);
}
}
#endif
/*find a nearby valid timing from that given*/
result = head1_validate_timing
(
&target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
&target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
);
if (result == B_ERROR)
{
LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
return result;
}
/* check if all connected output devices can display the requested mode's aspect: */
/* calculate display mode aspect */
target_aspect = (target->timing.h_display / ((float)target->timing.v_display));
/* NOTE:
* allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
switch (si->ps.monitors)
{
case 0x01: /* digital panel on head 1, nothing on head 2 */
if (si->ps.panel1_aspect < (target_aspect - 0.10))
{
LOG(4, ("PROPOSEMODE: connected panel1 is not widescreen type, aborted.\n"));
return B_ERROR;
}
break;
case 0x10: /* nothing on head 1, digital panel on head 2 */
if (si->ps.panel2_aspect < (target_aspect - 0.10))
{
LOG(4, ("PROPOSEMODE: connected panel2 is not widescreen type, aborted.\n"));
return B_ERROR;
}
break;
case 0x11: /* digital panels on both heads */
if ((si->ps.panel1_aspect < (target_aspect - 0.10)) ||
(si->ps.panel2_aspect < (target_aspect - 0.10)))
{
LOG(4, ("PROPOSEMODE: not all connected panels are widescreen type, aborted.\n"));
return B_ERROR;
}
break;
default: /* at least one analog monitor is connected, or nothing detected at all */
if (target_aspect > 1.34)
{
LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
return B_ERROR;
}
break;
}
/* only export widescreen panel-TV modes when an exact resolution match exists,
* to prevent the modelist from becoming too crowded */
if (target_aspect > 1.61)
{
status_t panel_TV_stat = B_ERROR;
if (si->ps.tmds1_active)
{
if ((target->timing.h_display == si->ps.p1_timing.h_display) &&
(target->timing.v_display == si->ps.p1_timing.v_display))
{
panel_TV_stat = B_OK;
}
}
if (si->ps.tmds2_active)
{
if ((target->timing.h_display == si->ps.p2_timing.h_display) &&
(target->timing.v_display == si->ps.p2_timing.v_display))
{
panel_TV_stat = B_OK;
}
}
if (panel_TV_stat != B_OK)
{
LOG(4, ("PROPOSEMODE: WS panel_TV mode requested but no such TV here, aborted.\n"));
return B_ERROR;
}
}
/* check if panel(s) can display the requested resolution (if connected) */
if (si->ps.tmds1_active)
{
if ((target->timing.h_display > si->ps.p1_timing.h_display) ||
(target->timing.v_display > si->ps.p1_timing.v_display))
{
LOG(4, ("PROPOSEMODE: panel1 can't display requested resolution, aborted.\n"));
return B_ERROR;
}
}
if (si->ps.tmds2_active)
{
if ((target->timing.h_display > si->ps.p2_timing.h_display) ||
(target->timing.v_display > si->ps.p2_timing.v_display))
{
LOG(4, ("PROPOSEMODE: panel2 can't display requested resolution, aborted.\n"));
return B_ERROR;
}
}
/* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
/* nail virtual size and 'subsequently' calculate rowbytes */
result = nv_general_validate_pic_size (target, &row_bytes, &acc_mode);
if (result == B_ERROR)
{
LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
return result;
}
/*check if virtual_width is still within the requested limits*/
if ((target->virtual_width < low->virtual_width) ||
(target->virtual_width > high->virtual_width))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
}
/*check if timing found is within the requested horizontal limits*/
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total))
{
/* BWindowScreen workaround: we accept everything except h_display deviations */
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
}
/*check if timing found is within the requested vertical limits*/
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.v_sync_start) ||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
)
{
/* BWindowScreen workaround: we accept everything except v_display deviations */
if ((target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
}
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
/* calculate settings, but do not actually test anything (that costs too much time!) */
result = head1_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
/* update the target mode */
target->timing.pixel_clock = (pix_clock_found * 1000);
/* note if we fell outside the limits */
if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
(target->timing.pixel_clock > high->timing.pixel_clock)
)
{
/* BWindowScreen workaround: we accept deviations <= 1Mhz */
if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
(target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
}
/* checkout space needed for hardcursor (if any) */
pointer_reservation = 0;
if (si->settings.hardcursor) pointer_reservation = 2048;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) >
(si->ps.memory_size - pointer_reservation))
{
target->virtual_height =
(si->ps.memory_size - pointer_reservation) / row_bytes;
}
if (target->virtual_height < target->timing.v_display)
{
LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
return B_ERROR;
}
LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
target->virtual_width, target->virtual_height));
if ((target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
}
/* setup status flags */
LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
/* preset to singlehead card without TVout, no overlay support and no hardcursor.
* also advice system that app_server and acc engine may touch the framebuffer
* simultaneously (fixed). */
target->flags &=
~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
/* we always allow parallel access (fixed), the DAC is always in 'enhanced'
* mode (fixed), and all modes support DPMS (fixed);
* We support scrolling and panning in every mode, so we 'send a signal' to
* BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
/* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables
* BDirectWindow windowed modes. */
target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
/* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
switch (target->space)
{
case B_CMAP8:
max_vclk = si->ps.max_dac2_clock_8;
bpp = 1;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_vclk = si->ps.max_dac2_clock_16;
bpp = 2;
break;
case B_RGB24_LITTLE:
max_vclk = si->ps.max_dac2_clock_24;
bpp = 3;
break;
case B_RGB32_LITTLE:
max_vclk = si->ps.max_dac2_clock_32dh;
bpp = 4;
break;
default:
/* use fail-safe value */
max_vclk = si->ps.max_dac2_clock_32dh;
bpp = 4;
break;
}
/* set DUALHEAD_CAPABLE if suitable */
//fixme: update for independant secondary head use! (reserve fixed memory then)
if (si->ps.secondary_head && (target->timing.pixel_clock <= (max_vclk * 1000)))
{
switch (target->flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->ps.memory_size - pointer_reservation) >=
(row_bytes * target->virtual_height)) &&
((uint16)(row_bytes / bpp) >= (target->timing.h_display * 2)))
{
target->flags |= DUALHEAD_CAPABLE;
}
break;
case DUALHEAD_CLONE:
if ((si->ps.memory_size - pointer_reservation) >=
(row_bytes * target->virtual_height))
{
target->flags |= DUALHEAD_CAPABLE;
}
break;
case DUALHEAD_OFF:
if ((si->ps.memory_size - pointer_reservation) >=
(row_bytes * target->virtual_height * 2))
{
target->flags |= DUALHEAD_CAPABLE;
}
break;
}
}
/* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
//fixme: modify for G100 and G200 TVout later on...
if (target->flags & DUALHEAD_CAPABLE)
{
if (si->ps.tvout &&
(target->timing.h_display <= 1024) &&
(target->timing.v_display <= 768))
{
target->flags |= TV_CAPABLE;
}
}
/* set HARDWARE_CURSOR mode if suitable */
if (si->settings.hardcursor)
target->flags |= B_HARDWARE_CURSOR;
/* set SUPPORTS_OVERLAYS */
target->flags |= B_SUPPORTS_OVERLAYS;
LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
/* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
* progressive scan (fixed), and sync_on_green not avaible. */
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
/* The HSYNC and VSYNC command flags are actually executed by the driver. */
if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
return status;
}
/* Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff)
*/
uint32 ACCELERANT_MODE_COUNT(void)
{
LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
return si->mode_count;
}
/* Copy the list of guaranteed supported video modes to the location provided.*/
status_t GET_MODE_LIST(display_mode *dm)
{
LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK;
}
/* Create a list of display_modes to pass back to the caller.*/
status_t create_mode_list(void)
{
size_t max_size;
uint32
i, j,
pix_clk_range;
const display_mode
*src;
display_mode
*dst,
low,
high;
color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8};
/* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */
max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
/* create an area to hold the info */
si->mode_area = my_mode_list_area =
create_area("NV accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (my_mode_list_area < B_OK) return my_mode_list_area;
/* walk through our predefined list and see which modes fit this device */
src = mode_list;
dst = my_mode_list;
si->mode_count = 0;
for (i = 0; i < MODE_COUNT; i++)
{
/* set ranges for acceptable values */
low = high = *src;
/* range is 6.25% of default clock: arbitrarily picked */
pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
/* 'some cards need wider virtual widths for certain modes':
* Not true. They might need a wider pitch, but this is _not_ reflected in
* virtual_width, but in fbc.bytes_per_row. */
//So disable next line:
//high.virtual_width = 4096;
/* do it once for each depth we want to support */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
{
/* set target values */
*dst = *src;
/* poke the specific space */
dst->space = low.space = high.space = spaces[j];
/* ask for a compatible mode */
/* We have to check for B_OK, because otherwise the pix_clk_range
* won't be taken into account!! */
//So don't do this:
//if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
//Instead, do this:
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
/* count it, and move on to next mode */
dst++;
si->mode_count++;
}
}
/* advance to next mode */
src++;
}
return B_OK;
}
@@ -0,0 +1,517 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 11/2002-4/2004
*/
#define MODULE_BIT 0x00200000
#include "acc_std.h"
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
*/
static void interrupt_enable(bool flag) {
status_t result;
nv_set_bool_state sbs;
/* set the magic number so the driver knows we're for real */
sbs.magic = NV_PRIVATE_DATA_MAGIC;
sbs.do_it = flag;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
}
/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
/* BOUNDS WARNING:
* It's impossible to deviate whatever small amount in a display_mode if the lower
* and upper limits are the same!
* Besides:
* BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE!
* Which means PROPOSEMODE should not return that on anything except on
* deviations for:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
* So:
* We don't use bounds here by making sure bounds and target are the same struct!
* (See the call to PROPOSE_DISPLAY_MODE below) */
display_mode /*bounds,*/ target;
uint8 colour_depth1 = 32;
status_t result;
uint32 startadd,startadd_right;
bool display, h, v;
// bool crt1, crt2, cross;
/* Adjust mode to valid one and fail if invalid */
target /*= bounds*/ = *mode_to_set;
/* show the mode bits */
LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
target.virtual_width, target.virtual_height));
/* See BOUNDS WARNING above... */
if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
/* if not dualhead capable card clear dualhead flags */
if (!(target.flags & DUALHEAD_CAPABLE))
{
target.flags &= ~DUALHEAD_BITS;
}
/* if not TVout capable card clear TVout flags */
if (!(target.flags & TV_CAPABLE))
{
target.flags &= ~TV_BITS;
}
LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
/* disable interrupts using the kernel driver */
interrupt_enable(false);
/* find current DPMS state, then turn off screen(s) */
head1_dpms_fetch(&display, &h, &v);
head1_dpms(false, false, false);
if (si->ps.secondary_head) head2_dpms(false, false, false);
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
/* calculate and set new mode bytes_per_row */
nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
/*Perform the very long mode switch!*/
if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
{
uint8 colour_depth2 = colour_depth1;
/* init display mode for secondary head */
display_mode target2 = target;
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
/* validate flags for secondary TVout */
if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
{
target.flags &= ~TV_BITS;//still needed for some routines...
target2.flags &= ~TV_BITS;
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
}
/* detect which connectors have a CRT connected */
//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
//or make it work with digital panels connected as well.
// crt1 = nv_dac_crt_connected();
// crt2 = nv_dac2_crt_connected();
/* connect outputs 'straight-through' */
// if (crt1)
// {
/* connector1 is used as primary output */
// cross = false;
// }
// else
// {
// if (crt2)
/* connector2 is used as primary output */
// cross = true;
// else
/* no CRT detected: assume connector1 is used as primary output */
// cross = false;
// }
/* set output connectors assignment if possible */
if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
/* invert output assignment in switch mode */
nv_general_head_select(true);
else
nv_general_head_select(false);
/* set the pixel clock PLL(s) */
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
if (head1_set_pix_pll(target) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
/* we do not need to set the pixelclock here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS))
{
LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
if (head2_set_pix_pll(target2) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
}
/*set the colour depth for CRTC1 and the DAC */
switch(target.space)
{
case B_CMAP8:
colour_depth1 = 8;
head1_mode(BPP8, 1.0);
head1_depth(BPP8);
break;
case B_RGB15_LITTLE:
colour_depth1 = 16;
head1_mode(BPP15, 1.0);
head1_depth(BPP15);
break;
case B_RGB16_LITTLE:
colour_depth1 = 16;
head1_mode(BPP16, 1.0);
head1_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth1 = 32;
head1_mode(BPP32, 1.0);
head1_depth(BPP32);
break;
}
/*set the colour depth for CRTC2 and DAC2 */
switch(target2.space)
{
case B_CMAP8:
colour_depth2 = 8;
head2_mode(BPP8, 1.0);
head2_depth(BPP8);
break;
case B_RGB15_LITTLE:
colour_depth2 = 16;
head2_mode(BPP15, 1.0);
head2_depth(BPP15);
break;
case B_RGB16_LITTLE:
colour_depth2 = 16;
head2_mode(BPP16, 1.0);
head2_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth2 = 32;
head2_mode(BPP32, 1.0);
head2_depth(BPP32);
break;
}
/* check if we are doing interlaced TVout mode */
si->interlaced_tv_mode = false;
/* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
si->interlaced_tv_mode = true;
*/
/*set the display(s) pitches*/
head1_set_display_pitch ();
//fixme: seperate for real dualhead modes:
//we need a secondary si->fbc!
head2_set_display_pitch ();
/*work out where the "right" screen starts*/
startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
/* Tell card what memory to display */
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
head1_set_display_start(startadd,colour_depth1);
head2_set_display_start(startadd_right,colour_depth2);
break;
case DUALHEAD_CLONE:
head1_set_display_start(startadd,colour_depth1);
head2_set_display_start(startadd,colour_depth2);
break;
}
/* set the timing */
head1_set_timing(target);
/* we do not need to setup CRTC2 here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS)) result = head2_set_timing(target2);
/* TVout support: setup CRTC2 and it's pixelclock */
if (si->ps.tvout && (target2.flags & TV_BITS)) maventv_init(target2);
}
else /* single head mode */
{
status_t status;
int colour_mode = BPP32;
/* connect output */
if (si->ps.secondary_head)
{
/* detect which connectors have a CRT connected */
//fixme: 'hot-plugging' for analog monitors removed: remove code as well;
//or make it work with digital panels connected as well.
// crt1 = nv_dac_crt_connected();
// crt2 = nv_dac2_crt_connected();
/* connect outputs 'straight-through' */
// if (crt1)
// {
/* connector1 is used as primary output */
// cross = false;
// }
// else
// {
// if (crt2)
/* connector2 is used as primary output */
// cross = true;
// else
/* no CRT detected: assume connector1 is used as primary output */
// cross = false;
// }
/* set output connectors assignment if possible */
nv_general_head_select(false);
}
switch(target.space)
{
case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
default:
LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
return B_ERROR;
}
/* set the pixel clock PLL */
status = head1_set_pix_pll(target);
if (status==B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
/* set the colour depth for CRTC1 and the DAC */
/* first set the colordepth */
head1_depth(colour_mode);
/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
head1_mode(colour_mode,1.0);
/* set the display pitch */
head1_set_display_pitch();
/* tell the card what memory to display */
head1_set_display_start(startadd,colour_depth1);
/* set the timing */
head1_set_timing(target);
//fixme: shut-off the videoPLL if it exists...
}
/* update driver's mode store */
si->dm = target;
/* turn screen one on */
head1_dpms(display, h, v);
/* turn screen two on if a dualhead mode is active */
if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v);
/* set up acceleration for this mode */
nv_acc_init();
/* set up overlay unit for this mode */
nv_bes_init();
LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
/* enable interrupts using the kernel driver */
interrupt_enable(true);
/* optimize memory-access if needed */
// head1_mem_priority(colour_depth1);
/* Tune RAM CAS-latency if needed. Must be done *here*! */
nv_set_cas_latency();
return B_OK;
}
/*
Set which pixel of the virtual frame buffer will show up in the
top left corner of the display device. Used for page-flipping
games and virtual desktops.
*/
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
uint8 colour_depth;
uint32 startadd,startadd_right;
LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
/* nVidia cards support pixelprecise panning on both heads in all modes:
* No stepping granularity needed! */
/* determine bits used for the colordepth */
switch(si->dm.space)
{
case B_CMAP8:
colour_depth=8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
colour_depth=16;
break;
case B_RGB24_LITTLE:
colour_depth=24;
break;
case B_RGB32_LITTLE:
colour_depth=32;
break;
default:
return B_ERROR;
}
/* do not run past end of display */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
default:
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
}
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR;
/* everybody remember where we parked... */
si->dm.h_display_start = h_display_start;
si->dm.v_display_start = v_display_start;
/* actually set the registers */
//fixme: seperate both heads: we need a secondary si->fbc!
startadd = v_display_start * si->fbc.bytes_per_row;
startadd += h_display_start * (colour_depth >> 3);
startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
interrupt_enable(false);
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
head1_set_display_start(startadd,colour_depth);
head2_set_display_start(startadd_right,colour_depth);
break;
case DUALHEAD_OFF:
head1_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_CLONE:
head1_set_display_start(startadd,colour_depth);
head2_set_display_start(startadd,colour_depth);
break;
}
interrupt_enable(true);
return B_OK;
}
/* Set the indexed color palette */
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
int i;
uint8 *r,*g,*b;
/* Protect gamma correction when not in CMAP8 */
if (si->dm.space != B_CMAP8) return;
r=si->color_data;
g=r+256;
b=g+256;
i=first;
while (count--)
{
r[i]=*color_data++;
g[i]=*color_data++;
b[i]=*color_data++;
i++;
}
head1_palette(r,g,b);
if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
}
/* Put the display into one of the Display Power Management modes. */
status_t SET_DPMS_MODE(uint32 dpms_flags) {
interrupt_enable(false);
LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on, display on */
head1_dpms(true, true, true);
if (si->ps.secondary_head) head2_dpms(true, true, true);
break;
case B_DPMS_STAND_BY:
head1_dpms(false, false, true);
if (si->ps.secondary_head) head2_dpms(false, false, true);
break;
case B_DPMS_SUSPEND:
head1_dpms(false, true, false);
if (si->ps.secondary_head) head2_dpms(false, true, false);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
head1_dpms(false, false, false);
if (si->ps.secondary_head) head2_dpms(false, false, false);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
else /* singlehead */
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on, display on */
head1_dpms(true, true, true);
break;
case B_DPMS_STAND_BY:
head1_dpms(false, false, true);
break;
case B_DPMS_SUSPEND:
head1_dpms(false, true, false);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
head1_dpms(false, false, false);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
interrupt_enable(true);
return B_OK;
}
/* Report device DPMS capabilities */
uint32 DPMS_CAPABILITIES(void) {
return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
}
/* Return the current DPMS mode */
uint32 DPMS_MODE(void) {
bool display, h, v;
interrupt_enable(false);
head1_dpms_fetch(&display, &h, &v);
interrupt_enable(true);
if (display && h && v)
return B_DPMS_ON;
else if(v)
return B_DPMS_STAND_BY;
else if(h)
return B_DPMS_SUSPEND;
else
return B_DPMS_OFF;
}
@@ -0,0 +1,17 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#if !defined(GLOBALDATA_H)
#define GLOBALDATA_H
#include <stdio.h>
#include <sys/ioctl.h>
#include "DriverInterface.h"
#include "nv_globals.h"
//apsed #include "nv_extern.h"
#include "nv_proto.h"
#include "be_driver_proto.h"
#endif
@@ -0,0 +1,68 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#if !defined(GENERIC_H)
#define GENERIC_H
#include <Accelerant.h>
#include "video_overlay.h"
#define DEBUG 1
status_t INIT_ACCELERANT(int fd);
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
void GET_ACCELERANT_CLONE_INFO(void *data);
status_t CLONE_ACCELERANT(void *data);
void UNINIT_ACCELERANT(void);
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
uint32 ACCELERANT_MODE_COUNT(void);
status_t GET_MODE_LIST(display_mode *dm);
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
status_t GET_DISPLAY_MODE(display_mode *current_mode);
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
uint32 DPMS_CAPABILITIES(void);
uint32 DPMS_MODE(void);
status_t SET_DPMS_MODE(uint32 dpms_flags);
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
void MOVE_CURSOR(uint16 x, uint16 y);
void SHOW_CURSOR(bool is_visible);
uint32 ACCELERANT_ENGINE_COUNT(void);
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
void WAIT_ENGINE_IDLE(void);
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
status_t SYNC_TO_TOKEN(sync_token *st);
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count);
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count);
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
/* video_overlay */
uint32 OVERLAY_COUNT(const display_mode *dm);
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm);
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space);
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height);
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob);
status_t GET_OVERLAY_CONSTRAINTS(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc);
overlay_token ALLOCATE_OVERLAY(void);
status_t RELEASE_OVERLAY(overlay_token ot);
status_t CONFIGURE_OVERLAY(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov);
status_t create_mode_list(void);
#endif
@@ -0,0 +1,20 @@
SubDir OBOS_TOP src add-ons accelerants skeleton engine ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics skeleton ] ;
StaticLibrary skeleton_engine :
acc.c
bes.c
brooktreetv.c
crtc.c
crtc2.c
dac.c
dac2.c
general.c
agp.c
globals.c
i2c.c
info.c
support.c
;
@@ -0,0 +1,888 @@
/* NV Acceleration functions */
/* Author:
Rudolf Cornelissen 8/2003-9/2004.
This code was possible thanks to the Linux NV driver.
*/
#define MODULE_BIT 0x00080000
#include "nv_std.h"
/*acceleration notes*/
/*functions Be's app_server uses:
fill span (horizontal only)
fill rectangle (these 2 are very similar)
invert rectangle
blit
*/
status_t nv_acc_wait_idle()
{
/* wait until engine completely idle */
while (ACCR(STATUS))
{
/* snooze a bit so I do not hammer the bus */
snooze (100);
}
return B_OK;
}
/* AFAIK this must be done for every new screenmode.
* Engine required init. */
status_t nv_acc_init()
{
uint16 cnt;
/* setup PTIMER: */
//fixme? how about NV28 setup as just after coldstarting? (see nv_info.c)
/* set timer numerator to 8 (in b0-15) */
ACCW(PT_NUMERATOR, 0x00000008);
/* set timer denominator to 3 (in b0-15) */
ACCW(PT_DENOMINATR, 0x00000003);
/* disable timer-alarm INT requests (b0) */
ACCW(PT_INTEN, 0x00000000);
/* reset timer-alarm INT status bit (b0) */
ACCW(PT_INTSTAT, 0xffffffff);
/* enable PRAMIN write access on pre NV10 before programming it! */
if (si->ps.card_arch == NV04A)
{
/* set framebuffer config: type = notiling, PRAMIN write access enabled */
NV_REG32(NV32_PFB_CONFIG_0) = 0x00001114;
}
/*** PFIFO ***/
/* (setup caches) */
/* disable caches reassign */
ACCW(PF_CACHES, 0x00000000);
/* cache1 push0 access disabled */
ACCW(PF_CACH1_PSH0, 0x00000000);
/* cache1 pull0 access disabled */
ACCW(PF_CACH1_PUL0, 0x00000000);
/* cache1 push1 mode = pio */
ACCW(PF_CACH1_PSH1, 0x00000000);
/* cache1 DMA instance adress = 0 (b0-15) */
ACCW(PF_CACH1_DMAI, 0x00000000);
/* cache0 push0 access disabled */
ACCW(PF_CACH0_PSH0, 0x00000000);
/* cache0 pull0 access disabled */
ACCW(PF_CACH0_PUL0, 0x00000000);
/* RAM HT (hash table(?)) baseadress = $10000 (b4-8), size = 4k,
* search = 128 (byte offset between hash 'sets'(?)) */
/* (note: so(?) HT base is $00710000, last is $00710fff) */
ACCW(PF_RAMHT, 0x03000100);
/* RAM FC baseadress = $11000 (b3-8) (size is fixed to 0.5k(?)) */
/* (note: so(?) FC base is $00711000, last is $007111ff) */
ACCW(PF_RAMFC, 0x00000110);
/* RAM RO baseadress = $11200 (b1-8), size = 0.5k */
/* (note: so(?) RO base is $00711200, last is $007113ff) */
/* (note also:
* This means(?) the PRAMIN CTX registers are accessible from base $00711400) */
ACCW(PF_RAMRO, 0x00000112);
/* PFIFO size: ch0-15 = 512 bytes, ch16-31 = 124 bytes */
ACCW(PF_SIZE, 0x0000ffff);
/* cache1 hash instance = $ffff (b0-15) */
ACCW(PF_CACH1_HASH, 0x0000ffff);
/* disable all PFIFO INTs */
ACCW(PF_INTEN, 0x00000000);
/* reset all PFIFO INT status bits */
ACCW(PF_INTSTAT, 0xffffffff);
/* cache0 pull0 engine = acceleration engine (graphics) */
ACCW(PF_CACH0_PUL1, 0x00000001);
/* cache1 push0 access enabled */
ACCW(PF_CACH1_PSH0, 0x00000001);
/* cache1 pull0 access enabled */
ACCW(PF_CACH1_PUL0, 0x00000001);
/* cache1 pull1 engine = acceleration engine (graphics) */
ACCW(PF_CACH1_PUL1, 0x00000001);
/* enable PFIFO caches reassign */
ACCW(PF_CACHES, 0x00000001);
/*** PRAMIN ***/
/* RAMHT space (hash-table(?)) */
/* (first set) */
ACCW(HT_HANDL_00, 0x80000010); /* 32bit handle */
ACCW(HT_VALUE_00, 0x80011145); /* instance $1145, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_01, 0x80000011); /* 32bit handle */
ACCW(HT_VALUE_01, 0x80011146); /* instance $1146, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_02, 0x80000012); /* 32bit handle */
ACCW(HT_VALUE_02, 0x80011147); /* instance $1147, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_03, 0x80000013); /* 32bit handle */
ACCW(HT_VALUE_03, 0x80011148); /* instance $1148, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_04, 0x80000014); /* 32bit handle */
ACCW(HT_VALUE_04, 0x80011149); /* instance $1149, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_05, 0x80000015); /* 32bit handle */
ACCW(HT_VALUE_05, 0x8001114a); /* instance $114a, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_06, 0x80000016); /* 32bit handle */
if (si->ps.card_arch != NV04A)
ACCW(HT_VALUE_06, 0x80011150); /* instance $1150, engine = acc engine, CHID = $00 */
else
ACCW(HT_VALUE_06, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */
/* (second set) */
ACCW(HT_HANDL_10, 0x80000000); /* 32bit handle */
ACCW(HT_VALUE_10, 0x80011142); /* instance $1142, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_11, 0x80000001); /* 32bit handle */
ACCW(HT_VALUE_11, 0x80011143); /* instance $1143, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_12, 0x80000002); /* 32bit handle */
ACCW(HT_VALUE_12, 0x80011144); /* instance $1144, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_13, 0x80000003); /* 32bit handle */
ACCW(HT_VALUE_13, 0x8001114b); /* instance $114b, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_14, 0x80000004); /* 32bit handle */
ACCW(HT_VALUE_14, 0x8001114c); /* instance $114c, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_15, 0x80000005); /* 32bit handle */
ACCW(HT_VALUE_15, 0x8001114d); /* instance $114d, engine = acc engine, CHID = $00 */
ACCW(HT_HANDL_16, 0x80000006); /* 32bit handle */
ACCW(HT_VALUE_16, 0x8001114e); /* instance $114e, engine = acc engine, CHID = $00 */
if (si->ps.card_arch != NV04A)
{
ACCW(HT_HANDL_17, 0x80000007); /* 32bit handle */
ACCW(HT_VALUE_17, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */
}
/* program CTX registers: CTX1 is mostly done later (colorspace dependant) */
/* (setup 'root' set first) */
ACCW(PR_CTX0_R, 0x00003000); /* NVclass = NVroot, chromakey and userclip enabled */
/* fixme: CTX1_R should reflect RAM amount? (no influence on current used functions) */
ACCW(PR_CTX1_R, 0x01ffffff); /* cardmemory mask(?) */
ACCW(PR_CTX2_R, 0x00000002); /* ??? */
ACCW(PR_CTX3_R, 0x00000002); /* ??? */
/* (setup set '0') */
ACCW(PR_CTX0_0, 0x01008043); /* NVclass $043, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_0, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_0, 0x00000000); /* method traps disabled */
/* (setup set '1') */
ACCW(PR_CTX0_1, 0x01008019); /* NVclass $019, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_1, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_1, 0x00000000); /* method traps disabled */
/* (setup set '2') */
ACCW(PR_CTX0_2, 0x01008018); /* NVclass $018, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_2, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_2, 0x00000000); /* method traps disabled */
/* (setup set '3') */
ACCW(PR_CTX0_3, 0x01008021); /* NVclass $021, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_3, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_3, 0x00000000); /* method traps disabled */
/* (setup set '4') */
ACCW(PR_CTX0_4, 0x0100805f); /* NVclass $05f, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_4, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_4, 0x00000000); /* method traps disabled */
/* (setup set '5') */
ACCW(PR_CTX0_5, 0x0100804b); /* NVclass $04b, patchcfg ROP_AND, nv10+: little endian */
ACCW(PR_CTX2_5, 0x00000000); /* DMA0 and DMA1 instance invalid */
ACCW(PR_CTX3_5, 0x00000000); /* method traps disabled */
/* (setup set '6') */
ACCW(PR_CTX0_6, 0x0100a048); /* NVclass $048, patchcfg ROP_AND, userclip enable,
* nv10+: little endian */
ACCW(PR_CTX1_6, 0x00000d01); /* format is A8RGB24, MSB mono */
ACCW(PR_CTX2_6, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_6, 0x00000000); /* method traps disabled */
/* (setup set '7') */
if (si->ps.card_arch != NV04A)
ACCW(PR_CTX0_7, 0x0300a094); /* NVclass $094, patchcfg ROP_AND, userclip enable,
* context surface0 valid, nv10+: little endian */
else
ACCW(PR_CTX0_7, 0x0300a054); /* NVclass $054, patchcfg ROP_AND, userclip enable,
* context surface0 valid */
ACCW(PR_CTX1_7, 0x00000d01); /* format is A8RGB24, MSB mono */
ACCW(PR_CTX2_7, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_7, 0x00000000); /* method traps disabled */
/* (setup set '8') */
if (si->ps.card_arch != NV04A)
ACCW(PR_CTX0_8, 0x0300a095); /* NVclass $095, patchcfg ROP_AND, userclip enable,
* context surface0 valid, nv10+: little endian */
else
ACCW(PR_CTX0_8, 0x0300a055); /* NVclass $055, patchcfg ROP_AND, userclip enable,
* context surface0 valid */
ACCW(PR_CTX1_8, 0x00000d01); /* format is A8RGB24, MSB mono */
ACCW(PR_CTX2_8, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_8, 0x00000000); /* method traps disabled */
/* (setup set '9') */
ACCW(PR_CTX0_9, 0x00000058); /* NVclass $058, nv10+: little endian */
ACCW(PR_CTX2_9, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_9, 0x00000000); /* method traps disabled */
/* (setup set 'A') */
ACCW(PR_CTX0_A, 0x00000059); /* NVclass $059, nv10+: little endian */
ACCW(PR_CTX2_A, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_A, 0x00000000); /* method traps disabled */
/* (setup set 'B') */
ACCW(PR_CTX0_B, 0x0000005a); /* NVclass $05a, nv10+: little endian */
ACCW(PR_CTX2_B, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_B, 0x00000000); /* method traps disabled */
/* (setup set 'C') */
ACCW(PR_CTX0_C, 0x0000005b); /* NVclass $05b, nv10+: little endian */
ACCW(PR_CTX2_C, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_C, 0x00000000); /* method traps disabled */
/* (setup set 'D') */
if (si->ps.card_arch != NV04A)
ACCW(PR_CTX0_D, 0x00000093); /* NVclass $093, nv10+: little endian */
else
ACCW(PR_CTX0_D, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable,
* context surface0 valid */
ACCW(PR_CTX2_D, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_D, 0x00000000); /* method traps disabled */
/* (setup set 'E' if needed) */
if (si->ps.card_arch != NV04A)
{
ACCW(PR_CTX0_E, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable,
* context surface0 valid, nv10+: little endian */
ACCW(PR_CTX2_E, 0x11401140); /* DMA0, DMA1 instance = $1140 */
ACCW(PR_CTX3_E, 0x00000000); /* method traps disabled */
}
/*** PGRAPH ***/
if (si->ps.card_arch != NV04A)
{
/* set resetstate for most function blocks */
ACCW(DEBUG0, 0x0003ffff);
/* init some function blocks */
ACCW(DEBUG1, 0x00118701);
ACCW(DEBUG2, 0x24f82ad9);
ACCW(DEBUG3, 0x55de0030);
/* end resetstate for the function blocks */
ACCW(DEBUG0, 0x00000000);
/* disable specific functions */
ACCW(NV10_DEBUG4, 0);
}
else
{
/* init some function blocks */
ACCW(DEBUG0, 0x1231c001);
ACCW(DEBUG1, 0x72111101);
ACCW(DEBUG2, 0x11d5f071);
ACCW(DEBUG3, 0x10d4ff31);
}
/* reset all cache sets */
ACCW(CACHE1_1, 0);
ACCW(CACHE1_2, 0);
ACCW(CACHE1_3, 0);
ACCW(CACHE1_4, 0);
ACCW(CACHE1_5, 0);
ACCW(CACHE2_1, 0);
ACCW(CACHE2_2, 0);
ACCW(CACHE2_3, 0);
ACCW(CACHE2_4, 0);
ACCW(CACHE2_5, 0);
ACCW(CACHE3_1, 0);
ACCW(CACHE3_2, 0);
ACCW(CACHE3_3, 0);
ACCW(CACHE3_4, 0);
ACCW(CACHE3_5, 0);
ACCW(CACHE4_1, 0);
ACCW(CACHE4_2, 0);
ACCW(CACHE4_3, 0);
ACCW(CACHE4_4, 0);
ACCW(CACHE4_5, 0);
if (si->ps.card_arch != NV04A)
ACCW(NV10_CACHE5_1, 0);
ACCW(CACHE5_2, 0);
ACCW(CACHE5_3, 0);
ACCW(CACHE5_4, 0);
ACCW(CACHE5_5, 0);
if (si->ps.card_arch != NV04A)
ACCW(NV10_CACHE6_1, 0);
ACCW(CACHE6_2, 0);
ACCW(CACHE6_3, 0);
ACCW(CACHE6_4, 0);
ACCW(CACHE6_5, 0);
if (si->ps.card_arch != NV04A)
ACCW(NV10_CACHE7_1, 0);
ACCW(CACHE7_2, 0);
ACCW(CACHE7_3, 0);
ACCW(CACHE7_4, 0);
ACCW(CACHE7_5, 0);
if (si->ps.card_arch != NV04A)
ACCW(NV10_CACHE8_1, 0);
ACCW(CACHE8_2, 0);
ACCW(CACHE8_3, 0);
ACCW(CACHE8_4, 0);
ACCW(CACHE8_5, 0);
if (si->ps.card_arch != NV04A)
{
/* reset (disable) context switch stuff */
ACCW(NV10_CTX_SW1, 0);
ACCW(NV10_CTX_SW2, 0);
ACCW(NV10_CTX_SW3, 0);
ACCW(NV10_CTX_SW4, 0);
ACCW(NV10_CTX_SW5, 0);
}
/* setup accesible card memory range for acc engine */
ACCW(BBASE0, 0x00000000);
ACCW(BBASE1, 0x00000000);
ACCW(BBASE2, 0x00000000);
ACCW(BBASE3, 0x00000000);
ACCW(BLIMIT0, (si->ps.memory_size - 1));
ACCW(BLIMIT1, (si->ps.memory_size - 1));
ACCW(BLIMIT2, (si->ps.memory_size - 1));
ACCW(BLIMIT3, (si->ps.memory_size - 1));
if (si->ps.card_arch >= NV10A)
{
ACCW(NV10_BBASE4, 0x00000000);
ACCW(NV10_BBASE5, 0x00000000);
ACCW(NV10_BLIMIT4, (si->ps.memory_size - 1));
ACCW(NV10_BLIMIT5, (si->ps.memory_size - 1));
}
if (si->ps.card_arch >= NV20A)
{
/* fixme(?): assuming more BLIMIT registers here: Then how about BBASE6-9?
* (linux fixed value 'BLIMIT6-9' 0x01ffffff) */
ACCW(NV20_BLIMIT6, (si->ps.memory_size - 1));
ACCW(NV20_BLIMIT7, (si->ps.memory_size - 1));
ACCW(NV20_BLIMIT8, (si->ps.memory_size - 1));
ACCW(NV20_BLIMIT9, (si->ps.memory_size - 1));
}
/* disable all acceleration engine INT reguests */
ACCW(ACC_INTE, 0x00000000);
/* reset all acceration engine INT status bits */
ACCW(ACC_INTS, 0xffffffff);
if (si->ps.card_arch != NV04A)
{
/* context control enabled */
ACCW(NV10_CTX_CTRL, 0x10010100);
/* all acceleration buffers, pitches and colors are valid */
ACCW(NV10_ACC_STAT, 0xffffffff);
}
else
{
/* context control enabled */
ACCW(NV04_CTX_CTRL, 0x10010100);
/* all acceleration buffers, pitches and colors are valid */
ACCW(NV04_ACC_STAT, 0xffffffff);
}
/* enable acceleration engine command FIFO */
ACCW(FIFO_EN, 0x00000001);
/* pattern shape value = 8x8, 2 color */
ACCW(PAT_SHP, 0x00000000);
if (si->ps.card_arch != NV04A)
{
/* surface type is non-swizzle */
ACCW(NV10_SURF_TYP, 0x00000001);
}
else
{
/* surface type is non-swizzle */
ACCW(NV04_SURF_TYP, 0x00000001);
}
/*** Set pixel width and format ***/
switch(si->dm.space)
{
case B_CMAP8:
/* acc engine */
ACCW(FORMATS, 0x00001010);
if (si->ps.card_arch < NV30A)
ACCW(BPIXEL, 0x00111111); /* set depth 0-5: 4 bits per color */
else
ACCW(BPIXEL, 0x00000021); /* set depth 0-1: 5 bits per color */
ACCW(STRD_FMT, 0x03020202);
/* PRAMIN */
ACCW(PR_CTX1_0, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX1_1, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX1_2, 0x00000202); /* format is X16A8Y8, LSB mono */
ACCW(PR_CTX1_3, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX1_4, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX1_5, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX1_9, 0x00000302); /* format is X24Y8, LSB mono */
ACCW(PR_CTX2_9, 0x00000302); /* dma_instance 0 valid, instance 1 invalid */
ACCW(PR_CTX1_B, 0x00000000); /* format is invalid */
ACCW(PR_CTX1_C, 0x00000000); /* format is invalid */
if (si->ps.card_arch == NV04A)
{
ACCW(PR_CTX1_D, 0x00000302); /* format is X24Y8, LSB mono */
}
else
{
ACCW(PR_CTX1_D, 0x00000000); /* format is invalid */
ACCW(PR_CTX1_E, 0x00000302); /* format is X24Y8, LSB mono */
}
break;
case B_RGB15_LITTLE:
/* acc engine */
ACCW(FORMATS, 0x00002071);
if (si->ps.card_arch < NV30A)
ACCW(BPIXEL, 0x00226222); /* set depth 0-5: 4 bits per color */
else
ACCW(BPIXEL, 0x00000042); /* set depth 0-1: 5 bits per color */
ACCW(STRD_FMT, 0x09080808);
/* PRAMIN */
ACCW(PR_CTX1_0, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_1, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_2, 0x00000802); /* format is X16A1RGB15, LSB mono */
ACCW(PR_CTX1_3, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_4, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_5, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_9, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX2_9, 0x00000902); /* dma_instance 0 valid, instance 1 invalid */
if (si->ps.card_arch == NV04A)
{
ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */
ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */
}
else
{
ACCW(PR_CTX1_B, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_C, 0x00000902); /* format is X17RGB15, LSB mono */
ACCW(PR_CTX1_E, 0x00000902); /* format is X17RGB15, LSB mono */
}
ACCW(PR_CTX1_D, 0x00000902); /* format is X17RGB15, LSB mono */
break;
case B_RGB16_LITTLE:
/* acc engine */
ACCW(FORMATS, 0x000050C2);
if (si->ps.card_arch < NV30A)
ACCW(BPIXEL, 0x00556555); /* set depth 0-5: 4 bits per color */
else
ACCW(BPIXEL, 0x000000a5); /* set depth 0-1: 5 bits per color */
if (si->ps.card_arch == NV04A)
ACCW(STRD_FMT, 0x0c0b0b0b);
else
ACCW(STRD_FMT, 0x000b0b0c);
/* PRAMIN */
ACCW(PR_CTX1_0, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_1, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_2, 0x00000b02); /* format is A16RGB16, LSB mono */
ACCW(PR_CTX1_3, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_4, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_5, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_9, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX2_9, 0x00000c02); /* dma_instance 0 valid, instance 1 invalid */
if (si->ps.card_arch == NV04A)
{
ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */
ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */
}
else
{
ACCW(PR_CTX1_B, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_C, 0x00000c02); /* format is X16RGB16, LSB mono */
ACCW(PR_CTX1_E, 0x00000c02); /* format is X16RGB16, LSB mono */
}
ACCW(PR_CTX1_D, 0x00000c02); /* format is X16RGB16, LSB mono */
break;
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
/* acc engine */
ACCW(FORMATS, 0x000070e5);
if (si->ps.card_arch < NV30A)
ACCW(BPIXEL, 0x0077d777); /* set depth 0-5: 4 bits per color */
else
ACCW(BPIXEL, 0x000000e7); /* set depth 0-1: 5 bits per color */
ACCW(STRD_FMT, 0x0e0d0d0d);
/* PRAMIN */
ACCW(PR_CTX1_0, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_1, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_2, 0x00000d02); /* format is A8RGB24, LSB mono */
ACCW(PR_CTX1_3, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_4, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_5, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_9, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX2_9, 0x00000e02); /* dma_instance 0 valid, instance 1 invalid */
ACCW(PR_CTX1_B, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_C, 0x00000e02); /* format is X8RGB24, LSB mono */
ACCW(PR_CTX1_D, 0x00000e02); /* format is X8RGB24, LSB mono */
if (si->ps.card_arch >= NV10A)
ACCW(PR_CTX1_E, 0x00000e02); /* format is X8RGB24, LSB mono */
break;
default:
LOG(8,("ACC: init, invalid bit depth\n"));
return B_ERROR;
}
/* setup some extra stuff for NV30A and later */
if (si->ps.card_arch >= NV30A)
{
/*
fixme: Does not belong here (and not needed?)
if(!chip->flatPanel)
{
chip->PRAMDAC0[0x0578/4] = state->vpllB; //0x00680578 = ??? never modified!
chip->PRAMDAC0[0x057C/4] = state->vpll2B; //0x0068057c = ??? never modified!
}
*/
/* activate Zcullflush(?) */
ACCW(DEBUG3, (ACCR(DEBUG3) | 0x00000001));
/* unknown */
ACCW(NV30_WHAT, (ACCR(NV30_WHAT) | 0x00040000));
}
/*** setup screen location and pitch ***/
switch (si->ps.card_arch)
{
case NV04A:
case NV10A:
/* location of active screen in framebuffer */
ACCW(OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(OFFSET4, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(OFFSET5, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
/* setup buffer pitch */
ACCW(PITCH0, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(PITCH1, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(PITCH2, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(PITCH3, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(PITCH4, (si->fbc.bytes_per_row & 0x0000ffff));
break;
case NV20A:
case NV30A:
case NV40A:
/* location of active screen in framebuffer */
ACCW(NV20_OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(NV20_OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(NV20_OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
ACCW(NV20_OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer));
/* setup buffer pitch */
ACCW(NV20_PITCH0, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(NV20_PITCH1, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(NV20_PITCH2, (si->fbc.bytes_per_row & 0x0000ffff));
ACCW(NV20_PITCH3, (si->fbc.bytes_per_row & 0x0000ffff));
break;
}
/*** setup tile and pipe stuff ***/
if (si->ps.card_arch >= NV10A)
{
/*
fixme: setup elsewhere (does not belong here):
chip->PRAMDAC[0x00000404/4] |= (1 << 25);//0x00680404 = ???
*/
/* setup acc engine tile stuff: */
/* reset tile adresses */
ACCW(NV10_FBTIL0AD, 0);
ACCW(NV10_FBTIL1AD, 0);
ACCW(NV10_FBTIL2AD, 0);
ACCW(NV10_FBTIL3AD, 0);
ACCW(NV10_FBTIL4AD, 0);
ACCW(NV10_FBTIL5AD, 0);
ACCW(NV10_FBTIL6AD, 0);
ACCW(NV10_FBTIL7AD, 0);
/* copy tile setup stuff from 'source' to acc engine */
if (si->ps.card_arch >= NV20A)
{
/* unknown: */
ACCW(NV20_WHAT0, ACCR(NV20_FBWHAT0));
ACCW(NV20_WHAT1, ACCR(NV20_FBWHAT1));
}
/* tile 0: */
/* tile invalid, tile adress = $00000 (18bit) */
ACCW(NV10_TIL0AD, ACCR(NV10_FBTIL0AD));
/* set tile end adress (18bit) */
ACCW(NV10_TIL0ED, ACCR(NV10_FBTIL0ED));
/* set tile size pitch (8bit: b8-15) */
ACCW(NV10_TIL0PT, ACCR(NV10_FBTIL0PT));
/* set tile status */
ACCW(NV10_TIL0ST, ACCR(NV10_FBTIL0ST));
/* tile 1: */
ACCW(NV10_TIL1AD, ACCR(NV10_FBTIL1AD));
ACCW(NV10_TIL1ED, ACCR(NV10_FBTIL1ED));
ACCW(NV10_TIL1PT, ACCR(NV10_FBTIL1PT));
ACCW(NV10_TIL1ST, ACCR(NV10_FBTIL1ST));
/* tile 2: */
ACCW(NV10_TIL2AD, ACCR(NV10_FBTIL2AD));
ACCW(NV10_TIL2ED, ACCR(NV10_FBTIL2ED));
ACCW(NV10_TIL2PT, ACCR(NV10_FBTIL2PT));
ACCW(NV10_TIL2ST, ACCR(NV10_FBTIL2ST));
/* tile 3: */
ACCW(NV10_TIL3AD, ACCR(NV10_FBTIL3AD));
ACCW(NV10_TIL3ED, ACCR(NV10_FBTIL3ED));
ACCW(NV10_TIL3PT, ACCR(NV10_FBTIL3PT));
ACCW(NV10_TIL3ST, ACCR(NV10_FBTIL3ST));
/* tile 4: */
ACCW(NV10_TIL4AD, ACCR(NV10_FBTIL4AD));
ACCW(NV10_TIL4ED, ACCR(NV10_FBTIL4ED));
ACCW(NV10_TIL4PT, ACCR(NV10_FBTIL4PT));
ACCW(NV10_TIL4ST, ACCR(NV10_FBTIL4ST));
/* tile 5: */
ACCW(NV10_TIL5AD, ACCR(NV10_FBTIL5AD));
ACCW(NV10_TIL5ED, ACCR(NV10_FBTIL5ED));
ACCW(NV10_TIL5PT, ACCR(NV10_FBTIL5PT));
ACCW(NV10_TIL5ST, ACCR(NV10_FBTIL5ST));
/* tile 6: */
ACCW(NV10_TIL6AD, ACCR(NV10_FBTIL6AD));
ACCW(NV10_TIL6ED, ACCR(NV10_FBTIL6ED));
ACCW(NV10_TIL6PT, ACCR(NV10_FBTIL6PT));
ACCW(NV10_TIL6ST, ACCR(NV10_FBTIL6ST));
/* tile 7: */
ACCW(NV10_TIL7AD, ACCR(NV10_FBTIL7AD));
ACCW(NV10_TIL7ED, ACCR(NV10_FBTIL7ED));
ACCW(NV10_TIL7PT, ACCR(NV10_FBTIL7PT));
ACCW(NV10_TIL7ST, ACCR(NV10_FBTIL7ST));
/* setup pipe */
/* set eyetype to local, lightning is off */
ACCW(NV10_XFMOD0, 0x10000000);
/* disable all lights */
ACCW(NV10_XFMOD1, 0x00000000);
ACCW(NV10_PIPEADR, 0x00000040);
ACCW(NV10_PIPEDAT, 0x00000008);
ACCW(NV10_PIPEADR, 0x00000200);
for (cnt = 0; cnt < (3 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00000040);
ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00000800);
for (cnt = 0; cnt < (16 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
/* turn lightning on */
ACCW(NV10_XFMOD0, 0x30000000);
/* set light 1 to infinite type, other lights remain off */
ACCW(NV10_XFMOD1, 0x00000004);
ACCW(NV10_PIPEADR, 0x00006400);
for (cnt = 0; cnt < (59 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00006800);
for (cnt = 0; cnt < (47 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00006c00);
for (cnt = 0; cnt < (3 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00007000);
for (cnt = 0; cnt < (19 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00007400);
for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00007800);
for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00004400);
for (cnt = 0; cnt < (8 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00000000);
for (cnt = 0; cnt < 16; cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
ACCW(NV10_PIPEADR, 0x00000040);
for (cnt = 0; cnt < 4; cnt++) ACCW(NV10_PIPEDAT, 0x00000000);
}
/*** setup acceleration engine command shortcuts (so via fifo) ***/
/* (b31 = 1 selects 'config' function?) */
ACCW(FIFO_00800000, 0x80000000); /* Raster OPeration */
ACCW(FIFO_00802000, 0x80000001); /* Clip */
ACCW(FIFO_00804000, 0x80000002); /* Pattern */
ACCW(FIFO_00806000, 0x80000010); /* Pixmap (not used) */
ACCW(FIFO_00808000, 0x80000011); /* Blit */
ACCW(FIFO_0080a000, 0x80000012); /* Bitmap */
ACCW(FIFO_0080c000, 0x80000016); /* Line (not used) */
ACCW(FIFO_0080e000, 0x80000014); /* ??? (not used) */
/* do first actual acceleration engine command:
* setup clipping region (workspace size) to 32768 x 32768 pixels:
* wait for room in fifo for clipping cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_CLP_FIFOFREE)) >> 2) < 2)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup clipping (writing 2 32bit words) */
ACCW(CLP_TOPLEFT, 0x00000000);
ACCW(CLP_WIDHEIGHT, 0x80008000);
return B_OK;
}
/* screen to screen blit - i.e. move windows around and scroll within them. */
status_t nv_acc_setup_blit()
{
/* setup solid pattern:
* wait for room in fifo for pattern cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup pattern (writing 5 32bit words) */
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
ACCW(PAT_COLOR0, 0xffffffff);
ACCW(PAT_COLOR1, 0xffffffff);
ACCW(PAT_MONO1, 0xffffffff);
ACCW(PAT_MONO2, 0xffffffff);
/* ROP3 registers (Raster OPeration):
* wait for room in fifo for ROP cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup ROP (writing 1 32bit word) */
ACCW(ROP_ROP3, 0xcc);
return B_OK;
}
status_t nv_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
{
/* Note: blit-copy direction is determined inside riva hardware: no setup needed */
/* instruct engine what to blit:
* wait for room in fifo for blit cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_BLT_FIFOFREE)) >> 2) < 3)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup blit (writing 3 32bit words) */
ACCW(BLT_TOPLFTSRC, ((ys << 16) | xs));
ACCW(BLT_TOPLFTDST, ((yd << 16) | xd));
ACCW(BLT_SIZE, (((h + 1) << 16) | (w + 1)));
return B_OK;
}
/* rectangle fill - i.e. workspace and window background color */
/* span fill - i.e. (selected) menuitem background color (Dano) */
status_t nv_acc_setup_rectangle(uint32 color)
{
/* setup solid pattern:
* wait for room in fifo for pattern cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup pattern (writing 5 32bit words) */
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
ACCW(PAT_COLOR0, 0xffffffff);
ACCW(PAT_COLOR1, 0xffffffff);
ACCW(PAT_MONO1, 0xffffffff);
ACCW(PAT_MONO2, 0xffffffff);
/* ROP3 registers (Raster OPeration):
* wait for room in fifo for ROP cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup ROP (writing 1 32bit word) for GXcopy */
ACCW(ROP_ROP3, 0xcc);
/* setup fill color:
* wait for room in fifo for bitmap cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup color (writing 1 32bit word) */
ACCW(BMP_COLOR1A, color);
return B_OK;
}
status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
{
/* instruct engine what to fill:
* wait for room in fifo for bitmap cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup fill (writing 2 32bit words) */
ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff)));
ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff)));
return B_OK;
}
/* rectangle invert - i.e. text cursor and text selection */
status_t nv_acc_setup_rect_invert()
{
/* setup solid pattern:
* wait for room in fifo for pattern cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup pattern (writing 5 32bit words) */
ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */
ACCW(PAT_COLOR0, 0xffffffff);
ACCW(PAT_COLOR1, 0xffffffff);
ACCW(PAT_MONO1, 0xffffffff);
ACCW(PAT_MONO2, 0xffffffff);
/* ROP3 registers (Raster OPeration):
* wait for room in fifo for ROP cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup ROP (writing 1 32bit word) for GXinvert */
ACCW(ROP_ROP3, 0x55);
/* reset fill color:
* wait for room in fifo for bitmap cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now reset color (writing 1 32bit word) */
ACCW(BMP_COLOR1A, 0);
return B_OK;
}
status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
{
/* instruct engine what to invert:
* wait for room in fifo for bitmap cmd if needed.
* (fifo holds 256 32bit words: count those, not bytes) */
while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2)
{
/* snooze a bit so I do not hammer the bus */
snooze (10);
}
/* now setup invert (writing 2 32bit words) */
ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff)));
ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff)));
return B_OK;
}
/* screen to screen tranparent blit */
status_t nv_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
{
//fixme: implement.
return B_ERROR;
}
/* screen to screen scaled filtered blit - i.e. scale video in memory */
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
uint16 xd,uint16 yd,uint16 wd,uint16 hd)
{
//fixme: implement.
return B_ERROR;
}
@@ -0,0 +1,216 @@
/* Author:
Rudolf Cornelissen 6/2004-9/2004
*/
#define MODULE_BIT 0x00000100
#include <unistd.h>
#include "nv_std.h"
static void nv_agp_list_info(agp_info ai);
static void nv_agp_list_active(uint32 cmd);
status_t nv_agp_setup(void)
{
nv_nth_agp_info nai;
nv_cmd_agp nca;
uint8 index;
agp_info nv_ai;
bool agp = false;
/* first try to enable FW support on our card if user requested this
* ('unsupported' tweak!)
* This has no effect on PCI cards. */
if (si->settings.unhide_fw)
{
uint32 reg;
LOG(4, ("AGP: STRAPINFO2 contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2)));
LOG(4, ("AGP: attempting to enable fastwrite support..\n"));
/* 'force' FW support */
reg = (NV_REG32(NV32_NVSTRAPINFO2) & ~0x00000800);
/* enable strapinfo overwrite */
NV_REG32(NV32_NVSTRAPINFO2) = (reg | 0x80000000);
LOG(4, ("AGP: STRAPINFO2 now contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2)));
}
/* set the magic number so the nvidia kerneldriver knows we're for real */
nca.magic = nai.magic = NV_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
for (index = 0; index < 8; index++)
{
/* get nth AGP device info */
nai.index = index;
ioctl(fd, NV_GET_NTH_AGP_INFO, &nai, sizeof(nai));
/* abort if no agp busmanager found */
if (!nai.agp_bus)
{
LOG(4,("AGP: no AGP busmanager found.\n"));
/* don't touch AGP command register, we don't know what has been setup:
* touching it anyway might 'hang' the graphics card! */
return B_ERROR;
}
/* exit if we didn't get device info for this index */
if (!nai.exist)
{
if (index != 0)
LOG(4,("AGP: end of AGP capable devices list.\n"));
else
LOG(4,("AGP: no AGP capable devices found.\n"));
break;
}
LOG(4,("AGP: AGP capable device #%d:\n", (index + 1)));
/* see if we are this one */
if ((nai.agpi.device_id == si->device_id) &&
(nai.agpi.vendor_id == si->vendor_id) &&
(nai.agpi.bus == si->bus) &&
(nai.agpi.device == si->device) &&
(nai.agpi.function == si->function))
{
LOG(4,("AGP: (this is the device this accelerant controls)\n"));
agp = true;
/* remember our info */
nv_ai = nai.agpi;
}
/* log capabilities */
nv_agp_list_info(nai.agpi);
}
/* if our card is not an AGP type, abort here */
/* Note:
* We have to iterate through the capability list as specified in the PCI spec
* one way or the other, otherwise we cannot distinquish between nVidia PCI and
* AGP type cards as nVidia PCI cards still have AGP registers that pretend to
* support AGP.
* We rely on the AGP busmanager to iterate trough this list for us. */
if (!agp)
{
LOG(4,("AGP: the graphicscard this accelerant controls is PCI type.\n"));
/* make sure card is set for PCI access */
CFGW(AGPCMD, 0x00000000);
return B_ERROR;
}
if (si->settings.force_pci)
{
/* set PCI mode if specified by user in nv.settings */
LOG(4,("AGP: forcing PCI mode (specified in nv.settings)\n"));
/* let the AGP busmanager setup PCI mode.
* (the AGP speed scheme is of no consequence now) */
nca.cmd = 0x00000000;
ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca));
}
else
{
/* activate AGP mode */
LOG(4,("AGP: activating AGP mode...\n"));
/* let the AGP busmanager worry about what mode to set.. */
nca.cmd = 0xfffffff7;
/* ..but we do need to select the right speed scheme fetched from our card */
if (nv_ai.interface.agp_stat & AGP_rate_rev) nca.cmd |= AGP_rate_rev;
ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca));
}
/* list mode now activated,
* make sure we have the correct speed scheme for logging */
nv_agp_list_active(nca.cmd | (nv_ai.interface.agp_stat & AGP_rate_rev));
/* extra check */
LOG(4,("AGP: graphics card AGPCMD register readback $%08x\n", CFGR(AGPCMD)));
return B_OK;
}
static void nv_agp_list_info(agp_info ai)
{
/*
list device
*/
if (ai.class_base == PCI_display)
LOG(4,("AGP: device is a graphicscard, subclass ID is $%02x\n", ai.class_sub));
else
LOG(4,("AGP: device is a hostbridge, subclass ID is $%02x\n", ai.class_sub));
LOG(4,("AGP: vendor ID $%04x\n", ai.vendor_id));
LOG(4,("AGP: device ID $%04x\n", ai.device_id));
LOG(4,("AGP: bus %d, device %d, function %d\n", ai.bus, ai.device, ai.function));
/*
list capabilities
*/
LOG(4,("AGP: this device supports AGP specification %d.%d;\n",
((ai.interface.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift),
((ai.interface.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift)));
/* the AGP devices determine AGP speed scheme version used on power-up/reset */
if (!(ai.interface.agp_stat & AGP_rate_rev))
{
/* AGP 2.0 scheme applies */
if (ai.interface.agp_stat & AGP_2_1x)
LOG(4,("AGP: AGP 2.0 1x mode is available\n"));
if (ai.interface.agp_stat & AGP_2_2x)
LOG(4,("AGP: AGP 2.0 2x mode is available\n"));
if (ai.interface.agp_stat & AGP_2_4x)
LOG(4,("AGP: AGP 2.0 4x mode is available\n"));
}
else
{
/* AGP 3.0 scheme applies */
if (ai.interface.agp_stat & AGP_3_4x)
LOG(4,("AGP: AGP 3.0 4x mode is available\n"));
if (ai.interface.agp_stat & AGP_3_8x)
LOG(4,("AGP: AGP 3.0 8x mode is available\n"));
}
if (ai.interface.agp_stat & AGP_FW) LOG(4,("AGP: fastwrite transfers are supported\n"));
if (ai.interface.agp_stat & AGP_SBA) LOG(4,("AGP: sideband adressing is supported\n"));
LOG(4,("AGP: %d queued AGP requests can be handled.\n",
(((ai.interface.agp_stat & AGP_RQ) >> AGP_RQ_shift) + 1)));
/*
list current settings,
make sure we have the correct speed scheme for logging
*/
nv_agp_list_active(ai.interface.agp_cmd | (ai.interface.agp_stat & AGP_rate_rev));
}
static void nv_agp_list_active(uint32 cmd)
{
LOG(4,("AGP: listing settings now in use:\n"));
if (!(cmd & AGP_rate_rev))
{
/* AGP 2.0 scheme applies */
if (cmd & AGP_2_1x)
LOG(4,("AGP: AGP 2.0 1x mode is set\n"));
if (cmd & AGP_2_2x)
LOG(4,("AGP: AGP 2.0 2x mode is set\n"));
if (cmd & AGP_2_4x)
LOG(4,("AGP: AGP 2.0 4x mode is set\n"));
}
else
{
/* AGP 3.0 scheme applies */
if (cmd & AGP_3_4x)
LOG(4,("AGP: AGP 3.0 4x mode is set\n"));
if (cmd & AGP_3_8x)
LOG(4,("AGP: AGP 3.0 8x mode is set\n"));
}
if (cmd & AGP_FW) LOG(4,("AGP: fastwrite transfers are enabled\n"));
if (cmd & AGP_SBA) LOG(4,("AGP: sideband adressing is enabled\n"));
LOG(4,("AGP: max. AGP queued request depth is set to %d\n",
(((cmd & AGP_RQ) >> AGP_RQ_shift) + 1)));
if (cmd & AGP_enable)
LOG(4,("AGP: the AGP interface is enabled.\n"));
else
LOG(4,("AGP: the AGP interface is disabled.\n"));
}
@@ -0,0 +1,868 @@
/* Nvidia TNT and GeForce Back End Scaler functions */
/* Written by Rudolf Cornelissen 05/2002-9/2004 */
#define MODULE_BIT 0x00000200
#include "nv_std.h"
typedef struct move_overlay_info move_overlay_info;
struct move_overlay_info
{
uint32 hcoordv; /* left and right edges of video output window */
uint32 vcoordv; /* top and bottom edges of video output window */
uint32 hsrcstv; /* horizontal source start in source buffer (clipping) */
uint32 v1srcstv; /* vertical source start in source buffer (clipping) */
uint32 a1orgv; /* alternate source clipping via startadress of source buffer */
};
static void nv_bes_calc_move_overlay(move_overlay_info *moi);
static void nv_bes_program_move_overlay(move_overlay_info moi);
/* move the overlay output window in virtualscreens */
/* Note:
* si->dm.h_display_start and si->dm.v_display_start determine where the new
* output window is located! */
void nv_bes_move_overlay()
{
move_overlay_info moi;
/* abort if overlay is not active */
if (!si->overlay.active) return;
nv_bes_calc_move_overlay(&moi);
nv_bes_program_move_overlay(moi);
}
static void nv_bes_calc_move_overlay(move_overlay_info *moi)
{
/* misc used variables */
uint16 temp1, temp2;
/* visible screen window in virtual workspaces */
uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
/* do 'overlay follow head' in dualhead modes on dualhead cards */
if (si->ps.secondary_head)
{
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if ((si->overlay.ow.h_start + (si->overlay.ow.width / 2)) <
(si->dm.h_display_start + si->dm.timing.h_display))
nv_bes_to_crtc(si->crtc_switch_mode);
else
nv_bes_to_crtc(!si->crtc_switch_mode);
break;
default:
nv_bes_to_crtc(si->crtc_switch_mode);
break;
}
}
/* the BES does not respect virtual_workspaces, but adheres to CRTC
* constraints only */
crtc_hstart = si->dm.h_display_start;
/* make dualhead stretch and switch mode work while we're at it.. */
if (si->overlay.crtc)
{
crtc_hstart += si->dm.timing.h_display;
}
/* horizontal end is the first position beyond the displayed range on the CRTC */
crtc_hend = crtc_hstart + si->dm.timing.h_display;
crtc_vstart = si->dm.v_display_start;
/* vertical end is the first position beyond the displayed range on the CRTC */
crtc_vend = crtc_vstart + si->dm.timing.v_display;
/****************************************
*** setup all edges of output window ***
****************************************/
/* setup left and right edges of output window */
moi->hcoordv = 0;
/* left edge coordinate of output window, must be inside desktop */
/* clipping on the left side */
if (si->overlay.ow.h_start < crtc_hstart)
{
temp1 = 0;
}
else
{
/* clipping on the right side */
if (si->overlay.ow.h_start >= (crtc_hend - 1))
{
/* width < 2 is not allowed */
temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (si->overlay.ow.h_start - crtc_hstart) & 0x7ff;
}
}
moi->hcoordv |= temp1 << 16;
/* right edge coordinate of output window, must be inside desktop */
/* width < 2 is not allowed */
if (si->overlay.ow.width < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the right side */
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
{
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
}
else
{
/* clipping on the left side */
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
{
/* width < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(si->overlay.ow.h_start + si->overlay.ow.width - crtc_hstart - 1)) & 0x7ff;
}
}
}
moi->hcoordv |= temp2 << 0;
LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
/* setup top and bottom edges of output window */
moi->vcoordv = 0;
/* top edge coordinate of output window, must be inside desktop */
/* clipping on the top side */
if (si->overlay.ow.v_start < crtc_vstart)
{
temp1 = 0;
}
else
{
/* clipping on the bottom side */
if (si->overlay.ow.v_start >= (crtc_vend - 1))
{
/* height < 2 is not allowed */
temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (si->overlay.ow.v_start - crtc_vstart) & 0x7ff;
}
}
moi->vcoordv |= temp1 << 16;
/* bottom edge coordinate of output window, must be inside desktop */
/* height < 2 is not allowed */
if (si->overlay.ow.height < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the bottom side */
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1))
{
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
}
else
{
/* clipping on the top side */
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
{
/* height < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(si->overlay.ow.v_start + si->overlay.ow.height - crtc_vstart - 1)) & 0x7ff;
}
}
}
moi->vcoordv |= temp2 << 0;
LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
/*********************************
*** setup horizontal clipping ***
*********************************/
/* Setup horizontal source start: first (sub)pixel contributing to output picture */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* After this is done, include the scaling factor so you get a value based on the input bitmap.
* Then add the left starting position of the bitmap's view (zoom function) to get the final value needed.
* Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
moi->hsrcstv = 0;
/* check for destination horizontal clipping at left side */
if (si->overlay.ow.h_start < crtc_hstart)
{
/* check if entire destination picture is clipping left:
* (2 pixels will be clamped onscreen at least) */
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
{
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
moi->hsrcstv += (si->overlay.ow.width - 2);
}
else
{
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
moi->hsrcstv += (crtc_hstart - si->overlay.ow.h_start);
}
LOG(4,("Overlay: clipping left...\n"));
/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
* Note that this also already takes care of aligning the value to the BES register! */
moi->hsrcstv *= si->overlay.h_ifactor;
}
/* take zoom into account */
moi->hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16;
/* AND below required by hardware */
moi->hsrcstv &= 0x03fffffc;
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", moi->hsrcstv / (float)65536));
/*******************************
*** setup vertical clipping ***
*******************************/
/* calculate inputbitmap origin adress */
moi->a1orgv = (uint32)((vuint32 *)si->overlay.ob.buffer);
moi->a1orgv -= (uint32)((vuint32 *)si->framebuffer);
/* Setup vertical source start: first (sub)pixel contributing to output picture. */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* 'After' this is done, include the scaling factor so you get a value based on the input bitmap.
* Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
moi->v1srcstv = 0;
/* check for destination vertical clipping at top side */
if (si->overlay.ow.v_start < crtc_vstart)
{
/* check if entire destination picture is clipping at top:
* (2 pixels will be clamped onscreen at least) */
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
{
/* increase 'number of clipping pixels' with 'fixed value':
* 'total height - 2' of dest. picture in pixels * inverse scaling factor */
moi->v1srcstv = (si->overlay.ow.height - 2) * si->overlay.v_ifactor;
/* on pre-NV10 we need to do clipping in the source
* bitmap because no seperate clipping registers exist... */
if (si->ps.card_arch < NV10A)
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
}
else
{
/* increase 'first contributing pixel' with:
* number of destination picture clipping pixels * inverse scaling factor */
moi->v1srcstv = (crtc_vstart - si->overlay.ow.v_start) * si->overlay.v_ifactor;
/* on pre-NV10 we need to do clipping in the source
* bitmap because no seperate clipping registers exist... */
if (si->ps.card_arch < NV10A)
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
}
LOG(4,("Overlay: clipping at top...\n"));
}
/* take zoom into account */
moi->v1srcstv += (((uint32)si->overlay.my_ov.v_start) << 16);
if (si->ps.card_arch < NV10A)
{
moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row);
LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv));
}
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", moi->v1srcstv / (float)65536));
/* AND below is probably required by hardware. */
/* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */
moi->a1orgv &= 0xfffffff0;
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv));
}
static void nv_bes_program_move_overlay(move_overlay_info moi)
{
/*************************************
*** sync to BES (Back End Scaler) ***
*************************************/
/* Done in card hardware:
* double buffered registers + trigger if programming complete feature. */
/**************************************
*** actually program the registers ***
**************************************/
if (si->ps.card_arch < NV10A)
{
/* unknown, but needed (otherwise high-res distortions and only half the frames */
BESW(NV04_OE_STATE, 0x00000000);
/* select buffer 0 as active (b16) */
BESW(NV04_SU_STATE, 0x00000000);
/* unknown (no effect?) */
BESW(NV04_RM_STATE, 0x00000000);
/* setup clipped(!) buffer startadress in RAM */
/* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
/* (program both buffers to prevent sync distortions) */
/* first include 'pixel precise' left clipping... (top clipping was already included) */
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
/* setup output window position */
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
/* setup output window size */
BESW(NV04_DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
/* select buffer 1 as active (b16) */
BESW(NV04_SU_STATE, 0x00010000);
}
else
{
/* >= NV10A */
/* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
/* setup output window position */
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
/* setup output window size */
BESW(NV10_0DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
/* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */
/* This also triggers activation of programmed values (double buffered registers feature) */
BESW(NV10_BUFSEL, 0x00000001);
}
}
status_t nv_bes_to_crtc(bool crtc)
{
if (si->ps.secondary_head)
{
if (crtc)
{
LOG(4,("Overlay: switching overlay to CRTC2\n"));
/* switch overlay engine to CRTC2 */
NV_REG32(NV32_FUNCSEL) &= ~0x00001000;
NV_REG32(NV32_2FUNCSEL) |= 0x00001000;
si->overlay.crtc = !si->crtc_switch_mode;
}
else
{
LOG(4,("Overlay: switching overlay to CRTC1\n"));
/* switch overlay engine to CRTC1 */
NV_REG32(NV32_2FUNCSEL) &= ~0x00001000;
NV_REG32(NV32_FUNCSEL) |= 0x00001000;
si->overlay.crtc = si->crtc_switch_mode;
}
return B_OK;
}
else
{
return B_ERROR;
}
}
status_t nv_bes_init()
{
if (si->ps.card_arch < NV10A)
{
/* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */
BESW(NV04_INTE, 0x00000000);
/* setup saturation to be 'neutral' */
BESW(NV04_SAT, 0x00000000);
/* setup RGB brightness to be 'neutral' */
BESW(NV04_RED_AMP, 0x00000069);
BESW(NV04_GRN_AMP, 0x0000003e);
BESW(NV04_BLU_AMP, 0x00000089);
/* setup fifo for fetching data */
BESW(NV04_FIFOBURL, 0x00000003);
BESW(NV04_FIFOTHRS, 0x00000038);
/* unknown, but needed (registers only have b0 implemented) */
/* (program both buffers to prevent sync distortions) */
BESW(NV04_0OFFSET, 0x00000000);
BESW(NV04_1OFFSET, 0x00000000);
}
else
{
/* >= NV10A */
/* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */
BESW(NV10_INTE, 0x00000000);
/* shut off GeForce4MX MPEG2 decoder */
BESW(DEC_GENCTRL, 0x00000000);
/* setup BES memory-range mask */
BESW(NV10_0MEMMASK, (si->ps.memory_size - 1));
/* unknown, but needed */
BESW(NV10_0OFFSET, 0x00000000);
/* setup brightness, contrast and saturation to be 'neutral' */
BESW(NV10_0BRICON, ((0x1000 << 16) | 0x1000));
BESW(NV10_0SAT, ((0x0000 << 16) | 0x1000));
}
return B_OK;
}
status_t nv_configure_bes
(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset)
{
/* yuy2 (4:2:2) colorspace calculations */
/* Note:
* in BeOS R5.0.3 and DANO:
* 'ow->offset_xxx' is always 0, so not used;
* 'ow->width' and 'ow->height' are the output window size: does not change
* if window is clipping;
* 'ow->h_start' and 'ow->v_start' are the left-top position of the output
* window. These values can be negative: this means the window is clipping
* at the left or the top of the display, respectively. */
/* 'ov' is the view in the source bitmap, so which part of the bitmap is actually
* displayed on screen. This is used for the 'hardware zoom' function. */
/* output window position and clipping info for source buffer */
move_overlay_info moi;
/* calculated BES register values */
uint32 hiscalv, viscalv;
/* interval representation, used for scaling calculations */
uint16 intrep;
/* inverse scaling factor, used for source positioning */
uint32 ifactor;
/* copy of overlay view which has checked valid values */
overlay_view my_ov;
/**************************************************************************************
*** copy, check and limit if needed the user-specified view into the intput bitmap ***
**************************************************************************************/
my_ov = *ov;
/* check for valid 'coordinates' */
if (my_ov.width == 0) my_ov.width++;
if (my_ov.height == 0) my_ov.height++;
if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
if (my_ov.v_start > (ob->height - 1))
my_ov.v_start = (ob->height - 1);
if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
LOG(4,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
/* save for nv_bes_calc_move_overlay() */
si->overlay.ow = *ow;
si->overlay.ob = *ob;
si->overlay.my_ov = my_ov;
/********************************
*** setup horizontal scaling ***
********************************/
LOG(4,("Overlay: total input picture width = %d, height = %d\n",
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
LOG(4,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
/* determine interval representation value, taking zoom into account */
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
{
/* horizontal filtering is ON */
if ((my_ov.width == ow->width) | (ow->width < 2))
{
/* no horizontal scaling used, OR destination width < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* horizontal filtering is OFF */
if ((ow->width < my_ov.width) & (ow->width >= 2))
{
/* horizontal downscaling used AND destination width >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep));
/* calculate inverse horizontal scaling factor, taking zoom into account */
/* standard scaling formula: */
ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep);
/* correct factor to prevent most-right visible 'line' from distorting */
ifactor -= (1 << 2);
hiscalv = ifactor;
/* save for nv_bes_calc_move_overlay() */
si->overlay.h_ifactor = ifactor;
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
/* check scaling factor (and modify if needed) to be within scaling limits */
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
if (hiscalv < 0x00002000)
{
/* (non-inverse) factor too large, set factor to max. valid value */
hiscalv = 0x00002000;
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv));
}
switch (si->ps.card_arch)
{
case NV04A:
/* Riva128-TNT2 series have a 'downscaling' limit of 1.000489
* (16bit register with 0.11 format value) */
if (hiscalv > 0x0000ffff)
{
/* (non-inverse) factor too small, set factor to min. valid value */
hiscalv = 0x0000ffff;
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)2048 / (hiscalv >> 5)));
}
break;
case NV30A:
case NV40A:
/* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */
if ((hiscalv > (2 << 16)) && (si->ps.card_type != NV31))
{
/* (non-inverse) factor too small, set factor to min. valid value */
hiscalv = (2 << 16);
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
}
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
* So let it fall through... */
if (si->ps.card_type != NV31) break;
default:
/* the rest has a downscaling limit of 0.125 */
if (hiscalv > (8 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
hiscalv = (8 << 16);
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
}
break;
}
/* AND below is required by hardware */
hiscalv &= 0x001ffffc;
/******************************
*** setup vertical scaling ***
******************************/
/* determine interval representation value, taking zoom into account */
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
{
/* vertical filtering is ON */
if ((my_ov.height == ow->height) | (ow->height < 2))
{
/* no vertical scaling used, OR destination height < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* vertical filtering is OFF */
if ((ow->height < my_ov.height) & (ow->height >= 2))
{
/* vertical downscaling used AND destination height >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: vertical interval representation value is %d\n",intrep));
/* calculate inverse vertical scaling factor, taking zoom into account */
/* standard scaling formula: */
ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep);
/* correct factor to prevent lowest visible line from distorting */
ifactor -= (1 << 2);
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor));
/* preserve ifactor for source positioning calculations later on */
viscalv = ifactor;
/* save for nv_bes_calc_move_overlay() */
si->overlay.v_ifactor = ifactor;
/* check scaling factor (and modify if needed) to be within scaling limits */
/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
if (viscalv < 0x00002000)
{
/* (non-inverse) factor too large, set factor to max. valid value */
viscalv = 0x00002000;
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv));
}
switch (si->ps.card_arch)
{
case NV04A:
/* Riva128-TNT2 series have a 'downscaling' limit of 1.000489
* (16bit register with 0.11 format value) */
if (viscalv > 0x0000ffff)
{
/* (non-inverse) factor too small, set factor to min. valid value */
viscalv = 0x0000ffff;
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)2048 / (viscalv >> 5)));
}
break;
case NV30A:
case NV40A:
/* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */
if ((viscalv > (2 << 16)) && (si->ps.card_type != NV31))
{
/* (non-inverse) factor too small, set factor to min. valid value */
viscalv = (2 << 16);
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
}
/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
* So let it fall through... */
if (si->ps.card_type != NV31) break;
default:
/* the rest has a downscaling limit of 0.125 */
if (viscalv > (8 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
viscalv = (8 << 16);
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
}
break;
}
/* AND below is required by hardware */
viscalv &= 0x001ffffc;
/********************************************************************************
*** setup all edges of output window, setup horizontal and vertical clipping ***
********************************************************************************/
nv_bes_calc_move_overlay(&moi);
/*****************************
*** log color keying info ***
*****************************/
LOG(4,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
LOG(4,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
/*****************
*** log flags ***
*****************/
LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags));
/* BTW: horizontal and vertical filtering are fixed and turned on for GeForce overlay. */
/*************************************
*** sync to BES (Back End Scaler) ***
*************************************/
/* Done in card hardware:
* double buffered registers + trigger if programming complete feature. */
/**************************************
*** actually program the registers ***
**************************************/
if (si->ps.card_arch < NV10A)
{
/* unknown, but needed (otherwise high-res distortions and only half the frames */
BESW(NV04_OE_STATE, 0x00000000);
/* select buffer 0 as active (b16) */
BESW(NV04_SU_STATE, 0x00000000);
/* unknown (no effect?) */
BESW(NV04_RM_STATE, 0x00000000);
/* setup clipped(!) buffer startadress in RAM */
/* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
/* (program both buffers to prevent sync distortions) */
/* first include 'pixel precise' left clipping... (top clipping was already included) */
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
/* setup buffer source pitch including slopspace (in bytes).
* Note:
* source pitch granularity = 16 pixels on the RIVA128 - TNT (so pre-NV10) bes */
/* (program both buffers to prevent sync distortions) */
BESW(NV04_0SRCPTCH, (ob->width * 2));
BESW(NV04_1SRCPTCH, (ob->width * 2));
/* setup output window position */
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
/* setup output window size */
BESW(NV04_DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
/* setup horizontal and vertical scaling */
BESW(NV04_ISCALVH, (((viscalv << 16) >> 5) | (hiscalv >> 5)));
/* enable vertical filtering (b0) */
BESW(NV04_CTRL_V, 0x00000001);
/* enable horizontal filtering (no effect?) */
BESW(NV04_CTRL_H, 0x00000111);
/* enable BES (b0), enable colorkeying (b4), format yuy2 (b8: 0 = ccir) */
BESW(NV04_GENCTRL, 0x00000111);
/* select buffer 1 as active (b16) */
BESW(NV04_SU_STATE, 0x00010000);
/**************************
*** setup color keying ***
**************************/
/* setup colorkeying */
switch(si->dm.space)
{
case B_RGB15_LITTLE:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 10) |
((ow->alpha.value & ow->alpha.mask) << 15)
));
break;
case B_RGB16_LITTLE:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 11)
/* this space has no alpha bits */
));
break;
case B_CMAP8:
case B_RGB32_LITTLE:
default:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 8) |
((ow->red.value & ow->red.mask) << 16) |
((ow->alpha.value & ow->alpha.mask) << 24)
));
break;
}
}
else
{
/* >= NV10A */
/* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
/* setup buffersize */
//fixme if needed: width must be even officially...
BESW(NV10_0SRCSIZE, ((ob->height << 16) | ob->width));
/* setup source pitch including slopspace (in bytes),
* b16: select YUY2 (0 = YV12), b20: use colorkey, b24: no iturbt_709 (do iturbt_601) */
/* Note:
* source pitch granularity = 32 pixels on GeForce cards!! */
BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (1 << 20) | (0 << 24)));
/* setup output window position */
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
/* setup output window size */
BESW(NV10_0DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
/* setup horizontal scaling */
BESW(NV10_0ISCALH, (hiscalv << 4));
/* setup vertical scaling */
BESW(NV10_0ISCALV, (viscalv << 4));
/* setup (unclipped!) buffer startadress in RAM */
BESW(NV10_0BUFADR, moi.a1orgv);
/* enable BES (b0 = 0) */
BESW(NV10_GENCTRL, 0x00000000);
/* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */
/* This also triggers activation of programmed values (double buffered registers feature) */
BESW(NV10_BUFSEL, 0x00000001);
/**************************
*** setup color keying ***
**************************/
/* setup colorkeying */
switch(si->dm.space)
{
case B_RGB15_LITTLE:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 10) |
((ow->alpha.value & ow->alpha.mask) << 15)
));
break;
case B_RGB16_LITTLE:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 11)
/* this space has no alpha bits */
));
break;
case B_CMAP8:
case B_RGB32_LITTLE:
default:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 8) |
((ow->red.value & ow->red.mask) << 16) |
((ow->alpha.value & ow->alpha.mask) << 24)
));
break;
}
}
/* note that overlay is in use (for nv_bes_move_overlay()) */
si->overlay.active = true;
return B_OK;
}
status_t nv_release_bes()
{
if (si->ps.card_arch < NV10A)
{
/* setup BES control: disable scaler (b0 = 0) */
BESW(NV04_GENCTRL, 0x00000000);
}
else
{
/* setup BES control: disable scaler (b0 = 1) */
BESW(NV10_GENCTRL, 0x00000001);
}
/* note that overlay is not in use (for nv_bes_move_overlay()) */
si->overlay.active = false;
return B_OK;
}
@@ -0,0 +1,829 @@
/* CTRC functionality */
/* Author:
Rudolf Cornelissen 11/2002-9/2004
*/
#define MODULE_BIT 0x00040000
#include "nv_std.h"
/*Adjust passed parameters to a valid mode line*/
status_t nv_crtc_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
)
{
/* horizontal */
/* make all parameters multiples of 8 */
*hd_e &= 0xfff8;
*hs_s &= 0xfff8;
*hs_e &= 0xfff8;
*ht &= 0xfff8;
/* confine to required number of bits, taking logic into account */
if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3);
if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3);
/* NOTE: keep horizontal timing at multiples of 8! */
/* confine to a reasonable width */
if (*hd_e < 640) *hd_e = 640;
if (si->ps.card_type > NV04)
{
if (*hd_e > 2048) *hd_e = 2048;
}
else
{
if (*hd_e > 1920) *hd_e = 1920;
}
/* if hor. total does not leave room for a sensible sync pulse, increase it! */
if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
/* if hor. total does not adhere to max. blanking pulse width, decrease it! */
if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8);
/* make sure sync pulse is not during display */
if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
/* correct sync pulse if it is too long:
* there are only 5 bits available to save this in the card registers! */
if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
/*vertical*/
/* confine to required number of bits, taking logic into account */
//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
if (*vs_e > 0x7ff ) *vs_e = 0x7ff ;
if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2);
/* confine to a reasonable height */
if (*vd_e < 480) *vd_e = 480;
if (si->ps.card_type > NV04)
{
if (*vd_e > 1536) *vd_e = 1536;
}
else
{
if (*vd_e > 1440) *vd_e = 1440;
}
/*if vertical total does not leave room for a sync pulse, increase it!*/
if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
/* if vert. total does not adhere to max. blanking pulse width, decrease it! */
if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
/* make sure sync pulse is not during display */
if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
/* correct sync pulse if it is too long:
* there are only 4 bits available to save this in the card registers! */
if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
return B_OK;
}
/*set a mode line - inputs are in pixels*/
status_t nv_crtc_set_timing(display_mode target)
{
uint8 temp;
uint32 htotal; /*total horizontal total VCLKs*/
uint32 hdisp_e; /*end of horizontal display (begins at 0)*/
uint32 hsync_s; /*begin of horizontal sync pulse*/
uint32 hsync_e; /*end of horizontal sync pulse*/
uint32 hblnk_s; /*begin horizontal blanking*/
uint32 hblnk_e; /*end horizontal blanking*/
uint32 vtotal; /*total vertical total scanlines*/
uint32 vdisp_e; /*end of vertical display*/
uint32 vsync_s; /*begin of vertical sync pulse*/
uint32 vsync_e; /*end of vertical sync pulse*/
uint32 vblnk_s; /*begin vertical blanking*/
uint32 vblnk_e; /*end vertical blanking*/
uint32 linecomp; /*split screen and vdisp_e interrupt*/
LOG(4,("CRTC: setting timing\n"));
/* setup tuned internal modeline for flatpanel if connected and active */
/* notes:
* - the CRTC modeline must end earlier than the panel modeline to keep correct
* sync going;
* - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel
* wide horizontal stripes. This can be observed earliest on fullscreen overlay,
* and if it gets worse, also normal desktop output will suffer. The stripes
* are mainly visible at the left of the screen, over the entire screen height. */
if (si->ps.tmds1_active)
{
LOG(2,("CRTC: DFP active: tuning modeline\n"));
/* horizontal timing */
target.timing.h_sync_start =
((uint16)((si->ps.p1_timing.h_sync_start / ((float)si->ps.p1_timing.h_display)) *
target.timing.h_display)) & 0xfff8;
target.timing.h_sync_end =
((uint16)((si->ps.p1_timing.h_sync_end / ((float)si->ps.p1_timing.h_display)) *
target.timing.h_display)) & 0xfff8;
target.timing.h_total =
(((uint16)((si->ps.p1_timing.h_total / ((float)si->ps.p1_timing.h_display)) *
target.timing.h_display)) & 0xfff8) - 8;
/* in native mode the CRTC needs some extra time to keep synced correctly;
* OTOH the overlay unit distorts if we reserve too much time! */
if (target.timing.h_display == si->ps.p1_timing.h_display)
{
/* NV11 timing has different constraints than later cards */
if (si->ps.card_type == NV11)
target.timing.h_total -= 56;
else
/* confirmed NV34 with 1680x1050 panel */
target.timing.h_total -= 32;
}
if (target.timing.h_sync_start == target.timing.h_display)
target.timing.h_sync_start += 8;
if (target.timing.h_sync_end == target.timing.h_total)
target.timing.h_sync_end -= 8;
/* vertical timing */
target.timing.v_sync_start =
((uint16)((si->ps.p1_timing.v_sync_start / ((float)si->ps.p1_timing.v_display)) *
target.timing.v_display));
target.timing.v_sync_end =
((uint16)((si->ps.p1_timing.v_sync_end / ((float)si->ps.p1_timing.v_display)) *
target.timing.v_display));
target.timing.v_total =
((uint16)((si->ps.p1_timing.v_total / ((float)si->ps.p1_timing.v_display)) *
target.timing.v_display)) - 1;
if (target.timing.v_sync_start == target.timing.v_display)
target.timing.v_sync_start += 1;
if (target.timing.v_sync_end == target.timing.v_total)
target.timing.v_sync_end -= 1;
/* disable GPU scaling testmode so automatic scaling will be done */
DACW(FP_DEBUG1, 0);
}
/* Modify parameters as required by standard VGA */
htotal = ((target.timing.h_total >> 3) - 5);
hdisp_e = ((target.timing.h_display >> 3) - 1);
hblnk_s = hdisp_e;
hblnk_e = (htotal + 4);//0;
hsync_s = (target.timing.h_sync_start >> 3);
hsync_e = (target.timing.h_sync_end >> 3);
vtotal = target.timing.v_total - 2;
vdisp_e = target.timing.v_display - 1;
vblnk_s = vdisp_e;
vblnk_e = (vtotal + 1);
vsync_s = target.timing.v_sync_start;//-1;
vsync_e = target.timing.v_sync_end;//-1;
/* prevent memory adress counter from being reset (linecomp may not occur) */
linecomp = target.timing.v_display;
/* enable access to primary head */
set_crtc_owner(0);
/* Note for laptop and DVI flatpanels:
* CRTC timing has a seperate set of registers from flatpanel timing.
* The flatpanel timing registers have scaling registers that are used to match
* these two modelines. */
{
LOG(4,("CRTC: Setting full timing...\n"));
/* log the mode that will be set */
LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
/* actually program the card! */
/* unlock CRTC registers at index 0-7 */
CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f));
/* horizontal standard VGA regs */
CRTCW(HTOTAL, (htotal & 0xff));
CRTCW(HDISPE, (hdisp_e & 0xff));
CRTCW(HBLANKS, (hblnk_s & 0xff));
/* also unlock vertical retrace registers in advance */
CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
CRTCW(HSYNCS, (hsync_s & 0xff));
CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
/* vertical standard VGA regs */
CRTCW(VTOTAL, (vtotal & 0xff));
CRTCW(OVERFLOW,
(
((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
));
CRTCW(PRROWSCN, 0x00); /* not used */
CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
CRTCW(VSYNCS, (vsync_s & 0xff));
CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
CRTCW(VDISPE, (vdisp_e & 0xff));
CRTCW(VBLANKS, (vblnk_s & 0xff));
CRTCW(VBLANKE, (vblnk_e & 0xff));
CRTCW(LINECOMP, (linecomp & 0xff));
/* horizontal extended regs */
//fixme: we reset bit4. is this correct??
CRTCW(HEB, (CRTCR(HEB) & 0xe0) |
(
((htotal & 0x100) >> (8 - 0)) |
((hdisp_e & 0x100) >> (8 - 1)) |
((hblnk_s & 0x100) >> (8 - 2)) |
((hsync_s & 0x100) >> (8 - 3))
));
/* (mostly) vertical extended regs */
CRTCW(LSR,
(
((vtotal & 0x400) >> (10 - 0)) |
((vdisp_e & 0x400) >> (10 - 1)) |
((vsync_s & 0x400) >> (10 - 2)) |
((vblnk_s & 0x400) >> (10 - 3)) |
((hblnk_e & 0x040) >> (6 - 4))
//fixme: we still miss one linecomp bit!?! is this it??
//| ((linecomp & 0x400) >> 3)
));
/* more vertical extended regs (on GeForce cards only) */
if (si->ps.card_arch >= NV10A)
{
CRTCW(EXTRA,
(
((vtotal & 0x800) >> (11 - 0)) |
((vdisp_e & 0x800) >> (11 - 2)) |
((vsync_s & 0x800) >> (11 - 4)) |
((vblnk_s & 0x800) >> (11 - 6))
//fixme: do we miss another linecomp bit!?!
));
}
/* setup 'large screen' mode */
if (target.timing.h_display >= 1280)
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb));
else
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04));
/* setup HSYNC & VSYNC polarity */
LOG(2,("CRTC: sync polarity: "));
temp = NV_REG8(NV8_MISCR);
if (target.timing.flags & B_POSITIVE_HSYNC)
{
LOG(2,("H:pos "));
temp &= ~0x40;
}
else
{
LOG(2,("H:neg "));
temp |= 0x40;
}
if (target.timing.flags & B_POSITIVE_VSYNC)
{
LOG(2,("V:pos "));
temp &= ~0x80;
}
else
{
LOG(2,("V:neg "));
temp |= 0x80;
}
NV_REG8(NV8_MISCW) = temp;
LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
}
/* always disable interlaced operation */
/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
CRTCW(INTERLACE, 0xff);
/* disable CRTC slaved mode unless a panel is in use */
// fixme: this kills TVout when it was in use...
if (!si->ps.tmds1_active) CRTCW(PIXEL, (CRTCR(PIXEL) & 0x7f));
/* setup flatpanel if connected and active */
if (si->ps.tmds1_active)
{
uint32 iscale_x, iscale_y;
/* calculate inverse scaling factors used by hardware in 20.12 format */
iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p1_timing.h_display);
iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p1_timing.v_display);
/* unblock flatpanel timing programming (or something like that..) */
CRTCW(FP_HTIMING, 0);
CRTCW(FP_VTIMING, 0);
LOG(2,("CRTC: FP_HTIMING reg readback: $%02x\n", CRTCR(FP_HTIMING)));
LOG(2,("CRTC: FP_VTIMING reg readback: $%02x\n", CRTCR(FP_VTIMING)));
/* enable full width visibility on flatpanel */
DACW(FP_HVALID_S, 0);
DACW(FP_HVALID_E, (si->ps.p1_timing.h_display - 1));
/* enable full height visibility on flatpanel */
DACW(FP_VVALID_S, 0);
DACW(FP_VVALID_E, (si->ps.p1_timing.v_display - 1));
/* nVidia cards support upscaling except on ??? */
/* NV11 cards can upscale after all! */
if (0)//si->ps.card_type == NV11)
{
/* disable last fetched line limiting */
DACW(FP_DEBUG2, 0x00000000);
/* inform panel to scale if needed */
if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12)))
{
LOG(2,("CRTC: DFP needs to do scaling\n"));
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) | 0x00000100));
}
else
{
LOG(2,("CRTC: no scaling for DFP needed\n"));
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff));
}
}
else
{
float dm_aspect;
LOG(2,("CRTC: GPU scales for DFP if needed\n"));
/* calculate display mode aspect */
dm_aspect = (target.timing.h_display / ((float)target.timing.v_display));
/* limit last fetched line if vertical scaling is done */
if (iscale_y != (1 << 12))
DACW(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16)));
else
DACW(FP_DEBUG2, 0x00000000);
/* inform panel not to scale */
DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff));
/* GPU scaling is automatically setup by hardware, so only modify this
* scalingfactor for non 4:3 (1.33) aspect panels;
* let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */
/* correct for widescreen panels relative to mode...
* (so if panel is more widescreen than mode being set) */
/* BTW: known widescreen panels:
* 1280 x 800 (1.60),
* 1440 x 900 (1.60),
* 1680 x 1050 (1.60),
* 1920 x 1200 (1.60). */
/* known 4:3 aspect non-standard resolution panels:
* 1400 x 1050 (1.33). */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_x != (1 << 12)) && (si->ps.panel1_aspect > (dm_aspect + 0.10)))
{
uint16 diff;
LOG(2,("CRTC: (relative) widescreen panel: tuning horizontal scaling\n"));
/* X-scaling should be the same as Y-scaling */
iscale_x = iscale_y;
/* enable testmode (b12) and program modified X-scaling factor */
DACW(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12)));
/* center/cut-off left and right side of screen */
diff = ((si->ps.p1_timing.h_display -
(target.timing.h_display * ((1 << 12) / ((float)iscale_x))))
/ 2);
DACW(FP_HVALID_S, diff);
DACW(FP_HVALID_E, ((si->ps.p1_timing.h_display - diff) - 1));
}
/* correct for portrait panels... */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_y != (1 << 12)) && (si->ps.panel1_aspect < (dm_aspect - 0.10)))
{
LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n"));
/* fixme: implement if this kind of portrait panels exist on nVidia... */
}
}
/* do some logging.. */
LOG(2,("CRTC: FP_HVALID_S reg readback: $%08x\n", DACR(FP_HVALID_S)));
LOG(2,("CRTC: FP_HVALID_E reg readback: $%08x\n", DACR(FP_HVALID_E)));
LOG(2,("CRTC: FP_VVALID_S reg readback: $%08x\n", DACR(FP_VVALID_S)));
LOG(2,("CRTC: FP_VVALID_E reg readback: $%08x\n", DACR(FP_VVALID_E)));
LOG(2,("CRTC: FP_DEBUG0 reg readback: $%08x\n", DACR(FP_DEBUG0)));
LOG(2,("CRTC: FP_DEBUG1 reg readback: $%08x\n", DACR(FP_DEBUG1)));
LOG(2,("CRTC: FP_DEBUG2 reg readback: $%08x\n", DACR(FP_DEBUG2)));
LOG(2,("CRTC: FP_DEBUG3 reg readback: $%08x\n", DACR(FP_DEBUG3)));
LOG(2,("CRTC: FP_TG_CTRL reg readback: $%08x\n", DACR(FP_TG_CTRL)));
}
return B_OK;
}
status_t nv_crtc_depth(int mode)
{
uint8 viddelay = 0;
uint32 genctrl = 0;
/* set VCLK scaling */
switch(mode)
{
case BPP8:
viddelay = 0x01;
/* genctrl b4 & b5 reset: 'direct mode' */
genctrl = 0x00101100;
break;
case BPP15:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP16:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
case BPP24:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP32:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
}
/* enable access to primary head */
set_crtc_owner(0);
CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay));
DACW(GENCTRL, genctrl);
return B_OK;
}
status_t nv_crtc_dpms(bool display, bool h, bool v)
{
uint8 temp;
LOG(4,("CRTC: setting DPMS: "));
/* enable access to primary head */
set_crtc_owner(0);
/* start synchronous reset: required before turning screen off! */
SEQW(RESET, 0x01);
/* turn screen off */
temp = SEQR(CLKMODE);
if (display)
{
SEQW(CLKMODE, (temp & ~0x20));
/* end synchronous reset if display should be enabled */
SEQW(RESET, 0x03);
//'safe mode' test! feedback needed with this 'setting'!
if (0)//si->ps.tmds1_active)
{
/* powerup both LVDS (laptop panellink) and TMDS (DVI panellink)
* internal transmitters... */
/* note:
* the powerbits in this register are hardwired to the DVI connectors,
* instead of to the DACs! (confirmed NV34) */
//fixme...
DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff));
/* ... and powerup external TMDS transmitter if it exists */
/* (confirmed OK on NV28 and NV34) */
CRTCW(0x59, (CRTCR(0x59) | 0x01));
}
LOG(4,("display on, "));
}
else
{
SEQW(CLKMODE, (temp | 0x20));
//'safe mode' test! feedback needed with this 'setting'!
if (0)//si->ps.tmds1_active)
{
/* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink)
* internal transmitters... */
/* note:
* the powerbits in this register are hardwired to the DVI connectors,
* instead of to the DACs! (confirmed NV34) */
//fixme...
DACW(FP_DEBUG0, (DACR(FP_DEBUG0) | 0x30000000));
/* ... and powerdown external TMDS transmitter if it exists */
/* (confirmed OK on NV28 and NV34) */
CRTCW(0x59, (CRTCR(0x59) & 0xfe));
}
LOG(4,("display off, "));
}
if (h)
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f));
LOG(4,("hsync enabled, "));
}
else
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80));
LOG(4,("hsync disabled, "));
}
if (v)
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf));
LOG(4,("vsync enabled\n"));
}
else
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40));
LOG(4,("vsync disabled\n"));
}
return B_OK;
}
status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v)
{
/* enable access to primary head */
set_crtc_owner(0);
*display = !(SEQR(CLKMODE) & 0x20);
*h = !(CRTCR(REPAINT1) & 0x80);
*v = !(CRTCR(REPAINT1) & 0x40);
LOG(4,("CTRC: fetched DPMS state: "));
if (*display) LOG(4,("display on, "));
else LOG(4,("display off, "));
if (*h) LOG(4,("hsync enabled, "));
else LOG(4,("hsync disabled, "));
if (*v) LOG(4,("vsync enabled\n"));
else LOG(4,("vsync disabled\n"));
return B_OK;
}
status_t nv_crtc_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
/* figure out offset value hardware needs */
offset = si->fbc.bytes_per_row / 8;
LOG(2,("CRTC: offset register set to: $%04x\n", offset));
/* enable access to primary head */
set_crtc_owner(0);
/* program the card */
CRTCW(PITCHL, (offset & 0x00ff));
CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
return B_OK;
}
status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp)
{
uint8 temp;
uint32 timeout = 0;
LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
LOG(2,("CRTC: startadd: $%08x\n", startadd));
LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer));
LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer));
/* we might have no retraces during setmode! */
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
while (((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) &&
(timeout < (25000/10)))
{
/* don't snooze much longer or retrace might get missed! */
snooze(10);
timeout++;
}
/* enable access to primary head */
set_crtc_owner(0);
if (si->ps.card_arch == NV04A)
{
/* upto 32Mb RAM adressing: must be used this way on pre-NV10! */
/* set standard registers */
/* (NVidia: startadress in 32bit words (b2 - b17) */
CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2));
CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10));
/* set extended registers */
/* NV4 extended bits: (b18-22) */
temp = (CRTCR(REPAINT0) & 0xe0);
CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18)));
/* NV4 extended bits: (b23-24) */
temp = (CRTCR(HEB) & 0x9f);
CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18)));
}
else
{
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
/* NOTE:
* While this register also exists on pre-NV10 cards, it will
* wrap-around at 16Mb boundaries!! */
/* 30bit adress in 32bit words */
NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc);
}
/* set NV4/NV10 byte adress: (b0 - 1) */
ATBW(HORPIXPAN, ((startadd & 0x00000003) << 1));
return B_OK;
}
status_t nv_crtc_cursor_init()
{
int i;
uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer */
const uint32 curadd = 0;
/* enable access to primary head */
set_crtc_owner(0);
/* set cursor bitmap adress ... */
if ((si->ps.card_arch == NV04A) || (si->ps.laptop))
{
/* must be used this way on pre-NV10 and on all 'Go' cards! */
/* cursorbitmap must start on 2Kbyte boundary: */
/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9));
/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
/* set adress bit24-31 */
CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24));
}
else
{
/* upto 4Gb RAM adressing:
* can be used on NV10 and later (except for 'Go' cards)! */
/* NOTE:
* This register does not exist on pre-NV10 and 'Go' cards. */
/* cursorbitmap must still start on 2Kbyte boundary: */
NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800);
}
/* set cursor colour: not needed because of direct nature of cursor bitmap. */
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(2048/4);i++)
{
fb[i]=0;
}
/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
NV_REG32(NV32_CURCONF) = 0x02000100;
/* activate hardware cursor */
nv_crtc_cursor_show();
return B_OK;
}
status_t nv_crtc_cursor_show()
{
LOG(4,("CRTC: enabling cursor\n"));
/* enable access to CRTC1 on dualhead cards */
set_crtc_owner(0);
/* b0 = 1 enables cursor */
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
return B_OK;
}
status_t nv_crtc_cursor_hide()
{
LOG(4,("CRTC: disabling cursor\n"));
/* enable access to primary head */
set_crtc_owner(0);
/* b0 = 0 disables cursor */
CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe));
return B_OK;
}
/*set up cursor shape*/
status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{
int x, y;
uint8 b;
uint16 *cursor;
uint16 pixel;
/* get a pointer to the cursor */
cursor = (uint16*) si->framebuffer;
/* draw the cursor */
/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
for (y = 0; y < 16; y++)
{
b = 0x80;
for (x = 0; x < 8; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
b = 0x80;
for (; x < 16; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
}
return B_OK;
}
/* position the cursor */
status_t nv_crtc_cursor_position(uint16 x, uint16 y)
{
uint16 yhigh;
/* make sure we are beyond the first line of the cursorbitmap being drawn during
* updating the position to prevent distortions: no double buffering feature */
/* Note:
* we need to return as quick as possible or some apps will exhibit lagging.. */
/* read the old cursor Y position */
yhigh = ((DACR(CURPOS) & 0x0fff0000) >> 16);
/* make sure we will wait until we are below both the old and new Y position:
* visible cursorbitmap drawing needs to be done at least... */
if (y > yhigh) yhigh = y;
if (yhigh < (si->dm.timing.v_display - 16))
{
/* we have vertical lines below old and new cursorposition to spare. So we
* update the cursor postion 'mid-screen', but below that area. */
while (((uint16)(NV_REG32(NV32_RASTER) & 0x000007ff)) < (yhigh + 16))
{
snooze(10);
}
}
else
{
/* no room to spare, just wait for retrace (is relatively slow) */
while ((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display)
{
/* don't snooze much longer or retrace might get missed! */
snooze(10);
}
}
/* update cursorposition */
DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
return B_OK;
}
@@ -0,0 +1,791 @@
/* second CTRC functionality for GeForce cards */
/* Author:
Rudolf Cornelissen 11/2002-9/2004
*/
#define MODULE_BIT 0x00020000
#include "nv_std.h"
/*Adjust passed parameters to a valid mode line*/
status_t nv_crtc2_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
)
{
/* horizontal */
/* make all parameters multiples of 8 */
*hd_e &= 0xfff8;
*hs_s &= 0xfff8;
*hs_e &= 0xfff8;
*ht &= 0xfff8;
/* confine to required number of bits, taking logic into account */
if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3);
if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3);
/* NOTE: keep horizontal timing at multiples of 8! */
/* confine to a reasonable width */
if (*hd_e < 640) *hd_e = 640;
if (*hd_e > 2048) *hd_e = 2048;
/* if hor. total does not leave room for a sensible sync pulse, increase it! */
if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
/* if hor. total does not adhere to max. blanking pulse width, decrease it! */
if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8);
/* make sure sync pulse is not during display */
if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
/* correct sync pulse if it is too long:
* there are only 5 bits available to save this in the card registers! */
if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
/*vertical*/
/* confine to required number of bits, taking logic into account */
//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
if (*vs_e > 0x7ff ) *vs_e = 0x7ff ;
if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2);
/* confine to a reasonable height */
if (*vd_e < 480) *vd_e = 480;
if (*vd_e > 1536) *vd_e = 1536;
/*if vertical total does not leave room for a sync pulse, increase it!*/
if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
/* if vert. total does not adhere to max. blanking pulse width, decrease it! */
if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
/* make sure sync pulse is not during display */
if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
/* correct sync pulse if it is too long:
* there are only 4 bits available to save this in the card registers! */
if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
return B_OK;
}
/*set a mode line - inputs are in pixels*/
status_t nv_crtc2_set_timing(display_mode target)
{
uint8 temp;
uint32 htotal; /*total horizontal total VCLKs*/
uint32 hdisp_e; /*end of horizontal display (begins at 0)*/
uint32 hsync_s; /*begin of horizontal sync pulse*/
uint32 hsync_e; /*end of horizontal sync pulse*/
uint32 hblnk_s; /*begin horizontal blanking*/
uint32 hblnk_e; /*end horizontal blanking*/
uint32 vtotal; /*total vertical total scanlines*/
uint32 vdisp_e; /*end of vertical display*/
uint32 vsync_s; /*begin of vertical sync pulse*/
uint32 vsync_e; /*end of vertical sync pulse*/
uint32 vblnk_s; /*begin vertical blanking*/
uint32 vblnk_e; /*end vertical blanking*/
uint32 linecomp; /*split screen and vdisp_e interrupt*/
LOG(4,("CRTC2: setting timing\n"));
/* setup tuned internal modeline for flatpanel if connected and active */
/* notes:
* - the CRTC modeline must end earlier than the panel modeline to keep correct
* sync going;
* - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel
* wide horizontal stripes. This can be observed earliest on fullscreen overlay,
* and if it gets worse, also normal desktop output will suffer. The stripes
* are mainly visible at the left of the screen, over the entire screen height. */
if (si->ps.tmds2_active)
{
LOG(2,("CRTC2: DFP active: tuning modeline\n"));
/* horizontal timing */
target.timing.h_sync_start =
((uint16)((si->ps.p2_timing.h_sync_start / ((float)si->ps.p2_timing.h_display)) *
target.timing.h_display)) & 0xfff8;
target.timing.h_sync_end =
((uint16)((si->ps.p2_timing.h_sync_end / ((float)si->ps.p2_timing.h_display)) *
target.timing.h_display)) & 0xfff8;
target.timing.h_total =
(((uint16)((si->ps.p2_timing.h_total / ((float)si->ps.p2_timing.h_display)) *
target.timing.h_display)) & 0xfff8) - 8;
/* in native mode the CRTC needs some extra time to keep synced correctly;
* OTOH the overlay unit distorts if we reserve too much time! */
if (target.timing.h_display == si->ps.p2_timing.h_display)
{
/* NV11 timing has different constraints than later cards */
if (si->ps.card_type == NV11)
target.timing.h_total -= 56;
else
/* confirmed NV34 with 1680x1050 panel */
target.timing.h_total -= 32;
}
if (target.timing.h_sync_start == target.timing.h_display)
target.timing.h_sync_start += 8;
if (target.timing.h_sync_end == target.timing.h_total)
target.timing.h_sync_end -= 8;
/* vertical timing */
target.timing.v_sync_start =
((uint16)((si->ps.p2_timing.v_sync_start / ((float)si->ps.p2_timing.v_display)) *
target.timing.v_display));
target.timing.v_sync_end =
((uint16)((si->ps.p2_timing.v_sync_end / ((float)si->ps.p2_timing.v_display)) *
target.timing.v_display));
target.timing.v_total =
((uint16)((si->ps.p2_timing.v_total / ((float)si->ps.p2_timing.v_display)) *
target.timing.v_display)) - 1;
if (target.timing.v_sync_start == target.timing.v_display)
target.timing.v_sync_start += 1;
if (target.timing.v_sync_end == target.timing.v_total)
target.timing.v_sync_end -= 1;
/* disable GPU scaling testmode so automatic scaling will be done */
DAC2W(FP_DEBUG1, 0);
}
/* Modify parameters as required by standard VGA */
htotal = ((target.timing.h_total >> 3) - 5);
hdisp_e = ((target.timing.h_display >> 3) - 1);
hblnk_s = hdisp_e;
hblnk_e = (htotal + 4);//0;
hsync_s = (target.timing.h_sync_start >> 3);
hsync_e = (target.timing.h_sync_end >> 3);
vtotal = target.timing.v_total - 2;
vdisp_e = target.timing.v_display - 1;
vblnk_s = vdisp_e;
vblnk_e = (vtotal + 1);
vsync_s = target.timing.v_sync_start;//-1;
vsync_e = target.timing.v_sync_end;//-1;
/* prevent memory adress counter from being reset (linecomp may not occur) */
linecomp = target.timing.v_display;
/* enable access to secondary head */
set_crtc_owner(1);
/* Note for laptop and DVI flatpanels:
* CRTC timing has a seperate set of registers from flatpanel timing.
* The flatpanel timing registers have scaling registers that are used to match
* these two modelines. */
{
LOG(4,("CRTC2: Setting full timing...\n"));
/* log the mode that will be set */
LOG(2,("CRTC2:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
/* actually program the card! */
/* unlock CRTC registers at index 0-7 */
CRTC2W(VSYNCE, (CRTC2R(VSYNCE) & 0x7f));
/* horizontal standard VGA regs */
CRTC2W(HTOTAL, (htotal & 0xff));
CRTC2W(HDISPE, (hdisp_e & 0xff));
CRTC2W(HBLANKS, (hblnk_s & 0xff));
/* also unlock vertical retrace registers in advance */
CRTC2W(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
CRTC2W(HSYNCS, (hsync_s & 0xff));
CRTC2W(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
/* vertical standard VGA regs */
CRTC2W(VTOTAL, (vtotal & 0xff));
CRTC2W(OVERFLOW,
(
((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
));
CRTC2W(PRROWSCN, 0x00); /* not used */
CRTC2W(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
CRTC2W(VSYNCS, (vsync_s & 0xff));
CRTC2W(VSYNCE, ((CRTC2R(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
CRTC2W(VDISPE, (vdisp_e & 0xff));
CRTC2W(VBLANKS, (vblnk_s & 0xff));
CRTC2W(VBLANKE, (vblnk_e & 0xff));
CRTC2W(LINECOMP, (linecomp & 0xff));
/* horizontal extended regs */
//fixme: we reset bit4. is this correct??
CRTC2W(HEB, (CRTC2R(HEB) & 0xe0) |
(
((htotal & 0x100) >> (8 - 0)) |
((hdisp_e & 0x100) >> (8 - 1)) |
((hblnk_s & 0x100) >> (8 - 2)) |
((hsync_s & 0x100) >> (8 - 3))
));
/* (mostly) vertical extended regs */
CRTC2W(LSR,
(
((vtotal & 0x400) >> (10 - 0)) |
((vdisp_e & 0x400) >> (10 - 1)) |
((vsync_s & 0x400) >> (10 - 2)) |
((vblnk_s & 0x400) >> (10 - 3)) |
((hblnk_e & 0x040) >> (6 - 4))
//fixme: we still miss one linecomp bit!?! is this it??
//| ((linecomp & 0x400) >> 3)
));
/* more vertical extended regs */
CRTC2W(EXTRA,
(
((vtotal & 0x800) >> (11 - 0)) |
((vdisp_e & 0x800) >> (11 - 2)) |
((vsync_s & 0x800) >> (11 - 4)) |
((vblnk_s & 0x800) >> (11 - 6))
//fixme: do we miss another linecomp bit!?!
));
/* setup 'large screen' mode */
if (target.timing.h_display >= 1280)
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xfb));
else
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x04));
/* setup HSYNC & VSYNC polarity */
LOG(2,("CRTC2: sync polarity: "));
temp = NV_REG8(NV8_MISCR);
if (target.timing.flags & B_POSITIVE_HSYNC)
{
LOG(2,("H:pos "));
temp &= ~0x40;
}
else
{
LOG(2,("H:neg "));
temp |= 0x40;
}
if (target.timing.flags & B_POSITIVE_VSYNC)
{
LOG(2,("V:pos "));
temp &= ~0x80;
}
else
{
LOG(2,("V:neg "));
temp |= 0x80;
}
NV_REG8(NV8_MISCW) = temp;
LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
}
/* always disable interlaced operation */
/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
CRTC2W(INTERLACE, 0xff);
/* disable CRTC slaved mode unless a panel is in use */
// fixme: this kills TVout when it was in use...
if (!si->ps.tmds2_active) CRTC2W(PIXEL, (CRTC2R(PIXEL) & 0x7f));
/* setup flatpanel if connected and active */
if (si->ps.tmds2_active)
{
uint32 iscale_x, iscale_y;
/* calculate inverse scaling factors used by hardware in 20.12 format */
iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p2_timing.h_display);
iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p2_timing.v_display);
/* unblock flatpanel timing programming (or something like that..) */
CRTC2W(FP_HTIMING, 0);
CRTC2W(FP_VTIMING, 0);
LOG(2,("CRTC2: FP_HTIMING reg readback: $%02x\n", CRTC2R(FP_HTIMING)));
LOG(2,("CRTC2: FP_VTIMING reg readback: $%02x\n", CRTC2R(FP_VTIMING)));
/* enable full width visibility on flatpanel */
DAC2W(FP_HVALID_S, 0);
DAC2W(FP_HVALID_E, (si->ps.p2_timing.h_display - 1));
/* enable full height visibility on flatpanel */
DAC2W(FP_VVALID_S, 0);
DAC2W(FP_VVALID_E, (si->ps.p2_timing.v_display - 1));
/* nVidia cards support upscaling except on ??? */
/* NV11 cards can upscale after all! */
if (0)//si->ps.card_type == NV11)
{
/* disable last fetched line limiting */
DAC2W(FP_DEBUG2, 0x00000000);
/* inform panel to scale if needed */
if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12)))
{
LOG(2,("CRTC2: DFP needs to do scaling\n"));
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) | 0x00000100));
}
else
{
LOG(2,("CRTC2: no scaling for DFP needed\n"));
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
}
}
else
{
float dm_aspect;
LOG(2,("CRTC2: GPU scales for DFP if needed\n"));
/* calculate display mode aspect */
dm_aspect = (target.timing.h_display / ((float)target.timing.v_display));
/* limit last fetched line if vertical scaling is done */
if (iscale_y != (1 << 12))
DAC2W(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16)));
else
DAC2W(FP_DEBUG2, 0x00000000);
/* inform panel not to scale */
DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff));
/* GPU scaling is automatically setup by hardware, so only modify this
* scalingfactor for non 4:3 (1.33) aspect panels;
* let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */
/* correct for widescreen panels relative to mode...
* (so if panel is more widescreen than mode being set) */
/* BTW: known widescreen panels:
* 1280 x 800 (1.60),
* 1440 x 900 (1.60),
* 1680 x 1050 (1.60),
* 1920 x 1200 (1.60). */
/* known 4:3 aspect non-standard resolution panels:
* 1400 x 1050 (1.33). */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_x != (1 << 12)) && (si->ps.panel2_aspect > (dm_aspect + 0.10)))
{
uint16 diff;
LOG(2,("CRTC2: (relative) widescreen panel: tuning horizontal scaling\n"));
/* X-scaling should be the same as Y-scaling */
iscale_x = iscale_y;
/* enable testmode (b12) and program new X-scaling factor */
DAC2W(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12)));
/* center/cut-off left and right side of screen */
diff = ((si->ps.p2_timing.h_display -
(target.timing.h_display * ((1 << 12) / ((float)iscale_x))))
/ 2);
DAC2W(FP_HVALID_S, diff);
DAC2W(FP_HVALID_E, ((si->ps.p2_timing.h_display - diff) - 1));
}
/* correct for portrait panels... */
/* NOTE:
* allow 0.10 difference so 1280x1024 panels will be used fullscreen! */
if ((iscale_y != (1 << 12)) && (si->ps.panel2_aspect < (dm_aspect - 0.10)))
{
LOG(2,("CRTC2: (relative) portrait panel: should tune vertical scaling\n"));
/* fixme: implement if this kind of portrait panels exist on nVidia... */
}
}
/* do some logging.. */
LOG(2,("CRTC2: FP_HVALID_S reg readback: $%08x\n", DAC2R(FP_HVALID_S)));
LOG(2,("CRTC2: FP_HVALID_E reg readback: $%08x\n", DAC2R(FP_HVALID_E)));
LOG(2,("CRTC2: FP_VVALID_S reg readback: $%08x\n", DAC2R(FP_VVALID_S)));
LOG(2,("CRTC2: FP_VVALID_E reg readback: $%08x\n", DAC2R(FP_VVALID_E)));
LOG(2,("CRTC2: FP_DEBUG0 reg readback: $%08x\n", DAC2R(FP_DEBUG0)));
LOG(2,("CRTC2: FP_DEBUG1 reg readback: $%08x\n", DAC2R(FP_DEBUG1)));
LOG(2,("CRTC2: FP_DEBUG2 reg readback: $%08x\n", DAC2R(FP_DEBUG2)));
LOG(2,("CRTC2: FP_DEBUG3 reg readback: $%08x\n", DAC2R(FP_DEBUG3)));
LOG(2,("CRTC2: FP_TG_CTRL reg readback: $%08x\n", DAC2R(FP_TG_CTRL)));
}
return B_OK;
}
status_t nv_crtc2_depth(int mode)
{
uint8 viddelay = 0;
uint32 genctrl = 0;
/* set VCLK scaling */
switch(mode)
{
case BPP8:
viddelay = 0x01;
/* genctrl b4 & b5 reset: 'direct mode' */
genctrl = 0x00101100;
break;
case BPP15:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP16:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
case BPP24:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP32:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
}
/* enable access to secondary head */
set_crtc_owner(1);
CRTC2W(PIXEL, ((CRTC2R(PIXEL) & 0xfc) | viddelay));
DAC2W(GENCTRL, genctrl);
return B_OK;
}
status_t nv_crtc2_dpms(bool display, bool h, bool v)
{
uint8 temp;
LOG(4,("CRTC2: setting DPMS: "));
/* enable access to secondary head */
set_crtc_owner(1);
/* start synchronous reset: required before turning screen off! */
SEQW(RESET, 0x01);
/* turn screen off */
temp = SEQR(CLKMODE);
if (display)
{
SEQW(CLKMODE, (temp & ~0x20));
/* end synchronous reset if display should be enabled */
SEQW(RESET, 0x03);
//'safe mode' test! feedback needed with this 'setting'!
if (0)//si->ps.tmds2_active)
{
/* powerup both LVDS (laptop panellink) and TMDS (DVI panellink)
* internal transmitters... */
/* note:
* the powerbits in this register are hardwired to the DVI connectors,
* instead of to the DACs! (confirmed NV34) */
//fixme...
DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) & 0xcfffffff));
/* ... and powerup external TMDS transmitter if it exists */
/* (confirmed OK on NV28 and NV34) */
CRTC2W(0x59, (CRTC2R(0x59) | 0x01));
}
LOG(4,("display on, "));
}
else
{
SEQW(CLKMODE, (temp | 0x20));
//'safe mode' test! feedback needed with this 'setting'!
if (0)//si->ps.tmds2_active)
{
/* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink)
* internal transmitters... */
/* note:
* the powerbits in this register are hardwired to the DVI connectors,
* instead of to the DACs! (confirmed NV34) */
//fixme...
DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) | 0x30000000));
/* ... and powerdown external TMDS transmitter if it exists */
/* (confirmed OK on NV28 and NV34) */
CRTC2W(0x59, (CRTC2R(0x59) & 0xfe));
}
LOG(4,("display off, "));
}
if (h)
{
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0x7f));
LOG(4,("hsync enabled, "));
}
else
{
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x80));
LOG(4,("hsync disabled, "));
}
if (v)
{
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xbf));
LOG(4,("vsync enabled\n"));
}
else
{
CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x40));
LOG(4,("vsync disabled\n"));
}
return B_OK;
}
status_t nv_crtc2_dpms_fetch(bool *display, bool *h, bool *v)
{
/* enable access to secondary head */
set_crtc_owner(1);
*display = !(SEQR(CLKMODE) & 0x20);
*h = !(CRTC2R(REPAINT1) & 0x80);
*v = !(CRTC2R(REPAINT1) & 0x40);
LOG(4,("CTRC2: fetched DPMS state: "));
if (*display) LOG(4,("display on, "));
else LOG(4,("display off, "));
if (*h) LOG(4,("hsync enabled, "));
else LOG(4,("hsync disabled, "));
if (*v) LOG(4,("vsync enabled\n"));
else LOG(4,("vsync disabled\n"));
return B_OK;
}
status_t nv_crtc2_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
/* figure out offset value hardware needs */
offset = si->fbc.bytes_per_row / 8;
LOG(2,("CRTC2: offset register set to: $%04x\n", offset));
/* enable access to secondary head */
set_crtc_owner(1);
/* program the card */
CRTC2W(PITCHL, (offset & 0x00ff));
CRTC2W(REPAINT0, ((CRTC2R(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
return B_OK;
}
status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp)
{
uint32 timeout = 0;
LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
LOG(2,("CRTC2: startadd: $%08x\n", startadd));
LOG(2,("CRTC2: frameRAM: $%08x\n", si->framebuffer));
LOG(2,("CRTC2: framebuffer: $%08x\n", si->fbc.frame_buffer));
/* we might have no retraces during setmode! */
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
while (((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) &&
(timeout < (25000/10)))
{
/* don't snooze much longer or retrace might get missed! */
snooze(10);
timeout++;
}
/* enable access to secondary head */
set_crtc_owner(1);
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
/* NOTE:
* While this register also exists on pre-NV10 cards, it will
* wrap-around at 16Mb boundaries!! */
/* 30bit adress in 32bit words */
NV_REG32(NV32_NV10FB2STADD32) = (startadd & 0xfffffffc);
/* set byte adress: (b0 - 1) */
ATB2W(HORPIXPAN, ((startadd & 0x00000003) << 1));
return B_OK;
}
status_t nv_crtc2_cursor_init()
{
int i;
uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer */
const uint32 curadd = 0;
/* enable access to secondary head */
set_crtc_owner(1);
/* set cursor bitmap adress ... */
if (si->ps.laptop)
{
/* must be used this way on pre-NV10 and on all 'Go' cards! */
/* cursorbitmap must start on 2Kbyte boundary: */
/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
CRTC2W(CURCTL0, ((curadd & 0x0001f800) >> 9));
/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
CRTC2W(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
/* set adress bit24-31 */
CRTC2W(CURCTL2, ((curadd & 0xff000000) >> 24));
}
else
{
/* upto 4Gb RAM adressing:
* can be used on NV10 and later (except for 'Go' cards)! */
/* NOTE:
* This register does not exist on pre-NV10 and 'Go' cards. */
/* cursorbitmap must still start on 2Kbyte boundary: */
NV_REG32(NV32_NV10CUR2ADD32) = (curadd & 0xfffff800);
}
/* set cursor colour: not needed because of direct nature of cursor bitmap. */
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(2048/4);i++)
{
fb[i]=0;
}
/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
NV_REG32(NV32_2CURCONF) = 0x02000100;
/* activate hardware cursor */
nv_crtc2_cursor_show();
return B_OK;
}
status_t nv_crtc2_cursor_show()
{
LOG(4,("CRTC2: enabling cursor\n"));
/* enable access to secondary head */
set_crtc_owner(1);
/* b0 = 1 enables cursor */
CRTC2W(CURCTL0, (CRTC2R(CURCTL0) | 0x01));
return B_OK;
}
status_t nv_crtc2_cursor_hide()
{
LOG(4,("CRTC2: disabling cursor\n"));
/* enable access to secondary head */
set_crtc_owner(1);
/* b0 = 0 disables cursor */
CRTC2W(CURCTL0, (CRTC2R(CURCTL0) & 0xfe));
return B_OK;
}
/*set up cursor shape*/
status_t nv_crtc2_cursor_define(uint8* andMask,uint8* xorMask)
{
int x, y;
uint8 b;
uint16 *cursor;
uint16 pixel;
/* get a pointer to the cursor */
cursor = (uint16*) si->framebuffer;
/* draw the cursor */
/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
for (y = 0; y < 16; y++)
{
b = 0x80;
for (x = 0; x < 8; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
b = 0x80;
for (; x < 16; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
}
return B_OK;
}
/* position the cursor */
status_t nv_crtc2_cursor_position(uint16 x, uint16 y)
{
uint16 yhigh;
/* make sure we are beyond the first line of the cursorbitmap being drawn during
* updating the position to prevent distortions: no double buffering feature */
/* Note:
* we need to return as quick as possible or some apps will exhibit lagging.. */
/* read the old cursor Y position */
yhigh = ((DAC2R(CURPOS) & 0x0fff0000) >> 16);
/* make sure we will wait until we are below both the old and new Y position:
* visible cursorbitmap drawing needs to be done at least... */
if (y > yhigh) yhigh = y;
if (yhigh < (si->dm.timing.v_display - 16))
{
/* we have vertical lines below old and new cursorposition to spare. So we
* update the cursor postion 'mid-screen', but below that area. */
while (((uint16)(NV_REG32(NV32_RASTER2) & 0x000007ff)) < (yhigh + 16))
{
snooze(10);
}
}
else
{
/* no room to spare, just wait for retrace (is relatively slow) */
while ((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display)
{
/* don't snooze much longer or retrace might get missed! */
snooze(10);
}
}
/* update cursorposition */
DAC2W(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
return B_OK;
}
@@ -0,0 +1,561 @@
/* program the DAC */
/* Author:
Rudolf Cornelissen 12/2003-10/2004
*/
#define MODULE_BIT 0x00010000
#include "nv_std.h"
static status_t nv4_nv10_nv20_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
/* see if an analog VGA monitor is connected to connector #1 */
bool nv_dac_crt_connected(void)
{
uint32 output, dac;
bool present;
/* save output connector setting */
output = DACR(OUTPUT);
/* save DAC state */
dac = DACR(TSTCTRL);
/* turn on DAC */
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeffff));
/* select primary head and turn off CRT (and DVI?) outputs */
DACW(OUTPUT, (output & 0x0000feee));
/* wait for signal lines to stabilize */
snooze(1000);
/* re-enable CRT output */
DACW(OUTPUT, (DACR(OUTPUT) | 0x00000001));
/* setup RGB test signal levels to approx 30% of DAC range and enable them */
DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0)));
/* route test signals to output */
DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000));
/* wait for signal lines to stabilize */
snooze(1000);
/* do actual detection: all signals paths high == CRT connected */
if (DACR(TSTCTRL) & 0x10000000)
{
present = true;
LOG(4,("DAC: CRT detected on connector #1\n"));
}
else
{
present = false;
LOG(4,("DAC: no CRT detected on connector #1\n"));
}
/* kill test signal routing */
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff));
/* restore output connector setting */
DACW(OUTPUT, output);
/* restore DAC state */
DACW(TSTCTRL, dac);
return present;
}
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t nv_dac_mode(int mode,float brightness)
{
uint8 *r,*g,*b;
int i, ri;
/*set colour arrays to point to space reserved in shared info*/
r = si->color_data;
g = r + 256;
b = g + 256;
LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness));
/* init the palette for brightness specified */
/* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */
for (i = 0; i < 256; i++)
{
ri = i * brightness;
if (ri > 255) ri = 255;
b[i] = g[i] = r[i] = ri;
}
if (nv_dac_palette(r,g,b) != B_OK) return B_ERROR;
/* disable palette RAM adressing mask */
NV_REG8(NV8_PALMASK) = 0xff;
LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PALMASK)));
return B_OK;
}
/*program the DAC palette using the given r,g,b values*/
status_t nv_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256])
{
int i;
LOG(4,("DAC: setting palette\n"));
/* select first PAL adress before starting programming */
NV_REG8(NV8_PALINDW) = 0x00;
/* loop through all 256 to program DAC */
for (i = 0; i < 256; i++)
{
/* the 6 implemented bits are on b0-b5 of the bus */
NV_REG8(NV8_PALDATA) = r[i];
NV_REG8(NV8_PALDATA) = g[i];
NV_REG8(NV8_PALDATA) = b[i];
}
if (NV_REG8(NV8_PALINDW) != 0x00)
{
LOG(8,("DAC: PAL write index incorrect after programming\n"));
return B_ERROR;
}
if (1)
{//reread LUT
uint8 R, G, B;
/* select first PAL adress to read (modulo 3 counter) */
NV_REG8(NV8_PALINDR) = 0x00;
for (i = 0; i < 256; i++)
{
R = NV_REG8(NV8_PALDATA);
G = NV_REG8(NV8_PALDATA);
B = NV_REG8(NV8_PALDATA);
if ((r[i] != R) || (g[i] != G) || (b[i] != B))
LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
}
}
return B_OK;
}
/*program the pixpll - frequency in kHz*/
status_t nv_dac_set_pix_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
// uint time = 0;
float pix_setting, req_pclk;
status_t result;
/* we offer this option because some panels have very tight restrictions,
* and there's no overlapping settings range that makes them all work.
* note:
* this assumes the cards BIOS correctly programmed the panel (is likely) */
//fixme: when VESA DDC EDID stuff is implemented, this option can be deleted...
if (si->ps.tmds1_active && !si->settings.pgm_panel)
{
LOG(4,("DAC: Not programming DFP refresh (specified in nv.settings)\n"));
return B_OK;
}
/* fix a DVI or laptop flatpanel to 60Hz refresh! */
/* Note:
* The pixelclock drives the flatpanel modeline, not the CRTC modeline. */
if (si->ps.tmds1_active)
{
LOG(4,("DAC: Fixing DFP refresh to 60Hz!\n"));
/* use the panel's modeline to determine the needed pixelclock */
target.timing.pixel_clock = si->ps.p1_timing.pixel_clock;
}
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk));
/* signal that we actually want to set the mode */
result = nv_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*reprogram (disable,select,wait for stability,enable)*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
/* program new frequency */
DACW(PIXPLLC, ((p << 16) | (n << 8) | m));
/* program 2nd set N and M scalers if they exist (b31=1 enables them) */
if (si->ps.ext_pll) DACW(PIXPLLC2, 0x80000401);
/* Wait for the PIXPLL frequency to lock until timeout occurs */
//fixme: do NV cards have a LOCK indication bit??
/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: PIX PLL frequency not locked!\n"));
else
LOG(2,("DAC: PIX PLL frequency locked\n"));
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL
*/
//for now:
/* Give the PIXPLL frequency some time to lock... */
snooze(1000);
LOG(2,("DAC: PIX PLL frequency should be locked now...\n"));
return B_OK;
}
/* find nearest valid pix pll */
status_t nv_dac_pix_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
switch (si->ps.card_type) {
default: return nv4_nv10_nv20_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
}
return B_ERROR;
}
/* find nearest valid pixel PLL setting */
static status_t nv4_nv10_nv20_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0, p = 0/*, m_max*/;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
/* switch(si->ps.card_type)
{
case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
*/
LOG(4,("DAC: NV4/NV10/NV20 restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac1_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 16.0))
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_pixel_vco / 16.0)));
req_pclk = (si->ps.min_pixel_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco))
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco /= 4;
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 7; m <= 14; m++)
{
/* check if phase-discriminator will be within operational limits */
//fixme: PLL calcs will be resetup/splitup/updated...
if (si->ps.card_type == NV36)
{
if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue;
}
else
{
if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue;
}
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 1) || (n > 255)) continue;
/* find error in frequency this setting gives */
if (si->ps.ext_pll)
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p));
}
else
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m = best[0];
n = best[1];
p = best[2];
/* log the VCO frequency found */
f_vco = ((si->ps.f_ref / m) * n);
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco *= 4;
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
/* return the results */
*calc_pclk = (f_vco / p);
*m_result = m;
*n_result = n;
switch(p)
{
case 1:
p = 0x00;
break;
case 2:
p = 0x01;
break;
case 4:
p = 0x02;
break;
case 8:
p = 0x03;
break;
case 16:
p = 0x04;
break;
}
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
/* find nearest valid system PLL setting */
status_t nv_dac_sys_pll_find(
float req_sclk, float* calc_sclk, uint8* m_result, uint8* n_result, uint8* p_result, uint8 test)
{
int m = 0, n = 0, p = 0, m_max, p_max;
float error, error_best = 999999999;
int best[3];
float f_vco, discr_low, discr_high;
/* determine the max. reference-frequency postscaler setting for the
* current requested clock */
switch (si->ps.card_arch)
{
case NV04A:
LOG(4,("DAC: NV04 restrictions apply\n"));
/* set phase-discriminator frequency range (Mhz) (verified) */
discr_low = 1.0;
discr_high = 2.0;
/* set max. useable reference frequency postscaler divider factor */
m_max = 14;
/* set max. useable VCO output postscaler divider factor */
p_max = 16;
break;
default:
switch (si->ps.card_type)
{
case NV28:
//fixme: how about some other cards???
LOG(4,("DAC: NV28 restrictions apply\n"));
/* set max. useable reference frequency postscaler divider factor;
* apparantly we would get distortions on high PLL output frequencies if
* we use the phase-discriminator at low frequencies */
if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */
else if (req_sclk > 200.0) m_max = 4; /* 200Mhz < Fpll <= 340Mhz */
else if (req_sclk > 150.0) m_max = 6; /* 150Mhz < Fpll <= 200Mhz */
else m_max = 14; /* Fpll < 150Mhz */
/* set max. useable VCO output postscaler divider factor */
p_max = 32;
/* set phase-discriminator frequency range (Mhz) (verified) */
discr_low = 1.0;
discr_high = 27.0;
break;
default:
LOG(4,("DAC: NV10/NV20/NV30 restrictions apply\n"));
/* set max. useable reference frequency postscaler divider factor;
* apparantly we would get distortions on high PLL output frequencies if
* we use the phase-discriminator at low frequencies */
if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */
else if (req_sclk > 250.0) m_max = 6; /* 250Mhz < Fpll <= 340Mhz */
else m_max = 14; /* Fpll < 250Mhz */
/* set max. useable VCO output postscaler divider factor */
p_max = 16;
/* set phase-discriminator frequency range (Mhz) (verified) */
if (si->ps.card_type == NV36) discr_low = 3.2;
else discr_low = 1.0;
/* (high discriminator spec is failsafe) */
discr_high = 14.0;
break;
}
break;
}
LOG(4,("DAC: PLL reference frequency postscaler divider range is 1 - %d\n", m_max));
LOG(4,("DAC: PLL VCO output postscaler divider range is 1 - %d\n", p_max));
LOG(4,("DAC: PLL discriminator input frequency range is %2.2fMhz - %2.2fMhz\n",
discr_low, discr_high));
/* Make sure the requested clock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / ((float)p_max)))
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (si->ps.min_system_vco / ((float)p_max))));
req_sclk = (si->ps.min_system_vco / ((float)p_max));
}
/* upper limit is given by pins */
if (req_sclk > si->ps.max_system_vco)
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)si->ps.max_system_vco));
req_sclk = si->ps.max_system_vco;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p <= p_max; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_sclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco))
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco /= 4;
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 1; m <= m_max; m++)
{
/* check if phase-discriminator will be within operational limits */
if (((si->ps.f_ref / m) < discr_low) || ((si->ps.f_ref / m) > discr_high))
continue;
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 1) || (n > 255)) continue;
/* find error in frequency this setting gives */
if (si->ps.ext_pll)
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
error = fabs((req_sclk / 4) - (((si->ps.f_ref / m) * n) / p));
}
else
error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m = best[0];
n = best[1];
p = best[2];
/* log the VCO frequency found */
f_vco = ((si->ps.f_ref / m) * n);
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco *= 4;
LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
/* return the results */
*calc_sclk = (f_vco / p);
*m_result = m;
*n_result = n;
switch(p)
{
case 1:
p = 0x00;
break;
case 2:
p = 0x01;
break;
case 4:
p = 0x02;
break;
case 8:
p = 0x03;
break;
case 16:
p = 0x04;
break;
case 32:
p = 0x05;
break;
}
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_sclk, *calc_sclk, *m_result, *n_result, *p_result));
return B_OK;
}
@@ -0,0 +1,391 @@
/* program the secondary DAC */
/* Author:
Rudolf Cornelissen 12/2003-9/2004
*/
#define MODULE_BIT 0x00001000
#include "nv_std.h"
static status_t nv10_nv20_dac2_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
/* see if an analog VGA monitor is connected to connector #2 */
bool nv_dac2_crt_connected()
{
uint32 output, dac;
bool present;
/* NOTE:
* NV11 can't do this: It will report DAC1 status instead because it HAS no
* actual secondary DAC function. */
/* (It DOES have a secondary palette RAM and pixelclock PLL though.) */
/* save output connector setting */
output = DAC2R(OUTPUT);
/* save DAC state */
dac = DAC2R(TSTCTRL);
/* turn on DAC2 */
DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeffff));
/* select primary head and turn off CRT (and DVI?) outputs */
DAC2W(OUTPUT, (output & 0x0000feee));
/* wait for signal lines to stabilize */
snooze(1000);
/* re-enable CRT output */
DAC2W(OUTPUT, (DAC2R(OUTPUT) | 0x00000001));
/* setup RGB test signal levels to approx 30% of DAC range and enable them
* (NOTE: testsignal function block resides in DAC1 only (!)) */
DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0)));
/* route test signals to output
* (NOTE: testsignal function block resides in DAC1 only (!)) */
DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000));
/* wait for signal lines to stabilize */
snooze(1000);
/* do actual detection: all signals paths high == CRT connected */
if (DAC2R(TSTCTRL) & 0x10000000)
{
present = true;
LOG(4,("DAC2: CRT detected on connector #2\n"));
}
else
{
present = false;
LOG(4,("DAC2: no CRT detected on connector #2\n"));
}
/* kill test signal routing
* (NOTE: testsignal function block resides in DAC1 only (!)) */
DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff));
/* restore output connector setting */
DAC2W(OUTPUT, output);
/* restore DAC state */
DAC2W(TSTCTRL, dac);
return present;
}
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t nv_dac2_mode(int mode,float brightness)
{
uint8 *r,*g,*b;
int i, ri;
/*set colour arrays to point to space reserved in shared info*/
r = si->color_data;
g = r + 256;
b = g + 256;
LOG(4,("DAC2: Setting screen mode %d brightness %f\n", mode, brightness));
/* init the palette for brightness specified */
/* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */
for (i = 0; i < 256; i++)
{
ri = i * brightness;
if (ri > 255) ri = 255;
b[i] = g[i] = r[i] = ri;
}
if (nv_dac2_palette(r,g,b) != B_OK) return B_ERROR;
/* disable palette RAM adressing mask */
NV_REG8(NV8_PAL2MASK) = 0xff;
LOG(2,("DAC2: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PAL2MASK)));
return B_OK;
}
/*program the DAC palette using the given r,g,b values*/
status_t nv_dac2_palette(uint8 r[256],uint8 g[256],uint8 b[256])
{
int i;
LOG(4,("DAC2: setting palette\n"));
/* select first PAL adress before starting programming */
NV_REG8(NV8_PAL2INDW) = 0x00;
/* loop through all 256 to program DAC */
for (i = 0; i < 256; i++)
{
/* the 6 implemented bits are on b0-b5 of the bus */
NV_REG8(NV8_PAL2DATA) = r[i];
NV_REG8(NV8_PAL2DATA) = g[i];
NV_REG8(NV8_PAL2DATA) = b[i];
}
if (NV_REG8(NV8_PAL2INDW) != 0x00)
{
LOG(8,("DAC2: PAL write index incorrect after programming\n"));
return B_ERROR;
}
if (1)
{//reread LUT
uint8 R, G, B;
/* select first PAL adress to read (modulo 3 counter) */
NV_REG8(NV8_PAL2INDR) = 0x00;
for (i = 0; i < 256; i++)
{
R = NV_REG8(NV8_PAL2DATA);
G = NV_REG8(NV8_PAL2DATA);
B = NV_REG8(NV8_PAL2DATA);
if ((r[i] != R) || (g[i] != G) || (b[i] != B))
LOG(1,("DAC2 palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
}
}
return B_OK;
}
/*program the pixpll - frequency in kHz*/
status_t nv_dac2_set_pix_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
// uint time = 0;
float pix_setting, req_pclk;
status_t result;
/* we offer this option because some panels have very tight restrictions,
* and there's no overlapping settings range that makes them all work.
* note:
* this assumes the cards BIOS correctly programmed the panel (is likely) */
//fixme: when VESA DDC EDID stuff is implemented, this option can be deleted...
if (si->ps.tmds2_active && !si->settings.pgm_panel)
{
LOG(4,("DAC2: Not programming DFP refresh (specified in nv.settings)\n"));
return B_OK;
}
/* fix a DVI or laptop flatpanel to 60Hz refresh! */
/* Note:
* The pixelclock drives the flatpanel modeline, not the CRTC modeline. */
if (si->ps.tmds2_active)
{
LOG(4,("DAC2: Fixing DFP refresh to 60Hz!\n"));
/* use the panel's modeline to determine the needed pixelclock */
target.timing.pixel_clock = si->ps.p2_timing.pixel_clock;
}
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC2: Setting PIX PLL for pixelclock %f\n", req_pclk));
/* signal that we actually want to set the mode */
result = nv_dac2_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*reprogram (disable,select,wait for stability,enable)*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
/* program new frequency */
DAC2W(PIXPLLC, ((p << 16) | (n << 8) | m));
/* program 2nd set N and M scalers if they exist (b31=1 enables them) */
if (si->ps.ext_pll) DAC2W(PIXPLLC2, 0x80000401);
/* Wait for the PIXPLL frequency to lock until timeout occurs */
//fixme: do NV cards have a LOCK indication bit??
/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: PIX PLL frequency not locked!\n"));
else
LOG(2,("DAC: PIX PLL frequency locked\n"));
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL
*/
//for now:
/* Give the PIXPLL frequency some time to lock... */
snooze(1000);
LOG(2,("DAC2: PIX PLL frequency should be locked now...\n"));
return B_OK;
}
/* find nearest valid pix pll */
status_t nv_dac2_pix_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
switch (si->ps.card_type) {
default: return nv10_nv20_dac2_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
}
return B_ERROR;
}
/* find nearest valid pixel PLL setting */
static status_t nv10_nv20_dac2_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0, p = 0/*, m_max*/;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
/* switch(si->ps.card_type)
{
case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
*/
LOG(4,("DAC2: NV10/NV20 restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_video_vco / 16.0))
{
LOG(4,("DAC2: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 16.0)));
req_pclk = (si->ps.min_video_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("DAC2: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco /= 4;
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 7; m <= 14; m++)
{
/* check if phase-discriminator will be within operational limits */
//fixme: PLL calcs will be resetup/splitup/updated...
if (si->ps.card_type == NV36)
{
if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue;
}
else
{
if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue;
}
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 1) || (n > 255)) continue;
/* find error in frequency this setting gives */
if (si->ps.ext_pll)
{
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p));
}
else
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m = best[0];
n = best[1];
p = best[2];
/* log the VCO frequency found */
f_vco = ((si->ps.f_ref / m) * n);
/* FX5600 and FX5700 tweak for 2nd set N and M scalers */
if (si->ps.ext_pll) f_vco *= 4;
LOG(2,("DAC2: pix VCO frequency found %fMhz\n", f_vco));
/* return the results */
*calc_pclk = (f_vco / p);
*m_result = m;
*n_result = n;
switch(p)
{
case 1:
p = 0x00;
break;
case 2:
p = 0x01;
break;
case 4:
p = 0x02;
break;
case 8:
p = 0x03;
break;
case 16:
p = 0x04;
break;
}
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC2: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,35 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 8/2004
*/
#include "nv_std.h"
int fd;
shared_info *si;
area_id shared_info_area;
vuint32 *regs;
area_id regs_area;
display_mode *my_mode_list;
area_id my_mode_list_area;
int accelerantIsClone;
nv_get_set_pci nv_pci_access=
{
NV_PRIVATE_DATA_MAGIC,
0,
4,
0
};
nv_in_out_isa nv_isa_access=
{
NV_PRIVATE_DATA_MAGIC,
0,
1,
0
};
@@ -0,0 +1,66 @@
extern int fd;
extern shared_info *si;
extern area_id shared_info_area;
extern area_id regs_area;
extern vuint32 *regs;
extern display_mode *my_mode_list;
extern area_id my_mode_list_area;
extern int accelerantIsClone;
extern nv_get_set_pci nv_pci_access;
extern nv_in_out_isa nv_isa_access;
typedef status_t (*crtc_validate_timing)(uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*);
typedef status_t (*crtc_set_timing)(display_mode);
typedef status_t (*crtc_depth)(int);
typedef status_t (*crtc_dpms)(bool, bool, bool);
typedef status_t (*crtc_dpms_fetch)(bool*, bool*, bool*);
typedef status_t (*crtc_set_display_pitch)(void);
typedef status_t (*crtc_set_display_start)(uint32, uint8);
typedef status_t (*crtc_cursor_init)(void);
typedef status_t (*crtc_cursor_show)(void);
typedef status_t (*crtc_cursor_hide)(void);
typedef status_t (*crtc_cursor_define)(uint8*, uint8*);
typedef status_t (*crtc_cursor_position)(uint16, uint16);
typedef status_t (*dac_mode)(int, float);
typedef status_t (*dac_palette)(uint8[256], uint8[256], uint8[256]);
typedef status_t (*dac_set_pix_pll)(display_mode);
typedef status_t (*dac_pix_pll_find)(display_mode, float*, uint8*, uint8*, uint8*, uint8);
crtc_validate_timing head1_validate_timing;
crtc_set_timing head1_set_timing;
crtc_depth head1_depth;
crtc_dpms head1_dpms;
crtc_dpms_fetch head1_dpms_fetch;
crtc_set_display_pitch head1_set_display_pitch;
crtc_set_display_start head1_set_display_start;
crtc_cursor_init head1_cursor_init;
crtc_cursor_show head1_cursor_show;
crtc_cursor_hide head1_cursor_hide;
crtc_cursor_define head1_cursor_define;
crtc_cursor_position head1_cursor_position;
crtc_validate_timing head2_validate_timing;
crtc_set_timing head2_set_timing;
crtc_depth head2_depth;
crtc_dpms head2_dpms;
crtc_dpms_fetch head2_dpms_fetch;
crtc_set_display_pitch head2_set_display_pitch;
crtc_set_display_start head2_set_display_start;
crtc_cursor_init head2_cursor_init;
crtc_cursor_show head2_cursor_show;
crtc_cursor_hide head2_cursor_hide;
crtc_cursor_define head2_cursor_define;
crtc_cursor_position head2_cursor_position;
dac_mode head1_mode;
dac_palette head1_palette;
dac_set_pix_pll head1_set_pix_pll;
dac_pix_pll_find head1_pix_pll_find;
dac_mode head2_mode;
dac_palette head2_palette;
dac_set_pix_pll head2_set_pix_pll;
dac_pix_pll_find head2_pix_pll_find;
@@ -0,0 +1,348 @@
/*
* i2c interface for the G400 MAVEN under BeOS
*
* Provides I2CR,I2CW - functions to parallel DACW,DACR
* Bus should be run at max. 100kHz: see original Philips I2C specification
*
* Much help was provided by observing the Linux i2c code,
* so thanks go to: Gerd Knorr
*
* Other authors:
* Mark Watson 6/2000,
* Rudolf Cornelissen 12/2002-12/2003
*/
#define MODULE_BIT 0x00004000
#include "nv_std.h"
int i2c_set_lines(int clock, int data);
int i2c_get_data(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high(void);
void i2c_low(void);
int i2c_get_ack(void);
void i2c_send_ack(void);
int i2c_sendbyte(unsigned char data);
unsigned char i2c_readbyte(int ack_required);
/*which device on the bus is the MAVEN?*/
#define MAVEN_WRITE (0x1B<<1)
#define MAVEN_READ ((0x1B<<1)|1)
#define I2C_CLOCK 0x20
#define I2C_DATA 0x10
/* NV-TVO I2C for G200, G400 */
#define I2C_CLOCK 0x20
#define I2C_DATA 0x10
/* primary head DDC for Mystique(?), G100, G200, G400 */
#define DDC1_CLK 0x08
#define DDC1_DATA 0x02
/* primary head DDC for Millennium, Millennium II */
#define DDC1B_CLK 0x10
#define DDC1B_DATA 0x04
/* secondary head DDC for G400, G450 and G550 */
#define DDC2_CLK 0x04
#define DDC2_DATA 0x01
status_t i2c_sec_tv_adapter()
{
status_t result = B_ERROR;
/* The secondary DDC channel only exist on dualhead cards */
if (!si->ps.secondary_head) return result;
/* make sure the output lines will be active-low when enabled
* (they will be pulled 'passive-high' when disabled) */
// DXIW(GENIODATA,0x00);
/* send out B_STOP condition on secondary head DDC channel and use it to
* check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */
/* make sure SDA is low */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA));
snooze(2);
/* make sure SCL should be high */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK));
snooze(2);
/* if SCL is low then the bus is blocked by a TV adapter */
// if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK;
snooze(5);
/* set SDA while SCL should be set (generates actual bus-stop condition) */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA));
snooze(5);
return result;
}
/*-----------------------------
*low level hardware access
*/
#define I2C_DELAY 2
#define I2C_TIMEOUT 100
int i2c_set_lines(int clock,int data)
{
int count=0;
int program;
int required;
/*work out which bits to zero*/
program =
(clock ? 0 : I2C_CLOCK)|
(data ? 0 : I2C_DATA);
/*what value do I require on data lines*/
required =
(clock ? I2C_CLOCK : 0);
/*set the bits to zero*/
// DXIW(GENIOCTRL,program); /*drive these bits*/
// DXIW(GENIODATA,0x00); /*to zero*/
/*wait a bit*/
delay(I2C_DELAY);
/*loop until the clock is as required*/
// while ((DXIR(GENIODATA)&I2C_CLOCK)!=required)
{
delay(I2C_DELAY);
count++;
if (count>I2C_TIMEOUT)
{
// LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA)));
return -1;
}
}
return 0;
}
int i2c_get_data()
{
int data = 0;
int clock;
int count=0;
do
{
/*read the data and clock lines*/
// data = DXIR(GENIODATA);
clock = (data&I2C_CLOCK) ? 1 : 0;
data = (data&I2C_DATA) ? 1 : 0;
/*manage timeout*/
count++;
if (count>I2C_TIMEOUT)
{
return -1;
}
/*wait a bit, so not hammering bus*/
delay(I2C_DELAY);
}while (!clock); /*wait for high clock*/
return data;
}
/*-----------------------
*Standard I2C operations
*/
void i2c_start()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: start - %d\n",error));
}
}
void i2c_stop()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: stop - %d\n",error));
}
}
void i2c_high()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: high - %d\n",error));
}
}
void i2c_low()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: low - %d\n",error));
}
}
int i2c_get_ack()
{
int error=0;
int ack;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
ack = i2c_get_data();
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: get_ack - %d value:%x\n",error,ack));
}
return ack;
}
void i2c_send_ack()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: send_ack - %d\n",error));
}
}
/*------------------------------
*use above functions to send and receive bytes
*/
int i2c_sendbyte(unsigned char data)
{
int i;
for (i=7; i>=0; i--)
{
if (data&(1<<i))
{
i2c_high();
}
else
{
i2c_low();
}
}
return i2c_get_ack();
}
unsigned char i2c_readbyte(int ack_required)
{
int i;
unsigned char data=0;
/*read data*/
i2c_set_lines(0,1);
for (i=7; i>=0; i--)
{
i2c_set_lines(1,1);
if (i2c_get_data()==1)
data |= (1<<i);
i2c_set_lines(0,1);
}
/*send acknowledge*/
if (ack_required) i2c_send_ack();
return data;
}
/*-------------------------------------------
*PUBLIC functions
*/
int i2c_maven_read(unsigned char address)
{
int error=0;
int data;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_READ);
error+=i2c_sendbyte(address);
data = i2c_readbyte(0);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVR ERROR - %x\n",error));
return data;
}
void i2c_maven_write(unsigned char address, unsigned char data)
{
int error=0;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_WRITE);
error+=i2c_sendbyte(address);
error+=i2c_sendbyte(data);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVW ERROR - %x\n",error));
}
status_t i2c_init(void)
{
/*init g400 i2c*/
// DXIW(GENIODATA,0x00); /*to zero*/
// DXIW(GENIOCTRL,0x30); /*drive clock and data*/
// DXIW(GENIOCTRL,0x00); /*stop driving*/
return B_OK;
}
status_t i2c_maven_probe(void)
{
int ack;
/*scan the bus for the MAVEN*/
i2c_start();
{
ack = i2c_sendbyte(MAVEN_READ);
}
i2c_stop();
if (ack==0)
{
return B_OK;
}
else
{
return B_ERROR;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,130 @@
/* general card functions */
status_t nv_general_powerup(void);
status_t nv_set_cas_latency(void);
void setup_virtualized_heads(bool);
void set_crtc_owner(bool);
status_t nv_general_output_select(bool);
status_t nv_general_head_select(bool);
status_t nv_general_wait_retrace(void);
status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode);
/* AGP functions */
status_t nv_agp_setup(void);
/* apsed: logging macros */
#define MSG(args) do { /* if needed or si->settings with si NULL */ \
nv_log args; \
} while (0)
#define LOG(level_bit, args) do { \
uint32 mod = (si->settings.logmask & 0xfffffff0) & MODULE_BIT; \
uint32 lev = (si->settings.logmask & ~0xfffffff0) & level_bit; \
if (mod && lev) nv_log args; \
} while (0)
/* support functions */
void delay(bigtime_t i);
void nv_log(char *format, ...);
/* i2c functions */
int i2c_maven_read(unsigned char address);
void i2c_maven_write(unsigned char address, unsigned char data);
status_t i2c_init(void);
status_t i2c_maven_probe(void);
/* card info functions */
status_t parse_pins(void);
void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2);
void fake_panel_start(void);
void set_specs(void);
void dump_pins(void);
/* DAC functions */
bool nv_dac_crt_connected(void);
status_t nv_dac_mode(int,float);
status_t nv_dac_palette(uint8*,uint8*,uint8*);
status_t nv_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8);
status_t nv_dac_set_pix_pll(display_mode target);
status_t nv_dac_sys_pll_find(float, float*, uint8*, uint8*, uint8*, uint8);
/* DAC2 functions */
bool nv_dac2_crt_connected(void);
status_t nv_dac2_mode(int,float);
status_t nv_dac2_palette(uint8*,uint8*,uint8*);
status_t nv_dac2_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8);
status_t nv_dac2_set_pix_pll(display_mode target);
/*MAVENTV functions*/
status_t g100_g400max_maventv_vid_pll_find(
display_mode target, unsigned int * ht_new, unsigned int * ht_last_line,
uint8 * m_result, uint8 * n_result, uint8 * p_result);
int maventv_init(display_mode target);
/* CRTC1 functions */
status_t nv_crtc_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
);
status_t nv_crtc_set_timing(display_mode target);
status_t nv_crtc_depth(int mode);
status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp);
status_t nv_crtc_set_display_pitch(void);
status_t nv_crtc_dpms(bool, bool, bool);
status_t nv_crtc_dpms_fetch(bool*, bool*, bool*);
status_t nv_crtc_mem_priority(uint8);
status_t nv_crtc_cursor_init(void); /*Yes, cursor follows CRTC1 - not the DAC!*/
status_t nv_crtc_cursor_define(uint8*,uint8*);
status_t nv_crtc_cursor_position(uint16 x ,uint16 y);
status_t nv_crtc_cursor_show(void);
status_t nv_crtc_cursor_hide(void);
/* CRTC2 functions */
status_t nv_crtc2_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
);
status_t nv_crtc2_set_timing(display_mode target);
status_t nv_crtc2_depth(int mode);
status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp);
status_t nv_crtc2_set_display_pitch(void);
status_t nv_crtc2_dpms(bool, bool, bool);
status_t nv_crtc2_dpms_fetch(bool*, bool*, bool*);
status_t nv_crtc2_mem_priority(uint8);
status_t nv_crtc2_cursor_init(void);
status_t nv_crtc2_cursor_define(uint8*,uint8*);
status_t nv_crtc2_cursor_position(uint16 x ,uint16 y);
status_t nv_crtc2_cursor_show(void);
status_t nv_crtc2_cursor_hide(void);
/* acceleration functions */
status_t check_acc_capability(uint32 feature);
status_t nv_acc_init(void);
status_t nv_acc_setup_blit(void);
status_t nv_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 );
status_t nv_acc_setup_rectangle(uint32 color);
status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl);
status_t nv_acc_setup_rect_invert(void);
status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl);
status_t nv_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32);
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
uint16 xd,uint16 yd,uint16 wd,uint16 hd);
status_t nv_acc_wait_idle(void);
/* backend scaler functions */
status_t check_overlay_capability(uint32 feature);
void nv_bes_move_overlay(void);
status_t nv_bes_to_crtc(bool crtc);
status_t nv_bes_init(void);
status_t nv_configure_bes
(const overlay_buffer *ob, const overlay_window *ow,const overlay_view *ov, int offset);
status_t nv_release_bes(void);
/* I2C functions */
status_t i2c_sec_tv_adapter(void);
/* driver structures and enums */
enum{BPP8 = 0, BPP15 = 1, BPP16 = 2, BPP24 = 3, BPP32 = 4};
enum{DS_CRTC1DAC_CRTC2MAVEN, DS_CRTC1MAVEN_CRTC2DAC, DS_CRTC1CON1_CRTC2CON2, DS_CRTC1CON2_CRTC2CON1};
@@ -0,0 +1,9 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <math.h>
#include <OS.h>
#include "DriverInterface.h"
#include "nv_globals.h"
//apsed #include "nv_extern.h"
#include "nv_proto.h"
#include "nv_macros.h"
@@ -0,0 +1,34 @@
/* Some commmon support functions */
/* Mark Watson 2/2000;
* Rudolf Cornelissen 1/2004 */
#define MODULE_BIT 0x00000800
#include <stdarg.h>
#include "nv_std.h"
/*delays in multiple of microseconds*/
void delay(bigtime_t i)
{
bigtime_t start=system_time();
while(system_time()-start<i);
}
/*debug logging*/
void nv_log(char *fmt, ...)
{
char buffer[1024];
char fname[64];
FILE *myhand;
va_list args;
sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.%d.log", accelerantIsClone);
myhand=fopen(fname,"a+");
if (myhand == NULL) return;
va_start(args,fmt);
vsprintf (buffer, fmt, args);
fprintf(myhand, "%s", buffer);
fclose(myhand);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
/*This file can be used to define custom timing for your monitor
* The format of each line is:
* {
* pixel clock frequency (kHz)
* width
* h-sync pulse start
* h-sync pulse end
* total pixels in line
* height
* v-sync pulse start
* v-sync pulse end
* total lines in frame
* sync polarity (0 is -ve,B_POSITIVE_HYSNC,B_POSITIVE_VSYNC)
* }
*
*To use this you must:
* Uncomment VALID MODE REQUIRED
* Fill in a number of modes that work with your display
* Change VALID MODES from three to the no. you defined
* run these commands:
* touch ProposeDisplayMode.c
* make install
*/
//#define VALID_MODE_REQUIRED 1
#define VALID_MODES 3
/*note colour depth and mode flags are ignored*/
static const display_timing valid_mode_list[] = {
{31500,640,648,744,840,480,481,500,500,0},
{49500,800,808,888,1056,600,601,620,625,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC},
{78750,1024,1032,1128,1312,768,769,788,800,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC}
};