From 08705d9664e3c9fe0b038c281945bcd462693715 Mon Sep 17 00:00:00 2001 From: shatty Date: Sun, 23 Nov 2003 05:30:55 +0000 Subject: [PATCH] add nvidia accelerant git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5450 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/accelerants/Jamfile | 3 + src/add-ons/accelerants/nvidia/Acceleration.c | 135 ++ src/add-ons/accelerants/nvidia/Cursor.c | 165 +++ .../accelerants/nvidia/EngineManagment.c | 68 + .../accelerants/nvidia/GetAccelerantHook.c | 241 ++++ .../accelerants/nvidia/GetDeviceInfo.c | 51 + src/add-ons/accelerants/nvidia/GetModeInfo.c | 134 ++ .../accelerants/nvidia/GetTimingConstraints.c | 30 + src/add-ons/accelerants/nvidia/GlobalData.c | 26 + .../accelerants/nvidia/InitAccelerant.c | 299 ++++ src/add-ons/accelerants/nvidia/Overlay.c | 648 +++++++++ .../accelerants/nvidia/ProposeDisplayMode.c | 447 ++++++ .../accelerants/nvidia/SetDisplayMode.c | 633 +++++++++ src/add-ons/accelerants/nvidia/acc_std.h | 17 + .../accelerants/nvidia/engine/nv_acc.c | 438 ++++++ .../accelerants/nvidia/engine/nv_bes.c | 699 ++++++++++ .../accelerants/nvidia/engine/nv_crtc.c | 543 ++++++++ .../accelerants/nvidia/engine/nv_crtc2.c | 247 ++++ .../accelerants/nvidia/engine/nv_dac.c | 462 +++++++ .../accelerants/nvidia/engine/nv_general.c | 963 +++++++++++++ .../accelerants/nvidia/engine/nv_i2c.c | 337 +++++ .../accelerants/nvidia/engine/nv_info.c | 685 ++++++++++ .../accelerants/nvidia/engine/nv_maven.c | 270 ++++ .../accelerants/nvidia/engine/nv_maventv.c | 1210 +++++++++++++++++ .../accelerants/nvidia/engine/nv_std.h | 9 + .../accelerants/nvidia/engine/nv_support.c | 30 + 26 files changed, 8790 insertions(+) create mode 100644 src/add-ons/accelerants/Jamfile create mode 100644 src/add-ons/accelerants/nvidia/Acceleration.c create mode 100644 src/add-ons/accelerants/nvidia/Cursor.c create mode 100644 src/add-ons/accelerants/nvidia/EngineManagment.c create mode 100644 src/add-ons/accelerants/nvidia/GetAccelerantHook.c create mode 100644 src/add-ons/accelerants/nvidia/GetDeviceInfo.c create mode 100644 src/add-ons/accelerants/nvidia/GetModeInfo.c create mode 100644 src/add-ons/accelerants/nvidia/GetTimingConstraints.c create mode 100644 src/add-ons/accelerants/nvidia/GlobalData.c create mode 100644 src/add-ons/accelerants/nvidia/InitAccelerant.c create mode 100644 src/add-ons/accelerants/nvidia/Overlay.c create mode 100644 src/add-ons/accelerants/nvidia/ProposeDisplayMode.c create mode 100644 src/add-ons/accelerants/nvidia/SetDisplayMode.c create mode 100644 src/add-ons/accelerants/nvidia/acc_std.h create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_acc.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_bes.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_crtc.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_crtc2.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_dac.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_general.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_i2c.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_info.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_maven.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_maventv.c create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_std.h create mode 100644 src/add-ons/accelerants/nvidia/engine/nv_support.c diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile new file mode 100644 index 0000000000..cacf5aedcf --- /dev/null +++ b/src/add-ons/accelerants/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP src add-ons accelerants ; + +SubInclude OBOS_TOP src add-ons accelerants nvidia ; diff --git a/src/add-ons/accelerants/nvidia/Acceleration.c b/src/add-ons/accelerants/nvidia/Acceleration.c new file mode 100644 index 0000000000..027a33086d --- /dev/null +++ b/src/add-ons/accelerants/nvidia/Acceleration.c @@ -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; + } +} diff --git a/src/add-ons/accelerants/nvidia/Cursor.c b/src/add-ons/accelerants/nvidia/Cursor.c new file mode 100644 index 0000000000..a63699c1ba --- /dev/null +++ b/src/add-ons/accelerants/nvidia/Cursor.c @@ -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(); +} diff --git a/src/add-ons/accelerants/nvidia/EngineManagment.c b/src/add-ons/accelerants/nvidia/EngineManagment.c new file mode 100644 index 0000000000..062927ac42 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/EngineManagment.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/GetAccelerantHook.c b/src/add-ons/accelerants/nvidia/GetAccelerantHook.c new file mode 100644 index 0000000000..5173fb6f86 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/GetAccelerantHook.c @@ -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; + } +} diff --git a/src/add-ons/accelerants/nvidia/GetDeviceInfo.c b/src/add-ons/accelerants/nvidia/GetDeviceInfo.c new file mode 100644 index 0000000000..ac4478dc68 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/GetDeviceInfo.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/GetModeInfo.c b/src/add-ons/accelerants/nvidia/GetModeInfo.c new file mode 100644 index 0000000000..1ea7098fcc --- /dev/null +++ b/src/add-ons/accelerants/nvidia/GetModeInfo.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/GetTimingConstraints.c b/src/add-ons/accelerants/nvidia/GetTimingConstraints.c new file mode 100644 index 0000000000..29751b96c8 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/GetTimingConstraints.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/GlobalData.c b/src/add-ons/accelerants/nvidia/GlobalData.c new file mode 100644 index 0000000000..d3a2e22aec --- /dev/null +++ b/src/add-ons/accelerants/nvidia/GlobalData.c @@ -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 + }; diff --git a/src/add-ons/accelerants/nvidia/InitAccelerant.c b/src/add-ons/accelerants/nvidia/InitAccelerant.c new file mode 100644 index 0000000000..3801d3e307 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/InitAccelerant.c @@ -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 +#include "acc_std.h" + +/* defined in ProposeDisplayMode.c */ +extern status_t create_mode_list(void); + +static status_t init_common(int the_fd); + +/* Initialization code shared between primary and cloned accelerants */ +static status_t init_common(int the_fd) { + status_t result; + nv_get_private_data gpd; + + // LOG not available from here to next LOG: NULL si + + /* memorize the file descriptor */ + fd = the_fd; + /* set the magic number so the driver knows we're for real */ + gpd.magic = NV_PRIVATE_DATA_MAGIC; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, NV_GET_PRIVATE_DATA, &gpd, sizeof(gpd)); + if (result != B_OK) goto error0; + + /* clone the shared area for our use */ + shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area); + if (shared_info_area < 0) { + result = shared_info_area; + goto error0; + } + // LOG is now available, si !NULL + LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, greensync %d\n", + si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync)); + + /*Check for R4.5.0 and if it is running, use work around*/ + { + if (si->use_clone_bugfix) + { + /*check for R4.5.0 bug and attempt to work around*/ + LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n")); + regs = si->clone_bugfix_regs; + } + else + { + /* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/ + regs_area = clone_area(DRIVER_PREFIX " regs", (void **)®s, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, si->regs_area); + if (regs_area < 0) { + result = regs_area; + goto error1; + } + } + } + + /*FIXME - print dma addresses*/ + //LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area)); + + /* all done */ + goto error0; + +error1: + delete_area(shared_info_area); +error0: + return result; +} + +/* Clean up code shared between primary and cloned accelrants */ +static void uninit_common(void) { + /* release the memory mapped registers */ + delete_area(regs_area); + /* a little cheap paranoia */ + regs = 0; + /* release our copy of the shared info from the kernel driver */ + delete_area(shared_info_area); + /* more cheap paranoia */ + si = 0; +} + +/* +Initialize the accelerant. the_fd is the file handle of the device (in +/dev/graphics) that has been opened by the app_server (or some test harness). +We need to determine if the kernel driver and the accelerant are compatible. +If they are, get the accelerant ready to handle other hook functions and +report success or failure. +*/ +status_t INIT_ACCELERANT(int the_fd) { + status_t result; + int pointer_reservation; //mem reserved for pointer + int cnt; //used for iteration through the overlay buffers + + if (1) { + time_t now = time (NULL); + // LOG not available from here to next LOG: NULL si +// MSG(("INIT_ACCELERANT: booted since %f ms %s\n", system_time()/1000.0, real_time_clock())); + MSG(("INIT_ACCELERANT: %s", ctime (&now))); + } + + /* note that we're the primary accelerant (accelerantIsClone is global) */ + accelerantIsClone = 0; + + /* do the initialization common to both the primary and the clones */ + result = init_common(the_fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error0; + // LOG now available: !NULL si + + /* call the device specific init code */ + result = nv_general_powerup(); + + /* bail out if it failed */ + if (result != B_OK) goto error1; + + /* + Now would be a good time to figure out what video modes your card supports. + We'll place the list of modes in another shared area so all of the copies + of the driver can see them. The primary copy of the accelerant (ie the one + initialized with this routine) will own the "one true copy" of the list. + Everybody else get's a read-only clone. + */ + result = create_mode_list(); + if (result != B_OK) + { + goto error1; + } + + /* + Put the cursor at the start of the frame buffer. + Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM. + */ + /* Initialize the rest of the cursor information while we're here */ + si->cursor.width = 16; + si->cursor.height = 16; + si->cursor.hot_x = 0; + si->cursor.hot_y = 0; + si->cursor.x = 0; + si->cursor.y = 0; + + /* + Put the frame buffer immediately following the cursor data. We store this + info in a frame_buffer_config structure to make it convienient to return + to the app_server later. + */ + pointer_reservation = 0; + /* Nvidia hardcursor needs 2kB space */ + if (si->settings.hardcursor) pointer_reservation = 2048; + + si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation); + si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation); + + /* count of issued parameters or commands */ + si->engine.last_idle = si->engine.count = 0; + INIT_BEN(si->engine.lock); + + INIT_BEN(si->overlay.lock); + for (cnt = 0; cnt < MAXBUFFERS; cnt++) + { + /* make sure overlay buffers are 'marked' as being free */ + si->overlay.myBuffer[cnt].buffer = NULL; + si->overlay.myBuffer[cnt].buffer_dma = NULL; + } + /* make sure overlay unit is 'marked' as being free */ + si->overlay.myToken = NULL; + + /* bail out if something failed */ + if (result != B_OK) goto error1; + + /* initialise various cursor stuff*/ + nv_crtc_cursor_init(); + + /* ensure cursor state */ + SHOW_CURSOR(false); + + /* a winner! */ + result = B_OK; + goto error0; + +error1: + /* + Initialization failed after init_common() succeeded, so we need to clean + up before quiting. + */ + uninit_common(); + +error0: + return result; +} + +/* +Return the number of bytes required to hold the information required +to clone the device. +*/ +ssize_t ACCELERANT_CLONE_INFO_SIZE(void) { + /* + Since we're passing the name of the device as the only required + info, return the size of the name buffer + */ + return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH; +} + + +/* +Return the info required to clone the device. void *data points to +a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length. +*/ +void GET_ACCELERANT_CLONE_INFO(void *data) { + nv_device_name dn; + status_t result; + + /* call the kernel driver to get the device name */ + dn.magic = NV_PRIVATE_DATA_MAGIC; + /* store the returned info directly into the passed buffer */ + dn.name = (char *)data; + result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn)); +} + +/* +Initialize a copy of the accelerant as a clone. void *data points to +a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). +*/ +status_t CLONE_ACCELERANT(void *data) { + status_t result; + char path[MAXPATHLEN]; + + /* the data is the device name */ + strcpy(path, "/dev"); + strcat(path, (const char *)data); + /* open the device, the permissions aren't important */ + fd = open(path, B_READ_WRITE); + if (fd < 0) { + result = fd; + goto error0; + } + + /* note that we're a clone accelerant */ + accelerantIsClone = 1; + + /* call the shared initialization code */ + result = init_common(fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error1; + + /* get shared area for display modes */ + result = my_mode_list_area = clone_area( + DRIVER_PREFIX " cloned display_modes", + (void **)&my_mode_list, + B_ANY_ADDRESS, + B_READ_AREA, + si->mode_area + ); + if (result < B_OK) goto error2; + + /* all done */ + LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n")); + + result = B_OK; + goto error0; + +error2: + /* free up the areas we cloned */ + uninit_common(); +error1: + /* close the device we opened */ + close(fd); +error0: + return result; +} + +void UNINIT_ACCELERANT(void) +{ + if (accelerantIsClone) + LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n")); + else + LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n")); + + /*delete benaphore*/ + DELETE_BEN(si->engine.lock); + DELETE_BEN(si->overlay.lock); + /* free our mode list area */ + delete_area(my_mode_list_area); + /* paranoia */ + my_mode_list = 0; + /* release our cloned data */ + uninit_common(); + /* close the file handle ONLY if we're the clone */ + if (accelerantIsClone) close(fd); +} diff --git a/src/add-ons/accelerants/nvidia/Overlay.c b/src/add-ons/accelerants/nvidia/Overlay.c new file mode 100644 index 0000000000..ebbffedf2c --- /dev/null +++ b/src/add-ons/accelerants/nvidia/Overlay.c @@ -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; + } + } +} diff --git a/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c b/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c new file mode 100644 index 0000000000..3b6f3ff53c --- /dev/null +++ b/src/add-ons/accelerants/nvidia/ProposeDisplayMode.c @@ -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;itiming.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; +} diff --git a/src/add-ons/accelerants/nvidia/SetDisplayMode.c b/src/add-ons/accelerants/nvidia/SetDisplayMode.c new file mode 100644 index 0000000000..65e71e2b72 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/SetDisplayMode.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/acc_std.h b/src/add-ons/accelerants/nvidia/acc_std.h new file mode 100644 index 0000000000..b4559bf824 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/acc_std.h @@ -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 +#include +#include "DriverInterface.h" +#include "global.h" +//apsed #include "nv_extern.h" +#include "nv_proto.h" +#include "be_driver_proto.h" + +#endif diff --git a/src/add-ons/accelerants/nvidia/engine/nv_acc.c b/src/add-ons/accelerants/nvidia/engine/nv_acc.c new file mode 100644 index 0000000000..0168dbfa32 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_acc.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_bes.c b/src/add-ons/accelerants/nvidia/engine/nv_bes.c new file mode 100644 index 0000000000..b2d75766fe --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_bes.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_crtc.c b/src/add-ons/accelerants/nvidia/engine/nv_crtc.c new file mode 100644 index 0000000000..cceff1090e --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_crtc.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_crtc2.c b/src/add-ons/accelerants/nvidia/engine/nv_crtc2.c new file mode 100644 index 0000000000..0306fae365 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_crtc2.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_dac.c b/src/add-ons/accelerants/nvidia/engine/nv_dac.c new file mode 100644 index 0000000000..c66f1a32d5 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_dac.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_general.c b/src/add-ons/accelerants/nvidia/engine/nv_general.c new file mode 100644 index 0000000000..9263034c60 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_general.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_i2c.c b/src/add-ons/accelerants/nvidia/engine/nv_i2c.c new file mode 100644 index 0000000000..d40d07377f --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_i2c.c @@ -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<=0; i--) + { + i2c_set_lines(1,1); + if (i2c_get_data()==1) + data |= (1<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; + } +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_info.c b/src/add-ons/accelerants/nvidia/engine/nv_info.c new file mode 100644 index 0000000000..a7e9180e99 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_info.c @@ -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")); +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_maven.c b/src/add-ons/accelerants/nvidia/engine/nv_maven.c new file mode 100644 index 0000000000..fd8a150fab --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_maven.c @@ -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; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_maventv.c b/src/add-ons/accelerants/nvidia/engine/nv_maventv.c new file mode 100644 index 0000000000..f99ba9976a --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_maventv.c @@ -0,0 +1,1210 @@ +/* Authors: + Mark Watson 2000, + Rudolf Cornelissen 1/2003-3/2003 + + Thanx to Petr Vandrovec for writing matroxfb. +*/ + +#define MODULE_BIT 0x00100000 + +#include "nv_std.h" + +typedef struct { + uint32 h_total; + uint32 h_display; + uint32 h_sync_length; + uint32 front_porch; + uint32 back_porch; + uint32 color_burst; + uint32 v_total; + float chroma_subcarrier; +} gx50_maven_timing; + +//fixme: setup fixed CRTC2 modes for all modes and block other modes: +// - 640x480, 800x600, 1024x768 NTSC and PAL overscan compensated modes (desktop) +// - 640x480, 720x480 NTSC and 768x576, 720x576 non-overscan compensated modes (video) +//fixme: try to implement 'fast' and 'slow' settings for all modes, +// so buffer duplication or skipping won't be neccesary for realtime video. +//fixme: try to setup the CRTC2 in interlaced mode for the video modes on <= G400MAX cards. + +/* find 'exact' valid video PLL setting */ +status_t g100_g400max_maventv_vid_pll_find( + display_mode target, unsigned int * ht_new, unsigned int * ht_last_line, + uint8 * m_result, uint8 * n_result, uint8 * p_result) +{ + int m = 0, n = 0, p = 0, m_max; + float diff, diff_smallest = 999999999; + int best[5], h_total_mod; + float fields_sec, f_vco; + /* We need to be exact, so work with clockperiods per field instead of with frequency. + * Make sure however we truncate these clocks to be integers! + * (The NTSC field frequency would otherwise prevent the 'whole number of clocks per field' + * check done in this routine later on...) */ + uint32 vco_clks_field, max_pclks_field, req_pclks_field; + /* We need this variable to be a float, because we need to be able to verify if this + * represents a whole number of clocks per field later on! */ + float calc_pclks_field; + + LOG(2,("MAVENTV: searching for EXACT videoclock match\n")); + + /* determine the max. reference-frequency postscaler setting for the current card */ + //fixme: check G100 and G200 m_max if exist and possible... + switch(si->ps.card_type) + { +/* case G100: + LOG(2,("MAVENTV: G100 restrictions apply\n")); + m_max = 32; + break; + case G200: + LOG(2,("MAVENTV: G200 restrictions apply\n")); + m_max = 32; + break; +*/ default: + LOG(2,("MAVENTV: G400/G400MAX restrictions apply\n")); + m_max = 32; + break; + } + + /* set number of fields per second to generate */ + if ((target.flags & TV_BITS) == TV_PAL) + fields_sec = 50.0; + else + fields_sec = 59.94; + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_RGB16_LITTLE: + max_pclks_field = (si->ps.max_dac2_clock_16 * 1000000) / fields_sec; + break; + case B_RGB32_LITTLE: + max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; + break; + default: + /* use fail-safe value */ + max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclks_field = (si->ps.max_dac2_clock_32dh * 1000000) / fields_sec; + + /* Checkout all possible Htotal settings within the current granularity step + * of CRTC2 to get a real close videoclock match! + * (The MAVEN apparantly has a granularity of 1 pixel, while CRTC2 has 8 pixels) */ + for (h_total_mod = 0; h_total_mod < 8; h_total_mod++) + { + LOG(2,("MAVENTV: trying h_total modification of +%d...\n", h_total_mod)); + + /* Calculate videoclock to be a bit to high so we can compensate for an exact + * match via h_total_lastline.. */ + *ht_new = target.timing.h_total + h_total_mod + 2; + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_video_vco divided by highest postscaler-factor */ + req_pclks_field = *ht_new * target.timing.v_total; + if (req_pclks_field < (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0)) + { + req_pclks_field = (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0); + LOG(4,("MAVENTV: WARNING, clamping at lowest possible videoclock\n")); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclks_field > max_pclks_field) + { + req_pclks_field = max_pclks_field; + LOG(4,("MAVENTV: WARNING, clamping at highest possible videoclock\n")); + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calc the needed number of VCO clocks per field for this postscaler setting */ + vco_clks_field = req_pclks_field * p; + + /* check if this is within range of the VCO specs */ + if ((vco_clks_field >= ((si->ps.min_video_vco * 1000000) / fields_sec)) && + (vco_clks_field <= ((si->ps.max_video_vco * 1000000) / fields_sec))) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= m_max; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((vco_clks_field * m) / ((si->ps.f_ref * 1000000) / fields_sec)) + 0.5); + /* ..and check for validity */ + if ((n < 8) || (n > 128)) continue; + + /* special TVmode stuff starts here (rest is in fact standard): */ + /* calculate number of videoclocks per field */ + calc_pclks_field = + (((uint32)((si->ps.f_ref * 1000000) / fields_sec)) * n) / ((float)(m * p)); + + /* we need a whole number of clocks per field, otherwise it won't work correctly. + * (TVout will flicker, green fields will occur) */ + if (calc_pclks_field != (uint32)calc_pclks_field) continue; + + /* check if we have the min. needed number of clocks per field for a sync lock */ + if (calc_pclks_field < ((*ht_new * (target.timing.v_total - 1)) + 2)) continue; + + /* calc number of clocks we have for the last field line */ + *ht_last_line = calc_pclks_field - (*ht_new * (target.timing.v_total - 1)); + + /* check if we haven't got too much clocks in the last field line for a sync lock */ + if (*ht_last_line > *ht_new) continue; + + /* we have a match! */ + /* calculate the difference between a full line and the last line */ + diff = *ht_new - *ht_last_line; + + /* if this last_line comes closer to a full line than earlier 'hits' then use it */ + if (diff < diff_smallest) + { + /* log results */ + if (diff_smallest == 999999999) + LOG(2,("MAVENTV: MATCH, ")); + else + LOG(2,("MAVENTV: better MATCH,")); + f_vco = (si->ps.f_ref / m) * n; + LOG(2,("found vid VCO freq %fMhz, pixclk %fMhz\n", f_vco, (f_vco / p))); + LOG(2,("MAVENTV: mnp(ex. filter) 0x%02x 0x%02x 0x%02x, h_total %d, ht_lastline %d\n", + (m - 1), (n - 1), (p - 1), (*ht_new - 2), (*ht_last_line - 2))); + + /* remember this best match */ + diff_smallest = diff; + best[0] = m; + best[1] = n; + best[2] = p; + /* h_total to use for this setting: + * exclude the 'calculate clock a bit too high' trick */ + best[3] = *ht_new - 2; + /* ht_last_line to use for this setting: + * exclude the 'calculate clock a bit too high' trick */ + best[4] = *ht_last_line - 2; + } + } + } + } + } + LOG(2,("MAVENTV: search completed.\n")); + + /* setup the scalers programming values for found optimum setting */ + m = best[0] - 1; + n = best[1] - 1; + p = best[2] - 1; + + /* if no match was found set fixed PLL frequency so we have something valid at least */ + if (diff_smallest == 999999999) + { + LOG(4,("MAVENTV: WARNING, no MATCH found!\n")); + + if (si->ps.f_ref == 27.000) + { + /* set 13.5Mhz */ + m = 0x03; + n = 0x07; + p = 0x03; + } + else + { + /* set 14.31818Mhz */ + m = 0x01; + n = 0x07; + p = 0x03; + } + best[3] = target.timing.h_total; + best[4] = target.timing.h_total; + } + + /* calc the needed PLL loopbackfilter setting belonging to current VCO speed */ + f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); + LOG(2,("MAVENTV: using vid VCO frequency %fMhz\n", f_vco)); + + switch(si->ps.card_type) + { +/* case G100: + case G200: + for(;;) + { + if (f_vco >= 180) {p |= (0x03 << 3); break;}; + if (f_vco >= 140) {p |= (0x02 << 3); break;}; + if (f_vco >= 100) {p |= (0x01 << 3); break;}; + break; + } + break; +*/ 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 results */ + *m_result = m; + *n_result = n; + *p_result = p; + *ht_new = best[3]; + *ht_last_line = best[4]; + + /* display the found pixelclock values */ + LOG(2,("MAVENTV: vid PLL check: got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + (f_vco / ((p & 0x07) + 1)), m, n, p)); + LOG(2,("MAVENTV: new h_total %d, ht_lastline %d\n", *ht_new, *ht_last_line)); + + /* return status */ + if (diff_smallest == 999999999) return B_ERROR; + return B_OK; +} + + /* Notes about timing: + * Note: + * all horizontal timing is measured in pixelclock periods; + * all? vertical timing is measured in field? lines. */ + + /* Note: + * <= G400MAX cards have a fixed 27Mhz(?) clock for TV timing register values, + * while on G450/G550 these need to be calculated based on the video pixelclock. */ + + + /* Notes about signal strengths: + * Note: + * G400 and earlier cards have a fixed reference voltage of +2.6 Volt; + * G450 and G550 cards MAVEN DACs have a switchable ref voltage of +1.5/+2.0 Volt. + * + * This voltage is used to feed the videosignals: + * - Hsync pulse level; + * - Lowest active video output level; + * - Highest active video output level. + * These actual voltages are set via 10bit DACs. + * + * G450/G550: + * The color burst amplitude videosignal is fed by 80% of the above mentioned + * ref. voltage, and is set via an 8bit DAC. + * On G400 and earlier cards the ref. voltage is different, and also differs + * for PAL and NTSC mode. */ + + /* Note: + * Increasing the distance between the highest and lowest active video output + * level increases contrast; decreasing it decreases contrast. */ + + /* Note: + * Increasing both the highest and lowest active video output level with the + * same amount increases brightness; decreasing it decreases brightness. */ + + /* Note: + * Increasing the Hsync pulse level increases the black level, so decreases + * brightness and contrast. */ + +/* Preset maven PAL output (625lines, 50Hz mode) */ +void gxx0_maventv_PAL_init(uint8* buffer) +{ + uint16 value; + + /* Chroma subcarrier divider */ + buffer[0x00] = 0x2A; + buffer[0x01] = 0x09; + buffer[0x02] = 0x8A; + buffer[0x03] = 0xCB; + + buffer[0x04] = 0x00; + buffer[0x05] = 0x00; + buffer[0x06] = 0xF9; + buffer[0x07] = 0x00; + /* Hsync pulse length */ + buffer[0x08] = 0x7E; + /* color burst length */ + buffer[0x09] = 0x44; + /* back porch length */ + buffer[0x0a] = 0x9C; + + /* color burst amplitude */ +/* if (si->ps.card_type <= G400MAX) + { + buffer[0x0b] = 0x3e; + } + else + { +*/ buffer[0x0b] = 0x48; +// } + + buffer[0x0c] = 0x21; + buffer[0x0d] = 0x00; + +// if (si->ps.card_type <= G400MAX) +// { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ +// value = 0x0ea; +// buffer[0x0e] = ((value >> 2) & 0xff); +// buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ +// buffer[0x10] = ((value >> 2) & 0xff); +// buffer[0x11] = (value & 0x03); +// } +// else + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x130; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + + buffer[0x12] = 0x1A; + buffer[0x13] = 0x2A; + + /* functional unit */ + buffer[0x14] = 0x1C; + buffer[0x15] = 0x3D; + buffer[0x16] = 0x14; + + /* vertical total */ //(=625) + /* b9-2 */ + buffer[0x17] = 0x9C; + /* b1-0 in b1-0 */ + buffer[0x18] = 0x01; + + buffer[0x19] = 0x00; + buffer[0x1a] = 0xFE; + buffer[0x1b] = 0x7E; + buffer[0x1c] = 0x60; + buffer[0x1d] = 0x05; + + /* Highest active video output level. + * Warning: make sure this stays above the lowest active video output level! */ +/* if (si->ps.card_type <= G400MAX) + { + value = 0x24f; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + else +*/ { + value = 0x300; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + + /* saturation (field?) #1 */ +// if (si->ps.card_type <= G400MAX) +// buffer[0x20] = 0x72; +// else + buffer[0x20] = 0xA5; + + buffer[0x21] = 0x07; + + /* saturation (field?) #2 */ +// if (si->ps.card_type <= G400MAX) +// buffer[0x22] = 0x72; +// else + buffer[0x22] = 0xA5; + + buffer[0x23] = 0x00; + buffer[0x24] = 0x00; + /* hue? */ + buffer[0x25] = 0x00; + + buffer[0x26] = 0x08; + buffer[0x27] = 0x04; + buffer[0x28] = 0x00; + buffer[0x29] = 0x1A; + + /* functional unit */ + buffer[0x2a] = 0x55; + buffer[0x2b] = 0x01; + + /* front porch length */ + buffer[0x2c] = 0x26; + + /* functional unit */ + buffer[0x2d] = 0x07; + buffer[0x2e] = 0x7E; + + /* functional unit */ + buffer[0x2f] = 0x02; + buffer[0x30] = 0x54; + + /* horizontal visible */ + value = 0x580; + buffer[0x31] = ((value >> 3) & 0xff); + buffer[0x32] = (value & 0x07); + + /* upper blanking (in field lines) */ + buffer[0x33] = 0x14; //=((v_total - v_sync_end)/2) -1 + + buffer[0x34] = 0x49; + buffer[0x35] = 0x00; + buffer[0x36] = 0x00; + buffer[0x37] = 0xA3; + buffer[0x38] = 0xC8; + buffer[0x39] = 0x22; + buffer[0x3a] = 0x02; + buffer[0x3b] = 0x22; + + /* functional unit */ + buffer[0x3c] = 0x3F; + buffer[0x3d] = 0x03; +} + +/* Preset maven NTSC output (525lines, 59.94Hz mode) */ +void gxx0_maventv_NTSC_init(uint8* buffer) +{ + uint16 value; + + /* Chroma subcarrier frequency */ + buffer[0x00] = 0x21; + buffer[0x01] = 0xF0; + buffer[0x02] = 0x7C; + buffer[0x03] = 0x1F; + + buffer[0x04] = 0x00; + buffer[0x05] = 0x00;//b1 = ON enables colorbar testimage + buffer[0x06] = 0xF9;//b0 = ON enables MAVEN TV output + buffer[0x07] = 0x00;//influences the colorburst signal amplitude somehow + + /* Hsync pulse length */ + buffer[0x08] = 0x7E; + /* color burst length */ + buffer[0x09] = 0x43; + /* back porch length */ + buffer[0x0a] = 0x7E; + + /* color burst amplitude */ +// if (si->ps.card_type <= G400MAX) +// { +// buffer[0x0b] = 0x46; +// } +// else + { + buffer[0x0b] = 0x48; + } + + buffer[0x0c] = 0x00; + buffer[0x0d] = 0x00; + +// if (si->ps.card_type <= G400MAX) +// { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ +// value = 0x0ea; +// buffer[0x0e] = ((value >> 2) & 0xff); +// buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ +// buffer[0x10] = ((value >> 2) & 0xff); +// buffer[0x11] = (value & 0x03); +// } +// else + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x130; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + + buffer[0x12] = 0x17; + buffer[0x13] = 0x21; + + /* functional unit */ + buffer[0x14] = 0x1B; + buffer[0x15] = 0x1B; + buffer[0x16] = 0x24; + + /* vertical total */ + /* b9-2 */ + buffer[0x17] = 0x83; + /* b1-0 in b1-0 */ + buffer[0x18] = 0x01; + + buffer[0x19] = 0x00;//mv register? + buffer[0x1a] = 0x0F; + buffer[0x1b] = 0x0F; + buffer[0x1c] = 0x60; + buffer[0x1d] = 0x05; + + /* Highest active video output level. + * Warning: make sure this stays above the lowest active video output level! */ +/* if (si->ps.card_type <= G400MAX) + { + value = 0x24f; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + else +*/ { + value = 0x300; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + + /* color saturation #1 (Y-B ?) */ +// if (si->ps.card_type <= G400MAX) +// buffer[0x20] = 0x5F; +// else + buffer[0x20] = 0x9C; + + buffer[0x21] = 0x04; + + /* color saturation #2 (Y-R ?) */ +// if (si->ps.card_type <= G400MAX) +// buffer[0x22] = 0x5F; +// else + buffer[0x22] = 0x9C; + + buffer[0x23] = 0x01; + buffer[0x24] = 0x02; + + /* hue: preset at 0 degrees */ + buffer[0x25] = 0x00; + + buffer[0x26] = 0x0A; + buffer[0x27] = 0x05;//sync stuff + buffer[0x28] = 0x00; + buffer[0x29] = 0x10;//field line-length stuff + + /* functional unit */ + buffer[0x2a] = 0xFF; + buffer[0x2b] = 0x03; + + /* front porch length */ + buffer[0x2c] = 0x24; + + /* functional unit */ + buffer[0x2d] = 0x0F; + buffer[0x2e] = 0x78; + + /* functional unit */ + buffer[0x2f] = 0x00; + buffer[0x30] = 0x00; + + /* horizontal visible */ + /* b10-3 */ + buffer[0x31] = 0xB2; + /* b2-0 in b2-0 */ + buffer[0x32] = 0x04; + + /* upper blanking (in field lines) */ + buffer[0x33] = 0x14; + + buffer[0x34] = 0x02;//colorphase or so stuff. + buffer[0x35] = 0x00; + buffer[0x36] = 0x00; + buffer[0x37] = 0xA3; + buffer[0x38] = 0xC8; + buffer[0x39] = 0x15; + buffer[0x3a] = 0x05; + buffer[0x3b] = 0x3B; + + /* functional unit */ + buffer[0x3c] = 0x3C; + buffer[0x3d] = 0x00; +} + +void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing) +{ + /* values are given in picoseconds */ + m_timing->h_total = 64000000; + /* the sum of the signal duration below should match h_total! */ + m_timing->h_display = 52148148; + m_timing->h_sync_length = 4666667; + m_timing->front_porch = 1407407; + m_timing->back_porch = 5777778; + /* colorburst is 'superimposed' on the above timing */ + m_timing->color_burst = 2518518; + /* number of lines per frame */ + m_timing->v_total = 625; + /* color carrier frequency in Mhz */ + m_timing->chroma_subcarrier = 4.43361875; +} + +void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing) +{ + /* values are given in picoseconds */ + m_timing->h_total = 63555556; + /* the sum of the signal duration below should match h_total! */ + m_timing->h_display = 52888889; + m_timing->h_sync_length = 4666667; + m_timing->front_porch = 1333333; + m_timing->back_porch = 4666667; + /* colorburst is 'superimposed' on the above timing */ + m_timing->color_burst = 2418418; + /* number of lines per frame */ + m_timing->v_total = 525; + /* color carrier frequency in Mhz */ + m_timing->chroma_subcarrier = 3.579545454; +} + +int maventv_init(display_mode target) +{ + uint8 val; + uint8 m_result, n_result, p_result; + unsigned int ht_new, ht_last_line; + float calc_pclk = 0; + /* use a display_mode copy because we might tune it for TVout compatibility */ + display_mode tv_target = target; + /* used as buffer for TVout signal to generate */ + uint8 maventv_regs[64]; + /* used in G450/G550 to calculate TVout signal timing dependant on pixelclock; + * <= G400MAX use fixed settings because base-clock here is the fixed crystal + * frequency. */ + //fixme: if <=G400 cards with MAVEN and crystal of 14.31818Mhz exist, modify!?! + gx50_maven_timing m_timing; + + /* preset new TVout mode */ + if ((tv_target.flags & TV_BITS) == TV_PAL) + { + LOG(4, ("MAVENTV: PAL TVout\n")); + gxx0_maventv_PAL_init(maventv_regs); + gx50_maventv_PAL_timing(&m_timing); + } + else + { + LOG(4, ("MAVENTV: NTSC TVout\n")); + gxx0_maventv_NTSC_init(maventv_regs); + gx50_maventv_NTSC_timing(&m_timing); + } + + /* enter mode-program mode */ +// if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x01); +// else +// { +// DXIW(TVO_IDX, NVMAV_PGM); +// DXIW(TVO_DATA, 0x01); +// } + + /* tune new TVout mode */ +// if (si->ps.card_type <= G400MAX) + { + /* setup TV-mode 'copy' of CRTC2, setup PLL, inputs, outputs and sync-locks */ + MAVW(MONSET, 0x00); + MAVW(MONEN, 0xA2); + + /* xmiscctrl */ + //unknown regs: + MAVWW(WREG_0X8E_L, 0x1EFF); + MAVW(BREG_0XC6, 0x01); + + MAVW(LOCK, 0x01); + MAVW(OUTMODE, 0x08); + MAVW(LUMA, 0x78); + MAVW(STABLE, 0x02); + MAVW(MONEN, 0xB3); + + /* setup video PLL */ + g100_g400max_maventv_vid_pll_find( + tv_target, &ht_new, &ht_last_line, &m_result, &n_result, &p_result); + MAVW(PIXPLLM, m_result); + MAVW(PIXPLLN, n_result); + MAVW(PIXPLLP, (p_result | 0x80)); + + MAVW(MONSET, 0x20); + + MAVW(TEST, 0x10); + + /* htotal - 2 */ + MAVWW(HTOTALL, ht_new); + + /* last line in field can have different length */ + /* hlen - 2 */ + MAVWW(LASTLINEL, ht_last_line); + + /* horizontal vidrst pos: 0 <= vidrst pos <= htotal - 2 */ + MAVWW(HVIDRSTL, (ht_last_line - si->crtc_delay - + (tv_target.timing.h_sync_end - tv_target.timing.h_sync_start))); + //ORG (does the same but with limit checks but these limits should never occur!): +// slen = tv_target.timing.h_sync_end - tv_target.timing.h_sync_start; +// hcrt = tv_target.timing.h_total - slen - si->crtc_delay; +// if (ht_last_line < tv_target.timing.h_total) hcrt += ht_last_line; +// if (hcrt > tv_target.timing.h_total) hcrt -= tv_target.timing.h_total; +// if (hcrt + 2 > tv_target.timing.h_total) hcrt = 0; /* or issue warning? */ +// MAVWW(HVIDRSTL, hcrt); + + /* who knows */ + MAVWW(HSYNCSTRL, 0x0004);//must be 4!! + + /* hblanking end: 100% */ + MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end)); + + /* vertical line count - 1 */ + MAVWW(VTOTALL, (tv_target.timing.v_total - 1)); + + /* vertical vidrst pos */ + MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2)); + + /* something end... [A6]+1..[A8] */ + MAVWW(VSYNCSTRL, 0x0001); + + /* vblanking end: stop vblanking */ + MAVWW(VSYNCLENL, (tv_target.timing.v_sync_end - tv_target.timing.v_sync_start - 1)); + //org: no visible diff: + //MAVWW(VSYNCLENL, (tv_target.timing.v_total - tv_target.timing.v_sync_start - 1)); + + /* something start... 0..[A4]-1 */ + MAVWW(VDISPLAYL, 0x0000); + //std setmode (no visible difference) + //MAVWW(VDISPLAYL, (tv_target.timing.v_total - 1)); + + /* ... */ + MAVWW(WREG_0X98_L, 0x0000); + + /* moves picture up/down and so on... */ + MAVWW(VSOMETHINGL, 0x0001); /* Fix this... 0..VTotal */ + + { + uint32 h_display_tv; + uint8 h_scale_tv; + + unsigned int ib_min_length; + unsigned int ib_length; + int index; + + /* calc hor scale-back factor from input to output picture (in 1.7 format) + * the MAVEN has 736 pixels fixed visible? outputline length for TVout */ + //fixme: shouldn't this be 768 (= PAL 1:1 output 4:3 ratio format)?!? + h_scale_tv = (736 << 7) / tv_target.timing.h_total;//should be PLL corrected + LOG(4,("MAVENTV: horizontal scale-back factor is: %f\n", (h_scale_tv / 128.0))); + + /* limit values to MAVEN capabilities (scale-back factor is 0.5-1.0) */ + //fixme: how about lowres upscaling? + if (h_scale_tv > 0x80) + { + h_scale_tv = 0x80; + LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); + } + if (h_scale_tv < 0x40) + { + h_scale_tv = 0x40; + LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); + } + /* make sure we get no round-off error artifacts on screen */ + h_scale_tv--; + + /* calc difference in (wanted output picture width (excl. hsync_length)) and + * (fixed total output line length (=768)), + * based on input picture and scaling factor */ + /* (MAVEN trick (part 1) to get output picture width to fit into just 8 bits) */ + h_display_tv = ((768 - 1) << 7) - + (((tv_target.timing.h_total - tv_target.timing.h_sync_end) /* is left margin */ + + tv_target.timing.h_display - 8) + * h_scale_tv); + /* convert result from 25.7 to 32.0 format */ + h_display_tv = h_display_tv >> 7; + LOG(4,("MAVENTV: displaying output on %d picture pixels\n", + ((768 - 1) - h_display_tv))); + + /* half result: MAVEN trick (part 2) + * (258 - 768 pixels, only even number per line is possible) */ + h_display_tv = h_display_tv >> 1; + /* limit value to register contraints */ + if (h_display_tv > 0xFF) h_display_tv = 0xFF; + MAVW(HSCALETV, h_scale_tv); + MAVW(HDISPLAYTV, h_display_tv); + + + /* calculate line inputbuffer length */ + /* It must be between (including): + * ((input picture left margin) + (input picture hor. resolution) + 4) + * AND + * (input picture total line length) (PLL corrected) */ + + /* calculate minimal line input buffer length */ + ib_min_length = ((tv_target.timing.h_total - tv_target.timing.h_sync_end) + + tv_target.timing.h_display + 4); + + /* calculate optimal line input buffer length (so top of picture is OK too) */ + /* The following formula applies: + * optimal buffer length = ((((0x78 * i) - R) / hor. scaling factor) + Q) + * + * where (in 4.8 format!) + * R Qmin Qmax + * 0x0E0 0x5AE 0x5BF + * 0x100 0x5CF 0x5FF + * 0x180 0x653 0x67F + * 0x200 0x6F8 0x6FF + */ + index = 1; + do + { + ib_length = ((((((0x7800 << 7) * index) - (0x100 << 7)) / h_scale_tv) + 0x05E7) >> 8); + index++; + } while (ib_length < ib_min_length); + LOG(4,("MAVENTV: optimal line inputbuffer length: %d\n", ib_length)); + + if (ib_length >= ht_new + 2) + { + ib_length = ib_min_length; + LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length)); + } + MAVWW(HDISPLAYL, ib_length); + } + + { + uint16 t_scale_tv; + uint32 v_display_tv; + + /* calc total scale-back factor from input to output picture */ + { + uint32 out_clocks; + uint32 in_clocks; + + //takes care of green stripes: + /* calc output clocks per frame */ + out_clocks = m_timing.v_total * (ht_new + 2); + + /* calc input clocks per frame */ + in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) + ht_last_line + 2; + + /* calc total scale-back factor from input to output picture in 1.15 format */ + t_scale_tv = ((((uint64)out_clocks) << 15) / in_clocks); + LOG(4,("MAVENTV: total scale-back factor is: %f\n", (t_scale_tv / 32768.0))); + + /* min. scale-back factor is 1.0 for 1:1 output */ + if (t_scale_tv > 0x8000) + { + t_scale_tv = 0x8000; + LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0))); + } + } + + /*calc output picture height based on input picture and scaling factor */ + //warning: v_display was 'one' lower originally! + v_display_tv = + ((tv_target.timing.v_sync_end - tv_target.timing.v_sync_start) /* is sync length */ + + (tv_target.timing.v_total - tv_target.timing.v_sync_end) /* is upper margin */ + + tv_target.timing.v_display) + * t_scale_tv; + /* convert result from 17.15 to 32.0 format */ + v_display_tv = (v_display_tv >> 15); + LOG(4,("MAVENTV: displaying output on %d picture frame-lines\n", v_display_tv)); + + /* half result, and compensate for internal register offset + * (MAVEN trick to get it to fit into just 8 bits). + * (allowed output frame height is 292 - 802 lines, only even numbers) */ + v_display_tv = (v_display_tv >> 1) - 146; + /* limit value to register contraints */ + if (v_display_tv > 0xFF) v_display_tv = 0xFF; + /* make sure we get no round-off error artifacts on screen */ + t_scale_tv--; + + MAVWW(TSCALETVL, t_scale_tv); + MAVW(VDISPLAYTV, v_display_tv); + } + + MAVW(TEST, 0x00); + + /* gamma correction registers */ + MAVW(GAMMA1, 0x00); + MAVW(GAMMA2, 0x00); + MAVW(GAMMA3, 0x00); + MAVW(GAMMA4, 0x1F); + MAVW(GAMMA5, 0x10); + MAVW(GAMMA6, 0x10); + MAVW(GAMMA7, 0x10); + MAVW(GAMMA8, 0x64); /* 100 */ + MAVW(GAMMA9, 0xC8); /* 200 */ + + /* set flickerfilter */ + /* OFF: is dependant on MAVEN chip version(?): NV_TVO_B = $40, else $00. + * ON : always set $a2. */ + MAVW(FFILTER, 0xa2); + + /* 0x10 or anything ored with it */ + //fixme? linux uses 0x14... + MAVW(TEST, (MAVR(TEST) & 0x10)); + + /* output: SVideo/Composite */ + MAVW(OUTMODE, 0x08); + } +// else /* card_type is >= G450 */ + { + //fixme: setup an intermediate buffer if vertical res is different than settings below! + //fixme: setup 2D or 3D engine to do screen_to_screen_scaled_filtered_blit between the buffers + // during vertical retrace! + if ((tv_target.flags & TV_BITS) == TV_PAL) + { + int diff; + + /* defined by the PAL standard */ + tv_target.timing.v_total = m_timing.v_total; + /* we need to center the image on TV vertically. + * note that 576 is the maximum supported resolution for the PAL standard, + * this is already overscanning by approx 8-10% */ + diff = 576 - tv_target.timing.v_display; + /* if we cannot display the current vertical resolution fully, clip it */ + if (diff < 0) + { + tv_target.timing.v_display = 576; + diff = 0; + } + /* now center the image on TV by centering the vertical sync pulse */ + tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); + tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; + } + else + { + int diff; + + /* defined by the NTSC standard */ + tv_target.timing.v_total = m_timing.v_total; + /* we need to center the image on TV vertically. + * note that 480 is the maximum supported resolution for the NTSC standard, + * this is already overscanning by approx 8-10% */ + diff = 480 - tv_target.timing.v_display; + /* if we cannot display the current vertical resolution fully, clip it */ + if (diff < 0) + { + tv_target.timing.v_display = 480; + diff = 0; + } + /* now center the image on TV by centering the vertical sync pulse */ + tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); + tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; + } + + /* setup video PLL for G450/G550: + * this can be done in the normal way because the MAVEN works in slave mode! + * NOTE: must be done before programming CRTC2, or interlaced startup may fail. */ + + //fixme: make sure videoPLL is powered up: XPWRCTRL b1=1 + { + uint16 front_porch, back_porch, h_sync_length, burst_length, h_total, h_display; + uint32 chromasc; + uint64 pix_period; + uint16 h_total_wanted, leftover; + + /* calculate tv_h_display in 'half pixelclocks' and adhere to MAVEN restrictions. + * ('half pixelclocks' exist because the MAVEN uses them...) */ + h_display = (((tv_target.timing.h_display << 1) + 3) & ~0x03); + if (h_display > 2044) h_display = 2044; + /* copy result to MAVEN TV mode */ + maventv_regs[0x31] = (h_display >> 3); + maventv_regs[0x32] = (h_display & 0x07); + + /* calculate needed video pixelclock in kHz. + * NOTE: + * The clock calculated is based on MAVEN output, so each pixelclock period + * is in fact a 'half pixelclock' period compared to monitor mode use. */ + tv_target.timing.pixel_clock = + ((((uint64)h_display) * 1000000000) / m_timing.h_display); + + /* tune display_mode adhering to CRTC2 restrictions */ + /* (truncate h_display to 'whole pixelclocks') */ + tv_target.timing.h_display = ((h_display >> 1) & ~0x07); + tv_target.timing.h_sync_start = tv_target.timing.h_display + 8; + +// g450_g550_maven_vid_pll_find(tv_target, &calc_pclk, &m_result, &n_result, &p_result, 1); + /* adjust mode to actually used pixelclock */ + tv_target.timing.pixel_clock = (calc_pclk * 1000); + + /* program videoPLL */ +// DXIW(VIDPLLM, m_result); +// DXIW(VIDPLLN, n_result); +// DXIW(VIDPLLP, p_result); + + /* calculate videoclock 'half' period duration in picoseconds */ + pix_period = (1000000000 / ((float)tv_target.timing.pixel_clock)) + 0.5; + LOG(4,("MAVENTV: TV videoclock period is %d picoseconds\n", pix_period)); + + /* calculate number of 'half' clocks per line according to pixelclock set */ + /* fixme: try to setup the modes in such a way that + * (h_total_clk % 16) == 0 because of the CRTC2 restrictions: + * we want to loose the truncating h_total trick below if possible! */ + /* Note: + * This is here so we can see the wanted and calc'd timing difference. */ + h_total_wanted = ((m_timing.h_total / ((float)pix_period)) + 0.5); + LOG(4,("MAVENTV: TV h_total should be %d units\n", h_total_wanted)); + + /* calculate chroma subcarrier value to setup: + * do this as exact as possible because this signal is very sensitive.. */ + chromasc = + ((((uint64)0x100000000) * (m_timing.chroma_subcarrier / calc_pclk)) + 0.5); + /* copy result to MAVEN TV mode */ + maventv_regs[0] = ((chromasc >> 24) & 0xff); + maventv_regs[1] = ((chromasc >> 16) & 0xff); + maventv_regs[2] = ((chromasc >> 8) & 0xff); + maventv_regs[3] = ((chromasc >> 0) & 0xff); + LOG(4,("MAVENTV: TV chroma subcarrier divider set is $%08x\n", chromasc)); + + /* calculate front porch in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + front_porch = ((m_timing.front_porch / ((float)pix_period)) + 1); + /* value must be even */ + front_porch &= ~0x01; + + /* calculate back porch in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + back_porch = ((m_timing.back_porch / ((float)pix_period)) + 1); + /* value must be even */ + back_porch &= ~0x01; + + /* calculate h_sync length in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + h_sync_length = ((m_timing.h_sync_length / ((float)pix_period)) + 1); + /* value must be even */ + h_sync_length &= ~0x01; + + /* calculate h_total in 'half pixelclocks' */ + h_total = h_display + front_porch + back_porch + h_sync_length; + + LOG(4,("MAVENTV: TV front_porch is %d clocks\n", front_porch)); + LOG(4,("MAVENTV: TV back_porch is %d clocks\n", back_porch)); + LOG(4,("MAVENTV: TV h_sync_length is %d clocks\n", h_sync_length)); + LOG(4,("MAVENTV: TV h_display is %d clocks \n", h_display)); + LOG(4,("MAVENTV: TV h_total is %d clocks\n", h_total)); + + /* calculate color_burst length in 'half pixelclocks' */ + burst_length = (((m_timing.color_burst /*- 1*/) / ((float)pix_period)) + 0.5); + LOG(4,("MAVENTV: TV color_burst is %d clocks.\n", burst_length)); + + /* copy result to MAVEN TV mode */ + maventv_regs[0x09] = burst_length; + + /* Calculate line length 'rest' that remains after truncating + * h_total to adhere to the CRTC2 timing restrictions. */ + leftover = h_total & 0x0F; + /* if some 'rest' exists, we need to compensate for it... */ + /* Note: + * It's much better to prevent this from happening because this + * 'trick' will decay TVout timing! (timing is nolonger official) */ + if (leftover) + { + /* truncate line length to adhere to CRTC2 restrictions */ + front_porch -= leftover; + h_total -= leftover; + + /* now set line length to closest CRTC2 valid match */ + if (leftover < 3) + { + /* 1 <= old rest <= 2: + * Truncated line length is closest match. */ + LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n")); + } + else + { + if (leftover < 10) + { + /* 3 <= old rest <= 9: + * We use the NTSC killer circuitry to get closest match. + * (The 'g400_crtc2_set_timing' routine will enable it + * because of the illegal h_total timing we create here.) */ + front_porch += 4; + h_total += 4; + LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via killer (> 2, < 10)\n")); + } + else + { + /* 10 <= old rest <= 15: + * Set closest valid CRTC2 match. */ + front_porch += 16; + h_total += 16; + LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via increase (> 9, < 16)\n")); + } + } + } + + /* (linux) fixme: maybe MAVEN has requirement 800 < h_total < 1184 */ + maventv_regs[0x2C] = front_porch; + maventv_regs[0x0A] = back_porch; + maventv_regs[0x08] = h_sync_length; + + /* change h_total to represent 'whole pixelclocks' */ + h_total = h_total >> 1; + + /* tune display_mode adhering to CRTC2 restrictions */ + tv_target.timing.h_sync_end = (h_total & ~0x07) - 8; + /* h_total is checked before being programmed! (NTSC killer circuitry) */ + tv_target.timing.h_total = h_total; + } + + /* output Y/C and CVBS signals (| $40 needed for SCART) */ +// DXIW(TVO_IDX, 0x80); +// DXIW(TVO_DATA, 0x03); + + /* select input colorspace */ + //fixme?: has no effect on output picture on monitor or TV... + //DXIW(TVO_IDX, 0x81); + //DXIW(TVO_DATA, 0x00); + + /* calculate vertical sync point */ + { + int upper; + + /* set 625 lines for PAL or 525 lines for NTSC */ + maventv_regs[0x17] = m_timing.v_total / 4; + maventv_regs[0x18] = m_timing.v_total & 3; + + /* calculate upper blanking range in field lines */ + upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1; + + /* blank TVout above the line number calculated */ + maventv_regs[0x33] = upper - 1; + + /* set calculated vertical sync point */ +// DXIW(TVO_IDX, 0x82); +// DXIW(TVO_DATA, (upper & 0xff)); +// DXIW(TVO_IDX, 0x83); +// DXIW(TVO_DATA, ((upper >> 8) & 0xff)); + LOG(4,("MAVENTV: TV upper blanking range set is %d\n", upper)); + } + + /* set fized horizontal sync point */ +// DXIW(TVO_IDX, 0x84); +// DXIW(TVO_DATA, 0x01); +// DXIW(TVO_IDX, 0x85); +// DXIW(TVO_DATA, 0x00); + + /* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (TVout mode) */ +// DXIW(OUTPUTCONN,0x0d); + } + + /* program new TVout mode */ + for (val = 0x00; val <= 0x3D; val++) + { +/* if (si->ps.card_type <= G400MAX) + { + i2c_maven_write(val, maventv_regs[val]); + } + else +*/ { +// DXIW(TVO_IDX, val); +// DXIW(TVO_DATA, maventv_regs[val]); + } + } + + /* leave mode-program mode */ +// if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x00); +// else +// { +// DXIW(TVO_IDX, NVMAV_PGM); +// DXIW(TVO_DATA, 0x00); + + /* Select 2.0 Volt MAVEN DAC ref. so we have enough contrast/brightness range */ +// DXIW(GENIOCTRL, DXIR(GENIOCTRL) | 0x40); +// DXIW(GENIODATA, 0x00); +// } + + /* setup CRTC2 timing */ + g400_crtc2_set_timing(tv_target); + + /* start whole thing if needed */ +// if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20); + + return 0; +} diff --git a/src/add-ons/accelerants/nvidia/engine/nv_std.h b/src/add-ons/accelerants/nvidia/engine/nv_std.h new file mode 100644 index 0000000000..82afcc4b7e --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_std.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include "DriverInterface.h" +#include "global.h" +//apsed #include "nv_extern.h" +#include "nv_proto.h" +#include "nv_macros.h" diff --git a/src/add-ons/accelerants/nvidia/engine/nv_support.c b/src/add-ons/accelerants/nvidia/engine/nv_support.c new file mode 100644 index 0000000000..f5167f65f2 --- /dev/null +++ b/src/add-ons/accelerants/nvidia/engine/nv_support.c @@ -0,0 +1,30 @@ +/* Some commmon support functions */ +/* Mark Watson 2/2000 */ + +#define MODULE_BIT 0x00000800 + +#include +#include "nv_std.h" + +/*delays in multiple of microseconds*/ +void delay(bigtime_t i) +{ + bigtime_t start=system_time(); + while(system_time()-start