From 6835336864a9a191c4de8a1b498a54ebb71264e6 Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Thu, 4 Nov 2004 12:30:26 +0000 Subject: [PATCH] initial import of skeleton graphics accelerant (not yet working/stripped) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9783 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../accelerants/skeleton/Acceleration.c | 140 + src/add-ons/accelerants/skeleton/Cursor.c | 195 + .../accelerants/skeleton/EngineManagement.c | 70 + .../accelerants/skeleton/GetAccelerantHook.c | 221 ++ .../accelerants/skeleton/GetDeviceInfo.c | 99 + .../accelerants/skeleton/GetModeInfo.c | 160 + .../skeleton/GetTimingConstraints.c | 33 + .../accelerants/skeleton/InitAccelerant.c | 324 ++ src/add-ons/accelerants/skeleton/Jamfile | 29 + src/add-ons/accelerants/skeleton/Overlay.c | 612 ++++ .../accelerants/skeleton/ProposeDisplayMode.c | 597 ++++ .../accelerants/skeleton/SetDisplayMode.c | 517 +++ src/add-ons/accelerants/skeleton/acc_std.h | 17 + .../accelerants/skeleton/be_driver_proto.h | 68 + .../accelerants/skeleton/engine/Jamfile | 20 + src/add-ons/accelerants/skeleton/engine/acc.c | 888 +++++ src/add-ons/accelerants/skeleton/engine/agp.c | 216 ++ src/add-ons/accelerants/skeleton/engine/bes.c | 868 +++++ .../accelerants/skeleton/engine/crtc.c | 829 +++++ .../accelerants/skeleton/engine/crtc2.c | 791 +++++ src/add-ons/accelerants/skeleton/engine/dac.c | 561 +++ .../accelerants/skeleton/engine/dac2.c | 391 +++ .../accelerants/skeleton/engine/general.c | 1454 ++++++++ .../accelerants/skeleton/engine/globals.c | 35 + .../accelerants/skeleton/engine/globals.h | 66 + src/add-ons/accelerants/skeleton/engine/i2c.c | 348 ++ .../accelerants/skeleton/engine/info.c | 3126 +++++++++++++++++ .../accelerants/skeleton/engine/proto.h | 130 + src/add-ons/accelerants/skeleton/engine/std.h | 9 + .../accelerants/skeleton/engine/support.c | 34 + .../accelerants/skeleton/engine/tvout.c | 1215 +++++++ .../accelerants/skeleton/valid_mode_list | 34 + 32 files changed, 14097 insertions(+) create mode 100644 src/add-ons/accelerants/skeleton/Acceleration.c create mode 100644 src/add-ons/accelerants/skeleton/Cursor.c create mode 100644 src/add-ons/accelerants/skeleton/EngineManagement.c create mode 100644 src/add-ons/accelerants/skeleton/GetAccelerantHook.c create mode 100644 src/add-ons/accelerants/skeleton/GetDeviceInfo.c create mode 100644 src/add-ons/accelerants/skeleton/GetModeInfo.c create mode 100644 src/add-ons/accelerants/skeleton/GetTimingConstraints.c create mode 100644 src/add-ons/accelerants/skeleton/InitAccelerant.c create mode 100644 src/add-ons/accelerants/skeleton/Jamfile create mode 100644 src/add-ons/accelerants/skeleton/Overlay.c create mode 100644 src/add-ons/accelerants/skeleton/ProposeDisplayMode.c create mode 100644 src/add-ons/accelerants/skeleton/SetDisplayMode.c create mode 100644 src/add-ons/accelerants/skeleton/acc_std.h create mode 100644 src/add-ons/accelerants/skeleton/be_driver_proto.h create mode 100644 src/add-ons/accelerants/skeleton/engine/Jamfile create mode 100644 src/add-ons/accelerants/skeleton/engine/acc.c create mode 100644 src/add-ons/accelerants/skeleton/engine/agp.c create mode 100644 src/add-ons/accelerants/skeleton/engine/bes.c create mode 100644 src/add-ons/accelerants/skeleton/engine/crtc.c create mode 100644 src/add-ons/accelerants/skeleton/engine/crtc2.c create mode 100644 src/add-ons/accelerants/skeleton/engine/dac.c create mode 100644 src/add-ons/accelerants/skeleton/engine/dac2.c create mode 100644 src/add-ons/accelerants/skeleton/engine/general.c create mode 100644 src/add-ons/accelerants/skeleton/engine/globals.c create mode 100644 src/add-ons/accelerants/skeleton/engine/globals.h create mode 100644 src/add-ons/accelerants/skeleton/engine/i2c.c create mode 100644 src/add-ons/accelerants/skeleton/engine/info.c create mode 100644 src/add-ons/accelerants/skeleton/engine/proto.h create mode 100644 src/add-ons/accelerants/skeleton/engine/std.h create mode 100644 src/add-ons/accelerants/skeleton/engine/support.c create mode 100644 src/add-ons/accelerants/skeleton/engine/tvout.c create mode 100644 src/add-ons/accelerants/skeleton/valid_mode_list diff --git a/src/add-ons/accelerants/skeleton/Acceleration.c b/src/add-ons/accelerants/skeleton/Acceleration.c new file mode 100644 index 0000000000..c5c91390bf --- /dev/null +++ b/src/add-ons/accelerants/skeleton/Acceleration.c @@ -0,0 +1,140 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 9/2003. +*/ + +#define MODULE_BIT 0x40000000 + +#include "acc_std.h" + +void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) { + int i; + + /* init acc engine for blit function */ + nv_acc_setup_blit(); + + /* do each blit */ + i=0; + while (count--) + { + nv_acc_blit + ( + list[i].src_left, + list[i].src_top, + list[i].dest_left, + list[i].dest_top, + list[i].width, + list[i].height + ); + i++; + } +} + +void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { + int i; + + /* do each blit */ + i=0; + while (count--) + { + nv_acc_video_blit + ( + list[i].src_left, + list[i].src_top, + list[i].src_width, + list[i].src_height, + list[i].dest_left, + list[i].dest_top, + list[i].dest_width, + list[i].dest_height + ); + i++; + } +} + +void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) { + int i; + + /* do each blit */ + i=0; + while (count--) + { + nv_acc_transparent_blit + ( + list[i].src_left, + list[i].src_top, + list[i].dest_left, + list[i].dest_top, + list[i].width, + list[i].height, + transparent_colour + ); + i++; + } +} + +void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) { + int i; + + /* init acc engine for fill function */ + nv_acc_setup_rectangle(colorIndex); + + /* draw each rectangle */ + i=0; + while (count--) + { + nv_acc_rectangle + ( + list[i].left, + (list[i].right)+1, + list[i].top, + (list[i].bottom-list[i].top)+1 + ); + i++; + } +} + +void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) { + int i; + + /* init acc engine for invert function */ + nv_acc_setup_rect_invert(); + + /* invert each rectangle */ + i=0; + while (count--) + { + nv_acc_rectangle_invert + ( + list[i].left, + (list[i].right)+1, + list[i].top, + (list[i].bottom-list[i].top)+1 + ); + i++; + } +} + +void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) { + int i; + + /* init acc engine for fill function */ + nv_acc_setup_rectangle(colorIndex); + + /* draw each span */ + i=0; + while (count--) + { + nv_acc_rectangle + ( + list[i+1], + list[i+2]+1, + list[i], + 1 + ); + i+=3; + } +} diff --git a/src/add-ons/accelerants/skeleton/Cursor.c b/src/add-ons/accelerants/skeleton/Cursor.c new file mode 100644 index 0000000000..6ec7033655 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/Cursor.c @@ -0,0 +1,195 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Rudolf Cornelissen 4/2003-5/2004 +*/ + +#define MODULE_BIT 0x20000000 + +#include "acc_std.h" + +status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask) +{ + LOG(4,("SET_CURSOR_SHAPE: width %d, height %d, hot_x %d, hot_y %d\n", + width, height, hot_x, hot_y)); + + if ((width != 16) || (height != 16)) + { + return B_ERROR; + } + else if ((hot_x >= width) || (hot_y >= height)) + { + return B_ERROR; + } + else + { + head1_cursor_define(andMask,xorMask); + if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_OFF) + head2_cursor_define(andMask,xorMask); + + /* Update cursor variables appropriately. */ + si->cursor.width = width; + si->cursor.height = height; + si->cursor.hot_x = hot_x; + si->cursor.hot_y = hot_y; + } + + return B_OK; +} + +/* Move the cursor to the specified position on the desktop, taking account of virtual/dual issues */ +void MOVE_CURSOR(uint16 x, uint16 y) +{ + uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */ + uint16 vds = si->dm.v_display_start; /* the current vertical starting line */ + uint16 h_adjust; + + /* clamp cursor to display */ + if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1; + if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1; + + /* store, for our info */ + si->cursor.x = x; + si->cursor.y = y; + + /* setting up minimum amount to scroll not needed: + * Nvidia cards can always do pixelprecise panning on both heads */ + h_adjust = 0x00; + + /* adjust h/v_display_start to move cursor onto screen */ + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (x >= ((si->dm.timing.h_display * 2) + hds)) + { + hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust; + /* make sure we stay within the display! */ + if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width) + hds -= (h_adjust + 1); + } + else if (x < hds) + hds = x & ~h_adjust; + break; + default: + if (x >= (si->dm.timing.h_display + hds)) + { + hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust; + /* make sure we stay within the display! */ + if ((hds + si->dm.timing.h_display) > si->dm.virtual_width) + hds -= (h_adjust + 1); + } + else if (x < hds) + hds = x & ~h_adjust; + break; + } + + if (y >= (si->dm.timing.v_display + vds)) + vds = y - si->dm.timing.v_display + 1; + else if (y < vds) + vds = y; + + /* reposition the desktop _and_ the overlay on the display if required */ + if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start)) + { + MOVE_DISPLAY(hds,vds); + nv_bes_move_overlay(); + } + + /* put cursor in correct physical position, so stay onscreen (rel. to CRTC) */ + if (x > (hds + si->cursor.hot_x)) x -= (hds + si->cursor.hot_x); + else x = 0; + if (y > (vds + si->cursor.hot_y)) y -= (vds + si->cursor.hot_y); + else y = 0; + + /* position the cursor on the display */ + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_CLONE: + head1_cursor_position(x,y); + head2_cursor_position(x,y); + break; + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (x < si->dm.timing.h_display) + { + if (si->cursor.dh_right) + { + LOG(4,("MOVE_CURSOR: now on left side\n")); + head2_cursor_hide(); + head1_cursor_show(); + si->cursor.dh_right = false; + } + head1_cursor_position(x, y); + } + else + { + if (!si->cursor.dh_right) + { + LOG(4,("MOVE_CURSOR: now on right side\n")); + head1_cursor_hide(); + head2_cursor_show(); + si->cursor.dh_right = true; + } + head2_cursor_position((x - si->dm.timing.h_display), y); + } + break; + default: /* singlehead mode */ + head1_cursor_position(x,y); + break; + } +} + +void SHOW_CURSOR(bool is_visible) +{ + /* record for our info */ + si->cursor.is_visible = is_visible; + + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_CLONE: + if (is_visible) + { + head1_cursor_show(); + head2_cursor_show(); + } + else + { + head1_cursor_hide(); + head2_cursor_hide(); + } + break; + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (is_visible) + { + if (!si->cursor.dh_right) + { + head1_cursor_show(); + } + else + { + head2_cursor_show(); + } + } + else + { + head1_cursor_hide(); + head2_cursor_hide(); + } + break; + default: /* singlehead mode */ + if (is_visible) + { + head1_cursor_show(); + } + else + { + head1_cursor_hide(); + } + break; + } +} diff --git a/src/add-ons/accelerants/skeleton/EngineManagement.c b/src/add-ons/accelerants/skeleton/EngineManagement.c new file mode 100644 index 0000000000..b31eb5dfb9 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/EngineManagement.c @@ -0,0 +1,70 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + other authors: + Mark Watson + Rudolf Cornelissen 3/2004 +*/ + +#define MODULE_BIT 0x10000000 + +#include "acc_std.h" + + +static engine_token nv_engine_token = { 1, B_2D_ACCELERATION, NULL }; + +uint32 ACCELERANT_ENGINE_COUNT(void) +{ + /* we have one acceleration engine */ + return 1; +} + +status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et) +{ + /* acquire the shared benaphore */ + AQUIRE_BEN(si->engine.lock) + /* sync if required */ + if (st) SYNC_TO_TOKEN(st); + + /* return an engine token */ + *et = &nv_engine_token; + return B_OK; +} + +status_t RELEASE_ENGINE(engine_token *et, sync_token *st) +{ + /* update the sync token, if any */ + if (st) GET_SYNC_TOKEN(et,st); + + /* release the shared benaphore */ + RELEASE_BEN(si->engine.lock) + return B_OK; +} + +void WAIT_ENGINE_IDLE(void) +{ + /*wait for the engine to be totally idle*/ + nv_acc_wait_idle(); +} + +status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) +{ + /* engine count will always be zero: we don't support syncing to token (yet) */ + st->engine_id = et->engine_id; + st->counter = si->engine.count; + return B_OK; +} + +status_t SYNC_TO_TOKEN(sync_token *st) +{ + /* wait until the engine is totally idle: we don't support syncing to token (yet) */ + /* note: + * AFAIK in order to be able to setup sync_to_token, we'd need a circular fifo + * buffer in (main) memory instead of directly programming the GPU fifo so we + * can tell (via a hardware maintained pointer into this circular fifo) where + * the acc engine is with executing commands! */ + WAIT_ENGINE_IDLE(); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/GetAccelerantHook.c b/src/add-ons/accelerants/skeleton/GetAccelerantHook.c new file mode 100644 index 0000000000..f26aeb93a6 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/GetAccelerantHook.c @@ -0,0 +1,221 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Rudolf Cornelissen 10/2002-4/2004 +*/ + +#define MODULE_BIT 0x08000000 + +#include "acc_std.h" + +/* +The standard entry point. Given a uint32 feature identifier, this routine +returns a pointer to the function that implements the feature. Some features +require more information than just the identifier to select the proper +function. The extra information (which is specific to the feature) is +pointed at by the void *data parameter. By default, no extra information +is available. Any extra information available to choose the function will be +noted on a case by case below. +*/ + +/* +These definitions are out of pure lazyness. +*/ +#define CHKO(x) case B_##x: \ + if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 +#define CHKA(x) case B_##x: \ + if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 +#define HOOK(x) case B_##x: return (void *)x +#define ZERO(x) case B_##x: return (void *)0 +#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed + +void * get_accelerant_hook(uint32 feature, void *data) +{ + switch (feature) + { + /* + One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and + subsequently called before any other hook is requested. All other feature + hook selections can be predicated on variables assigned during the accelerant + initialization process. + */ + + /* initialization */ + HOOK(INIT_ACCELERANT); + HOOK(CLONE_ACCELERANT); + + HOOK(ACCELERANT_CLONE_INFO_SIZE); + HOOK(GET_ACCELERANT_CLONE_INFO); + HOOK(UNINIT_ACCELERANT); + HOOK(GET_ACCELERANT_DEVICE_INFO); + HOOK(ACCELERANT_RETRACE_SEMAPHORE); + + /* mode configuration */ + HOOK(ACCELERANT_MODE_COUNT); + HOOK(GET_MODE_LIST); + HOOK(PROPOSE_DISPLAY_MODE); + HOOK(SET_DISPLAY_MODE); + HOOK(GET_DISPLAY_MODE); + HOOK(GET_FRAME_BUFFER_CONFIG); + HOOK(GET_PIXEL_CLOCK_LIMITS); + HOOK(MOVE_DISPLAY); + HOOK(SET_INDEXED_COLORS); + HOOK(GET_TIMING_CONSTRAINTS); + + HOOK(DPMS_CAPABILITIES); + HOOK(DPMS_MODE); + HOOK(SET_DPMS_MODE); + + /* cursor managment */ + HRDC(SET_CURSOR_SHAPE); + HRDC(MOVE_CURSOR); + HRDC(SHOW_CURSOR); + + /* synchronization */ + HOOK(ACCELERANT_ENGINE_COUNT); + HOOK(ACQUIRE_ENGINE); + HOOK(RELEASE_ENGINE); + HOOK(WAIT_ENGINE_IDLE); + HOOK(GET_SYNC_TOKEN); + HOOK(SYNC_TO_TOKEN); + + /* + Depending on the engine architecture, you may choose to provide a different + function to be used with each bit-depth for example. + + Note: These hooks are re-acquired by the app_server after each mode switch. + */ + + /* only export video overlay functions if card is capable of it */ + CHKO(OVERLAY_COUNT); + CHKO(OVERLAY_SUPPORTED_SPACES); + CHKO(OVERLAY_SUPPORTED_FEATURES); + CHKO(ALLOCATE_OVERLAY_BUFFER); + CHKO(RELEASE_OVERLAY_BUFFER); + CHKO(GET_OVERLAY_CONSTRAINTS); + CHKO(ALLOCATE_OVERLAY); + CHKO(RELEASE_OVERLAY); + CHKO(CONFIGURE_OVERLAY); + + /* + When requesting an acceleration hook, the calling application provides a + pointer to the display_mode for which the acceleration function will be used. + Depending on the engine architecture, you may choose to provide a different + function to be used with each bit-depth. In the sample driver we return + the same function all the time. + + Note: These hooks are re-acquired by the app_server after each mode switch. + */ + + /* only export 2D acceleration functions in modes that are capable of it */ + /* used by the app_server and applications (BWindowScreen) */ + CHKA(SCREEN_TO_SCREEN_BLIT); + CHKA(FILL_RECTANGLE); + CHKA(INVERT_RECTANGLE); + CHKA(FILL_SPAN); + /* not (yet) used by the app_server: + * so just for application use (BWindowScreen) */ +// CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT); +// CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT; + } + + /* Return a null pointer for any feature we don't understand. */ + return 0; +} +#undef CHKO +#undef CHKA +#undef HOOK +#undef ZERO +#undef HRDC + +status_t check_overlay_capability(uint32 feature) +{ + char *msg = ""; + + /* setup logmessage text */ + switch (feature) + { + case B_OVERLAY_COUNT: + msg = "B_OVERLAY_COUNT"; + break; + case B_OVERLAY_SUPPORTED_SPACES: + msg = "B_OVERLAY_SUPPORTED_SPACES"; + break; + case B_OVERLAY_SUPPORTED_FEATURES: + msg = "B_OVERLAY_SUPPORTED_FEATURES"; + break; + case B_ALLOCATE_OVERLAY_BUFFER: + msg = "B_ALLOCATE_OVERLAY_BUFFER"; + break; + case B_RELEASE_OVERLAY_BUFFER: + msg = "B_RELEASE_OVERLAY_BUFFER"; + break; + case B_GET_OVERLAY_CONSTRAINTS: + msg = "B_GET_OVERLAY_CONSTRAINTS"; + break; + case B_ALLOCATE_OVERLAY: + msg = "B_ALLOCATE_OVERLAY"; + break; + case B_RELEASE_OVERLAY: + msg = "B_RELEASE_OVERLAY"; + break; + case B_CONFIGURE_OVERLAY: + msg = "B_CONFIGURE_OVERLAY"; + break; + default: + msg = "UNKNOWN"; + break; + } + + /* all supported cards have a bes */ + LOG(4, ("Overlay: Exporting hook %s.\n", msg)); + + return B_OK; +} + +status_t check_acc_capability(uint32 feature) +{ + char *msg = ""; + + /* setup logmessage text */ + switch (feature) + { + case B_SCREEN_TO_SCREEN_BLIT: + msg = "B_SCREEN_TO_SCREEN_BLIT"; + break; + case B_FILL_RECTANGLE: + msg = "B_FILL_RECTANGLE"; + break; + case B_INVERT_RECTANGLE: + msg = "B_INVERT_RECTANGLE"; + break; + case B_FILL_SPAN: + msg = "B_FILL_SPAN"; + break; + case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT: + msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT"; + break; + case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT: + msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT"; + break; + default: + msg = "UNKNOWN"; + break; + } + + /* hardware acceleration is only supported in modes with upto a certain + * memory pitch.. */ + if (si->acc_mode) + { + LOG(4, ("Acc: Exporting hook %s.\n", msg)); + return B_OK; + } + else + { + LOG(4, ("Acc: Not exporting hook %s.\n", msg)); + return B_ERROR; + } +} diff --git a/src/add-ons/accelerants/skeleton/GetDeviceInfo.c b/src/add-ons/accelerants/skeleton/GetDeviceInfo.c new file mode 100644 index 0000000000..bc18184fbc --- /dev/null +++ b/src/add-ons/accelerants/skeleton/GetDeviceInfo.c @@ -0,0 +1,99 @@ +/* + Author: + Rudolf Cornelissen 7/2004-11/2004 +*/ + +#define MODULE_BIT 0x04000000 + +#include "acc_std.h" + +/* Get some info about the device */ +status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi) +{ + LOG(4,("GET_ACCELERANT_DEVICE_INFO: returning info\n")); + + /* no info on version is provided, so presumably this is for my info */ + adi->version = 1; + + sprintf(adi->name, "nVidia chipset"); + switch (si->ps.card_type) + { + case NV04: + sprintf(adi->chipset, "NV04"); + break; + case NV05: + sprintf(adi->chipset, "NV05"); + break; + case NV05M64: + sprintf(adi->chipset, "NV05 model 64"); + break; + case NV06: + sprintf(adi->chipset, "NV06"); + break; + case NV10: + sprintf(adi->chipset, "NV10"); + break; + case NV11: + case NV11M: + sprintf(adi->chipset, "NV11"); + break; + case NV15: + sprintf(adi->chipset, "NV15"); + break; + case NV17: + case NV17M: + sprintf(adi->chipset, "NV17"); + break; + case NV18: + case NV18M: + sprintf(adi->chipset, "NV18"); + break; + case NV20: + sprintf(adi->chipset, "NV20"); + break; + case NV25: + sprintf(adi->chipset, "NV25"); + break; + case NV28: + sprintf(adi->chipset, "NV28"); + break; + case NV30: + sprintf(adi->chipset, "NV30"); + break; + case NV31: + sprintf(adi->chipset, "NV31"); + break; + case NV34: + sprintf(adi->chipset, "NV34"); + break; + case NV35: + sprintf(adi->chipset, "NV35"); + break; + case NV36: + sprintf(adi->chipset, "NV36"); + break; + case NV38: + sprintf(adi->chipset, "NV38"); + break; + case NV40: + sprintf(adi->chipset, "NV40"); + break; + case NV41: + sprintf(adi->chipset, "NV41"); + break; + case NV43: + sprintf(adi->chipset, "NV43"); + break; + case NV45: + sprintf(adi->chipset, "NV45"); + break; + default: + sprintf(adi->chipset, "unknown"); + break; + } + sprintf(adi->serial_no, "unknown"); + adi->memory = si->ps.memory_size; + adi->dac_speed = si->ps.max_dac1_clock; + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/GetModeInfo.c b/src/add-ons/accelerants/skeleton/GetModeInfo.c new file mode 100644 index 0000000000..ea1dd2561a --- /dev/null +++ b/src/add-ons/accelerants/skeleton/GetModeInfo.c @@ -0,0 +1,160 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson + Rudolf Cornelissen 9/2002-5/2003 +*/ + +#define MODULE_BIT 0x02000000 + +#include "acc_std.h" + +/* + Return the current display mode. The only time you might return an + error is if a mode hasn't been set. Or if the system hands you a NULL pointer. +*/ +status_t GET_DISPLAY_MODE(display_mode *current_mode) +{ + /* check for NULL pointer */ + if (current_mode == NULL) return B_ERROR; + + *current_mode = si->dm; + return B_OK; +} + +/* Return the frame buffer configuration information. */ +status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) +{ + /* check for NULL pointer */ + if (afb == NULL) return B_ERROR; + + *afb = si->fbc; + return B_OK; +} + +/* Return the maximum and minium pixelclock limits for the specified mode. */ +/* NOTE: + * Due to BeOS constraints output for all heads will be limited to the head with + * the least capabilities. */ +status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) +{ + uint32 max_pclk = 0; + uint32 min_pclk = 0; + + /* check for NULL pointers */ + if ((dm == NULL) || (low == NULL) || (high == NULL)) return B_ERROR; + + /* specify requested info */ + if (dm->flags & DUALHEAD_BITS) + { + /* dualhead mode */ + /* find min. value */ + switch (si->ps.card_type) + { + default: + *low = ((si->ps.min_video_vco * 1000) / 16); + break; + } + /* find max. value: + * using decondary DAC specs because they could be narrower (twinview) */ + switch (dm->space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac2_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac2_clock_24; + break; + case B_RGB32_LITTLE: + /* specially noted because of RAM speed constraints! */ + max_pclk = si->ps.max_dac2_clock_32dh; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32dh; + break; + } + /* return values in kHz */ + *high = max_pclk * 1000; + } + else + { + /* singlehead mode */ + /* find min. value */ + switch (si->ps.card_type) + { + default: + *low = ((si->ps.min_pixel_vco * 1000) / 16); + break; + } + /* find max. value: depends on which head is used as primary head */ + if (!si->ps.crtc2_prim) + { + switch (dm->space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac1_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac1_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac1_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac1_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_32; + break; + } + } + else + { + switch (dm->space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac2_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac2_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac2_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32; + break; + } + } + /* return values in kHz */ + *high = max_pclk * 1000; + } + + /* clamp lower limit to 48Hz vertical refresh for now. + * Apparantly the BeOS screenprefs app does limit the upper refreshrate to 90Hz, + * while it does not limit the lower refreshrate. */ + min_pclk = ((uint32)dm->timing.h_total * (uint32)dm->timing.v_total * 48) / 1000; + if (min_pclk > *low) *low = min_pclk; + + return B_OK; +} + +/* Return the semaphore id that will be used to signal a vertical sync occured. */ +sem_id ACCELERANT_RETRACE_SEMAPHORE(void) +{ + return si->vblank; +} diff --git a/src/add-ons/accelerants/skeleton/GetTimingConstraints.c b/src/add-ons/accelerants/skeleton/GetTimingConstraints.c new file mode 100644 index 0000000000..2b00bbbf87 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/GetTimingConstraints.c @@ -0,0 +1,33 @@ +/* + Author: + Rudolf Cornelissen 7/2004 +*/ + +#define MODULE_BIT 0x01000000 + +#include "acc_std.h" + +/* Used to help generate mode lines */ +status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc) +{ + LOG(4, ("GET_TIMING_CONSTRAINTS: returning info\n")); + + /* specs are identical for all nVidia cards */ + dtc->h_res = 8; + dtc->h_sync_min = 8; + dtc->h_sync_max = 248; + /* Note: + * h_blank info is used to determine the max. diff. between h_total and h_display! */ + dtc->h_blank_min = 8; + dtc->h_blank_max = 1016; + + dtc->v_res = 1; + dtc->v_sync_min = 1; + dtc->v_sync_max = 15; + /* Note: + * v_blank info is used to determine the max. diff. between v_total and v_display! */ + dtc->v_blank_min = 1; + dtc->v_blank_max = 255; + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/InitAccelerant.c b/src/add-ons/accelerants/skeleton/InitAccelerant.c new file mode 100644 index 0000000000..059c64b749 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/InitAccelerant.c @@ -0,0 +1,324 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Rudolf Cornelissen 10/2002-7/2004. +*/ + +#define MODULE_BIT 0x00800000 + +#include +#include +#include "acc_std.h" + +static status_t init_common(int the_fd); + +/* Initialization code shared between primary and cloned accelerants */ +static status_t init_common(int the_fd) { + status_t result; + nv_get_private_data gpd; + + // LOG not available from here to next LOG: NULL si + + /* memorize the file descriptor */ + fd = the_fd; + /* set the magic number so the driver knows we're for real */ + gpd.magic = NV_PRIVATE_DATA_MAGIC; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, NV_GET_PRIVATE_DATA, &gpd, sizeof(gpd)); + if (result != B_OK) goto error0; + + /* clone the shared area for our use */ + shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area); + if (shared_info_area < 0) { + result = shared_info_area; + goto error0; + } + // LOG is now available, si !NULL + LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, switchhead %d, force_pci %d\n", + si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead, si->settings.force_pci)); + LOG(4,("init_common: dumprom %d, unhide_fw %d, pgm_panel %d\n", + si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel)); + + /*Check for R4.5.0 and if it is running, use work around*/ + { + if (si->use_clone_bugfix) + { + /*check for R4.5.0 bug and attempt to work around*/ + LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n")); + regs = si->clone_bugfix_regs; + } + else + { + /* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/ + regs_area = clone_area(DRIVER_PREFIX " regs", (void **)®s, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, si->regs_area); + if (regs_area < 0) { + result = regs_area; + goto error1; + } + } + } + + /*FIXME - print dma addresses*/ + //LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area)); + + /* all done */ + goto error0; + +error1: + delete_area(shared_info_area); +error0: + return result; +} + +/* Clean up code shared between primary and cloned accelrants */ +static void uninit_common(void) { + /* release the memory mapped registers */ + delete_area(regs_area); + /* a little cheap paranoia */ + regs = 0; + /* release our copy of the shared info from the kernel driver */ + delete_area(shared_info_area); + /* more cheap paranoia */ + si = 0; +} + +/* +Initialize the accelerant. the_fd is the file handle of the device (in +/dev/graphics) that has been opened by the app_server (or some test harness). +We need to determine if the kernel driver and the accelerant are compatible. +If they are, get the accelerant ready to handle other hook functions and +report success or failure. +*/ +status_t INIT_ACCELERANT(int the_fd) { + status_t result; + int pointer_reservation; //mem reserved for pointer + int cnt; //used for iteration through the overlay buffers + + if (0) { + time_t now = time (NULL); + // LOG not available from here to next LOG: NULL si + MSG(("INIT_ACCELERANT: %s", ctime (&now))); + } + + /* note that we're the primary accelerant (accelerantIsClone is global) */ + accelerantIsClone = 0; + + /* do the initialization common to both the primary and the clones */ + result = init_common(the_fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error0; + // LOG now available: !NULL si + + /* call the device specific init code */ + result = nv_general_powerup(); + + /* bail out if it failed */ + if (result != B_OK) goto error1; + + /* + Now would be a good time to figure out what video modes your card supports. + We'll place the list of modes in another shared area so all of the copies + of the driver can see them. The primary copy of the accelerant (ie the one + initialized with this routine) will own the "one true copy" of the list. + Everybody else get's a read-only clone. + */ + result = create_mode_list(); + if (result != B_OK) + { + goto error1; + } + + /* + Put the cursor at the start of the frame buffer. + Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM. + */ + /* Initialize the rest of the cursor information while we're here */ + si->cursor.width = 16; + si->cursor.height = 16; + si->cursor.hot_x = 0; + si->cursor.hot_y = 0; + si->cursor.x = 0; + si->cursor.y = 0; + si->cursor.dh_right = false; + + /* + Put the frame buffer immediately following the cursor data. We store this + info in a frame_buffer_config structure to make it convienient to return + to the app_server later. + */ + pointer_reservation = 0; + /* Nvidia hardcursor needs 2kB space */ + if (si->settings.hardcursor) pointer_reservation = 2048; + + si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation); + si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation); + + /* count of issued parameters or commands */ + si->engine.last_idle = si->engine.count = 0; + INIT_BEN(si->engine.lock); + + INIT_BEN(si->overlay.lock); + for (cnt = 0; cnt < MAXBUFFERS; cnt++) + { + /* make sure overlay buffers are 'marked' as being free */ + si->overlay.myBuffer[cnt].buffer = NULL; + si->overlay.myBuffer[cnt].buffer_dma = NULL; + } + /* make sure overlay unit is 'marked' as being free */ + si->overlay.myToken = NULL; + + /* note that overlay is not in use (for nv_bes_move_overlay()) */ + si->overlay.active = false; + + /* bail out if something failed */ + if (result != B_OK) goto error1; + + /* initialise various cursor stuff */ + head1_cursor_init(); + if (si->ps.secondary_head) head2_cursor_init(); + + /* ensure cursor state */ + head1_cursor_hide(); + if (si->ps.secondary_head) head2_cursor_hide(); + + /* a winner! */ + result = B_OK; + goto error0; + +error1: + /* + Initialization failed after init_common() succeeded, so we need to clean + up before quiting. + */ + uninit_common(); + +error0: + return result; +} + +/* +Return the number of bytes required to hold the information required +to clone the device. +*/ +ssize_t ACCELERANT_CLONE_INFO_SIZE(void) { + /* + Since we're passing the name of the device as the only required + info, return the size of the name buffer + */ + return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH; +} + + +/* +Return the info required to clone the device. void *data points to +a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length. +*/ +void GET_ACCELERANT_CLONE_INFO(void *data) { + nv_device_name dn; + status_t result; + + /* call the kernel driver to get the device name */ + dn.magic = NV_PRIVATE_DATA_MAGIC; + /* store the returned info directly into the passed buffer */ + dn.name = (char *)data; + result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn)); +} + +/* +Initialize a copy of the accelerant as a clone. void *data points to +a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). +*/ +status_t CLONE_ACCELERANT(void *data) { + status_t result; + char path[MAXPATHLEN]; + + /* the data is the device name */ + /* Note: the R4 graphics driver kit is in error here (missing trailing '/') */ + strcpy(path, "/dev/"); + strcat(path, (const char *)data); + /* open the device, the permissions aren't important */ + fd = open(path, B_READ_WRITE); + if (fd < 0) + { + /* we can't use LOG because we didn't get the shared_info struct.. */ + char fname[64]; + FILE *myhand = NULL; + + sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log"); + myhand=fopen(fname,"a+"); + fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path); + fclose(myhand); + + /* abort with resultcode from open attempt on kerneldriver */ + result = fd; + goto error0; + } + + /* note that we're a clone accelerant */ + accelerantIsClone = 1; + + /* call the shared initialization code */ + result = init_common(fd); + + /* setup CRTC and DAC functions access */ + setup_virtualized_heads(si->crtc_switch_mode); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error1; + + /* get shared area for display modes */ + result = my_mode_list_area = clone_area( + DRIVER_PREFIX " cloned display_modes", + (void **)&my_mode_list, + B_ANY_ADDRESS, + B_READ_AREA, + si->mode_area + ); + if (result < B_OK) goto error2; + + /* all done */ + LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n")); + + result = B_OK; + goto error0; + +error2: + /* free up the areas we cloned */ + uninit_common(); +error1: + /* close the device we opened */ + close(fd); +error0: + return result; +} + +void UNINIT_ACCELERANT(void) +{ + if (accelerantIsClone) + { + LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n")); + } + else + { + LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n")); + + /* delete benaphores ONLY if we are the primary accelerant */ + DELETE_BEN(si->engine.lock); + DELETE_BEN(si->overlay.lock); + } + + /* free our mode list area */ + delete_area(my_mode_list_area); + /* paranoia */ + my_mode_list = 0; + /* release our cloned data */ + uninit_common(); + /* close the file handle ONLY if we're the clone */ + if (accelerantIsClone) close(fd); +} diff --git a/src/add-ons/accelerants/skeleton/Jamfile b/src/add-ons/accelerants/skeleton/Jamfile new file mode 100644 index 0000000000..56f25f0184 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/Jamfile @@ -0,0 +1,29 @@ +SubDir OBOS_TOP src add-ons accelerants skeleton ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics skeleton ] ; +UseHeaders [ FDirName $(SUBDIR) engine ] ; + + +Addon skel.accelerant : accelerants : + Acceleration.c + Cursor.c + EngineManagment.c + GetAccelerantHook.c + GetDeviceInfo.c + GetModeInfo.c + GetTimingConstraints.c + InitAccelerant.c + Overlay.c + ProposeDisplayMode.c + SetDisplayMode.c + : false : libnvidia_engine.a +; + +Package haiku-skeleton-cvs : + skel.accelerant : + boot home config add-ons accelerants ; + +Depends skel.accelerant : skel.driver ; + +SubInclude OBOS_TOP src add-ons accelerants skeleton engine ; diff --git a/src/add-ons/accelerants/skeleton/Overlay.c b/src/add-ons/accelerants/skeleton/Overlay.c new file mode 100644 index 0000000000..c1f37af207 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/Overlay.c @@ -0,0 +1,612 @@ +/* Written by Rudolf Cornelissen 05/2002-9/2004 */ + +/* Note on 'missing features' in BeOS 5.0.3 and DANO: + * BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions' + * of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?) + */ + +#define MODULE_BIT 0x00000400 + +#include "acc_std.h" + +/* define the supported overlay input colorspaces */ +/* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace + * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */ +static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE }; + +uint32 OVERLAY_COUNT(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: count called\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + } + /* apparantly overlay count should report the number of 'overlay units' on the card */ + return 1; +} + +const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: supported_spaces called.\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + return NULL; + } + + /* assuming interlaced VGA is not supported */ + if (dm->timing.flags && B_TIMING_INTERLACED) + { + return NULL; + } + /* return a B_NO_COLOR_SPACE terminated list */ + return &overlay_colorspaces[0]; +} + +uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space) +// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported! +{ + LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space)); + + /* check what features are supported for the current overlaybitmap colorspace */ + switch (a_color_space) + { + default: + return + ( B_OVERLAY_KEYING_USES_ALPHA | + B_OVERLAY_COLOR_KEY | + B_OVERLAY_HORIZONTAL_FILTERING | + B_OVERLAY_VERTICAL_FILTERING ); + } +} + +const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height) +{ + int offset = 0; /* used to determine next buffer to create */ + uint32 adress, adress2, temp32; /* used to calculate buffer adresses */ + uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */ + int cnt; /* loopcounter */ + + /* acquire the shared benaphore */ + AQUIRE_BEN(si->overlay.lock) + + LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer))); + LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci))); + LOG(4,("Overlay: cardRAM_size = %3.3fMb\n",(si->ps.memory_size / (1024.0 * 1024.0)))); + + /* find first empty slot (room for another buffer?) */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == NULL) break; + } + + LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset)); + + if (offset < MAXBUFFERS) + /* setup new scaler input buffer */ + { + switch (cs) + { + case B_YCbCr422: + if (si->ps.card_arch < NV10A) + { + /* check if slopspace is needed: RIVA128 and TNT need ~0x000f. */ + si->overlay.myBuffer[offset].width = ((width + 0x000f) & ~0x000f); + } + else + { + /* check if slopspace is needed: GeForce need ~0x001f. */ + /* fixme: + * update needed for GF DVDmax support to adhere to CRTC2 constraints?? */ + si->overlay.myBuffer[offset].width = ((width + 0x001f) & ~0x001f); + } + si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width; + + /* check if the requested horizontal pitch is supported: */ + //fixme: tune for GF and TNT... + if (si->overlay.myBuffer[offset].width > 4088) + { + LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + break; + default: + /* unsupported colorspace! */ + LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs)); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + break; + } + + /* check if the requested buffer width is supported */ + if (si->overlay.myBuffer[offset].width > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + /* check if the requested buffer height is supported */ + if (height > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + + /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */ + si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width; + + si->overlay.myBuffer[offset].space = cs; + si->overlay.myBuffer[offset].height = height; + + /* we define the overlay buffers to reside 'in the back' of the cards RAM */ + /* NOTE to app programmers: + * Beware that an app using overlay needs to track workspace switches and screenprefs + * changes. If such an action is detected, the app needs to reset it's pointers to the + * newly created overlay bitmaps, which will be assigned by BeOS automatically after such + * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!) + * + * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them + * than previously setup by the app might be re-setup. This is due to cardRAM restraints then. + * This means that the app should also check for NULL pointers returned by the bitmaps, + * and if this happens, it needs to fallback to single buffered overlay or even fallback to + * bitmap output for the new situation. */ + + /* Another NOTE for app programmers: + * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the + * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately. + * This *greatly* simplifies tracking such errors! + * Of course such errors may lead to strange effects in the app or driver behaviour if they are + * not hunted down and removed.. */ + + /* calculate first free RAM adress in card: + * Driver setup is as follows: + * card base: - hardware cursor bitmap (if used), + * directly above - screen memory for both heads */ + adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */ + (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */ + LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2)); + + /* calculate 'preliminary' buffer size including slopspace */ + oldsize = si->overlay.myBufInfo[offset].size; + si->overlay.myBufInfo[offset].size = + si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height; + + /* calculate virtual memory adress that would be needed for a new bitmap */ + /* NOTE to app programmers: + * For testing app behaviour regarding workspace switches or screen prefs changes to settings + * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with + * a low amount of RAM. Or you can set in the file nv.settings for example: + * memory 8 #8Mb RAM on card + * and reboot (this simulates 8Mb RAM on the card). + * + * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to + * bitmap output or maybe single buffered overlay output if small bitmaps are used. */ + + adress = (((uint32)((uint8*)si->framebuffer)) + si->ps.memory_size); + for (cnt = 0; cnt <= offset; cnt++) + { + adress -= si->overlay.myBufInfo[cnt].size; + } + + /* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with + * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */ + + /* Check if we need to modify the buffers starting adress and thus the size */ + /* calculate 'would be' cardRAM offset */ + temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer))); + /* check if it is aligned */ + if (temp32 != (temp32 & 0xfffffff0)) + { + /* update the (already calculated) buffersize to get it aligned */ + si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0)); + /* update the (already calculated) adress to get it aligned */ + adress -= (temp32 - (temp32 & 0xfffffff0)); + } + LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress)); + + /* First check now if buffer to be defined is 'last one' in memory (speaking backwards): + * this is done to prevent a large buffer getting created in the space a small buffer + * occupied earlier, if not all buffers created were deleted. + * Note also that the app can delete the buffers in any order desired. */ + + /* NOTE to app programmers: + * If you are going to delete a overlay buffer you created, you should delete them *all* and + * then re-create only the new ones needed. This way you are sure not to get unused memory- + * space in between your overlay buffers for instance, so cardRAM is used 'to the max'. + * If you don't, you might not get a buffer at all if you are trying to set up a larger one + * than before. + * (Indeed: not all buffers *have* to be of the same type and size...) */ + + for (cnt = offset; cnt < MAXBUFFERS; cnt++) + { + if (si->overlay.myBuffer[cnt].buffer != NULL) + { + /* Check if the new buffer would fit into the space the single old one used here */ + if (si->overlay.myBufInfo[offset].size <= oldsize) + { + /* It does, so we reset to the old size and adresses to prevent the space from shrinking + * if we get here again... */ + adress -= (oldsize - si->overlay.myBufInfo[offset].size); + si->overlay.myBufInfo[offset].size = oldsize; + LOG(4,("Overlay: 'squeezing' in buffer:\n" + "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize)); + /* force exiting the FOR loop */ + cnt = MAXBUFFERS; + } + else + { + /* nogo, sorry */ + LOG(4,("Overlay: Other buffer(s) exist after this one:\n" + "Overlay: not enough space to 'squeeze' this one in, aborted\n")); + + /* Reset to the old size to prevent the space from 'growing' if we get here again... */ + si->overlay.myBufInfo[offset].size = oldsize; + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + } + } + + /* check if we have enough space to setup this new bitmap + * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */ + if (adress < adress2) + /* nope, sorry */ + { + LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + /* continue buffer setup */ + si->overlay.myBuffer[offset].buffer = (void *) adress; + + /* calculate physical memory adress (for dma use) */ + adress = (((uint32)((uint8*)si->framebuffer_pci)) + si->ps.memory_size); + for (cnt = 0; cnt <= offset; cnt++) + { + adress -= si->overlay.myBufInfo[cnt].size; + } + /* this adress is already aligned to the scaler's requirements (via the already modified sizes) */ + si->overlay.myBuffer[offset].buffer_dma = (void *) adress; + + LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n", + (uint32)((uint8*)si->overlay.myBuffer[offset].buffer), + (uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs)); + LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size)); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return &si->overlay.myBuffer[offset]; + } + else + /* sorry, no more room for buffers */ + { + LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } +} + +status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob) +/* Note that the user can delete the buffers in any order desired! */ +{ + int offset = 0; + + if (ob != NULL) + { + /* find the buffer */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + /* delete current buffer */ + { + si->overlay.myBuffer[offset].buffer = NULL; + si->overlay.myBuffer[offset].buffer_dma = NULL; + + LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset)); + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n")); + + return B_ERROR; + } + } + else + /* no buffer specified! */ + { + LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n")); + + return B_ERROR; + } +} + +status_t GET_OVERLAY_CONSTRAINTS + (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc) +{ + int offset = 0; + + LOG(4,("Overlay: Get_overlay_constraints called\n")); + + /* check for NULL pointers */ + if ((dm == NULL) || (ob == NULL) || (oc == NULL)) + { + LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n")); + return B_ERROR; + } + + /* find the buffer */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + { + /* scaler input (values are in pixels) */ + oc->view.h_alignment = 0; + oc->view.v_alignment = 0; + + switch (ob->space) + { + case B_YCbCr422: + if (si->ps.card_arch < NV10A) + { + /* RIVA128 and TNT need 15. + * Note: this has to be in sync with the slopspace setup during buffer allocation.. */ + oc->view.width_alignment = 15; + } + else + { + /* GeForce need 31. + * Note: this has to be in sync with the slopspace setup during buffer allocation.. */ + oc->view.width_alignment = 31; + } + break; + default: + /* we should not be here, but set the worst-case value just to be safe anyway */ + oc->view.width_alignment = 31; + break; + } + + oc->view.height_alignment = 0; + oc->view.width.min = 1; + oc->view.height.min = 2; /* two fields */ + oc->view.width.max = ob->width; + oc->view.height.max = ob->height; + + /* scaler output restrictions */ + oc->window.h_alignment = 0; + oc->window.v_alignment = 0; + oc->window.width_alignment = 0; + oc->window.height_alignment = 0; + oc->window.width.min = 2; + /* GeForce cards can output upto and including 2046 pixels in width */ + //fixme: how about TNT? + if (dm->virtual_width > 2046) + { + oc->window.width.max = 2046; + } + else + { + oc->window.width.max = dm->virtual_width; + } + oc->window.height.min = 2; + /* GeForce cards can output upto and including 2046 pixels in height */ + //fixme: how about TNT? + if (dm->virtual_height > 2046) + { + oc->window.height.max = 2046; + } + else + { + oc->window.height.max = dm->virtual_height; + } + + /* GeForce scaling restrictions */ + switch (si->ps.card_arch) + { + case NV04A: + /* Riva128-TNT2 series have an old BES engine... */ + oc->h_scale.min = 1.0; + oc->v_scale.min = 1.0; + break; + case NV30A: + case NV40A: + /* GeForceFX series and up have a new BES engine... */ + oc->h_scale.min = 0.5; + oc->v_scale.min = 0.5; + /* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + default: + /* the rest in between... */ + oc->h_scale.min = 0.125; + oc->v_scale.min = 0.125; + break; + } + /* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */ + oc->h_scale.max = 8.0; + oc->v_scale.max = 8.0; + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n")); + + return B_ERROR; + } +} + +overlay_token ALLOCATE_OVERLAY(void) +{ + uint32 tmpToken; + LOG(4,("Overlay: Allocate_overlay called: ")); + + /* come up with a token */ + tmpToken = 0x12345678; + + /* acquire the shared benaphore */ + AQUIRE_BEN(si->overlay.lock) + + /* overlay unit already in use? */ + if (si->overlay.myToken == NULL) + /* overlay unit is available */ + { + LOG(4,("succesfull\n")); + + si->overlay.myToken = &tmpToken; + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return si->overlay.myToken; + } + else + /* sorry, overlay unit is occupied */ + { + LOG(4,("failed: already in use!\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } +} + +status_t RELEASE_OVERLAY(overlay_token ot) +{ + LOG(4,("Overlay: Release_overlay called: ")); + + /* is this call for real? */ + if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) + /* nope, abort */ + { + LOG(4,("failed, not in use!\n")); + + return B_ERROR; + } + else + /* call is for real */ + { + + nv_release_bes(); + + LOG(4,("succesfull\n")); + + si->overlay.myToken = NULL; + return B_OK; + } +} + +status_t CONFIGURE_OVERLAY + (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov) +{ + int offset = 0; /* used for buffer index */ + + LOG(4,("Overlay: Configure_overlay called: ")); + + /* Note: + * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will + * release all overlay buffers. The buffer currently displayed at that moment, may need some + * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets + * called one more time then, with a null pointer for overlay_window and overlay_view, while + * the currently displayed overlay_buffer is given. + * The G200-G550 do not need to do anything on such an occasion, so we simply return if we + * get called then. */ + if ((ow == NULL) || (ov == NULL)) + { + LOG(4,("output properties changed\n")); + + return B_OK; + } + + /* Note: + * If during overlay use the screen prefs are changed, or the workspace has changed, it + * may be that we were not able to re-allocate the requested overlay buffers (or only partly) + * due to lack of cardRAM. If the app does not respond properly to this, we might end up + * with a NULL pointer instead of a overlay_buffer to work with here. + * Of course, we need to abort then to prevent the system from 'going down'. + * The app will probably crash because it will want to write into this non-existant buffer + * at some point. */ + if (ob == NULL) + { + LOG(4,("no overlay buffer specified\n")); + + return B_ERROR; + } + + /* is this call done by the app that owns us? */ + if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) + /* nope, abort */ + { + LOG(4,("failed\n")); + + return B_ERROR; + } + else + /* call is for real */ + { + /* find the buffer's offset */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + { + LOG(4,("succesfull, switching to buffer %d\n", offset)); + + /* program overlay hardware */ + nv_configure_bes(ob, ow, ov, offset); + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("buffer is not ours, aborted!\n")); + + return B_ERROR; + } + } +} diff --git a/src/add-ons/accelerants/skeleton/ProposeDisplayMode.c b/src/add-ons/accelerants/skeleton/ProposeDisplayMode.c new file mode 100644 index 0000000000..6c59e4c656 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/ProposeDisplayMode.c @@ -0,0 +1,597 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors for NV driver: + Mark Watson, + Rudolf Cornelissen 9/2002-10/2004 +*/ + +#define MODULE_BIT 0x00400000 + +#include "acc_std.h" + +#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) +/* mode flags will be setup as status info by PROPOSEMODE! */ +#define MODE_FLAGS 0 +#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode)) + +/*some monitors only handle a fixed set of modes*/ +#include "valid_mode_list" + +/* Standard VESA modes, + * plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual + * panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */ +static const display_mode mode_list[] = { +/* 4:3 modes; 307.2k pixels */ +{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ +{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ +{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ +{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ +{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ +{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ +/* 4:3 modes; 480k pixels */ +{ { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) from Be, Inc. driver + XFree86 */ +{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ +{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) + XFree86 */ +{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) + XFree86 */ +{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) + XFree86 */ +{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) + XFree86 */ +/* 4:3 modes; 786.432k pixels */ +{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */ +{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) + XFree86 */ +{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) + XFree86 */ +{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) + XFree86 */ +/* 4:3 modes; 995.328k pixels */ +{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) + XFree86 */ +{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ +/* 5:4 modes; 1.311M pixels */ +{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024) from Be, Inc. driver + XFree86 */ +{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) + XFree86 */ +{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) + XFree86 */ +/* 4:3 panel mode; 1.47M pixels */ +{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */ +/* 4:3 modes; 1.92M pixels */ +{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) + XFree86 */ +/* identical lines to above one, apart from refreshrate.. */ +{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) + XFree86 */ +{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) + XFree86 */ +{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) + XFree86 */ +{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */ +{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) + XFree86 */ +/* end identical lines. */ +/* 4:3 modes; 2.408M pixels */ +{ { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) from Be, Inc. driver + XFree86 */ +{ { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) from Be, Inc. driver + XFree86 */ +/* 4:3 modes; 2.584M pixels */ +{ { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) from Be, Inc. driver + XFree86 */ +{ { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) from Be, Inc. driver + XFree86 */ +/* 4:3 modes; 2.765M pixels */ +{ { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1440) from Be, Inc. driver + XFree86 */ +{ { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1920X1440) from Be, Inc. driver + XFree86 */ +/* 4:3 modes; 3.146M pixels */ +{ { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* From XFree86 posting @60Hz + XFree86 */ +/* 16:10 panel mode; 400k pixels */ +{ { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X500) */ +/* 16:10 panel mode; 655.36k pixels */ +{ { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X640) */ +/* 16:10 panel-TV mode; 983.04k pixels */ +{ { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X768) */ +/* 16:10 panel mode; 1.024M pixels */ +{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */ +/* 16:10 panel mode; 1.296M pixels */ +{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */ +/* 16:10 panel mode; 1.764M pixels */ +{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */ +/* 16:10 panel mode; 2.304M pixels */ +{ { 193200, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */ +}; + +/* +Check mode is between low and high limits +returns: + B_OK - found one + B_BAD_VALUE - mode can be made, but outside limits + B_ERROR - not possible +*/ +/* BOUNDS WARNING: + * BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE + * returns B_BAD_VALUE. It's called by the OS with target, low and high set to + * have the same settings for BWindowScreen! + * Which means we should not return B_BAD_VALUE on anything except for deviations on: + * display_mode.virtual_width; + * display_mode.virtual_height; + * display_mode.timing.h_display; + * display_mode.timing.v_display; + */ +/* Note: + * The target mode should be modified to correspond to the mode as it can be made. */ +status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) +{ + status_t status = B_OK; + float pix_clock_found, target_aspect; + uint8 m,n,p, bpp; + status_t result; + uint32 max_vclk, row_bytes, pointer_reservation; + bool acc_mode; + double target_refresh = ((double)target->timing.pixel_clock * 1000.0) / + ( + (double)target->timing.h_total * + (double)target->timing.v_total + ); + bool + want_same_width = target->timing.h_display == target->virtual_width, + want_same_height = target->timing.v_display == target->virtual_height; + + LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n", + target->virtual_width, target->virtual_height)); + + /*check valid list: + if (VALID_REQUIRED is set) + { + if (find modes with same size) + { + pick one with nearest pixel clock + } + else + { + pick next largest with nearest pixel clock and modify visible portion as far as possible + } + } + */ + #ifdef VALID_MODE_REQUIRED + { + int i; + int closest_mode_ptr; + uint32 closest_mode_clock; + + LOG(1, ("PROPOSEMODE: valid mode required!\n")); + + closest_mode_ptr = 0xbad; + closest_mode_clock = 0; + for (i=0;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 = head1_validate_timing + ( + &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total, + &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total + ); + if (result == B_ERROR) + { + LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n")); + return result; + } + + /* check if all connected output devices can display the requested mode's aspect: */ + /* calculate display mode aspect */ + target_aspect = (target->timing.h_display / ((float)target->timing.v_display)); + /* NOTE: + * allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */ + switch (si->ps.monitors) + { + case 0x01: /* digital panel on head 1, nothing on head 2 */ + if (si->ps.panel1_aspect < (target_aspect - 0.10)) + { + LOG(4, ("PROPOSEMODE: connected panel1 is not widescreen type, aborted.\n")); + return B_ERROR; + } + break; + case 0x10: /* nothing on head 1, digital panel on head 2 */ + if (si->ps.panel2_aspect < (target_aspect - 0.10)) + { + LOG(4, ("PROPOSEMODE: connected panel2 is not widescreen type, aborted.\n")); + return B_ERROR; + } + break; + case 0x11: /* digital panels on both heads */ + if ((si->ps.panel1_aspect < (target_aspect - 0.10)) || + (si->ps.panel2_aspect < (target_aspect - 0.10))) + { + LOG(4, ("PROPOSEMODE: not all connected panels are widescreen type, aborted.\n")); + return B_ERROR; + } + break; + default: /* at least one analog monitor is connected, or nothing detected at all */ + if (target_aspect > 1.34) + { + LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n")); + return B_ERROR; + } + break; + } + + /* only export widescreen panel-TV modes when an exact resolution match exists, + * to prevent the modelist from becoming too crowded */ + if (target_aspect > 1.61) + { + status_t panel_TV_stat = B_ERROR; + + if (si->ps.tmds1_active) + { + if ((target->timing.h_display == si->ps.p1_timing.h_display) && + (target->timing.v_display == si->ps.p1_timing.v_display)) + { + panel_TV_stat = B_OK; + } + } + if (si->ps.tmds2_active) + { + if ((target->timing.h_display == si->ps.p2_timing.h_display) && + (target->timing.v_display == si->ps.p2_timing.v_display)) + { + panel_TV_stat = B_OK; + } + } + if (panel_TV_stat != B_OK) + { + LOG(4, ("PROPOSEMODE: WS panel_TV mode requested but no such TV here, aborted.\n")); + return B_ERROR; + } + } + + /* check if panel(s) can display the requested resolution (if connected) */ + if (si->ps.tmds1_active) + { + if ((target->timing.h_display > si->ps.p1_timing.h_display) || + (target->timing.v_display > si->ps.p1_timing.v_display)) + { + LOG(4, ("PROPOSEMODE: panel1 can't display requested resolution, aborted.\n")); + return B_ERROR; + } + } + if (si->ps.tmds2_active) + { + if ((target->timing.h_display > si->ps.p2_timing.h_display) || + (target->timing.v_display > si->ps.p2_timing.v_display)) + { + LOG(4, ("PROPOSEMODE: panel2 can't display requested resolution, aborted.\n")); + return B_ERROR; + } + } + + /* validate display vs. virtual */ + if ((target->timing.h_display > target->virtual_width) || want_same_width) + target->virtual_width = target->timing.h_display; + if ((target->timing.v_display > target->virtual_height) || want_same_height) + target->virtual_height = target->timing.v_display; + + /* nail virtual size and 'subsequently' calculate rowbytes */ + result = nv_general_validate_pic_size (target, &row_bytes, &acc_mode); + if (result == B_ERROR) + { + LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n")); + return result; + } + + /*check if virtual_width is still within the requested limits*/ + if ((target->virtual_width < low->virtual_width) || + (target->virtual_width > high->virtual_width)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n")); + } + + /*check if timing found is within the requested horizontal limits*/ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display) || + (target->timing.h_sync_start < low->timing.h_sync_start) || + (target->timing.h_sync_start > high->timing.h_sync_start) || + (target->timing.h_sync_end < low->timing.h_sync_end) || + (target->timing.h_sync_end > high->timing.h_sync_end) || + (target->timing.h_total < low->timing.h_total) || + (target->timing.h_total > high->timing.h_total)) + { + /* BWindowScreen workaround: we accept everything except h_display deviations */ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n")); + } + + /*check if timing found is within the requested vertical limits*/ + if ( + (target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display) || + (target->timing.v_sync_start < low->timing.v_sync_start) || + (target->timing.v_sync_start > high->timing.v_sync_start) || + (target->timing.v_sync_end < low->timing.v_sync_end) || + (target->timing.v_sync_end > high->timing.v_sync_end) || + (target->timing.v_total < low->timing.v_total) || + (target->timing.v_total > high->timing.v_total) + ) + { + /* BWindowScreen workaround: we accept everything except v_display deviations */ + if ((target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n")); + } + + /* adjust pixelclock for possible timing modifications done above */ + target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0; + + /* Now find the nearest valid pixelclock we actually can setup for the target mode, + * this also makes sure we don't generate more pixel bandwidth than the device can handle */ + /* calculate settings, but do not actually test anything (that costs too much time!) */ + result = head1_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0); + /* update the target mode */ + target->timing.pixel_clock = (pix_clock_found * 1000); + + /* note if we fell outside the limits */ + if ((target->timing.pixel_clock < low->timing.pixel_clock) || + (target->timing.pixel_clock > high->timing.pixel_clock) + ) + { + /* BWindowScreen workaround: we accept deviations <= 1Mhz */ + if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) || + (target->timing.pixel_clock > (high->timing.pixel_clock + 1000))) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n")); + } + + /* checkout space needed for hardcursor (if any) */ + pointer_reservation = 0; + if (si->settings.hardcursor) pointer_reservation = 2048; + /* memory requirement for frame buffer */ + if ((row_bytes * target->virtual_height) > + (si->ps.memory_size - pointer_reservation)) + { + target->virtual_height = + (si->ps.memory_size - pointer_reservation) / row_bytes; + } + if (target->virtual_height < target->timing.v_display) + { + LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n")); + return B_ERROR; + } + LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n", + target->virtual_width, target->virtual_height)); + + if ((target->virtual_height < low->virtual_height) || + (target->virtual_height > high->virtual_height)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n")); + } + + /* setup status flags */ + LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags)); + /* preset to singlehead card without TVout, no overlay support and no hardcursor. + * also advice system that app_server and acc engine may touch the framebuffer + * simultaneously (fixed). */ + target->flags &= + ~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA); + /* we always allow parallel access (fixed), the DAC is always in 'enhanced' + * mode (fixed), and all modes support DPMS (fixed); + * We support scrolling and panning in every mode, so we 'send a signal' to + * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */ + /* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables + * BDirectWindow windowed modes. */ + target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL); + + /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */ + switch (target->space) + { + case B_CMAP8: + max_vclk = si->ps.max_dac2_clock_8; + bpp = 1; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_vclk = si->ps.max_dac2_clock_16; + bpp = 2; + break; + case B_RGB24_LITTLE: + max_vclk = si->ps.max_dac2_clock_24; + bpp = 3; + break; + case B_RGB32_LITTLE: + max_vclk = si->ps.max_dac2_clock_32dh; + bpp = 4; + break; + default: + /* use fail-safe value */ + max_vclk = si->ps.max_dac2_clock_32dh; + bpp = 4; + break; + } + + /* set DUALHEAD_CAPABLE if suitable */ + //fixme: update for independant secondary head use! (reserve fixed memory then) + if (si->ps.secondary_head && (target->timing.pixel_clock <= (max_vclk * 1000))) + { + switch (target->flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (((si->ps.memory_size - pointer_reservation) >= + (row_bytes * target->virtual_height)) && + ((uint16)(row_bytes / bpp) >= (target->timing.h_display * 2))) + { + target->flags |= DUALHEAD_CAPABLE; + } + break; + case DUALHEAD_CLONE: + if ((si->ps.memory_size - pointer_reservation) >= + (row_bytes * target->virtual_height)) + { + target->flags |= DUALHEAD_CAPABLE; + } + break; + case DUALHEAD_OFF: + if ((si->ps.memory_size - pointer_reservation) >= + (row_bytes * target->virtual_height * 2)) + { + target->flags |= DUALHEAD_CAPABLE; + } + break; + } + } + + /* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */ + //fixme: modify for G100 and G200 TVout later on... + if (target->flags & DUALHEAD_CAPABLE) + { + if (si->ps.tvout && + (target->timing.h_display <= 1024) && + (target->timing.v_display <= 768)) + { + target->flags |= TV_CAPABLE; + } + } + + /* set HARDWARE_CURSOR mode if suitable */ + if (si->settings.hardcursor) + target->flags |= B_HARDWARE_CURSOR; + + /* set SUPPORTS_OVERLAYS */ + target->flags |= B_SUPPORTS_OVERLAYS; + + LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags)); + + /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE, + * progressive scan (fixed), and sync_on_green not avaible. */ + target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN); + /* The HSYNC and VSYNC command flags are actually executed by the driver. */ + + if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n")); + else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n")); + return status; +} + +/* Return the number of modes this device will return from GET_MODE_LIST(). + This is precalculated in create_mode_list (called from InitAccelerant stuff) +*/ +uint32 ACCELERANT_MODE_COUNT(void) +{ + LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count)); + + return si->mode_count; +} + +/* Copy the list of guaranteed supported video modes to the location provided.*/ +status_t GET_MODE_LIST(display_mode *dm) +{ + LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n")); + + memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode)); + return B_OK; +} + +/* Create a list of display_modes to pass back to the caller.*/ +status_t create_mode_list(void) +{ + size_t max_size; + uint32 + i, j, + pix_clk_range; + const display_mode + *src; + display_mode + *dst, + low, + high; + + color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8}; + + /* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */ + max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1); + /* create an area to hold the info */ + si->mode_area = my_mode_list_area = + create_area("NV accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (my_mode_list_area < B_OK) return my_mode_list_area; + + /* walk through our predefined list and see which modes fit this device */ + src = mode_list; + dst = my_mode_list; + si->mode_count = 0; + for (i = 0; i < MODE_COUNT; i++) + { + /* set ranges for acceptable values */ + low = high = *src; + /* range is 6.25% of default clock: arbitrarily picked */ + pix_clk_range = low.timing.pixel_clock >> 5; + low.timing.pixel_clock -= pix_clk_range; + high.timing.pixel_clock += pix_clk_range; + /* 'some cards need wider virtual widths for certain modes': + * Not true. They might need a wider pitch, but this is _not_ reflected in + * virtual_width, but in fbc.bytes_per_row. */ + //So disable next line: + //high.virtual_width = 4096; + /* do it once for each depth we want to support */ + for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) + { + /* set target values */ + *dst = *src; + /* poke the specific space */ + dst->space = low.space = high.space = spaces[j]; + /* ask for a compatible mode */ + /* We have to check for B_OK, because otherwise the pix_clk_range + * won't be taken into account!! */ + //So don't do this: + //if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) { + //Instead, do this: + if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) { + /* count it, and move on to next mode */ + dst++; + si->mode_count++; + } + } + /* advance to next mode */ + src++; + } + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/SetDisplayMode.c b/src/add-ons/accelerants/skeleton/SetDisplayMode.c new file mode 100644 index 0000000000..776bcd3386 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/SetDisplayMode.c @@ -0,0 +1,517 @@ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Apsed, + Rudolf Cornelissen 11/2002-4/2004 +*/ + +#define MODULE_BIT 0x00200000 + +#include "acc_std.h" + +/* + Enable/Disable interrupts. Just a wrapper around the + ioctl() to the kernel driver. +*/ +static void interrupt_enable(bool flag) { + status_t result; + nv_set_bool_state sbs; + + /* set the magic number so the driver knows we're for real */ + sbs.magic = NV_PRIVATE_DATA_MAGIC; + sbs.do_it = flag; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs)); +} + +/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ +status_t SET_DISPLAY_MODE(display_mode *mode_to_set) +{ + /* BOUNDS WARNING: + * It's impossible to deviate whatever small amount in a display_mode if the lower + * and upper limits are the same! + * Besides: + * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE + * returns B_BAD_VALUE! + * Which means PROPOSEMODE should not return that on anything except on + * deviations for: + * display_mode.virtual_width; + * display_mode.virtual_height; + * display_mode.timing.h_display; + * display_mode.timing.v_display; + * So: + * We don't use bounds here by making sure bounds and target are the same struct! + * (See the call to PROPOSE_DISPLAY_MODE below) */ + display_mode /*bounds,*/ target; + + uint8 colour_depth1 = 32; + status_t result; + uint32 startadd,startadd_right; + bool display, h, v; +// bool crt1, crt2, cross; + + /* Adjust mode to valid one and fail if invalid */ + target /*= bounds*/ = *mode_to_set; + /* show the mode bits */ + LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); + LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); + LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", + target.virtual_width, target.virtual_height)); + + /* See BOUNDS WARNING above... */ + if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; + + /* if not dualhead capable card clear dualhead flags */ + if (!(target.flags & DUALHEAD_CAPABLE)) + { + target.flags &= ~DUALHEAD_BITS; + } + /* if not TVout capable card clear TVout flags */ + if (!(target.flags & TV_CAPABLE)) + { + target.flags &= ~TV_BITS; + } + LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags)); + + /* disable interrupts using the kernel driver */ + interrupt_enable(false); + + /* find current DPMS state, then turn off screen(s) */ + head1_dpms_fetch(&display, &h, &v); + head1_dpms(false, false, false); + if (si->ps.secondary_head) head2_dpms(false, false, false); + + /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ + startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; + + /* calculate and set new mode bytes_per_row */ + nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); + + /*Perform the very long mode switch!*/ + if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ + { + uint8 colour_depth2 = colour_depth1; + + /* init display mode for secondary head */ + display_mode target2 = target; + + LOG(1,("SETMODE: setting DUALHEAD mode\n")); + + /* validate flags for secondary TVout */ + if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS)) + { + target.flags &= ~TV_BITS;//still needed for some routines... + target2.flags &= ~TV_BITS; + LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); + } + + /* detect which connectors have a CRT connected */ + //fixme: 'hot-plugging' for analog monitors removed: remove code as well; + //or make it work with digital panels connected as well. +// crt1 = nv_dac_crt_connected(); +// crt2 = nv_dac2_crt_connected(); + /* connect outputs 'straight-through' */ +// if (crt1) +// { + /* connector1 is used as primary output */ +// cross = false; +// } +// else +// { +// if (crt2) + /* connector2 is used as primary output */ +// cross = true; +// else + /* no CRT detected: assume connector1 is used as primary output */ +// cross = false; +// } + /* set output connectors assignment if possible */ + if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH) + /* invert output assignment in switch mode */ + nv_general_head_select(true); + else + nv_general_head_select(false); + + /* set the pixel clock PLL(s) */ + LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); + if (head1_set_pix_pll(target) == B_ERROR) + LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); + + /* we do not need to set the pixelclock here for a head that's in TVout mode */ + if (!(target2.flags & TV_BITS)) + { + LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); + if (head2_set_pix_pll(target2) == B_ERROR) + LOG(8,("SETMODE: error setting pixel clock (DAC2)\n")); + } + + /*set the colour depth for CRTC1 and the DAC */ + switch(target.space) + { + case B_CMAP8: + colour_depth1 = 8; + head1_mode(BPP8, 1.0); + head1_depth(BPP8); + break; + case B_RGB15_LITTLE: + colour_depth1 = 16; + head1_mode(BPP15, 1.0); + head1_depth(BPP15); + break; + case B_RGB16_LITTLE: + colour_depth1 = 16; + head1_mode(BPP16, 1.0); + head1_depth(BPP16); + break; + case B_RGB32_LITTLE: + colour_depth1 = 32; + head1_mode(BPP32, 1.0); + head1_depth(BPP32); + break; + } + /*set the colour depth for CRTC2 and DAC2 */ + switch(target2.space) + { + case B_CMAP8: + colour_depth2 = 8; + head2_mode(BPP8, 1.0); + head2_depth(BPP8); + break; + case B_RGB15_LITTLE: + colour_depth2 = 16; + head2_mode(BPP15, 1.0); + head2_depth(BPP15); + break; + case B_RGB16_LITTLE: + colour_depth2 = 16; + head2_mode(BPP16, 1.0); + head2_depth(BPP16); + break; + case B_RGB32_LITTLE: + colour_depth2 = 32; + head2_mode(BPP32, 1.0); + head2_depth(BPP32); + break; + } + + /* check if we are doing interlaced TVout mode */ + si->interlaced_tv_mode = false; +/* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450)) + si->interlaced_tv_mode = true; +*/ + /*set the display(s) pitches*/ + head1_set_display_pitch (); + //fixme: seperate for real dualhead modes: + //we need a secondary si->fbc! + head2_set_display_pitch (); + + /*work out where the "right" screen starts*/ + startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3)); + + /* Tell card what memory to display */ + switch (target.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + head1_set_display_start(startadd,colour_depth1); + head2_set_display_start(startadd_right,colour_depth2); + break; + case DUALHEAD_CLONE: + head1_set_display_start(startadd,colour_depth1); + head2_set_display_start(startadd,colour_depth2); + break; + } + + /* set the timing */ + head1_set_timing(target); + /* we do not need to setup CRTC2 here for a head that's in TVout mode */ + if (!(target2.flags & TV_BITS)) result = head2_set_timing(target2); + + /* TVout support: setup CRTC2 and it's pixelclock */ + if (si->ps.tvout && (target2.flags & TV_BITS)) maventv_init(target2); + } + else /* single head mode */ + { + status_t status; + int colour_mode = BPP32; + + /* connect output */ + if (si->ps.secondary_head) + { + /* detect which connectors have a CRT connected */ + //fixme: 'hot-plugging' for analog monitors removed: remove code as well; + //or make it work with digital panels connected as well. +// crt1 = nv_dac_crt_connected(); +// crt2 = nv_dac2_crt_connected(); + /* connect outputs 'straight-through' */ +// if (crt1) +// { + /* connector1 is used as primary output */ +// cross = false; +// } +// else +// { +// if (crt2) + /* connector2 is used as primary output */ +// cross = true; +// else + /* no CRT detected: assume connector1 is used as primary output */ +// cross = false; +// } + /* set output connectors assignment if possible */ + nv_general_head_select(false); + } + + switch(target.space) + { + case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; + case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; + case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; + case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; + default: + LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); + return B_ERROR; + } + + /* set the pixel clock PLL */ + status = head1_set_pix_pll(target); + + if (status==B_ERROR) + LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); + + /* set the colour depth for CRTC1 and the DAC */ + /* first set the colordepth */ + head1_depth(colour_mode); + /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */ + head1_mode(colour_mode,1.0); + + /* set the display pitch */ + head1_set_display_pitch(); + + /* tell the card what memory to display */ + head1_set_display_start(startadd,colour_depth1); + + /* set the timing */ + head1_set_timing(target); + + //fixme: shut-off the videoPLL if it exists... + } + + /* update driver's mode store */ + si->dm = target; + + /* turn screen one on */ + head1_dpms(display, h, v); + /* turn screen two on if a dualhead mode is active */ + if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v); + + /* set up acceleration for this mode */ + nv_acc_init(); + /* set up overlay unit for this mode */ + nv_bes_init(); + + LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); + + /* enable interrupts using the kernel driver */ + interrupt_enable(true); + + /* optimize memory-access if needed */ +// head1_mem_priority(colour_depth1); + + /* Tune RAM CAS-latency if needed. Must be done *here*! */ + nv_set_cas_latency(); + + return B_OK; +} + +/* + Set which pixel of the virtual frame buffer will show up in the + top left corner of the display device. Used for page-flipping + games and virtual desktops. +*/ +status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { + uint8 colour_depth; + uint32 startadd,startadd_right; + + LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); + + /* nVidia cards support pixelprecise panning on both heads in all modes: + * No stepping granularity needed! */ + + /* determine bits used for the colordepth */ + switch(si->dm.space) + { + case B_CMAP8: + colour_depth=8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + colour_depth=16; + break; + case B_RGB24_LITTLE: + colour_depth=24; + break; + case B_RGB32_LITTLE: + colour_depth=32; + break; + default: + return B_ERROR; + } + + /* do not run past end of display */ + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) + return B_ERROR; + break; + default: + if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) + return B_ERROR; + break; + } + if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) + return B_ERROR; + + /* everybody remember where we parked... */ + si->dm.h_display_start = h_display_start; + si->dm.v_display_start = v_display_start; + + /* actually set the registers */ + //fixme: seperate both heads: we need a secondary si->fbc! + startadd = v_display_start * si->fbc.bytes_per_row; + startadd += h_display_start * (colour_depth >> 3); + startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; + startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); + + interrupt_enable(false); + + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + head1_set_display_start(startadd,colour_depth); + head2_set_display_start(startadd_right,colour_depth); + break; + case DUALHEAD_OFF: + head1_set_display_start(startadd,colour_depth); + break; + case DUALHEAD_CLONE: + head1_set_display_start(startadd,colour_depth); + head2_set_display_start(startadd,colour_depth); + break; + } + + interrupt_enable(true); + return B_OK; +} + +/* Set the indexed color palette */ +void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { + int i; + uint8 *r,*g,*b; + + /* Protect gamma correction when not in CMAP8 */ + if (si->dm.space != B_CMAP8) return; + + r=si->color_data; + g=r+256; + b=g+256; + + i=first; + while (count--) + { + r[i]=*color_data++; + g[i]=*color_data++; + b[i]=*color_data++; + i++; + } + head1_palette(r,g,b); + if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b); +} + +/* Put the display into one of the Display Power Management modes. */ +status_t SET_DPMS_MODE(uint32 dpms_flags) { + interrupt_enable(false); + + LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags)); + + if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/ + { + switch(dpms_flags) + { + case B_DPMS_ON: /* H: on, V: on, display on */ + head1_dpms(true, true, true); + if (si->ps.secondary_head) head2_dpms(true, true, true); + break; + case B_DPMS_STAND_BY: + head1_dpms(false, false, true); + if (si->ps.secondary_head) head2_dpms(false, false, true); + break; + case B_DPMS_SUSPEND: + head1_dpms(false, true, false); + if (si->ps.secondary_head) head2_dpms(false, true, false); + break; + case B_DPMS_OFF: /* H: off, V: off, display off */ + head1_dpms(false, false, false); + if (si->ps.secondary_head) head2_dpms(false, false, false); + break; + default: + LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); + interrupt_enable(true); + return B_ERROR; + } + } + else /* singlehead */ + { + switch(dpms_flags) + { + case B_DPMS_ON: /* H: on, V: on, display on */ + head1_dpms(true, true, true); + break; + case B_DPMS_STAND_BY: + head1_dpms(false, false, true); + break; + case B_DPMS_SUSPEND: + head1_dpms(false, true, false); + break; + case B_DPMS_OFF: /* H: off, V: off, display off */ + head1_dpms(false, false, false); + break; + default: + LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); + interrupt_enable(true); + return B_ERROR; + } + } + interrupt_enable(true); + return B_OK; +} + +/* Report device DPMS capabilities */ +uint32 DPMS_CAPABILITIES(void) { + return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); +} + +/* Return the current DPMS mode */ +uint32 DPMS_MODE(void) { + bool display, h, v; + + interrupt_enable(false); + head1_dpms_fetch(&display, &h, &v); + interrupt_enable(true); + + if (display && h && v) + return B_DPMS_ON; + else if(v) + return B_DPMS_STAND_BY; + else if(h) + return B_DPMS_SUSPEND; + else + return B_DPMS_OFF; +} diff --git a/src/add-ons/accelerants/skeleton/acc_std.h b/src/add-ons/accelerants/skeleton/acc_std.h new file mode 100644 index 0000000000..560ab04a67 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/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 "nv_globals.h" +//apsed #include "nv_extern.h" +#include "nv_proto.h" +#include "be_driver_proto.h" + +#endif diff --git a/src/add-ons/accelerants/skeleton/be_driver_proto.h b/src/add-ons/accelerants/skeleton/be_driver_proto.h new file mode 100644 index 0000000000..efd6c8418c --- /dev/null +++ b/src/add-ons/accelerants/skeleton/be_driver_proto.h @@ -0,0 +1,68 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#if !defined(GENERIC_H) +#define GENERIC_H + +#include +#include "video_overlay.h" + +#define DEBUG 1 + +status_t INIT_ACCELERANT(int fd); +ssize_t ACCELERANT_CLONE_INFO_SIZE(void); +void GET_ACCELERANT_CLONE_INFO(void *data); +status_t CLONE_ACCELERANT(void *data); +void UNINIT_ACCELERANT(void); +status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi); +sem_id ACCELERANT_RETRACE_SEMAPHORE(void); + +uint32 ACCELERANT_MODE_COUNT(void); +status_t GET_MODE_LIST(display_mode *dm); +status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high); +status_t SET_DISPLAY_MODE(display_mode *mode_to_set); +status_t GET_DISPLAY_MODE(display_mode *current_mode); +status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer); +status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high); +status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start); +status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc); +void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags); + +uint32 DPMS_CAPABILITIES(void); +uint32 DPMS_MODE(void); +status_t SET_DPMS_MODE(uint32 dpms_flags); + +status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask); +void MOVE_CURSOR(uint16 x, uint16 y); +void SHOW_CURSOR(bool is_visible); + +uint32 ACCELERANT_ENGINE_COUNT(void); +status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et); +status_t RELEASE_ENGINE(engine_token *et, sync_token *st); +void WAIT_ENGINE_IDLE(void); +status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st); +status_t SYNC_TO_TOKEN(sync_token *st); + +void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count); +void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count); +void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count); +void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count); +void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count); +void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count); + +/* video_overlay */ +uint32 OVERLAY_COUNT(const display_mode *dm); +const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm); +uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space); +const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height); +status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob); +status_t GET_OVERLAY_CONSTRAINTS(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc); +overlay_token ALLOCATE_OVERLAY(void); +status_t RELEASE_OVERLAY(overlay_token ot); +status_t CONFIGURE_OVERLAY(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov); + +status_t create_mode_list(void); + +#endif diff --git a/src/add-ons/accelerants/skeleton/engine/Jamfile b/src/add-ons/accelerants/skeleton/engine/Jamfile new file mode 100644 index 0000000000..73a871e223 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/Jamfile @@ -0,0 +1,20 @@ +SubDir OBOS_TOP src add-ons accelerants skeleton engine ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics skeleton ] ; + +StaticLibrary skeleton_engine : + acc.c + bes.c + brooktreetv.c + crtc.c + crtc2.c + dac.c + dac2.c + general.c + agp.c + globals.c + i2c.c + info.c + support.c + ; diff --git a/src/add-ons/accelerants/skeleton/engine/acc.c b/src/add-ons/accelerants/skeleton/engine/acc.c new file mode 100644 index 0000000000..68515b828f --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/acc.c @@ -0,0 +1,888 @@ +/* NV Acceleration functions */ +/* Author: + Rudolf Cornelissen 8/2003-9/2004. + + This code was possible thanks to the Linux NV driver. +*/ + +#define MODULE_BIT 0x00080000 + +#include "nv_std.h" + +/*acceleration notes*/ + +/*functions Be's app_server uses: +fill span (horizontal only) +fill rectangle (these 2 are very similar) +invert rectangle +blit +*/ + +status_t nv_acc_wait_idle() +{ + /* wait until engine completely idle */ + while (ACCR(STATUS)) + { + /* snooze a bit so I do not hammer the bus */ + snooze (100); + } + + return B_OK; +} + +/* AFAIK this must be done for every new screenmode. + * Engine required init. */ +status_t nv_acc_init() +{ + uint16 cnt; + + /* setup PTIMER: */ + //fixme? how about NV28 setup as just after coldstarting? (see nv_info.c) + /* set timer numerator to 8 (in b0-15) */ + ACCW(PT_NUMERATOR, 0x00000008); + /* set timer denominator to 3 (in b0-15) */ + ACCW(PT_DENOMINATR, 0x00000003); + + /* disable timer-alarm INT requests (b0) */ + ACCW(PT_INTEN, 0x00000000); + /* reset timer-alarm INT status bit (b0) */ + ACCW(PT_INTSTAT, 0xffffffff); + + /* enable PRAMIN write access on pre NV10 before programming it! */ + if (si->ps.card_arch == NV04A) + { + /* set framebuffer config: type = notiling, PRAMIN write access enabled */ + NV_REG32(NV32_PFB_CONFIG_0) = 0x00001114; + } + + /*** PFIFO ***/ + /* (setup caches) */ + /* disable caches reassign */ + ACCW(PF_CACHES, 0x00000000); + /* cache1 push0 access disabled */ + ACCW(PF_CACH1_PSH0, 0x00000000); + /* cache1 pull0 access disabled */ + ACCW(PF_CACH1_PUL0, 0x00000000); + /* cache1 push1 mode = pio */ + ACCW(PF_CACH1_PSH1, 0x00000000); + /* cache1 DMA instance adress = 0 (b0-15) */ + ACCW(PF_CACH1_DMAI, 0x00000000); + /* cache0 push0 access disabled */ + ACCW(PF_CACH0_PSH0, 0x00000000); + /* cache0 pull0 access disabled */ + ACCW(PF_CACH0_PUL0, 0x00000000); + /* RAM HT (hash table(?)) baseadress = $10000 (b4-8), size = 4k, + * search = 128 (byte offset between hash 'sets'(?)) */ + /* (note: so(?) HT base is $00710000, last is $00710fff) */ + ACCW(PF_RAMHT, 0x03000100); + /* RAM FC baseadress = $11000 (b3-8) (size is fixed to 0.5k(?)) */ + /* (note: so(?) FC base is $00711000, last is $007111ff) */ + ACCW(PF_RAMFC, 0x00000110); + /* RAM RO baseadress = $11200 (b1-8), size = 0.5k */ + /* (note: so(?) RO base is $00711200, last is $007113ff) */ + /* (note also: + * This means(?) the PRAMIN CTX registers are accessible from base $00711400) */ + ACCW(PF_RAMRO, 0x00000112); + /* PFIFO size: ch0-15 = 512 bytes, ch16-31 = 124 bytes */ + ACCW(PF_SIZE, 0x0000ffff); + /* cache1 hash instance = $ffff (b0-15) */ + ACCW(PF_CACH1_HASH, 0x0000ffff); + /* disable all PFIFO INTs */ + ACCW(PF_INTEN, 0x00000000); + /* reset all PFIFO INT status bits */ + ACCW(PF_INTSTAT, 0xffffffff); + /* cache0 pull0 engine = acceleration engine (graphics) */ + ACCW(PF_CACH0_PUL1, 0x00000001); + /* cache1 push0 access enabled */ + ACCW(PF_CACH1_PSH0, 0x00000001); + /* cache1 pull0 access enabled */ + ACCW(PF_CACH1_PUL0, 0x00000001); + /* cache1 pull1 engine = acceleration engine (graphics) */ + ACCW(PF_CACH1_PUL1, 0x00000001); + /* enable PFIFO caches reassign */ + ACCW(PF_CACHES, 0x00000001); + + /*** PRAMIN ***/ + /* RAMHT space (hash-table(?)) */ + /* (first set) */ + ACCW(HT_HANDL_00, 0x80000010); /* 32bit handle */ + ACCW(HT_VALUE_00, 0x80011145); /* instance $1145, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_01, 0x80000011); /* 32bit handle */ + ACCW(HT_VALUE_01, 0x80011146); /* instance $1146, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_02, 0x80000012); /* 32bit handle */ + ACCW(HT_VALUE_02, 0x80011147); /* instance $1147, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_03, 0x80000013); /* 32bit handle */ + ACCW(HT_VALUE_03, 0x80011148); /* instance $1148, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_04, 0x80000014); /* 32bit handle */ + ACCW(HT_VALUE_04, 0x80011149); /* instance $1149, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_05, 0x80000015); /* 32bit handle */ + ACCW(HT_VALUE_05, 0x8001114a); /* instance $114a, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_06, 0x80000016); /* 32bit handle */ + if (si->ps.card_arch != NV04A) + ACCW(HT_VALUE_06, 0x80011150); /* instance $1150, engine = acc engine, CHID = $00 */ + else + ACCW(HT_VALUE_06, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */ + /* (second set) */ + ACCW(HT_HANDL_10, 0x80000000); /* 32bit handle */ + ACCW(HT_VALUE_10, 0x80011142); /* instance $1142, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_11, 0x80000001); /* 32bit handle */ + ACCW(HT_VALUE_11, 0x80011143); /* instance $1143, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_12, 0x80000002); /* 32bit handle */ + ACCW(HT_VALUE_12, 0x80011144); /* instance $1144, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_13, 0x80000003); /* 32bit handle */ + ACCW(HT_VALUE_13, 0x8001114b); /* instance $114b, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_14, 0x80000004); /* 32bit handle */ + ACCW(HT_VALUE_14, 0x8001114c); /* instance $114c, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_15, 0x80000005); /* 32bit handle */ + ACCW(HT_VALUE_15, 0x8001114d); /* instance $114d, engine = acc engine, CHID = $00 */ + ACCW(HT_HANDL_16, 0x80000006); /* 32bit handle */ + ACCW(HT_VALUE_16, 0x8001114e); /* instance $114e, engine = acc engine, CHID = $00 */ + if (si->ps.card_arch != NV04A) + { + ACCW(HT_HANDL_17, 0x80000007); /* 32bit handle */ + ACCW(HT_VALUE_17, 0x8001114f); /* instance $114f, engine = acc engine, CHID = $00 */ + } + /* program CTX registers: CTX1 is mostly done later (colorspace dependant) */ + /* (setup 'root' set first) */ + ACCW(PR_CTX0_R, 0x00003000); /* NVclass = NVroot, chromakey and userclip enabled */ + /* fixme: CTX1_R should reflect RAM amount? (no influence on current used functions) */ + ACCW(PR_CTX1_R, 0x01ffffff); /* cardmemory mask(?) */ + ACCW(PR_CTX2_R, 0x00000002); /* ??? */ + ACCW(PR_CTX3_R, 0x00000002); /* ??? */ + /* (setup set '0') */ + ACCW(PR_CTX0_0, 0x01008043); /* NVclass $043, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_0, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_0, 0x00000000); /* method traps disabled */ + /* (setup set '1') */ + ACCW(PR_CTX0_1, 0x01008019); /* NVclass $019, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_1, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_1, 0x00000000); /* method traps disabled */ + /* (setup set '2') */ + ACCW(PR_CTX0_2, 0x01008018); /* NVclass $018, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_2, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_2, 0x00000000); /* method traps disabled */ + /* (setup set '3') */ + ACCW(PR_CTX0_3, 0x01008021); /* NVclass $021, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_3, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_3, 0x00000000); /* method traps disabled */ + /* (setup set '4') */ + ACCW(PR_CTX0_4, 0x0100805f); /* NVclass $05f, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_4, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_4, 0x00000000); /* method traps disabled */ + /* (setup set '5') */ + ACCW(PR_CTX0_5, 0x0100804b); /* NVclass $04b, patchcfg ROP_AND, nv10+: little endian */ + ACCW(PR_CTX2_5, 0x00000000); /* DMA0 and DMA1 instance invalid */ + ACCW(PR_CTX3_5, 0x00000000); /* method traps disabled */ + /* (setup set '6') */ + ACCW(PR_CTX0_6, 0x0100a048); /* NVclass $048, patchcfg ROP_AND, userclip enable, + * nv10+: little endian */ + ACCW(PR_CTX1_6, 0x00000d01); /* format is A8RGB24, MSB mono */ + ACCW(PR_CTX2_6, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_6, 0x00000000); /* method traps disabled */ + /* (setup set '7') */ + if (si->ps.card_arch != NV04A) + ACCW(PR_CTX0_7, 0x0300a094); /* NVclass $094, patchcfg ROP_AND, userclip enable, + * context surface0 valid, nv10+: little endian */ + else + ACCW(PR_CTX0_7, 0x0300a054); /* NVclass $054, patchcfg ROP_AND, userclip enable, + * context surface0 valid */ + ACCW(PR_CTX1_7, 0x00000d01); /* format is A8RGB24, MSB mono */ + ACCW(PR_CTX2_7, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_7, 0x00000000); /* method traps disabled */ + /* (setup set '8') */ + if (si->ps.card_arch != NV04A) + ACCW(PR_CTX0_8, 0x0300a095); /* NVclass $095, patchcfg ROP_AND, userclip enable, + * context surface0 valid, nv10+: little endian */ + else + ACCW(PR_CTX0_8, 0x0300a055); /* NVclass $055, patchcfg ROP_AND, userclip enable, + * context surface0 valid */ + ACCW(PR_CTX1_8, 0x00000d01); /* format is A8RGB24, MSB mono */ + ACCW(PR_CTX2_8, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_8, 0x00000000); /* method traps disabled */ + /* (setup set '9') */ + ACCW(PR_CTX0_9, 0x00000058); /* NVclass $058, nv10+: little endian */ + ACCW(PR_CTX2_9, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_9, 0x00000000); /* method traps disabled */ + /* (setup set 'A') */ + ACCW(PR_CTX0_A, 0x00000059); /* NVclass $059, nv10+: little endian */ + ACCW(PR_CTX2_A, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_A, 0x00000000); /* method traps disabled */ + /* (setup set 'B') */ + ACCW(PR_CTX0_B, 0x0000005a); /* NVclass $05a, nv10+: little endian */ + ACCW(PR_CTX2_B, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_B, 0x00000000); /* method traps disabled */ + /* (setup set 'C') */ + ACCW(PR_CTX0_C, 0x0000005b); /* NVclass $05b, nv10+: little endian */ + ACCW(PR_CTX2_C, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_C, 0x00000000); /* method traps disabled */ + /* (setup set 'D') */ + if (si->ps.card_arch != NV04A) + ACCW(PR_CTX0_D, 0x00000093); /* NVclass $093, nv10+: little endian */ + else + ACCW(PR_CTX0_D, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable, + * context surface0 valid */ + ACCW(PR_CTX2_D, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_D, 0x00000000); /* method traps disabled */ + /* (setup set 'E' if needed) */ + if (si->ps.card_arch != NV04A) + { + ACCW(PR_CTX0_E, 0x0300a01c); /* NVclass $01c, patchcfg ROP_AND, userclip enable, + * context surface0 valid, nv10+: little endian */ + ACCW(PR_CTX2_E, 0x11401140); /* DMA0, DMA1 instance = $1140 */ + ACCW(PR_CTX3_E, 0x00000000); /* method traps disabled */ + } + + /*** PGRAPH ***/ + if (si->ps.card_arch != NV04A) + { + /* set resetstate for most function blocks */ + ACCW(DEBUG0, 0x0003ffff); + /* init some function blocks */ + ACCW(DEBUG1, 0x00118701); + ACCW(DEBUG2, 0x24f82ad9); + ACCW(DEBUG3, 0x55de0030); + /* end resetstate for the function blocks */ + ACCW(DEBUG0, 0x00000000); + /* disable specific functions */ + ACCW(NV10_DEBUG4, 0); + } + else + { + /* init some function blocks */ + ACCW(DEBUG0, 0x1231c001); + ACCW(DEBUG1, 0x72111101); + ACCW(DEBUG2, 0x11d5f071); + ACCW(DEBUG3, 0x10d4ff31); + } + + /* reset all cache sets */ + ACCW(CACHE1_1, 0); + ACCW(CACHE1_2, 0); + ACCW(CACHE1_3, 0); + ACCW(CACHE1_4, 0); + ACCW(CACHE1_5, 0); + ACCW(CACHE2_1, 0); + ACCW(CACHE2_2, 0); + ACCW(CACHE2_3, 0); + ACCW(CACHE2_4, 0); + ACCW(CACHE2_5, 0); + ACCW(CACHE3_1, 0); + ACCW(CACHE3_2, 0); + ACCW(CACHE3_3, 0); + ACCW(CACHE3_4, 0); + ACCW(CACHE3_5, 0); + ACCW(CACHE4_1, 0); + ACCW(CACHE4_2, 0); + ACCW(CACHE4_3, 0); + ACCW(CACHE4_4, 0); + ACCW(CACHE4_5, 0); + if (si->ps.card_arch != NV04A) + ACCW(NV10_CACHE5_1, 0); + ACCW(CACHE5_2, 0); + ACCW(CACHE5_3, 0); + ACCW(CACHE5_4, 0); + ACCW(CACHE5_5, 0); + if (si->ps.card_arch != NV04A) + ACCW(NV10_CACHE6_1, 0); + ACCW(CACHE6_2, 0); + ACCW(CACHE6_3, 0); + ACCW(CACHE6_4, 0); + ACCW(CACHE6_5, 0); + if (si->ps.card_arch != NV04A) + ACCW(NV10_CACHE7_1, 0); + ACCW(CACHE7_2, 0); + ACCW(CACHE7_3, 0); + ACCW(CACHE7_4, 0); + ACCW(CACHE7_5, 0); + if (si->ps.card_arch != NV04A) + ACCW(NV10_CACHE8_1, 0); + ACCW(CACHE8_2, 0); + ACCW(CACHE8_3, 0); + ACCW(CACHE8_4, 0); + ACCW(CACHE8_5, 0); + + if (si->ps.card_arch != NV04A) + { + /* reset (disable) context switch stuff */ + ACCW(NV10_CTX_SW1, 0); + ACCW(NV10_CTX_SW2, 0); + ACCW(NV10_CTX_SW3, 0); + ACCW(NV10_CTX_SW4, 0); + ACCW(NV10_CTX_SW5, 0); + } + + /* setup accesible card memory range for acc engine */ + ACCW(BBASE0, 0x00000000); + ACCW(BBASE1, 0x00000000); + ACCW(BBASE2, 0x00000000); + ACCW(BBASE3, 0x00000000); + ACCW(BLIMIT0, (si->ps.memory_size - 1)); + ACCW(BLIMIT1, (si->ps.memory_size - 1)); + ACCW(BLIMIT2, (si->ps.memory_size - 1)); + ACCW(BLIMIT3, (si->ps.memory_size - 1)); + if (si->ps.card_arch >= NV10A) + { + ACCW(NV10_BBASE4, 0x00000000); + ACCW(NV10_BBASE5, 0x00000000); + ACCW(NV10_BLIMIT4, (si->ps.memory_size - 1)); + ACCW(NV10_BLIMIT5, (si->ps.memory_size - 1)); + } + if (si->ps.card_arch >= NV20A) + { + /* fixme(?): assuming more BLIMIT registers here: Then how about BBASE6-9? + * (linux fixed value 'BLIMIT6-9' 0x01ffffff) */ + ACCW(NV20_BLIMIT6, (si->ps.memory_size - 1)); + ACCW(NV20_BLIMIT7, (si->ps.memory_size - 1)); + ACCW(NV20_BLIMIT8, (si->ps.memory_size - 1)); + ACCW(NV20_BLIMIT9, (si->ps.memory_size - 1)); + } + + /* disable all acceleration engine INT reguests */ + ACCW(ACC_INTE, 0x00000000); + + /* reset all acceration engine INT status bits */ + ACCW(ACC_INTS, 0xffffffff); + if (si->ps.card_arch != NV04A) + { + /* context control enabled */ + ACCW(NV10_CTX_CTRL, 0x10010100); + /* all acceleration buffers, pitches and colors are valid */ + ACCW(NV10_ACC_STAT, 0xffffffff); + } + else + { + /* context control enabled */ + ACCW(NV04_CTX_CTRL, 0x10010100); + /* all acceleration buffers, pitches and colors are valid */ + ACCW(NV04_ACC_STAT, 0xffffffff); + } + /* enable acceleration engine command FIFO */ + ACCW(FIFO_EN, 0x00000001); + /* pattern shape value = 8x8, 2 color */ + ACCW(PAT_SHP, 0x00000000); + if (si->ps.card_arch != NV04A) + { + /* surface type is non-swizzle */ + ACCW(NV10_SURF_TYP, 0x00000001); + } + else + { + /* surface type is non-swizzle */ + ACCW(NV04_SURF_TYP, 0x00000001); + } + + /*** Set pixel width and format ***/ + switch(si->dm.space) + { + case B_CMAP8: + /* acc engine */ + ACCW(FORMATS, 0x00001010); + if (si->ps.card_arch < NV30A) + ACCW(BPIXEL, 0x00111111); /* set depth 0-5: 4 bits per color */ + else + ACCW(BPIXEL, 0x00000021); /* set depth 0-1: 5 bits per color */ + ACCW(STRD_FMT, 0x03020202); + /* PRAMIN */ + ACCW(PR_CTX1_0, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX1_1, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX1_2, 0x00000202); /* format is X16A8Y8, LSB mono */ + ACCW(PR_CTX1_3, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX1_4, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX1_5, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX1_9, 0x00000302); /* format is X24Y8, LSB mono */ + ACCW(PR_CTX2_9, 0x00000302); /* dma_instance 0 valid, instance 1 invalid */ + ACCW(PR_CTX1_B, 0x00000000); /* format is invalid */ + ACCW(PR_CTX1_C, 0x00000000); /* format is invalid */ + if (si->ps.card_arch == NV04A) + { + ACCW(PR_CTX1_D, 0x00000302); /* format is X24Y8, LSB mono */ + } + else + { + ACCW(PR_CTX1_D, 0x00000000); /* format is invalid */ + ACCW(PR_CTX1_E, 0x00000302); /* format is X24Y8, LSB mono */ + } + break; + case B_RGB15_LITTLE: + /* acc engine */ + ACCW(FORMATS, 0x00002071); + if (si->ps.card_arch < NV30A) + ACCW(BPIXEL, 0x00226222); /* set depth 0-5: 4 bits per color */ + else + ACCW(BPIXEL, 0x00000042); /* set depth 0-1: 5 bits per color */ + ACCW(STRD_FMT, 0x09080808); + /* PRAMIN */ + ACCW(PR_CTX1_0, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_1, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_2, 0x00000802); /* format is X16A1RGB15, LSB mono */ + ACCW(PR_CTX1_3, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_4, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_5, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_9, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX2_9, 0x00000902); /* dma_instance 0 valid, instance 1 invalid */ + if (si->ps.card_arch == NV04A) + { + ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */ + ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */ + } + else + { + ACCW(PR_CTX1_B, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_C, 0x00000902); /* format is X17RGB15, LSB mono */ + ACCW(PR_CTX1_E, 0x00000902); /* format is X17RGB15, LSB mono */ + } + ACCW(PR_CTX1_D, 0x00000902); /* format is X17RGB15, LSB mono */ + break; + case B_RGB16_LITTLE: + /* acc engine */ + ACCW(FORMATS, 0x000050C2); + if (si->ps.card_arch < NV30A) + ACCW(BPIXEL, 0x00556555); /* set depth 0-5: 4 bits per color */ + else + ACCW(BPIXEL, 0x000000a5); /* set depth 0-1: 5 bits per color */ + if (si->ps.card_arch == NV04A) + ACCW(STRD_FMT, 0x0c0b0b0b); + else + ACCW(STRD_FMT, 0x000b0b0c); + /* PRAMIN */ + ACCW(PR_CTX1_0, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_1, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_2, 0x00000b02); /* format is A16RGB16, LSB mono */ + ACCW(PR_CTX1_3, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_4, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_5, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_9, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX2_9, 0x00000c02); /* dma_instance 0 valid, instance 1 invalid */ + if (si->ps.card_arch == NV04A) + { + ACCW(PR_CTX1_B, 0x00000702); /* format is X1RGB15, LSB mono */ + ACCW(PR_CTX1_C, 0x00000702); /* format is X1RGB15, LSB mono */ + } + else + { + ACCW(PR_CTX1_B, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_C, 0x00000c02); /* format is X16RGB16, LSB mono */ + ACCW(PR_CTX1_E, 0x00000c02); /* format is X16RGB16, LSB mono */ + } + ACCW(PR_CTX1_D, 0x00000c02); /* format is X16RGB16, LSB mono */ + break; + case B_RGB32_LITTLE:case B_RGBA32_LITTLE: + /* acc engine */ + ACCW(FORMATS, 0x000070e5); + if (si->ps.card_arch < NV30A) + ACCW(BPIXEL, 0x0077d777); /* set depth 0-5: 4 bits per color */ + else + ACCW(BPIXEL, 0x000000e7); /* set depth 0-1: 5 bits per color */ + ACCW(STRD_FMT, 0x0e0d0d0d); + /* PRAMIN */ + ACCW(PR_CTX1_0, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_1, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_2, 0x00000d02); /* format is A8RGB24, LSB mono */ + ACCW(PR_CTX1_3, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_4, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_5, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_9, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX2_9, 0x00000e02); /* dma_instance 0 valid, instance 1 invalid */ + ACCW(PR_CTX1_B, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_C, 0x00000e02); /* format is X8RGB24, LSB mono */ + ACCW(PR_CTX1_D, 0x00000e02); /* format is X8RGB24, LSB mono */ + if (si->ps.card_arch >= NV10A) + ACCW(PR_CTX1_E, 0x00000e02); /* format is X8RGB24, LSB mono */ + break; + default: + LOG(8,("ACC: init, invalid bit depth\n")); + return B_ERROR; + } + + /* setup some extra stuff for NV30A and later */ + if (si->ps.card_arch >= NV30A) + { +/* + fixme: Does not belong here (and not needed?) + if(!chip->flatPanel) + { + chip->PRAMDAC0[0x0578/4] = state->vpllB; //0x00680578 = ??? never modified! + chip->PRAMDAC0[0x057C/4] = state->vpll2B; //0x0068057c = ??? never modified! + } +*/ + + /* activate Zcullflush(?) */ + ACCW(DEBUG3, (ACCR(DEBUG3) | 0x00000001)); + /* unknown */ + ACCW(NV30_WHAT, (ACCR(NV30_WHAT) | 0x00040000)); + } + + /*** setup screen location and pitch ***/ + switch (si->ps.card_arch) + { + case NV04A: + case NV10A: + /* location of active screen in framebuffer */ + ACCW(OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(OFFSET4, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(OFFSET5, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + + /* setup buffer pitch */ + ACCW(PITCH0, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(PITCH1, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(PITCH2, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(PITCH3, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(PITCH4, (si->fbc.bytes_per_row & 0x0000ffff)); + break; + case NV20A: + case NV30A: + case NV40A: + /* location of active screen in framebuffer */ + ACCW(NV20_OFFSET0, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(NV20_OFFSET1, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(NV20_OFFSET2, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + ACCW(NV20_OFFSET3, ((uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer)); + + /* setup buffer pitch */ + ACCW(NV20_PITCH0, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(NV20_PITCH1, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(NV20_PITCH2, (si->fbc.bytes_per_row & 0x0000ffff)); + ACCW(NV20_PITCH3, (si->fbc.bytes_per_row & 0x0000ffff)); + break; + } + + /*** setup tile and pipe stuff ***/ + if (si->ps.card_arch >= NV10A) + { +/* + fixme: setup elsewhere (does not belong here): + chip->PRAMDAC[0x00000404/4] |= (1 << 25);//0x00680404 = ??? +*/ + + /* setup acc engine tile stuff: */ + /* reset tile adresses */ + ACCW(NV10_FBTIL0AD, 0); + ACCW(NV10_FBTIL1AD, 0); + ACCW(NV10_FBTIL2AD, 0); + ACCW(NV10_FBTIL3AD, 0); + ACCW(NV10_FBTIL4AD, 0); + ACCW(NV10_FBTIL5AD, 0); + ACCW(NV10_FBTIL6AD, 0); + ACCW(NV10_FBTIL7AD, 0); + /* copy tile setup stuff from 'source' to acc engine */ + if (si->ps.card_arch >= NV20A) + { + /* unknown: */ + ACCW(NV20_WHAT0, ACCR(NV20_FBWHAT0)); + ACCW(NV20_WHAT1, ACCR(NV20_FBWHAT1)); + } + /* tile 0: */ + /* tile invalid, tile adress = $00000 (18bit) */ + ACCW(NV10_TIL0AD, ACCR(NV10_FBTIL0AD)); + /* set tile end adress (18bit) */ + ACCW(NV10_TIL0ED, ACCR(NV10_FBTIL0ED)); + /* set tile size pitch (8bit: b8-15) */ + ACCW(NV10_TIL0PT, ACCR(NV10_FBTIL0PT)); + /* set tile status */ + ACCW(NV10_TIL0ST, ACCR(NV10_FBTIL0ST)); + /* tile 1: */ + ACCW(NV10_TIL1AD, ACCR(NV10_FBTIL1AD)); + ACCW(NV10_TIL1ED, ACCR(NV10_FBTIL1ED)); + ACCW(NV10_TIL1PT, ACCR(NV10_FBTIL1PT)); + ACCW(NV10_TIL1ST, ACCR(NV10_FBTIL1ST)); + /* tile 2: */ + ACCW(NV10_TIL2AD, ACCR(NV10_FBTIL2AD)); + ACCW(NV10_TIL2ED, ACCR(NV10_FBTIL2ED)); + ACCW(NV10_TIL2PT, ACCR(NV10_FBTIL2PT)); + ACCW(NV10_TIL2ST, ACCR(NV10_FBTIL2ST)); + /* tile 3: */ + ACCW(NV10_TIL3AD, ACCR(NV10_FBTIL3AD)); + ACCW(NV10_TIL3ED, ACCR(NV10_FBTIL3ED)); + ACCW(NV10_TIL3PT, ACCR(NV10_FBTIL3PT)); + ACCW(NV10_TIL3ST, ACCR(NV10_FBTIL3ST)); + /* tile 4: */ + ACCW(NV10_TIL4AD, ACCR(NV10_FBTIL4AD)); + ACCW(NV10_TIL4ED, ACCR(NV10_FBTIL4ED)); + ACCW(NV10_TIL4PT, ACCR(NV10_FBTIL4PT)); + ACCW(NV10_TIL4ST, ACCR(NV10_FBTIL4ST)); + /* tile 5: */ + ACCW(NV10_TIL5AD, ACCR(NV10_FBTIL5AD)); + ACCW(NV10_TIL5ED, ACCR(NV10_FBTIL5ED)); + ACCW(NV10_TIL5PT, ACCR(NV10_FBTIL5PT)); + ACCW(NV10_TIL5ST, ACCR(NV10_FBTIL5ST)); + /* tile 6: */ + ACCW(NV10_TIL6AD, ACCR(NV10_FBTIL6AD)); + ACCW(NV10_TIL6ED, ACCR(NV10_FBTIL6ED)); + ACCW(NV10_TIL6PT, ACCR(NV10_FBTIL6PT)); + ACCW(NV10_TIL6ST, ACCR(NV10_FBTIL6ST)); + /* tile 7: */ + ACCW(NV10_TIL7AD, ACCR(NV10_FBTIL7AD)); + ACCW(NV10_TIL7ED, ACCR(NV10_FBTIL7ED)); + ACCW(NV10_TIL7PT, ACCR(NV10_FBTIL7PT)); + ACCW(NV10_TIL7ST, ACCR(NV10_FBTIL7ST)); + + /* setup pipe */ + /* set eyetype to local, lightning is off */ + ACCW(NV10_XFMOD0, 0x10000000); + /* disable all lights */ + ACCW(NV10_XFMOD1, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00000040); + ACCW(NV10_PIPEDAT, 0x00000008); + + ACCW(NV10_PIPEADR, 0x00000200); + for (cnt = 0; cnt < (3 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00000040); + ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00000800); + for (cnt = 0; cnt < (16 * 16); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + /* turn lightning on */ + ACCW(NV10_XFMOD0, 0x30000000); + /* set light 1 to infinite type, other lights remain off */ + ACCW(NV10_XFMOD1, 0x00000004); + + ACCW(NV10_PIPEADR, 0x00006400); + for (cnt = 0; cnt < (59 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00006800); + for (cnt = 0; cnt < (47 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00006c00); + for (cnt = 0; cnt < (3 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00007000); + for (cnt = 0; cnt < (19 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00007400); + for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00007800); + for (cnt = 0; cnt < (12 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00004400); + for (cnt = 0; cnt < (8 * 4); cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00000000); + for (cnt = 0; cnt < 16; cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + + ACCW(NV10_PIPEADR, 0x00000040); + for (cnt = 0; cnt < 4; cnt++) ACCW(NV10_PIPEDAT, 0x00000000); + } + + /*** setup acceleration engine command shortcuts (so via fifo) ***/ + /* (b31 = 1 selects 'config' function?) */ + ACCW(FIFO_00800000, 0x80000000); /* Raster OPeration */ + ACCW(FIFO_00802000, 0x80000001); /* Clip */ + ACCW(FIFO_00804000, 0x80000002); /* Pattern */ + ACCW(FIFO_00806000, 0x80000010); /* Pixmap (not used) */ + ACCW(FIFO_00808000, 0x80000011); /* Blit */ + ACCW(FIFO_0080a000, 0x80000012); /* Bitmap */ + ACCW(FIFO_0080c000, 0x80000016); /* Line (not used) */ + ACCW(FIFO_0080e000, 0x80000014); /* ??? (not used) */ + + /* do first actual acceleration engine command: + * setup clipping region (workspace size) to 32768 x 32768 pixels: + * wait for room in fifo for clipping cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_CLP_FIFOFREE)) >> 2) < 2) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup clipping (writing 2 32bit words) */ + ACCW(CLP_TOPLEFT, 0x00000000); + ACCW(CLP_WIDHEIGHT, 0x80008000); + + return B_OK; +} + +/* screen to screen blit - i.e. move windows around and scroll within them. */ +status_t nv_acc_setup_blit() +{ + /* setup solid pattern: + * wait for room in fifo for pattern cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup pattern (writing 5 32bit words) */ + ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */ + ACCW(PAT_COLOR0, 0xffffffff); + ACCW(PAT_COLOR1, 0xffffffff); + ACCW(PAT_MONO1, 0xffffffff); + ACCW(PAT_MONO2, 0xffffffff); + + /* ROP3 registers (Raster OPeration): + * wait for room in fifo for ROP cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup ROP (writing 1 32bit word) */ + ACCW(ROP_ROP3, 0xcc); + + return B_OK; +} + +status_t nv_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h) +{ + /* Note: blit-copy direction is determined inside riva hardware: no setup needed */ + + /* instruct engine what to blit: + * wait for room in fifo for blit cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_BLT_FIFOFREE)) >> 2) < 3) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup blit (writing 3 32bit words) */ + ACCW(BLT_TOPLFTSRC, ((ys << 16) | xs)); + ACCW(BLT_TOPLFTDST, ((yd << 16) | xd)); + ACCW(BLT_SIZE, (((h + 1) << 16) | (w + 1))); + + return B_OK; +} + +/* rectangle fill - i.e. workspace and window background color */ +/* span fill - i.e. (selected) menuitem background color (Dano) */ +status_t nv_acc_setup_rectangle(uint32 color) +{ + /* setup solid pattern: + * wait for room in fifo for pattern cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup pattern (writing 5 32bit words) */ + ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */ + ACCW(PAT_COLOR0, 0xffffffff); + ACCW(PAT_COLOR1, 0xffffffff); + ACCW(PAT_MONO1, 0xffffffff); + ACCW(PAT_MONO2, 0xffffffff); + + /* ROP3 registers (Raster OPeration): + * wait for room in fifo for ROP cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup ROP (writing 1 32bit word) for GXcopy */ + ACCW(ROP_ROP3, 0xcc); + + /* setup fill color: + * wait for room in fifo for bitmap cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup color (writing 1 32bit word) */ + ACCW(BMP_COLOR1A, color); + + return B_OK; +} + +status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl) +{ + /* instruct engine what to fill: + * wait for room in fifo for bitmap cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup fill (writing 2 32bit words) */ + ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff))); + ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff))); + + return B_OK; +} + +/* rectangle invert - i.e. text cursor and text selection */ +status_t nv_acc_setup_rect_invert() +{ + /* setup solid pattern: + * wait for room in fifo for pattern cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_PAT_FIFOFREE)) >> 2) < 5) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup pattern (writing 5 32bit words) */ + ACCW(PAT_SHAPE, 0); /* 0 = 8x8, 1 = 64x1, 2 = 1x64 */ + ACCW(PAT_COLOR0, 0xffffffff); + ACCW(PAT_COLOR1, 0xffffffff); + ACCW(PAT_MONO1, 0xffffffff); + ACCW(PAT_MONO2, 0xffffffff); + + /* ROP3 registers (Raster OPeration): + * wait for room in fifo for ROP cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_ROP_FIFOFREE)) >> 2) < 1) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup ROP (writing 1 32bit word) for GXinvert */ + ACCW(ROP_ROP3, 0x55); + + /* reset fill color: + * wait for room in fifo for bitmap cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 1) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now reset color (writing 1 32bit word) */ + ACCW(BMP_COLOR1A, 0); + + return B_OK; +} + +status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl) +{ + /* instruct engine what to invert: + * wait for room in fifo for bitmap cmd if needed. + * (fifo holds 256 32bit words: count those, not bytes) */ + while (((NV_REG16(NV16_BMP_FIFOFREE)) >> 2) < 2) + { + /* snooze a bit so I do not hammer the bus */ + snooze (10); + } + /* now setup invert (writing 2 32bit words) */ + ACCW(BMP_UCRECTL_0, ((xs << 16) | (ys & 0x0000ffff))); + ACCW(BMP_UCRECSZ_0, (((xe - xs) << 16) | (yl & 0x0000ffff))); + + return B_OK; +} + +/* screen to screen tranparent blit */ +status_t nv_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour) +{ + //fixme: implement. + + return B_ERROR; +} + +/* screen to screen scaled filtered blit - i.e. scale video in memory */ +status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd) +{ + //fixme: implement. + + return B_ERROR; +} diff --git a/src/add-ons/accelerants/skeleton/engine/agp.c b/src/add-ons/accelerants/skeleton/engine/agp.c new file mode 100644 index 0000000000..d3ab459784 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/agp.c @@ -0,0 +1,216 @@ +/* Author: + Rudolf Cornelissen 6/2004-9/2004 +*/ + +#define MODULE_BIT 0x00000100 + +#include +#include "nv_std.h" + +static void nv_agp_list_info(agp_info ai); +static void nv_agp_list_active(uint32 cmd); + +status_t nv_agp_setup(void) +{ + nv_nth_agp_info nai; + nv_cmd_agp nca; + uint8 index; + agp_info nv_ai; + bool agp = false; + + /* first try to enable FW support on our card if user requested this + * ('unsupported' tweak!) + * This has no effect on PCI cards. */ + if (si->settings.unhide_fw) + { + uint32 reg; + + LOG(4, ("AGP: STRAPINFO2 contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2))); + + LOG(4, ("AGP: attempting to enable fastwrite support..\n")); + /* 'force' FW support */ + reg = (NV_REG32(NV32_NVSTRAPINFO2) & ~0x00000800); + /* enable strapinfo overwrite */ + NV_REG32(NV32_NVSTRAPINFO2) = (reg | 0x80000000); + + LOG(4, ("AGP: STRAPINFO2 now contains $%08x\n", NV_REG32(NV32_NVSTRAPINFO2))); + } + + /* set the magic number so the nvidia kerneldriver knows we're for real */ + nca.magic = nai.magic = NV_PRIVATE_DATA_MAGIC; + + /* contact driver and get a pointer to the registers and shared data */ + for (index = 0; index < 8; index++) + { + /* get nth AGP device info */ + nai.index = index; + ioctl(fd, NV_GET_NTH_AGP_INFO, &nai, sizeof(nai)); + + /* abort if no agp busmanager found */ + if (!nai.agp_bus) + { + LOG(4,("AGP: no AGP busmanager found.\n")); + /* don't touch AGP command register, we don't know what has been setup: + * touching it anyway might 'hang' the graphics card! */ + + return B_ERROR; + } + + /* exit if we didn't get device info for this index */ + if (!nai.exist) + { + if (index != 0) + LOG(4,("AGP: end of AGP capable devices list.\n")); + else + LOG(4,("AGP: no AGP capable devices found.\n")); + break; + } + + LOG(4,("AGP: AGP capable device #%d:\n", (index + 1))); + + /* see if we are this one */ + if ((nai.agpi.device_id == si->device_id) && + (nai.agpi.vendor_id == si->vendor_id) && + (nai.agpi.bus == si->bus) && + (nai.agpi.device == si->device) && + (nai.agpi.function == si->function)) + { + LOG(4,("AGP: (this is the device this accelerant controls)\n")); + agp = true; + /* remember our info */ + nv_ai = nai.agpi; + } + + /* log capabilities */ + nv_agp_list_info(nai.agpi); + } + + /* if our card is not an AGP type, abort here */ + /* Note: + * We have to iterate through the capability list as specified in the PCI spec + * one way or the other, otherwise we cannot distinquish between nVidia PCI and + * AGP type cards as nVidia PCI cards still have AGP registers that pretend to + * support AGP. + * We rely on the AGP busmanager to iterate trough this list for us. */ + if (!agp) + { + LOG(4,("AGP: the graphicscard this accelerant controls is PCI type.\n")); + + /* make sure card is set for PCI access */ + CFGW(AGPCMD, 0x00000000); + + return B_ERROR; + } + + if (si->settings.force_pci) + { + /* set PCI mode if specified by user in nv.settings */ + LOG(4,("AGP: forcing PCI mode (specified in nv.settings)\n")); + + /* let the AGP busmanager setup PCI mode. + * (the AGP speed scheme is of no consequence now) */ + nca.cmd = 0x00000000; + ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca)); + } + else + { + /* activate AGP mode */ + LOG(4,("AGP: activating AGP mode...\n")); + + /* let the AGP busmanager worry about what mode to set.. */ + nca.cmd = 0xfffffff7; + /* ..but we do need to select the right speed scheme fetched from our card */ + if (nv_ai.interface.agp_stat & AGP_rate_rev) nca.cmd |= AGP_rate_rev; + ioctl(fd, NV_ENABLE_AGP, &nca, sizeof(nca)); + } + + /* list mode now activated, + * make sure we have the correct speed scheme for logging */ + nv_agp_list_active(nca.cmd | (nv_ai.interface.agp_stat & AGP_rate_rev)); + + /* extra check */ + LOG(4,("AGP: graphics card AGPCMD register readback $%08x\n", CFGR(AGPCMD))); + return B_OK; +} + +static void nv_agp_list_info(agp_info ai) +{ + /* + list device + */ + if (ai.class_base == PCI_display) + LOG(4,("AGP: device is a graphicscard, subclass ID is $%02x\n", ai.class_sub)); + else + LOG(4,("AGP: device is a hostbridge, subclass ID is $%02x\n", ai.class_sub)); + LOG(4,("AGP: vendor ID $%04x\n", ai.vendor_id)); + LOG(4,("AGP: device ID $%04x\n", ai.device_id)); + LOG(4,("AGP: bus %d, device %d, function %d\n", ai.bus, ai.device, ai.function)); + + /* + list capabilities + */ + LOG(4,("AGP: this device supports AGP specification %d.%d;\n", + ((ai.interface.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift), + ((ai.interface.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift))); + + /* the AGP devices determine AGP speed scheme version used on power-up/reset */ + if (!(ai.interface.agp_stat & AGP_rate_rev)) + { + /* AGP 2.0 scheme applies */ + if (ai.interface.agp_stat & AGP_2_1x) + LOG(4,("AGP: AGP 2.0 1x mode is available\n")); + if (ai.interface.agp_stat & AGP_2_2x) + LOG(4,("AGP: AGP 2.0 2x mode is available\n")); + if (ai.interface.agp_stat & AGP_2_4x) + LOG(4,("AGP: AGP 2.0 4x mode is available\n")); + } + else + { + /* AGP 3.0 scheme applies */ + if (ai.interface.agp_stat & AGP_3_4x) + LOG(4,("AGP: AGP 3.0 4x mode is available\n")); + if (ai.interface.agp_stat & AGP_3_8x) + LOG(4,("AGP: AGP 3.0 8x mode is available\n")); + } + if (ai.interface.agp_stat & AGP_FW) LOG(4,("AGP: fastwrite transfers are supported\n")); + if (ai.interface.agp_stat & AGP_SBA) LOG(4,("AGP: sideband adressing is supported\n")); + LOG(4,("AGP: %d queued AGP requests can be handled.\n", + (((ai.interface.agp_stat & AGP_RQ) >> AGP_RQ_shift) + 1))); + + /* + list current settings, + make sure we have the correct speed scheme for logging + */ + nv_agp_list_active(ai.interface.agp_cmd | (ai.interface.agp_stat & AGP_rate_rev)); +} + +static void nv_agp_list_active(uint32 cmd) +{ + LOG(4,("AGP: listing settings now in use:\n")); + if (!(cmd & AGP_rate_rev)) + { + /* AGP 2.0 scheme applies */ + if (cmd & AGP_2_1x) + LOG(4,("AGP: AGP 2.0 1x mode is set\n")); + if (cmd & AGP_2_2x) + LOG(4,("AGP: AGP 2.0 2x mode is set\n")); + if (cmd & AGP_2_4x) + LOG(4,("AGP: AGP 2.0 4x mode is set\n")); + } + else + { + /* AGP 3.0 scheme applies */ + if (cmd & AGP_3_4x) + LOG(4,("AGP: AGP 3.0 4x mode is set\n")); + if (cmd & AGP_3_8x) + LOG(4,("AGP: AGP 3.0 8x mode is set\n")); + } + if (cmd & AGP_FW) LOG(4,("AGP: fastwrite transfers are enabled\n")); + if (cmd & AGP_SBA) LOG(4,("AGP: sideband adressing is enabled\n")); + LOG(4,("AGP: max. AGP queued request depth is set to %d\n", + (((cmd & AGP_RQ) >> AGP_RQ_shift) + 1))); + if (cmd & AGP_enable) + LOG(4,("AGP: the AGP interface is enabled.\n")); + else + LOG(4,("AGP: the AGP interface is disabled.\n")); +} diff --git a/src/add-ons/accelerants/skeleton/engine/bes.c b/src/add-ons/accelerants/skeleton/engine/bes.c new file mode 100644 index 0000000000..da2988edc7 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/bes.c @@ -0,0 +1,868 @@ +/* Nvidia TNT and GeForce Back End Scaler functions */ +/* Written by Rudolf Cornelissen 05/2002-9/2004 */ + +#define MODULE_BIT 0x00000200 + +#include "nv_std.h" + +typedef struct move_overlay_info move_overlay_info; + +struct move_overlay_info +{ + uint32 hcoordv; /* left and right edges of video output window */ + uint32 vcoordv; /* top and bottom edges of video output window */ + uint32 hsrcstv; /* horizontal source start in source buffer (clipping) */ + uint32 v1srcstv; /* vertical source start in source buffer (clipping) */ + uint32 a1orgv; /* alternate source clipping via startadress of source buffer */ +}; + +static void nv_bes_calc_move_overlay(move_overlay_info *moi); +static void nv_bes_program_move_overlay(move_overlay_info moi); + +/* move the overlay output window in virtualscreens */ +/* Note: + * si->dm.h_display_start and si->dm.v_display_start determine where the new + * output window is located! */ +void nv_bes_move_overlay() +{ + move_overlay_info moi; + + /* abort if overlay is not active */ + if (!si->overlay.active) return; + + nv_bes_calc_move_overlay(&moi); + nv_bes_program_move_overlay(moi); +} + +static void nv_bes_calc_move_overlay(move_overlay_info *moi) +{ + /* misc used variables */ + uint16 temp1, temp2; + /* visible screen window in virtual workspaces */ + uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend; + + /* do 'overlay follow head' in dualhead modes on dualhead cards */ + if (si->ps.secondary_head) + { + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if ((si->overlay.ow.h_start + (si->overlay.ow.width / 2)) < + (si->dm.h_display_start + si->dm.timing.h_display)) + nv_bes_to_crtc(si->crtc_switch_mode); + else + nv_bes_to_crtc(!si->crtc_switch_mode); + break; + default: + nv_bes_to_crtc(si->crtc_switch_mode); + break; + } + } + + /* the BES does not respect virtual_workspaces, but adheres to CRTC + * constraints only */ + crtc_hstart = si->dm.h_display_start; + /* make dualhead stretch and switch mode work while we're at it.. */ + if (si->overlay.crtc) + { + crtc_hstart += si->dm.timing.h_display; + } + + /* horizontal end is the first position beyond the displayed range on the CRTC */ + crtc_hend = crtc_hstart + si->dm.timing.h_display; + crtc_vstart = si->dm.v_display_start; + /* vertical end is the first position beyond the displayed range on the CRTC */ + crtc_vend = crtc_vstart + si->dm.timing.v_display; + + + /**************************************** + *** setup all edges of output window *** + ****************************************/ + + /* setup left and right edges of output window */ + moi->hcoordv = 0; + /* left edge coordinate of output window, must be inside desktop */ + /* clipping on the left side */ + if (si->overlay.ow.h_start < crtc_hstart) + { + temp1 = 0; + } + else + { + /* clipping on the right side */ + if (si->overlay.ow.h_start >= (crtc_hend - 1)) + { + /* width < 2 is not allowed */ + temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (si->overlay.ow.h_start - crtc_hstart) & 0x7ff; + } + } + moi->hcoordv |= temp1 << 16; + /* right edge coordinate of output window, must be inside desktop */ + /* width < 2 is not allowed */ + if (si->overlay.ow.width < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the right side */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1)) + { + temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff; + } + else + { + /* clipping on the left side */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1)) + { + /* width < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(si->overlay.ow.h_start + si->overlay.ow.width - crtc_hstart - 1)) & 0x7ff; + } + } + } + moi->hcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2)); + + /* setup top and bottom edges of output window */ + moi->vcoordv = 0; + /* top edge coordinate of output window, must be inside desktop */ + /* clipping on the top side */ + if (si->overlay.ow.v_start < crtc_vstart) + { + temp1 = 0; + } + else + { + /* clipping on the bottom side */ + if (si->overlay.ow.v_start >= (crtc_vend - 1)) + { + /* height < 2 is not allowed */ + temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (si->overlay.ow.v_start - crtc_vstart) & 0x7ff; + } + } + moi->vcoordv |= temp1 << 16; + /* bottom edge coordinate of output window, must be inside desktop */ + /* height < 2 is not allowed */ + if (si->overlay.ow.height < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the bottom side */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1)) + { + temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff; + } + else + { + /* clipping on the top side */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1)) + { + /* height < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(si->overlay.ow.v_start + si->overlay.ow.height - crtc_vstart - 1)) & 0x7ff; + } + } + } + moi->vcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2)); + + + /********************************* + *** setup horizontal clipping *** + *********************************/ + + /* Setup horizontal source start: first (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the left starting position of the bitmap's view (zoom function) to get the final value needed. + * Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + moi->hsrcstv = 0; + /* check for destination horizontal clipping at left side */ + if (si->overlay.ow.h_start < crtc_hstart) + { + /* check if entire destination picture is clipping left: + * (2 pixels will be clamped onscreen at least) */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1)) + { + /* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */ + moi->hsrcstv += (si->overlay.ow.width - 2); + } + else + { + /* increase 'first contributing pixel' with actual number of dest. clipping pixels */ + moi->hsrcstv += (crtc_hstart - si->overlay.ow.h_start); + } + LOG(4,("Overlay: clipping left...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + moi->hsrcstv *= si->overlay.h_ifactor; + } + /* take zoom into account */ + moi->hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16; + /* AND below required by hardware */ + moi->hsrcstv &= 0x03fffffc; + LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", moi->hsrcstv / (float)65536)); + + + /******************************* + *** setup vertical clipping *** + *******************************/ + + /* calculate inputbitmap origin adress */ + moi->a1orgv = (uint32)((vuint32 *)si->overlay.ob.buffer); + moi->a1orgv -= (uint32)((vuint32 *)si->framebuffer); + + /* Setup vertical source start: first (sub)pixel contributing to output picture. */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * 'After' this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + + moi->v1srcstv = 0; + /* check for destination vertical clipping at top side */ + if (si->overlay.ow.v_start < crtc_vstart) + { + /* check if entire destination picture is clipping at top: + * (2 pixels will be clamped onscreen at least) */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1)) + { + /* increase 'number of clipping pixels' with 'fixed value': + * 'total height - 2' of dest. picture in pixels * inverse scaling factor */ + moi->v1srcstv = (si->overlay.ow.height - 2) * si->overlay.v_ifactor; + /* on pre-NV10 we need to do clipping in the source + * bitmap because no seperate clipping registers exist... */ + if (si->ps.card_arch < NV10A) + moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row); + } + else + { + /* increase 'first contributing pixel' with: + * number of destination picture clipping pixels * inverse scaling factor */ + moi->v1srcstv = (crtc_vstart - si->overlay.ow.v_start) * si->overlay.v_ifactor; + /* on pre-NV10 we need to do clipping in the source + * bitmap because no seperate clipping registers exist... */ + if (si->ps.card_arch < NV10A) + moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row); + } + LOG(4,("Overlay: clipping at top...\n")); + } + /* take zoom into account */ + moi->v1srcstv += (((uint32)si->overlay.my_ov.v_start) << 16); + if (si->ps.card_arch < NV10A) + { + moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row); + LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv)); + } + LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", moi->v1srcstv / (float)65536)); + + /* AND below is probably required by hardware. */ + /* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */ + moi->a1orgv &= 0xfffffff0; + LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv)); +} + +static void nv_bes_program_move_overlay(move_overlay_info moi) +{ + /************************************* + *** sync to BES (Back End Scaler) *** + *************************************/ + + /* Done in card hardware: + * double buffered registers + trigger if programming complete feature. */ + + + /************************************** + *** actually program the registers *** + **************************************/ + + if (si->ps.card_arch < NV10A) + { + /* unknown, but needed (otherwise high-res distortions and only half the frames */ + BESW(NV04_OE_STATE, 0x00000000); + /* select buffer 0 as active (b16) */ + BESW(NV04_SU_STATE, 0x00000000); + /* unknown (no effect?) */ + BESW(NV04_RM_STATE, 0x00000000); + /* setup clipped(!) buffer startadress in RAM */ + /* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping + * either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */ + /* (program both buffers to prevent sync distortions) */ + /* first include 'pixel precise' left clipping... (top clipping was already included) */ + moi.a1orgv += ((moi.hsrcstv >> 16) * 2); + /* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */ + BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03)); + BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03)); + /* setup output window position */ + BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16))); + /* setup output window size */ + BESW(NV04_DSTSIZE, ( + (((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) | + ((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1) + )); + /* select buffer 1 as active (b16) */ + BESW(NV04_SU_STATE, 0x00010000); + } + else + { + /* >= NV10A */ + + /* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */ + BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff)); + /* setup output window position */ + BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16))); + /* setup output window size */ + BESW(NV10_0DSTSIZE, ( + (((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) | + ((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1) + )); + /* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */ + /* This also triggers activation of programmed values (double buffered registers feature) */ + BESW(NV10_BUFSEL, 0x00000001); + } +} + +status_t nv_bes_to_crtc(bool crtc) +{ + if (si->ps.secondary_head) + { + if (crtc) + { + LOG(4,("Overlay: switching overlay to CRTC2\n")); + /* switch overlay engine to CRTC2 */ + NV_REG32(NV32_FUNCSEL) &= ~0x00001000; + NV_REG32(NV32_2FUNCSEL) |= 0x00001000; + si->overlay.crtc = !si->crtc_switch_mode; + } + else + { + LOG(4,("Overlay: switching overlay to CRTC1\n")); + /* switch overlay engine to CRTC1 */ + NV_REG32(NV32_2FUNCSEL) &= ~0x00001000; + NV_REG32(NV32_FUNCSEL) |= 0x00001000; + si->overlay.crtc = si->crtc_switch_mode; + } + return B_OK; + } + else + { + return B_ERROR; + } +} + +status_t nv_bes_init() +{ + if (si->ps.card_arch < NV10A) + { + /* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */ + BESW(NV04_INTE, 0x00000000); + + /* setup saturation to be 'neutral' */ + BESW(NV04_SAT, 0x00000000); + /* setup RGB brightness to be 'neutral' */ + BESW(NV04_RED_AMP, 0x00000069); + BESW(NV04_GRN_AMP, 0x0000003e); + BESW(NV04_BLU_AMP, 0x00000089); + + /* setup fifo for fetching data */ + BESW(NV04_FIFOBURL, 0x00000003); + BESW(NV04_FIFOTHRS, 0x00000038); + + /* unknown, but needed (registers only have b0 implemented) */ + /* (program both buffers to prevent sync distortions) */ + BESW(NV04_0OFFSET, 0x00000000); + BESW(NV04_1OFFSET, 0x00000000); + } + else + { + /* >= NV10A */ + + /* disable overlay ints (b0 = buffer 0, b4 = buffer 1) */ + BESW(NV10_INTE, 0x00000000); + /* shut off GeForce4MX MPEG2 decoder */ + BESW(DEC_GENCTRL, 0x00000000); + /* setup BES memory-range mask */ + BESW(NV10_0MEMMASK, (si->ps.memory_size - 1)); + /* unknown, but needed */ + BESW(NV10_0OFFSET, 0x00000000); + + /* setup brightness, contrast and saturation to be 'neutral' */ + BESW(NV10_0BRICON, ((0x1000 << 16) | 0x1000)); + BESW(NV10_0SAT, ((0x0000 << 16) | 0x1000)); + } + + return B_OK; +} + +status_t nv_configure_bes + (const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset) +{ + /* yuy2 (4:2:2) colorspace calculations */ + + /* Note: + * in BeOS R5.0.3 and DANO: + * 'ow->offset_xxx' is always 0, so not used; + * 'ow->width' and 'ow->height' are the output window size: does not change + * if window is clipping; + * 'ow->h_start' and 'ow->v_start' are the left-top position of the output + * window. These values can be negative: this means the window is clipping + * at the left or the top of the display, respectively. */ + + /* 'ov' is the view in the source bitmap, so which part of the bitmap is actually + * displayed on screen. This is used for the 'hardware zoom' function. */ + + /* output window position and clipping info for source buffer */ + move_overlay_info moi; + /* calculated BES register values */ + uint32 hiscalv, viscalv; + /* interval representation, used for scaling calculations */ + uint16 intrep; + /* inverse scaling factor, used for source positioning */ + uint32 ifactor; + /* copy of overlay view which has checked valid values */ + overlay_view my_ov; + + + /************************************************************************************** + *** copy, check and limit if needed the user-specified view into the intput bitmap *** + **************************************************************************************/ + my_ov = *ov; + /* check for valid 'coordinates' */ + if (my_ov.width == 0) my_ov.width++; + if (my_ov.height == 0) my_ov.height++; + if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1)) + my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1); + if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1)) + my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1); + if (my_ov.v_start > (ob->height - 1)) + my_ov.v_start = (ob->height - 1); + if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1)) + my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1); + + LOG(4,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n", + my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height)); + + /* save for nv_bes_calc_move_overlay() */ + si->overlay.ow = *ow; + si->overlay.ob = *ob; + si->overlay.my_ov = my_ov; + + + /******************************** + *** setup horizontal scaling *** + ********************************/ + LOG(4,("Overlay: total input picture width = %d, height = %d\n", + (ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height)); + LOG(4,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height)); + + /* determine interval representation value, taking zoom into account */ + if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) + { + /* horizontal filtering is ON */ + if ((my_ov.width == ow->width) | (ow->width < 2)) + { + /* no horizontal scaling used, OR destination width < 2 */ + intrep = 0; + } + else + { + intrep = 1; + } + } + else + { + /* horizontal filtering is OFF */ + if ((ow->width < my_ov.width) & (ow->width >= 2)) + { + /* horizontal downscaling used AND destination width >= 2 */ + intrep = 1; + } + else + { + intrep = 0; + } + } + LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep)); + + /* calculate inverse horizontal scaling factor, taking zoom into account */ + /* standard scaling formula: */ + ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep); + + /* correct factor to prevent most-right visible 'line' from distorting */ + ifactor -= (1 << 2); + hiscalv = ifactor; + /* save for nv_bes_calc_move_overlay() */ + si->overlay.h_ifactor = ifactor; + LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor)); + + /* check scaling factor (and modify if needed) to be within scaling limits */ + /* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */ + if (hiscalv < 0x00002000) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + hiscalv = 0x00002000; + LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv)); + } + switch (si->ps.card_arch) + { + case NV04A: + /* Riva128-TNT2 series have a 'downscaling' limit of 1.000489 + * (16bit register with 0.11 format value) */ + if (hiscalv > 0x0000ffff) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + hiscalv = 0x0000ffff; + LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)2048 / (hiscalv >> 5))); + } + break; + case NV30A: + case NV40A: + /* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */ + if ((hiscalv > (2 << 16)) && (si->ps.card_type != NV31)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + hiscalv = (2 << 16); + LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv)); + } + /* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + default: + /* the rest has a downscaling limit of 0.125 */ + if (hiscalv > (8 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + hiscalv = (8 << 16); + LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv)); + } + break; + } + /* AND below is required by hardware */ + hiscalv &= 0x001ffffc; + + + /****************************** + *** setup vertical scaling *** + ******************************/ + + /* determine interval representation value, taking zoom into account */ + if (ow->flags & B_OVERLAY_VERTICAL_FILTERING) + { + /* vertical filtering is ON */ + if ((my_ov.height == ow->height) | (ow->height < 2)) + { + /* no vertical scaling used, OR destination height < 2 */ + intrep = 0; + } + else + { + intrep = 1; + } + } + else + { + /* vertical filtering is OFF */ + if ((ow->height < my_ov.height) & (ow->height >= 2)) + { + /* vertical downscaling used AND destination height >= 2 */ + intrep = 1; + } + else + { + intrep = 0; + } + } + LOG(4,("Overlay: vertical interval representation value is %d\n",intrep)); + + /* calculate inverse vertical scaling factor, taking zoom into account */ + /* standard scaling formula: */ + ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep); + + /* correct factor to prevent lowest visible line from distorting */ + ifactor -= (1 << 2); + LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor)); + + /* preserve ifactor for source positioning calculations later on */ + viscalv = ifactor; + /* save for nv_bes_calc_move_overlay() */ + si->overlay.v_ifactor = ifactor; + + /* check scaling factor (and modify if needed) to be within scaling limits */ + /* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */ + if (viscalv < 0x00002000) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + viscalv = 0x00002000; + LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv)); + } + switch (si->ps.card_arch) + { + case NV04A: + /* Riva128-TNT2 series have a 'downscaling' limit of 1.000489 + * (16bit register with 0.11 format value) */ + if (viscalv > 0x0000ffff) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + viscalv = 0x0000ffff; + LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)2048 / (viscalv >> 5))); + } + break; + case NV30A: + case NV40A: + /* GeForceFX series and up have a downscaling limit of 0.5 (except NV31!) */ + if ((viscalv > (2 << 16)) && (si->ps.card_type != NV31)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + viscalv = (2 << 16); + LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv)); + } + /* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + default: + /* the rest has a downscaling limit of 0.125 */ + if (viscalv > (8 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + viscalv = (8 << 16); + LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv)); + } + break; + } + /* AND below is required by hardware */ + viscalv &= 0x001ffffc; + + + /******************************************************************************** + *** setup all edges of output window, setup horizontal and vertical clipping *** + ********************************************************************************/ + nv_bes_calc_move_overlay(&moi); + + + /***************************** + *** log color keying info *** + *****************************/ + + LOG(4,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n", + ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value)); + LOG(4,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n", + ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask)); + + + /***************** + *** log flags *** + *****************/ + + LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags)); + /* BTW: horizontal and vertical filtering are fixed and turned on for GeForce overlay. */ + + + /************************************* + *** sync to BES (Back End Scaler) *** + *************************************/ + + /* Done in card hardware: + * double buffered registers + trigger if programming complete feature. */ + + + /************************************** + *** actually program the registers *** + **************************************/ + + if (si->ps.card_arch < NV10A) + { + /* unknown, but needed (otherwise high-res distortions and only half the frames */ + BESW(NV04_OE_STATE, 0x00000000); + /* select buffer 0 as active (b16) */ + BESW(NV04_SU_STATE, 0x00000000); + /* unknown (no effect?) */ + BESW(NV04_RM_STATE, 0x00000000); + /* setup clipped(!) buffer startadress in RAM */ + /* RIVA128 - TNT bes doesn't have clipping registers, so no subpixelprecise clipping + * either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */ + /* (program both buffers to prevent sync distortions) */ + /* first include 'pixel precise' left clipping... (top clipping was already included) */ + moi.a1orgv += ((moi.hsrcstv >> 16) * 2); + /* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */ + BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03)); + BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03)); + /* setup buffer source pitch including slopspace (in bytes). + * Note: + * source pitch granularity = 16 pixels on the RIVA128 - TNT (so pre-NV10) bes */ + /* (program both buffers to prevent sync distortions) */ + BESW(NV04_0SRCPTCH, (ob->width * 2)); + BESW(NV04_1SRCPTCH, (ob->width * 2)); + /* setup output window position */ + BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16))); + /* setup output window size */ + BESW(NV04_DSTSIZE, ( + (((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) | + ((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1) + )); + /* setup horizontal and vertical scaling */ + BESW(NV04_ISCALVH, (((viscalv << 16) >> 5) | (hiscalv >> 5))); + /* enable vertical filtering (b0) */ + BESW(NV04_CTRL_V, 0x00000001); + /* enable horizontal filtering (no effect?) */ + BESW(NV04_CTRL_H, 0x00000111); + + /* enable BES (b0), enable colorkeying (b4), format yuy2 (b8: 0 = ccir) */ + BESW(NV04_GENCTRL, 0x00000111); + /* select buffer 1 as active (b16) */ + BESW(NV04_SU_STATE, 0x00010000); + + /************************** + *** setup color keying *** + **************************/ + + /* setup colorkeying */ + switch(si->dm.space) + { + case B_RGB15_LITTLE: + BESW(NV04_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 5) | + ((ow->red.value & ow->red.mask) << 10) | + ((ow->alpha.value & ow->alpha.mask) << 15) + )); + break; + case B_RGB16_LITTLE: + BESW(NV04_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 5) | + ((ow->red.value & ow->red.mask) << 11) + /* this space has no alpha bits */ + )); + break; + case B_CMAP8: + case B_RGB32_LITTLE: + default: + BESW(NV04_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 8) | + ((ow->red.value & ow->red.mask) << 16) | + ((ow->alpha.value & ow->alpha.mask) << 24) + )); + break; + } + } + else + { + /* >= NV10A */ + + /* setup buffer origin: GeForce uses subpixel precise clipping on left and top! (12.4 values) */ + BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff)); + /* setup buffersize */ + //fixme if needed: width must be even officially... + BESW(NV10_0SRCSIZE, ((ob->height << 16) | ob->width)); + /* setup source pitch including slopspace (in bytes), + * b16: select YUY2 (0 = YV12), b20: use colorkey, b24: no iturbt_709 (do iturbt_601) */ + /* Note: + * source pitch granularity = 32 pixels on GeForce cards!! */ + BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (1 << 20) | (0 << 24))); + /* setup output window position */ + BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16))); + /* setup output window size */ + BESW(NV10_0DSTSIZE, ( + (((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) | + ((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1) + )); + /* setup horizontal scaling */ + BESW(NV10_0ISCALH, (hiscalv << 4)); + /* setup vertical scaling */ + BESW(NV10_0ISCALV, (viscalv << 4)); + /* setup (unclipped!) buffer startadress in RAM */ + BESW(NV10_0BUFADR, moi.a1orgv); + /* enable BES (b0 = 0) */ + BESW(NV10_GENCTRL, 0x00000000); + /* We only use buffer buffer 0: select it. (0x01 = buffer 0, 0x10 = buffer 1) */ + /* This also triggers activation of programmed values (double buffered registers feature) */ + BESW(NV10_BUFSEL, 0x00000001); + + /************************** + *** setup color keying *** + **************************/ + + /* setup colorkeying */ + switch(si->dm.space) + { + case B_RGB15_LITTLE: + BESW(NV10_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 5) | + ((ow->red.value & ow->red.mask) << 10) | + ((ow->alpha.value & ow->alpha.mask) << 15) + )); + break; + case B_RGB16_LITTLE: + BESW(NV10_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 5) | + ((ow->red.value & ow->red.mask) << 11) + /* this space has no alpha bits */ + )); + break; + case B_CMAP8: + case B_RGB32_LITTLE: + default: + BESW(NV10_COLKEY, ( + ((ow->blue.value & ow->blue.mask) << 0) | + ((ow->green.value & ow->green.mask) << 8) | + ((ow->red.value & ow->red.mask) << 16) | + ((ow->alpha.value & ow->alpha.mask) << 24) + )); + break; + } + } + + /* note that overlay is in use (for nv_bes_move_overlay()) */ + si->overlay.active = true; + + return B_OK; +} + +status_t nv_release_bes() +{ + if (si->ps.card_arch < NV10A) + { + /* setup BES control: disable scaler (b0 = 0) */ + BESW(NV04_GENCTRL, 0x00000000); + } + else + { + /* setup BES control: disable scaler (b0 = 1) */ + BESW(NV10_GENCTRL, 0x00000001); + } + + /* note that overlay is not in use (for nv_bes_move_overlay()) */ + si->overlay.active = false; + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/crtc.c b/src/add-ons/accelerants/skeleton/engine/crtc.c new file mode 100644 index 0000000000..0cd2eeb986 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/crtc.c @@ -0,0 +1,829 @@ +/* CTRC functionality */ +/* Author: + Rudolf Cornelissen 11/2002-9/2004 +*/ + +#define MODULE_BIT 0x00040000 + +#include "nv_std.h" + +/*Adjust passed parameters to a valid mode line*/ +status_t nv_crtc_validate_timing( + uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, + uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt +) +{ +/* horizontal */ + /* make all parameters multiples of 8 */ + *hd_e &= 0xfff8; + *hs_s &= 0xfff8; + *hs_e &= 0xfff8; + *ht &= 0xfff8; + + /* confine to required number of bits, taking logic into account */ + if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3); + if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3); + if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3); + if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3); + + /* NOTE: keep horizontal timing at multiples of 8! */ + /* confine to a reasonable width */ + if (*hd_e < 640) *hd_e = 640; + if (si->ps.card_type > NV04) + { + if (*hd_e > 2048) *hd_e = 2048; + } + else + { + if (*hd_e > 1920) *hd_e = 1920; + } + + /* if hor. total does not leave room for a sensible sync pulse, increase it! */ + if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); + + /* if hor. total does not adhere to max. blanking pulse width, decrease it! */ + if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8); + + /* make sure sync pulse is not during display */ + if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); + if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); + + /* correct sync pulse if it is too long: + * there are only 5 bits available to save this in the card registers! */ + if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); + +/*vertical*/ + /* confine to required number of bits, taking logic into account */ + //fixme if needed: on GeForce cards there are 12 instead of 11 bits... + if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); + if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); + if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; + if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); + + /* confine to a reasonable height */ + if (*vd_e < 480) *vd_e = 480; + if (si->ps.card_type > NV04) + { + if (*vd_e > 1536) *vd_e = 1536; + } + else + { + if (*vd_e > 1440) *vd_e = 1440; + } + + /*if vertical total does not leave room for a sync pulse, increase it!*/ + if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); + + /* if vert. total does not adhere to max. blanking pulse width, decrease it! */ + if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff); + + /* make sure sync pulse is not during display */ + if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); + if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); + + /* correct sync pulse if it is too long: + * there are only 4 bits available to save this in the card registers! */ + if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); + + return B_OK; +} + +/*set a mode line - inputs are in pixels*/ +status_t nv_crtc_set_timing(display_mode target) +{ + uint8 temp; + + uint32 htotal; /*total horizontal total VCLKs*/ + uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ + uint32 hsync_s; /*begin of horizontal sync pulse*/ + uint32 hsync_e; /*end of horizontal sync pulse*/ + uint32 hblnk_s; /*begin horizontal blanking*/ + uint32 hblnk_e; /*end horizontal blanking*/ + + uint32 vtotal; /*total vertical total scanlines*/ + uint32 vdisp_e; /*end of vertical display*/ + uint32 vsync_s; /*begin of vertical sync pulse*/ + uint32 vsync_e; /*end of vertical sync pulse*/ + uint32 vblnk_s; /*begin vertical blanking*/ + uint32 vblnk_e; /*end vertical blanking*/ + + uint32 linecomp; /*split screen and vdisp_e interrupt*/ + + LOG(4,("CRTC: setting timing\n")); + + /* setup tuned internal modeline for flatpanel if connected and active */ + /* notes: + * - the CRTC modeline must end earlier than the panel modeline to keep correct + * sync going; + * - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel + * wide horizontal stripes. This can be observed earliest on fullscreen overlay, + * and if it gets worse, also normal desktop output will suffer. The stripes + * are mainly visible at the left of the screen, over the entire screen height. */ + if (si->ps.tmds1_active) + { + LOG(2,("CRTC: DFP active: tuning modeline\n")); + + /* horizontal timing */ + target.timing.h_sync_start = + ((uint16)((si->ps.p1_timing.h_sync_start / ((float)si->ps.p1_timing.h_display)) * + target.timing.h_display)) & 0xfff8; + + target.timing.h_sync_end = + ((uint16)((si->ps.p1_timing.h_sync_end / ((float)si->ps.p1_timing.h_display)) * + target.timing.h_display)) & 0xfff8; + + target.timing.h_total = + (((uint16)((si->ps.p1_timing.h_total / ((float)si->ps.p1_timing.h_display)) * + target.timing.h_display)) & 0xfff8) - 8; + + /* in native mode the CRTC needs some extra time to keep synced correctly; + * OTOH the overlay unit distorts if we reserve too much time! */ + if (target.timing.h_display == si->ps.p1_timing.h_display) + { + /* NV11 timing has different constraints than later cards */ + if (si->ps.card_type == NV11) + target.timing.h_total -= 56; + else + /* confirmed NV34 with 1680x1050 panel */ + target.timing.h_total -= 32; + } + + if (target.timing.h_sync_start == target.timing.h_display) + target.timing.h_sync_start += 8; + if (target.timing.h_sync_end == target.timing.h_total) + target.timing.h_sync_end -= 8; + + /* vertical timing */ + target.timing.v_sync_start = + ((uint16)((si->ps.p1_timing.v_sync_start / ((float)si->ps.p1_timing.v_display)) * + target.timing.v_display)); + + target.timing.v_sync_end = + ((uint16)((si->ps.p1_timing.v_sync_end / ((float)si->ps.p1_timing.v_display)) * + target.timing.v_display)); + + target.timing.v_total = + ((uint16)((si->ps.p1_timing.v_total / ((float)si->ps.p1_timing.v_display)) * + target.timing.v_display)) - 1; + + if (target.timing.v_sync_start == target.timing.v_display) + target.timing.v_sync_start += 1; + if (target.timing.v_sync_end == target.timing.v_total) + target.timing.v_sync_end -= 1; + + /* disable GPU scaling testmode so automatic scaling will be done */ + DACW(FP_DEBUG1, 0); + } + + /* Modify parameters as required by standard VGA */ + htotal = ((target.timing.h_total >> 3) - 5); + hdisp_e = ((target.timing.h_display >> 3) - 1); + hblnk_s = hdisp_e; + hblnk_e = (htotal + 4);//0; + hsync_s = (target.timing.h_sync_start >> 3); + hsync_e = (target.timing.h_sync_end >> 3); + + vtotal = target.timing.v_total - 2; + vdisp_e = target.timing.v_display - 1; + vblnk_s = vdisp_e; + vblnk_e = (vtotal + 1); + vsync_s = target.timing.v_sync_start;//-1; + vsync_e = target.timing.v_sync_end;//-1; + + /* prevent memory adress counter from being reset (linecomp may not occur) */ + linecomp = target.timing.v_display; + + /* enable access to primary head */ + set_crtc_owner(0); + + /* Note for laptop and DVI flatpanels: + * CRTC timing has a seperate set of registers from flatpanel timing. + * The flatpanel timing registers have scaling registers that are used to match + * these two modelines. */ + { + LOG(4,("CRTC: Setting full timing...\n")); + + /* log the mode that will be set */ + LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e)); + LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e)); + + /* actually program the card! */ + /* unlock CRTC registers at index 0-7 */ + CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f)); + /* horizontal standard VGA regs */ + CRTCW(HTOTAL, (htotal & 0xff)); + CRTCW(HDISPE, (hdisp_e & 0xff)); + CRTCW(HBLANKS, (hblnk_s & 0xff)); + /* also unlock vertical retrace registers in advance */ + CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); + CRTCW(HSYNCS, (hsync_s & 0xff)); + CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); + + /* vertical standard VGA regs */ + CRTCW(VTOTAL, (vtotal & 0xff)); + CRTCW(OVERFLOW, + ( + ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | + ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | + ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | + ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) + )); + CRTCW(PRROWSCN, 0x00); /* not used */ + CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); + CRTCW(VSYNCS, (vsync_s & 0xff)); + CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f))); + CRTCW(VDISPE, (vdisp_e & 0xff)); + CRTCW(VBLANKS, (vblnk_s & 0xff)); + CRTCW(VBLANKE, (vblnk_e & 0xff)); + CRTCW(LINECOMP, (linecomp & 0xff)); + + /* horizontal extended regs */ + //fixme: we reset bit4. is this correct?? + CRTCW(HEB, (CRTCR(HEB) & 0xe0) | + ( + ((htotal & 0x100) >> (8 - 0)) | + ((hdisp_e & 0x100) >> (8 - 1)) | + ((hblnk_s & 0x100) >> (8 - 2)) | + ((hsync_s & 0x100) >> (8 - 3)) + )); + + /* (mostly) vertical extended regs */ + CRTCW(LSR, + ( + ((vtotal & 0x400) >> (10 - 0)) | + ((vdisp_e & 0x400) >> (10 - 1)) | + ((vsync_s & 0x400) >> (10 - 2)) | + ((vblnk_s & 0x400) >> (10 - 3)) | + ((hblnk_e & 0x040) >> (6 - 4)) + //fixme: we still miss one linecomp bit!?! is this it?? + //| ((linecomp & 0x400) >> 3) + )); + + /* more vertical extended regs (on GeForce cards only) */ + if (si->ps.card_arch >= NV10A) + { + CRTCW(EXTRA, + ( + ((vtotal & 0x800) >> (11 - 0)) | + ((vdisp_e & 0x800) >> (11 - 2)) | + ((vsync_s & 0x800) >> (11 - 4)) | + ((vblnk_s & 0x800) >> (11 - 6)) + //fixme: do we miss another linecomp bit!?! + )); + } + + /* setup 'large screen' mode */ + if (target.timing.h_display >= 1280) + CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb)); + else + CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04)); + + /* setup HSYNC & VSYNC polarity */ + LOG(2,("CRTC: sync polarity: ")); + temp = NV_REG8(NV8_MISCR); + if (target.timing.flags & B_POSITIVE_HSYNC) + { + LOG(2,("H:pos ")); + temp &= ~0x40; + } + else + { + LOG(2,("H:neg ")); + temp |= 0x40; + } + if (target.timing.flags & B_POSITIVE_VSYNC) + { + LOG(2,("V:pos ")); + temp &= ~0x80; + } + else + { + LOG(2,("V:neg ")); + temp |= 0x80; + } + NV_REG8(NV8_MISCW) = temp; + + LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR))); + } + + /* always disable interlaced operation */ + /* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */ + CRTCW(INTERLACE, 0xff); + + /* disable CRTC slaved mode unless a panel is in use */ + // fixme: this kills TVout when it was in use... + if (!si->ps.tmds1_active) CRTCW(PIXEL, (CRTCR(PIXEL) & 0x7f)); + + /* setup flatpanel if connected and active */ + if (si->ps.tmds1_active) + { + uint32 iscale_x, iscale_y; + + /* calculate inverse scaling factors used by hardware in 20.12 format */ + iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p1_timing.h_display); + iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p1_timing.v_display); + + /* unblock flatpanel timing programming (or something like that..) */ + CRTCW(FP_HTIMING, 0); + CRTCW(FP_VTIMING, 0); + LOG(2,("CRTC: FP_HTIMING reg readback: $%02x\n", CRTCR(FP_HTIMING))); + LOG(2,("CRTC: FP_VTIMING reg readback: $%02x\n", CRTCR(FP_VTIMING))); + + /* enable full width visibility on flatpanel */ + DACW(FP_HVALID_S, 0); + DACW(FP_HVALID_E, (si->ps.p1_timing.h_display - 1)); + /* enable full height visibility on flatpanel */ + DACW(FP_VVALID_S, 0); + DACW(FP_VVALID_E, (si->ps.p1_timing.v_display - 1)); + + /* nVidia cards support upscaling except on ??? */ + /* NV11 cards can upscale after all! */ + if (0)//si->ps.card_type == NV11) + { + /* disable last fetched line limiting */ + DACW(FP_DEBUG2, 0x00000000); + /* inform panel to scale if needed */ + if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12))) + { + LOG(2,("CRTC: DFP needs to do scaling\n")); + DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) | 0x00000100)); + } + else + { + LOG(2,("CRTC: no scaling for DFP needed\n")); + DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); + } + } + else + { + float dm_aspect; + + LOG(2,("CRTC: GPU scales for DFP if needed\n")); + + /* calculate display mode aspect */ + dm_aspect = (target.timing.h_display / ((float)target.timing.v_display)); + + /* limit last fetched line if vertical scaling is done */ + if (iscale_y != (1 << 12)) + DACW(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16))); + else + DACW(FP_DEBUG2, 0x00000000); + + /* inform panel not to scale */ + DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); + + /* GPU scaling is automatically setup by hardware, so only modify this + * scalingfactor for non 4:3 (1.33) aspect panels; + * let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */ + + /* correct for widescreen panels relative to mode... + * (so if panel is more widescreen than mode being set) */ + /* BTW: known widescreen panels: + * 1280 x 800 (1.60), + * 1440 x 900 (1.60), + * 1680 x 1050 (1.60), + * 1920 x 1200 (1.60). */ + /* known 4:3 aspect non-standard resolution panels: + * 1400 x 1050 (1.33). */ + /* NOTE: + * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ + if ((iscale_x != (1 << 12)) && (si->ps.panel1_aspect > (dm_aspect + 0.10))) + { + uint16 diff; + + LOG(2,("CRTC: (relative) widescreen panel: tuning horizontal scaling\n")); + + /* X-scaling should be the same as Y-scaling */ + iscale_x = iscale_y; + /* enable testmode (b12) and program modified X-scaling factor */ + DACW(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12))); + /* center/cut-off left and right side of screen */ + diff = ((si->ps.p1_timing.h_display - + (target.timing.h_display * ((1 << 12) / ((float)iscale_x)))) + / 2); + DACW(FP_HVALID_S, diff); + DACW(FP_HVALID_E, ((si->ps.p1_timing.h_display - diff) - 1)); + } + /* correct for portrait panels... */ + /* NOTE: + * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ + if ((iscale_y != (1 << 12)) && (si->ps.panel1_aspect < (dm_aspect - 0.10))) + { + LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n")); + /* fixme: implement if this kind of portrait panels exist on nVidia... */ + } + } + + /* do some logging.. */ + LOG(2,("CRTC: FP_HVALID_S reg readback: $%08x\n", DACR(FP_HVALID_S))); + LOG(2,("CRTC: FP_HVALID_E reg readback: $%08x\n", DACR(FP_HVALID_E))); + LOG(2,("CRTC: FP_VVALID_S reg readback: $%08x\n", DACR(FP_VVALID_S))); + LOG(2,("CRTC: FP_VVALID_E reg readback: $%08x\n", DACR(FP_VVALID_E))); + LOG(2,("CRTC: FP_DEBUG0 reg readback: $%08x\n", DACR(FP_DEBUG0))); + LOG(2,("CRTC: FP_DEBUG1 reg readback: $%08x\n", DACR(FP_DEBUG1))); + LOG(2,("CRTC: FP_DEBUG2 reg readback: $%08x\n", DACR(FP_DEBUG2))); + LOG(2,("CRTC: FP_DEBUG3 reg readback: $%08x\n", DACR(FP_DEBUG3))); + LOG(2,("CRTC: FP_TG_CTRL reg readback: $%08x\n", DACR(FP_TG_CTRL))); + } + + return B_OK; +} + +status_t nv_crtc_depth(int mode) +{ + uint8 viddelay = 0; + uint32 genctrl = 0; + + /* set VCLK scaling */ + switch(mode) + { + case BPP8: + viddelay = 0x01; + /* genctrl b4 & b5 reset: 'direct mode' */ + genctrl = 0x00101100; + break; + case BPP15: + viddelay = 0x02; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00100130; + break; + case BPP16: + viddelay = 0x02; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00101130; + break; + case BPP24: + viddelay = 0x03; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00100130; + break; + case BPP32: + viddelay = 0x03; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00101130; + break; + } + /* enable access to primary head */ + set_crtc_owner(0); + + CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay)); + DACW(GENCTRL, genctrl); + + return B_OK; +} + +status_t nv_crtc_dpms(bool display, bool h, bool v) +{ + uint8 temp; + + LOG(4,("CRTC: setting DPMS: ")); + + /* enable access to primary head */ + set_crtc_owner(0); + + /* start synchronous reset: required before turning screen off! */ + SEQW(RESET, 0x01); + + /* turn screen off */ + temp = SEQR(CLKMODE); + if (display) + { + SEQW(CLKMODE, (temp & ~0x20)); + + /* end synchronous reset if display should be enabled */ + SEQW(RESET, 0x03); + + //'safe mode' test! feedback needed with this 'setting'! + if (0)//si->ps.tmds1_active) + { + /* powerup both LVDS (laptop panellink) and TMDS (DVI panellink) + * internal transmitters... */ + /* note: + * the powerbits in this register are hardwired to the DVI connectors, + * instead of to the DACs! (confirmed NV34) */ + //fixme... + DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff)); + /* ... and powerup external TMDS transmitter if it exists */ + /* (confirmed OK on NV28 and NV34) */ + CRTCW(0x59, (CRTCR(0x59) | 0x01)); + } + + LOG(4,("display on, ")); + } + else + { + SEQW(CLKMODE, (temp | 0x20)); + + //'safe mode' test! feedback needed with this 'setting'! + if (0)//si->ps.tmds1_active) + { + /* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink) + * internal transmitters... */ + /* note: + * the powerbits in this register are hardwired to the DVI connectors, + * instead of to the DACs! (confirmed NV34) */ + //fixme... + DACW(FP_DEBUG0, (DACR(FP_DEBUG0) | 0x30000000)); + /* ... and powerdown external TMDS transmitter if it exists */ + /* (confirmed OK on NV28 and NV34) */ + CRTCW(0x59, (CRTCR(0x59) & 0xfe)); + } + + LOG(4,("display off, ")); + } + + if (h) + { + CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f)); + LOG(4,("hsync enabled, ")); + } + else + { + CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80)); + LOG(4,("hsync disabled, ")); + } + if (v) + { + CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf)); + LOG(4,("vsync enabled\n")); + } + else + { + CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40)); + LOG(4,("vsync disabled\n")); + } + + return B_OK; +} + +status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v) +{ + /* enable access to primary head */ + set_crtc_owner(0); + + *display = !(SEQR(CLKMODE) & 0x20); + *h = !(CRTCR(REPAINT1) & 0x80); + *v = !(CRTCR(REPAINT1) & 0x40); + + LOG(4,("CTRC: fetched DPMS state: ")); + if (*display) LOG(4,("display on, ")); + else LOG(4,("display off, ")); + if (*h) LOG(4,("hsync enabled, ")); + else LOG(4,("hsync disabled, ")); + if (*v) LOG(4,("vsync enabled\n")); + else LOG(4,("vsync disabled\n")); + + return B_OK; +} + +status_t nv_crtc_set_display_pitch() +{ + uint32 offset; + + LOG(4,("CRTC: setting card pitch (offset between lines)\n")); + + /* figure out offset value hardware needs */ + offset = si->fbc.bytes_per_row / 8; + + LOG(2,("CRTC: offset register set to: $%04x\n", offset)); + + /* enable access to primary head */ + set_crtc_owner(0); + + /* program the card */ + CRTCW(PITCHL, (offset & 0x00ff)); + CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3))); + + return B_OK; +} + +status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp) +{ + uint8 temp; + uint32 timeout = 0; + + LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp)); + + LOG(2,("CRTC: startadd: $%08x\n", startadd)); + LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer)); + LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer)); + + /* we might have no retraces during setmode! */ + /* wait 25mS max. for retrace to occur (refresh > 40Hz) */ + while (((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) && + (timeout < (25000/10))) + { + /* don't snooze much longer or retrace might get missed! */ + snooze(10); + timeout++; + } + + /* enable access to primary head */ + set_crtc_owner(0); + + if (si->ps.card_arch == NV04A) + { + /* upto 32Mb RAM adressing: must be used this way on pre-NV10! */ + + /* set standard registers */ + /* (NVidia: startadress in 32bit words (b2 - b17) */ + CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2)); + CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10)); + + /* set extended registers */ + /* NV4 extended bits: (b18-22) */ + temp = (CRTCR(REPAINT0) & 0xe0); + CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18))); + /* NV4 extended bits: (b23-24) */ + temp = (CRTCR(HEB) & 0x9f); + CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18))); + } + else + { + /* upto 4Gb RAM adressing: must be used on NV10 and later! */ + /* NOTE: + * While this register also exists on pre-NV10 cards, it will + * wrap-around at 16Mb boundaries!! */ + + /* 30bit adress in 32bit words */ + NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc); + } + + /* set NV4/NV10 byte adress: (b0 - 1) */ + ATBW(HORPIXPAN, ((startadd & 0x00000003) << 1)); + + return B_OK; +} + +status_t nv_crtc_cursor_init() +{ + int i; + uint32 * fb; + /* cursor bitmap will be stored at the start of the framebuffer */ + const uint32 curadd = 0; + + /* enable access to primary head */ + set_crtc_owner(0); + + /* set cursor bitmap adress ... */ + if ((si->ps.card_arch == NV04A) || (si->ps.laptop)) + { + /* must be used this way on pre-NV10 and on all 'Go' cards! */ + + /* cursorbitmap must start on 2Kbyte boundary: */ + /* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */ + CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9)); + /* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */ + CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80)); + /* set adress bit24-31 */ + CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24)); + } + else + { + /* upto 4Gb RAM adressing: + * can be used on NV10 and later (except for 'Go' cards)! */ + /* NOTE: + * This register does not exist on pre-NV10 and 'Go' cards. */ + + /* cursorbitmap must still start on 2Kbyte boundary: */ + NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800); + } + + /* set cursor colour: not needed because of direct nature of cursor bitmap. */ + + /*clear cursor*/ + fb = (uint32 *) si->framebuffer + curadd; + for (i=0;i<(2048/4);i++) + { + fb[i]=0; + } + + /* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */ + NV_REG32(NV32_CURCONF) = 0x02000100; + + /* activate hardware cursor */ + nv_crtc_cursor_show(); + + return B_OK; +} + +status_t nv_crtc_cursor_show() +{ + LOG(4,("CRTC: enabling cursor\n")); + + /* enable access to CRTC1 on dualhead cards */ + set_crtc_owner(0); + + /* b0 = 1 enables cursor */ + CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01)); + + return B_OK; +} + +status_t nv_crtc_cursor_hide() +{ + LOG(4,("CRTC: disabling cursor\n")); + + /* enable access to primary head */ + set_crtc_owner(0); + + /* b0 = 0 disables cursor */ + CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe)); + + return B_OK; +} + +/*set up cursor shape*/ +status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask) +{ + int x, y; + uint8 b; + uint16 *cursor; + uint16 pixel; + + /* get a pointer to the cursor */ + cursor = (uint16*) si->framebuffer; + + /* draw the cursor */ + /* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */ + for (y = 0; y < 16; y++) + { + b = 0x80; + for (x = 0; x < 8; x++) + { + /* preset transparant */ + pixel = 0x0000; + /* set white if requested */ + if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; + /* set black if requested */ + if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; + /* set invert if requested */ + if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; + /* place the pixel in the bitmap */ + cursor[x + (y * 32)] = pixel; + b >>= 1; + } + xorMask++; + andMask++; + b = 0x80; + for (; x < 16; x++) + { + /* preset transparant */ + pixel = 0x0000; + /* set white if requested */ + if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; + /* set black if requested */ + if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; + /* set invert if requested */ + if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; + /* place the pixel in the bitmap */ + cursor[x + (y * 32)] = pixel; + b >>= 1; + } + xorMask++; + andMask++; + } + + return B_OK; +} + +/* position the cursor */ +status_t nv_crtc_cursor_position(uint16 x, uint16 y) +{ + uint16 yhigh; + + /* make sure we are beyond the first line of the cursorbitmap being drawn during + * updating the position to prevent distortions: no double buffering feature */ + /* Note: + * we need to return as quick as possible or some apps will exhibit lagging.. */ + + /* read the old cursor Y position */ + yhigh = ((DACR(CURPOS) & 0x0fff0000) >> 16); + /* make sure we will wait until we are below both the old and new Y position: + * visible cursorbitmap drawing needs to be done at least... */ + if (y > yhigh) yhigh = y; + + if (yhigh < (si->dm.timing.v_display - 16)) + { + /* we have vertical lines below old and new cursorposition to spare. So we + * update the cursor postion 'mid-screen', but below that area. */ + while (((uint16)(NV_REG32(NV32_RASTER) & 0x000007ff)) < (yhigh + 16)) + { + snooze(10); + } + } + else + { + /* no room to spare, just wait for retrace (is relatively slow) */ + while ((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) + { + /* don't snooze much longer or retrace might get missed! */ + snooze(10); + } + } + + /* update cursorposition */ + DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16))); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/crtc2.c b/src/add-ons/accelerants/skeleton/engine/crtc2.c new file mode 100644 index 0000000000..31264dfdb3 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/crtc2.c @@ -0,0 +1,791 @@ +/* second CTRC functionality for GeForce cards */ +/* Author: + Rudolf Cornelissen 11/2002-9/2004 +*/ + +#define MODULE_BIT 0x00020000 + +#include "nv_std.h" + +/*Adjust passed parameters to a valid mode line*/ +status_t nv_crtc2_validate_timing( + uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, + uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt +) +{ +/* horizontal */ + /* make all parameters multiples of 8 */ + *hd_e &= 0xfff8; + *hs_s &= 0xfff8; + *hs_e &= 0xfff8; + *ht &= 0xfff8; + + /* confine to required number of bits, taking logic into account */ + if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3); + if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3); + if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3); + if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3); + + /* NOTE: keep horizontal timing at multiples of 8! */ + /* confine to a reasonable width */ + if (*hd_e < 640) *hd_e = 640; + if (*hd_e > 2048) *hd_e = 2048; + + /* if hor. total does not leave room for a sensible sync pulse, increase it! */ + if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); + + /* if hor. total does not adhere to max. blanking pulse width, decrease it! */ + if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8); + + /* make sure sync pulse is not during display */ + if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); + if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); + + /* correct sync pulse if it is too long: + * there are only 5 bits available to save this in the card registers! */ + if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); + +/*vertical*/ + /* confine to required number of bits, taking logic into account */ + //fixme if needed: on GeForce cards there are 12 instead of 11 bits... + if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); + if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); + if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; + if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); + + /* confine to a reasonable height */ + if (*vd_e < 480) *vd_e = 480; + if (*vd_e > 1536) *vd_e = 1536; + + /*if vertical total does not leave room for a sync pulse, increase it!*/ + if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); + + /* if vert. total does not adhere to max. blanking pulse width, decrease it! */ + if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff); + + /* make sure sync pulse is not during display */ + if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); + if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); + + /* correct sync pulse if it is too long: + * there are only 4 bits available to save this in the card registers! */ + if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); + + return B_OK; +} + +/*set a mode line - inputs are in pixels*/ +status_t nv_crtc2_set_timing(display_mode target) +{ + uint8 temp; + + uint32 htotal; /*total horizontal total VCLKs*/ + uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ + uint32 hsync_s; /*begin of horizontal sync pulse*/ + uint32 hsync_e; /*end of horizontal sync pulse*/ + uint32 hblnk_s; /*begin horizontal blanking*/ + uint32 hblnk_e; /*end horizontal blanking*/ + + uint32 vtotal; /*total vertical total scanlines*/ + uint32 vdisp_e; /*end of vertical display*/ + uint32 vsync_s; /*begin of vertical sync pulse*/ + uint32 vsync_e; /*end of vertical sync pulse*/ + uint32 vblnk_s; /*begin vertical blanking*/ + uint32 vblnk_e; /*end vertical blanking*/ + + uint32 linecomp; /*split screen and vdisp_e interrupt*/ + + LOG(4,("CRTC2: setting timing\n")); + + /* setup tuned internal modeline for flatpanel if connected and active */ + /* notes: + * - the CRTC modeline must end earlier than the panel modeline to keep correct + * sync going; + * - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel + * wide horizontal stripes. This can be observed earliest on fullscreen overlay, + * and if it gets worse, also normal desktop output will suffer. The stripes + * are mainly visible at the left of the screen, over the entire screen height. */ + if (si->ps.tmds2_active) + { + LOG(2,("CRTC2: DFP active: tuning modeline\n")); + + /* horizontal timing */ + target.timing.h_sync_start = + ((uint16)((si->ps.p2_timing.h_sync_start / ((float)si->ps.p2_timing.h_display)) * + target.timing.h_display)) & 0xfff8; + + target.timing.h_sync_end = + ((uint16)((si->ps.p2_timing.h_sync_end / ((float)si->ps.p2_timing.h_display)) * + target.timing.h_display)) & 0xfff8; + + target.timing.h_total = + (((uint16)((si->ps.p2_timing.h_total / ((float)si->ps.p2_timing.h_display)) * + target.timing.h_display)) & 0xfff8) - 8; + + /* in native mode the CRTC needs some extra time to keep synced correctly; + * OTOH the overlay unit distorts if we reserve too much time! */ + if (target.timing.h_display == si->ps.p2_timing.h_display) + { + /* NV11 timing has different constraints than later cards */ + if (si->ps.card_type == NV11) + target.timing.h_total -= 56; + else + /* confirmed NV34 with 1680x1050 panel */ + target.timing.h_total -= 32; + } + + if (target.timing.h_sync_start == target.timing.h_display) + target.timing.h_sync_start += 8; + if (target.timing.h_sync_end == target.timing.h_total) + target.timing.h_sync_end -= 8; + + /* vertical timing */ + target.timing.v_sync_start = + ((uint16)((si->ps.p2_timing.v_sync_start / ((float)si->ps.p2_timing.v_display)) * + target.timing.v_display)); + + target.timing.v_sync_end = + ((uint16)((si->ps.p2_timing.v_sync_end / ((float)si->ps.p2_timing.v_display)) * + target.timing.v_display)); + + target.timing.v_total = + ((uint16)((si->ps.p2_timing.v_total / ((float)si->ps.p2_timing.v_display)) * + target.timing.v_display)) - 1; + + if (target.timing.v_sync_start == target.timing.v_display) + target.timing.v_sync_start += 1; + if (target.timing.v_sync_end == target.timing.v_total) + target.timing.v_sync_end -= 1; + + /* disable GPU scaling testmode so automatic scaling will be done */ + DAC2W(FP_DEBUG1, 0); + } + + /* Modify parameters as required by standard VGA */ + htotal = ((target.timing.h_total >> 3) - 5); + hdisp_e = ((target.timing.h_display >> 3) - 1); + hblnk_s = hdisp_e; + hblnk_e = (htotal + 4);//0; + hsync_s = (target.timing.h_sync_start >> 3); + hsync_e = (target.timing.h_sync_end >> 3); + + vtotal = target.timing.v_total - 2; + vdisp_e = target.timing.v_display - 1; + vblnk_s = vdisp_e; + vblnk_e = (vtotal + 1); + vsync_s = target.timing.v_sync_start;//-1; + vsync_e = target.timing.v_sync_end;//-1; + + /* prevent memory adress counter from being reset (linecomp may not occur) */ + linecomp = target.timing.v_display; + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* Note for laptop and DVI flatpanels: + * CRTC timing has a seperate set of registers from flatpanel timing. + * The flatpanel timing registers have scaling registers that are used to match + * these two modelines. */ + { + LOG(4,("CRTC2: Setting full timing...\n")); + + /* log the mode that will be set */ + LOG(2,("CRTC2:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e)); + LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e)); + + /* actually program the card! */ + /* unlock CRTC registers at index 0-7 */ + CRTC2W(VSYNCE, (CRTC2R(VSYNCE) & 0x7f)); + /* horizontal standard VGA regs */ + CRTC2W(HTOTAL, (htotal & 0xff)); + CRTC2W(HDISPE, (hdisp_e & 0xff)); + CRTC2W(HBLANKS, (hblnk_s & 0xff)); + /* also unlock vertical retrace registers in advance */ + CRTC2W(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); + CRTC2W(HSYNCS, (hsync_s & 0xff)); + CRTC2W(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); + + /* vertical standard VGA regs */ + CRTC2W(VTOTAL, (vtotal & 0xff)); + CRTC2W(OVERFLOW, + ( + ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | + ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | + ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | + ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) + )); + CRTC2W(PRROWSCN, 0x00); /* not used */ + CRTC2W(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); + CRTC2W(VSYNCS, (vsync_s & 0xff)); + CRTC2W(VSYNCE, ((CRTC2R(VSYNCE) & 0xf0) | (vsync_e & 0x0f))); + CRTC2W(VDISPE, (vdisp_e & 0xff)); + CRTC2W(VBLANKS, (vblnk_s & 0xff)); + CRTC2W(VBLANKE, (vblnk_e & 0xff)); + CRTC2W(LINECOMP, (linecomp & 0xff)); + + /* horizontal extended regs */ + //fixme: we reset bit4. is this correct?? + CRTC2W(HEB, (CRTC2R(HEB) & 0xe0) | + ( + ((htotal & 0x100) >> (8 - 0)) | + ((hdisp_e & 0x100) >> (8 - 1)) | + ((hblnk_s & 0x100) >> (8 - 2)) | + ((hsync_s & 0x100) >> (8 - 3)) + )); + + /* (mostly) vertical extended regs */ + CRTC2W(LSR, + ( + ((vtotal & 0x400) >> (10 - 0)) | + ((vdisp_e & 0x400) >> (10 - 1)) | + ((vsync_s & 0x400) >> (10 - 2)) | + ((vblnk_s & 0x400) >> (10 - 3)) | + ((hblnk_e & 0x040) >> (6 - 4)) + //fixme: we still miss one linecomp bit!?! is this it?? + //| ((linecomp & 0x400) >> 3) + )); + + /* more vertical extended regs */ + CRTC2W(EXTRA, + ( + ((vtotal & 0x800) >> (11 - 0)) | + ((vdisp_e & 0x800) >> (11 - 2)) | + ((vsync_s & 0x800) >> (11 - 4)) | + ((vblnk_s & 0x800) >> (11 - 6)) + //fixme: do we miss another linecomp bit!?! + )); + + /* setup 'large screen' mode */ + if (target.timing.h_display >= 1280) + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xfb)); + else + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x04)); + + /* setup HSYNC & VSYNC polarity */ + LOG(2,("CRTC2: sync polarity: ")); + temp = NV_REG8(NV8_MISCR); + if (target.timing.flags & B_POSITIVE_HSYNC) + { + LOG(2,("H:pos ")); + temp &= ~0x40; + } + else + { + LOG(2,("H:neg ")); + temp |= 0x40; + } + if (target.timing.flags & B_POSITIVE_VSYNC) + { + LOG(2,("V:pos ")); + temp &= ~0x80; + } + else + { + LOG(2,("V:neg ")); + temp |= 0x80; + } + NV_REG8(NV8_MISCW) = temp; + + LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR))); + } + + /* always disable interlaced operation */ + /* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */ + CRTC2W(INTERLACE, 0xff); + + /* disable CRTC slaved mode unless a panel is in use */ + // fixme: this kills TVout when it was in use... + if (!si->ps.tmds2_active) CRTC2W(PIXEL, (CRTC2R(PIXEL) & 0x7f)); + + /* setup flatpanel if connected and active */ + if (si->ps.tmds2_active) + { + uint32 iscale_x, iscale_y; + + /* calculate inverse scaling factors used by hardware in 20.12 format */ + iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p2_timing.h_display); + iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p2_timing.v_display); + + /* unblock flatpanel timing programming (or something like that..) */ + CRTC2W(FP_HTIMING, 0); + CRTC2W(FP_VTIMING, 0); + LOG(2,("CRTC2: FP_HTIMING reg readback: $%02x\n", CRTC2R(FP_HTIMING))); + LOG(2,("CRTC2: FP_VTIMING reg readback: $%02x\n", CRTC2R(FP_VTIMING))); + + /* enable full width visibility on flatpanel */ + DAC2W(FP_HVALID_S, 0); + DAC2W(FP_HVALID_E, (si->ps.p2_timing.h_display - 1)); + /* enable full height visibility on flatpanel */ + DAC2W(FP_VVALID_S, 0); + DAC2W(FP_VVALID_E, (si->ps.p2_timing.v_display - 1)); + + /* nVidia cards support upscaling except on ??? */ + /* NV11 cards can upscale after all! */ + if (0)//si->ps.card_type == NV11) + { + /* disable last fetched line limiting */ + DAC2W(FP_DEBUG2, 0x00000000); + /* inform panel to scale if needed */ + if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12))) + { + LOG(2,("CRTC2: DFP needs to do scaling\n")); + DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) | 0x00000100)); + } + else + { + LOG(2,("CRTC2: no scaling for DFP needed\n")); + DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff)); + } + } + else + { + float dm_aspect; + + LOG(2,("CRTC2: GPU scales for DFP if needed\n")); + + /* calculate display mode aspect */ + dm_aspect = (target.timing.h_display / ((float)target.timing.v_display)); + + /* limit last fetched line if vertical scaling is done */ + if (iscale_y != (1 << 12)) + DAC2W(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16))); + else + DAC2W(FP_DEBUG2, 0x00000000); + + /* inform panel not to scale */ + DAC2W(FP_TG_CTRL, (DAC2R(FP_TG_CTRL) & 0xfffffeff)); + + /* GPU scaling is automatically setup by hardware, so only modify this + * scalingfactor for non 4:3 (1.33) aspect panels; + * let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */ + + /* correct for widescreen panels relative to mode... + * (so if panel is more widescreen than mode being set) */ + /* BTW: known widescreen panels: + * 1280 x 800 (1.60), + * 1440 x 900 (1.60), + * 1680 x 1050 (1.60), + * 1920 x 1200 (1.60). */ + /* known 4:3 aspect non-standard resolution panels: + * 1400 x 1050 (1.33). */ + /* NOTE: + * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ + if ((iscale_x != (1 << 12)) && (si->ps.panel2_aspect > (dm_aspect + 0.10))) + { + uint16 diff; + + LOG(2,("CRTC2: (relative) widescreen panel: tuning horizontal scaling\n")); + + /* X-scaling should be the same as Y-scaling */ + iscale_x = iscale_y; + /* enable testmode (b12) and program new X-scaling factor */ + DAC2W(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12))); + /* center/cut-off left and right side of screen */ + diff = ((si->ps.p2_timing.h_display - + (target.timing.h_display * ((1 << 12) / ((float)iscale_x)))) + / 2); + DAC2W(FP_HVALID_S, diff); + DAC2W(FP_HVALID_E, ((si->ps.p2_timing.h_display - diff) - 1)); + } + /* correct for portrait panels... */ + /* NOTE: + * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ + if ((iscale_y != (1 << 12)) && (si->ps.panel2_aspect < (dm_aspect - 0.10))) + { + LOG(2,("CRTC2: (relative) portrait panel: should tune vertical scaling\n")); + /* fixme: implement if this kind of portrait panels exist on nVidia... */ + } + } + + /* do some logging.. */ + LOG(2,("CRTC2: FP_HVALID_S reg readback: $%08x\n", DAC2R(FP_HVALID_S))); + LOG(2,("CRTC2: FP_HVALID_E reg readback: $%08x\n", DAC2R(FP_HVALID_E))); + LOG(2,("CRTC2: FP_VVALID_S reg readback: $%08x\n", DAC2R(FP_VVALID_S))); + LOG(2,("CRTC2: FP_VVALID_E reg readback: $%08x\n", DAC2R(FP_VVALID_E))); + LOG(2,("CRTC2: FP_DEBUG0 reg readback: $%08x\n", DAC2R(FP_DEBUG0))); + LOG(2,("CRTC2: FP_DEBUG1 reg readback: $%08x\n", DAC2R(FP_DEBUG1))); + LOG(2,("CRTC2: FP_DEBUG2 reg readback: $%08x\n", DAC2R(FP_DEBUG2))); + LOG(2,("CRTC2: FP_DEBUG3 reg readback: $%08x\n", DAC2R(FP_DEBUG3))); + LOG(2,("CRTC2: FP_TG_CTRL reg readback: $%08x\n", DAC2R(FP_TG_CTRL))); + } + + return B_OK; +} + +status_t nv_crtc2_depth(int mode) +{ + uint8 viddelay = 0; + uint32 genctrl = 0; + + /* set VCLK scaling */ + switch(mode) + { + case BPP8: + viddelay = 0x01; + /* genctrl b4 & b5 reset: 'direct mode' */ + genctrl = 0x00101100; + break; + case BPP15: + viddelay = 0x02; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00100130; + break; + case BPP16: + viddelay = 0x02; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00101130; + break; + case BPP24: + viddelay = 0x03; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00100130; + break; + case BPP32: + viddelay = 0x03; + /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ + genctrl = 0x00101130; + break; + } + /* enable access to secondary head */ + set_crtc_owner(1); + + CRTC2W(PIXEL, ((CRTC2R(PIXEL) & 0xfc) | viddelay)); + DAC2W(GENCTRL, genctrl); + + return B_OK; +} + +status_t nv_crtc2_dpms(bool display, bool h, bool v) +{ + uint8 temp; + + LOG(4,("CRTC2: setting DPMS: ")); + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* start synchronous reset: required before turning screen off! */ + SEQW(RESET, 0x01); + + /* turn screen off */ + temp = SEQR(CLKMODE); + if (display) + { + SEQW(CLKMODE, (temp & ~0x20)); + + /* end synchronous reset if display should be enabled */ + SEQW(RESET, 0x03); + + //'safe mode' test! feedback needed with this 'setting'! + if (0)//si->ps.tmds2_active) + { + /* powerup both LVDS (laptop panellink) and TMDS (DVI panellink) + * internal transmitters... */ + /* note: + * the powerbits in this register are hardwired to the DVI connectors, + * instead of to the DACs! (confirmed NV34) */ + //fixme... + DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) & 0xcfffffff)); + /* ... and powerup external TMDS transmitter if it exists */ + /* (confirmed OK on NV28 and NV34) */ + CRTC2W(0x59, (CRTC2R(0x59) | 0x01)); + } + + LOG(4,("display on, ")); + } + else + { + SEQW(CLKMODE, (temp | 0x20)); + + //'safe mode' test! feedback needed with this 'setting'! + if (0)//si->ps.tmds2_active) + { + /* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink) + * internal transmitters... */ + /* note: + * the powerbits in this register are hardwired to the DVI connectors, + * instead of to the DACs! (confirmed NV34) */ + //fixme... + DAC2W(FP_DEBUG0, (DAC2R(FP_DEBUG0) | 0x30000000)); + /* ... and powerdown external TMDS transmitter if it exists */ + /* (confirmed OK on NV28 and NV34) */ + CRTC2W(0x59, (CRTC2R(0x59) & 0xfe)); + } + + LOG(4,("display off, ")); + } + + if (h) + { + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0x7f)); + LOG(4,("hsync enabled, ")); + } + else + { + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x80)); + LOG(4,("hsync disabled, ")); + } + if (v) + { + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xbf)); + LOG(4,("vsync enabled\n")); + } + else + { + CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x40)); + LOG(4,("vsync disabled\n")); + } + + return B_OK; +} + +status_t nv_crtc2_dpms_fetch(bool *display, bool *h, bool *v) +{ + /* enable access to secondary head */ + set_crtc_owner(1); + + *display = !(SEQR(CLKMODE) & 0x20); + *h = !(CRTC2R(REPAINT1) & 0x80); + *v = !(CRTC2R(REPAINT1) & 0x40); + + LOG(4,("CTRC2: fetched DPMS state: ")); + if (*display) LOG(4,("display on, ")); + else LOG(4,("display off, ")); + if (*h) LOG(4,("hsync enabled, ")); + else LOG(4,("hsync disabled, ")); + if (*v) LOG(4,("vsync enabled\n")); + else LOG(4,("vsync disabled\n")); + + return B_OK; +} + +status_t nv_crtc2_set_display_pitch() +{ + uint32 offset; + + LOG(4,("CRTC2: setting card pitch (offset between lines)\n")); + + /* figure out offset value hardware needs */ + offset = si->fbc.bytes_per_row / 8; + + LOG(2,("CRTC2: offset register set to: $%04x\n", offset)); + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* program the card */ + CRTC2W(PITCHL, (offset & 0x00ff)); + CRTC2W(REPAINT0, ((CRTC2R(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3))); + + return B_OK; +} + +status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp) +{ + uint32 timeout = 0; + + LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp)); + + LOG(2,("CRTC2: startadd: $%08x\n", startadd)); + LOG(2,("CRTC2: frameRAM: $%08x\n", si->framebuffer)); + LOG(2,("CRTC2: framebuffer: $%08x\n", si->fbc.frame_buffer)); + + /* we might have no retraces during setmode! */ + /* wait 25mS max. for retrace to occur (refresh > 40Hz) */ + while (((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) && + (timeout < (25000/10))) + { + /* don't snooze much longer or retrace might get missed! */ + snooze(10); + timeout++; + } + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* upto 4Gb RAM adressing: must be used on NV10 and later! */ + /* NOTE: + * While this register also exists on pre-NV10 cards, it will + * wrap-around at 16Mb boundaries!! */ + + /* 30bit adress in 32bit words */ + NV_REG32(NV32_NV10FB2STADD32) = (startadd & 0xfffffffc); + + /* set byte adress: (b0 - 1) */ + ATB2W(HORPIXPAN, ((startadd & 0x00000003) << 1)); + + return B_OK; +} + +status_t nv_crtc2_cursor_init() +{ + int i; + uint32 * fb; + /* cursor bitmap will be stored at the start of the framebuffer */ + const uint32 curadd = 0; + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* set cursor bitmap adress ... */ + if (si->ps.laptop) + { + /* must be used this way on pre-NV10 and on all 'Go' cards! */ + + /* cursorbitmap must start on 2Kbyte boundary: */ + /* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */ + CRTC2W(CURCTL0, ((curadd & 0x0001f800) >> 9)); + /* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */ + CRTC2W(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80)); + /* set adress bit24-31 */ + CRTC2W(CURCTL2, ((curadd & 0xff000000) >> 24)); + } + else + { + /* upto 4Gb RAM adressing: + * can be used on NV10 and later (except for 'Go' cards)! */ + /* NOTE: + * This register does not exist on pre-NV10 and 'Go' cards. */ + + /* cursorbitmap must still start on 2Kbyte boundary: */ + NV_REG32(NV32_NV10CUR2ADD32) = (curadd & 0xfffff800); + } + + /* set cursor colour: not needed because of direct nature of cursor bitmap. */ + + /*clear cursor*/ + fb = (uint32 *) si->framebuffer + curadd; + for (i=0;i<(2048/4);i++) + { + fb[i]=0; + } + + /* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */ + NV_REG32(NV32_2CURCONF) = 0x02000100; + + /* activate hardware cursor */ + nv_crtc2_cursor_show(); + + return B_OK; +} + +status_t nv_crtc2_cursor_show() +{ + LOG(4,("CRTC2: enabling cursor\n")); + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* b0 = 1 enables cursor */ + CRTC2W(CURCTL0, (CRTC2R(CURCTL0) | 0x01)); + + return B_OK; +} + +status_t nv_crtc2_cursor_hide() +{ + LOG(4,("CRTC2: disabling cursor\n")); + + /* enable access to secondary head */ + set_crtc_owner(1); + + /* b0 = 0 disables cursor */ + CRTC2W(CURCTL0, (CRTC2R(CURCTL0) & 0xfe)); + + return B_OK; +} + +/*set up cursor shape*/ +status_t nv_crtc2_cursor_define(uint8* andMask,uint8* xorMask) +{ + int x, y; + uint8 b; + uint16 *cursor; + uint16 pixel; + + /* get a pointer to the cursor */ + cursor = (uint16*) si->framebuffer; + + /* draw the cursor */ + /* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */ + for (y = 0; y < 16; y++) + { + b = 0x80; + for (x = 0; x < 8; x++) + { + /* preset transparant */ + pixel = 0x0000; + /* set white if requested */ + if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; + /* set black if requested */ + if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; + /* set invert if requested */ + if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; + /* place the pixel in the bitmap */ + cursor[x + (y * 32)] = pixel; + b >>= 1; + } + xorMask++; + andMask++; + b = 0x80; + for (; x < 16; x++) + { + /* preset transparant */ + pixel = 0x0000; + /* set white if requested */ + if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; + /* set black if requested */ + if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; + /* set invert if requested */ + if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; + /* place the pixel in the bitmap */ + cursor[x + (y * 32)] = pixel; + b >>= 1; + } + xorMask++; + andMask++; + } + + return B_OK; +} + +/* position the cursor */ +status_t nv_crtc2_cursor_position(uint16 x, uint16 y) +{ + uint16 yhigh; + + /* make sure we are beyond the first line of the cursorbitmap being drawn during + * updating the position to prevent distortions: no double buffering feature */ + /* Note: + * we need to return as quick as possible or some apps will exhibit lagging.. */ + + /* read the old cursor Y position */ + yhigh = ((DAC2R(CURPOS) & 0x0fff0000) >> 16); + /* make sure we will wait until we are below both the old and new Y position: + * visible cursorbitmap drawing needs to be done at least... */ + if (y > yhigh) yhigh = y; + + if (yhigh < (si->dm.timing.v_display - 16)) + { + /* we have vertical lines below old and new cursorposition to spare. So we + * update the cursor postion 'mid-screen', but below that area. */ + while (((uint16)(NV_REG32(NV32_RASTER2) & 0x000007ff)) < (yhigh + 16)) + { + snooze(10); + } + } + else + { + /* no room to spare, just wait for retrace (is relatively slow) */ + while ((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) + { + /* don't snooze much longer or retrace might get missed! */ + snooze(10); + } + } + + /* update cursorposition */ + DAC2W(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16))); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/dac.c b/src/add-ons/accelerants/skeleton/engine/dac.c new file mode 100644 index 0000000000..d19b25d4e1 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/dac.c @@ -0,0 +1,561 @@ +/* program the DAC */ +/* Author: + Rudolf Cornelissen 12/2003-10/2004 +*/ + +#define MODULE_BIT 0x00010000 + +#include "nv_std.h" + +static status_t nv4_nv10_nv20_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); + +/* see if an analog VGA monitor is connected to connector #1 */ +bool nv_dac_crt_connected(void) +{ + uint32 output, dac; + bool present; + + /* save output connector setting */ + output = DACR(OUTPUT); + /* save DAC state */ + dac = DACR(TSTCTRL); + + /* turn on DAC */ + DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeffff)); + /* select primary head and turn off CRT (and DVI?) outputs */ + DACW(OUTPUT, (output & 0x0000feee)); + /* wait for signal lines to stabilize */ + snooze(1000); + /* re-enable CRT output */ + DACW(OUTPUT, (DACR(OUTPUT) | 0x00000001)); + + /* setup RGB test signal levels to approx 30% of DAC range and enable them */ + DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0))); + /* route test signals to output */ + DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000)); + /* wait for signal lines to stabilize */ + snooze(1000); + + /* do actual detection: all signals paths high == CRT connected */ + if (DACR(TSTCTRL) & 0x10000000) + { + present = true; + LOG(4,("DAC: CRT detected on connector #1\n")); + } + else + { + present = false; + LOG(4,("DAC: no CRT detected on connector #1\n")); + } + + /* kill test signal routing */ + DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff)); + + /* restore output connector setting */ + DACW(OUTPUT, output); + /* restore DAC state */ + DACW(TSTCTRL, dac); + + return present; +} + +/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ +status_t nv_dac_mode(int mode,float brightness) +{ + uint8 *r,*g,*b; + int i, ri; + + /*set colour arrays to point to space reserved in shared info*/ + r = si->color_data; + g = r + 256; + b = g + 256; + + LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness)); + /* init the palette for brightness specified */ + /* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */ + for (i = 0; i < 256; i++) + { + ri = i * brightness; + if (ri > 255) ri = 255; + b[i] = g[i] = r[i] = ri; + } + + if (nv_dac_palette(r,g,b) != B_OK) return B_ERROR; + + /* disable palette RAM adressing mask */ + NV_REG8(NV8_PALMASK) = 0xff; + LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PALMASK))); + + return B_OK; +} + +/*program the DAC palette using the given r,g,b values*/ +status_t nv_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256]) +{ + int i; + + LOG(4,("DAC: setting palette\n")); + + /* select first PAL adress before starting programming */ + NV_REG8(NV8_PALINDW) = 0x00; + + /* loop through all 256 to program DAC */ + for (i = 0; i < 256; i++) + { + /* the 6 implemented bits are on b0-b5 of the bus */ + NV_REG8(NV8_PALDATA) = r[i]; + NV_REG8(NV8_PALDATA) = g[i]; + NV_REG8(NV8_PALDATA) = b[i]; + } + if (NV_REG8(NV8_PALINDW) != 0x00) + { + LOG(8,("DAC: PAL write index incorrect after programming\n")); + return B_ERROR; + } +if (1) + {//reread LUT + uint8 R, G, B; + + /* select first PAL adress to read (modulo 3 counter) */ + NV_REG8(NV8_PALINDR) = 0x00; + for (i = 0; i < 256; i++) + { + R = NV_REG8(NV8_PALDATA); + G = NV_REG8(NV8_PALDATA); + B = NV_REG8(NV8_PALDATA); + if ((r[i] != R) || (g[i] != G) || (b[i] != B)) + LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed + } + } + + return B_OK; +} + +/*program the pixpll - frequency in kHz*/ +status_t nv_dac_set_pix_pll(display_mode target) +{ + uint8 m=0,n=0,p=0; +// uint time = 0; + + float pix_setting, req_pclk; + status_t result; + + /* we offer this option because some panels have very tight restrictions, + * and there's no overlapping settings range that makes them all work. + * note: + * this assumes the cards BIOS correctly programmed the panel (is likely) */ + //fixme: when VESA DDC EDID stuff is implemented, this option can be deleted... + if (si->ps.tmds1_active && !si->settings.pgm_panel) + { + LOG(4,("DAC: Not programming DFP refresh (specified in nv.settings)\n")); + return B_OK; + } + + /* fix a DVI or laptop flatpanel to 60Hz refresh! */ + /* Note: + * The pixelclock drives the flatpanel modeline, not the CRTC modeline. */ + if (si->ps.tmds1_active) + { + LOG(4,("DAC: Fixing DFP refresh to 60Hz!\n")); + + /* use the panel's modeline to determine the needed pixelclock */ + target.timing.pixel_clock = si->ps.p1_timing.pixel_clock; + } + + req_pclk = (target.timing.pixel_clock)/1000.0; + LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); + + /* signal that we actually want to set the mode */ + result = nv_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1); + if (result != B_OK) + { + return result; + } + + /*reprogram (disable,select,wait for stability,enable)*/ +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ + + /* program new frequency */ + DACW(PIXPLLC, ((p << 16) | (n << 8) | m)); + + /* program 2nd set N and M scalers if they exist (b31=1 enables them) */ + if (si->ps.ext_pll) DACW(PIXPLLC2, 0x80000401); + + /* Wait for the PIXPLL frequency to lock until timeout occurs */ +//fixme: do NV cards have a LOCK indication bit?? +/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: PIX PLL frequency not locked!\n")); + else + LOG(2,("DAC: PIX PLL frequency locked\n")); + DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL +*/ + +//for now: + /* Give the PIXPLL frequency some time to lock... */ + snooze(1000); + LOG(2,("DAC: PIX PLL frequency should be locked now...\n")); + + return B_OK; +} + +/* find nearest valid pix pll */ +status_t nv_dac_pix_pll_find + (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) +{ + switch (si->ps.card_type) { + default: return nv4_nv10_nv20_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); + } + return B_ERROR; +} + +/* find nearest valid pixel PLL setting */ +static status_t nv4_nv10_nv20_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) +{ + int m = 0, n = 0, p = 0/*, m_max*/; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + /* determine the max. reference-frequency postscaler setting for the + * current card (see G100, G200 and G400 specs). */ +/* switch(si->ps.card_type) + { + case G100: + LOG(4,("DAC: G100 restrictions apply\n")); + m_max = 7; + break; + case G200: + LOG(4,("DAC: G200 restrictions apply\n")); + m_max = 7; + break; + default: + LOG(4,("DAC: G400/G400MAX restrictions apply\n")); + m_max = 32; + break; + } +*/ + LOG(4,("DAC: NV4/NV10/NV20 restrictions apply\n")); + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac1_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac1_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac1_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac1_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_32; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclk = si->ps.max_dac1_clock_32dh; + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_pixel_vco divided by highest postscaler-factor */ + if (req_pclk < (si->ps.min_pixel_vco / 16.0)) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_pixel_vco / 16.0))); + req_pclk = (si->ps.min_pixel_vco / 16.0); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x20; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco)) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco /= 4; + + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 7; m <= 14; m++) + { + /* check if phase-discriminator will be within operational limits */ + //fixme: PLL calcs will be resetup/splitup/updated... + if (si->ps.card_type == NV36) + { + if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue; + } + else + { + if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue; + } + + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + + /* ..and check for validity */ + if ((n < 1) || (n > 255)) continue; + + /* find error in frequency this setting gives */ + if (si->ps.ext_pll) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p)); + } + else + error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m = best[0]; + n = best[1]; + p = best[2]; + + /* log the VCO frequency found */ + f_vco = ((si->ps.f_ref / m) * n); + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco *= 4; + + LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco)); + + /* return the results */ + *calc_pclk = (f_vco / p); + *m_result = m; + *n_result = n; + switch(p) + { + case 1: + p = 0x00; + break; + case 2: + p = 0x01; + break; + case 4: + p = 0x02; + break; + case 8: + p = 0x03; + break; + case 16: + p = 0x04; + break; + } + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); + + return B_OK; +} + +/* find nearest valid system PLL setting */ +status_t nv_dac_sys_pll_find( + float req_sclk, float* calc_sclk, uint8* m_result, uint8* n_result, uint8* p_result, uint8 test) +{ + int m = 0, n = 0, p = 0, m_max, p_max; + float error, error_best = 999999999; + int best[3]; + float f_vco, discr_low, discr_high; + + /* determine the max. reference-frequency postscaler setting for the + * current requested clock */ + switch (si->ps.card_arch) + { + case NV04A: + LOG(4,("DAC: NV04 restrictions apply\n")); + /* set phase-discriminator frequency range (Mhz) (verified) */ + discr_low = 1.0; + discr_high = 2.0; + /* set max. useable reference frequency postscaler divider factor */ + m_max = 14; + /* set max. useable VCO output postscaler divider factor */ + p_max = 16; + break; + default: + switch (si->ps.card_type) + { + case NV28: + //fixme: how about some other cards??? + LOG(4,("DAC: NV28 restrictions apply\n")); + /* set max. useable reference frequency postscaler divider factor; + * apparantly we would get distortions on high PLL output frequencies if + * we use the phase-discriminator at low frequencies */ + if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */ + else if (req_sclk > 200.0) m_max = 4; /* 200Mhz < Fpll <= 340Mhz */ + else if (req_sclk > 150.0) m_max = 6; /* 150Mhz < Fpll <= 200Mhz */ + else m_max = 14; /* Fpll < 150Mhz */ + + /* set max. useable VCO output postscaler divider factor */ + p_max = 32; + /* set phase-discriminator frequency range (Mhz) (verified) */ + discr_low = 1.0; + discr_high = 27.0; + break; + default: + LOG(4,("DAC: NV10/NV20/NV30 restrictions apply\n")); + /* set max. useable reference frequency postscaler divider factor; + * apparantly we would get distortions on high PLL output frequencies if + * we use the phase-discriminator at low frequencies */ + if (req_sclk > 340.0) m_max = 2; /* Fpll > 340Mhz */ + else if (req_sclk > 250.0) m_max = 6; /* 250Mhz < Fpll <= 340Mhz */ + else m_max = 14; /* Fpll < 250Mhz */ + + /* set max. useable VCO output postscaler divider factor */ + p_max = 16; + /* set phase-discriminator frequency range (Mhz) (verified) */ + if (si->ps.card_type == NV36) discr_low = 3.2; + else discr_low = 1.0; + /* (high discriminator spec is failsafe) */ + discr_high = 14.0; + break; + } + break; + } + + LOG(4,("DAC: PLL reference frequency postscaler divider range is 1 - %d\n", m_max)); + LOG(4,("DAC: PLL VCO output postscaler divider range is 1 - %d\n", p_max)); + LOG(4,("DAC: PLL discriminator input frequency range is %2.2fMhz - %2.2fMhz\n", + discr_low, discr_high)); + + /* Make sure the requested clock is within the PLL's operational limits */ + /* lower limit is min_system_vco divided by highest postscaler-factor */ + if (req_sclk < (si->ps.min_system_vco / ((float)p_max))) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (si->ps.min_system_vco / ((float)p_max)))); + req_sclk = (si->ps.min_system_vco / ((float)p_max)); + } + /* upper limit is given by pins */ + if (req_sclk > si->ps.max_system_vco) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (float)si->ps.max_system_vco)); + req_sclk = si->ps.max_system_vco; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p <= p_max; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_sclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco)) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco /= 4; + + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 1; m <= m_max; m++) + { + /* check if phase-discriminator will be within operational limits */ + if (((si->ps.f_ref / m) < discr_low) || ((si->ps.f_ref / m) > discr_high)) + continue; + + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + + /* ..and check for validity */ + if ((n < 1) || (n > 255)) continue; + + /* find error in frequency this setting gives */ + if (si->ps.ext_pll) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + error = fabs((req_sclk / 4) - (((si->ps.f_ref / m) * n) / p)); + } + else + error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m = best[0]; + n = best[1]; + p = best[2]; + + /* log the VCO frequency found */ + f_vco = ((si->ps.f_ref / m) * n); + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco *= 4; + + LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco)); + + /* return the results */ + *calc_sclk = (f_vco / p); + *m_result = m; + *n_result = n; + switch(p) + { + case 1: + p = 0x00; + break; + case 2: + p = 0x01; + break; + case 4: + p = 0x02; + break; + case 8: + p = 0x03; + break; + case 16: + p = 0x04; + break; + case 32: + p = 0x05; + break; + } + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_sclk, *calc_sclk, *m_result, *n_result, *p_result)); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/dac2.c b/src/add-ons/accelerants/skeleton/engine/dac2.c new file mode 100644 index 0000000000..cd6f457df1 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/dac2.c @@ -0,0 +1,391 @@ +/* program the secondary DAC */ +/* Author: + Rudolf Cornelissen 12/2003-9/2004 +*/ + +#define MODULE_BIT 0x00001000 + +#include "nv_std.h" + +static status_t nv10_nv20_dac2_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); + +/* see if an analog VGA monitor is connected to connector #2 */ +bool nv_dac2_crt_connected() +{ + uint32 output, dac; + bool present; + + /* NOTE: + * NV11 can't do this: It will report DAC1 status instead because it HAS no + * actual secondary DAC function. */ + /* (It DOES have a secondary palette RAM and pixelclock PLL though.) */ + + /* save output connector setting */ + output = DAC2R(OUTPUT); + /* save DAC state */ + dac = DAC2R(TSTCTRL); + + /* turn on DAC2 */ + DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeffff)); + /* select primary head and turn off CRT (and DVI?) outputs */ + DAC2W(OUTPUT, (output & 0x0000feee)); + /* wait for signal lines to stabilize */ + snooze(1000); + /* re-enable CRT output */ + DAC2W(OUTPUT, (DAC2R(OUTPUT) | 0x00000001)); + + /* setup RGB test signal levels to approx 30% of DAC range and enable them + * (NOTE: testsignal function block resides in DAC1 only (!)) */ + DACW(TSTDATA, ((0x2 << 30) | (0x140 << 20) | (0x140 << 10) | (0x140 << 0))); + /* route test signals to output + * (NOTE: testsignal function block resides in DAC1 only (!)) */ + DACW(TSTCTRL, (DACR(TSTCTRL) | 0x00001000)); + /* wait for signal lines to stabilize */ + snooze(1000); + + /* do actual detection: all signals paths high == CRT connected */ + if (DAC2R(TSTCTRL) & 0x10000000) + { + present = true; + LOG(4,("DAC2: CRT detected on connector #2\n")); + } + else + { + present = false; + LOG(4,("DAC2: no CRT detected on connector #2\n")); + } + + /* kill test signal routing + * (NOTE: testsignal function block resides in DAC1 only (!)) */ + DACW(TSTCTRL, (DACR(TSTCTRL) & 0xffffefff)); + + /* restore output connector setting */ + DAC2W(OUTPUT, output); + /* restore DAC state */ + DAC2W(TSTCTRL, dac); + + return present; +} + +/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ +status_t nv_dac2_mode(int mode,float brightness) +{ + uint8 *r,*g,*b; + int i, ri; + + /*set colour arrays to point to space reserved in shared info*/ + r = si->color_data; + g = r + 256; + b = g + 256; + + LOG(4,("DAC2: Setting screen mode %d brightness %f\n", mode, brightness)); + /* init the palette for brightness specified */ + /* (Nvidia cards always use MSbits from screenbuffer as index for PAL) */ + for (i = 0; i < 256; i++) + { + ri = i * brightness; + if (ri > 255) ri = 255; + b[i] = g[i] = r[i] = ri; + } + + if (nv_dac2_palette(r,g,b) != B_OK) return B_ERROR; + + /* disable palette RAM adressing mask */ + NV_REG8(NV8_PAL2MASK) = 0xff; + LOG(2,("DAC2: PAL pixrdmsk readback $%02x\n", NV_REG8(NV8_PAL2MASK))); + + return B_OK; +} + +/*program the DAC palette using the given r,g,b values*/ +status_t nv_dac2_palette(uint8 r[256],uint8 g[256],uint8 b[256]) +{ + int i; + + LOG(4,("DAC2: setting palette\n")); + + /* select first PAL adress before starting programming */ + NV_REG8(NV8_PAL2INDW) = 0x00; + + /* loop through all 256 to program DAC */ + for (i = 0; i < 256; i++) + { + /* the 6 implemented bits are on b0-b5 of the bus */ + NV_REG8(NV8_PAL2DATA) = r[i]; + NV_REG8(NV8_PAL2DATA) = g[i]; + NV_REG8(NV8_PAL2DATA) = b[i]; + } + if (NV_REG8(NV8_PAL2INDW) != 0x00) + { + LOG(8,("DAC2: PAL write index incorrect after programming\n")); + return B_ERROR; + } +if (1) + {//reread LUT + uint8 R, G, B; + + /* select first PAL adress to read (modulo 3 counter) */ + NV_REG8(NV8_PAL2INDR) = 0x00; + for (i = 0; i < 256; i++) + { + R = NV_REG8(NV8_PAL2DATA); + G = NV_REG8(NV8_PAL2DATA); + B = NV_REG8(NV8_PAL2DATA); + if ((r[i] != R) || (g[i] != G) || (b[i] != B)) + LOG(1,("DAC2 palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed + } + } + + return B_OK; +} + +/*program the pixpll - frequency in kHz*/ +status_t nv_dac2_set_pix_pll(display_mode target) +{ + uint8 m=0,n=0,p=0; +// uint time = 0; + + float pix_setting, req_pclk; + status_t result; + + /* we offer this option because some panels have very tight restrictions, + * and there's no overlapping settings range that makes them all work. + * note: + * this assumes the cards BIOS correctly programmed the panel (is likely) */ + //fixme: when VESA DDC EDID stuff is implemented, this option can be deleted... + if (si->ps.tmds2_active && !si->settings.pgm_panel) + { + LOG(4,("DAC2: Not programming DFP refresh (specified in nv.settings)\n")); + return B_OK; + } + + /* fix a DVI or laptop flatpanel to 60Hz refresh! */ + /* Note: + * The pixelclock drives the flatpanel modeline, not the CRTC modeline. */ + if (si->ps.tmds2_active) + { + LOG(4,("DAC2: Fixing DFP refresh to 60Hz!\n")); + + /* use the panel's modeline to determine the needed pixelclock */ + target.timing.pixel_clock = si->ps.p2_timing.pixel_clock; + } + + req_pclk = (target.timing.pixel_clock)/1000.0; + LOG(4,("DAC2: Setting PIX PLL for pixelclock %f\n", req_pclk)); + + /* signal that we actually want to set the mode */ + result = nv_dac2_pix_pll_find(target,&pix_setting,&m,&n,&p, 1); + if (result != B_OK) + { + return result; + } + + /*reprogram (disable,select,wait for stability,enable)*/ +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ + + /* program new frequency */ + DAC2W(PIXPLLC, ((p << 16) | (n << 8) | m)); + + /* program 2nd set N and M scalers if they exist (b31=1 enables them) */ + if (si->ps.ext_pll) DAC2W(PIXPLLC2, 0x80000401); + + /* Wait for the PIXPLL frequency to lock until timeout occurs */ +//fixme: do NV cards have a LOCK indication bit?? +/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: PIX PLL frequency not locked!\n")); + else + LOG(2,("DAC: PIX PLL frequency locked\n")); + DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL +*/ + +//for now: + /* Give the PIXPLL frequency some time to lock... */ + snooze(1000); + LOG(2,("DAC2: PIX PLL frequency should be locked now...\n")); + + return B_OK; +} + +/* find nearest valid pix pll */ +status_t nv_dac2_pix_pll_find + (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) +{ + switch (si->ps.card_type) { + default: return nv10_nv20_dac2_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); + } + return B_ERROR; +} + +/* find nearest valid pixel PLL setting */ +static status_t nv10_nv20_dac2_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) +{ + int m = 0, n = 0, p = 0/*, m_max*/; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + /* determine the max. reference-frequency postscaler setting for the + * current card (see G100, G200 and G400 specs). */ +/* switch(si->ps.card_type) + { + case G100: + LOG(4,("DAC: G100 restrictions apply\n")); + m_max = 7; + break; + case G200: + LOG(4,("DAC: G200 restrictions apply\n")); + m_max = 7; + break; + default: + LOG(4,("DAC: G400/G400MAX restrictions apply\n")); + m_max = 32; + break; + } +*/ + LOG(4,("DAC2: NV10/NV20 restrictions apply\n")); + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac2_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac2_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac2_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclk = si->ps.max_dac2_clock_32dh; + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_pixel_vco divided by highest postscaler-factor */ + if (req_pclk < (si->ps.min_video_vco / 16.0)) + { + LOG(4,("DAC2: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_video_vco / 16.0))); + req_pclk = (si->ps.min_video_vco / 16.0); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("DAC2: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x20; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco)) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco /= 4; + + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 7; m <= 14; m++) + { + /* check if phase-discriminator will be within operational limits */ + //fixme: PLL calcs will be resetup/splitup/updated... + if (si->ps.card_type == NV36) + { + if (((si->ps.f_ref / m) < 3.2) || ((si->ps.f_ref / m) > 6.4)) continue; + } + else + { + if (((si->ps.f_ref / m) < 1.0) || ((si->ps.f_ref / m) > 2.0)) continue; + } + + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + /* ..and check for validity */ + if ((n < 1) || (n > 255)) continue; + + /* find error in frequency this setting gives */ + if (si->ps.ext_pll) + { + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + error = fabs((req_pclk / 4) - (((si->ps.f_ref / m) * n) / p)); + } + else + error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m = best[0]; + n = best[1]; + p = best[2]; + + /* log the VCO frequency found */ + f_vco = ((si->ps.f_ref / m) * n); + /* FX5600 and FX5700 tweak for 2nd set N and M scalers */ + if (si->ps.ext_pll) f_vco *= 4; + + LOG(2,("DAC2: pix VCO frequency found %fMhz\n", f_vco)); + + /* return the results */ + *calc_pclk = (f_vco / p); + *m_result = m; + *n_result = n; + switch(p) + { + case 1: + p = 0x00; + break; + case 2: + p = 0x01; + break; + case 4: + p = 0x02; + break; + case 8: + p = 0x03; + break; + case 16: + p = 0x04; + break; + } + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC2: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/general.c b/src/add-ons/accelerants/skeleton/engine/general.c new file mode 100644 index 0000000000..fbf2894be9 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/general.c @@ -0,0 +1,1454 @@ +/* Authors: + Mark Watson 12/1999, + Apsed, + Rudolf Cornelissen 10/2002-9/2004 +*/ + +#define MODULE_BIT 0x00008000 + +#include "nv_std.h" + +static status_t test_ram(void); +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 (CAPPTR, 0); + DUMP_CFG (CFG_1, 0); + DUMP_CFG (INTERRUPT,0); + DUMP_CFG (SUBSYSID2,0); + DUMP_CFG (AGPREF, 0); + DUMP_CFG (AGPSTAT, 0); + DUMP_CFG (AGPCMD, 0); + DUMP_CFG (ROMSHADOW,0); + DUMP_CFG (VGA, 0); + DUMP_CFG (SCHRATCH, 0); + DUMP_CFG (CFG_10, 0); + DUMP_CFG (CFG_11, 0); + DUMP_CFG (CFG_12, 0); + DUMP_CFG (CFG_13, 0); + DUMP_CFG (CFG_14, 0); + DUMP_CFG (CFG_15, 0); + DUMP_CFG (CFG_16, 0); + DUMP_CFG (CFG_17, 0); + DUMP_CFG (CFG_18, 0); + DUMP_CFG (CFG_19, 0); + DUMP_CFG (CFG_19, 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.30 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 0x004010de: /* Nvidia GeForce FX 6800 Ultra */ + case 0x004110de: /* Nvidia GeForce FX 6800 */ + case 0x004210de: /* Nvidia GeForce FX 6800LE */ + case 0x004510de: /* Nvidia GeForce FX 6800 GT */ + si->ps.card_type = NV40; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 6800 (NV40)\n")); + status = nvxx_general_powerup(); + break; + case 0x004310de: /* Nvidia unknown FX */ + si->ps.card_type = NV40; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia unknown FX (NV40)\n")); + status = nvxx_general_powerup(); + break; + case 0x004e10de: /* Nvidia Quadro FX 4000 */ + si->ps.card_type = NV40; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 4000 (NV40)\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 0x00c010de: /* Nvidia unknown FX */ + case 0x00c110de: /* Nvidia unknown FX */ + si->ps.card_type = NV41; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia unknown FX (NV41)\n")); + status = nvxx_general_powerup(); + break; + case 0x00f810de: /* Nvidia Quadro FX 3400 PCIe(?) */ + si->ps.card_type = NV35; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 3400 PCIe(?) (NV35(?))\n")); + status = nvxx_general_powerup(); + break; + case 0x00f910de: /* Nvidia GeForce PCX 6800 PCIe */ + si->ps.card_type = NV45; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia GeForce PCX 6800 PCIe (NV45)\n")); + status = nvxx_general_powerup(); + break; + case 0x00fa10de: /* Nvidia GeForce PCX 5750 PCIe */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce PCX 5750 PCIe (NV36(?))\n")); + status = nvxx_general_powerup(); + break; + case 0x00fb10de: /* Nvidia GeForce PCX 5900 PCIe */ + si->ps.card_type = NV35; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce PCX 5900 PCIe (NV35(?))\n")); + status = nvxx_general_powerup(); + break; + case 0x00fc10de: /* Nvidia GeForce PCX 5300 PCIe */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce PCX 5300 PCIe (NV34(?))\n")); + status = nvxx_general_powerup(); + break; + case 0x00fd10de: /* Nvidia Quadro PCX PCIe */ + si->ps.card_type = NV45; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia Quadro PCX PCIe (NV45)\n")); + status = nvxx_general_powerup(); + break; + case 0x00fe10de: /* Nvidia Quadro FX 1300 PCIe(?) */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 1300 PCIe(?) (NV36(?))\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 0x014010de: /* Nvidia GeForce FX 6600 GT */ + case 0x014110de: /* Nvidia GeForce FX 6600 */ + si->ps.card_type = NV43; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 6600 (NV43)\n")); + status = nvxx_general_powerup(); + break; + case 0x014510de: /* Nvidia GeForce FX 6610 XL */ + si->ps.card_type = NV43; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 6610 XL (NV43)\n")); + status = nvxx_general_powerup(); + break; + case 0x014e10de: /* Nvidia Quadro FX 540 */ + si->ps.card_type = NV43; + si->ps.card_arch = NV40A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 540 (NV43)\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 (on PPC GeForce4 MX) */ + 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; + case 0x017d10de: /* Nvidia GeForce4 410 Go 16M*/ + si->ps.card_type = NV17; + si->ps.card_arch = NV10A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce4 410 Go (NV17)\n")); + status = nvxx_general_powerup(); + break; + case 0x018110de: /* Nvidia GeForce4 MX 440 AGP8X */ + case 0x018210de: /* Nvidia GeForce4 MX 440SE AGP8X */ + case 0x018310de: /* Nvidia GeForce4 MX 420 AGP8X */ + case 0x018510de: /* Nvidia GeForce4 MX 4000 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 0x018610de: /* Nvidia GeForce4 448 Go */ + case 0x018710de: /* Nvidia GeForce4 488 Go */ + si->ps.card_type = NV18; + si->ps.card_arch = NV10A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce4 Go (NV18)\n")); + status = nvxx_general_powerup(); + break; + case 0x018810de: /* Nvidia Quadro4 580 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 0x018910de: /* Nvidia GeForce4 MX 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 0x018a10de: /* Nvidia Quadro4 280 NVS AGP8X */ + 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 0x025210de: /* Nvidia GeForce4 Ti 4600 */ + 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 4800 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 0x028c10de: /* Nvidia Quadro4 700 GoGL */ + si->ps.card_type = NV28; + si->ps.card_arch = NV20A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia Quadro4 700 GoGL (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 0x031310de: /* Nvidia unknown FX */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia unknown FX (NV31)\n")); + status = nvxx_general_powerup(); + break; + case 0x031410de: /* Nvidia GeForce FX 5600XT */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5600XT (NV31)\n")); + status = nvxx_general_powerup(); + break; + case 0x031610de: /* Nvidia unknown FX Go */ + case 0x031710de: /* Nvidia unknown FX Go */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia unknown FX Go (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 0x031b10de: /* Nvidia GeForce FX 5650 Go */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5650 Go (NV31)\n")); + status = nvxx_general_powerup(); + break; + case 0x031c10de: /* Nvidia Quadro FX 700 Go */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 700 Go (NV31)\n")); + status = nvxx_general_powerup(); + break; + case 0x031d10de: /* Nvidia unknown FX Go */ + case 0x031e10de: /* Nvidia unknown FX Go */ + case 0x031f10de: /* Nvidia unknown FX Go */ + si->ps.card_type = NV31; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia unknown FX Go (NV31)\n")); + status = nvxx_general_powerup(); + break; + case 0x032010de: /* Nvidia GeForce FX 5200 */ + case 0x032110de: /* Nvidia GeForce FX 5200 Ultra */ + case 0x032210de: /* Nvidia GeForce FX 5200 */ + case 0x032310de: /* Nvidia GeForce FX 5200SE */ + 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 0x032410de: /* Nvidia GeForce FX 5200 Go */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5200 Go (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032510de: /* Nvidia GeForce FX 5250 Go */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5250 Go (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032610de: /* Nvidia GeForce FX 5500 */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5500 (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032710de: /* Nvidia GeForce FX 5100 */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5100 (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032810de: /* Nvidia GeForce FX 5200 Go 32M/64M */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5200 Go (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032910de: /* Nvidia GeForce FX 5200 (PPC) */ + 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 0x032a10de: /* Nvidia Quadro NVS 280 PCI */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro NVS 280 PCI (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032b10de: /* Nvidia Quadro FX 500/600 PCI */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 500/600 PCI (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032c10de: /* Nvidia GeForce FX 5300 Go */ + case 0x032d10de: /* Nvidia GeForce FX 5100 Go */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX Go (NV34)\n")); + status = nvxx_general_powerup(); + break; + case 0x032e10de: /* Nvidia unknown FX Go */ + case 0x032f10de: /* Nvidia unknown FX Go */ + si->ps.card_type = NV34; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia unknown FX Go (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 0x033210de: /* Nvidia GeForce FX 5900 XT */ + si->ps.card_type = NV35; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5900 XT (NV35)\n")); + status = nvxx_general_powerup(); + break; + case 0x033310de: /* Nvidia GeForce FX 5950 Ultra */ + si->ps.card_type = NV38; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5950 Ultra (NV38)\n")); + status = nvxx_general_powerup(); + break; + case 0x033410de: /* Nvidia GeForce FX 5900 ZT */ + si->ps.card_type = NV38; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5900 ZT (NV38(?))\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; + case 0x033f10de: /* Nvidia Quadro FX 700 */ + si->ps.card_type = NV35; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 700 (NV35)\n")); + status = nvxx_general_powerup(); + break; + case 0x034110de: /* Nvidia GeForce FX 5700 Ultra */ + case 0x034210de: /* Nvidia GeForce FX 5700 */ + case 0x034310de: /* Nvidia GeForce FX 5700LE */ + case 0x034410de: /* Nvidia GeForce FX 5700VE */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5700 (NV36)\n")); + status = nvxx_general_powerup(); + break; + case 0x034710de: /* Nvidia GeForce FX 5700 Go */ + case 0x034810de: /* Nvidia GeForce FX 5700 Go */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia GeForce FX 5700 Go (NV36)\n")); + status = nvxx_general_powerup(); + break; + case 0x034c10de: /* Nvidia Quadro FX 1000 Go */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + si->ps.laptop = true; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 1000 Go (NV36)\n")); + status = nvxx_general_powerup(); + break; + case 0x034e10de: /* Nvidia Quadro FX 1100 */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia Quadro FX 1100 (NV36)\n")); + status = nvxx_general_powerup(); + break; + case 0x034f10de: /* Nvidia unknown FX */ + si->ps.card_type = NV36; + si->ps.card_arch = NV30A; + LOG(4,("POWERUP: Detected Nvidia unknown FX (NV36(?))\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; + } + + return status; +} + +static status_t test_ram() +{ + uint32 value, offset; + status_t result = B_OK; + + /* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */ + if (si->fbc.frame_buffer == NULL) + { + LOG(8,("INIT: test_ram detected NULL pointer.\n")); + return B_ERROR; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* write testpattern to cardRAM */ + ((uint32 *)si->fbc.frame_buffer)[offset] = value; + /* toggle testpattern */ + value = 0xffffffff - value; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* readback and verify testpattern from cardRAM */ + if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR; + /* toggle testpattern */ + value = 0xffffffff - value; + } + return result; +} + +/* NOTE: + * This routine *has* to be done *after* SetDispplayMode has been executed, + * or test results will not be representative! + * (CAS latency is dependant on NV setup on some (DRAM) boards) */ +status_t nv_set_cas_latency() +{ + status_t result = B_ERROR; + uint8 latency = 0; + + /* check current RAM access to see if we need to change anything */ + if (test_ram() == B_OK) + { + LOG(4,("INIT: RAM access OK.\n")); + return B_OK; + } + + /* check if we read PINS at starttime so we have valid registersettings at our disposal */ + if (si->ps.pins_status != B_OK) + { + LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n")); + return B_ERROR; + } + + /* OK. We might have a problem, try to fix it now.. */ + LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n")); + + switch(si->ps.card_type) + { + default: + LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n")); + return B_OK; + break; + } + if (result == B_OK) + LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency)); + else + LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency)); + + return result; +} + +void setup_virtualized_heads(bool cross) +{ + if (cross) + { + head1_validate_timing = (crtc_validate_timing) nv_crtc2_validate_timing; + head1_set_timing = (crtc_set_timing) nv_crtc2_set_timing; + head1_depth = (crtc_depth) nv_crtc2_depth; + head1_dpms = (crtc_dpms) nv_crtc2_dpms; + head1_dpms_fetch = (crtc_dpms_fetch) nv_crtc2_dpms_fetch; + head1_set_display_pitch = (crtc_set_display_pitch) nv_crtc2_set_display_pitch; + head1_set_display_start = (crtc_set_display_start) nv_crtc2_set_display_start; + head1_cursor_init = (crtc_cursor_init) nv_crtc2_cursor_init; + head1_cursor_show = (crtc_cursor_show) nv_crtc2_cursor_show; + head1_cursor_hide = (crtc_cursor_hide) nv_crtc2_cursor_hide; + head1_cursor_define = (crtc_cursor_define) nv_crtc2_cursor_define; + head1_cursor_position = (crtc_cursor_position) nv_crtc2_cursor_position; + + head1_mode = (dac_mode) nv_dac2_mode; + head1_palette = (dac_palette) nv_dac2_palette; + head1_set_pix_pll = (dac_set_pix_pll) nv_dac2_set_pix_pll; + head1_pix_pll_find = (dac_pix_pll_find) nv_dac2_pix_pll_find; + + head2_validate_timing = (crtc_validate_timing) nv_crtc_validate_timing; + head2_set_timing = (crtc_set_timing) nv_crtc_set_timing; + head2_depth = (crtc_depth) nv_crtc_depth; + head2_dpms = (crtc_dpms) nv_crtc_dpms; + head2_dpms_fetch = (crtc_dpms_fetch) nv_crtc_dpms_fetch; + head2_set_display_pitch = (crtc_set_display_pitch) nv_crtc_set_display_pitch; + head2_set_display_start = (crtc_set_display_start) nv_crtc_set_display_start; + head2_cursor_init = (crtc_cursor_init) nv_crtc_cursor_init; + head2_cursor_show = (crtc_cursor_show) nv_crtc_cursor_show; + head2_cursor_hide = (crtc_cursor_hide) nv_crtc_cursor_hide; + head2_cursor_define = (crtc_cursor_define) nv_crtc_cursor_define; + head2_cursor_position = (crtc_cursor_position) nv_crtc_cursor_position; + + head2_mode = (dac_mode) nv_dac_mode; + head2_palette = (dac_palette) nv_dac_palette; + head2_set_pix_pll = (dac_set_pix_pll) nv_dac_set_pix_pll; + head2_pix_pll_find = (dac_pix_pll_find) nv_dac_pix_pll_find; + } + else + { + head1_validate_timing = (crtc_validate_timing) nv_crtc_validate_timing; + head1_set_timing = (crtc_set_timing) nv_crtc_set_timing; + head1_depth = (crtc_depth) nv_crtc_depth; + head1_dpms = (crtc_dpms) nv_crtc_dpms; + head1_dpms_fetch = (crtc_dpms_fetch) nv_crtc_dpms_fetch; + head1_set_display_pitch = (crtc_set_display_pitch) nv_crtc_set_display_pitch; + head1_set_display_start = (crtc_set_display_start) nv_crtc_set_display_start; + head1_cursor_init = (crtc_cursor_init) nv_crtc_cursor_init; + head1_cursor_show = (crtc_cursor_show) nv_crtc_cursor_show; + head1_cursor_hide = (crtc_cursor_hide) nv_crtc_cursor_hide; + head1_cursor_define = (crtc_cursor_define) nv_crtc_cursor_define; + head1_cursor_position = (crtc_cursor_position) nv_crtc_cursor_position; + + head1_mode = (dac_mode) nv_dac_mode; + head1_palette = (dac_palette) nv_dac_palette; + head1_set_pix_pll = (dac_set_pix_pll) nv_dac_set_pix_pll; + head1_pix_pll_find = (dac_pix_pll_find) nv_dac_pix_pll_find; + + head2_validate_timing = (crtc_validate_timing) nv_crtc2_validate_timing; + head2_set_timing = (crtc_set_timing) nv_crtc2_set_timing; + head2_depth = (crtc_depth) nv_crtc2_depth; + head2_dpms = (crtc_dpms) nv_crtc2_dpms; + head2_dpms_fetch = (crtc_dpms_fetch) nv_crtc2_dpms_fetch; + head2_set_display_pitch = (crtc_set_display_pitch) nv_crtc2_set_display_pitch; + head2_set_display_start = (crtc_set_display_start) nv_crtc2_set_display_start; + head2_cursor_init = (crtc_cursor_init) nv_crtc2_cursor_init; + head2_cursor_show = (crtc_cursor_show) nv_crtc2_cursor_show; + head2_cursor_hide = (crtc_cursor_hide) nv_crtc2_cursor_hide; + head2_cursor_define = (crtc_cursor_define) nv_crtc2_cursor_define; + head2_cursor_position = (crtc_cursor_position) nv_crtc2_cursor_position; + + head2_mode = (dac_mode) nv_dac2_mode; + head2_palette = (dac_palette) nv_dac2_palette; + head2_set_pix_pll = (dac_set_pix_pll) nv_dac2_set_pix_pll; + head2_pix_pll_find = (dac_pix_pll_find) nv_dac2_pix_pll_find; + } +} + +void set_crtc_owner(bool head) +{ + if (si->ps.secondary_head) + { + if (!head) + { + /* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's, + * while non-NV11 cards behave normally. + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: needed on NV11 */ + CRTCW(OWNER, 0xff); + /* enable access to CRTC1, SEQ1, GRPH1, ATB1, ??? */ + CRTCW(OWNER, 0x00); + } + else + { + /* note: 'OWNER' is a non-standard register in behaviour(!) on NV11's, + * while non-NV11 cards behave normally. + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: needed on NV11 */ + CRTC2W(OWNER, 0xff); + /* enable access to CRTC2, SEQ2, GRPH2, ATB2, ??? */ + CRTC2W(OWNER, 0x03); + } + } +} + +static status_t nvxx_general_powerup() +{ + LOG(4, ("INIT: NV powerup\n")); + + /* setup cardspecs */ + /* note: + * this MUST be done before the driver attempts a card coldstart */ + set_specs(); + + /* only process BIOS for finetuning specs and coldstarting card if requested + * by the user; + * note: + * this in fact frees the driver from relying on the BIOS to be executed + * at system power-up POST time. */ + if (!si->settings.usebios) + { + LOG(2, ("INIT: Attempting card coldstart!\n")); + /* update the cardspecs in the shared_info PINS struct according to reported + * specs as much as is possible; + * this also coldstarts the card if possible (executes BIOS CMD script(s)) */ + parse_pins(); + } + else + { + LOG(2, ("INIT: Skipping card coldstart!\n")); + } + + /* get RAM size and fake panel startup (panel init code is still missing) */ + fake_panel_start(); + + /* log the final card specifications */ + dump_pins(); + + /* dump config space as it is after a possible coldstart attempt */ + if (si->settings.logmask & 0x80000000) nv_dump_configuration_space(); + + /* setup CRTC and DAC functions access: determined in fake_panel_start */ + setup_virtualized_heads(si->ps.crtc2_prim); + + /* do powerup needed from pre-inited card state as done by system POST cardBIOS + * execution or driver coldstart above */ + return nv_general_bios_to_powergraphics(); +} + +/* this routine switches the CRTC/DAC sets to 'connectors', but only for analog + * outputs. We need this to make sure the analog 'switch' is set in the same way the + * digital 'switch' is set by the BIOS or we might not be able to use dualhead. */ +status_t nv_general_output_select(bool cross) +{ + /* make sure this call is warranted */ + if (si->ps.secondary_head) + { + /* NV11 cards can't switch heads (confirmed) */ + if (si->ps.card_type != NV11) + { + if (cross) + { + LOG(4,("INIT: switching analog outputs to be cross-connected\n")); + + /* enable head 2 on connector 1 */ + /* (b8 = select CRTC (head) for output, + * b4 = ??? (confirmed not to be a FP switch), + * b0 = enable CRT) */ + DACW(OUTPUT, 0x00000101); + /* enable head 1 on connector 2 */ + DAC2W(OUTPUT, 0x00000001); + } + else + { + LOG(4,("INIT: switching analog outputs to be straight-through\n")); + + /* enable head 1 on connector 1 */ + DACW(OUTPUT, 0x00000001); + /* enable head 2 on connector 2 */ + DAC2W(OUTPUT, 0x00000101); + } + } + else + { + LOG(4,("INIT: NV11 analog outputs are hardwired to be straight-through\n")); + } + return B_OK; + } + else + { + return B_ERROR; + } +} + +/* this routine switches CRTC/DAC set use. We need this because it's unknown howto + * switch digital panels to/from a specific CRTC/DAC set. */ +status_t nv_general_head_select(bool cross) +{ + /* make sure this call is warranted */ + if (si->ps.secondary_head) + { + /* invert CRTC/DAC use to do switching */ + if (cross) + { + LOG(4,("INIT: switching CRTC/DAC use to be cross-connected\n")); + si->crtc_switch_mode = !si->ps.crtc2_prim; + } + else + { + LOG(4,("INIT: switching CRTC/DAC use to be straight-through\n")); + si->crtc_switch_mode = si->ps.crtc2_prim; + } + /* update CRTC and DAC functions access */ + setup_virtualized_heads(si->crtc_switch_mode); + + return B_OK; + } + else + { + return B_ERROR; + } +} + +/* basic change of card state from VGA to enhanced mode: + * Should work from VGA BIOS POST init state. */ +static status_t nv_general_bios_to_powergraphics() +{ + /* let acc engine make power off/power on cycle to start 'fresh' */ + NV_REG32(NV32_PWRUPCTRL) = 0x13110011; + snooze(1000); + + /* power-up all nvidia hardware function blocks */ + /* bit 28: OVERLAY ENGINE (BES), + * bit 25: CRTC2, (> NV04A) + * bit 24: CRTC1, + * bit 20: framebuffer, + * bit 16: PPMI, + * bit 12: PGRAPH, + * bit 8: PFIFO, + * bit 4: PMEDIA, + * bit 0: TVOUT. (> NV04A) */ + NV_REG32(NV32_PWRUPCTRL) = 0x13111111; + + /* select colormode CRTC registers base adresses */ + NV_REG8(NV8_MISCW) = 0xcb; + + /* enable access to primary head */ + set_crtc_owner(0); + /* unlock head's registers for R/W access */ + CRTCW(LOCK, 0x57); + CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + if (si->ps.secondary_head) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* unlock head's registers for R/W access */ + CRTC2W(LOCK, 0x57); + CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + } + + /* turn off both displays and the hardcursors (also disables transfers) */ + head1_dpms(false, false, false); + head1_cursor_hide(); + if (si->ps.secondary_head) + { + head2_dpms(false, false, false); + head2_cursor_hide(); + } + + if (si->ps.secondary_head) + { + /* switch overlay engine to CRTC1 */ + /* bit 17: GPU FP port #1 (confirmed NV25, NV28, confirmed not on NV34), + * bit 16: GPU FP port #2 (confirmed NV25, NV28, NV34), + * bit 12: overlay engine (all cards), + * bit 9: TVout chip #2 (confirmed on NV18, NV25, NV28), + * bit 8: TVout chip #1 (all cards), + * bit 4: both I2C busses (all cards) */ + NV_REG32(NV32_2FUNCSEL) &= ~0x00001000; + NV_REG32(NV32_FUNCSEL) |= 0x00001000; + } + si->overlay.crtc = false; + + /* enable 'enhanced' mode on primary head: */ + /* enable access to primary head */ + set_crtc_owner(0); + /* note: 'BUFFER' is a non-standard register in behaviour(!) on most + * NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards + * behave normally. + * Also readback is not nessesarily what was written before! + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: don't doublebuffer CRTC access: set programmed values immediately... */ + CRTCW(BUFFER, 0xff); + /* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */ + /* note: this has no effect on possible bandwidth issues. */ + CRTCW(BUFFER, 0xfb); + /* select VGA mode (old VGA register) */ + CRTCW(MODECTL, 0xc3); + /* select graphics mode (old VGA register) */ + SEQW(MEMMODE, 0x0e); + /* select 8 dots character clocks (old VGA register) */ + SEQW(CLKMODE, 0x21); + /* select VGA mode (old VGA register) */ + GRPHW(MODE, 0x00); + /* select graphics mode (old VGA register) */ + GRPHW(MISC, 0x01); + /* select graphics mode (old VGA register) */ + ATBW(MODECTL, 0x01); + /* enable 'enhanced mode', enable Vsync & Hsync, + * set DAC palette to 8-bit width, disable large screen */ + CRTCW(REPAINT1, 0x04); + + /* enable 'enhanced' mode on secondary head: */ + if (si->ps.secondary_head) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* select colormode CRTC2 registers base adresses */ + NV_REG8(NV8_MISCW) = 0xcb; + /* note: 'BUFFER' is a non-standard register in behaviour(!) on most + * NV11's like the GeForce2 MX200, while the MX400 and non-NV11 cards + * behave normally. + * Also readback is not nessesarily what was written before! + * + * Double-write action needed on those strange NV11 cards: */ + /* RESET: don't doublebuffer CRTC2 access: set programmed values immediately... */ + CRTC2W(BUFFER, 0xff); + /* ... and use fine pitched CRTC granularity on > NV4 cards (b2 = 0) */ + /* note: this has no effect on possible bandwidth issues. */ + CRTC2W(BUFFER, 0xfb); + /* select VGA mode (old VGA register) */ + CRTC2W(MODECTL, 0xc3); + /* select graphics mode (old VGA register) */ + SEQW(MEMMODE, 0x0e); + /* select 8 dots character clocks (old VGA register) */ + SEQW(CLKMODE, 0x21); + /* select VGA mode (old VGA register) */ + GRPHW(MODE, 0x00); + /* select graphics mode (old VGA register) */ + GRPHW(MISC, 0x01); + /* select graphics mode (old VGA register) */ + ATB2W(MODECTL, 0x01); + /* enable 'enhanced mode', enable Vsync & Hsync, + * set DAC palette to 8-bit width, disable large screen */ + CRTC2W(REPAINT1, 0x04); + } + + /* enable palettes */ + DACW(GENCTRL, 0x00100100); + if (si->ps.secondary_head) DAC2W(GENCTRL, 0x00100100); + + /* enable programmable PLLs */ + DACW(PLLSEL, 0x10000700); + if (si->ps.secondary_head) DACW(PLLSEL, (DACR(PLLSEL) | 0x20000800)); + + /* turn on DAC and make sure detection testsignal routing is disabled + * (b16 = disable DAC, + * b12 = enable testsignal output */ + DACW(TSTCTRL, (DACR(TSTCTRL) & 0xfffeefff)); + /* turn on DAC2 if it exists + * (NOTE: testsignal function block resides in DAC1 only (!)) */ + if (si->ps.secondary_head) DAC2W(TSTCTRL, (DAC2R(TSTCTRL) & 0xfffeefff)); + + /* setup AGP: + * Note: + * This may only be done when no transfers are in progress on the bus, so now + * is probably a good time.. */ + nv_agp_setup(); + + /* turn screen one on */ + head1_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. + * Also: check if virtual_width adheres to the cards granularity constraints, and + * create mode slopspace if not so. + * We use acc or crtc granularity constraints based on the 'worst case' scenario. + * + * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ +status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode) +{ + uint32 video_pitch; + uint32 acc_mask, crtc_mask; + uint32 max_crtc_width, max_acc_width; + uint8 depth = 8; + + /* determine pixel multiple based on 2D/3D engine constraints */ + switch (si->ps.card_arch) + { + default: + /* confirmed for: + * TNT1, TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */ + switch (target->space) + { + case B_CMAP8: acc_mask = 0x0f; depth = 8; break; + case B_RGB15: acc_mask = 0x07; depth = 16; break; + case B_RGB16: acc_mask = 0x07; depth = 16; break; + case B_RGB24: acc_mask = 0x0f; depth = 24; break; + case B_RGB32: acc_mask = 0x03; depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + /* NV31 (confirmed GeForceFX 5600) has NV20A granularity! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + case NV20A: + /* confirmed for: + * GeForce4 Ti4200 */ + switch (target->space) + { + case B_CMAP8: acc_mask = 0x3f; depth = 8; break; + case B_RGB15: acc_mask = 0x1f; depth = 16; break; + case B_RGB16: acc_mask = 0x1f; depth = 16; break; + case B_RGB24: acc_mask = 0x3f; depth = 24; break; + case B_RGB32: acc_mask = 0x0f; depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + } + + /* determine pixel multiple based on CRTC memory pitch constraints: + * -> all NV cards have same granularity constraints on CRTC1 and CRTC2, + * provided that the CRTC1 and CRTC2 BUFFER register b2 = 0; + * + * (Note: Don't mix this up with CRTC timing contraints! Those are + * multiples of 8 for horizontal, 1 for vertical timing.) */ + switch (si->ps.card_type) + { + default: +// case NV04: + /* confirmed for: + * TNT1 always; + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */ + /* NOTE: + * Unfortunately older cards have a hardware fault that prevents use. + * We need doubled granularity on those to prevent the single top line + * from shifting to the left! + * This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400. + * Confirmed OK are: + * GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */ + switch (target->space) + { + case B_CMAP8: crtc_mask = 0x0f; break; /* 0x07 */ + case B_RGB15: crtc_mask = 0x07; break; /* 0x03 */ + case B_RGB16: crtc_mask = 0x07; break; /* 0x03 */ + case B_RGB24: crtc_mask = 0x0f; break; /* 0x07 */ + case B_RGB32: crtc_mask = 0x03; break; /* 0x01 */ + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +// default: + /* confirmed for: + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */ +/* switch (target->space) + { + case B_CMAP8: crtc_mask = 0x1f; break; + case B_RGB15: crtc_mask = 0x0f; break; + case B_RGB16: crtc_mask = 0x0f; break; + case B_RGB24: crtc_mask = 0x1f; break; + case B_RGB32: crtc_mask = 0x07; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +*/ } + + /* set virtual_width limit for accelerated modes */ + switch (si->ps.card_arch) + { + case NV04A: + /* confirmed for: + * TNT1, TNT2, TNT2-M64 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 8176; break; + case B_RGB15: max_acc_width = 4088; break; + case B_RGB16: max_acc_width = 4088; break; + case B_RGB24: max_acc_width = 2720; break; + case B_RGB32: max_acc_width = 2044; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + default: + /* confirmed for: + * GeForce2 MX400, GeForce4 MX440, GeForceFX 5200 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 16368; break; + case B_RGB15: max_acc_width = 8184; break; + case B_RGB16: max_acc_width = 8184; break; + case B_RGB24: max_acc_width = 5456; break; + case B_RGB32: max_acc_width = 4092; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + /* NV31 (confirmed GeForceFX 5600) has NV20A granularity! + * So let it fall through... */ + if (si->ps.card_type != NV31) break; + case NV20A: + /* confirmed for: + * GeForce4 Ti4200 */ + switch(target->space) + { + case B_CMAP8: max_acc_width = 16320; break; + case B_RGB15: max_acc_width = 8160; break; + case B_RGB16: max_acc_width = 8160; break; + case B_RGB24: max_acc_width = 5440; break; + case B_RGB32: max_acc_width = 4080; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + } + + /* set virtual_width limit for unaccelerated modes */ + switch (si->ps.card_type) + { + default: +// case NV04: + /* confirmed for: + * TNT1 always; + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 0 */ + /* NOTE: + * Unfortunately older cards have a hardware fault that prevents use. + * We need doubled granularity on those to prevent the single top line + * from shifting to the left! + * This is confirmed for TNT2, GeForce2 MX200, GeForce2 MX400. + * Confirmed OK are: + * GeForce4 MX440, GeForce4 Ti4200, GeForceFX 5200. */ + switch(target->space) + { + case B_CMAP8: max_crtc_width = 16368; break; /* 16376 */ + case B_RGB15: max_crtc_width = 8184; break; /* 8188 */ + case B_RGB16: max_crtc_width = 8184; break; /* 8188 */ + case B_RGB24: max_crtc_width = 5456; break; /* 5456 */ + case B_RGB32: max_crtc_width = 4092; break; /* 4094 */ + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +// default: + /* confirmed for: + * TNT2, TNT2-M64, GeForce2 MX400, GeForce4 MX440, GeForce4 Ti4200, + * GeForceFX 5200: if the CRTC1 (and CRTC2) BUFFER register b2 = 1 */ +/* switch(target->space) + { + case B_CMAP8: max_crtc_width = 16352; break; + case B_RGB15: max_crtc_width = 8176; break; + case B_RGB16: max_crtc_width = 8176; break; + case B_RGB24: max_crtc_width = 5440; break; + case B_RGB32: max_crtc_width = 4088; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +*/ } + + /* check for acc capability, and adjust mode to adhere to hardware constraints */ + if (max_acc_width <= max_crtc_width) + { + /* check if we can setup this mode with acceleration */ + *acc_mode = true; + /* virtual_width */ + if (target->virtual_width > max_acc_width) *acc_mode = false; + /* virtual_height */ + /* (NV cards can even do more than this(?)... + * but 4096 is confirmed on all cards at max. accelerated width.) */ + if (target->virtual_height > 4096) *acc_mode = false; + + /* now check virtual_size based on CRTC constraints */ + if (target->virtual_width > max_crtc_width) target->virtual_width = max_crtc_width; + /* virtual_height: The only constraint here is the cards memory size which is + * checked later on in ProposeMode: virtual_height is adjusted then if needed. + * 'Limiting here' to the variable size that's at least available (uint16). */ + if (target->virtual_height > 65535) target->virtual_height = 65535; + + /* OK, now we know that virtual_width is valid, and it's needing no slopspace if + * it was confined above, so we can finally calculate safely if we need slopspace + * for this mode... */ + if (*acc_mode) + { + /* the mode needs to adhere to the largest granularity imposed... */ + if (acc_mask < crtc_mask) + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + else + video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); + } + else /* unaccelerated mode */ + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + } + else /* max_acc_width > max_crtc_width */ + { + /* check if we can setup this mode with acceleration */ + *acc_mode = true; + /* (we already know virtual_width will be no problem) */ + /* virtual_height */ + /* (NV cards can even do more than this(?)... + * but 4096 is confirmed on all cards at max. accelerated width.) */ + if (target->virtual_height > 4096) *acc_mode = false; + + /* now check virtual_size based on CRTC constraints */ + if (*acc_mode) + { + /* note that max_crtc_width already adheres to crtc_mask */ + if (target->virtual_width > (max_crtc_width & ~acc_mask)) + target->virtual_width = (max_crtc_width & ~acc_mask); + } + else /* unaccelerated mode */ + { + if (target->virtual_width > max_crtc_width) + target->virtual_width = max_crtc_width; + } + /* virtual_height: The only constraint here is the cards memory size which is + * checked later on in ProposeMode: virtual_height is adjusted then if needed. + * 'Limiting here' to the variable size that's at least available (uint16). */ + if (target->virtual_height > 65535) target->virtual_height = 65535; + + /* OK, now we know that virtual_width is valid, and it's needing no slopspace if + * it was confined above, so we can finally calculate safely if we need slopspace + * for this mode... */ + if (*acc_mode) + { + /* the mode needs to adhere to the largest granularity imposed... */ + if (acc_mask < crtc_mask) + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + else + video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); + } + else /* unaccelerated mode */ + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + } + + LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n", + video_pitch, target->space)); + if (target->virtual_width != video_pitch) + LOG(2,("INIT: effective mode slopspace is %d pixels\n", + (video_pitch - target->virtual_width))); + + /* now calculate bytes_per_row for this mode */ + *bytes_per_row = video_pitch * (depth >> 3); + + return B_OK; +} diff --git a/src/add-ons/accelerants/skeleton/engine/globals.c b/src/add-ons/accelerants/skeleton/engine/globals.c new file mode 100644 index 0000000000..af3fb8c8a6 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/globals.c @@ -0,0 +1,35 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Rudolf Cornelissen 8/2004 +*/ + +#include "nv_std.h" + +int fd; +shared_info *si; +area_id shared_info_area; +vuint32 *regs; +area_id regs_area; +display_mode *my_mode_list; +area_id my_mode_list_area; +int accelerantIsClone; + +nv_get_set_pci nv_pci_access= + { + NV_PRIVATE_DATA_MAGIC, + 0, + 4, + 0 + }; + +nv_in_out_isa nv_isa_access= + { + NV_PRIVATE_DATA_MAGIC, + 0, + 1, + 0 + }; diff --git a/src/add-ons/accelerants/skeleton/engine/globals.h b/src/add-ons/accelerants/skeleton/engine/globals.h new file mode 100644 index 0000000000..5afab87516 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/globals.h @@ -0,0 +1,66 @@ +extern int fd; +extern shared_info *si; +extern area_id shared_info_area; +extern area_id regs_area; +extern vuint32 *regs; +extern display_mode *my_mode_list; +extern area_id my_mode_list_area; +extern int accelerantIsClone; + +extern nv_get_set_pci nv_pci_access; +extern nv_in_out_isa nv_isa_access; + + +typedef status_t (*crtc_validate_timing)(uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*, uint16*); +typedef status_t (*crtc_set_timing)(display_mode); +typedef status_t (*crtc_depth)(int); +typedef status_t (*crtc_dpms)(bool, bool, bool); +typedef status_t (*crtc_dpms_fetch)(bool*, bool*, bool*); +typedef status_t (*crtc_set_display_pitch)(void); +typedef status_t (*crtc_set_display_start)(uint32, uint8); +typedef status_t (*crtc_cursor_init)(void); +typedef status_t (*crtc_cursor_show)(void); +typedef status_t (*crtc_cursor_hide)(void); +typedef status_t (*crtc_cursor_define)(uint8*, uint8*); +typedef status_t (*crtc_cursor_position)(uint16, uint16); + +typedef status_t (*dac_mode)(int, float); +typedef status_t (*dac_palette)(uint8[256], uint8[256], uint8[256]); +typedef status_t (*dac_set_pix_pll)(display_mode); +typedef status_t (*dac_pix_pll_find)(display_mode, float*, uint8*, uint8*, uint8*, uint8); + +crtc_validate_timing head1_validate_timing; +crtc_set_timing head1_set_timing; +crtc_depth head1_depth; +crtc_dpms head1_dpms; +crtc_dpms_fetch head1_dpms_fetch; +crtc_set_display_pitch head1_set_display_pitch; +crtc_set_display_start head1_set_display_start; +crtc_cursor_init head1_cursor_init; +crtc_cursor_show head1_cursor_show; +crtc_cursor_hide head1_cursor_hide; +crtc_cursor_define head1_cursor_define; +crtc_cursor_position head1_cursor_position; + +crtc_validate_timing head2_validate_timing; +crtc_set_timing head2_set_timing; +crtc_depth head2_depth; +crtc_dpms head2_dpms; +crtc_dpms_fetch head2_dpms_fetch; +crtc_set_display_pitch head2_set_display_pitch; +crtc_set_display_start head2_set_display_start; +crtc_cursor_init head2_cursor_init; +crtc_cursor_show head2_cursor_show; +crtc_cursor_hide head2_cursor_hide; +crtc_cursor_define head2_cursor_define; +crtc_cursor_position head2_cursor_position; + +dac_mode head1_mode; +dac_palette head1_palette; +dac_set_pix_pll head1_set_pix_pll; +dac_pix_pll_find head1_pix_pll_find; + +dac_mode head2_mode; +dac_palette head2_palette; +dac_set_pix_pll head2_set_pix_pll; +dac_pix_pll_find head2_pix_pll_find; diff --git a/src/add-ons/accelerants/skeleton/engine/i2c.c b/src/add-ons/accelerants/skeleton/engine/i2c.c new file mode 100644 index 0000000000..1e12005f7a --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/i2c.c @@ -0,0 +1,348 @@ +/* + * i2c interface for the G400 MAVEN under BeOS + * + * Provides I2CR,I2CW - functions to parallel DACW,DACR + * Bus should be run at max. 100kHz: see original Philips I2C specification + * + * Much help was provided by observing the Linux i2c code, + * so thanks go to: Gerd Knorr + * + * Other authors: + * Mark Watson 6/2000, + * Rudolf Cornelissen 12/2002-12/2003 + */ + +#define MODULE_BIT 0x00004000 + +#include "nv_std.h" + +int i2c_set_lines(int clock, int data); +int i2c_get_data(void); +void i2c_start(void); +void i2c_stop(void); +void i2c_high(void); +void i2c_low(void); +int i2c_get_ack(void); +void i2c_send_ack(void); +int i2c_sendbyte(unsigned char data); +unsigned char i2c_readbyte(int ack_required); + +/*which device on the bus is the MAVEN?*/ +#define MAVEN_WRITE (0x1B<<1) +#define MAVEN_READ ((0x1B<<1)|1) + +#define I2C_CLOCK 0x20 +#define I2C_DATA 0x10 + +/* NV-TVO I2C for G200, G400 */ +#define I2C_CLOCK 0x20 +#define I2C_DATA 0x10 +/* primary head DDC for Mystique(?), G100, G200, G400 */ +#define DDC1_CLK 0x08 +#define DDC1_DATA 0x02 +/* primary head DDC for Millennium, Millennium II */ +#define DDC1B_CLK 0x10 +#define DDC1B_DATA 0x04 +/* secondary head DDC for G400, G450 and G550 */ +#define DDC2_CLK 0x04 +#define DDC2_DATA 0x01 + +status_t i2c_sec_tv_adapter() +{ + status_t result = B_ERROR; + + /* The secondary DDC channel only exist on dualhead cards */ + if (!si->ps.secondary_head) return result; + + /* make sure the output lines will be active-low when enabled + * (they will be pulled 'passive-high' when disabled) */ +// DXIW(GENIODATA,0x00); + /* send out B_STOP condition on secondary head DDC channel and use it to + * check for 'shortcut', indicating the Matrox VGA->TV adapter is connected */ + + /* make sure SDA is low */ +// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) | DDC2_DATA)); + snooze(2); + /* make sure SCL should be high */ +// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_CLK)); + snooze(2); + /* if SCL is low then the bus is blocked by a TV adapter */ +// if (!(DXIR(GENIODATA) & DDC2_CLK)) result = B_OK; + snooze(5); + /* set SDA while SCL should be set (generates actual bus-stop condition) */ +// DXIW(GENIOCTRL, (DXIR(GENIOCTRL) & ~DDC2_DATA)); + snooze(5); + + return result; +} + +/*----------------------------- + *low level hardware access + */ +#define I2C_DELAY 2 +#define I2C_TIMEOUT 100 +int i2c_set_lines(int clock,int data) +{ + int count=0; + int program; + int required; + + /*work out which bits to zero*/ + program = + (clock ? 0 : I2C_CLOCK)| + (data ? 0 : I2C_DATA); + + /*what value do I require on data lines*/ + required = + (clock ? I2C_CLOCK : 0); + + /*set the bits to zero*/ +// DXIW(GENIOCTRL,program); /*drive these bits*/ +// DXIW(GENIODATA,0x00); /*to zero*/ + + /*wait a bit*/ + delay(I2C_DELAY); + + /*loop until the clock is as required*/ +// while ((DXIR(GENIODATA)&I2C_CLOCK)!=required) + { + delay(I2C_DELAY); + count++; + if (count>I2C_TIMEOUT) + { +// LOG(8,("I2C: Timeout on set lines - clock:%d data:%d actual:%x\n",clock,data,DXIR(GENIODATA))); + return -1; + } + } + + return 0; +} + +int i2c_get_data() +{ + int data = 0; + int clock; + int count=0; + + do + { + /*read the data and clock lines*/ +// data = DXIR(GENIODATA); + clock = (data&I2C_CLOCK) ? 1 : 0; + data = (data&I2C_DATA) ? 1 : 0; + + /*manage timeout*/ + count++; + if (count>I2C_TIMEOUT) + { + return -1; + } + + /*wait a bit, so not hammering bus*/ + delay(I2C_DELAY); + + }while (!clock); /*wait for high clock*/ + + return data; +} + + +/*----------------------- + *Standard I2C operations + */ +void i2c_start() +{ + int error=0; + + error+= i2c_set_lines(0,1); + error+= i2c_set_lines(1,1); + error+= i2c_set_lines(1,0); + error+= i2c_set_lines(0,0); + + if (error) + { + LOG(8,("I2C: start - %d\n",error)); + } +} + +void i2c_stop() +{ + int error=0; + + error+= i2c_set_lines(0,0); + error+= i2c_set_lines(1,0); + error+= i2c_set_lines(1,1); + error+= i2c_set_lines(0,1); + + if (error) + { + LOG(8,("I2C: stop - %d\n",error)); + } +} + +void i2c_high() +{ + int error=0; + + error+= i2c_set_lines(0,1); + error+= i2c_set_lines(1,1); + error+= i2c_set_lines(0,1); + + if (error) + { + LOG(8,("I2C: high - %d\n",error)); + } +} + +void i2c_low() +{ + int error=0; + + error+= i2c_set_lines(0,0); + error+= i2c_set_lines(1,0); + error+= i2c_set_lines(0,0); + + if (error) + { + LOG(8,("I2C: low - %d\n",error)); + } +} + +int i2c_get_ack() +{ + int error=0; + int ack; + + error+= i2c_set_lines(0,1); + error+= i2c_set_lines(1,1); + ack = i2c_get_data(); + error+= i2c_set_lines(0,1); + + if (error) + { + LOG(8,("I2C: get_ack - %d value:%x\n",error,ack)); + } + + return ack; +} + +void i2c_send_ack() +{ + int error=0; + + error+= i2c_set_lines(0,0); + error+= i2c_set_lines(1,0); + error+= i2c_set_lines(0,0); + + if (error) + { + LOG(8,("I2C: send_ack - %d\n",error)); + } +} + +/*------------------------------ + *use above functions to send and receive bytes + */ + +int i2c_sendbyte(unsigned char data) +{ + int i; + + for (i=7; i>=0; i--) + { + if (data&(1<=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/skeleton/engine/info.c b/src/add-ons/accelerants/skeleton/engine/info.c new file mode 100644 index 0000000000..f65c921929 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/info.c @@ -0,0 +1,3126 @@ +/* Read initialisation information from card */ +/* some bits are hacks, where PINS is not known */ +/* Author: + Rudolf Cornelissen 7/2003-10/2004 +*/ + +#define MODULE_BIT 0x00002000 + +#include "nv_std.h" + +/* pins V5.16 and up ROM infoblock stuff */ +typedef struct { + uint16 InitScriptTablePtr; /* ptr to list of ptrs to scripts to exec */ + uint16 MacroIndexTablePtr; /* ptr to list with indexes and sizes of items in MacroTable */ + uint16 MacroTablePtr; /* ptr to list with items containing multiple 32bit reg writes */ + uint16 ConditionTablePtr; /* ptr to list of PCI regs and bits to tst for exec mode */ + uint16 IOConditionTablePtr; /* ptr to list of ISA regs and bits to tst for exec mode */ + uint16 IOFlagConditionTablePtr;/* ptr to list of ISA regs and bits to tst, ref'd to a matrix, for exec mode */ + uint16 InitFunctionTablePtr; /* ptr to list of startadresses of fixed ROM init routines */ +} PinsTables; + +static void detect_panels(void); +static void setup_output_matrix(void); +static void pinsnv4_fake(void); +static void pinsnv5_nv5m64_fake(void); +static void pinsnv6_fake(void); +static void pinsnv10_arch_fake(void); +static void pinsnv20_arch_fake(void); +static void pinsnv30_arch_fake(void); +static void getRAMsize_arch_nv4(void); +static void getstrap_arch_nv4(void); +static void getRAMsize_arch_nv10_20_30_40(void); +static void getstrap_arch_nv10_20_30_40(void); +static status_t pins2_read(uint8 *rom, uint32 offset); +static status_t pins3_5_read(uint8 *rom, uint32 offset); +static status_t coldstart_card(uint8* rom, uint16 init1, uint16 init2, uint16 init_size, uint16 ram_tab); +static status_t coldstart_card_516_up(uint8* rom, PinsTables tabs, uint16 ram_tab); +static status_t exec_type1_script(uint8* rom, uint16 adress, int16* size, uint16 ram_tab); +static status_t exec_type2_script(uint8* rom, uint16 adress, int16* size, PinsTables tabs, uint16 ram_tab); +static status_t exec_type2_script_mode(uint8* rom, uint16* adress, int16* size, PinsTables tabs, uint16 ram_tab, bool* exec); +static void exec_cmd_39_type2(uint8* rom, uint32 data, PinsTables tabs, bool* exec); +static void log_pll(uint32 reg, uint32 freq); +static void setup_ram_config(uint8* rom, uint16 ram_tab); +static void setup_ram_config_nv10_up(uint8* rom); +static void setup_ram_config_nv28(uint8* rom); +static status_t translate_ISA_PCI(uint32* reg); +static status_t nv_crtc_setup_fifo(void); + +/* Parse the BIOS PINS structure if there */ +status_t parse_pins () +{ + uint8 *rom; + uint8 chksum = 0; + int i; + uint32 offset; + 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 - this is defined in the PCI standard */ + if (rom[0]!=0x55 || rom[1]!=0xaa) + { + LOG(8,("INFO: BIOS signature not found\n")); + return B_ERROR; + } + LOG(2,("INFO: BIOS signature $AA55 found OK\n")); + + /* find the PINS struct adress */ + for (offset = 0; offset < 65536; offset++) + { + if (rom[offset ] != 0xff) continue; + if (rom[offset + 1] != 0x7f) continue; + if (rom[offset + 2] != 0x4e) continue; /* N */ + if (rom[offset + 3] != 0x56) continue; /* V */ + if (rom[offset + 4] != 0x00) continue; + + LOG(8,("INFO: PINS signature found\n")); + break; + } + + if (offset > 65535) + { + LOG(8,("INFO: PINS signature not found\n")); + return B_ERROR; + } + + /* verify PINS checksum */ + for (i = 0; i < 8; i++) + { + chksum += rom[offset + i]; + } + if (chksum) + { + LOG(8,("INFO: PINS checksum error\n")); + return B_ERROR; + } + + /* checkout PINS struct version */ + LOG(2,("INFO: PINS checksum is OK; PINS version is %d.%d\n", + rom[offset + 5], rom[offset + 6])); + + /* update the si->ps struct as far as is possible and coldstart card */ + //fixme: NV40 and up(?) nolonger use this system... + switch (rom[offset + 5]) + { + case 2: + result = pins2_read(rom, offset); + break; + case 3: + case 4: + case 5: + result = pins3_5_read(rom, offset); + break; + default: + LOG(8,("INFO: unknown PINS version\n")); + return B_ERROR; + break; + } + + /* check PINS read result */ + if (result == B_ERROR) + { + LOG(8,("INFO: PINS read/decode/execute 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; +} + +static status_t pins2_read(uint8 *rom, uint32 offset) +{ + uint16 init1 = rom[offset + 18] + (rom[offset + 19] * 256); + uint16 init2 = rom[offset + 20] + (rom[offset + 21] * 256); + uint16 init_size = rom[offset + 22] + (rom[offset + 23] * 256) + 1; + /* confirmed by comparing cards */ + uint16 ram_tab = init1 - 0x0010; + /* fixme: PPC BIOSes (might) return NULL pointers for messages here */ + char* signon_msg = &(rom[(rom[offset + 24] + (rom[offset + 25] * 256))]); + char* vendor_name = &(rom[(rom[offset + 40] + (rom[offset + 41] * 256))]); + char* product_name = &(rom[(rom[offset + 42] + (rom[offset + 43] * 256))]); + char* product_rev = &(rom[(rom[offset + 44] + (rom[offset + 45] * 256))]); + + LOG(8,("INFO: cmdlist 1: $%04x, 2: $%04x, max. size $%04x\n", init1, init2, init_size)); + LOG(8,("INFO: signon msg:\n%s\n", signon_msg)); + LOG(8,("INFO: vendor name: %s\n", vendor_name)); + LOG(8,("INFO: product name: %s\n", product_name)); + LOG(8,("INFO: product rev: %s\n", product_rev)); + + return coldstart_card(rom, init1, init2, init_size, ram_tab); +} + +static status_t pins3_5_read(uint8 *rom, uint32 offset) +{ + uint16 init1 = rom[offset + 18] + (rom[offset + 19] * 256); + uint16 init2 = rom[offset + 20] + (rom[offset + 21] * 256); + uint16 init_size = rom[offset + 22] + (rom[offset + 23] * 256) + 1; + /* still confirm!! */ + uint16 ram_tab = init1 - 0x0010; + /* fixme: PPC BIOSes (might) return NULL pointers for messages here */ + char* signon_msg = &(rom[(rom[offset + 30] + (rom[offset + 31] * 256))]); + char* vendor_name = &(rom[(rom[offset + 46] + (rom[offset + 47] * 256))]); + char* product_name = &(rom[(rom[offset + 48] + (rom[offset + 49] * 256))]); + char* product_rev = &(rom[(rom[offset + 50] + (rom[offset + 51] * 256))]); + + LOG(8,("INFO: pre PINS 5.16 cmdlist 1: $%04x, 2: $%04x, max. size $%04x\n", init1, init2, init_size)); + LOG(8,("INFO: signon msg:\n%s\n", signon_msg)); + LOG(8,("INFO: vendor name: %s\n", vendor_name)); + LOG(8,("INFO: product name: %s\n", product_name)); + LOG(8,("INFO: product rev: %s\n", product_rev)); + + /* pins 5.06 and higher has VCO range info */ + if (((rom[offset + 5]) == 5) && ((rom[offset + 6]) >= 0x06)) + { + /* get PLL VCO range info */ + uint32 fvco_max = *((uint32*)(&(rom[offset + 67]))); + uint32 fvco_min = *((uint32*)(&(rom[offset + 71]))); + + LOG(8,("INFO: PLL VCO range is %dkHz - %dkHz\n", fvco_min, fvco_max)); + + /* modify presets to reflect card capability */ + si->ps.min_system_vco = fvco_min / 1000; + si->ps.max_system_vco = fvco_max / 1000; + //fixme: enable and modify PLL code... + //si->ps.min_pixel_vco = fvco_min / 1000; + //si->ps.max_pixel_vco = fvco_max / 1000; + //si->ps.min_video_vco = fvco_min / 1000; + //si->ps.max_video_vco = fvco_max / 1000; + } + + //fixme: add 'parsing scripts while not actually executing' as warmstart method, + // instead of not parsing at all: this will update the driver's speeds + // as below, while logging the scripts as well (for our learning pleasure :) + + /* pins 5.16 and higher is more extensive, and works differently from before */ + if (((rom[offset + 5]) == 5) && ((rom[offset + 6]) >= 0x10)) + { + /* pins 5.16 and up have a more extensive command list table, and have more + * commands to choose from as well. */ + PinsTables tabs; + tabs.InitScriptTablePtr = rom[offset + 75] + (rom[offset + 76] * 256); + tabs.MacroIndexTablePtr = rom[offset + 77] + (rom[offset + 78] * 256); + tabs.MacroTablePtr = rom[offset + 79] + (rom[offset + 80] * 256); + tabs.ConditionTablePtr = rom[offset + 81] + (rom[offset + 82] * 256); + tabs.IOConditionTablePtr = rom[offset + 83] + (rom[offset + 84] * 256); + tabs.IOFlagConditionTablePtr = rom[offset + 85] + (rom[offset + 86] * 256); + tabs.InitFunctionTablePtr = rom[offset + 87] + (rom[offset + 88] * 256); + + LOG(8,("INFO: PINS 5.16 and later cmdlist pointers:\n")); + LOG(8,("INFO: InitScriptTablePtr: $%04x\n", tabs.InitScriptTablePtr)); + LOG(8,("INFO: MacroIndexTablePtr: $%04x\n", tabs.MacroIndexTablePtr)); + LOG(8,("INFO: MacroTablePtr: $%04x\n", tabs.MacroTablePtr)); + LOG(8,("INFO: ConditionTablePtr: $%04x\n", tabs.ConditionTablePtr)); + LOG(8,("INFO: IOConditionTablePtr: $%04x\n", tabs.IOConditionTablePtr)); + LOG(8,("INFO: IOFlagConditionTablePtr: $%04x\n", tabs.IOFlagConditionTablePtr)); + LOG(8,("INFO: InitFunctionTablePtr: $%04x\n", tabs.InitFunctionTablePtr)); + + return coldstart_card_516_up(rom, tabs, ram_tab); + } + else + { + /* pre 'pins 5.16' still uses the 'old' method in which the command list + * table always has two entries. */ + return coldstart_card(rom, init1, init2, init_size, ram_tab); + } +} + +static status_t coldstart_card(uint8* rom, uint16 init1, uint16 init2, uint16 init_size, uint16 ram_tab) +{ + status_t result = B_OK; + int16 size = init_size; + + LOG(8,("INFO: now executing coldstart...\n")); + + /* select colormode CRTC registers base adresses */ + NV_REG8(NV8_MISCW) = 0xcb; + + /* unknown.. */ + NV_REG8(NV8_VSE2) = 0x01; + + /* enable access to primary head */ + set_crtc_owner(0); + /* unlock head's registers for R/W access */ + CRTCW(LOCK, 0x57); + CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + /* disable RMA as it's not used */ + /* (RMA is the cmd register for the 32bit port in the GPU to access 32bit registers + * and framebuffer via legacy ISA I/O space.) */ + CRTCW(RMA, 0x00); + + if (si->ps.secondary_head) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* unlock head's registers for R/W access */ + CRTC2W(LOCK, 0x57); + CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + } + + /* turn off both displays and the hardcursors (also disables transfers) */ + nv_crtc_dpms(false, false, false); + nv_crtc_cursor_hide(); + if (si->ps.secondary_head) + { + nv_crtc2_dpms(false, false, false); + nv_crtc2_cursor_hide(); + } + + /* execute BIOS coldstart script(s) */ + if (init1 || init2) + { + if (init1) + if (exec_type1_script(rom, init1, &size, ram_tab) != B_OK) result = B_ERROR; + if (init2 && (result == B_OK)) + if (exec_type1_script(rom, init2, &size, ram_tab) != B_OK) result = B_ERROR; + + /* now enable ROM shadow or the card will remain shut-off! */ + CFGW(ROMSHADOW, (CFGR(ROMSHADOW) |= 0x00000001)); + + //temporary: should be called from setmode probably.. + nv_crtc_setup_fifo(); + } + else + { + result = B_ERROR; + } + + if (result != B_OK) + LOG(8,("INFO: coldstart failed.\n")); + else + LOG(8,("INFO: coldstart execution completed OK.\n")); + + return result; +} + +static status_t coldstart_card_516_up(uint8* rom, PinsTables tabs, uint16 ram_tab) +{ + status_t result = B_OK; + uint16 adress; + uint32 fb_mrs1 = 0; + uint32 fb_mrs2 = 0; + + LOG(8,("INFO: now executing coldstart...\n")); + + /* get some strapinfo(?) for NV28 framebuffer access */ + //fixme?: works on at least one NV28... how about other cards? + if (si->ps.card_type == NV28) + { + fb_mrs2 = NV_REG32(NV32_FB_MRS2); + fb_mrs1 = NV_REG32(NV32_FB_MRS1); + } + + /* select colormode CRTC registers base adresses */ + NV_REG8(NV8_MISCW) = 0xcb; + + /* unknown.. */ + NV_REG8(NV8_VSE2) = 0x01; + + /* enable access to primary head */ + set_crtc_owner(0); + /* unlock head's registers for R/W access */ + CRTCW(LOCK, 0x57); + CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + /* disable RMA as it's not used */ + /* (RMA is the cmd register for the 32bit port in the GPU to access 32bit registers + * and framebuffer via legacy ISA I/O space.) */ + CRTCW(RMA, 0x00); + + if (si->ps.secondary_head) + { + /* enable access to secondary head */ + set_crtc_owner(1); + /* unlock head's registers for R/W access */ + CRTC2W(LOCK, 0x57); + CRTC2W(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + } + + /* turn off both displays and the hardcursors (also disables transfers) */ + nv_crtc_dpms(false, false, false); + nv_crtc_cursor_hide(); + if (si->ps.secondary_head) + { + nv_crtc2_dpms(false, false, false); + nv_crtc2_cursor_hide(); + } + + /* execute all BIOS coldstart script(s) */ + if (tabs.InitScriptTablePtr) + { + /* size is nolonger used, keeping it anyway for testing purposes :) */ + int16 size = 32767; + uint16 index = tabs.InitScriptTablePtr; + + adress = *((uint16*)(&(rom[index]))); + if (!adress) + { + LOG(8,("INFO: no cmdlist found!\n")); + result = B_ERROR; + } + + while (adress && (result == B_OK)) + { + result = exec_type2_script(rom, adress, &size, tabs, ram_tab); + /* next command script, please */ + index += 2; + adress = *((uint16*)(&(rom[index]))); + } + + /* do some NV28 specific extra stuff */ + //fixme: NV28 only?? + if (si->ps.card_type == NV28) + { + /* setup PTIMER */ + ACCW(PT_NUMERATOR, (si->ps.std_engine_clock * 20)); + ACCW(PT_DENOMINATR, 0x00000271); + + /* get NV28 RAM access up and running */ + //fixme?: works on at least one NV28... how about other cards? + NV_REG32(NV32_FB_MRS2) = fb_mrs2; + NV_REG32(NV32_FB_MRS1) = fb_mrs1; + } + + /* now enable ROM shadow or the card will remain shut-off! */ + CFGW(ROMSHADOW, (CFGR(ROMSHADOW) |= 0x00000001)); + + //temporary: should be called from setmode probably.. + nv_crtc_setup_fifo(); + } + else + { + result = B_ERROR; + } + + if (result != B_OK) + LOG(8,("INFO: coldstart failed.\n")); + else + LOG(8,("INFO: coldstart execution completed OK.\n")); + + return result; +} + +/* This routine is complete, and is used for pre-NV10 cards. It's tested on a Elsa + * Erazor III with TNT2 (NV05) and on a no-name TNT2-M64. Both cards coldstart + * perfectly. */ +static status_t exec_type1_script(uint8* rom, uint16 adress, int16* size, uint16 ram_tab) +{ + status_t result = B_OK; + bool end = false; + bool exec = true; + uint8 index, byte; + uint32 reg, data, data2, and_out, or_in; + + LOG(8,("\nINFO: executing type1 script at adress $%04x...\n", adress)); + LOG(8,("INFO: ---Executing following command(s):\n")); + + while (!end) + { + LOG(8,("INFO: $%04x ($%02x); ", adress, rom[adress])); + + switch (rom[adress]) + { + case 0x59: + *size -= 7; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint16*)(&(rom[adress]))); + adress += 2; + data2 = *((uint16*)(&(rom[data]))); + LOG(8,("cmd 'calculate indirect and set PLL 32bit reg $%08x for %.3fMHz'\n", + reg, ((float)data2))); + if (exec) + { + float calced_clk; + uint8 m, n, p; + nv_dac_sys_pll_find(((float)data2), &calced_clk, &m, &n, &p, 0); + NV_REG32(reg) = ((p << 16) | (n << 8) | m); + } + log_pll(reg, data2); + break; + case 0x5a: + *size -= 7; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint16*)(&(rom[adress]))); + adress += 2; + data2 = *((uint32*)(&(rom[data]))); + LOG(8,("cmd 'WR indirect 32bit reg' $%08x = $%08x\n", reg, data2)); + if (exec) NV_REG32(reg) = data2; + break; + case 0x63: + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + LOG(8,("cmd 'setup RAM config' (always done)\n")); + /* always done */ + setup_ram_config(rom, ram_tab); + break; + case 0x65: + *size -= 13; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint32*)(&(rom[adress]))); + adress += 4; + data2 = *((uint32*)(&(rom[adress]))); + adress += 4; + LOG(8,("cmd 'WR 32bit reg $%08x = $%08x, then = $%08x' (always done)\n", + reg, data, data2)); + /* always done */ + NV_REG32(reg) = data; + NV_REG32(reg) = data2; + CFGW(ROMSHADOW, (CFGR(ROMSHADOW) & 0xfffffffe)); + break; + case 0x69: + *size -= 5; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint16*)(&(rom[adress]))); + adress += 2; + and_out = *((uint8*)(&(rom[adress]))); + adress += 1; + or_in = *((uint8*)(&(rom[adress]))); + adress += 1; + LOG(8,("cmd 'RD 8bit ISA reg $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n", + reg, and_out, or_in)); + if (exec) + { + translate_ISA_PCI(®); + byte = NV_REG8(reg); + byte &= (uint8)and_out; + byte |= (uint8)or_in; + NV_REG8(reg) = byte; + } + break; + case 0x6d: + *size -= 3; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + data = NV_REG32(NV32_NV4STRAPINFO); + and_out = *((uint8*)(&(rom[adress]))); + adress += 1; + byte = *((uint8*)(&(rom[adress]))); + adress += 1; + data &= (uint32)and_out; + LOG(8,("cmd 'CHK bits AND-out $%02x RAMCFG for $%02x'\n", + and_out, byte)); + if (((uint8)data) != byte) + { + LOG(8,("INFO: ---No match: not executing following command(s):\n")); + exec = false; + } + else + { + LOG(8,("INFO: ---Match, so this cmd has no effect.\n")); + } + break; + case 0x6e: + *size -= 13; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + and_out = *((uint32*)(&(rom[adress]))); + adress += 4; + or_in = *((uint32*)(&(rom[adress]))); + adress += 4; + LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, OR-in = $%08x, WR-bk'\n", + reg, and_out, or_in)); + if (exec) + { + data = NV_REG32(reg); + data &= and_out; + data |= or_in; + NV_REG32(reg) = data; + } + break; + case 0x71: + LOG(8,("cmd 'END', execution completed.\n\n")); + end = true; + + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + break; + case 0x72: + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + + /* execute */ + adress += 1; + LOG(8,("cmd 'PGM commands'\n")); + LOG(8,("INFO: ---Executing following command(s):\n")); + exec = true; + break; + case 0x73: + *size -= 9; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + data = NV_REG32(NV32_NVSTRAPINFO2); + and_out = *((uint32*)(&(rom[adress]))); + adress += 4; + data2 = *((uint32*)(&(rom[adress]))); + adress += 4; + data &= and_out; + LOG(8,("cmd 'CHK bits AND-out $%08x STRAPCFG2 for $%08x'\n", + and_out, data2)); + if (data != data2) + { + LOG(8,("INFO: ---No match: not executing following command(s):\n")); + exec = false; + } + else + { + LOG(8,("INFO: ---Match, so this cmd has no effect.\n")); + } + break; + case 0x74: + *size -= 3; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + data = *((uint16*)(&(rom[adress]))); + adress += 2; + LOG(8,("cmd 'SNOOZE for %d ($%04x) microSeconds' (always done)\n", data, data)); + /* always done */ + snooze(data); + break; + case 0x77: + *size -= 7; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint16*)(&(rom[adress]))); + adress += 2; + LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x (b31-16 = '0', b15-0 = data)\n", + reg, data)); + if (exec) NV_REG32(reg) = data; + break; + case 0x78: + *size -= 6; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint16*)(&(rom[adress]))); + adress += 2; + index = *((uint8*)(&(rom[adress]))); + adress += 1; + and_out = *((uint8*)(&(rom[adress]))); + adress += 1; + or_in = *((uint8*)(&(rom[adress]))); + adress += 1; + LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n", + index, reg, and_out, or_in)); + if (exec) + { + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + byte |= (uint8)or_in; + NV_REG8(reg + 1) = byte; + } + break; + case 0x79: + *size -= 7; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint16*)(&(rom[adress]))); + adress += 2; + LOG(8,("cmd 'calculate and set PLL 32bit reg $%08x for %.3fMHz'\n", reg, (data / 100.0))); + if (exec) + { + float calced_clk; + uint8 m, n, p; + nv_dac_sys_pll_find((data / 100.0), &calced_clk, &m, &n, &p, 0); + NV_REG32(reg) = ((p << 16) | (n << 8) | m); + } + log_pll(reg, (data / 100)); + break; + case 0x7a: + *size -= 9; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + adress += 1; + reg = *((uint32*)(&(rom[adress]))); + adress += 4; + data = *((uint32*)(&(rom[adress]))); + adress += 4; + LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x\n", reg, data)); + if (exec) NV_REG32(reg) = data; + break; + default: + LOG(8,("unknown cmd, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + } + + return result; +} + +static void log_pll(uint32 reg, uint32 freq) +{ + if ((si->ps.card_type == NV31) || (si->ps.card_type == NV36)) + LOG(8,("INFO: ---WARNING: check/update PLL programming script code!!!\n")); + switch (reg) + { + case NV32_MEMPLL: + LOG(8,("INFO: ---Memory PLL accessed.\n")); + /* update the card's specs */ + si->ps.std_memory_clock = freq; + break; + case NV32_COREPLL: + LOG(8,("INFO: ---Core PLL accessed.\n")); + /* update the card's specs */ + si->ps.std_engine_clock = freq; + break; + case NVDAC_PIXPLLC: + LOG(8,("INFO: ---DAC1 PLL accessed.\n")); + break; + case NVDAC2_PIXPLLC: + LOG(8,("INFO: ---DAC2 PLL accessed.\n")); + break; + /* unexpected cases, here for learning goals... */ + case NV32_MEMPLL2: + LOG(8,("INFO: ---NV31/NV36 extension to memory PLL accessed only!\n")); + break; + case NV32_COREPLL2: + LOG(8,("INFO: ---NV31/NV36 extension to core PLL accessed only!\n")); + break; + case NVDAC_PIXPLLC2: + LOG(8,("INFO: ---NV31/NV36 extension to DAC1 PLL accessed only!\n")); + break; + case NVDAC2_PIXPLLC2: + LOG(8,("INFO: ---NV31/NV36 extension to DAC2 PLL accessed only!\n")); + break; + default: + LOG(8,("INFO: ---Unknown PLL accessed!\n")); + break; + } +} + +static void setup_ram_config(uint8* rom, uint16 ram_tab) +{ + uint32 ram_cfg, data; + uint8 cnt; + + /* set MRS = 256 */ + NV_REG32(NV32_PFB_DEBUG_0) &= 0xffffffef; + /* read RAM config hardware(?) strap */ + ram_cfg = ((NV_REG32(NV32_NVSTRAPINFO2) >> 2) & 0x0000000f); + LOG(8,("INFO: ---RAM config strap is $%01x\n", ram_cfg)); + /* use it as a pointer in a BIOS table for prerecorded RAM configurations */ + ram_cfg = *((uint16*)(&(rom[(ram_tab + (ram_cfg * 2))]))); + /* log info */ + switch (ram_cfg & 0x00000003) + { + case 0: + LOG(8,("INFO: ---32Mb RAM should be connected\n")); + break; + case 1: + LOG(8,("INFO: ---4Mb RAM should be connected\n")); + break; + case 2: + LOG(8,("INFO: ---8Mb RAM should be connected\n")); + break; + case 3: + LOG(8,("INFO: ---16Mb RAM should be connected\n")); + break; + } + if (ram_cfg & 0x00000004) + LOG(8,("INFO: ---RAM should be 128bits wide\n")); + else + LOG(8,("INFO: ---RAM should be 64bits wide\n")); + switch ((ram_cfg & 0x00000038) >> 3) + { + case 0: + LOG(8,("INFO: ---RAM type: 8Mbit SGRAM\n")); + break; + case 1: + LOG(8,("INFO: ---RAM type: 16Mbit SGRAM\n")); + break; + case 2: + LOG(8,("INFO: ---RAM type: 4 banks of 16Mbit SGRAM\n")); + break; + case 3: + LOG(8,("INFO: ---RAM type: 16Mbit SDRAM\n")); + break; + case 4: + LOG(8,("INFO: ---RAM type: 64Mbit SDRAM\n")); + break; + case 5: + LOG(8,("INFO: ---RAM type: 64Mbit x16 SDRAM\n")); + break; + } + /* set RAM amount, width and type */ + data = (NV_REG32(NV32_NV4STRAPINFO) & 0xffffffc0); + NV_REG32(NV32_NV4STRAPINFO) = (data | (ram_cfg & 0x0000003f)); + /* setup write to read delay (?) */ + data = (NV_REG32(NV32_PFB_CONFIG_1) & 0xff8ffffe); + data |= ((ram_cfg & 0x00000700) << 12); + /* force update via b0 = 0... */ + NV_REG32(NV32_PFB_CONFIG_1) = data; + /* ... followed by b0 = 1(?) */ + NV_REG32(NV32_PFB_CONFIG_1) = (data | 0x00000001); + + /* do RAM width test to confirm RAM width set to be correct */ + /* write testpattern to first 128 bits of graphics memory... */ + data = 0x4e563541; + for (cnt = 0; cnt < 4; cnt++) + ((uint32 *)si->framebuffer)[cnt] = data; + /* ... if second 64 bits does not contain the testpattern we are apparantly + * set to 128bits width while we should be set to 64bits width, so correct. */ + if (((uint32 *)si->framebuffer)[3] != data) + { + LOG(8,("INFO: ---RAM width tested: width is 64bits, correcting settings.\n")); + NV_REG32(NV32_NV4STRAPINFO) &= ~0x00000004; + } + else + { + LOG(8,("INFO: ---RAM width tested: access is OK.\n")); + } + + //fixme?: do RAM size test +} + +/* this routine is used for NV10 and later */ +static status_t exec_type2_script(uint8* rom, uint16 adress, int16* size, PinsTables tabs, uint16 ram_tab) +{ + bool exec = true; + + LOG(8,("\nINFO: executing type2 script at adress $%04x...\n", adress)); + LOG(8,("INFO: ---Executing following command(s):\n")); + + return exec_type2_script_mode(rom, &adress, size, tabs, ram_tab, &exec); +} + +/* this routine is used for NV10 and later. It's tested on a GeForce2 MX400 (NV11), + * GeForce4 MX440 (NV18), GeForce4 Ti4200 (NV28) and a GeForceFX 5200 (NV34). + * These cards coldstart perfectly. */ +static status_t exec_type2_script_mode(uint8* rom, uint16* adress, int16* size, PinsTables tabs, uint16 ram_tab, bool* exec) +{ + status_t result = B_OK; + bool end = false; + uint8 index, byte, byte2, shift; + uint32 reg, reg2, data, data2, and_out, and_out2, or_in, or_in2, safe32, offset32, size32; + + while (!end) + { + LOG(8,("INFO: $%04x ($%02x); ", *adress, rom[*adress])); + + /* all commands are here (verified NV11 and NV28) */ + switch (rom[*adress]) + { + case 0x31: /* new */ + *size -= (15 + ((*((uint8*)(&(rom[(*adress + 10)])))) << 2)); + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + and_out = *((uint32*)(&(rom[*adress]))); + *adress += 4; + shift = *((uint8*)(&(rom[*adress]))); + *adress += 1; + size32 = ((*((uint8*)(&(rom[*adress])))) << 2); + *adress += 1; + reg2 = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, shift-right = $%02x,\n", + reg, and_out, shift)); + LOG(8,("INFO: (cont.) RD 32bit data from subtable with size $%04x, at offset (result << 2),\n", + size32)); + LOG(8,("INFO: (cont.) then WR result data to 32bit reg $%08x'\n", reg2)); + if (*exec && reg2) + { + data = NV_REG32(reg); + data &= and_out; + data >>= shift; + data2 = *((uint32*)(&(rom[(*adress + (data << 2))]))); + NV_REG32(reg2) = data2; + } + *adress += size32; + break; + case 0x32: /* new */ + *size -= (11 + ((*((uint8*)(&(rom[(*adress + 6)])))) << 2)); + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + index = *((uint8*)(&(rom[*adress]))); + *adress += 1; + and_out = *((uint8*)(&(rom[*adress]))); + *adress += 1; + byte2 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + size32 = ((*((uint8*)(&(rom[*adress])))) << 2); + *adress += 1; + reg2 = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, shift-right = $%02x,\n", + index, reg, and_out, byte2)); + LOG(8,("INFO: (cont.) RD 32bit data from subtable with size $%04x, at offset (result << 2),\n", + size32)); + LOG(8,("INFO: (cont.) then WR result data to 32bit reg $%08x'\n", reg2)); + if (*exec && reg2) + { + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + byte >>= byte2; + offset32 = (byte << 2); + data = *((uint32*)(&(rom[(*adress + offset32)]))); + NV_REG32(reg2) = data; + } + *adress += size32; + break; + case 0x33: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + size32 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + /* executed 1-256 times */ + if (!size32) size32 = 256; + /* remember where to start each time */ + safe32 = *adress; + LOG(8,("cmd 'execute following part of this script $%03x times' (always done)\n", size32)); + for (offset32 = 0; offset32 < size32; offset32++) + { + LOG(8,("\nINFO: (#$%02x) executing part of type2 script at adress $%04x...\n", + offset32, *adress)); + LOG(8,("INFO: ---Not touching 'execution' mode at this time:\n")); + *adress = safe32; + result = exec_type2_script_mode(rom, adress, size, tabs, ram_tab, exec); + } + LOG(8,("INFO: ---Continuing script:\n")); + break; + case 0x34: /* new */ + *size -= (12 + ((*((uint8*)(&(rom[(*adress + 7)])))) << 1)); + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + index = *((uint8*)(&(rom[*adress]))); + *adress += 1; + and_out = *((uint8*)(&(rom[*adress]))); + *adress += 1; + shift = *((uint8*)(&(rom[*adress]))); + *adress += 1; + offset32 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + size32 = ((*((uint8*)(&(rom[*adress])))) << 1); + *adress += 1; + reg2 = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, shift-right = $%02x,\n", + index, reg, and_out, shift)); + LOG(8,("INFO: (cont.) RD 16bit PLL frequency to pgm from subtable with size $%04x, at offset (result << 1),\n", + size32)); + LOG(8,("INFO: (cont.) RD table-index ($%02x) for cmd $39'\n", + offset32)); + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + data = (byte >> shift); + data <<= 1; + data2 = *((uint16*)(&(rom[(*adress + data)]))); + if (offset32 < 0x80) + { + bool double_f = true; + LOG(8,("INFO: Do subcmd ($39); ")); + exec_cmd_39_type2(rom, offset32, tabs, &double_f); + LOG(8,("INFO: (cont. cmd $34) Doubling PLL frequency to be set for cmd $34.\n")); + if (double_f) data2 <<= 1; + LOG(8,("INFO: ---Reverting to pre-subcmd ($39) 'execution' mode.\n")); + } + else + { + LOG(8,("INFO: table index is negative, not executing subcmd ($39).\n")); + } + LOG(8,("INFO: (cont.) 'calc and set PLL 32bit reg $%08x for %.3fMHz'\n", + reg2, (data2 / 100.0))); + if (*exec && reg2) + { + float calced_clk; + uint8 m, n, p; + nv_dac_sys_pll_find((data2 / 100.0), &calced_clk, &m, &n, &p, 0); + /* programming the PLL needs to be done in steps! (confirmed NV28) */ + data = NV_REG32(reg2); + NV_REG32(reg2) = ((data & 0xffff0000) | (n << 8) | m); + data = NV_REG32(reg2); + NV_REG32(reg2) = ((p << 16) | (n << 8) | m); +//fixme? + /* program 2nd set N and M scalers if they exist (b31=1 enables them) */ +// if ((si->ps.card_type == NV31) || (si->ps.card_type == NV36)) +// DACW(PIXPLLC2, 0x80000401); + } + log_pll(reg2, (data2 / 100)); + *adress += size32; + break; + case 0x35: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + byte = *((uint8*)(&(rom[*adress]))); + *adress += 1; + offset32 = (byte << 1); + offset32 += tabs.InitFunctionTablePtr; + LOG(8,("cmd 'execute fixed VGA BIOS routine #$%02x at adress $%04x'\n", + byte, offset32)); + /* note: + * This command is BIOS/'pins' version specific. Confirmed a NV28 having NO + * entries at all in InitFunctionTable! + * (BIOS version 4.28.20.05.11; 'pins' version 5.21) */ + //fixme: impl. if it turns out this cmd is used.. (didn't see that yet) + if (*exec) + { + //fixme: add BIOS/'pins' version dependancy... + switch(byte) + { + default: + LOG(8,("\n\nINFO: WARNING: function not implemented, skipping!\n\n")); + break; + } + } + break; + case 0x37: /* new */ + *size -= 11; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + byte2 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + and_out = *((uint8*)(&(rom[*adress]))); + *adress += 1; + reg2 = *((uint16*)(&(rom[*adress]))); + *adress += 2; + index = *((uint8*)(&(rom[*adress]))); + *adress += 1; + and_out2 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + LOG(8,("cmd 'RD 32bit reg $%08x, shift-right = $%02x, AND-out lsb = $%02x,\n", + reg, byte2, and_out)); + LOG(8,("INFO: (cont.) RD 8bit ISA reg $%02x via $%04x, AND-out = $%02x, OR-in lsb result 32bit, WR-bk'\n", + index, reg2, and_out2)); + if (*exec) + { + data = NV_REG32(reg); + if (byte2 < 0x80) + { + data >>= byte2; + } + else + { + data <<= (0x0100 - byte2); + } + data &= and_out; + translate_ISA_PCI(®2); + NV_REG8(reg2) = index; + byte = NV_REG8(reg2 + 1); + byte &= (uint8)and_out2; + byte |= (uint8)data; + NV_REG8(reg2 + 1) = byte; + } + break; + case 0x38: /* new */ + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + LOG(8,("cmd 'invert current mode'\n")); + *exec = !(*exec); + if (*exec) + LOG(8,("INFO: ---Executing following command(s):\n")); + else + LOG(8,("INFO: ---Not executing following command(s):\n")); + break; + case 0x39: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + data = *((uint8*)(&(rom[*adress]))); + *adress += 1; + exec_cmd_39_type2(rom, data, tabs, exec); + break; + case 0x49: /* new */ + size32 = *((uint8*)(&(rom[*adress + 17]))); + if (!size32) size32 = 256; + *size -= (18 + (size32 << 1)); + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + reg2 = *((uint32*)(&(rom[*adress]))); + *adress += 4; + and_out = *((uint32*)(&(rom[*adress]))); + *adress += 4; + or_in = *((uint32*)(&(rom[*adress]))); + *adress += 4; + size32 = *((uint8*)(&(rom[*adress]))); + if (!size32) size32 = 256; + *adress += 1; + LOG(8,("cmd 'do following cmd structure $%03x time(s)':\n", size32)); + for (offset32 = 0; offset32 < size32; offset32++) + { + or_in2 = *((uint8*)(&(rom[(*adress + (offset32 << 1))]))); + data2 = *((uint8*)(&(rom[(*adress + (offset32 << 1) + 1)]))); + LOG(8,("INFO (cont.) (#$%02x) cmd 'WR 32bit reg $%08x = $%08x, RD 32bit reg $%08x,\n", + offset32, reg2, data2, reg)); + LOG(8,("INFO (cont.) AND-out $%08x, OR-in $%08x, OR-in $%08x, WR-bk'\n", + and_out, or_in, or_in2)); + } + if (*exec) + { + for (index = 0; index < size32; index++) + { + or_in2 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data2 = *((uint8*)(&(rom[*adress]))); + *adress += 1; + NV_REG32(reg2) = data2; + data = NV_REG32(reg); + data &= and_out; + data |= or_in; + data |= or_in2; + NV_REG32(reg) = data; + } + } + else + { + *adress += (size32 << 1); + } + break; + case 0x61: /* new */ + *size -= 4; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + byte = *((uint8*)(&(rom[*adress]))); + *adress += 1; + LOG(8,("cmd 'WR ISA reg $%04x = $%02x'\n", reg, byte)); + if (*exec) + { + translate_ISA_PCI(®); + NV_REG8(reg) = byte; + } + break; + case 0x62: /* new */ + *size -= 5; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + index = *((uint8*)(&(rom[*adress]))); + *adress += 1; + byte = *((uint8*)(&(rom[*adress]))); + *adress += 1; + LOG(8,("cmd 'WR idx ISA reg $%02x via $%04x = $%02x'\n", index, reg, byte)); + if (*exec) + { + translate_ISA_PCI(®); + NV_REG16(reg) = ((((uint16)byte) << 8) | index); + } + break; + case 0x63: /* new setup compared to pre-NV10 version */ + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + LOG(8,("cmd 'setup RAM config' (always done)\n")); + /* always done */ + switch (si->ps.card_type) + { + case NV28: + setup_ram_config_nv28(rom); + break; + default: + setup_ram_config_nv10_up(rom); + break; + } + break; + case 0x65: /* identical to type1 */ + *size -= 13; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + data = *((uint32*)(&(rom[*adress]))); + *adress += 4; + data2 = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'WR 32bit reg $%08x = $%08x, then = $%08x' (always done)\n", + reg, data, data2)); + /* always done */ + NV_REG32(reg) = data; + NV_REG32(reg) = data2; + CFGW(ROMSHADOW, (CFGR(ROMSHADOW) & 0xfffffffe)); + break; + case 0x69: /* identical to type1 */ + *size -= 5; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + and_out = *((uint8*)(&(rom[*adress]))); + *adress += 1; + or_in = *((uint8*)(&(rom[*adress]))); + *adress += 1; + LOG(8,("cmd 'RD 8bit ISA reg $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n", + reg, and_out, or_in)); + if (*exec) + { + translate_ISA_PCI(®); + byte = NV_REG8(reg); + byte &= (uint8)and_out; + byte |= (uint8)or_in; + NV_REG8(reg) = byte; + } + break; + case 0x6a: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + data = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data2 = *((uint16*)(&(rom[(tabs.InitScriptTablePtr + (data << 1))]))); + LOG(8,("cmd 'jump to script #$%02x at adress $%04x'\n", data, data2)); + if (*exec) + { + *adress = data2; + LOG(8,("INFO: ---Jumping; not touching 'execution' mode.\n")); + } + break; + case 0x6b: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + data = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data2 = *((uint16*)(&(rom[(tabs.InitScriptTablePtr + (data << 1))]))); + LOG(8,("cmd 'gosub script #$%02x at adress $%04x'\n", data, data2)); + if (*exec && data2) + { + result = exec_type2_script(rom, data2, size, tabs, ram_tab); + LOG(8,("INFO: ---Reverting to pre-gosub 'execution' mode.\n")); + } + break; + case 0x6e: /* identical to type1 */ + *size -= 13; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + and_out = *((uint32*)(&(rom[*adress]))); + *adress += 4; + or_in = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'RD 32bit reg $%08x, AND-out = $%08x, OR-in = $%08x, WR-bk'\n", + reg, and_out, or_in)); + if (*exec) + { + data = NV_REG32(reg); + data &= and_out; + data |= or_in; + NV_REG32(reg) = data; + } + break; + case 0x6f: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + byte = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data = tabs.MacroIndexTablePtr + (byte << 1); + offset32 = (*((uint8*)(&(rom[data]))) << 3); + size32 = *((uint8*)(&(rom[(data + 1)]))); + offset32 += tabs.MacroTablePtr; + /* note: min 1, max 255 commands can be requested */ + LOG(8,("cmd 'do $%02x time(s) a 32bit reg WR with 32bit data' (MacroIndexTable idx = $%02x):\n", + size32, byte)); + safe32 = 0; + while (safe32 < size32) + { + reg2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3))]))); + data2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3) + 4)]))); + LOG(8,("INFO: (cont.) (#$%02x) cmd 'WR 32bit reg' $%08x = $%08x\n", + safe32, reg2, data2)); + safe32++; + } + if (*exec) + { + safe32 = 0; + while (safe32 < size32) + { + reg2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3))]))); + data2 = *((uint32*)(&(rom[(offset32 + (safe32 << 3) + 4)]))); + NV_REG32(reg2) = data2; + safe32++; + } + } + break; + case 0x36: /* new */ + case 0x66: /* new */ + case 0x67: /* new */ + case 0x68: /* new */ + case 0x6c: /* new */ + case 0x71: /* identical to type1 */ + LOG(8,("cmd 'END', execution completed.\n\n")); + end = true; + + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + + /* execute */ + *adress += 1; /* needed to make cmd #$33 work correctly! */ + break; + case 0x72: /* identical to type1 */ + *size -= 1; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + + /* execute */ + *adress += 1; + LOG(8,("cmd 'PGM commands'\n")); + LOG(8,("INFO: ---Executing following command(s):\n")); + *exec = true; + break; + case 0x74: /* identical to type1 */ + //fixme? on at least NV28 this cmd hammers the CRTC PCI-timeout register + //'data' number of times instead of snoozing. + //Couldn't see any diff in behaviour though! + *size -= 3; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + data = *((uint16*)(&(rom[*adress]))); + *adress += 2; + LOG(8,("cmd 'SNOOZE for %d ($%04x) microSeconds' (always done)\n", data, data)); + /* always done */ + snooze(data); + break; + case 0x75: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + + /* execute */ + *adress += 1; + data = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data *= 12; + data += tabs.ConditionTablePtr; + reg = *((uint32*)(&(rom[data]))); + and_out = *((uint32*)(&(rom[(data + 4)]))); + data2 = *((uint32*)(&(rom[(data + 8)]))); + data = NV_REG32(reg); + data &= and_out; + LOG(8,("cmd 'CHK bits AND-out $%08x reg $%08x for $%08x'\n", + and_out, reg, data2)); + if (data != data2) + { + LOG(8,("INFO: ---No match: not executing following command(s):\n")); + *exec = false; + } + else + { + LOG(8,("INFO: ---Match, so this cmd has no effect.\n")); + } + break; + case 0x76: /* new */ + *size -= 2; + if (*size < 0) + { + LOG(8,("script size error!\n\n")); + result = B_ERROR; + } + + /* execute */ + *adress += 1; + data = *((uint8*)(&(rom[*adress]))); + *adress += 1; + data *= 5; + data += tabs.IOConditionTablePtr; + reg = *((uint16*)(&(rom[data]))); + index = *((uint8*)(&(rom[(data + 2)]))); + and_out = *((uint8*)(&(rom[(data + 3)]))); + byte2 = *((uint8*)(&(rom[(data + 4)]))); + LOG(8,("cmd 'CHK bits AND-out $%02x idx ISA reg $%02x via $%04x for $%02x'\n", + and_out, index, reg, byte2)); + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + if (byte != byte2) + { + LOG(8,("INFO: ---No match: not executing following command(s):\n")); + *exec = false; + } + else + { + LOG(8,("INFO: ---Match, so this cmd has no effect.\n")); + } + break; + case 0x78: /* identical to type1 */ + *size -= 6; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint16*)(&(rom[*adress]))); + *adress += 2; + index = *((uint8*)(&(rom[*adress]))); + *adress += 1; + and_out = *((uint8*)(&(rom[*adress]))); + *adress += 1; + or_in = *((uint8*)(&(rom[*adress]))); + *adress += 1; + LOG(8,("cmd 'RD idx ISA reg $%02x via $%04x, AND-out = $%02x, OR-in = $%02x, WR-bk'\n", + index, reg, and_out, or_in)); + if (*exec) + { + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + byte |= (uint8)or_in; + NV_REG8(reg + 1) = byte; + } + break; + case 0x79: + *size -= 7; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + data = *((uint16*)(&(rom[*adress]))); + *adress += 2; + LOG(8,("cmd 'calculate and set PLL 32bit reg $%08x for %.3fMHz'\n", reg, (data / 100.0))); + if (*exec) + { + float calced_clk; + uint8 m, n, p; + nv_dac_sys_pll_find((data / 100.0), &calced_clk, &m, &n, &p, 0); + /* programming the PLL needs to be done in steps! (confirmed NV28) */ + data2 = NV_REG32(reg); + NV_REG32(reg) = ((data2 & 0xffff0000) | (n << 8) | m); + data2 = NV_REG32(reg); + NV_REG32(reg) = ((p << 16) | (n << 8) | m); +//fixme? + /* program 2nd set N and M scalers if they exist (b31=1 enables them) */ +// if ((si->ps.card_type == NV31) || (si->ps.card_type == NV36)) +// DACW(PIXPLLC2, 0x80000401); + } + log_pll(reg, (data / 100)); + break; + case 0x7a: /* identical to type1 */ + *size -= 9; + if (*size < 0) + { + LOG(8,("script size error, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + + /* execute */ + *adress += 1; + reg = *((uint32*)(&(rom[*adress]))); + *adress += 4; + data = *((uint32*)(&(rom[*adress]))); + *adress += 4; + LOG(8,("cmd 'WR 32bit reg' $%08x = $%08x\n", reg, data)); + if (*exec) NV_REG32(reg) = data; + break; + default: + LOG(8,("unknown cmd, aborting!\n\n")); + end = true; + result = B_ERROR; + break; + } + } + + return result; +} + +static void exec_cmd_39_type2(uint8* rom, uint32 data, PinsTables tabs, bool* exec) +{ + uint8 index, byte, byte2, safe, shift; + uint32 reg, and_out, and_out2, offset32; + + data *= 9; + data += tabs.IOFlagConditionTablePtr; + reg = *((uint16*)(&(rom[data]))); + index = *((uint8*)(&(rom[(data + 2)]))); + and_out = *((uint8*)(&(rom[(data + 3)]))); + shift = *((uint8*)(&(rom[(data + 4)]))); + offset32 = *((uint16*)(&(rom[data + 5]))); + and_out2 = *((uint8*)(&(rom[(data + 7)]))); + byte2 = *((uint8*)(&(rom[(data + 8)]))); + LOG(8,("cmd 'AND-out bits $%02x idx ISA reg $%02x via $%04x, shift-right = $%02x,\n", + and_out, index, reg, shift)); + translate_ISA_PCI(®); + NV_REG8(reg) = index; + byte = NV_REG8(reg + 1); + byte &= (uint8)and_out; + offset32 += (byte >> shift); + safe = byte = *((uint8*)(&(rom[offset32]))); + byte &= (uint8)and_out2; + LOG(8,("INFO: (cont.) use result as index in table to get data $%02x,\n", + safe)); + LOG(8,("INFO: (cont.) then chk bits AND-out $%02x of data for $%02x'\n", + and_out2, byte2)); + if (byte != byte2) + { + LOG(8,("INFO: ---No match: not executing following command(s):\n")); + *exec = false; + } + else + { + LOG(8,("INFO: ---Match, so this cmd has no effect.\n")); + } +} + +static void setup_ram_config_nv10_up(uint8* rom) +{ + uint32 data, dummy; + uint8 cnt = 0; + status_t stat = B_ERROR; + + /* set 'refctrl is valid' */ + NV_REG32(NV32_PFB_REFCTRL) = 0x80000000; + + /* check RAM for 256bits buswidth(?) */ + while ((cnt < 4) && (stat != B_OK)) + { + /* reset RAM bits at offset 224-255 bits four times */ + ((uint32 *)si->framebuffer)[0x07] = 0x00000000; + ((uint32 *)si->framebuffer)[0x07] = 0x00000000; + ((uint32 *)si->framebuffer)[0x07] = 0x00000000; + ((uint32 *)si->framebuffer)[0x07] = 0x00000000; + /* write testpattern */ + ((uint32 *)si->framebuffer)[0x07] = 0x4e563131; + /* reset RAM bits at offset 480-511 bits */ + ((uint32 *)si->framebuffer)[0x0f] = 0x00000000; + /* check testpattern to have survived */ + if (((uint32 *)si->framebuffer)[0x07] == 0x4e563131) stat = B_OK; + cnt++; + } + + /* if pattern did not hold modify RAM-type setup */ + if (stat != B_OK) + { + LOG(8,("INFO: ---RAM test #1 done: access errors, modified setup.\n")); + data = NV_REG32(NV32_PFB_CONFIG_0); + if (data & 0x00000010) + { + data &= 0xffffffcf; + } + else + { + data &= 0xffffffcf; + data |= 0x00000020; + } + NV_REG32(NV32_PFB_CONFIG_0) = data; + } + else + { + LOG(8,("INFO: ---RAM test #1 done: access is OK.\n")); + } + + /* check RAM bankswitching stuff(?) */ + cnt = 0; + stat = B_ERROR; + while ((cnt < 4) && (stat != B_OK)) + { + /* read RAM size */ + data = NV_REG32(NV32_NV10STRAPINFO); + /* subtract 1MB */ + data -= 0x00100000; + /* write testpattern at generated RAM adress */ + ((uint32 *)si->framebuffer)[(data >> 2)] = 0x4e564441; + /* reset first RAM adress */ + ((uint32 *)si->framebuffer)[0x00] = 0x00000000; + /* dummyread first RAM adress four times */ + dummy = ((uint32 *)si->framebuffer)[0x00]; + dummy = ((uint32 *)si->framebuffer)[0x00]; + dummy = ((uint32 *)si->framebuffer)[0x00]; + dummy = ((uint32 *)si->framebuffer)[0x00]; + /* check testpattern to have survived */ + if (((uint32 *)si->framebuffer)[(data >> 2)] == 0x4e564441) stat = B_OK; + cnt++; + } + + /* if pattern did not hold modify RAM-type setup */ + if (stat != B_OK) + { + LOG(8,("INFO: ---RAM test #2 done: access errors, modified setup.\n")); + NV_REG32(NV32_PFB_CONFIG_0) &= 0xffffefff; + } + else + { + LOG(8,("INFO: ---RAM test #2 done: access is OK.\n")); + } +} + +/* Note: this routine assumes at least 128Mb was mapped to memory (kerneldriver). + * It doesn't matter if the card actually _has_ this amount of RAM or not(!) */ +static void setup_ram_config_nv28(uint8* rom) +{ + uint32 dummy; + uint8 cnt = 0; + status_t stat = B_ERROR; + + /* set 'refctrl is valid' */ + NV_REG32(NV32_PFB_REFCTRL) = 0x80000000; + + /* check RAM */ + while ((cnt < 4) && (stat != B_OK)) + { + /* set bit 11: 'pulse' something into a new setting? */ + NV_REG32(NV32_PFB_CONFIG_0) |= 0x00000800; + /* write testpattern to RAM adress 127Mb */ + ((uint32 *)si->framebuffer)[0x01fc0000] = 0x4e564441; + /* reset first RAM adress */ + ((uint32 *)si->framebuffer)[0x00000000] = 0x00000000; + /* dummyread first RAM adress four times */ + dummy = ((uint32 *)si->framebuffer)[0x00000000]; + LOG(8,("INFO: (#%d) dummy1 = $%08x, ", cnt, dummy)); + dummy = ((uint32 *)si->framebuffer)[0x00000000]; + LOG(8,("dummy2 = $%08x, ", dummy)); + dummy = ((uint32 *)si->framebuffer)[0x00000000]; + LOG(8,("dummy3 = $%08x, ", dummy)); + dummy = ((uint32 *)si->framebuffer)[0x00000000]; + LOG(8,("dummy4 = $%08x\n", dummy)); + /* check testpattern to have survived */ + if (((uint32 *)si->framebuffer)[0x01fc0000] == 0x4e564441) stat = B_OK; + cnt++; + } + + /* clear bit 11: set normal mode */ + NV_REG32(NV32_PFB_CONFIG_0) &= ~0x00000800; + + if (stat == B_OK) + LOG(8,("INFO: ---RAM test done: access was OK within %d iteration(s).\n", cnt)); + else + LOG(8,("INFO: ---RAM test done: access was still not OK after 4 iterations.\n")); +} + +static status_t translate_ISA_PCI(uint32* reg) +{ + switch (*reg) + { + case 0x03c0: + *reg = NV8_ATTRDATW; + break; + case 0x03c1: + *reg = NV8_ATTRDATR; + break; + case 0x03c2: + *reg = NV8_MISCW; + break; + case 0x03c4: + *reg = NV8_SEQIND; + break; + case 0x03c5: + *reg = NV8_SEQDAT; + break; + case 0x03c6: + *reg = NV8_PALMASK; + break; + case 0x03c7: + *reg = NV8_PALINDR; + break; + case 0x03c8: + *reg = NV8_PALINDW; + break; + case 0x03c9: + *reg = NV8_PALDATA; + break; + case 0x03cc: + *reg = NV8_MISCR; + break; + case 0x03ce: + *reg = NV8_GRPHIND; + break; + case 0x03cf: + *reg = NV8_GRPHDAT; + break; + case 0x03d4: + *reg = NV8_CRTCIND; + break; + case 0x03d5: + *reg = NV8_CRTCDAT; + break; + case 0x03da: + *reg = NV8_INSTAT1; + break; + default: + LOG(8,("\n\nINFO: WARNING: ISA->PCI register adress translation failed!\n\n")); + return B_ERROR; + break; + } + + return B_OK; +} + +//fixme: move to crtc sourcefile, also setup for crtc2(?) +static status_t nv_crtc_setup_fifo() +{ + /* enable access to primary head */ + set_crtc_owner(0); + + //fixme: setup according to colordepth and RAM bus width... + /* set CRTC FIFO burst size to 256 */ + CRTCW(FIFO, 0x03); + + /* set CRTC FIFO low watermark to 32 */ + CRTCW(FIFO_LWM, 0x20); + + return B_OK; +} + +/* (pre)set 'fixed' card specifications */ +void set_specs(void) +{ + LOG(8,("INFO: setting up card specifications\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: + case NV40A: + pinsnv30_arch_fake(); + break; + default: + /* 'failsafe' values... */ + pinsnv10_arch_fake(); + break; + } + break; + } + + /* detect reference crystal frequency and dualhead */ + switch (si->ps.card_arch) + { + case NV04A: + getstrap_arch_nv4(); + break; + default: + getstrap_arch_nv10_20_30_40(); + break; + } +} + +/* this routine presumes the card was coldstarted by the card's BIOS for panel stuff */ +void fake_panel_start(void) +{ + LOG(8,("INFO: detecting RAM size\n")); + + /* detect RAM amount */ + switch (si->ps.card_arch) + { + case NV04A: + getRAMsize_arch_nv4(); + break; + default: + getRAMsize_arch_nv10_20_30_40(); + break; + } + + /* override memory detection if requested by user */ + if (si->settings.memory != 0) + { + LOG(2,("INFO: forcing memory size (specified in settings file)\n")); + si->ps.memory_size = si->settings.memory * 1024 * 1024; + } + + /* 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 = ???; + } +*/ + + LOG(8,("INFO: faking panel startup\n")); + + /* find out the BIOS preprogrammed panel use status... */ + detect_panels(); + + /* determine and setup output devices and heads */ + setup_output_matrix(); + + /* select other CRTC for primary head use if specified by user in settings file */ + if (si->ps.secondary_head && si->settings.switchhead) + { + LOG(2,("INFO: inverting head use (specified in settings file)\n")); + si->ps.crtc2_prim = !si->ps.crtc2_prim; + } +} + +static void detect_panels() +{ + /* detect if the BIOS enabled LCD's (internal panels or DVI) or TVout */ + + /* both external TMDS transmitters (used for LCD/DVI) and external TVencoders + * (can) use the CRTC's in slaved mode. */ + /* Note: + * DFP's are programmed with standard VESA modelines by the card's BIOS! */ + bool slaved_for_dev1 = false, slaved_for_dev2 = false; + bool tvout1 = false, tvout2 = false; + + /* check primary head: */ + /* enable access to primary head */ + set_crtc_owner(0); + + /* unlock head's registers for R/W access */ + CRTCW(LOCK, 0x57); + CRTCW(VSYNCE ,(CRTCR(VSYNCE) & 0x7f)); + + LOG(2,("INFO: Dumping flatpanel related CRTC registers:\n")); + /* related info PIXEL register: + * b7: 1 = slaved mode (all cards). */ + LOG(2,("CRTC1: PIXEL register: $%02x\n", CRTCR(PIXEL))); + /* info LCD register: + * b7: 1 = stereo view (shutter glasses use) (all cards), + * b5: 1 = power ext. TMDS (or something)/0 = TVout use (?) (confirmed NV17, NV28), + * b4: 1 = power ext. TMDS (or something)/0 = TVout use (?) (confirmed NV34), + * b3: 1 = ??? (not panel related probably!) (confirmed NV34), + * b1: 1 = power ext. TMDS (or something) (?) (confirmed NV05?, NV17), + * b0: 1 = select panel encoder / 0 = select TVout encoder (all cards). */ + LOG(2,("CRTC1: LCD register: $%02x\n", CRTCR(LCD))); + /* info 0x59 register: + * b0: 1 = enable ext. TMDS clock (DPMS) (confirmed NV28, NV34). */ + LOG(2,("CRTC1: register $59: $%02x\n", CRTCR(0x59))); + /* info 0x9f register: + * b4: 0 = TVout use (?). */ + LOG(2,("CRTC1: register $9f: $%02x\n", CRTCR(0x9f))); + + /* detect active slave device (if any) */ + slaved_for_dev1 = (CRTCR(PIXEL) & 0x80); + if (slaved_for_dev1) + { + /* if the panel isn't selected, tvout is.. */ + tvout1 = !(CRTCR(LCD) & 0x01); + } + + if (si->ps.secondary_head) + { + /* check secondary head: */ + /* enable access to secondary head */ + set_crtc_owner(1); + /* unlock head's registers for R/W access */ + CRTC2W(LOCK, 0x57); + CRTC2W(VSYNCE ,(CRTC2R(VSYNCE) & 0x7f)); + + LOG(2,("CRTC2: PIXEL register: $%02x\n", CRTC2R(PIXEL))); + LOG(2,("CRTC2: LCD register: $%02x\n", CRTC2R(LCD))); + LOG(2,("CRTC2: register $59: $%02x\n", CRTC2R(0x59))); + LOG(2,("CRTC2: register $9f: $%02x\n", CRTC2R(0x9f))); + + /* detect active slave device (if any) */ + slaved_for_dev2 = (CRTC2R(PIXEL) & 0x80); + if (slaved_for_dev2) + { + /* if the panel isn't selected, tvout is.. */ + tvout2 = !(CRTC2R(LCD) & 0x01); + } + } + + LOG(2,("INFO: End flatpanel related CRTC registers dump.\n")); + + /* do some presets */ + si->ps.p1_timing.h_display = 0; + si->ps.p1_timing.v_display = 0; + si->ps.panel1_aspect = 0; + si->ps.p2_timing.h_display = 0; + si->ps.p2_timing.v_display = 0; + si->ps.panel2_aspect = 0; + si->ps.slaved_tmds1 = false; + si->ps.slaved_tmds2 = false; + si->ps.master_tmds1 = false; + si->ps.master_tmds2 = false; + si->ps.tmds1_active = false; + si->ps.tmds2_active = false; + /* determine the situation we are in... (regarding flatpanels) */ + /* fixme: add VESA DDC EDID stuff one day... */ + /* fixme: find out how to program those transmitters one day instead of + * relying on the cards BIOS to do it. This adds TVout options where panels + * are used! + * Currently we'd loose the panel setup while not being able to restore it. */ + + /* note: (facts) + * -> NV11 and NV17 laptops have LVDS panels, programmed in both sets registers; + * -> NV34 laptops have TMDS panels, programmed in only one set of registers; + * -> NV11, NV25 and NV34 DVI cards, so external panels (TMDS) are programmed + * in only one set of registers; + * -> a register-set's FP_TG_CTRL register, bit 31 tells you if a LVDS panel is + * connected to the primary head (0), or to the secondary head (1) except + * on some NV11's if this bit is '0' there; + * -> for LVDS panels both registersets are programmed identically by the card's + * BIOSes; + * -> the programmed set of registers tells you where a TMDS (DVI) panel is + * connected; + * -> On all cards a CRTC is used in slaved mode when a panel is connected, + * except on NV11: here master mode is (might be?) detected. */ + /* note also: + * external TMDS encoders are only used for logic-level translation: it's + * modeline registers are not used. Instead the GPU's internal modeline registers + * are used. The external encoder is not connected to a I2C bus (confirmed NV34). */ + if (slaved_for_dev1 && !tvout1) + { + uint16 width = ((DACR(FP_HDISPEND) & 0x0000ffff) + 1); + uint16 height = ((DACR(FP_VDISPEND) & 0x0000ffff) + 1); + if ((width >= 640) && (height >= 480)) + { + si->ps.slaved_tmds1 = true; + si->ps.tmds1_active = true; + si->ps.p1_timing.h_display = width; + si->ps.p1_timing.v_display = height; + } + } + + if (si->ps.secondary_head && slaved_for_dev2 && !tvout2) + { + uint16 width = ((DAC2R(FP_HDISPEND) & 0x0000ffff) + 1); + uint16 height = ((DAC2R(FP_VDISPEND) & 0x0000ffff) + 1); + if ((width >= 640) && (height >= 480)) + { + si->ps.slaved_tmds2 = true; + si->ps.tmds2_active = true; + si->ps.p2_timing.h_display = width; + si->ps.p2_timing.v_display = height; + } + } + + if ((si->ps.card_type == NV11) && + !si->ps.slaved_tmds1 && !tvout1) + { + uint16 width = ((DACR(FP_HDISPEND) & 0x0000ffff) + 1); + uint16 height = ((DACR(FP_VDISPEND) & 0x0000ffff) + 1); + if ((width >= 640) && (height >= 480)) + { + si->ps.master_tmds1 = true; + si->ps.tmds1_active = true; + si->ps.p1_timing.h_display = width; + si->ps.p1_timing.v_display = height; + } + } + + if ((si->ps.card_type == NV11) && + si->ps.secondary_head && !si->ps.slaved_tmds2 && !tvout2) + { + uint16 width = ((DAC2R(FP_HDISPEND) & 0x0000ffff) + 1); + uint16 height = ((DAC2R(FP_VDISPEND) & 0x0000ffff) + 1); + if ((width >= 640) && (height >= 480)) + { + si->ps.master_tmds2 = true; + si->ps.tmds2_active = true; + si->ps.p2_timing.h_display = width; + si->ps.p2_timing.v_display = height; + } + } + + //fixme...: + //we are assuming that no DVI is used as external monitor on laptops; + //otherwise we probably get into trouble here if the checked specs match. + if (si->ps.laptop && si->ps.tmds1_active && si->ps.tmds2_active && + ((DACR(FP_TG_CTRL) & 0x80000000) == (DAC2R(FP_TG_CTRL) & 0x80000000)) && + (si->ps.p1_timing.h_display == si->ps.p2_timing.h_display) && + (si->ps.p1_timing.v_display == si->ps.p2_timing.v_display)) + { + LOG(2,("INFO: correcting double detection of single panel!\n")); + + if (si->ps.card_type == NV11) + { + /* LVDS panel is _always_ on CRTC2, so clear false primary detection */ + si->ps.slaved_tmds1 = false; + si->ps.master_tmds1 = false; + si->ps.tmds1_active = false; + si->ps.p1_timing.h_display = 0; + si->ps.p1_timing.v_display = 0; + } + else + { + if (DACR(FP_TG_CTRL) & 0x80000000) + { + /* LVDS panel is on CRTC2, so clear false primary detection */ + si->ps.slaved_tmds1 = false; + si->ps.master_tmds1 = false; + si->ps.tmds1_active = false; + si->ps.p1_timing.h_display = 0; + si->ps.p1_timing.v_display = 0; + } + else + { + /* LVDS panel is on CRTC1, so clear false secondary detection */ + si->ps.slaved_tmds2 = false; + si->ps.master_tmds2 = false; + si->ps.tmds2_active = false; + si->ps.p2_timing.h_display = 0; + si->ps.p2_timing.v_display = 0; + } + } + } + + /* fetch panel(s) modeline(s) */ + if (si->ps.tmds1_active) + { + /* determine panel aspect ratio */ + si->ps.panel1_aspect = + (si->ps.p1_timing.h_display / ((float)si->ps.p1_timing.v_display)); + /* horizontal timing */ + si->ps.p1_timing.h_sync_start = (DACR(FP_HSYNC_S) & 0x0000ffff) + 1; + si->ps.p1_timing.h_sync_end = (DACR(FP_HSYNC_E) & 0x0000ffff) + 1; + si->ps.p1_timing.h_total = (DACR(FP_HTOTAL) & 0x0000ffff) + 1; + /* vertical timing */ + si->ps.p1_timing.v_sync_start = (DACR(FP_VSYNC_S) & 0x0000ffff) + 1; + si->ps.p1_timing.v_sync_end = (DACR(FP_VSYNC_E) & 0x0000ffff) + 1; + si->ps.p1_timing.v_total = (DACR(FP_VTOTAL) & 0x0000ffff) + 1; + /* sync polarity */ + si->ps.p1_timing.flags = 0; + if (DACR(FP_TG_CTRL) & 0x00000001) si->ps.p1_timing.flags |= B_POSITIVE_VSYNC; + if (DACR(FP_TG_CTRL) & 0x00000010) si->ps.p1_timing.flags |= B_POSITIVE_HSYNC; + /* refreshrate: + * fix a DVI or laptop flatpanel to 60Hz refresh! */ + si->ps.p1_timing.pixel_clock = + (si->ps.p1_timing.h_total * si->ps.p1_timing.v_total * 60) / 1000; + } + if (si->ps.tmds2_active) + { + /* determine panel aspect ratio */ + si->ps.panel2_aspect = + (si->ps.p2_timing.h_display / ((float)si->ps.p2_timing.v_display)); + /* horizontal timing */ + si->ps.p2_timing.h_sync_start = (DAC2R(FP_HSYNC_S) & 0x0000ffff) + 1; + si->ps.p2_timing.h_sync_end = (DAC2R(FP_HSYNC_E) & 0x0000ffff) + 1; + si->ps.p2_timing.h_total = (DAC2R(FP_HTOTAL) & 0x0000ffff) + 1; + /* vertical timing */ + si->ps.p2_timing.v_sync_start = (DAC2R(FP_VSYNC_S) & 0x0000ffff) + 1; + si->ps.p2_timing.v_sync_end = (DAC2R(FP_VSYNC_E) & 0x0000ffff) + 1; + si->ps.p2_timing.v_total = (DAC2R(FP_VTOTAL) & 0x0000ffff) + 1; + /* sync polarity */ + si->ps.p2_timing.flags = 0; + if (DAC2R(FP_TG_CTRL) & 0x00000001) si->ps.p2_timing.flags |= B_POSITIVE_VSYNC; + if (DAC2R(FP_TG_CTRL) & 0x00000010) si->ps.p2_timing.flags |= B_POSITIVE_HSYNC; + /* refreshrate: + * fix a DVI or laptop flatpanel to 60Hz refresh! */ + si->ps.p2_timing.pixel_clock = + (si->ps.p2_timing.h_total * si->ps.p2_timing.v_total * 60) / 1000; + } + + /* dump some panel configuration registers... */ + LOG(2,("INFO: Dumping flatpanel registers:\n")); + LOG(2,("DUALHEAD_CTRL: $%08x\n", NV_REG32(NV32_DUALHEAD_CTRL))); + LOG(2,("DAC1: FP_HDISPEND: %d\n", DACR(FP_HDISPEND))); + LOG(2,("DAC1: FP_HTOTAL: %d\n", DACR(FP_HTOTAL))); + LOG(2,("DAC1: FP_HCRTC: %d\n", DACR(FP_HCRTC))); + LOG(2,("DAC1: FP_HSYNC_S: %d\n", DACR(FP_HSYNC_S))); + LOG(2,("DAC1: FP_HSYNC_E: %d\n", DACR(FP_HSYNC_E))); + LOG(2,("DAC1: FP_HVALID_S: %d\n", DACR(FP_HVALID_S))); + LOG(2,("DAC1: FP_HVALID_E: %d\n", DACR(FP_HVALID_E))); + + LOG(2,("DAC1: FP_VDISPEND: %d\n", DACR(FP_VDISPEND))); + LOG(2,("DAC1: FP_VTOTAL: %d\n", DACR(FP_VTOTAL))); + LOG(2,("DAC1: FP_VCRTC: %d\n", DACR(FP_VCRTC))); + LOG(2,("DAC1: FP_VSYNC_S: %d\n", DACR(FP_VSYNC_S))); + LOG(2,("DAC1: FP_VSYNC_E: %d\n", DACR(FP_VSYNC_E))); + LOG(2,("DAC1: FP_VVALID_S: %d\n", DACR(FP_VVALID_S))); + LOG(2,("DAC1: FP_VVALID_E: %d\n", DACR(FP_VVALID_E))); + + LOG(2,("DAC1: FP_CHKSUM: $%08x = (dec) %d\n", DACR(FP_CHKSUM),DACR(FP_CHKSUM))); + LOG(2,("DAC1: FP_TST_CTRL: $%08x\n", DACR(FP_TST_CTRL))); + LOG(2,("DAC1: FP_TG_CTRL: $%08x\n", DACR(FP_TG_CTRL))); + LOG(2,("DAC1: FP_DEBUG0: $%08x\n", DACR(FP_DEBUG0))); + LOG(2,("DAC1: FP_DEBUG1: $%08x\n", DACR(FP_DEBUG1))); + LOG(2,("DAC1: FP_DEBUG2: $%08x\n", DACR(FP_DEBUG2))); + LOG(2,("DAC1: FP_DEBUG3: $%08x\n", DACR(FP_DEBUG3))); + + LOG(2,("DAC1: FUNCSEL: $%08x\n", NV_REG32(NV32_FUNCSEL))); + LOG(2,("DAC1: PANEL_PWR: $%08x\n", NV_REG32(NV32_PANEL_PWR))); + + if(si->ps.secondary_head) + { + LOG(2,("DAC2: FP_HDISPEND: %d\n", DAC2R(FP_HDISPEND))); + LOG(2,("DAC2: FP_HTOTAL: %d\n", DAC2R(FP_HTOTAL))); + LOG(2,("DAC2: FP_HCRTC: %d\n", DAC2R(FP_HCRTC))); + LOG(2,("DAC2: FP_HSYNC_S: %d\n", DAC2R(FP_HSYNC_S))); + LOG(2,("DAC2: FP_HSYNC_E: %d\n", DAC2R(FP_HSYNC_E))); + LOG(2,("DAC2: FP_HVALID_S:%d\n", DAC2R(FP_HVALID_S))); + LOG(2,("DAC2: FP_HVALID_E: %d\n", DAC2R(FP_HVALID_E))); + + LOG(2,("DAC2: FP_VDISPEND: %d\n", DAC2R(FP_VDISPEND))); + LOG(2,("DAC2: FP_VTOTAL: %d\n", DAC2R(FP_VTOTAL))); + LOG(2,("DAC2: FP_VCRTC: %d\n", DAC2R(FP_VCRTC))); + LOG(2,("DAC2: FP_VSYNC_S: %d\n", DAC2R(FP_VSYNC_S))); + LOG(2,("DAC2: FP_VSYNC_E: %d\n", DAC2R(FP_VSYNC_E))); + LOG(2,("DAC2: FP_VVALID_S: %d\n", DAC2R(FP_VVALID_S))); + LOG(2,("DAC2: FP_VVALID_E: %d\n", DAC2R(FP_VVALID_E))); + + LOG(2,("DAC2: FP_CHKSUM: $%08x = (dec) %d\n", DAC2R(FP_CHKSUM),DAC2R(FP_CHKSUM))); + LOG(2,("DAC2: FP_TST_CTRL: $%08x\n", DAC2R(FP_TST_CTRL))); + LOG(2,("DAC2: FP_TG_CTRL: $%08x\n", DAC2R(FP_TG_CTRL))); + LOG(2,("DAC2: FP_DEBUG0: $%08x\n", DAC2R(FP_DEBUG0))); + LOG(2,("DAC2: FP_DEBUG1: $%08x\n", DAC2R(FP_DEBUG1))); + LOG(2,("DAC2: FP_DEBUG2: $%08x\n", DAC2R(FP_DEBUG2))); + LOG(2,("DAC2: FP_DEBUG3: $%08x\n", DAC2R(FP_DEBUG3))); + + LOG(2,("DAC2: FUNCSEL: $%08x\n", NV_REG32(NV32_2FUNCSEL))); + LOG(2,("DAC2: PANEL_PWR: $%08x\n", NV_REG32(NV32_2PANEL_PWR))); + } + LOG(2,("INFO: End flatpanel registers dump.\n")); +} + +static void setup_output_matrix() +{ + /* setup defaults: */ + /* no monitors (output devices) detected */ + si->ps.monitors = 0x00; + /* head 1 will be the primary head */ + si->ps.crtc2_prim = false; + + /* setup output devices and heads */ + if (si->ps.secondary_head) + { + if (si->ps.card_type != NV11) + { + /* setup defaults: */ + /* connect analog outputs straight through */ + nv_general_output_select(false); + + /* presetup by the card's BIOS, we can't change this (lack of info) */ + if (si->ps.tmds1_active) si->ps.monitors |= 0x01; + if (si->ps.tmds2_active) si->ps.monitors |= 0x10; + /* detect analog monitors (confirmed working OK on NV18, NV28 and NV34): */ + /* sense analog monitor on primary connector */ + if (nv_dac_crt_connected()) si->ps.monitors |= 0x02; + /* sense analog monitor on secondary connector */ + if (nv_dac2_crt_connected()) si->ps.monitors |= 0x20; + + /* setup correct output and head use */ + //fixme? add TVout (only, so no CRT(s) connected) support... + switch (si->ps.monitors) + { + case 0x00: /* no monitor found at all */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x01: /* digital panel on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x02: /* analog panel or CRT on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x03: /* both types on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has a digital panel AND an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: correcting...\n")); + /* cross connect analog outputs so analog panel or CRT gets head 2 */ + nv_general_output_select(true); + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has an analog panel or CRT:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x10: /* nothing on head 1, digital panel on head 2 */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + case 0x20: /* nothing on head 1, analog panel or CRT on head 2 */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has an analog panel or CRT:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + case 0x30: /* nothing on head 1, both types on head 2 */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has a digital panel AND an analog panel or CRT:\n")); + LOG(2,("INFO: correcting...\n")); + /* cross connect analog outputs so analog panel or CRT gets head 1 */ + nv_general_output_select(true); + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + case 0x11: /* digital panels on both heads */ + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x12: /* analog panel or CRT on head 1, digital panel on head 2 */ + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + case 0x21: /* digital panel on head 1, analog panel or CRT on head 2 */ + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has an analog panel or CRT:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x22: /* analog panel(s) or CRT(s) on both heads */ + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has an analog panel or CRT:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + default: /* more than two monitors connected to just two outputs: illegal! */ + LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors)); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + } + } + else /* dualhead NV11 cards */ + { + /* confirmed no analog output switch-options for NV11 */ + LOG(2,("INFO: NV11 outputs are hardwired to be straight-through\n")); + + /* presetup by the card's BIOS, we can't change this (lack of info) */ + if (si->ps.tmds1_active) si->ps.monitors |= 0x01; + if (si->ps.tmds2_active) si->ps.monitors |= 0x10; + /* detect analog monitor (confirmed working OK on NV11): */ + /* sense analog monitor on primary connector */ + if (nv_dac_crt_connected()) si->ps.monitors |= 0x02; + /* (sense analog monitor on secondary connector is impossible on NV11) */ + + /* setup correct output and head use */ + //fixme? add TVout (only, so no CRT(s) connected) support... + switch (si->ps.monitors) + { + case 0x00: /* no monitor found at all */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x01: /* digital panel on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x02: /* analog panel or CRT on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x03: /* both types on head 1, nothing on head 2 */ + LOG(2,("INFO: head 1 has a digital panel AND an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has nothing connected:\n")); + LOG(2,("INFO: correction not possible...\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x10: /* nothing on head 1, digital panel on head 2 */ + LOG(2,("INFO: head 1 has nothing connected;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + case 0x11: /* digital panels on both heads */ + LOG(2,("INFO: head 1 has a digital panel;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + case 0x12: /* analog panel or CRT on head 1, digital panel on head 2 */ + LOG(2,("INFO: head 1 has an analog panel or CRT;\n")); + LOG(2,("INFO: head 2 has a digital panel:\n")); + LOG(2,("INFO: defaulting to head 2 for primary use.\n")); + si->ps.crtc2_prim = true; + break; + default: /* more than two monitors connected to just two outputs: illegal! */ + LOG(2,("INFO: illegal monitor setup ($%02x):\n", si->ps.monitors)); + LOG(2,("INFO: defaulting to head 1 for primary use.\n")); + break; + } + } + } + else /* singlehead cards */ + { + /* presetup by the card's BIOS, we can't change this (lack of info) */ + if (si->ps.tmds1_active) si->ps.monitors |= 0x01; + /* detect analog monitor (confirmed working OK on all cards): */ + /* sense analog monitor on primary connector */ + if (nv_dac_crt_connected()) si->ps.monitors |= 0x02; + + //fixme? add TVout (only, so no CRT connected) support... + } +} + +void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2) +{ + if (si->ps.tmds1_active) + { + /* timing ('modeline') */ + p1->timing = si->ps.p1_timing; + /* setup the rest */ + p1->space = B_CMAP8; + p1->virtual_width = p1->timing.h_display; + p1->virtual_height = p1->timing.v_display; + p1->h_display_start = 0; + p1->v_display_start = 0; + p1->flags = 0; + *pan1 = true; + } + else + *pan1 = false; + + if (si->ps.tmds2_active) + { + /* timing ('modeline') */ + p2->timing = si->ps.p2_timing; + /* setup the rest */ + p2->space = B_CMAP8; + p2->virtual_width = p2->timing.h_display; + p2->virtual_height = p2->timing.v_display; + p2->h_display_start = 0; + p2->v_display_start = 0; + p2->flags = 0; + *pan2 = true; + } + else + *pan2 = false; +} + +static void pinsnv4_fake(void) +{ + /* we have a standard PLL */ + si->ps.ext_pll = false; + /* 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; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 90; + si->ps.std_memory_clock = 110; +} + +static void pinsnv5_nv5m64_fake(void) +{ + /* we have a standard PLL */ + si->ps.ext_pll = false; + /* 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; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 125; + si->ps.std_memory_clock = 150; +} + +static void pinsnv6_fake(void) +{ + /* we have a standard PLL */ + si->ps.ext_pll = false; + /* 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; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 100; + si->ps.std_memory_clock = 125; +} + +static void pinsnv10_arch_fake(void) +{ + /* we have a standard PLL */ + si->ps.ext_pll = false; + /* 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 */ + if (si->ps.card_type < NV17) + { + /* if a GeForce2 has analog VGA dualhead capability, + * it uses an external secondary DAC probably with limited capability. */ + /* (called twinview technology) */ + 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; + } + else + { + /* GeForce4 cards have dual integrated DACs with identical capaability */ + /* (called nview technology) */ + si->ps.max_dac2_clock = 350; + si->ps.max_dac2_clock_8 = 350; + si->ps.max_dac2_clock_16 = 350; + /* 'failsave' values */ + si->ps.max_dac2_clock_24 = 320; + si->ps.max_dac2_clock_32 = 280; + si->ps.max_dac2_clock_32dh = 250; + } + //fixme: primary & secondary_dvi should be overrule-able via nv.settings + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 120; + si->ps.std_memory_clock = 150; +} + +static void pinsnv20_arch_fake(void) +{ + /* we have a standard PLL */ + si->ps.ext_pll = false; + /* 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 */ + /* GeForce4 cards have dual integrated DACs with identical capaability */ + /* (called nview technology) */ + si->ps.max_dac2_clock = 350; + si->ps.max_dac2_clock_8 = 350; + si->ps.max_dac2_clock_16 = 350; + /* 'failsave' values */ + si->ps.max_dac2_clock_24 = 320; + si->ps.max_dac2_clock_32 = 280; + si->ps.max_dac2_clock_32dh = 250; + //fixme: primary & secondary_dvi should be overrule-able via nv.settings + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 175; + si->ps.std_memory_clock = 200; +} + +static void pinsnv30_arch_fake(void) +{ + /* determine PLL type */ + LOG(8,("INFO: NV30 architecture chip, PIXPLLC2 DAC1 = $%08x, DAC2 = $%08x\n", + DACR(PIXPLLC2), DAC2R(PIXPLLC2))); + switch (si->ps.card_type) + { + case NV31: + case NV36: + case NV40: + /* we have a extended PLL */ + si->ps.ext_pll = true; + break; + default: + /* we have a standard PLL */ + si->ps.ext_pll = false; + break; + } + /* 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 */ + /* GeForceFX cards have dual integrated DACs with identical capaability */ + /* (called nview technology) */ + si->ps.max_dac2_clock = 350; + si->ps.max_dac2_clock_8 = 350; + si->ps.max_dac2_clock_16 = 350; + /* 'failsave' values */ + si->ps.max_dac2_clock_24 = 320; + si->ps.max_dac2_clock_32 = 280; + si->ps.max_dac2_clock_32dh = 250; + //fixme: primary & secondary_dvi should be overrule-able via nv.settings + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* not used (yet) because no coldstart will be attempted (yet) */ + si->ps.std_engine_clock = 190; + si->ps.std_memory_clock = 190; +} + +static void getRAMsize_arch_nv4(void) +{ + uint32 strapinfo = NV_REG32(NV32_NV4STRAPINFO); + + if (strapinfo & 0x00000100) + { + /* Unified memory architecture used */ + si->ps.memory_size = 1024 * 1024 * + ((((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 * 1024 * 1024; + break; + case 1: + si->ps.memory_size = 4 * 1024 * 1024; + break; + case 2: + si->ps.memory_size = 8 * 1024 * 1024; + break; + case 3: + si->ps.memory_size = 16 * 1024 * 1024; + break; + } + } +} + +static void getstrap_arch_nv4(void) +{ + uint32 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; +} + +static void getRAMsize_arch_nv10_20_30_40(void) +{ + uint32 dev_manID = CFGR(DEVID); + uint32 strapinfo = NV_REG32(NV32_NV10STRAPINFO); + + switch (dev_manID) + { + case 0x01a010de: /* Nvidia GeForce2 Integrated GPU */ + case 0x01f010de: /* Nvidia GeForce4 MX Integrated GPU */ + /* the kerneldriver already determined the amount of RAM these cards have at + * their disposal (UMA, values read from PCI config space in other device) */ + LOG(8,("INFO: nVidia GPU with UMA detected\n")); + break; + default: + LOG(8,("INFO: (Memory detection) Strapinfo value is: $%08x\n", strapinfo)); + + switch ((strapinfo & 0x1ff00000) >> 20) + { + case 2: + si->ps.memory_size = 2 * 1024 * 1024; + break; + case 4: + si->ps.memory_size = 4 * 1024 * 1024; + break; + case 8: + si->ps.memory_size = 8 * 1024 * 1024; + break; + case 16: + si->ps.memory_size = 16 * 1024 * 1024; + break; + case 32: + si->ps.memory_size = 32 * 1024 * 1024; + break; + case 64: + si->ps.memory_size = 64 * 1024 * 1024; + break; + case 128: + si->ps.memory_size = 128 * 1024 * 1024; + break; + case 256: + si->ps.memory_size = 256 * 1024 * 1024; + break; + default: + si->ps.memory_size = 16 * 1024 * 1024; + + LOG(8,("INFO: NV10/20/30 architecture chip with unknown RAM amount detected;\n")); + LOG(8,("INFO: Setting 16Mb\n")); + break; + } + } +} + +static void getstrap_arch_nv10_20_30_40(void) +{ + uint32 dev_manID = CFGR(DEVID); + uint32 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 0x004010de: + case 0x00c010de: + case 0x00f010de: + case 0x014010de: + case 0x017010de: + case 0x018010de: + case 0x01f010de: + case 0x025010de: + case 0x028010de: + case 0x030010de: + case 0x031010de: + case 0x032010de: + case 0x033010de: + case 0x034010de: + /* 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 0x004010de: + case 0x00c010de: + case 0x00f010de: + case 0x011010de: + case 0x014010de: + case 0x017010de: + case 0x018010de: + case 0x01f010de: + case 0x025010de: + case 0x028010de: + case 0x030010de: + case 0x031010de: + case 0x032010de: + case 0x033010de: + case 0x034010de: + /* 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,("PLL type: ")); + if (si->ps.ext_pll) LOG(2,("extended\n")); else LOG(2,("standard\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 CH7008: + msg = "Chrontel CH7008"; + break; + case SAA7102: + msg = "Philips SAA7102"; + break; + case SAA7103: + msg = "Philips SAA7103"; + break; + case SAA7104: + msg = "Philips SAA7104"; + break; + case SAA7105: + msg = "Philips SAA7105"; + 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: %3.3fMb\n", (si->ps.memory_size / (1024.0 * 1024.0)))); + LOG(2,("laptop: ")); + if (si->ps.laptop) LOG(2,("yes\n")); else LOG(2,("no\n")); + if (si->ps.tmds1_active) + { + LOG(2,("found DFP (digital flatpanel) on CRTC1; CRTC1 is ")); + if (si->ps.slaved_tmds1) LOG(2,("slaved\n")); else LOG(2,("master\n")); + LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n", + si->ps.p1_timing.h_display, si->ps.p1_timing.v_display, si->ps.panel1_aspect)); + } + if (si->ps.tmds2_active) + { + LOG(2,("found DFP (digital flatpanel) on CRTC2; CRTC2 is ")); + if (si->ps.slaved_tmds2) LOG(2,("slaved\n")); else LOG(2,("master\n")); + LOG(2,("panel width: %d, height: %d, aspect ratio: %1.2f\n", + si->ps.p2_timing.h_display, si->ps.p2_timing.v_display, si->ps.panel2_aspect)); + } + LOG(2,("monitor (output devices) setup matrix: $%02x\n", si->ps.monitors)); + LOG(2,("INFO: end pinsdump.\n")); +} diff --git a/src/add-ons/accelerants/skeleton/engine/proto.h b/src/add-ons/accelerants/skeleton/engine/proto.h new file mode 100644 index 0000000000..eb15c98490 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/proto.h @@ -0,0 +1,130 @@ +/* general card functions */ +status_t nv_general_powerup(void); +status_t nv_set_cas_latency(void); +void setup_virtualized_heads(bool); +void set_crtc_owner(bool); +status_t nv_general_output_select(bool); +status_t nv_general_head_select(bool); +status_t nv_general_wait_retrace(void); +status_t nv_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode); + +/* AGP functions */ +status_t nv_agp_setup(void); + +/* apsed: logging macros */ +#define MSG(args) do { /* if needed or si->settings with si NULL */ \ + nv_log args; \ +} while (0) +#define LOG(level_bit, args) do { \ + uint32 mod = (si->settings.logmask & 0xfffffff0) & MODULE_BIT; \ + uint32 lev = (si->settings.logmask & ~0xfffffff0) & level_bit; \ + if (mod && lev) nv_log args; \ +} while (0) + +/* support functions */ +void delay(bigtime_t i); +void nv_log(char *format, ...); + +/* i2c functions */ +int i2c_maven_read(unsigned char address); +void i2c_maven_write(unsigned char address, unsigned char data); +status_t i2c_init(void); +status_t i2c_maven_probe(void); + +/* card info functions */ +status_t parse_pins(void); +void get_panel_modes(display_mode *p1, display_mode *p2, bool *pan1, bool *pan2); +void fake_panel_start(void); +void set_specs(void); +void dump_pins(void); + +/* DAC functions */ +bool nv_dac_crt_connected(void); +status_t nv_dac_mode(int,float); +status_t nv_dac_palette(uint8*,uint8*,uint8*); +status_t nv_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8); +status_t nv_dac_set_pix_pll(display_mode target); +status_t nv_dac_sys_pll_find(float, float*, uint8*, uint8*, uint8*, uint8); + +/* DAC2 functions */ +bool nv_dac2_crt_connected(void); +status_t nv_dac2_mode(int,float); +status_t nv_dac2_palette(uint8*,uint8*,uint8*); +status_t nv_dac2_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8); +status_t nv_dac2_set_pix_pll(display_mode target); + +/*MAVENTV functions*/ +status_t g100_g400max_maventv_vid_pll_find( + display_mode target, unsigned int * ht_new, unsigned int * ht_last_line, + uint8 * m_result, uint8 * n_result, uint8 * p_result); +int maventv_init(display_mode target); + +/* CRTC1 functions */ +status_t nv_crtc_validate_timing( + uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, + uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt +); +status_t nv_crtc_set_timing(display_mode target); +status_t nv_crtc_depth(int mode); +status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp); +status_t nv_crtc_set_display_pitch(void); + +status_t nv_crtc_dpms(bool, bool, bool); +status_t nv_crtc_dpms_fetch(bool*, bool*, bool*); +status_t nv_crtc_mem_priority(uint8); + +status_t nv_crtc_cursor_init(void); /*Yes, cursor follows CRTC1 - not the DAC!*/ +status_t nv_crtc_cursor_define(uint8*,uint8*); +status_t nv_crtc_cursor_position(uint16 x ,uint16 y); +status_t nv_crtc_cursor_show(void); +status_t nv_crtc_cursor_hide(void); + +/* CRTC2 functions */ +status_t nv_crtc2_validate_timing( + uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, + uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt +); +status_t nv_crtc2_set_timing(display_mode target); +status_t nv_crtc2_depth(int mode); +status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp); +status_t nv_crtc2_set_display_pitch(void); + +status_t nv_crtc2_dpms(bool, bool, bool); +status_t nv_crtc2_dpms_fetch(bool*, bool*, bool*); +status_t nv_crtc2_mem_priority(uint8); + +status_t nv_crtc2_cursor_init(void); +status_t nv_crtc2_cursor_define(uint8*,uint8*); +status_t nv_crtc2_cursor_position(uint16 x ,uint16 y); +status_t nv_crtc2_cursor_show(void); +status_t nv_crtc2_cursor_hide(void); + +/* acceleration functions */ +status_t check_acc_capability(uint32 feature); +status_t nv_acc_init(void); +status_t nv_acc_setup_blit(void); +status_t nv_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 ); +status_t nv_acc_setup_rectangle(uint32 color); +status_t nv_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl); +status_t nv_acc_setup_rect_invert(void); +status_t nv_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl); +status_t nv_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32); +status_t nv_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd); +status_t nv_acc_wait_idle(void); + +/* backend scaler functions */ +status_t check_overlay_capability(uint32 feature); +void nv_bes_move_overlay(void); +status_t nv_bes_to_crtc(bool crtc); +status_t nv_bes_init(void); +status_t nv_configure_bes + (const overlay_buffer *ob, const overlay_window *ow,const overlay_view *ov, int offset); +status_t nv_release_bes(void); + +/* I2C functions */ +status_t i2c_sec_tv_adapter(void); + +/* driver structures and enums */ +enum{BPP8 = 0, BPP15 = 1, BPP16 = 2, BPP24 = 3, BPP32 = 4}; +enum{DS_CRTC1DAC_CRTC2MAVEN, DS_CRTC1MAVEN_CRTC2DAC, DS_CRTC1CON1_CRTC2CON2, DS_CRTC1CON2_CRTC2CON1}; diff --git a/src/add-ons/accelerants/skeleton/engine/std.h b/src/add-ons/accelerants/skeleton/engine/std.h new file mode 100644 index 0000000000..3a8200ab0a --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/std.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include "DriverInterface.h" +#include "nv_globals.h" +//apsed #include "nv_extern.h" +#include "nv_proto.h" +#include "nv_macros.h" diff --git a/src/add-ons/accelerants/skeleton/engine/support.c b/src/add-ons/accelerants/skeleton/engine/support.c new file mode 100644 index 0000000000..4c0990d731 --- /dev/null +++ b/src/add-ons/accelerants/skeleton/engine/support.c @@ -0,0 +1,34 @@ +/* Some commmon support functions */ +/* Mark Watson 2/2000; + * Rudolf Cornelissen 1/2004 */ + +#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()-startps.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 */ + head2_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/skeleton/valid_mode_list b/src/add-ons/accelerants/skeleton/valid_mode_list new file mode 100644 index 0000000000..4c0f04023f --- /dev/null +++ b/src/add-ons/accelerants/skeleton/valid_mode_list @@ -0,0 +1,34 @@ +/*This file can be used to define custom timing for your monitor + * The format of each line is: + * { + * pixel clock frequency (kHz) + * width + * h-sync pulse start + * h-sync pulse end + * total pixels in line + * height + * v-sync pulse start + * v-sync pulse end + * total lines in frame + * sync polarity (0 is -ve,B_POSITIVE_HYSNC,B_POSITIVE_VSYNC) + * } + * + *To use this you must: + * Uncomment VALID MODE REQUIRED + * Fill in a number of modes that work with your display + * Change VALID MODES from three to the no. you defined + * run these commands: + * touch ProposeDisplayMode.c + * make install + */ + +//#define VALID_MODE_REQUIRED 1 + +#define VALID_MODES 3 + +/*note colour depth and mode flags are ignored*/ +static const display_timing valid_mode_list[] = { +{31500,640,648,744,840,480,481,500,500,0}, +{49500,800,808,888,1056,600,601,620,625,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC}, +{78750,1024,1032,1128,1312,768,769,788,800,B_POSITIVE_HSYNC|B_POSITIVE_VSYNC} +};