add nvidia accelerant

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5450 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2003-11-23 05:30:55 +00:00
parent 6e2d4bbc30
commit 08705d9664
26 changed files with 8790 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
SubDir OBOS_TOP src add-ons accelerants ;
SubInclude OBOS_TOP src add-ons accelerants nvidia ;
@@ -0,0 +1,135 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 2/2003.
*/
#define MODULE_BIT 0x40000000
// apsed, TODO ?? change interface of nv_acc_* and use NV pseudo DMA
#include "acc_std.h"
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
nv_acc_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height
);
i++;
}
}
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
nv_acc_video_blit
(
list[i].src_left,
list[i].src_top,
list[i].src_width,
list[i].src_height,
list[i].dest_left,
list[i].dest_top,
list[i].dest_width,
list[i].dest_height
);
i++;
}
}
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
nv_acc_transparent_blit
(
list[i].src_left,
list[i].src_top,
list[i].dest_left,
list[i].dest_top,
list[i].width,
list[i].height,
transparent_colour
);
i++;
}
}
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) {
int i;
/*draw each rectangle*/
i=0;
while (count--)
{
nv_acc_rectangle
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1,
colorIndex
);
i++;
}
}
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
int i;
/*draw each rectangle*/
i=0;
while (count--)
{
nv_acc_rectangle_invert
(
list[i].left,
(list[i].right)+1,
list[i].top,
(list[i].bottom-list[i].top)+1,
0
);
i++;
}
}
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
int i;
/*draw each span*/
i=0;
while (count--)
{
nv_acc_rectangle
(
list[i+1],
list[i+2]+1,
list[i],
1,
colorIndex
);
i+=3;
}
}
+165
View File
@@ -0,0 +1,165 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 4/2003
*/
#define MODULE_BIT 0x20000000
/*DUALHEAD notes -
No hardware cursor possible on the secondary head :(
Reasons:
CRTC1 has a cursor, can be displayed on DAC or MAVEN
CRTC2 has no cursor
Can not switch CRTC in one vblank (has to resync)
CRTC2 does not support split screen
app_server does not support some modes with and some without cursor
virtual not supported, because of MAVEN blanking issues
*/
#include "acc_std.h"
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask)
{
LOG(4,("SET_CURSOR_SHAPE: width %d, height %d\n", width, height));
if ((width != 16) || (height != 16))
{
return B_ERROR;
}
else if ((hot_x >= width) || (hot_y >= height))
{
return B_ERROR;
}
else
{
nv_crtc_cursor_define(andMask,xorMask);
/* Update cursor variables appropriately. */
si->cursor.width = width;
si->cursor.height = height;
si->cursor.hot_x = hot_x;
si->cursor.hot_y = hot_y;
}
return B_OK;
}
/* Move the cursor to the specified position on the desktop, taking account of virtual/dual issues */
void MOVE_CURSOR(uint16 x, uint16 y)
{
uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */
uint16 vds = si->dm.v_display_start; /* the current vertical starting line */
uint16 h_adjust;
/* clamp cursor to display */
if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1;
if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1;
/* store, for our info */
si->cursor.x = x;
si->cursor.y = y;
/*set up minimum amount to scroll*/
if (si->dm.flags & DUALHEAD_BITS)
{
/* fixme???? Nvidia always does pixelprecise panning on sec head?? */
switch(si->dm.space)
{
case B_RGB16_LITTLE:
h_adjust = 0x1f;
break;
case B_RGB32_LITTLE:
h_adjust = 0x0f;
break;
default:
h_adjust = 0x1f;
break;
}
}
else
{
/* switch(si->dm.space)
{
case B_CMAP8:
h_adjust = 0x07;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
h_adjust = 0x03;
break;
case B_RGB32_LITTLE:
h_adjust = 0x01;
break;
default:
h_adjust = 0x07;
break;
}
*/
/* Nvidia always does pixelprecise panning on primary head */
h_adjust = 0x00;
}
/* adjust h/v_display_start to move cursor onto screen */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (x >= ((si->dm.timing.h_display * 2) + hds))
{
hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
default:
if (x >= (si->dm.timing.h_display + hds))
{
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + si->dm.timing.h_display) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
}
if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1;
else if (y < vds)
vds = y;
/* reposition the desktop _and_ the overlay on the display if required */
if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
{
MOVE_DISPLAY(hds,vds);
//fixme: implement:
//move_overlay(hds,vds);
}
/* put cursor in correct physical position */
x -= hds + si->cursor.hot_x;
y -= vds + si->cursor.hot_y;
/* account for switched CRTC's */
if (si->switched_crtcs) x -= si->dm.timing.h_display;
/* position the cursor on the display */
nv_crtc_cursor_position(x,y);
}
void SHOW_CURSOR(bool is_visible)
{
/* record for our info */
si->cursor.is_visible = is_visible;
if (is_visible)
nv_crtc_cursor_show();
else
nv_crtc_cursor_hide();
}
@@ -0,0 +1,68 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
modification to call G400 functions and mess-ups - Mark Watson
*/
#define MODULE_BIT 0x10000000
#include "acc_std.h"
static engine_token nv_engine_token = { 1, B_2D_ACCELERATION, NULL };
uint32 ACCELERANT_ENGINE_COUNT(void) {
return 1;
}
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et) {
/* acquire the shared benaphore */
AQUIRE_BEN(si->engine.lock)
/* sync if required */
if (st) SYNC_TO_TOKEN(st);
/* return an engine token */
*et = &nv_engine_token;
return B_OK;
}
status_t RELEASE_ENGINE(engine_token *et, sync_token *st) {
/* update the sync token, if any */
if (st) {
GET_SYNC_TOKEN(et,st);
}
/* release the shared benaphore */
RELEASE_BEN(si->engine.lock)
return B_OK;
}
void WAIT_ENGINE_IDLE(void) {
uint32 count;
/*wait for the engine to be totally idle*/
count = si->engine.count;
nv_acc_wait_idle();
si->engine.last_idle = count;
}
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) {
si->engine.count+=4;
st->engine_id = et->engine_id;
st->counter = si->engine.count;
return B_OK;
}
status_t SYNC_TO_TOKEN(sync_token *st) {
/* a quick out */
if (st->counter <= si->engine.last_idle) return B_OK;
/* another quick out! */
if ((st->counter >0xFFFFFFF) && (si->engine.last_idle <0xFFFF)) return B_OK; /*for when counter wraps*/
/* If not we have to wait :-(*/
WAIT_ENGINE_IDLE();
return B_OK;
}
@@ -0,0 +1,241 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002-4/2003
*/
#define MODULE_BIT 0x08000000
#include "acc_std.h"
/*
The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper
function. The extra information (which is specific to the feature) is
pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be
noted on a case by case below.
*/
/*
These definitions are out of pure lazyness.
*/
#define CHKO(x) case B_##x: \
if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define CHKA(x) case B_##x: \
if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed
void * get_accelerant_hook(uint32 feature, void *data)
{
switch (feature)
{
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
/* initialization */
HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT);
HOOK(ACCELERANT_CLONE_INFO_SIZE);
HOOK(GET_ACCELERANT_CLONE_INFO);
HOOK(UNINIT_ACCELERANT);
HOOK(GET_ACCELERANT_DEVICE_INFO);
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
/* mode configuration */
HOOK(ACCELERANT_MODE_COUNT);
HOOK(GET_MODE_LIST);
HOOK(PROPOSE_DISPLAY_MODE);
HOOK(SET_DISPLAY_MODE);
HOOK(GET_DISPLAY_MODE);
HOOK(GET_FRAME_BUFFER_CONFIG);
HOOK(GET_PIXEL_CLOCK_LIMITS);
HOOK(MOVE_DISPLAY);
HOOK(SET_INDEXED_COLORS);
HOOK(GET_TIMING_CONSTRAINTS);
HOOK(DPMS_CAPABILITIES);
HOOK(DPMS_MODE);
HOOK(SET_DPMS_MODE);
/* cursor managment */
HRDC(SET_CURSOR_SHAPE);
HRDC(MOVE_CURSOR);
HRDC(SHOW_CURSOR);
/* synchronization */
HOOK(ACCELERANT_ENGINE_COUNT);
HOOK(ACQUIRE_ENGINE);
HOOK(RELEASE_ENGINE);
HOOK(WAIT_ENGINE_IDLE);
HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_TOKEN);
/*
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth for example.
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export video overlay functions if card is capable of it */
CHKO(OVERLAY_COUNT);
CHKO(OVERLAY_SUPPORTED_SPACES);
CHKO(OVERLAY_SUPPORTED_FEATURES);
CHKO(ALLOCATE_OVERLAY_BUFFER);
CHKO(RELEASE_OVERLAY_BUFFER);
CHKO(GET_OVERLAY_CONSTRAINTS);
CHKO(ALLOCATE_OVERLAY);
CHKO(RELEASE_OVERLAY);
CHKO(CONFIGURE_OVERLAY);
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export 2D acceleration functions in modes that are capable of it */
/* used by the app_server and applications (BWindowScreen) */
CHKA(SCREEN_TO_SCREEN_BLIT);
CHKA(FILL_RECTANGLE);
CHKA(INVERT_RECTANGLE);
CHKA(FILL_SPAN);
/* not (yet) used by the app_server:
* so just for application use (BWindowScreen) */
CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);
//CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
}
/* Return a null pointer for any feature we don't understand. */
return 0;
}
#undef CHKO
#undef CHKA
#undef HOOK
#undef ZERO
#undef HRDC
status_t check_overlay_capability(uint32 feature)
{
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_OVERLAY_COUNT:
msg = "B_OVERLAY_COUNT";
break;
case B_OVERLAY_SUPPORTED_SPACES:
msg = "B_OVERLAY_SUPPORTED_SPACES";
break;
case B_OVERLAY_SUPPORTED_FEATURES:
msg = "B_OVERLAY_SUPPORTED_FEATURES";
break;
case B_ALLOCATE_OVERLAY_BUFFER:
msg = "B_ALLOCATE_OVERLAY_BUFFER";
break;
case B_RELEASE_OVERLAY_BUFFER:
msg = "B_RELEASE_OVERLAY_BUFFER";
break;
case B_GET_OVERLAY_CONSTRAINTS:
msg = "B_GET_OVERLAY_CONSTRAINTS";
break;
case B_ALLOCATE_OVERLAY:
msg = "B_ALLOCATE_OVERLAY";
break;
case B_RELEASE_OVERLAY:
msg = "B_RELEASE_OVERLAY";
break;
case B_CONFIGURE_OVERLAY:
msg = "B_CONFIGURE_OVERLAY";
break;
default:
msg = "UNKNOWN";
break;
}
//temp disabled:
if (si->ps.card_type > G550)
{
/* export video overlay functions */
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
return B_OK;
}
/* do not export video overlay functions */
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
return B_ERROR;
}
status_t check_acc_capability(uint32 feature)
{
bool fill = false;
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_SCREEN_TO_SCREEN_BLIT:
msg = "B_SCREEN_TO_SCREEN_BLIT";
break;
case B_FILL_RECTANGLE:
msg = "B_FILL_RECTANGLE";
fill = true;
break;
case B_INVERT_RECTANGLE:
msg = "B_INVERT_RECTANGLE";
fill = true;
break;
case B_FILL_SPAN:
msg = "B_FILL_SPAN";
fill = true;
break;
case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT:
msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT";
break;
case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT:
msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT";
break;
default:
msg = "UNKNOWN";
break;
}
/* hardware acceleration is only supported in modes with upto a certain
* memory pitch.. */
if (si->acc_mode)
{
/* see if we support hardware rectangle fills in the current mode:
* the Matrox card's acc engine can adress upto 16Mbyte memory for this cmd! */
if (fill &&
((si->fbc.bytes_per_row * si->dm.virtual_height) > (16 * 1024 * 1024)))
{
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
return B_ERROR;
}
LOG(4, ("Acc: Exporting hook %s.\n", msg));
return B_OK;
}
else
{
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
return B_ERROR;
}
}
@@ -0,0 +1,51 @@
/*
Authors:
Mark Watson - 21/6/00,
Apsed
*/
#define MODULE_BIT 0x04000000
#include "acc_std.h"
/* Get some info about the device */
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi)
{
/*no info on version is provided, so presumably this is for my info*/
LOG(4,("DEVICE_INFO: version 0x%08x\n", adi->version));
switch ((si->ps.secondary_head << 4)|si->ps.card_type)
{
case 0x01:
sprintf(adi->name,"Matrox G400 Plain");
break;
case 0x02:
sprintf(adi->name,"Matrox G400 MAX");
break;
case 0x11:
sprintf(adi->name,"Matrox Dualhead G400 Plain");
break;
case 0x12:
sprintf(adi->name,"Matrox Dualhead G400 MAX");
break;
}
sprintf(adi->chipset,"NVG400");
sprintf(adi->serial_no,"01134"); /*FIXME*/
adi->memory=si->ps.memory_size * 1024 * 1024;
adi->dac_speed=si->ps.max_dac1_clock;
// apsed, TODO ?? GET_ACCELERANT_DEVICE_INFO never called and kind of cards
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "version", adi->version, adi->version));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "name", adi->name));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "chipset", adi->chipset));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "serial_no", adi->serial_no));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "memory", adi->memory, adi->memory));
LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %d\n", "dac_speed", adi->dac_speed));
return B_OK;
}
@@ -0,0 +1,134 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
Rudolf Cornelissen 9-11/2002
*/
#define MODULE_BIT 0x02000000
#include "acc_std.h"
/*
Return the current display mode. The only time you might return an
error is if a mode hasn't been set. Or if the system hands you a NULL pointer.
*/
status_t GET_DISPLAY_MODE(display_mode *current_mode)
{
/* check for NULL pointer */
if (current_mode == NULL) return B_ERROR;
*current_mode = si->dm;
return B_OK;
}
/* Return the frame buffer configuration information. */
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb)
{
/* check for NULL pointer */
if (afb == NULL) return B_ERROR;
*afb = si->fbc;
return B_OK;
}
/* Return the maximum and minium pixelclock limits for the specified mode. */
/* Rewritten / fixed by Rudolf */
/* NOTE:
* Due to BeOS constraints output for all heads will be limited to the head with
* the least capabilities. (BeOS should ask for seperate constraints for all heads.) */
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high)
{
uint32 max_pclk = 0;
uint32 min_pclk = 0;
/* check for NULL pointers */
if ((dm == NULL) || (low == NULL) || (high == NULL)) return B_ERROR;
/* specify requested info */
if (dm->flags & DUALHEAD_BITS)
{
/* dualhead mode */
/* find min. value */
switch (si->ps.card_type)
{
default:
*low = ((si->ps.min_video_vco * 1000) / 16);
break;
}
/* find max. value */
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
/* specially noted because of RAM speed constraints! */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32dh;
break;
}
/* return values in kHz */
*high = max_pclk * 1000;
}
else
{
/* singlehead mode */
/* find min. value */
switch (si->ps.card_type)
{
default:
*low = ((si->ps.min_pixel_vco * 1000) / 16);
break;
}
/* find max. value */
switch (dm->space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* return values in kHz */
*high = max_pclk * 1000;
}
/* clamp lower limit to 48Hz vertical refresh for now.
* Apparantly the BeOS screenprefs app does limit the upper refreshrate to 90Hz,
* while it does not limit the lower refreshrate. */
min_pclk = ((uint32)dm->timing.h_total * (uint32)dm->timing.v_total * 48) / 1000;
if (min_pclk > *low) *low = min_pclk;
return B_OK;
}
/* Return the semaphore id that will be used to signal a vertical sync occured. */
sem_id ACCELERANT_RETRACE_SEMAPHORE(void)
{
return si->vblank;
}
@@ -0,0 +1,30 @@
/*
Authors:
Mark Watson - 21/6/00,
Apsed
*/
#define MODULE_BIT 0x01000000
#include "acc_std.h"
/* Used to help generate mode lines */
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc)
{
// apsed, TODO, is that following card capabilities ??
LOG(4, ("GET_TIMING_CONSTRAINTS\n"));
dtc->h_res=8;
dtc->h_sync_min=8;
dtc->h_sync_max=248;
dtc->h_blank_min=8;
dtc->h_blank_max=504;
dtc->v_res=1;
dtc->v_sync_min=1;
dtc->v_sync_max=15;
dtc->v_blank_min=1;
dtc->v_blank_max=255;
return B_OK;
}
@@ -0,0 +1,26 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
*/
#include "acc_std.h"
int fd;
shared_info *si;
area_id shared_info_area;
vuint32 *regs;
area_id regs_area;
display_mode *my_mode_list;
area_id my_mode_list_area;
int accelerantIsClone;
nv_get_set_pci nv_pci_access=
{
NV_PRIVATE_DATA_MAGIC,
0,
4,
0
};
@@ -0,0 +1,299 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002-7/2003.
*/
#define MODULE_BIT 0x00800000
#include <string.h>
#include "acc_std.h"
/* defined in ProposeDisplayMode.c */
extern status_t create_mode_list(void);
static status_t init_common(int the_fd);
/* Initialization code shared between primary and cloned accelerants */
static status_t init_common(int the_fd) {
status_t result;
nv_get_private_data gpd;
// LOG not available from here to next LOG: NULL si
/* memorize the file descriptor */
fd = the_fd;
/* set the magic number so the driver knows we're for real */
gpd.magic = NV_PRIVATE_DATA_MAGIC;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, NV_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
if (result != B_OK) goto error0;
/* clone the shared area for our use */
shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
if (shared_info_area < 0) {
result = shared_info_area;
goto error0;
}
// LOG is now available, si !NULL
LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, greensync %d\n",
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync));
/*Check for R4.5.0 and if it is running, use work around*/
{
if (si->use_clone_bugfix)
{
/*check for R4.5.0 bug and attempt to work around*/
LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
regs = si->clone_bugfix_regs;
}
else
{
/* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/
regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&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 (1) {
time_t now = time (NULL);
// LOG not available from here to next LOG: NULL si
// MSG(("INIT_ACCELERANT: booted since %f ms %s\n", system_time()/1000.0, real_time_clock()));
MSG(("INIT_ACCELERANT: %s", ctime (&now)));
}
/* note that we're the primary accelerant (accelerantIsClone is global) */
accelerantIsClone = 0;
/* do the initialization common to both the primary and the clones */
result = init_common(the_fd);
/* bail out if the common initialization failed */
if (result != B_OK) goto error0;
// LOG now available: !NULL si
/* call the device specific init code */
result = nv_general_powerup();
/* bail out if it failed */
if (result != B_OK) goto error1;
/*
Now would be a good time to figure out what video modes your card supports.
We'll place the list of modes in another shared area so all of the copies
of the driver can see them. The primary copy of the accelerant (ie the one
initialized with this routine) will own the "one true copy" of the list.
Everybody else get's a read-only clone.
*/
result = create_mode_list();
if (result != B_OK)
{
goto error1;
}
/*
Put the cursor at the start of the frame buffer.
Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM.
*/
/* Initialize the rest of the cursor information while we're here */
si->cursor.width = 16;
si->cursor.height = 16;
si->cursor.hot_x = 0;
si->cursor.hot_y = 0;
si->cursor.x = 0;
si->cursor.y = 0;
/*
Put the frame buffer immediately following the cursor data. We store this
info in a frame_buffer_config structure to make it convienient to return
to the app_server later.
*/
pointer_reservation = 0;
/* Nvidia hardcursor needs 2kB space */
if (si->settings.hardcursor) pointer_reservation = 2048;
si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
/* count of issued parameters or commands */
si->engine.last_idle = si->engine.count = 0;
INIT_BEN(si->engine.lock);
INIT_BEN(si->overlay.lock);
for (cnt = 0; cnt < MAXBUFFERS; cnt++)
{
/* make sure overlay buffers are 'marked' as being free */
si->overlay.myBuffer[cnt].buffer = NULL;
si->overlay.myBuffer[cnt].buffer_dma = NULL;
}
/* make sure overlay unit is 'marked' as being free */
si->overlay.myToken = NULL;
/* bail out if something failed */
if (result != B_OK) goto error1;
/* initialise various cursor stuff*/
nv_crtc_cursor_init();
/* ensure cursor state */
SHOW_CURSOR(false);
/* a winner! */
result = B_OK;
goto error0;
error1:
/*
Initialization failed after init_common() succeeded, so we need to clean
up before quiting.
*/
uninit_common();
error0:
return result;
}
/*
Return the number of bytes required to hold the information required
to clone the device.
*/
ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
/*
Since we're passing the name of the device as the only required
info, return the size of the name buffer
*/
return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH;
}
/*
Return the info required to clone the device. void *data points to
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
*/
void GET_ACCELERANT_CLONE_INFO(void *data) {
nv_device_name dn;
status_t result;
/* call the kernel driver to get the device name */
dn.magic = NV_PRIVATE_DATA_MAGIC;
/* store the returned info directly into the passed buffer */
dn.name = (char *)data;
result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn));
}
/*
Initialize a copy of the accelerant as a clone. void *data points to
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
*/
status_t CLONE_ACCELERANT(void *data) {
status_t result;
char path[MAXPATHLEN];
/* the data is the device name */
strcpy(path, "/dev");
strcat(path, (const char *)data);
/* open the device, the permissions aren't important */
fd = open(path, B_READ_WRITE);
if (fd < 0) {
result = fd;
goto error0;
}
/* note that we're a clone accelerant */
accelerantIsClone = 1;
/* call the shared initialization code */
result = init_common(fd);
/* bail out if the common initialization failed */
if (result != B_OK) goto error1;
/* get shared area for display modes */
result = my_mode_list_area = clone_area(
DRIVER_PREFIX " cloned display_modes",
(void **)&my_mode_list,
B_ANY_ADDRESS,
B_READ_AREA,
si->mode_area
);
if (result < B_OK) goto error2;
/* all done */
LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
result = B_OK;
goto error0;
error2:
/* free up the areas we cloned */
uninit_common();
error1:
/* close the device we opened */
close(fd);
error0:
return result;
}
void UNINIT_ACCELERANT(void)
{
if (accelerantIsClone)
LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
else
LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
/*delete benaphore*/
DELETE_BEN(si->engine.lock);
DELETE_BEN(si->overlay.lock);
/* free our mode list area */
delete_area(my_mode_list_area);
/* paranoia */
my_mode_list = 0;
/* release our cloned data */
uninit_common();
/* close the file handle ONLY if we're the clone */
if (accelerantIsClone) close(fd);
}
+648
View File
@@ -0,0 +1,648 @@
/* Written by Rudolf Cornelissen 05-2002/03-2003 */
/* Note on 'missing features' in BeOS 5.0.3 and DANO:
* BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
* of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?)
*/
#define MODULE_BIT 0x00000400
#include "acc_std.h"
/* define the supported overlay input colorspaces */
/* Note:
* G200-G550 can all do YUV4:2:0 2-plane colorspace as well,
* G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering),
* G200 does not support YUV4:2:0 3-plane mode while > G200 do.
* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
* definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
uint32 OVERLAY_COUNT(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: count called\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
}
/* apparantly overlay count should report the number of 'overlay units' on the card */
return 1;
}
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
// Does someone know howto invoke it?
{
LOG(4,("Overlay: supported_spaces called.\n"));
/* check for NULL pointer */
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
return NULL;
}
/* interlaced VGA is not supported by G200-G550 BES */
if (dm->timing.flags && B_TIMING_INTERLACED)
{
return NULL;
}
/* return a B_NO_COLOR_SPACE terminated list */
return &overlay_colorspaces[0];
}
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported!
{
LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
/* check what features (like the keying method) are supported on the current
* Desktop colorspace */
//fixme? Or are we talking about the overlay input bitmap's colorspace?
switch (a_color_space)
{
default:
/* fixme: for now 'direct 32bit' desktop colorspace assumed */
return
( B_OVERLAY_KEYING_USES_ALPHA |
B_OVERLAY_COLOR_KEY |
B_OVERLAY_HORIZONTAL_FILTERING |
B_OVERLAY_VERTICAL_FILTERING );
}
}
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
{
int offset = 0; /* used to determine next buffer to create */
uint32 adress, adress2, temp32; /* used to calculate buffer adresses */
uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */
int cnt; /* loopcounter */
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer)));
LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci)));
LOG(4,("Overlay: cardRAM_size = %dMb\n",si->ps.memory_size));
/* find first empty slot (room for another buffer?) */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == NULL) break;
}
LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset));
if (offset < MAXBUFFERS)
/* setup new scaler input buffer */
{
switch (cs)
{
case B_YCbCr422:
/* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0003 while > G200 need ~x0007.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
/* fixme: update needed for DVDmax support to adhere to CRTC2 constraints:
* case display_mode == B_RGB16: multiple = 32
* case display_mode == B_RGB32: multiple = 16 */
if (width == (width & ~0x0007))
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8;
}
si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
/* check if the requested horizontal pitch is supported:
* G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace.
* Compatible check done, has no downside consequences here. */
if (si->overlay.myBuffer[offset].width > 4088)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
// case 0xffff://fixme: which one(s)?
//fixme: 4:2:0 2-plane supported format, should be selected only if detected
/* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0007 while > G200 need ~x001f.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
/* if (width == (width & ~0x001f))
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32;
}
*/ /* assuming Y-plane only bytes_per_row are requested here */
/* si->overlay.myBuffer[offset].bytes_per_row = si->overlay.myBuffer[offset].width;
*/
/* check if the requested horizontal pitch is supported:
* G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace.
* Compatible check done, has no real downside consequences here. */
/* if (si->overlay.myBuffer[offset].width > 4064)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n");
*/
/* release the shared benaphore */
/* RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
*/
default:
/* unsupported colorspace! */
LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
break;
}
/* check if the requested buffer width is supported */
if (si->overlay.myBuffer[offset].width > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* check if the requested buffer height is supported */
if (height > 1024)
{
LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
si->overlay.myBuffer[offset].space = cs;
si->overlay.myBuffer[offset].height = height;
/* we define the overlay buffers to reside 'in the back' of the cards RAM */
/* NOTE to app programmers:
* Beware that an app using overlay needs to track workspace switches and screenprefs
* changes. If such an action is detected, the app needs to reset it's pointers to the
* newly created overlay bitmaps, which will be assigned by BeOS automatically after such
* an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
*
* It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
* than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
* This means that the app should also check for NULL pointers returned by the bitmaps,
* and if this happens, it needs to fallback to single buffered overlay or even fallback to
* bitmap output for the new situation. */
/* Another NOTE for app programmers:
* A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
* cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
* This *greatly* simplifies tracking such errors!
* Of course such errors may lead to strange effects in the app or driver behaviour if they are
* not hunted down and removed.. */
/* calculate first free RAM adress in card:
* Driver setup is as follows:
* card base: - hardware cursor bitmap (if used),
* directly above - screen memory for both heads */
adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */
(si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */
LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
/* calculate 'preliminary' buffer size including slopspace */
oldsize = si->overlay.myBufInfo[offset].size;
si->overlay.myBufInfo[offset].size =
si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
/* calculate virtual memory adress that would be needed for a new bitmap */
/* NOTE to app programmers:
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file nv.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uint32)((uint8*)si->framebuffer)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
* 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
/* Check if we need to modify the buffers starting adress and thus the size */
/* calculate 'would be' cardRAM offset */
temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer)));
/* check if it is aligned */
if (temp32 != (temp32 & 0xfffffff0))
{
/* update the (already calculated) buffersize to get it aligned */
si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
/* update the (already calculated) adress to get it aligned */
adress -= (temp32 - (temp32 & 0xfffffff0));
}
LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
/* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
* this is done to prevent a large buffer getting created in the space a small buffer
* occupied earlier, if not all buffers created were deleted.
* Note also that the app can delete the buffers in any order desired. */
/* NOTE to app programmers:
* If you are going to delete a overlay buffer you created, you should delete them *all* and
* then re-create only the new ones needed. This way you are sure not to get unused memory-
* space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
* If you don't, you might not get a buffer at all if you are trying to set up a larger one
* than before.
* (Indeed: not all buffers *have* to be of the same type and size...) */
for (cnt = offset; cnt < MAXBUFFERS; cnt++)
{
if (si->overlay.myBuffer[cnt].buffer != NULL)
{
/* Check if the new buffer would fit into the space the single old one used here */
if (si->overlay.myBufInfo[offset].size <= oldsize)
{
/* It does, so we reset to the old size and adresses to prevent the space from shrinking
* if we get here again... */
adress -= (oldsize - si->overlay.myBufInfo[offset].size);
si->overlay.myBufInfo[offset].size = oldsize;
LOG(4,("Overlay: 'squeezing' in buffer:\n"
"Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
/* force exiting the FOR loop */
cnt = MAXBUFFERS;
}
else
{
/* nogo, sorry */
LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
"Overlay: not enough space to 'squeeze' this one in, aborted\n"));
/* Reset to the old size to prevent the space from 'growing' if we get here again... */
si->overlay.myBufInfo[offset].size = oldsize;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
}
/* check if we have enough space to setup this new bitmap
* (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
if (adress < adress2)
/* nope, sorry */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
/* continue buffer setup */
si->overlay.myBuffer[offset].buffer = (void *) adress;
/* calculate physical memory adress (for dma use) */
/* NOTE to app programmers:
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file nv.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uint32)((uint8*)si->framebuffer_pci)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
/* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n",
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer),
(uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs));
LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return &si->overlay.myBuffer[offset];
}
else
/* sorry, no more room for buffers */
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
/* Note that the user can delete the buffers in any order desired! */
{
int offset = 0;
if (ob != NULL)
{
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
/* delete current buffer */
{
si->overlay.myBuffer[offset].buffer = NULL;
si->overlay.myBuffer[offset].buffer_dma = NULL;
LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
return B_ERROR;
}
}
else
/* no buffer specified! */
{
LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
return B_ERROR;
}
}
status_t GET_OVERLAY_CONSTRAINTS
(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
{
int offset = 0;
LOG(4,("Overlay: Get_overlay_constraints called\n"));
/* check for NULL pointers */
if ((dm == NULL) || (ob == NULL) || (oc == NULL))
{
LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
return B_ERROR;
}
/* find the buffer */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
/* scaler input (values are in pixels) */
oc->view.h_alignment = 0;
oc->view.v_alignment = 0;
switch (ob->space)
{
case B_YCbCr422:
/* G200 can work with 3, > G200 need 7. Compatible setting returned for now.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
oc->view.width_alignment = 7;
break;
// case 0xffff://fixme: which one(s)? (4:2:0 supported formats. Not yet used...)
/* G200 can work with 7, > G200 need 31. Compatible setting returned for now.
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
/* oc->view.width_alignment = 31;
break;
*/
default:
/* we should not be here, but set the worst-case value just to be safe anyway */
oc->view.width_alignment = 31;
break;
}
oc->view.height_alignment = 0;
oc->view.width.min = 1;
oc->view.height.min = 2; /* two fields */
oc->view.width.max = ob->width;
oc->view.height.max = ob->height;
/* scaler output restrictions */
oc->window.h_alignment = 0;
oc->window.v_alignment = 0;
oc->window.width_alignment = 0;
oc->window.height_alignment = 0;
oc->window.width.min = 2;
/* G200-G550 can output upto and including 2048 pixels in width */
if (dm->virtual_width > 2048)
{
oc->window.width.max = 2048;
}
else
{
oc->window.width.max = dm->virtual_width;
}
oc->window.height.min = 2;
/* G200-G550 can output upto and including 2048 pixels in height */
if (dm->virtual_height > 2048)
{
oc->window.height.max = 2048;
}
else
{
oc->window.height.max = dm->virtual_height;
}
/* G200-G550 scaling restrictions */
/* Adjust horizontal restrictions if pixelclock is above BES max. speed! */
/* Note: If RGB32 is implemented no scaling is supported! */
if (si->dm.timing.pixel_clock > BESMAXSPEED)
{
oc->h_scale.min = (1 * 2) / (32 - (1 / (float)16384));
oc->h_scale.max = (16384 * 2)/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
else
{
oc->h_scale.min = 1 / (32 - (1 / (float)16384));
oc->h_scale.max = 16384/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
oc->v_scale.min = 1 / (32 - (1 / (float)16384));
oc->v_scale.max = 16384/(float)ob->height;
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
overlay_token ALLOCATE_OVERLAY(void)
{
uint32 tmpToken;
LOG(4,("Overlay: Allocate_overlay called: "));
/* come up with a token */
tmpToken = 0x12345678;
/* acquire the shared benaphore */
AQUIRE_BEN(si->overlay.lock)
/* overlay unit already in use? */
if (si->overlay.myToken == NULL)
/* overlay unit is available */
{
LOG(4,("succesfull\n"));
si->overlay.myToken = &tmpToken;
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return si->overlay.myToken;
}
else
/* sorry, overlay unit is occupied */
{
LOG(4,("failed: already in use!\n"));
/* release the shared benaphore */
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY(overlay_token ot)
{
LOG(4,("Overlay: Release_overlay called: "));
/* is this call for real? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed, not in use!\n"));
return B_ERROR;
}
else
/* call is for real */
{
nv_release_bes();
LOG(4,("succesfull\n"));
si->overlay.myToken = NULL;
return B_OK;
}
}
status_t CONFIGURE_OVERLAY
(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
{
int offset = 0; /* used for buffer index */
LOG(4,("Overlay: Configure_overlay called: "));
/* Note:
* When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
* release all overlay buffers. The buffer currently displayed at that moment, may need some
* 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
* called one more time then, with a null pointer for overlay_window and overlay_view, while
* the currently displayed overlay_buffer is given.
* The G200-G550 do not need to do anything on such an occasion, so we simply return if we
* get called then. */
if ((ow == NULL) || (ov == NULL))
{
LOG(4,("output properties changed\n"));
return B_OK;
}
/* Note:
* If during overlay use the screen prefs are changed, or the workspace has changed, it
* may be that we were not able to re-allocate the requested overlay buffers (or only partly)
* due to lack of cardRAM. If the app does not respond properly to this, we might end up
* with a NULL pointer instead of a overlay_buffer to work with here.
* Of course, we need to abort then to prevent the system from 'going down'.
* The app will probably crash because it will want to write into this non-existant buffer
* at some point. */
if (ob == NULL)
{
LOG(4,("no overlay buffer specified\n"));
return B_ERROR;
}
/* is this call done by the app that owns us? */
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
/* nope, abort */
{
LOG(4,("failed\n"));
return B_ERROR;
}
else
/* call is for real */
{
/* find the buffer's offset */
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
LOG(4,("succesfull, switching to buffer %d\n", offset));
nv_configure_bes(ob, ow, ov, offset);
return B_OK;
}
else
{
/* this is no buffer of ours! */
LOG(4,("buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
}
@@ -0,0 +1,447 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors for NV driver:
Mark Watson,
Rudolf Cornelissen 9/2002-4/2003
*/
#define MODULE_BIT 0x00400000
#include "acc_std.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
/* mode flags will be setup as status info by PROPOSEMODE! */
#define MODE_FLAGS 0
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
/*some monitors only handle a fixed set of modes*/
#include "valid_mode_list"
/*Standard VESA modes*/
static const display_mode mode_list[] = {
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 120000, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
{ { 108000, 1280, 1328, 1440, 1680, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
};
/*
Check mode is between low and high limits
returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
*/
/* BOUNDS WARNING:
* BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE. It's called by the OS with target, low and high set to
* have the same settings for BWindowScreen!
* Which means we should not return B_BAD_VALUE on anything except for deviations on:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
*/
/* Note:
* The target mode should be modified to correspond to the mode as it can be made. */
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
status_t status = B_OK;
float pix_clock_found;
uint8 m,n,p;
status_t result;
uint32 max_vclk, row_bytes, pointer_reservation;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
(
(double)target->timing.h_total *
(double)target->timing.v_total
);
bool
want_same_width = target->timing.h_display == target->virtual_width,
want_same_height = target->timing.v_display == target->virtual_height;
LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
target->virtual_width, target->virtual_height));
/*check valid list:
if (VALID_REQUIRED is set)
{
if (find modes with same size)
{
pick one with nearest pixel clock
}
else
{
pick next largest with nearest pixel clock and modify visible portion as far as possible
}
}
*/
#ifdef VALID_MODE_REQUIRED
{
int i;
int closest_mode_ptr;
uint32 closest_mode_clock;
LOG(1, ("PROPOSEMODE: valid mode required!\n"));
closest_mode_ptr = 0xbad;
closest_mode_clock = 0;
for (i=0;i<VALID_MODES;i++)
{
/*check size is ok and clock is better than any found before*/
if(
target->timing.h_display==valid_mode_list[i].h_display &&
target->timing.v_display==valid_mode_list[i].v_display
)
{
if (
abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)<
abs(closest_mode_clock-target->timing.pixel_clock)
)
{
closest_mode_clock=valid_mode_list[i].pixel_clock;
closest_mode_ptr=i;
}
}
}
if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
{
LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
return B_ERROR;
}
else
{
target->timing=valid_mode_list[closest_mode_ptr];
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
((double)target->timing.h_total * (double)target->timing.v_total);
}
}
#endif
/*find a nearby valid timing from that given*/
result = nv_crtc_validate_timing
(
&target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
&target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
);
if (result == B_ERROR)
{
LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
return result;
}
/* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
/* nail virtual size and 'subsequently' calculate rowbytes */
result = nv_general_validate_pic_size (target, &row_bytes);
if (result == B_ERROR)
{
LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
return result;
}
/*check if virtual_width is still within the requested limits*/
if ((target->virtual_width < low->virtual_width) ||
(target->virtual_width > high->virtual_width))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
}
/*check if timing found is within the requested horizontal limits*/
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total))
{
/* BWindowScreen workaround: we accept everything except h_display deviations */
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
}
/*check if timing found is within the requested vertical limits*/
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.v_sync_start) ||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
)
{
/* BWindowScreen workaround: we accept everything except v_display deviations */
if ((target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
}
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
/* calculate settings, but do not actually test anything (that costs too much time!) */
result = nv_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
/* update the target mode */
target->timing.pixel_clock = (pix_clock_found * 1000);
/* note if we fell outside the limits */
if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
(target->timing.pixel_clock > high->timing.pixel_clock)
)
{
/* BWindowScreen workaround: we accept deviations <= 1Mhz */
if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
(target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
}
/* checkout space needed for hardcursor (if any) */
pointer_reservation = 0;
if (si->settings.hardcursor) pointer_reservation = 2048;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) >
((si->ps.memory_size * 1024 * 1024) - pointer_reservation))
{
target->virtual_height =
((si->ps.memory_size * 1024 * 1024) - pointer_reservation) / row_bytes;
}
if (target->virtual_height < target->timing.v_display)
{
LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
return B_ERROR;
}
LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
target->virtual_width, target->virtual_height));
if ((target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
}
/* setup status flags */
LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
/* preset to singlehead card without TVout, no overlay support and no hardcursor.
* also advice system that app_server and acc engine may touch the framebuffer
* simultaneously (fixed). */
target->flags &=
~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
/* we always allow parallel access (fixed), the DAC is always in 'enhanced'
* mode (fixed), and all modes support DPMS (fixed);
* We support scrolling and panning in every mode, so we 'send a signal' to
* BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
//fixme: secondary head does not support DPMS...
target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
/* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
switch (target->space)
{
case B_CMAP8:
max_vclk = si->ps.max_dac2_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_vclk = si->ps.max_dac2_clock_16;
break;
case B_RGB24_LITTLE:
max_vclk = si->ps.max_dac2_clock_24;
break;
case B_RGB32_LITTLE:
max_vclk = si->ps.max_dac2_clock_32dh;
break;
default:
/* use fail-safe value */
max_vclk = si->ps.max_dac2_clock_32dh;
break;
}
/* set DUALHEAD_CAPABLE if suitable */
//fixme: update for independant secondary head use! (reserve fixed memory then)
if (si->ps.secondary_head &&
(((si->ps.memory_size * 1024 * 1024) - pointer_reservation) >=
/* note: extra line for maven vblank included here! */
(row_bytes * (target->virtual_height + 1) * 2)) &&
((target->space == B_RGB16_LITTLE) || (target->space == B_RGB32_LITTLE)) &&
(target->timing.pixel_clock <= (max_vclk * 1000)))
{
target->flags |= DUALHEAD_CAPABLE;
}
/* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
//fixme: modify for G100 and G200 TVout later on...
if (target->flags & DUALHEAD_CAPABLE)
{
if (si->ps.tvout &&
(target->timing.h_display <= 1024) &&
(target->timing.v_display <= 768))
{
target->flags |= TV_CAPABLE;
}
}
/* set HARDWARE_CURSOR mode if suitable */
if (si->settings.hardcursor)
target->flags |= B_HARDWARE_CURSOR;
/* set SUPPORTS_OVERLAYS */
target->flags |= B_SUPPORTS_OVERLAYS;
LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
/* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
* progressive scan (fixed), and setup sync_on_green flag according to
* nv.settings options file */
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
if (si->settings.greensync)
target->timing.flags |= B_SYNC_ON_GREEN;
/* The HSYNC and VSYNC command flags are actually executed by the driver. */
if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
return status;
}
/* Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff)
*/
uint32 ACCELERANT_MODE_COUNT(void)
{
LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
return si->mode_count;
}
/* Copy the list of guaranteed supported video modes to the location provided.*/
status_t GET_MODE_LIST(display_mode *dm)
{
LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK;
}
/* Create a list of display_modes to pass back to the caller.*/
status_t create_mode_list(void) {
size_t max_size;
uint32
i, j,
pix_clk_range;
const display_mode
*src;
display_mode
*dst,
low,
high;
color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8};
/* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE*/
max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
/* create an area to hold the info */
si->mode_area = my_mode_list_area =
create_area("NV accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (my_mode_list_area < B_OK) return my_mode_list_area;
/* walk through our predefined list and see which modes fit this device */
src = mode_list;
dst = my_mode_list;
si->mode_count = 0;
for (i = 0; i < MODE_COUNT; i++) {
/* set ranges for acceptable values */
low = high = *src;
/* range is 6.25% of default clock: arbitrarily picked */
pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
/* 'some cards need wider virtual widths for certain modes':
* Not true. They might need a wider pitch, but this is _not_ reflected in
* virtual_width, but in fbc.bytes_per_row. */
//So disable next line:
//high.virtual_width = 4096;
/* do it once for each depth we want to support */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
{
/* set target values */
*dst = *src;
/* poke the specific space */
dst->space = low.space = high.space = spaces[j];
/* ask for a compatible mode */
/* We have to check for B_OK, because otherwise the pix_clk_range
* won't be taken into account!! */
//So don't do this:
//if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
//Instead, do this:
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
/* count it, and move on to next mode */
dst++;
si->mode_count++;
}
}
/* advance to next mode */
src++;
}
return B_OK;
}
@@ -0,0 +1,633 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 11/2002-7/2003
*/
#define MODULE_BIT 0x00200000
#include "acc_std.h"
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
*/
static void interrupt_enable(bool flag) {
status_t result;
nv_set_bool_state sbs;
/* set the magic number so the driver knows we're for real */
sbs.magic = NV_PRIVATE_DATA_MAGIC;
sbs.do_it = flag;
/* contact driver and get a pointer to the registers and shared data */
result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
}
/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
/* BOUNDS WARNING:
* It's impossible to deviate whatever small amount in a display_mode if the lower
* and upper limits are the same!
* Besides:
* BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE!
* Which means PROPOSEMODE should not return that on anything except on
* deviations for:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
* So:
* We don't use bounds here by making sure bounds and target are the same struct!
* (See the call to PROPOSE_DISPLAY_MODE below) */
display_mode /*bounds,*/ target;
uint8 colour_depth1 = 32;
status_t result;
uint32 startadd,startadd_right;
// apsed TODO startadd is 19 bits if < g200
bool display, h, v;
si->switched_crtcs = false;
/* Adjust mode to valid one and fail if invalid */
target /*= bounds*/ = *mode_to_set;
/* show the mode bits */
LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
target.virtual_width, target.virtual_height));
/* See BOUNDS WARNING above... */
if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
/* if not dualhead capable card clear dualhead flags */
if (!(target.flags & DUALHEAD_CAPABLE))
{
target.flags &= ~DUALHEAD_BITS;
}
/* if not TVout capable card clear TVout flags */
if (!(target.flags & TV_CAPABLE))
{
target.flags &= ~TV_BITS;
}
LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
/* disable interrupts using the kernel driver */
interrupt_enable(false);
/* find current DPMS state, then turn off screen(s) */
nv_crtc_dpms_fetch(&display, &h, &v);
nv_crtc_dpms(false, false, false);
// if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
startadd = si->fbc.frame_buffer - si->framebuffer;
/* calculate and set new mode bytes_per_row */
nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row);
/*Perform the very long mode switch!*/
if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
{
uint8 colour_depth2 = colour_depth1;
/* init display mode for secondary head */
display_mode target2 = target;
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
/* validate flags for secondary TVout */
if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
{
target.flags &= ~TV_BITS;//still needed for some routines...
target2.flags &= ~TV_BITS;
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
}
/* set the pixel clock PLL(s) */
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
if (nv_dac_set_pix_pll(target) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
/* we do not need to set the pixelclock here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS))
{
LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
if (nv_maven_set_vid_pll(target2) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
}
/*set the colour depth for CRTC1 and the DAC */
switch(target.space)
{
case B_RGB16_LITTLE:
colour_depth1 = 16;
nv_dac_mode(BPP16, 1.0);
nv_crtc_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth1 = 32;
nv_dac_mode(BPP32, 1.0);
nv_crtc_depth(BPP32);
break;
}
/*set the colour depth for CRTC2 and the MAVEN */
switch(target2.space)
{
case B_RGB16_LITTLE:
colour_depth2 = 16;
nv_maven_mode(BPP16, 1.0);
g400_crtc2_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth2 = 32;
nv_maven_mode(BPP32DIR, 1.0);
g400_crtc2_depth(BPP32DIR);
break;
}
/* check if we are doing interlaced TVout mode */
si->interlaced_tv_mode = false;
/* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
si->interlaced_tv_mode = true;
*/
/*set the display(s) pitches*/
nv_crtc_set_display_pitch ();
//fixme: seperate for real dualhead modes:
//we need a secondary si->fbc!
g400_crtc2_set_display_pitch ();
/*work out where the "right" screen starts*/
startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3));
/* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */
si->crtc_delay = 44 + 0 * (colour_depth2 == 16);
/* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */
/* (extra "blanking" line for MAVEN) */
target2.timing.v_display++;
/* set the outputs */
switch (si->ps.card_type)
{
case NV11:
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
si->switched_crtcs = false;
break;
case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK)
{
/* Don't switch CRTC's because MAVEN YUV is impossible then,
* and primary head output will be limited to 135Mhz pixelclock. */
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
si->switched_crtcs = true;
}
else
{
/* This limits the pixelclocks on both heads to 135Mhz,
* but you can use overlay on the other output now. */
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
nv_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC);
si->switched_crtcs = false;
/* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
si->crtc_delay = 17 + 4 * (colour_depth1 == 16);
/* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */
/* (extra "blanking" line for MAVEN) */
target.timing.v_display++;
target2.timing.v_display--;
}
break;
}
break;
//fixme:
//setup crtc_delay and vertical timing adjust for G450(?)/G550,
//and remove the '+1' in crtc2 vertical timing(?)
case NV17:
if (!si->ps.primary_dvi)
/* output connector use is always 'straight-through' */
//fixme: re-evaluate when DVI is setup...
{
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
si->switched_crtcs = false;
break;
case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK)
{
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
si->switched_crtcs = true;
}
else
{
/* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
si->switched_crtcs = false;
}
break;
}
}
else
/* output connector use is cross-linked if no TV cable connected! */
//fixme: re-evaluate when DVI is setup...
{
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
if (i2c_sec_tv_adapter() == B_OK)
{
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
si->switched_crtcs = false;
}
else
{
/* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */
nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
si->switched_crtcs = false;
}
break;
case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK)
{
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
si->switched_crtcs = true;
}
else
{
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
si->switched_crtcs = false;
}
break;
}
}
break;
default:
break;
}
if (si->switched_crtcs)
{
uint32 temp = startadd;
startadd = startadd_right;
startadd_right = temp;
}
/*Tell card what memory to display*/
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
nv_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd_right,colour_depth2);
break;
case DUALHEAD_CLONE:
nv_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd,colour_depth2);
break;
}
/* set the timing */
nv_crtc_set_timing(target);
/* we do not need to setup CRTC2 here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2);
/* TVout support: setup CRTC2 and it's pixelclock */
if (si->ps.tvout && (target2.flags & TV_BITS))
{
si->crtc_delay += 5;
maventv_init(target2);
}
}
else /* single head mode */
{
status_t status;
int colour_mode = BPP32;
switch(target.space)
{
case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
default:
LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
return B_ERROR;
}
/* set the pixel clock PLL */
status = nv_dac_set_pix_pll(target);
if (status==B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
/* set the colour depth for CRTC1 and the DAC */
/* first set the colordepth */
nv_crtc_depth(colour_mode);
/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
nv_dac_mode(colour_mode,1.0);
/* set the display pitch */
nv_crtc_set_display_pitch();
/* tell the card what memory to display */
nv_crtc_set_display_start(startadd,colour_depth1);
/* enable primary analog output */
switch (si->ps.card_type)
{
case NV11:
// nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
break;
case NV17:
// nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
// gx50_general_output_select();
break;
default:
break;
}
/* set the timing */
nv_crtc_set_timing(target);
//fixme: shut-off the videoPLL if it exists...
}
/* update driver's mode store */
si->dm = target;
/* turn screen one on */
nv_crtc_dpms(display, h, v);
/* turn screen two on if a dualhead mode is active */
// if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v);
/* set up acceleration for this mode */
si->dm.virtual_height += 1;//for clipping!
// nv_acc_init();
si->dm.virtual_height -= 1;
/* clear line at bottom of screen (for maven) if dualhead mode */
// nv_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0);
MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0));
/* enable interrupts using the kernel driver */
interrupt_enable(true);
/* optimize memory-access if needed */
// nv_crtc_mem_priority(colour_depth1);
/* Tune RAM CAS-latency if needed. Must be done *here*! */
nv_set_cas_latency();
return B_OK;
}
/*
Set which pixel of the virtual frame buffer will show up in the
top left corner of the display device. Used for page-flipping
games and virtual desktops.
*/
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
uint8 colour_depth;
uint32 startadd,startadd_right;
LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
/* reset lower bits, don't return an error! */
//fixme: not needed in dualhead on Nvidia??? (pixelprecise panning on sec. head??)
if (si->dm.flags & DUALHEAD_BITS)
{
switch(si->dm.space)
{
case B_RGB16_LITTLE:
colour_depth=16;
h_display_start &= ~0x1f;
break;
case B_RGB32_LITTLE:
colour_depth=32;
h_display_start &= ~0x0f;
break;
default:
LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space));
return B_ERROR;
}
}
else
{
/* Nvidia always does pixelprecise panning on primary head */
switch(si->dm.space)
{
case B_CMAP8:
colour_depth=8;
// h_display_start &= ~0x07;
break;
case B_RGB15_LITTLE: case B_RGB16_LITTLE:
colour_depth=16;
// h_display_start &= ~0x03;
break;
case B_RGB32_LITTLE:
colour_depth=32;
// h_display_start &= ~0x01;
break;
default:
return B_ERROR;
}
}
/* do not run past end of display */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
default:
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
}
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR;
/* everybody remember where we parked... */
si->dm.h_display_start = h_display_start;
si->dm.v_display_start = v_display_start;
/* actually set the registers */
//fixme: seperate both heads: we need a secondary si->fbc!
startadd = v_display_start * si->fbc.bytes_per_row;
startadd += h_display_start * (colour_depth >> 3);
startadd += si->fbc.frame_buffer - si->framebuffer;
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
/* account for switched CRTC's */
if (si->switched_crtcs)
{
uint32 temp = startadd;
startadd = startadd_right;
startadd_right = temp;
}
interrupt_enable(false);
switch (si->dm.flags&DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
nv_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth);
break;
case DUALHEAD_OFF:
nv_crtc_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_CLONE:
nv_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
break;
}
interrupt_enable(true);
return B_OK;
}
/*
Set the indexed color palette.
*/
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
int i;
uint8 *r,*g,*b;
/* Protect gamma correction when not in CMAP8 */
if (si->dm.space != B_CMAP8) return;
r=si->color_data;
g=r+256;
b=g+256;
i=first;
while (count--)
{
r[i]=*color_data++;
g[i]=*color_data++;
b[i]=*color_data++;
i++;
}
nv_dac_palette(r,g,b);
}
/* masks for DPMS control bits */
enum {
H_SYNC_OFF = 0x01,
V_SYNC_OFF = 0x02,
DISPLAY_OFF = 0x04,
BITSMASK = (H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF)
};
/* Put the display into one of the Display Power Management modes. */
status_t SET_DPMS_MODE(uint32 dpms_flags) {
interrupt_enable(false);
LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on, display on */
nv_crtc_dpms(true, true, true);
if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1);
break;
case B_DPMS_STAND_BY:
nv_crtc_dpms(false, false, true);
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1);
break;
case B_DPMS_SUSPEND:
nv_crtc_dpms(false, true, false);
if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
nv_crtc_dpms(false, false, false);
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
else /* singlehead */
{
switch(dpms_flags)
{
case B_DPMS_ON: /* H: on, V: on, display on */
nv_crtc_dpms(true, true, true);
break;
case B_DPMS_STAND_BY:
nv_crtc_dpms(false, false, true);
break;
case B_DPMS_SUSPEND:
nv_crtc_dpms(false, true, false);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
nv_crtc_dpms(false, false, false);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
interrupt_enable(true);
return B_ERROR;
}
}
interrupt_enable(true);
return B_OK;
}
/* Report device DPMS capabilities */
uint32 DPMS_CAPABILITIES(void) {
return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
}
/* Return the current DPMS mode */
uint32 DPMS_MODE(void) {
bool display, h, v;
interrupt_enable(false);
nv_crtc_dpms_fetch(&display, &h, &v);
interrupt_enable(true);
if (display && h && v)
return B_DPMS_ON;
else if(v)
return B_DPMS_STAND_BY;
else if(h)
return B_DPMS_SUSPEND;
else
return B_DPMS_OFF;
}
+17
View File
@@ -0,0 +1,17 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#if !defined(GLOBALDATA_H)
#define GLOBALDATA_H
#include <stdio.h>
#include <sys/ioctl.h>
#include "DriverInterface.h"
#include "global.h"
//apsed #include "nv_extern.h"
#include "nv_proto.h"
#include "be_driver_proto.h"
#endif
@@ -0,0 +1,438 @@
/* NV Acceleration functions */
/* Authors:
Mark Watson 2/2000,
Rudolf Cornelissen 10/2002-4/2003.
*/
#define MODULE_BIT 0x00080000
#include "nv_std.h"
/*acceleration notes*/
/*functions Be's app_server uses:
fill span (horizontal only)
fill rectangle (these 2 are very similar)
invert rectangle
blit
*/
/* G100 pre SRCORG/DSTORG registers */
static uint32 src_dst;
/* MIL1/2 adress linearisation does not always work */
static uint8 y_lin;
static uint8 depth;
/* needed by MIL 1/2 because of adress linearisation constraints */
#define ACCW_YDSTLEN(dst, len) do { \
if (y_lin) { \
ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \
ACCW(LEN,len); \
} else ACCW(YDSTLEN,((dst)<<16)|(len)); \
} while (0)
status_t nv_acc_wait_idle()
{
volatile int i;
while (ACCR(STATUS)&(1<<16))
{
for (i=0;i<10000;i++); /*spin in place so I do not hammer the bus*/
};
return B_OK;
}
/* AFAIK this must be done for every new screenmode.
* Engine required init. */
status_t nv_acc_init()
{
/* used for convenience: MACCESS is a write only register! */
uint32 maccess = 0x00000000;
/* if we were unable to read PINS, we have to assume something (keeping bit6 zero) */
// if ((si->ps.card_type >= G450) && (si->ps.pins_status = B_OK))
// {
/* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */
// maccess |= ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1);
// }
/* preset using hardware adress linearisation */
y_lin = 0x00;
/* reset depth */
depth = 0;
/* cleanup bitblt */
ACCW(OPMODE,0);
/* Set the Z origin to the start of FB (otherwise lockup on blits) */
ACCW(ZORG,0);
/* Set pixel width */
switch(si->dm.space)
{
case B_CMAP8:
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00));
depth = 8;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01));
depth = 16;
break;
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02));
depth = 32;
break;
default:
LOG(8,("ACC: init, invalid bit depth\n"));
return B_ERROR;
}
/* setup PITCH: very cardtype specific! */
/* switch (si->ps.card_type)
{
case MIL1:
switch (si->fbc.bytes_per_row / (depth >> 3))
{
case 640:
case 768:
case 800:
case 960:
case 1024:
case 1152:
case 1280:
case 1600:
case 1920:
case 2048:
*/ /* we are using hardware adress linearisation */
/* break;
default:
*/ /* we are using software adress linearisation */
/* y_lin = 0x01;
LOG(8,("ACC: using software adress linearisation\n"));
break;
}
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
case MIL2:
switch (si->fbc.bytes_per_row / (depth >> 3))
{
case 512:
case 640:
case 768:
case 800:
case 832:
case 960:
case 1024:
case 1152:
case 1280:
case 1600:
case 1664:
case 1920:
case 2048:
*/ /* we are using hardware adress linearisation */
/* break;
default:
*/ /* we are using software adress linearisation */
/* y_lin = 0x01;
LOG(8,("ACC: using software adress linearisation\n"));
break;
}
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
case G100:
*/ /* always using hardware adress linearisation, because 2D/3D
* engine works on every pitch multiple of 32 */
/* ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
default:
*/ /* G200 and up are equal.. */
/* always using hardware adress linearisation, because 2D/3D
* engine works on every pitch multiple of 32 */
/* ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF));
break;
}
*/
/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
ACCW(PLNWT,0x00000000);
ACCW(PLNWT,0xffffffff);
// if (si->ps.card_type >= G200) {
/*DSTORG - location of active screen in framebuffer*/
// ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer));
/*SRCORG - init source address - same as dest*/
// ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer));
// }
/* init YDSTORG - apsed, if not inited, BitBlts may fails on <= G200 */
src_dst = 0;
ACCW(YDSTORG, src_dst);
/* <= G100 uses this register as SRCORG/DSTORG replacement, but
* MIL 1/2 does not need framebuffer space for the hardcursor! */
/* if ((si->ps.card_type == G100) && (si->settings.hardcursor))
{
switch (si->dm.space)
{
case B_CMAP8:
src_dst = 1024 / 1;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
src_dst = 1024 / 2;
break;
case B_RGB32_LITTLE:
src_dst = 1024 / 4;
break;
default:
LOG(8,("ACC: G100 hardcursor not supported for current colorspace\n"));
return B_ERROR;
}
}
*/ ACCW(YDSTORG,src_dst);
/* clipping */
/* i.e. highest and lowest X pixel adresses */
ACCW(CXBNDRY,(((si->fbc.bytes_per_row / (depth >> 3)) - 1) << 16) | (0));
/* Y pixel addresses must be linear */
/* lowest adress */
ACCW(YTOP, 0 + src_dst);
/* highest adress */
ACCW(YBOT,((si->dm.virtual_height - 1) *
(si->fbc.bytes_per_row / (depth >> 3))) + src_dst);
return B_OK;
}
/* screen to screen blit - i.e. move windows around.
* Engine function bitblit, paragraph 4.5.7.2 */
status_t nv_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
{
uint32 t_start,t_end,offset;
uint32 b_start,b_end;
/*find where the top,bottom and offset are*/
offset = (si->fbc.bytes_per_row / (depth >> 3));
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
case 0: /*L->R,down*/
ACCW(SGN,0);
ACCW(AR3,t_start);
ACCW(AR0,t_end);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 1: /*L->R,up*/
ACCW(SGN,4);
ACCW(AR3,b_start);
ACCW(AR0,b_end);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
case 2: /*R->L,down*/
ACCW(SGN,1);
ACCW(AR3,t_end);
ACCW(AR0,t_start);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 3: /*R->L,up*/
ACCW(SGN,5);
ACCW(AR3,b_end);
ACCW(AR0,b_start);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
}
ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/
ACCGO(DWGCTL,0x040C4018); // atype RSTR
return B_OK;
}
/* screen to screen tranparent blit - not sure what uses this.
* Engine function bitblit, paragraph 4.5.7.2 */
status_t nv_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
{
uint32 t_start,t_end,offset;
uint32 b_start,b_end;
return B_ERROR;
/*find where the top,bottom and offset are*/
offset = (si->fbc.bytes_per_row / (depth >> 3));
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
case 0: /*L->R,down*/
ACCW(SGN,0);
ACCW(AR3,t_start);
ACCW(AR0,t_end);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 1: /*L->R,up*/
ACCW(SGN,4);
ACCW(AR3,b_start);
ACCW(AR0,b_end);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
case 2: /*R->L,down*/
ACCW(SGN,1);
ACCW(AR3,t_end);
ACCW(AR0,t_start);
ACCW(AR5,offset);
ACCW_YDSTLEN(yd,h+1);
break;
case 3: /*R->L,up*/
ACCW(SGN,5);
ACCW(AR3,b_end);
ACCW(AR0,b_start);
ACCW(AR5,-offset);
ACCW_YDSTLEN(yd+h,h+1);
break;
}
ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/
ACCW(FCOL,colour);
ACCW(BCOL,0xffffffff);
ACCGO(DWGCTL,0x440C4018); // atype RSTR
return B_OK;
}
/* rectangle fill.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/
status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
/*
FXBNDRY - left and right coordinates a
YDSTLEN - y start and no of lines a
(or YDST and LEN)
DWGCTL - atype must be RSTR or BLK a
FCOL - foreground colour a
*/
ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
//acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode
// for other functions, and use fastblt on MIL1/2 if possible...
//or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?)
if (si->dm.space==B_CMAP8 || si->ps.sdram)
{
ACCGO(DWGCTL,0x400C7814); // atype RSTR
}
else
{
ACCGO(DWGCTL,0x400C7844); // atype BLK
}
return B_OK;
}
/* rectangle invert.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/
status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
// int i;
// uint32 * dma;
// uint32 pci;
/*
FXBNDRY - left and right coordinates a
YDSTLEN - y start and no of lines a
(or YDST and LEN)
DWGCTL - atype must be RSTR or BLK a
FCOL - foreground colour a
*/
ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
/*draw it! top nibble is c is clipping enabled*/
ACCGO(DWGCTL,0x40057814); // atype RSTR
/*pseudo_dma version!*/
//NVACC_DWGCTL =0x1C00,
//NVACC_FCOL =0x1C24,
//NVACC_FXBNDRY =0x1C84,
//NVACC_YDSTLEN =0x1C88,
//
//40,09,21,22 (ordered as registers)
// dma = (uint32 *)si->pseudo_dma;
// *dma++=0x40092221;
// *dma++=(xe<<16)|xs;
// *dma++=(ys<<16)|yl;
// *dma++=col;
// *dma++=0x40057814;
/*real dma version!*/
// dma = (vuint32 *)si->dma_buffer;
// *dma++=0x40092221;/*indices*/
// *dma++=(xe<<16)|xs;
// *dma++=(ys<<16)|yl;
// *dma++=col;
// *dma++=0x40057814;
// pci = si->dma_buffer_pci;
// ACCW(PRIMADDRESS,(pci));
// ACCW(PRIMEND,(20+pci));
// delay(100);
return B_OK;
}
/* screen to screen scaled filtered blit - i.e. scale video in memory.
* Engine function texture mapping for video, paragraphs 4.5.5.5 - 4.5.5.9 */
status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
uint16 xd,uint16 yd,uint16 wd,uint16 hd)
{
//fixme: implement. Used for G450/G550 Desktop TVout...
//fixme: see if MIL1 - G200 support this function as well...
return B_OK;
}
@@ -0,0 +1,699 @@
/* G200-G550 Back End Scaler functions */
/* Written by Rudolf Cornelissen 05/2002-04/2003 */
#define MODULE_BIT 0x00000200
#include "nv_std.h"
//fixme: implement: (used for virtual screens!)
//void move_overlay(uint16 hdisp_start, uint16 vdisp_start);
status_t nv_configure_bes
(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset)
{
/* yuy2 (4:2:2) colorspace calculations */
/* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */
/* Note:
* in BeOS R5.0.3 and DANO:
* 'ow->offset_xxx' is always 0, so not used;
* 'ow->width' and 'ow->height' are the output window size: does not change
* if window is clipping;
* 'ow->h_start' and 'ow->v_start' are the left-top position of the output
* window. These values can be negative: this means the window is clipping
* at the left or the top of the display, respectively. */
/* 'ov' is the view in the source bitmap, so which part of the bitmap is actually
* displayed on screen. This is used for the 'hardware zoom' function. */
/* calculated BES register values */
uint32 hcoordv, vcoordv, hiscalv, hsrcstv, hsrcendv, hsrclstv,
viscalv, a1orgv, v1wghtv, v1srclstv, globctlv, ctlv;
/* misc used variables */
uint16 temp1, temp2;
/* interval representation, used for scaling calculations */
uint16 intrep, crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
/* inverse scaling factor, used for source positioning */
uint32 ifactor;
/* used for vertical weight starting value */
uint32 weight;
/* copy of overlay view which has checked valid values */
overlay_view my_ov;
/* Slowdown the G200-G550 BES if the pixelclock is too high for it to cope.
* This will in fact half the horizontal resolution of the BES with high
* pixelclocks (by setting a BES hardware 'zoom' = 2x).
* If you want optimal output quality better make sure you set the refreshrate/resolution
* of your monitor not too high ... */
uint16 acczoom = 1;
LOG(4,("Overlay: pixelclock is %dkHz, ", si->dm.timing.pixel_clock));
if (si->dm.timing.pixel_clock > BESMAXSPEED)
{
/* BES running at half speed and resolution */
/* This is how it works (BES slowing down):
* - Activate BES internal horizontal hardware scaling = 4x (in GLOBCTL below),
* - This also sets up BES only getting half the amount of pixels per line from
* the input picture buffer (in effect half-ing the BES pixelclock input speed).
* Now in order to get the picture back to original size, we need to also double
* the inverse horizontal scaling factor here (x4 /2 /2 = 1x again).
* Note that every other pixel is now doubled or interpolated, according to another
* GLOBCTL bit. */
acczoom = 2;
LOG(4,("slowing down BES!\n"));
}
else
{
/* BES running at full speed and resolution */
LOG(4,("BES is running at full speed\n"));
}
/**************************************************************************************
*** copy, check and limit if needed the user-specified view into the intput bitmap ***
**************************************************************************************/
my_ov = *ov;
/* check for valid 'coordinates' */
if (my_ov.width == 0) my_ov.width++;
if (my_ov.height == 0) my_ov.height++;
if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
if (my_ov.v_start > (ob->height - 1))
my_ov.v_start = (ob->height - 1);
if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
/* the BES does not respect virtual_workspaces, but adheres to CRTC
* constraints only */
crtc_hstart = si->dm.h_display_start;
/* make dualhead switch mode with TVout enabled work while we're at it.. */
if (si->switched_crtcs)
{
crtc_hstart += si->dm.timing.h_display;
}
/* horizontal end is the first position beyond the displayed range on the CRTC */
crtc_hend = crtc_hstart + si->dm.timing.h_display;
crtc_vstart = si->dm.v_display_start;
/* vertical end is the first position beyond the displayed range on the CRTC */
crtc_vend = crtc_vstart + si->dm.timing.v_display;
/****************************************
*** setup all edges of output window ***
****************************************/
/* setup left and right edges of output window */
hcoordv = 0;
/* left edge coordinate of output window, must be inside desktop */
/* clipping on the left side */
if (ow->h_start < crtc_hstart)
{
temp1 = 0;
}
else
{
/* clipping on the right side */
if (ow->h_start >= (crtc_hend - 1))
{
/* width < 2 is not allowed */
temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (ow->h_start - crtc_hstart) & 0x7ff;
}
}
hcoordv |= temp1 << 16;
/* right edge coordinate of output window, must be inside desktop */
/* width < 2 is not allowed */
if (ow->width < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the right side */
if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
{
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
}
else
{
/* clipping on the left side */
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
{
/* width < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1)) & 0x7ff;
}
}
}
hcoordv |= temp2 << 0;
LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
/* setup top and bottom edges of output window */
vcoordv = 0;
/* top edge coordinate of output window, must be inside desktop */
/* clipping on the top side */
if (ow->v_start < crtc_vstart)
{
temp1 = 0;
}
else
{
/* clipping on the bottom side */
if (ow->v_start >= (crtc_vend - 1))
{
/* height < 2 is not allowed */
temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (ow->v_start - crtc_vstart) & 0x7ff;
}
}
vcoordv |= temp1 << 16;
/* bottom edge coordinate of output window, must be inside desktop */
/* height < 2 is not allowed */
if (ow->height < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
/* clipping on the bottom side */
if ((ow->v_start + ow->height - 1) > (crtc_vend - 1))
{
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
}
else
{
/* clipping on the top side */
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
{
/* height < 2 is not allowed */
temp2 = 1;
}
else
/* no clipping here */
{
temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1)) & 0x7ff;
}
}
}
vcoordv |= temp2 << 0;
LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
/*********************************************
*** setup horizontal scaling and clipping ***
*********************************************/
LOG(6,("Overlay: total input picture width = %d, height = %d\n",
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
/* do horizontal scaling... */
/* determine interval representation value, taking zoom into account */
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
{
/* horizontal filtering is ON */
if ((my_ov.width == ow->width) | (ow->width < 2))
{
/* no horizontal scaling used, OR destination width < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* horizontal filtering is OFF */
if ((ow->width < my_ov.width) & (ow->width >= 2))
{
/* horizontal downscaling used AND destination width >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep));
/* calculate inverse horizontal scaling factor, taking zoom into account */
/* standard scaling formula: */
ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep);
/* correct factor to prevent most-right visible 'line' from distorting */
ifactor -= (1 << 2);
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
/* compensate for accelerated 2x zoom (slowdown BES if pixelclock is too high) */
hiscalv = ifactor * acczoom;
LOG(4,("Overlay: horizontal speed compensated factor is %f\n", (float)65536 / hiscalv));
/* check scaling factor (and modify if needed) to be within scaling limits */
if (((((uint32)my_ov.width) << 16) / 16384) > hiscalv)
{
/* (non-inverse) factor too large, set factor to max. valid value */
hiscalv = ((((uint32)my_ov.width) << 16) / 16384);
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv));
}
if (hiscalv >= (32 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
hiscalv = 0x1ffffc;
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
}
/* AND below is required by hardware */
hiscalv &= 0x001ffffc;
/* do horizontal clipping... */
/* Setup horizontal source start: first (sub)pixel contributing to output picture */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* After this is done, include the scaling factor so you get a value based on the input bitmap.
* Then add the left starting position of the bitmap's view (zoom function) to get the final value needed.
* Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
hsrcstv = 0;
/* check for destination horizontal clipping at left side */
if (ow->h_start < crtc_hstart)
{
/* check if entire destination picture is clipping left:
* (2 pixels will be clamped onscreen at least) */
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
{
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
hsrcstv += (ow->width - 2);
}
else
{
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
hsrcstv += (crtc_hstart - ow->h_start);
}
LOG(4,("Overlay: clipping left...\n"));
/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
* Note that this also already takes care of aligning the value to the BES register! */
hsrcstv *= ifactor;
}
/* take zoom into account */
hsrcstv += ((uint32)my_ov.h_start) << 16;
/* AND below required by hardware */
hsrcstv &= 0x03fffffc;
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", hsrcstv / (float)65536));
/* Setup horizontal source end: last (sub)pixel contributing to output picture */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* After this is done, include the scaling factor so you get a value based on the input bitmap.
* Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
hsrcendv = 0;
/* check for destination horizontal clipping at right side */
if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
{
/* check if entire destination picture is clipping right:
* (2 pixels will be clamped onscreen at least) */
if (ow->h_start > (crtc_hend - 2))
{
/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
hsrcendv += (ow->width - 2);
}
else
{
/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 1));
}
LOG(4,("Overlay: clipping right...\n"));
/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
* Note that this also already takes care of aligning the value to the BES register! */
hsrcendv *= ifactor;
/* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */
hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16) - hsrcendv;
}
else
{
/* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */
hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16);
}
/* AND below required by hardware */
hsrcendv &= 0x03fffffc;
LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", hsrcendv / (float)65536));
/* setup horizontal source last position excluding slopspace:
* this is the last pixel that will be used for calculating interpolated pixels */
hsrclstv = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16;
/* AND below required by hardware */
hsrclstv &= 0x03ff0000;
/*******************************************
*** setup vertical scaling and clipping ***
*******************************************/
/* do vertical scaling... */
/* determine interval representation value, taking zoom into account */
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
{
/* vertical filtering is ON */
if ((my_ov.height == ow->height) | (ow->height < 2))
{
/* no vertical scaling used, OR destination height < 2 */
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
/* vertical filtering is OFF */
if ((ow->height < my_ov.height) & (ow->height >= 2))
{
/* vertical downscaling used AND destination height >= 2 */
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: vertical interval representation value is %d\n",intrep));
/* calculate inverse vertical scaling factor, taking zoom into account */
/* standard scaling formula: */
ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep);
/* correct factor to prevent lowest visible line from distorting */
ifactor -= (1 << 2);
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor));
/* preserve ifactor for source positioning calculations later on */
viscalv = ifactor;
/* check scaling factor (and modify if needed) to be within scaling limits */
if (((((uint32)my_ov.height) << 16) / 16384) > viscalv)
{
/* (non-inverse) factor too large, set factor to max. valid value */
viscalv = ((((uint32)my_ov.height) << 16) / 16384);
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv));
}
if (viscalv >= (32 << 16))
{
/* (non-inverse) factor too small, set factor to min. valid value */
viscalv = 0x1ffffc;
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
}
/* AND below is required by hardware */
viscalv &= 0x001ffffc;
/* do vertical clipping... */
/* Setup vertical source start: first (sub)pixel contributing to output picture.
* Note: this exists of two parts:
* 1. setup fractional part (sign is always 'positive');
* 2. setup relative base_adress, taking clipping on top (and zoom) into account.
* Both parts are done intertwined below. */
/* Note:
* The method is to calculate, based on 1:1 scaling, based on the output window.
* 'After' this is done, include the scaling factor so you get a value based on the input bitmap.
* Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
/* calculate relative base_adress and 'vertical weight fractional part' */
weight = 0;
a1orgv = (uint32)((vuint32 *)ob->buffer);
a1orgv -= (uint32)((vuint32 *)si->framebuffer);
/* calculate origin adress */
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv));
/* check for destination vertical clipping at top side */
if (ow->v_start < crtc_vstart)
{
/* check if entire destination picture is clipping at top:
* (2 pixels will be clamped onscreen at least) */
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
{
/* increase source buffer origin with 'fixed value':
* (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) *
* bytes per row source picture */
a1orgv += ((((ow->height - 2) * ifactor) >> 16) * ob->bytes_per_row);
weight = (ow->height - 2) * ifactor;
}
else
{
/* increase source buffer origin with:
* (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
* bytes per row source picture */
a1orgv += ((((crtc_vstart - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
weight = (crtc_vstart - ow->v_start) * ifactor;
}
LOG(4,("Overlay: clipping at top...\n"));
}
/* take zoom into account */
a1orgv += (my_ov.v_start * ob->bytes_per_row);
weight += (((uint32)my_ov.v_start) << 16);
LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n",a1orgv));
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", weight / (float)65536));
/* Note:
* Because all > G200 overlay units will ignore b0-3 of the calculated adress,
* we do not use the above way for horizontal source positioning.
* (G200 cards ignore b0-2.)
* If we did, 8 source-image pixel jumps (in 4:2:2 colorspace) will occur if the picture
* is shifted horizontally during left clipping on all > G200 cards, while G200 cards
* will have 4 source-image pixel jumps occuring. */
/* AND below is required by G200-G550 hardware. > G200 cards can have max. 32Mb RAM on board
* (16Mb on G200 cards). Compatible setting used (between G200 and the rest), this has no
* downside consequences here. */
/* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */
a1orgv &= 0x01fffff0;
/* field 1 weight: AND below required by hardware, also make sure 'sign' is always 'positive' */
v1wghtv = weight & 0x0000fffc;
/* setup field 1 (is our complete frame) vertical source last position.
* this is the last pixel that will be used for calculating interpolated pixels */
v1srclstv = (ob->height - 1);
/* AND below required by hardware */
v1srclstv &= 0x000003ff;
/*****************************
*** log color keying info ***
*****************************/
LOG(6,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
LOG(6,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
/*************************
*** setup BES control ***
*************************/
/* BES global control: setup functions */
globctlv = 0;
/* slowdown BES if nessesary */
if (acczoom == 1)
{
/* run at full speed and resolution */
globctlv |= 0 << 0;
/* disable filtering for half speed interpolation */
globctlv |= 0 << 1;
}
else
{
/* run at half speed and resolution */
globctlv |= 1 << 0;
/* enable filtering for half speed interpolation */
globctlv |= 1 << 1;
}
/* 4:2:0 specific setup: not needed here */
globctlv |= 0 << 3;
/* BES testregister: keep zero */
globctlv |= 0 << 4;
/* the following bits marked (> G200) *must* be zero on G200: */
/* 4:2:0 specific setup: not needed here (> G200) */
globctlv |= 0 << 5;
/* select yuy2 byte-order to B_YCbCr422 (> G200) */
globctlv |= 0 << 6;
/* BES internal contrast and brighness controls are not used, disabled (> G200) */
globctlv |= 0 << 7;
/* RGB specific setup: not needed here, so disabled (> G200) */
globctlv |= 0 << 8;
globctlv |= 0 << 9;
/* 4:2:0 specific setup: not needed here (> G200) */
globctlv |= 0 << 10;
/* Tell BES when to copy the new register values to the actual active registers.
* bits 16-27 (12 bits) are the CRTC vert. count value at which copying takes
* place.
* (This is the double buffering feature: programming must be completed *before*
* the CRTC vert count value set here!) */
/* CRTC vert count for copying = $000, so during retrace, line 0. */
globctlv |= 0x000 << 16;
/* BES control: enable scaler and setup functions */
/* pre-reset all bits */
ctlv = 0;
/* enable BES */
ctlv |= 1 << 0;
/* we start displaying at an even startline (zero) in 'field 1' (no hardware de-interlacing is used) */
ctlv |= 0 << 6;
/* we don't use field 2, so its startline is not important */
ctlv |= 0 << 7;
LOG(6,("Overlay: ow->flags is $%08x\n",ow->flags));
/* enable horizontal filtering on scaling if asked for: if we *are* actually scaling */
if ((ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) && (hiscalv != (0x01 << 16)))
{
ctlv |= 1 << 10;
LOG(6,("Overlay: using horizontal interpolation on scaling\n"));
}
else
{
ctlv |= 0 << 10;
LOG(6,("Overlay: using horizontal dropping or replication on scaling\n"));
}
/* enable vertical filtering on scaling if asked for: if we are *upscaling* only */
if ((ow->flags & B_OVERLAY_VERTICAL_FILTERING) && (viscalv < (0x01 << 16)))
{
ctlv |= 1 << 11;
LOG(6,("Overlay: using vertical interpolation on scaling\n"));
}
else
{
ctlv |= 0 << 11;
LOG(6,("Overlay: using vertical dropping or replication on scaling\n"));
}
/* use actual calculated weight for horizontal interpolation */
ctlv |= 0 << 12;
/* use horizontal chroma interpolation upsampling on BES input picture */
ctlv |= 1 << 16;
/* select 4:2:2 BES input format */
ctlv |= 0 << 17;
/* dithering is enabled */
ctlv |= 1 << 18;
/* horizontal mirroring is not used */
ctlv |= 0 << 19;
/* BES output should be in color */
ctlv |= 0 << 20;
/* BES output blanking is disabled: we want a picture, no 'black box'! */
ctlv |= 0 << 21;
/* we do software field select (field select is not used) */
ctlv |= 0 << 24;
/* we always display field 1 in buffer A, this contains our full frames */
/* select field 1 */
ctlv |= 0 << 25;
/* select buffer A */
ctlv |= 0 << 26;
/*************************************
*** sync to BES (Back End Scaler) ***
*************************************/
/* Make sure reprogramming the BES completes before the next retrace occurs,
* to prevent register-update glitches (double buffer feature). */
LOG(3,("Overlay: starting register programming beyond Vcount %d\n", CR1R(VCOUNT)));
/* Even at 1600x1200x90Hz, a single line still takes about 9uS to complete:
* this resolution will generate about 180Mhz pixelclock while we can do
* upto 360Mhz. So snooze about 4uS to prevent bus-congestion...
* Appr. 200 lines time will provide enough room even on a 100Mhz CPU if it's
* screen is set to the highest refreshrate/resolution possible. */
while (CR1R(VCOUNT) > (si->dm.timing.v_total - 200)) snooze(4);
/**************************************
*** actually program the registers ***
**************************************/
BESW(HCOORD, hcoordv);
BESW(VCOORD, vcoordv);
BESW(HISCAL, hiscalv);
BESW(HSRCST, hsrcstv);
BESW(HSRCEND, hsrcendv);
BESW(HSRCLST, hsrclstv);
BESW(VISCAL, viscalv);
BESW(A1ORG, a1orgv);
BESW(V1WGHT, v1wghtv);
BESW(V1SRCLST, v1srclstv);
BESW(GLOBCTL, globctlv);
BESW(CTL, ctlv);
/**************************
*** setup color keying ***
**************************/
/* setup colorkeying */
// DXIW(COLKEY, (ow->alpha.value & ow->alpha.mask));
// DXIW(COLKEY0RED, (ow->red.value & ow->red.mask));
// DXIW(COLKEY0GREEN, (ow->green.value & ow->green.mask));
// DXIW(COLKEY0BLUE, (ow->blue.value & ow->blue.mask));
// DXIW(COLMSK, ow->alpha.mask);
// DXIW(COLMSK0RED, ow->red.mask);
// DXIW(COLMSK0GREEN, ow->green.mask);
// DXIW(COLMSK0BLUE, ow->blue.mask);
/* enable colorkeying */
// DXIW(KEYOPMODE,0x01);
/*************************
*** setup misc. stuff ***
*************************/
/* setup brightness and contrast to be 'neutral' (this is not implemented on G200) */
BESW(LUMACTL, 0x00000080);
/* setup source pitch including slopspace (in pixels); AND is required by hardware */
BESW(PITCH, (ob->width & 0x00000fff));
/* on a 500Mhz P3 CPU just logging a line costs 400uS (18-19 vcounts at 1024x768x60Hz)!
* programming the registers above actually costs 180uS here */
LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT)));
return B_OK;
}
status_t nv_release_bes()
{
/* setup BES control: disable scaler */
BESW(CTL, 0x00000000);
return B_OK;
}
@@ -0,0 +1,543 @@
/* CTRC functionality */
/* Author:
Rudolf Cornelissen 11/2002-7/2003
*/
#define MODULE_BIT 0x00040000
#include "nv_std.h"
/*Adjust passed parameters to a valid mode line*/
status_t nv_crtc_validate_timing(
uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
)
{
/* horizontal */
/* make all parameters multiples of 8 */
*hd_e &= 0xfff8;
*hs_s &= 0xfff8;
*hs_e &= 0xfff8;
*ht &= 0xfff8;
/* confine to required number of bits, taking logic into account */
if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3);
if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3);
/* NOTE: keep horizontal timing at multiples of 8! */
/* confine to a reasonable width */
if (*hd_e < 640) *hd_e = 640;
if (si->ps.card_type > NV04)
{
if (*hd_e > 2048) *hd_e = 2048;
}
else
{
if (*hd_e > 1920) *hd_e = 1920;
}
/* if hor. total does not leave room for a sensible sync pulse, increase it! */
if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
/* make sure sync pulse is not during display */
if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
/* correct sync pulse if it is too long:
* there are only 5 bits available to save this in the card registers! */
if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
/*vertical*/
/* confine to required number of bits, taking logic into account */
if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
if (*vs_e > 0x7ff ) *vs_e = 0x7ff ;
if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2);
/* confine to a reasonable height */
if (*vd_e < 480) *vd_e = 480;
if (si->ps.card_type > NV04)
{
if (*vd_e > 1536) *vd_e = 1536;
}
else
{
if (*vd_e > 1440) *vd_e = 1440;
}
/*if vertical total does not leave room for a sync pulse, increase it!*/
if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
/* make sure sync pulse is not during display */
if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
/* correct sync pulse if it is too long:
* there are only 4 bits available to save this in the card registers! */
if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
return B_OK;
}
/*set a mode line - inputs are in pixels*/
status_t nv_crtc_set_timing(display_mode target)
{
uint8 temp;
uint32 htotal; /*total horizontal total VCLKs*/
uint32 hdisp_e; /*end of horizontal display (begins at 0)*/
uint32 hsync_s; /*begin of horizontal sync pulse*/
uint32 hsync_e; /*end of horizontal sync pulse*/
uint32 hblnk_s; /*begin horizontal blanking*/
uint32 hblnk_e; /*end horizontal blanking*/
uint32 vtotal; /*total vertical total scanlines*/
uint32 vdisp_e; /*end of vertical display*/
uint32 vsync_s; /*begin of vertical sync pulse*/
uint32 vsync_e; /*end of vertical sync pulse*/
uint32 vblnk_s; /*begin vertical blanking*/
uint32 vblnk_e; /*end vertical blanking*/
uint32 linecomp; /*split screen and vdisp_e interrupt*/
LOG(4,("CRTC: setting timing\n"));
/* Modify parameters as required by standard VGA */
htotal = ((target.timing.h_total >> 3) - 5);
hdisp_e = ((target.timing.h_display >> 3) - 1);
hblnk_s = hdisp_e;
hblnk_e = (htotal + 4);//0;
hsync_s = (target.timing.h_sync_start >> 3);
hsync_e = (target.timing.h_sync_end >> 3);
vtotal = target.timing.v_total - 2;
vdisp_e = target.timing.v_display - 1;
vblnk_s = vdisp_e;
vblnk_e = (vtotal + 1);
vsync_s = target.timing.v_sync_start;//-1;
vsync_e = target.timing.v_sync_end;//-1;
/* prevent memory adress counter from being reset (linecomp may not occur) */
linecomp = target.timing.v_display;
//fixme: flatpanel 'don't touch' update needed for 'Go' cards!?!
if (true)
{
LOG(4,("CRTC: CRT only mode, setting full timing...\n"));
/* log the mode that will be set */
LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
/* actually program the card! */
/* unlock CRTC registers at index 0-7 */
CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f));
/* horizontal standard VGA regs */
CRTCW(HTOTAL, (htotal & 0xff));
CRTCW(HDISPE, (hdisp_e & 0xff));
CRTCW(HBLANKS, (hblnk_s & 0xff));
/* also unlock vertical retrace registers in advance */
CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
CRTCW(HSYNCS, (hsync_s & 0xff));
CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
/* vertical standard VGA regs */
CRTCW(VTOTAL, (vtotal & 0xff));
CRTCW(OVERFLOW,
(
((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
));
CRTCW(PRROWSCN, 0x00); /* not used */
CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
CRTCW(VSYNCS, (vsync_s & 0xff));
CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
CRTCW(VDISPE, (vdisp_e & 0xff));
CRTCW(VBLANKS, (vblnk_s & 0xff));
CRTCW(VBLANKE, (vblnk_e & 0xff));
CRTCW(LINECOMP, (linecomp & 0xff));
/* horizontal extended regs */
//fixme: we reset bit4. is this correct??
CRTCW(HEB, (CRTCR(HEB) & 0xe0) |
(
((htotal & 0x100) >> (8 - 0)) |
((hdisp_e & 0x100) >> (8 - 1)) |
((hblnk_s & 0x100) >> (8 - 2)) |
((hsync_s & 0x100) >> (8 - 3))
));
/* (mostly) vertical extended regs */
CRTCW(LSR,
(
((vtotal & 0x400) >> (10 - 0)) |
((vdisp_e & 0x400) >> (10 - 1)) |
((vsync_s & 0x400) >> (10 - 2)) |
((vblnk_s & 0x400) >> (10 - 3)) |
((hblnk_e & 0x040) >> (6 - 4))
//fixme: we still miss one linecomp bit!?! is this it??
//| ((linecomp & 0x400) >> 3)
));
/* setup 'large screen' mode */
if (target.timing.h_display >= 1280)
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb));
else
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04));
/* setup HSYNC & VSYNC polarity */
LOG(2,("CRTC: sync polarity: "));
temp = NV_REG8(NV8_MISCR);
if (target.timing.flags & B_POSITIVE_HSYNC)
{
LOG(2,("H:pos "));
temp &= ~0x40;
}
else
{
LOG(2,("H:neg "));
temp |= 0x40;
}
if (target.timing.flags & B_POSITIVE_VSYNC)
{
LOG(2,("V:pos "));
temp &= ~0x80;
}
else
{
LOG(2,("V:neg "));
temp |= 0x80;
}
NV_REG8(NV8_MISCW) = temp;
LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
}
return B_OK;
}
status_t nv_crtc_depth(int mode)
{
uint8 viddelay = 0;
uint32 genctrl = 0;
/* set VCLK scaling */
switch(mode)
{
case BPP8:
viddelay = 0x01;
/* genctrl b4 & b5 reset: 'direct mode' */
genctrl = 0x00101100;
break;
case BPP15:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP16:
viddelay = 0x02;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
case BPP24:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00100130;
break;
case BPP32:
viddelay = 0x03;
/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
genctrl = 0x00101130;
break;
}
CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay));
DACW(GENCTRL, genctrl);
return B_OK;
}
status_t nv_crtc_dpms(bool display, bool h, bool v)
{
uint8 temp;
LOG(4,("CRTC: setting DPMS: "));
/* start synchronous reset: required before turning screen off! */
SEQW(RESET, 0x01);
/* turn screen off */
temp = SEQR(CLKMODE);
if (display)
{
SEQW(CLKMODE, (temp & ~0x20));
/* end synchronous reset if display should be enabled */
SEQW(RESET, 0x03);
LOG(4,("display on, "));
}
else
{
SEQW(CLKMODE, (temp | 0x20));
LOG(4,("display off, "));
}
if (h)
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f));
LOG(4,("hsync enabled, "));
}
else
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80));
LOG(4,("hsync disabled, "));
}
if (v)
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf));
LOG(4,("vsync enabled\n"));
}
else
{
CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40));
LOG(4,("vsync disabled\n"));
}
return B_OK;
}
status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v)
{
*display = !(SEQR(CLKMODE) & 0x20);
*h = !(CRTCR(REPAINT1) & 0x80);
*v = !(CRTCR(REPAINT1) & 0x40);
LOG(4,("CTRC: fetched DPMS state:"));
if (display) LOG(4,("display on, "));
else LOG(4,("display off, "));
if (h) LOG(4,("hsync enabled, "));
else LOG(4,("hsync disabled, "));
if (v) LOG(4,("vsync enabled\n"));
else LOG(4,("vsync disabled\n"));
return B_OK;
}
status_t nv_crtc_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
/* figure out offset value hardware needs */
offset = si->fbc.bytes_per_row / 8;
LOG(2,("CRTC: offset register set to: $%04x\n", offset));
/*program the card!*/
CRTCW(PITCHL, (offset & 0x00ff));
CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
return B_OK;
}
status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp)
{
uint8 temp;
LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
LOG(2,("CRTC: startadd: $%08x\n", startadd));
LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer));
LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer));
//fixme? on TNT1, TNT2, and GF2MX400 not needed. How about the rest??
/* make sure we are in retrace on MIL cards (if possible), because otherwise
* distortions might occur during our reprogramming them (no double buffering) */
// if (si->ps.card_type < G100)
// {
/* we might have no retraces during setmode! */
// uint32 timeout = 0;
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
// while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4)))
// {
// snooze(4);
// timeout++;
// }
// }
if (si->ps.card_arch == NV04A)
{
/* upto 32Mb RAM adressing: must be used this way on pre-NV10! */
/* set standard registers */
/* (NVidia: startadress in 32bit words (b2 - b17) */
CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2));
CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10));
/* set extended registers */
/* NV4 extended bits: (b18-22) */
temp = (CRTCR(REPAINT0) & 0xe0);
CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18)));
/* NV4 extended bits: (b23-24) */
temp = (CRTCR(HEB) & 0x9f);
CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18)));
}
else
{
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
/* NOTE:
* While this register also exists on pre-NV10 cards, it will
* wrap-around at 16Mb boundaries!! */
/* 30bit adress in 32bit words */
NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc);
}
/* set NV4/NV10 byte adress: (b0 - 1) */
temp = (ATBR(HORPIXPAN) & 0xf9);
ATBW(HORPIXPAN, (temp | ((startadd & 0x00000003) << 1)));
return B_OK;
}
status_t nv_crtc_cursor_init()
{
int i;
uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer */
const uint32 curadd = 0;
/* set cursor bitmap adress ... */
if (si->ps.card_arch == NV04A)
{
/* must be used this way on pre-NV10! */
/* cursorbitmap must start on 2Kbyte boundary: */
/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9));
/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
/* set adress bit24-31 */
CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24));
}
else
{
/* upto 4Gb RAM adressing: must be used on NV10 and later! */
/* NOTE:
* This register does not exist on pre-NV10 cards. */
/* cursorbitmap must still start on 2Kbyte boundary: */
NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800);
}
/* set cursor colour: not needed because of direct nature of cursor bitmap. */
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(2048/4);i++)
{
fb[i]=0;
}
/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
NV_REG32(NV32_CURCONF) = 0x02000100;
/* activate hardware cursor */
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
return B_OK;
}
status_t nv_crtc_cursor_show()
{
/* b0 = 1 enables cursor */
CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01));
return B_OK;
}
status_t nv_crtc_cursor_hide()
{
/* b0 = 0 disables cursor */
CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe));
return B_OK;
}
/*set up cursor shape*/
status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{
int x, y;
uint8 b;
uint16 *cursor;
uint16 pixel;
/* get a pointer to the cursor */
cursor = (uint16*) si->framebuffer;
/* draw the cursor */
/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
for (y = 0; y < 16; y++)
{
b = 0x80;
for (x = 0; x < 8; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
b = 0x80;
for (; x < 16; x++)
{
/* preset transparant */
pixel = 0x0000;
/* set white if requested */
if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
/* set black if requested */
if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000;
/* set invert if requested */
if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff;
/* place the pixel in the bitmap */
cursor[x + (y * 32)] = pixel;
b >>= 1;
}
xorMask++;
andMask++;
}
return B_OK;
}
/*position the cursor*/
status_t nv_crtc_cursor_position(uint16 x ,uint16 y)
{
/* make sure we are not in retrace, because the register(s) might get copied
* during our reprogramming them (double buffering feature) */
//fixme if needed...
/* while (ACCR(STATUS) & 0x08)
{
snooze(4);
}
*/
DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
return B_OK;
}
@@ -0,0 +1,247 @@
/* second CTRC functionality
Authors:
Mark Watson 6/2000,
Rudolf Cornelissen 12/2002 - 4/2003
*/
#define MODULE_BIT 0x00020000
#include "nv_std.h"
/*set a mode line - inputs are in pixels/scanlines*/
status_t g400_crtc2_set_timing(display_mode target)
{
uint32 temp;
LOG(4,("CRTC2: setting timing\n"));
// if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX))
{
/* G450/G550 monitor mode, and all modes on older cards */
/* check horizontal timing parameters are to nearest 8 pixels */
if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) |
(target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07))
{
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/* make sure NTSC clock killer circuitry is disabled */
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
/* make sure CRTC2 is set to progressive scan for monitor mode */
CR2W(CTL, (CR2R(CTL) & ~0x02001000));
/* program the second CRTC */
CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) |
((target.timing.h_total - 8) & 0x0fff)));
CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) |
((target.timing.h_sync_start - 8) & 0x0fff)));
CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) |
((target.timing.v_total - 1) & 0x0fff)));
CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) |
((target.timing.v_sync_start - 1) & 0x0fff)));
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
//CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) |
// (target.timing.h_sync_start & 0x0fff)));
CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) |
((target.timing.h_sync_start - 8) & 0x0fff)));
temp = (0xfff << 16);
if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
CR2W(MISC, temp);
/* On <= G400MAX dualhead cards we need to send a copy to the MAVEN;
* unless TVout is active */
if ((si->ps.secondary_head) && (!(target.flags & TV_BITS)))
nv_maven_set_timing(target);
}
// else
{
/* G450/G550 TVout mode */
display_mode tv_mode = target;
uint8 frame;
unsigned int vcount, prev_vcount;
LOG(4,("CRTC2: setting up G450/G550 TVout mode\n"));
/* check horizontal timing parameters are to nearest 8 pixels */
if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) |
(tv_mode.timing.h_sync_end & 0x07))
{
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/* disable NTSC clock killer circuitry */
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
if (tv_mode.timing.h_total & 0x07)
{
/* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */
LOG(4,("CRTC2: enabling clock killer circuitry\n"));
CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010));
}
/* make sure h_total is valid for TVout mode */
tv_mode.timing.h_total &= ~0x07;
/* modify tv_mode for interlaced use */
tv_mode.timing.v_display >>= 1;
tv_mode.timing.v_sync_start >>= 1;
tv_mode.timing.v_sync_end >>= 1;
tv_mode.timing.v_total >>= 1;
/*program the second CRTC*/
CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) |
((tv_mode.timing.h_total - 8) & 0x0fff)));
CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) |
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) |
((tv_mode.timing.v_total - 1) & 0x0fff)));
CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) |
((tv_mode.timing.v_sync_start - 1) & 0x0fff)));
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
//CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) |
// (tv_mode.timing.h_sync_start & 0x0fff)));
CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) |
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
/* set CRTC2 to interlaced mode:
* First enable progressive scan mode while making sure
* CRTC2 is setup for TVout mode use... */
CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000));
/* now synchronize to the start of a frame... */
prev_vcount = 0;
for (frame = 0; frame < 2; frame++)
{
for (;;)
{
vcount = (CR2R(VCOUNT) & 0x00000fff);
if (vcount >= prev_vcount)
prev_vcount = vcount;
else
break;
}
}
/* and start interlaced mode now! */
CR2W(CTL, (CR2R(CTL) | 0x02000000));
temp = (0xfff << 16);
if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
CR2W(MISC, temp);
}
return B_OK;
}
status_t g400_crtc2_depth(int mode)
{
/* validate bit depth and set mode */
/* also clears TVout mode (b12) */
switch(mode)
{
case BPP16:case BPP32DIR:
CR2W(CTL,(CR2R(CTL)&0xFF10077F)|(mode<<21));
break;
case BPP8:case BPP15:case BPP24:case BPP32:default:
LOG(8,("CRTC2:Invalid bit depth\n"));
return B_ERROR;
break;
}
return B_OK;
}
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v)
{
if (display & h & v)
{
/* enable CRTC2 and don't touch the rest */
CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01));
}
else
{
/* disable CRTC2 and don't touch the rest */
CR2W(CTL, (CR2R(CTL) & 0xFFF0177E));
}
// if (si->ps.card_type >= G450)
// {
//fixme:
/* setup monitor mode DPMS: G450 and later fully support this on CRTC2 */
//for now:
//enable 'straight-through' sync outputs on both analog output connectors...
// DXIW(SYNCCTRL,0x00);
// }
/* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */
if (si->ps.secondary_head) nv_maven_dpms(display, h, v);
return B_OK;
}
status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v)
{
*display=CR2R(CTL)&1;
*h=*v=1; /*h/vsync always enabled on second CRTC, does not support other*/
return B_OK;
}
status_t g400_crtc2_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
/* figure out offset value hardware needs */
offset = si->fbc.bytes_per_row;
if (si->interlaced_tv_mode)
{
LOG(4,("CRTC2: setting interlaced mode\n"));
/* double the CRTC2 linelength so fields are displayed instead of frames */
offset *= 2;
}
else
LOG(4,("CRTC2: setting progressive scan mode\n"));
LOG(2,("CRTC2: offset set to %d bytes\n", offset));
/* program the head */
CR2W(OFFSET,offset);
return B_OK;
}
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp)
{
LOG(4,("CRTC2: setting card RAM to be displayed for %d bits per pixel\n", bpp));
LOG(2,("CRTC2: startadd: $%x\n",startadd));
LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer));
LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer));
if (si->interlaced_tv_mode)
{
LOG(4,("CRTC2: setting up fields for interlaced mode\n"));
/* program the head for interlaced use */
//fixme: seperate both heads: we need a secondary si->fbc!
/* setup field 0 startadress in buffer to read picture's odd lines */
CR2W(STARTADD0, (startadd + si->fbc.bytes_per_row));
/* setup field 1 startadress in buffer to read picture's even lines */
CR2W(STARTADD1, startadd);
}
else
{
LOG(4,("CRTC2: setting up frames for progressive scan mode\n"));
/* program the head for non-interlaced use */
CR2W(STARTADD0, startadd);
}
return B_OK;
}
@@ -0,0 +1,462 @@
/* program the DAC */
/* Author:
Rudolf Cornelissen 7/2003
*/
#define MODULE_BIT 0x00010000
#include "nv_std.h"
static status_t nv4_nv10_nv20_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t nv_dac_mode(int mode,float brightness)
{
uint8 *r,*g,*b;
int i, ri;
/*set colour arrays to point to space reserved in shared info*/
r = si->color_data;
g = r + 256;
b = g + 256;
LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness));
/* init the palette for brightness specified */
/* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */
for (i = 0; i < 256; i++)
{
ri = i * brightness;
if (ri > 255) ri = 255;
b[i] = g[i] = r[i] = ri;
}
if (nv_dac_palette(r,g,b) != B_OK) return B_ERROR;
/*set the mode - also sets VCLK dividor*/
// DXIW(MULCTRL, mode);
// LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL)));
/* disable palette RAM adressing mask */
NV_REG8(NV8_PALMASK) = 0xff;
LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PALMASK)));
return B_OK;
}
/*program the DAC palette using the given r,g,b values*/
status_t nv_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256])
{
int i;
LOG(4,("DAC: setting palette\n"));
/* select first PAL adress before starting programming */
NV_REG8(NV8_PALINDW) = 0x00;
/* loop through all 256 to program DAC */
for (i = 0; i < 256; i++)
{
/* the 6 implemented bits are on b0-b5 of the bus */
NV_REG8(NV8_PALDATA) = r[i];
NV_REG8(NV8_PALDATA) = g[i];
NV_REG8(NV8_PALDATA) = b[i];
}
if (NV_REG8(NV8_PALINDW) != 0x00)
{
LOG(8,("DAC: PAL write index incorrect after programming\n"));
return B_ERROR;
}
if (1)
{//reread LUT
uint8 R, G, B;
/* select first PAL adress to read (modulo 3 counter) */
NV_REG8(NV8_PALINDR) = 0x00;
for (i = 0; i < 256; i++)
{
R = NV_REG8(NV8_PALDATA);
G = NV_REG8(NV8_PALDATA);
B = NV_REG8(NV8_PALDATA);
if ((r[i] != R) || (g[i] != G) || (b[i] != B))
LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
}
}
return B_OK;
}
/*program the pixpll - frequency in kHz*/
/*important notes:
* PIXPLLC is used - others should be kept as is
* BESCLK,CRTC2 are not touched
*/
status_t nv_dac_set_pix_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
// uint time = 0;
float pix_setting, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk));
/* signal that we actually want to set the mode */
result = nv_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*reprogram (disable,select,wait for stability,enable)*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
/* select pixelPLL registerset C */
DACW(PLLSEL, 0x10000700);
/* program new frequency */
DACW(PIXPLLC, ((p << 16) | (n << 8) | m));
/* Wait for the PIXPLL frequency to lock until timeout occurs */
//fixme: do NV cards have a LOCK indication bit??
/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: PIX PLL frequency not locked!\n"));
else
LOG(2,("DAC: PIX PLL frequency locked\n"));
DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL
*/
//for now:
/* Give the PIXPLL frequency some time to lock... */
snooze(1000);
LOG(2,("DAC: PIX PLL frequency should be locked now...\n"));
return B_OK;
}
/* find nearest valid pix pll */
status_t nv_dac_pix_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
switch (si->ps.card_type) {
default: return nv4_nv10_nv20_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
}
return B_ERROR;
}
/* find nearest valid pixel PLL setting */
static status_t nv4_nv10_nv20_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0, p = 0/*, m_max*/;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
/* switch(si->ps.card_type)
{
case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
*/
LOG(4,("DAC: NV4/NV10/NV20 restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac1_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 16.0))
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_pixel_vco / 16.0)));
req_pclk = (si->ps.min_pixel_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 7; m <= 14; m++)
{
/* check if phase-discriminator will be within operational limits */
if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue;
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 1) || (n > 255)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m = best[0];
n = best[1];
p = best[2];
/* log the VCO frequency found */
f_vco = ((si->ps.f_ref / m) * n);
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
/* return the results */
*calc_pclk = (f_vco / p);
*m_result = m;
*n_result = n;
switch(p)
{
case 1:
p = 0x00;
break;
case 2:
p = 0x01;
break;
case 4:
p = 0x02;
break;
case 8:
p = 0x03;
break;
case 16:
p = 0x04;
break;
}
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
/* find nearest valid system PLL setting */
static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
int best[3];
float f_vco;
/* determine the max. reference-frequency postscaler setting for the
* current card (see G100, G200 and G400 specs). */
switch(si->ps.card_type)
{
/* case G100:
LOG(4,("DAC: G100 restrictions apply\n"));
m_max = 7;
break;
case G200:
LOG(4,("DAC: G200 restrictions apply\n"));
m_max = 7;
break;
*/ default:
LOG(4,("DAC: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/* Make sure the requested systemclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 8.0))
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)(si->ps.min_system_vco / 8.0)));
req_sclk = (si->ps.min_system_vco / 8.0);
}
/* upper limit is max_system_vco */
if (req_sclk > si->ps.max_system_vco)
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)si->ps.max_system_vco));
req_sclk = si->ps.max_system_vco;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_sclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
/* calc the needed PLL loopbackfilter setting belonging to current VCO speed,
* for the current card (see G100, G200 and G400 specs). */
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
switch(si->ps.card_type)
{
default:
for(;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
/* return the results */
*calc_sclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_sclk, *calc_sclk, *m_result, *n_result, *p_result));
return B_OK;
}
/*set up system pll - NB mclk is memory clock */
status_t g400_dac_set_sys_pll()
{
/* values for DAC sys pll registers */
uint8 m, n, p;
// uint time = 0;
float calc_sclk;
LOG(1,("DAC: Setting up G400/G400MAX system clock\n"));
g100_g400max_dac_sys_pll_find((float)si->ps.std_engine_clock, &calc_sclk, &m, &n, &p);
/* reprogram the clock - set PCI/AGP, program, set to programmed */
/* clear, so don't o/clock addons */
// CFGW(OPTION2, 0);
/* disable the SYSPLL */
// CFGW(OPTION, CFGR(OPTION) | 0x04);
/* select the PCI/AGP clock */
// CFGW(OPTION3, 0);
/* enable the SYSPLL */
// CFGW(OPTION, CFGR(OPTION) & 0xfffffffb);
/* program the new clock */
// DXIW(SYSPLLM, m);
// DXIW(SYSPLLN, n);
// DXIW(SYSPLLP, p);
/* Wait for the SYSPLL frequency to lock until timeout occurs */
/* while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("DAC: sys PLL frequency not locked!\n"));
else
LOG(2,("DAC: sys PLL frequency locked\n"));
*/
/* disable the SYSPLL */
// CFGW(OPTION, CFGR(OPTION) | 0x04);
/* setup Gclk, Mclk and Wclk divs via PINS and select SYSPLL as system clock source */
// CFGW(OPTION3, si->ps.option3_reg);
/* make sure the PLLs are not swapped (set default config) */
// CFGW(OPTION, CFGR(OPTION) & 0xffffffbf);
/* enable the SYSPLL (and make sure the SYSPLL is indeed powered up) */
// CFGW(OPTION, (CFGR(OPTION) & 0xfffffffb) | 0x20);
return B_OK;
}
@@ -0,0 +1,963 @@
/* Authors:
Mark Watson 12/1999,
Apsed,
Rudolf Cornelissen 10/2002-7/2003
*/
#define MODULE_BIT 0x00008000
#include "nv_std.h"
//apsed #include "memory"
status_t test_ram();
static status_t nvxx_general_powerup (void);
static status_t nv_general_bios_to_powergraphics(void);
static void nv_dump_configuration_space (void)
{
#define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \
uint32 value = CFGR(reg); \
MSG(("configuration_space 0x%02x %20s 0x%08x\n", \
NVCFG_##reg, #reg, value)); \
} while (0)
DUMP_CFG (DEVID, 0);
DUMP_CFG (DEVCTRL, 0);
DUMP_CFG (CLASS, 0);
DUMP_CFG (HEADER, 0);
DUMP_CFG (BASE1REGS,0);
DUMP_CFG (BASE2FB, 0);
DUMP_CFG (BASE3, 0);
DUMP_CFG (BASE4, 0);
DUMP_CFG (BASE5, 0);
DUMP_CFG (BASE6, 0);
DUMP_CFG (BASE7, 0);
DUMP_CFG (SUBSYSID1,0);
DUMP_CFG (ROMBASE, 0);
DUMP_CFG (CFG_0, 0);
DUMP_CFG (CFG_1, 0);
DUMP_CFG (INTERRUPT,0);
DUMP_CFG (SUBSYSID2,0);
DUMP_CFG (AGPREF, 0);
DUMP_CFG (AGPSTAT, 0);
DUMP_CFG (AGPCMD, 0);
DUMP_CFG (ROMSHADOW,0);
DUMP_CFG (VGA, 0);
DUMP_CFG (SCHRATCH, 0);
DUMP_CFG (CFG_10, 0);
DUMP_CFG (CFG_11, 0);
DUMP_CFG (CFG_12, 0);
DUMP_CFG (CFG_13, 0);
DUMP_CFG (CFG_14, 0);
DUMP_CFG (CFG_15, 0);
DUMP_CFG (CFG_16, 0);
DUMP_CFG (CFG_17, 0);
DUMP_CFG (GF2IGPU, 0);
DUMP_CFG (CFG_19, 0);
DUMP_CFG (GF4MXIGPU,0);
DUMP_CFG (CFG_21, 0);
DUMP_CFG (CFG_22, 0);
DUMP_CFG (CFG_23, 0);
DUMP_CFG (CFG_24, 0);
DUMP_CFG (CFG_25, 0);
DUMP_CFG (CFG_26, 0);
DUMP_CFG (CFG_27, 0);
DUMP_CFG (CFG_28, 0);
DUMP_CFG (CFG_29, 0);
DUMP_CFG (CFG_30, 0);
DUMP_CFG (CFG_41, 0);
DUMP_CFG (CFG_42, 0);
DUMP_CFG (CFG_43, 0);
DUMP_CFG (CFG_44, 0);
DUMP_CFG (CFG_45, 0);
DUMP_CFG (CFG_46, 0);
DUMP_CFG (CFG_47, 0);
DUMP_CFG (CFG_48, 0);
DUMP_CFG (CFG_49, 0);
DUMP_CFG (CFG_50, 0);
#undef DUMP_CFG
}
status_t nv_general_powerup()
{
status_t status;
LOG(1,("POWERUP: nVidia (open)BeOS Accelerant 0.02 running.\n"));
/* preset no laptop */
si->ps.laptop = false;
/* detect card type and power it up */
switch(CFGR(DEVID))
{
/* Vendor Nvidia */
case 0x002010de: /* Nvidia TNT1 */
si->ps.card_type = NV04;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia TNT1 (NV04)\n"));
status = nvxx_general_powerup();
break;
case 0x002810de: /* Nvidia TNT2 (pro) */
case 0x002910de: /* Nvidia TNT2 Ultra */
case 0x002a10de: /* Nvidia TNT2 */
case 0x002b10de: /* Nvidia TNT2 */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia TNT2 (NV05)\n"));
status = nvxx_general_powerup();
break;
case 0x002c10de: /* Nvidia Vanta (Lt) */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia Vanta (Lt) (NV05)\n"));
status = nvxx_general_powerup();
break;
case 0x002d10de: /* Nvidia TNT2-M64 (Pro) */
si->ps.card_type = NV05M64;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia TNT2-M64 (Pro) (NV05M64)\n"));
status = nvxx_general_powerup();
break;
case 0x002e10de: /* Nvidia NV06 Vanta */
case 0x002f10de: /* Nvidia NV06 Vanta */
si->ps.card_type = NV06;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia Vanta (NV06)\n"));
status = nvxx_general_powerup();
break;
case 0x00a010de: /* Nvidia Aladdin TNT2 */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia Aladdin TNT2 (NV05)\n"));
status = nvxx_general_powerup();
break;
case 0x010010de: /* Nvidia GeForce256 SDR */
case 0x010110de: /* Nvidia GeForce256 DDR */
case 0x010210de: /* Nvidia GeForce256 Ultra */
si->ps.card_type = NV10;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce256 (NV10)\n"));
status = nvxx_general_powerup();
break;
case 0x010310de: /* Nvidia Quadro */
si->ps.card_type = NV10;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia Quadro (NV10)\n"));
status = nvxx_general_powerup();
break;
case 0x011010de: /* Nvidia GeForce2 MX/MX400 */
case 0x011110de: /* Nvidia GeForce2 MX100/MX200 DDR */
si->ps.card_type = NV11;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce2 MX (NV11)\n"));
status = nvxx_general_powerup();
break;
case 0x011210de: /* Nvidia GeForce2 Go */
si->ps.card_type = NV11;
si->ps.card_arch = NV10A;
si->ps.laptop = true;
LOG(4,("POWERUP: Detected Nvidia GeForce2 Go (NV11)\n"));
status = nvxx_general_powerup();
break;
case 0x011310de: /* Nvidia Quadro2 MXR/EX/Go */
si->ps.card_type = NV11;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia Quadro2 MXR/EX/Go (NV11)\n"));
status = nvxx_general_powerup();
break;
case 0x015010de: /* Nvidia GeForce2 GTS/Pro */
case 0x015110de: /* Nvidia GeForce2 Ti DDR */
case 0x015210de: /* Nvidia GeForce2 Ultra */
si->ps.card_type = NV15;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce2 (NV15)\n"));
status = nvxx_general_powerup();
break;
case 0x015310de: /* Nvidia Quadro2 Pro */
si->ps.card_type = NV15;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia Quadro2 Pro (NV15)\n"));
status = nvxx_general_powerup();
break;
case 0x017010de: /* Nvidia GeForce4 MX 460 */
case 0x017110de: /* Nvidia GeForce4 MX 440 */
case 0x017210de: /* Nvidia GeForce4 MX 420 */
case 0x017310de: /* Nvidia GeForce4 MX 440SE */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX (NV17)\n"));
status = nvxx_general_powerup();
break;
case 0x017410de: /* Nvidia GeForce4 440 Go */
case 0x017510de: /* Nvidia GeForce4 420 Go */
case 0x017610de: /* Nvidia GeForce4 420 Go 32M */
case 0x017710de: /* Nvidia GeForce4 460 Go */
case 0x017910de: /* Nvidia GeForce4 440 Go 64M */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
si->ps.laptop = true;
LOG(4,("POWERUP: Detected Nvidia GeForce4 Go (NV17)\n"));
status = nvxx_general_powerup();
break;
case 0x017810de: /* Nvidia Quadro4 500 XGL/550 XGL */
case 0x017a10de: /* Nvidia Quadro4 200 NVS/400 NVS */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia Quadro4 (NV17)\n"));
status = nvxx_general_powerup();
break;
case 0x017c10de: /* Nvidia Quadro4 500 GoGL */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
si->ps.laptop = true;
LOG(4,("POWERUP: Detected Nvidia Quadro4 500 GoGL (NV17)\n"));
status = nvxx_general_powerup();
break;
//fixme: three IDs below correct??
case 0x018010de: /* Nvidia GeForce4 MX 440 AGP8X */
case 0x018110de: /* Nvidia GeForce4 MX 440SE AGP8X */
case 0x018210de: /* Nvidia GeForce4 MX 420 AGP8X */
si->ps.card_type = NV18;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX AGP8X (NV18)\n"));
status = nvxx_general_powerup();
break;
case 0x018810de: /* Nvidia Quadro4 580 XGL */
case 0x018a10de: /* Nvidia Quadro4 280 NVS */
case 0x018b10de: /* Nvidia Quadro4 380 XGL */
si->ps.card_type = NV18;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia Quadro4 (NV18)\n"));
status = nvxx_general_powerup();
break;
case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */
si->ps.card_type = NV11;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce2 Integrated GPU (CRUSH, NV11)\n"));
status = nvxx_general_powerup();
break;
case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 MX Integrated GPU (NFORCE2, NV17)\n"));
status = nvxx_general_powerup();
break;
case 0x020010de: /* Nvidia GeForce3 */
case 0x020110de: /* Nvidia GeForce3 Ti 200 */
case 0x020210de: /* Nvidia GeForce3 Ti 500 */
si->ps.card_type = NV20;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia GeForce3 (NV20)\n"));
status = nvxx_general_powerup();
break;
case 0x020310de: /* Nvidia Quadro DCC */
si->ps.card_type = NV20;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia Quadro DCC (NV20)\n"));
status = nvxx_general_powerup();
break;
case 0x025010de: /* Nvidia GeForce4 Ti 4600 */
case 0x025110de: /* Nvidia GeForce4 Ti 4400 */
case 0x025310de: /* Nvidia GeForce4 Ti 4200 */
si->ps.card_type = NV25;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti (NV25)\n"));
status = nvxx_general_powerup();
break;
case 0x025810de: /* Nvidia Quadro4 900 XGL */
case 0x025910de: /* Nvidia Quadro4 750 XGL */
case 0x025b10de: /* Nvidia Quadro4 700 XGL */
si->ps.card_type = NV25;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia Quadro4 XGL (NV25)\n"));
status = nvxx_general_powerup();
break;
case 0x028010de: /* Nvidia GeForce4 Ti 4600 AGP8X */
case 0x028110de: /* Nvidia GeForce4 Ti 4200 AGP8X */
si->ps.card_type = NV28;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti AGP8X (NV28)\n"));
status = nvxx_general_powerup();
break;
case 0x028210de: /* Nvidia GeForce4 Ti 4800SE */
si->ps.card_type = NV28;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia GeForce4 Ti 4800SE (NV28)\n"));
status = nvxx_general_powerup();
break;
case 0x028610de: /* Nvidia GeForce4 4200 Go */
si->ps.card_type = NV28;
si->ps.card_arch = NV20A;
si->ps.laptop = true;
LOG(4,("POWERUP: Detected Nvidia GeForce4 4200 Go (NV28)\n"));
status = nvxx_general_powerup();
break;
case 0x028810de: /* Nvidia Quadro4 980 XGL */
case 0x028910de: /* Nvidia Quadro4 780 XGL */
si->ps.card_type = NV28;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia Quadro4 XGL (NV28)\n"));
status = nvxx_general_powerup();
break;
case 0x02a010de: /* Nvidia GeForce3 Integrated GPU */
si->ps.card_type = NV20;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Nvidia GeForce3 Integrated GPU (XBOX, NV20)\n"));
status = nvxx_general_powerup();
break;
case 0x030110de: /* Nvidia GeForce FX 5800 Ultra */
case 0x030210de: /* Nvidia GeForce FX 5800 */
si->ps.card_type = NV30;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5800 (NV30)\n"));
status = nvxx_general_powerup();
break;
case 0x030810de: /* Nvidia Quadro FX 2000 */
case 0x030910de: /* Nvidia Quadro FX 1000 */
si->ps.card_type = NV30;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia Quadro FX (NV30)\n"));
status = nvxx_general_powerup();
break;
case 0x031110de: /* Nvidia GeForce FX 5600 Ultra */
case 0x031210de: /* Nvidia GeForce FX 5600 */
si->ps.card_type = NV31;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5600 (NV31)\n"));
status = nvxx_general_powerup();
break;
case 0x031a10de: /* Nvidia GeForce FX 5600 Go */
si->ps.card_type = NV31;
si->ps.card_arch = NV30A;
si->ps.laptop = true;
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5600 Go (NV31)\n"));
status = nvxx_general_powerup();
break;
case 0x032110de: /* Nvidia GeForce FX 5200 Ultra */
case 0x032210de: /* Nvidia GeForce FX 5200 */
si->ps.card_type = NV34;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5200 (NV34)\n"));
status = nvxx_general_powerup();
break;
case 0x032b10de: /* Nvidia Quadro FX 500 */
si->ps.card_type = NV34;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia Quadro FX 500 (NV34)\n"));
status = nvxx_general_powerup();
break;
case 0x033010de: /* Nvidia GeForce FX 5900 Ultra */
case 0x033110de: /* Nvidia GeForce FX 5900 */
si->ps.card_type = NV35;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia GeForce FX 5900 (NV35)\n"));
status = nvxx_general_powerup();
break;
case 0x033810de: /* Nvidia Quadro FX 3000 */
si->ps.card_type = NV35;
si->ps.card_arch = NV30A;
LOG(4,("POWERUP: Detected Nvidia Quadro FX 3000 (NV35)\n"));
status = nvxx_general_powerup();
break;
/* Vendor Elsa GmbH */
case 0x0c601048: /* Elsa Gladiac Geforce2 MX */
si->ps.card_type = NV11;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Elsa Gladiac Geforce2 MX (NV11)\n"));
status = nvxx_general_powerup();
break;
/* Vendor Nvidia STB/SGS-Thompson */
case 0x002012d2: /* Nvidia STB/SGS-Thompson TNT1 */
si->ps.card_type = NV04;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT1 (NV04)\n"));
status = nvxx_general_powerup();
break;
case 0x002812d2: /* Nvidia STB/SGS-Thompson TNT2 (pro) */
case 0x002912d2: /* Nvidia STB/SGS-Thompson TNT2 Ultra */
case 0x002a12d2: /* Nvidia STB/SGS-Thompson TNT2 */
case 0x002b12d2: /* Nvidia STB/SGS-Thompson TNT2 */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT2 (NV05)\n"));
status = nvxx_general_powerup();
break;
case 0x002c12d2: /* Nvidia STB/SGS-Thompson Vanta (Lt) */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Vanta (Lt) (NV05)\n"));
status = nvxx_general_powerup();
break;
case 0x002d12d2: /* Nvidia STB/SGS-Thompson TNT2-M64 (Pro) */
si->ps.card_type = NV05M64;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson TNT2-M64 (Pro) (NV05M64)\n"));
status = nvxx_general_powerup();
break;
case 0x002e12d2: /* Nvidia STB/SGS-Thompson NV06 Vanta */
case 0x002f12d2: /* Nvidia STB/SGS-Thompson NV06 Vanta */
si->ps.card_type = NV06;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Vanta (NV06)\n"));
status = nvxx_general_powerup();
break;
case 0x00a012d2: /* Nvidia STB/SGS-Thompson Aladdin TNT2 */
si->ps.card_type = NV05;
si->ps.card_arch = NV04A;
LOG(4,("POWERUP: Detected Nvidia STB/SGS-Thompson Aladdin TNT2 (NV05)\n"));
status = nvxx_general_powerup();
break;
/* Vendor Varisys Limited */
case 0x35031888: /* Varisys GeForce4 MX440 */
si->ps.card_type = NV17;
si->ps.card_arch = NV10A;
LOG(4,("POWERUP: Detected Varisys GeForce4 MX440 (NV17)\n"));
status = nvxx_general_powerup();
break;
case 0x35051888: /* Varisys GeForce4 Ti 4200 */
si->ps.card_type = NV25;
si->ps.card_arch = NV20A;
LOG(4,("POWERUP: Detected Varisys GeForce4 Ti 4200 (NV25)\n"));
status = nvxx_general_powerup();
break;
default:
LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
return B_ERROR;
}
/* override memory detection if requested by user */
if (si->settings.memory != 0)
si->ps.memory_size = si->settings.memory;
return status;
}
status_t test_ram()
{
uint32 value, offset;
status_t result = B_OK;
/* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */
if (si->fbc.frame_buffer == NULL)
{
LOG(8,("INIT: test_ram detected NULL pointer.\n"));
return B_ERROR;
}
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
{
/* write testpattern to cardRAM */
((uint32 *)si->fbc.frame_buffer)[offset] = value;
/* toggle testpattern */
value = 0xffffffff - value;
}
for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
{
/* readback and verify testpattern from cardRAM */
if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
/* toggle testpattern */
value = 0xffffffff - value;
}
return result;
}
/* NOTE:
* This routine *has* to be done *after* SetDispplayMode has been executed,
* or test results will not be representative!
* (CAS latency is dependant on NV setup on some (DRAM) boards) */
status_t nv_set_cas_latency()
{
status_t result = B_ERROR;
uint8 latency = 0;
/* check current RAM access to see if we need to change anything */
if (test_ram() == B_OK)
{
LOG(4,("INIT: RAM access OK.\n"));
return B_OK;
}
/* check if we read PINS at starttime so we have valid registersettings at our disposal */
if (si->ps.pins_status != B_OK)
{
LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n"));
return B_ERROR;
}
/* OK. We might have a problem, try to fix it now.. */
LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n"));
switch(si->ps.card_type)
{
case G550:
if (!si->ps.sdram)
{
LOG(4,("INIT: G100 SGRAM CAS tuning not permitted, aborting.\n"));
return B_OK;
}
/* SDRAM card */
for (latency = 4; latency >= 2; latency-- )
{
/* MCTLWTST is a write-only register! */
// ACCW(MCTLWTST, ((si->ps.mctlwtst_reg & 0xfffffffc) | (latency - 2)));
result = test_ram();
if (result == B_OK) break;
}
break;
default:
/* fixme: Millenium2 and others if needed */
LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n"));
return B_OK;
break;
}
if (result == B_OK)
LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency));
else
LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency));
return result;
}
static status_t nvxx_general_powerup()
{
status_t result;
LOG(4, ("INIT: NV powerup\n"));
if (si->settings.logmask & 0x80000000) nv_dump_configuration_space();
/* initialize the shared_info PINS struct */
result = parse_pins();
if (result != B_OK) fake_pins();
/* log the PINS struct settings */
dump_pins();
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
//temp:
return nv_general_bios_to_powergraphics();
if (si->settings.usebios || (result != B_OK)) return nv_general_bios_to_powergraphics();
/*power up the PLLs,LUT,DAC*/
LOG(2,("INIT: PLL/LUT/DAC powerup\n"));
/* turn off both displays and the hardcursor (also disables transfers) */
nv_crtc_dpms(false, false, false);
nv_crtc_cursor_hide();
/* G200 SGRAM and SDRAM use external pix and dac refs, do *not* activate internals!
* (this would create electrical shortcuts,
* resulting in extra chip heat and distortions visible on screen */
/* set voltage reference - using DAC reference block partly */
// DXIW(VREFCTRL,0x03);
/* wait for 100ms for voltage reference to stabilize */
delay(100000);
/* power up the SYSPLL */
// CFGW(OPTION,CFGR(OPTION)|0x20);
/* power up the PIXPLL */
// DXIW(PIXCLKCTRL,0x08);
/* disable pixelclock oscillations before switching on CLUT */
// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */
// DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
// DXIW(MISCCTRL,0x1b);
snooze(250);
/* re-enable pixelclock oscillations */
// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) & 0xfb));
/* setup i2c bus */
i2c_init();
/*make sure card is in powergraphics mode*/
// VGAW_I(CRTCEXT,3,0x80);
/*set the system clocks to powergraphics speed*/
LOG(2,("INIT: Setting system PLL to powergraphics speeds\n"));
g400_dac_set_sys_pll();
/* 'official' RAM initialisation */
LOG(2,("INIT: RAM init\n"));
/* disable hardware plane write mask if SDRAM card */
// if (si->ps.sdram) CFGW(OPTION,(CFGR(OPTION) & 0xffffbfff));
/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
// ACCW(PLNWT,0x00000000);
// ACCW(PLNWT,0xffffffff);
/* program memory control waitstates */
// ACCW(MCTLWTST,si->ps.mctlwtst_reg);
/* set memory configuration including:
* - SDRAM / SGRAM special functions select. */
// CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF) | ((si->ps.v3_mem_type & 0x07) << 10));
// if (!si->ps.sdram) CFGW(OPTION,(CFGR(OPTION) | (0x01 << 14)));
/* set memory buffer type */
// CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|((si->ps.v3_option2_reg & 0x03) << 12));
/* set mode register opcode and streamer flow control */
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0x0000FFFF)|(si->ps.memrdbk_reg & 0xffff0000));
/* set RAM read tap delays */
// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.memrdbk_reg & 0x0000ffff));
/* wait 200uS minimum */
snooze(250);
/* reset memory (MACCESS is a write only register!) */
// ACCW(MACCESS, 0x00000000);
/* perform actual RAM reset */
// ACCW(MACCESS, 0x00008000);
snooze(250);
/* start memory refresh */
// CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
/* set memory control waitstate again AFTER the RAM reset */
// ACCW(MCTLWTST,si->ps.mctlwtst_reg);
/* end 'official' RAM initialisation. */
/* Bus parameters: enable retries, use advanced read */
// CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29)));
/*enable writing to crtc registers*/
// VGAW_I(CRTC,0x11,0);
/* turn on display one */
nv_crtc_dpms(true , true, true);
return B_OK;
}
status_t gx50_general_output_select()
{
/* make sure this call is warranted */
if ((si->ps.card_type != NV11) && (si->ps.card_type != NV17)) return B_ERROR;
/* choose primary analog outputconnector */
if ((si->ps.primary_dvi) && (si->ps.secondary_head) && (si->ps.tvout))
{
if (i2c_sec_tv_adapter() == B_OK)
{
LOG(4,("INIT: secondary TV-adapter detected, using primary connector\n"));
// DXIW(OUTPUTCONN,0x01);
}
else
{
LOG(4,("INIT: no secondary TV-adapter detected, using secondary connector\n"));
// DXIW(OUTPUTCONN,0x04);
}
}
else
{
LOG(4,("INIT: using primary connector\n"));
// DXIW(OUTPUTCONN,0x01);
}
return B_OK;
}
/*connect CRTC1 to the specified DAC*/
status_t nv_general_dac_select(int dac)
{
if (!si->ps.secondary_head)
return B_ERROR;
/*MISCCTRL, clock src,...*/
switch(dac)
{
/* G400 */
case DS_CRTC1DAC_CRTC2MAVEN:
/* connect CRTC1 to pixPLL */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL, connect CRTC1 to internal DAC and
* enable CRTC2 external video timing reset signal.
* (Setting for MAVEN 'master mode' TVout signal generation.) */
// CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002);
/* disable CRTC1 external video timing reset signal */
// VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
/* select CRTC2 RGB24 MAFC mode: connects CRTC2 to MAVEN DAC */
// DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
break;
case DS_CRTC1MAVEN_CRTC2DAC:
/* connect CRTC1 to vidPLL */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2);
/* connect CRTC2 to pixPLL and internal DAC and
* disable CRTC2 external video timing reset signal */
// CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20));
/* enable CRTC1 external video timing reset signal.
* note: this is nolonger used as G450/G550 cannot do TVout on CRTC1 */
// VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88));
/* select CRTC1 RGB24 MAFC mode: connects CRTC1 to MAVEN DAC */
// DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02);
break;
/* G450/G550 */
case DS_CRTC1CON1_CRTC2CON2:
/* connect CRTC1 to pixPLL */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL, connect CRTC1 to DAC1, disable CRTC2
* external video timing reset signal, set CRTC2 progressive scan mode
* and disable TVout mode (b12).
* (Setting for MAVEN 'slave mode' TVout signal generation.) */
//fixme: enable timing resets if TVout is used in master mode!
//otherwise keep it disabled.
// CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x0<<20));
/* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (monitor mode) */
// DXIW(OUTPUTCONN,0x09);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
// DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
// DXIW(GENIODATA, 0x00);
break;
//fixme: toggle PLL's below if possible:
// otherwise toggle PLL's for G400 2nd case?
case DS_CRTC1CON2_CRTC2CON1:
/* connect CRTC1 to pixPLL */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL and DAC1, disable CRTC2 external
* video timing reset signal, and set CRTC2 progressive scan mode and
* disable TVout mode (b12). */
// CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x1<<20));
/* connect DAC1 to CON2 (monitor mode), CRTC2/'DAC2' to CON1 */
// DXIW(OUTPUTCONN,0x05);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
// DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
// DXIW(GENIODATA, 0x00);
break;
default:
return B_ERROR;
}
return B_OK;
}
/*busy wait until retrace!*/
status_t nv_general_wait_retrace()
{
// while (!(ACCR(STATUS)&0x8));
return B_OK;
}
/* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/
static
status_t nv_general_bios_to_powergraphics()
{
LOG(2, ("INIT: Skipping card coldstart!\n"));
/* unlock card registers for R/W access */
CRTCW(LOCK, 0x57);
/* turn off both displays and the hardcursor (also disables transfers) */
nv_crtc_dpms(false, false, false);
nv_crtc_cursor_hide();
/* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */
/* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */
// CRTCW(MODECTL, 0xc3);
/* ... plain sequential memory use, more than 64Kb RAM installed,
* switch to graphics mode ... */
// SEQW(MEMMODE, 0x0e);
/* ... disable bitplane tweaking ... */
// GRPHW(ENSETRESET, 0x00);
/* ... no logical function tweaking with display data, no data rotation ... */
// GRPHW(DATAROTATE, 0x00);
/* ... reset read map select to plane 0 ... */
// GRPHW(READMAPSEL, 0x00);
/* ... set standard mode ... */
// GRPHW(MODE, 0x00);
/* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again),
* select standard adressing ... */
// GRPHW(MISC, 0x05);
/* ... disable bit masking ... */
// GRPHW(BITMASK, 0xff);
/* ... attributes are in color, switch to graphics mode (again) ... */
// ATBW(MODECTL, 0x01);
/* ... set overscan color to black ... */
// ATBW(OSCANCOLOR, 0x00);
/* ... enable all color planes ... */
// ATBW(COLPLANE_EN, 0x0f);
/* ... reset horizontal pixelpanning ... */
// ATBW(HORPIXPAN, 0x00);
/* ... and reset colorpalette groupselect bits. */
// ATBW(COLSEL, 0x00);
/* setup sequencer clocking mode */
// SEQW(CLKMODE, 0x21);
/* enable 'enhanced mode', enable Vsync & Hsync,
* set DAC palette to 8-bit width, disable large screen */
CRTCW(REPAINT1, 0x04);
/* turn on display */
nv_crtc_dpms(true, true, true);
return B_OK;
}
/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
* virtual_size to the nearest valid maximum for the mode on the card if not so.
* Then: check if virtual_width adheres to the cards _multiple_ constraints, and
* create mode slopspace if not so.
* We use acc multiple constraints here if we expect we can use acceleration, because
* acc constraints are worse than CRTC constraints.
*
* Mode slopspace is reflected in fbc->bytes_per_row BTW. */
//fixme: seperate heads for real dualhead modes:
//CRTC1 and 2 constraints differ!
status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row)
{
/* Note:
* This routine assumes that the CRTC memory pitch granularity is 'smaller than',
* or 'equals' the acceleration engine memory pitch granularity! */
uint32 video_pitch;
uint32 acc_mask, crtc_mask;
uint8 depth = 8;
/* determine pixel multiple based on 2D/3D engine constraints */
switch (si->ps.card_type)
{
// case MIL2:
/* see MIL1/2 specs:
* these cards always use a 64bit RAMDAC (TVP3026) and interleaved memory */
/* switch (target->space)
{
case B_CMAP8: acc_mask = 0x7f; depth = 8; break;
case B_RGB15: acc_mask = 0x3f; depth = 16; break;
case B_RGB16: acc_mask = 0x3f; depth = 16; break;
case B_RGB24: acc_mask = 0x7f; depth = 24; break;
case B_RGB32: acc_mask = 0x1f; depth = 32; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
break;
*/ default:
/* see G100 and up specs:
* these cards can do 2D as long as multiples of 32 are used.
* (Note: don't mix this up with adress linearisation!) */
switch (target->space)
{
case B_CMAP8: depth = 8; break;
case B_RGB15: depth = 16; break;
case B_RGB16: depth = 16; break;
case B_RGB24: depth = 24; break;
case B_RGB32: depth = 32; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
acc_mask = 0x1f;
break;
}
/* determine pixel multiple based on CRTC memory pitch constraints.
* (Note: Don't mix this up with CRTC timing contraints! Those are
* multiples of 8 for horizontal, 1 for vertical timing.) */
switch (si->ps.card_type)
{
// case MIL2:
/* see MIL1/2 specs:
* these cards always use a 64bit RAMDAC and interleaved memory */
/* switch (target->space)
{
case B_CMAP8: crtc_mask = 0x7f; break;
case B_RGB15: crtc_mask = 0x3f; break;
case B_RGB16: crtc_mask = 0x3f; break;
*/ /* for B_RGB24 crtc_mask 0x7f is worst case scenario (MIL2 constraint) */
/* case B_RGB24: crtc_mask = 0x7f; break;
case B_RGB32: crtc_mask = 0x1f; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
break;
*/ default:
/* all NV cards */
switch (target->space)
{
case B_CMAP8: crtc_mask = 0x07; break;
case B_RGB15: crtc_mask = 0x03; break;
case B_RGB16: crtc_mask = 0x03; break;
case B_RGB24: crtc_mask = 0x07; break;
case B_RGB32: crtc_mask = 0x01; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
/* see G400 specs: CRTC2 has different constraints */
/* Note:
* set for RGB and B_YCbCr422 modes. Other modes need larger multiples! */
//fixme..
if (target->flags & DUALHEAD_BITS)
{
switch (target->space)
{
case B_RGB16: crtc_mask = 0x1f; break;
case B_RGB32: crtc_mask = 0x0f; break;
default:
LOG(8,("INIT: illegal DH color space: 0x%08x\n", target->space));
return B_ERROR;
}
}
break;
}
/* check if we can setup this mode with acceleration:
* Max sizes need to adhere to both the acceleration engine _and_ the CRTC constraints! */
si->acc_mode = true;
/* check virtual_width */
switch (si->ps.card_type)
{
default:
/* G200-G550 */
/* acc constraint: */
if (target->virtual_width > 4096) si->acc_mode = false;
/* for 32bit mode a lower CRTC1 restriction applies! */
if ((target->space == B_RGB32_LITTLE) && (target->virtual_width > (4092 & ~acc_mask)))
si->acc_mode = false;
break;
}
/* virtual_height */
if (target->virtual_height > 2048) si->acc_mode = false;
/* now check NV virtual_size based on CRTC constraints */
{
/* virtual_width */
//fixme for NV CRTC2?...:
switch(target->space)
{
case B_CMAP8:
if (target->virtual_width > 16376)
target->virtual_width = 16376;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
if (target->virtual_width > 8188)
target->virtual_width = 8188;
break;
case B_RGB24_LITTLE:
if (target->virtual_width > 5456)
target->virtual_width = 5456;
break;
case B_RGB32_LITTLE:
if (target->virtual_width > 4094)
target->virtual_width = 4094;
break;
}
/* virtual_height: The only constraint here is the cards memory size which is
* checked later on in ProposeMode: virtual_height is adjusted then if needed.
* 'Limiting here' to the variable size that's at least available (uint16). */
if (target->virtual_height > 65535) target->virtual_height = 65535;
}
//temp disabled:
si->acc_mode = false;
/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
* it was confined above, so we can finally calculate safely if we need slopspace
* for this mode... */
if (si->acc_mode)
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
else
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
video_pitch, target->space));
if (target->virtual_width != video_pitch)
LOG(2,("INIT: effective mode slopspace is %d pixels\n",
(video_pitch - target->virtual_width)));
/* now calculate bytes_per_row for this mode */
*bytes_per_row = video_pitch * (depth >> 3);
return B_OK;
}
@@ -0,0 +1,337 @@
/*
* i2c interface for the G400 MAVEN under BeOS
*
* Provides I2CR,I2CW - functions to parallel DACW,DACR
* Bus should be run at max. 100kHz: see original Philips I2C specification
*
* Much help was provided by observing the Linux i2c code,
* so thanks go to: Gerd Knorr
*
* Other authors:
* Mark Watson 6/2000,
* Rudolf Cornelissen 12/2002
*/
#define MODULE_BIT 0x00004000
#include "nv_std.h"
/*which device on the bus is the MAVEN?*/
#define MAVEN_WRITE (0x1B<<1)
#define MAVEN_READ ((0x1B<<1)|1)
#define I2C_CLOCK 0x20
#define I2C_DATA 0x10
/* NV-TVO I2C for G200, G400 */
#define I2C_CLOCK 0x20
#define I2C_DATA 0x10
/* primary head DDC for Mystique(?), G100, G200, G400 */
#define DDC1_CLK 0x08
#define DDC1_DATA 0x02
/* primary head DDC for Millennium, Millennium II */
#define DDC1B_CLK 0x10
#define DDC1B_DATA 0x04
/* secondary head DDC for G400, G450 and G550 */
#define DDC2_CLK 0x04
#define DDC2_DATA 0x01
status_t i2c_sec_tv_adapter()
{
status_t result = B_ERROR;
/* The secondary DDC channel only exist on dualhead cards */
if (!si->ps.secondary_head) return result;
/* make sure the output lines will be active-low when enabled
* (they will be pulled 'passive-high' when disabled) */
// DXIW(GENIODATA,0x00);
/* send out B_STOP condition on secondary head DDC channel and use it to
* check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */
/* make sure SDA is low */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA));
snooze(2);
/* make sure SCL should be high */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK));
snooze(2);
/* if SCL is low then the bus is blocked by a TV adapter */
// if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK;
snooze(5);
/* set SDA while SCL should be set (generates actual bus-stop condition) */
// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA));
snooze(5);
return result;
}
/*-----------------------------
*low level hardware access
*/
#define I2C_DELAY 2
#define I2C_TIMEOUT 100
int i2c_set_lines(int clock,int data)
{
int count=0;
int program;
int required;
/*work out which bits to zero*/
program =
(clock ? 0 : I2C_CLOCK)|
(data ? 0 : I2C_DATA);
/*what value do I require on data lines*/
required =
(clock ? I2C_CLOCK : 0);
/*set the bits to zero*/
// DXIW(GENIOCTRL,program); /*drive these bits*/
// DXIW(GENIODATA,0x00); /*to zero*/
/*wait a bit*/
delay(I2C_DELAY);
/*loop until the clock is as required*/
// while ((DXIR(GENIODATA)&I2C_CLOCK)!=required)
{
delay(I2C_DELAY);
count++;
if (count>I2C_TIMEOUT)
{
// LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA)));
return -1;
}
}
return 0;
}
int i2c_get_data()
{
int data = 0;
int clock;
int count=0;
do
{
/*read the data and clock lines*/
// data = DXIR(GENIODATA);
clock = (data&I2C_CLOCK) ? 1 : 0;
data = (data&I2C_DATA) ? 1 : 0;
/*manage timeout*/
count++;
if (count>I2C_TIMEOUT)
{
return -1;
}
/*wait a bit, so not hammering bus*/
delay(I2C_DELAY);
}while (!clock); /*wait for high clock*/
return data;
}
/*-----------------------
*Standard I2C operations
*/
void i2c_start()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: start - %d\n",error));
}
}
void i2c_stop()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: stop - %d\n",error));
}
}
void i2c_high()
{
int error=0;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: high - %d\n",error));
}
}
void i2c_low()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: low - %d\n",error));
}
}
int i2c_get_ack()
{
int error=0;
int ack;
error+= i2c_set_lines(0,1);
error+= i2c_set_lines(1,1);
ack = i2c_get_data();
error+= i2c_set_lines(0,1);
if (error)
{
LOG(8,("I2C: get_ack - %d value:%x\n",error,ack));
}
return ack;
}
void i2c_send_ack()
{
int error=0;
error+= i2c_set_lines(0,0);
error+= i2c_set_lines(1,0);
error+= i2c_set_lines(0,0);
if (error)
{
LOG(8,("I2C: send_ack - %d\n",error));
}
}
/*------------------------------
*use above functions to send and receive bytes
*/
int i2c_sendbyte(unsigned char data)
{
int i;
for (i=7; i>=0; i--)
{
if (data&(1<<i))
{
i2c_high();
}
else
{
i2c_low();
}
}
return i2c_get_ack();
}
unsigned char i2c_readbyte(int ack_required)
{
int i;
unsigned char data=0;
/*read data*/
i2c_set_lines(0,1);
for (i=7; i>=0; i--)
{
i2c_set_lines(1,1);
if (i2c_get_data()==1)
data |= (1<<i);
i2c_set_lines(0,1);
}
/*send acknowledge*/
if (ack_required) i2c_send_ack();
return data;
}
/*-------------------------------------------
*PUBLIC functions
*/
int i2c_maven_read(unsigned char address)
{
int error=0;
int data;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_READ);
error+=i2c_sendbyte(address);
data = i2c_readbyte(0);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVR ERROR - %x\n",error));
return data;
}
void i2c_maven_write(unsigned char address, unsigned char data)
{
int error=0;
i2c_start();
{
error+=i2c_sendbyte(MAVEN_WRITE);
error+=i2c_sendbyte(address);
error+=i2c_sendbyte(data);
}
i2c_stop();
if (error>0) LOG(8,("I2C: MAVW ERROR - %x\n",error));
}
status_t i2c_init(void)
{
/*init g400 i2c*/
// DXIW(GENIODATA,0x00); /*to zero*/
// DXIW(GENIOCTRL,0x30); /*drive clock and data*/
// DXIW(GENIOCTRL,0x00); /*stop driving*/
return B_OK;
}
status_t i2c_maven_probe(void)
{
int ack;
/*scan the bus for the MAVEN*/
i2c_start();
{
ack = i2c_sendbyte(MAVEN_READ);
}
i2c_stop();
if (ack==0)
{
return B_OK;
}
else
{
return B_ERROR;
}
}
@@ -0,0 +1,685 @@
/* Read initialisation information from card */
/* some bits are hacks, where PINS is not known */
/* Author:
Rudolf Cornelissen 7/2003
*/
#define MODULE_BIT 0x00002000
#include "nv_std.h"
/* Parse the BIOS PINS structure if there */
status_t parse_pins ()
{
uint8 pins_len = 0;
uint8 *rom;
uint8 *pins;
uint8 chksum = 0;
int i;
status_t result = B_ERROR;
/* preset PINS read status to failed */
si->ps.pins_status = B_ERROR;
/* check the validity of PINS */
LOG(2,("INFO: Reading PINS info\n"));
rom = (uint8 *) si->rom_mirror;
/* check BIOS signature */
if (rom[0]!=0x55 || rom[1]!=0xaa)
{
LOG(8,("INFO: BIOS signiture not found\n"));
return B_ERROR;
}
LOG(2,("INFO: BIOS signiture $AA55 found OK\n"));
/* check for a valid PINS struct adress */
pins = rom + (rom[0x7FFC]|(rom[0x7FFD]<<8));
if ((pins - rom) > 0x7F80)
{
LOG(8,("INFO: invalid PINS adress\n"));
return B_ERROR;
}
/* checkout new PINS struct version if there */
if ((pins[0] == 0x2E) && (pins[1] == 0x41))
{
pins_len = pins[2];
if (pins_len < 3 || pins_len > 128)
{
LOG(8,("INFO: invalid PINS size\n"));
return B_ERROR;
}
/* calculate PINS checksum */
for (i = 0; i < pins_len; i++)
{
chksum += pins[i];
}
if (chksum)
{
LOG(8,("INFO: PINS checksum error\n"));
return B_ERROR;
}
LOG(2,("INFO: new PINS, version %u.%u, length %u\n", pins[5], pins[4], pins[2]));
/* fill out the si->ps struct if possible */
switch (pins[5])
{
case 5:
result = pins5_read(pins, pins_len);
break;
default:
LOG(8,("INFO: unknown PINS version\n"));
return B_ERROR;
break;
}
}
/* no valid PINS signature found */
else
{
LOG(8,("INFO: no PINS signature found\n"));
return B_ERROR;
}
/* check PINS read result */
if (result == B_ERROR)
{
LOG(8,("INFO: PINS read/decode error\n"));
return B_ERROR;
}
/* PINS scan succeeded */
si->ps.pins_status = B_OK;
LOG(2,("INFO: PINS scan completed succesfully\n"));
return B_OK;
}
/* pins v5 is used by G450 and G550 */
status_t pins5_read(uint8 *pins, uint8 length)
{
unsigned int m_factor = 6;
if (length != 128)
{
LOG(8,("INFO: wrong PINS length, expected 128, got %d\n", length));
return B_ERROR;
}
/* fill out the shared info si->ps struct */
if (pins[4] == 0x01) m_factor = 8;
if (pins[4] >= 0x02) m_factor = 10;
si->ps.max_system_vco = m_factor * pins[36];
si->ps.max_video_vco = m_factor * pins[37];
si->ps.max_pixel_vco = m_factor * pins[38];
si->ps.min_system_vco = m_factor * pins[121];
si->ps.min_video_vco = m_factor * pins[122];
si->ps.min_pixel_vco = m_factor * pins[123];
if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco;
else si->ps.max_dac1_clock_8 = 4 * pins[39];
if (pins[40] == 0xff) si->ps.max_dac1_clock_16 = si->ps.max_dac1_clock_8;
else si->ps.max_dac1_clock_16 = 4 * pins[40];
if (pins[41] == 0xff) si->ps.max_dac1_clock_24 = si->ps.max_dac1_clock_16;
else si->ps.max_dac1_clock_24 = 4 * pins[41];
if (pins[42] == 0xff) si->ps.max_dac1_clock_32 = si->ps.max_dac1_clock_24;
else si->ps.max_dac1_clock_32 = 4 * pins[42];
if (pins[124] == 0xff) si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32;
else si->ps.max_dac1_clock_32dh = 4 * pins[124];
if (pins[43] == 0xff) si->ps.max_dac2_clock_16 = si->ps.max_video_vco;
else si->ps.max_dac2_clock_16 = 4 * pins[43];
if (pins[44] == 0xff) si->ps.max_dac2_clock_32 = si->ps.max_dac2_clock_16;
else si->ps.max_dac2_clock_32 = 4 * pins[44];
if (pins[125] == 0xff) si->ps.max_dac2_clock_32dh = si->ps.max_dac2_clock_32;
else si->ps.max_dac2_clock_32dh = 4 * pins[125];
if (pins[118] == 0xff) si->ps.max_dac1_clock = si->ps.max_dac1_clock_8;
else si->ps.max_dac1_clock = 4 * pins[118];
if (pins[119] == 0xff) si->ps.max_dac2_clock = si->ps.max_dac1_clock;
else si->ps.max_dac2_clock = 4 * pins[119];
si->ps.std_engine_clock = 4 * pins[74];
si->ps.std_memory_clock = 4 * pins[92];
si->ps.memory_size = ((pins[114] & 0x03) + 1) * 8;
if ((pins[114] & 0x07) > 3)
{
LOG(8,("INFO: unknown RAM size, defaulting to 8Mb\n"));
si->ps.memory_size = 8;
}
if (pins[110] & 0x01) si->ps.f_ref = 14.31818;
else si->ps.f_ref = 27.00000;
/* make sure SGRAM functions only get enabled if SGRAM mounted */
if ((pins[114] & 0x18) == 0x08) si->ps.sdram = false;
else si->ps.sdram = true;
/* various registers */
si->ps.secondary_head = (pins[117] & 0x70);
si->ps.tvout = (pins[117] & 0x40);
si->ps.primary_dvi = (pins[117] & 0x02);
si->ps.secondary_dvi = (pins[117] & 0x20);
/* not supported: */
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_24 = 0;
return B_OK;
}
/* fake_pins presumes the card was coldstarted by it's BIOS */
void fake_pins(void)
{
LOG(8,("INFO: faking PINS\n"));
/* set failsave speeds */
switch (si->ps.card_type)
{
case NV04:
pinsnv4_fake();
break;
case NV05:
case NV05M64:
pinsnv5_nv5m64_fake();
break;
case NV06:
pinsnv6_fake();
break;
default:
switch (si->ps.card_arch)
{
case NV10A:
pinsnv10_arch_fake();
break;
case NV20A:
pinsnv20_arch_fake();
break;
case NV30A:
pinsnv30_arch_fake();
break;
default:
/* 'failsafe' values... */
pinsnv10_arch_fake();
break;
}
break;
}
/* detect RAM amount, reference crystal frequency and dualhead */
switch (si->ps.card_arch)
{
case NV04A:
getstrap_arch_nv4();
break;
default:
getstrap_arch_nv10_20();
break;
}
/* find out if the card has a tvout chip */
si->ps.tvout = false;
si->ps.tvout_chip_type = NONE;
//fixme ;-)
/* if (i2c_maven_probe() == B_OK)
{
si->ps.tvout = true;
si->ps.tvout_chip_bus = ???;
si->ps.tvout_chip_type = ???;
}
*/
}
void pinsnv4_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 256;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 256;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 250;
si->ps.max_dac1_clock_8 = 250;
si->ps.max_dac1_clock_16 = 250;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 220;
si->ps.max_dac1_clock_32 = 180;
si->ps.max_dac1_clock_32dh = 180;
/* secondary head */
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 0;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 90;
si->ps.std_memory_clock = 110;
}
void pinsnv5_nv5m64_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 300;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 300;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 300;
si->ps.max_dac1_clock_8 = 300;
si->ps.max_dac1_clock_16 = 300;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 270;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 230;
/* secondary head */
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 0;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 125;
si->ps.std_memory_clock = 150;
}
void pinsnv6_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 300;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 300;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
si->ps.max_dac1_clock = 300;
si->ps.max_dac1_clock_8 = 300;
si->ps.max_dac1_clock_16 = 300;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 270;
si->ps.max_dac1_clock_32 = 230;
si->ps.max_dac1_clock_32dh = 230;
/* secondary head */
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 0;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 100;
si->ps.std_memory_clock = 125;
}
void pinsnv10_arch_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
/* secondary head */
//fixme? assuming...
si->ps.max_dac2_clock = 200;
si->ps.max_dac2_clock_8 = 200;
si->ps.max_dac2_clock_16 = 200;
si->ps.max_dac2_clock_24 = 200;
si->ps.max_dac2_clock_32 = 200;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 180;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 120;
si->ps.std_memory_clock = 150;
}
void pinsnv20_arch_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
/* secondary head */
//fixme? assuming...
si->ps.max_dac2_clock = 200;
si->ps.max_dac2_clock_8 = 200;
si->ps.max_dac2_clock_16 = 200;
si->ps.max_dac2_clock_24 = 200;
si->ps.max_dac2_clock_32 = 200;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 180;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 175;
si->ps.std_memory_clock = 200;
}
void pinsnv30_arch_fake(void)
{
/* carefull not to take to high limits, and high should be >= 2x low. */
si->ps.max_system_vco = 350;
si->ps.min_system_vco = 128;
si->ps.max_pixel_vco = 350;
si->ps.min_pixel_vco = 128;
si->ps.max_video_vco = 350;
si->ps.min_video_vco = 128;
si->ps.max_dac1_clock = 350;
si->ps.max_dac1_clock_8 = 350;
si->ps.max_dac1_clock_16 = 350;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 320;
si->ps.max_dac1_clock_32 = 280;
si->ps.max_dac1_clock_32dh = 250;
/* secondary head */
//fixme? assuming...
si->ps.max_dac2_clock = 200;
si->ps.max_dac2_clock_8 = 200;
si->ps.max_dac2_clock_16 = 200;
si->ps.max_dac2_clock_24 = 200;
si->ps.max_dac2_clock_32 = 200;
/* 'failsave' values */
si->ps.max_dac2_clock_32dh = 180;
//fixme: primary & secondary_dvi should be overrule-able via nv.settings
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
//fixme: is this needed for nv acc?
//fail-safe mode for now:
si->ps.sdram = true;
/* not used (yet) because no coldstart will be attempted (yet) */
si->ps.std_engine_clock = 190;
si->ps.std_memory_clock = 190;
}
void getstrap_arch_nv4(void)
{
uint32 strapinfo = NV_REG32(NV32_NV4STRAPINFO);
if (strapinfo & 0x00000100)
{
/* Unified memory architecture used */
si->ps.memory_size =
((((strapinfo & 0x0000f000) >> 12) * 2) + 2);
LOG(8,("INFO: NV4 architecture chip with UMA detected\n"));
}
else
{
/* private memory architecture used */
switch (strapinfo & 0x00000003)
{
case 0:
si->ps.memory_size = 32;
break;
case 1:
si->ps.memory_size = 4;
break;
case 2:
si->ps.memory_size = 8;
break;
case 3:
si->ps.memory_size = 16;
break;
}
}
strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
/* determine PLL reference crystal frequency */
if (strapinfo & 0x00000040)
si->ps.f_ref = 14.31818;
else
si->ps.f_ref = 13.50000;
/* these cards are always singlehead */
si->ps.secondary_head = false;
}
void getstrap_arch_nv10_20(void)
{
uint32 dev_manID = CFGR(DEVID);
uint32 strapinfo = NV_REG32(NV32_NV10STRAPINFO);
switch (dev_manID)
{
case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */
si->ps.memory_size = (((CFGR(GF2IGPU) & 0x000007c0) >> 6) + 1);
break;
case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */
si->ps.memory_size = (((CFGR(GF4MXIGPU) & 0x000007f0) >> 4) + 1);
//remove this line if det. is OK: int amt = pciReadLong(pciTag(0, 0, 1), 0x84);
break;
default:
switch ((strapinfo & 0x0ff00000) >> 20)
{
case 2:
si->ps.memory_size = 2;
break;
case 4:
si->ps.memory_size = 4;
break;
case 8:
si->ps.memory_size = 8;
break;
case 16:
si->ps.memory_size = 16;
break;
case 32:
si->ps.memory_size = 32;
break;
case 64:
si->ps.memory_size = 64;
break;
case 128:
si->ps.memory_size = 128;
break;
default:
si->ps.memory_size = 16;
LOG(8,("INFO: NV10/20 architecture chip with unknown RAM amount detected;\n"));
LOG(8,("INFO: Setting 16Mb\n"));
break;
}
}
strapinfo = NV_REG32(NV32_NVSTRAPINFO2);
/* determine PLL reference crystal frequency: three types are used... */
if (strapinfo & 0x00000040)
si->ps.f_ref = 14.31818;
else
si->ps.f_ref = 13.50000;
switch (dev_manID & 0xfff0ffff)
{
/* Nvidia cards: */
case 0x017010de:
case 0x018010de:
case 0x01f010de:
case 0x025010de:
case 0x028010de:
case 0x030010de:
case 0x031010de:
case 0x032010de:
case 0x033010de:
/* Varisys cards: */
case 0x35001888:
if (strapinfo & 0x00400000) si->ps.f_ref = 27.00000;
break;
default:
break;
}
/* determine if we have a dualhead card */
switch (dev_manID & 0xfff0ffff)
{
/* Nvidia cards: */
case 0x011010de:
case 0x017010de:
case 0x018010de:
case 0x01f010de:
case 0x025010de:
case 0x028010de:
case 0x030010de:
case 0x031010de:
case 0x032010de:
case 0x033010de:
/* Varisys cards: */
case 0x35001888:
si->ps.secondary_head = true;
break;
default:
si->ps.secondary_head = false;
break;
}
}
void dump_pins(void)
{
char *msg = "";
LOG(2,("INFO: pinsdump follows:\n"));
LOG(2,("f_ref: %fMhz\n", si->ps.f_ref));
LOG(2,("max_system_vco: %dMhz\n", si->ps.max_system_vco));
LOG(2,("min_system_vco: %dMhz\n", si->ps.min_system_vco));
LOG(2,("max_pixel_vco: %dMhz\n", si->ps.max_pixel_vco));
LOG(2,("min_pixel_vco: %dMhz\n", si->ps.min_pixel_vco));
LOG(2,("max_video_vco: %dMhz\n", si->ps.max_video_vco));
LOG(2,("min_video_vco: %dMhz\n", si->ps.min_video_vco));
LOG(2,("std_engine_clock: %dMhz\n", si->ps.std_engine_clock));
LOG(2,("std_memory_clock: %dMhz\n", si->ps.std_memory_clock));
LOG(2,("max_dac1_clock: %dMhz\n", si->ps.max_dac1_clock));
LOG(2,("max_dac1_clock_8: %dMhz\n", si->ps.max_dac1_clock_8));
LOG(2,("max_dac1_clock_16: %dMhz\n", si->ps.max_dac1_clock_16));
LOG(2,("max_dac1_clock_24: %dMhz\n", si->ps.max_dac1_clock_24));
LOG(2,("max_dac1_clock_32: %dMhz\n", si->ps.max_dac1_clock_32));
LOG(2,("max_dac1_clock_32dh: %dMhz\n", si->ps.max_dac1_clock_32dh));
LOG(2,("max_dac2_clock: %dMhz\n", si->ps.max_dac2_clock));
LOG(2,("max_dac2_clock_8: %dMhz\n", si->ps.max_dac2_clock_8));
LOG(2,("max_dac2_clock_16: %dMhz\n", si->ps.max_dac2_clock_16));
LOG(2,("max_dac2_clock_24: %dMhz\n", si->ps.max_dac2_clock_24));
LOG(2,("max_dac2_clock_32: %dMhz\n", si->ps.max_dac2_clock_32));
LOG(2,("max_dac2_clock_32dh: %dMhz\n", si->ps.max_dac2_clock_32dh));
LOG(2,("secondary_head: "));
if (si->ps.secondary_head) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("tvout: "));
if (si->ps.tvout) LOG(2,("present\n")); else LOG(2,("absent\n"));
/* setup TVout logmessage text */
switch (si->ps.tvout_chip_type)
{
case NONE:
msg = "No";
break;
case CH7003:
msg = "Chrontel CH7003";
break;
case CH7004:
msg = "Chrontel CH7004";
break;
case CH7005:
msg = "Chrontel CH7005";
break;
case CH7006:
msg = "Chrontel CH7006";
break;
case CH7007:
msg = "Chrontel CH7007";
break;
case SAA7102:
msg = "Philips SAA7102";
break;
case SAA7108:
msg = "Philips SAA7108";
break;
case BT868:
msg = "Brooktree/Conexant BT868";
break;
case BT869:
msg = "Brooktree/Conexant BT869";
break;
case CX25870:
msg = "Conexant CX25870";
break;
case CX25871:
msg = "Conexant CX25871";
break;
case NVIDIA:
msg = "Nvidia internal";
break;
default:
msg = "Unknown";
break;
}
LOG(2, ("%s TVout chip detected\n", msg));
LOG(2,("primary_dvi: "));
if (si->ps.primary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("secondary_dvi: "));
if (si->ps.secondary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n"));
LOG(2,("card memory_size: %dMb\n", si->ps.memory_size));
LOG(2,("sdram: "));
if (si->ps.sdram) LOG(2,("SDRAM card\n")); else LOG(2,("SGRAM card\n"));
LOG(2,("laptop: "));
if (si->ps.laptop) LOG(2,("yes\n")); else LOG(2,("no\n"));
LOG(2,("INFO: end pinsdump.\n"));
}
@@ -0,0 +1,270 @@
/* program the MAVEN in monitor mode */
/* Authors:
Mark Watson 6/2000,
Rudolf Cornelissen 1/2003-4/2003
Thanx to Petr Vandrovec for writing matroxfb.
*/
#define MODULE_BIT 0x00001000
#include "nv_std.h"
status_t g450_g550_maven_set_vid_pll(display_mode target);
status_t g100_g400max_maven_set_vid_pll(display_mode target);
status_t nv_maven_dpms(uint8 display,uint8 h,uint8 v)
{
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G550) return B_OK;
if (display & h & v)
{
/* turn on screen */
if (!(si->dm.flags & TV_BITS))
{
/* monitor mode */
MAVW(MONEN, 0xb2);
MAVW(MONSET, 0x20); /* must be set to this in monitor mode */
MAVW(OUTMODE, 0x03); /* output: monitor mode */
MAVW(STABLE, 0x22); /* makes picture stable? */
MAVW(TEST, 0x00); /* turn off test signal */
}
else
{
/* TVout mode */
MAVW(MONEN, 0xb3);
MAVW(MONSET, 0x20);
MAVW(OUTMODE, 0x08); /* output: SVideo/Composite */
MAVW(STABLE, 0x02); /* makes picture stable? */
//fixme? linux uses 0x14...
MAVW(TEST, (MAVR(TEST) & 0x10));
}
}
else
{
/* turn off screen using a few methods! */
MAVW(STABLE, 0x6a);
// MAVW(TEST, 0x03);
MAVW(OUTMODE, 0x00);
}
return B_OK;
}
/*set a mode line - inputs are in pixels/scanlines*/
status_t nv_maven_set_timing(display_mode target)
{
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G550) return B_OK;
LOG(4,("MAVEN: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/
if ((target.timing.h_display & 0x07) |
(target.timing.h_sync_start & 0x07) |
(target.timing.h_sync_end & 0x07) |
(target.timing.h_total & 0x07))
{
LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n"));
return B_ERROR;
}
/*program the MAVEN*/
MAVWW(LASTLINEL, target.timing.h_total);
MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
target.timing.h_display));
MAVWW(HTOTALL, (target.timing.h_total + 1));
MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
MAVWW(VDISPLAYL, (target.timing.v_total - 1));
MAVWW(VTOTALL, (target.timing.v_total - 1));
MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
MAVWW(VVIDRSTL, (target.timing.v_total - 2));
return B_OK;
}
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t nv_maven_mode(int mode,float brightness)
{
uint8 luma;
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G550) return B_OK;
/*set luma to a suitable value for brightness*/
/*assuming 1A is a sensible value*/
luma = (uint8)(0x1a * brightness);
MAVW(LUMA,luma);
LOG(4,("MAVEN: LUMA setting - %x\n",luma));
return B_OK;
}
status_t nv_maven_set_vid_pll(display_mode target)
{
switch (si->ps.card_type)
{
default:
return g100_g400max_maven_set_vid_pll(target);
break;
}
return B_ERROR;
}
/* program the video PLL in the MAVEN */
status_t g100_g400max_maven_set_vid_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
float pix_setting, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p);
if (result != B_OK)
{
return result;
}
/*reprogram (select,wait for stability)*/
MAVW(PIXPLLM,(m)); /* set m value */
MAVW(PIXPLLN,(n)); /* set n value */
MAVW(PIXPLLP,(p | 0x80)); /* set p value enabling PLL */
/* Wait for the VIDPLL frequency to lock: detection is not possible it seems */
snooze(2000);
LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
return B_OK;
}
/* find nearest valid video PLL setting */
status_t g100_g400max_maven_vid_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the current card */
//fixme: check G100 and G200 m_max if possible...
switch(si->ps.card_type)
{
default:
LOG(4,("MAVEN: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_video_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_video_vco / 8.0))
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 8.0)));
req_pclk = (si->ps.min_video_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
/* calc the needed PLL loopbackfilter setting belonging to current VCO speed */
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
switch(si->ps.card_type)
{
default:
for(;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
/* return the results */
*calc_pclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,9 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <math.h>
#include <OS.h>
#include "DriverInterface.h"
#include "global.h"
//apsed #include "nv_extern.h"
#include "nv_proto.h"
#include "nv_macros.h"
@@ -0,0 +1,30 @@
/* Some commmon support functions */
/* Mark Watson 2/2000 */
#define MODULE_BIT 0x00000800
#include <stdarg.h>
#include "nv_std.h"
/*delays in multiple of microseconds*/
void delay(bigtime_t i)
{
bigtime_t start=system_time();
while(system_time()-start<i);
}
/*debug logging*/
void nv_log(char *fmt, ...)
{
char buffer[1024];
FILE *myhand;
va_list args;
myhand=fopen("/boot/home/" DRIVER_PREFIX ".accelerant.log","a+");
if (myhand == NULL) return;
va_start(args,fmt);
vsprintf (buffer, fmt, args);
fprintf(myhand, "%s", buffer);
fclose(myhand);
}