From 091b52d5b26b0fb530a4bca8318832c2afe7d3bf Mon Sep 17 00:00:00 2001 From: shatty Date: Mon, 1 Dec 2003 05:44:13 +0000 Subject: [PATCH] openBeOS_Matrox_V0.13beta1_src git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5512 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/accelerants/matrox/Acceleration.c | 126 +++ src/add-ons/accelerants/matrox/Cursor.c | 112 ++ .../accelerants/matrox/EngineManagment.c | 68 ++ .../accelerants/matrox/GetAccelerantHook.c | 175 ++++ .../accelerants/matrox/GetDeviceInfo.c | 51 + src/add-ons/accelerants/matrox/GetModeInfo.c | 134 +++ .../accelerants/matrox/GetTimingConstraints.c | 30 + src/add-ons/accelerants/matrox/GlobalData.c | 26 + .../accelerants/matrox/InitAccelerant.c | 288 +++++ src/add-ons/accelerants/matrox/Jamfile | 26 + src/add-ons/accelerants/matrox/Overlay.c | 664 ++++++++++++ .../accelerants/matrox/ProposeDisplayMode.c | 409 ++++++++ .../accelerants/matrox/SetDisplayMode.c | 577 ++++++++++ src/add-ons/accelerants/matrox/acc_std.h | 17 + .../accelerants/matrox/be_driver_proto.h | 66 ++ src/add-ons/accelerants/matrox/engine/Jamfile | 20 + src/add-ons/accelerants/matrox/engine/LICENSE | 9 + .../matrox/engine/matroxfb_maven_hack.c | 879 ++++++++++++++++ .../matrox/engine/matroxfb_maven_hack.h | 88 ++ .../accelerants/matrox/engine/mga_acc.c | 341 ++++++ .../accelerants/matrox/engine/mga_bes.c | 628 +++++++++++ .../accelerants/matrox/engine/mga_crtc.c | 404 +++++++ .../accelerants/matrox/engine/mga_crtc2.c | 96 ++ .../accelerants/matrox/engine/mga_dac.c | 837 +++++++++++++++ .../accelerants/matrox/engine/mga_general.c | 735 +++++++++++++ .../accelerants/matrox/engine/mga_i2c.c | 291 +++++ .../accelerants/matrox/engine/mga_info.c | 990 ++++++++++++++++++ .../accelerants/matrox/engine/mga_maven.c | 172 +++ .../accelerants/matrox/engine/mga_proto.h | 131 +++ .../accelerants/matrox/engine/mga_std.h | 9 + .../accelerants/matrox/engine/mga_support.c | 30 + src/add-ons/accelerants/matrox/global.h | 10 + .../accelerants/matrox/valid_mode_list | 34 + 33 files changed, 8473 insertions(+) create mode 100644 src/add-ons/accelerants/matrox/Acceleration.c create mode 100644 src/add-ons/accelerants/matrox/Cursor.c create mode 100644 src/add-ons/accelerants/matrox/EngineManagment.c create mode 100644 src/add-ons/accelerants/matrox/GetAccelerantHook.c create mode 100644 src/add-ons/accelerants/matrox/GetDeviceInfo.c create mode 100644 src/add-ons/accelerants/matrox/GetModeInfo.c create mode 100644 src/add-ons/accelerants/matrox/GetTimingConstraints.c create mode 100644 src/add-ons/accelerants/matrox/GlobalData.c create mode 100644 src/add-ons/accelerants/matrox/InitAccelerant.c create mode 100644 src/add-ons/accelerants/matrox/Jamfile create mode 100644 src/add-ons/accelerants/matrox/Overlay.c create mode 100644 src/add-ons/accelerants/matrox/ProposeDisplayMode.c create mode 100644 src/add-ons/accelerants/matrox/SetDisplayMode.c create mode 100644 src/add-ons/accelerants/matrox/acc_std.h create mode 100644 src/add-ons/accelerants/matrox/be_driver_proto.h create mode 100644 src/add-ons/accelerants/matrox/engine/Jamfile create mode 100644 src/add-ons/accelerants/matrox/engine/LICENSE create mode 100644 src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c create mode 100644 src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h create mode 100644 src/add-ons/accelerants/matrox/engine/mga_acc.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_bes.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_crtc.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_crtc2.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_dac.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_general.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_i2c.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_info.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_maven.c create mode 100644 src/add-ons/accelerants/matrox/engine/mga_proto.h create mode 100644 src/add-ons/accelerants/matrox/engine/mga_std.h create mode 100644 src/add-ons/accelerants/matrox/engine/mga_support.c create mode 100644 src/add-ons/accelerants/matrox/global.h create mode 100644 src/add-ons/accelerants/matrox/valid_mode_list diff --git a/src/add-ons/accelerants/matrox/Acceleration.c b/src/add-ons/accelerants/matrox/Acceleration.c new file mode 100644 index 0000000000..fa070846e2 --- /dev/null +++ b/src/add-ons/accelerants/matrox/Acceleration.c @@ -0,0 +1,126 @@ +/* + 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. +*/ + +#define MODULE_BIT 0x40000000 + +// apsed, TODO ?? change interface of gx00_acc_* and use MGA pseudo DMA + +#include "acc_std.h" + +void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) { + int i; + + /*do each blit*/ + i=0; + while (count--) + { + gx00_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++; + } +} + +//Not possible with G400 AFAIK (if anyone knows otherwise then please contact me) +//void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { +//typedef struct { +// uint16 src_left; /* guaranteed constrained to virtual width and height */ +// uint16 src_top; +// uint16 src_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ +// uint16 src_height; /* 0 to M, where zero means one line, one means two lines, etc. */ +// uint16 dest_left; +// uint16 dest_top; +// uint16 dest_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ +// uint16 dest_height; /* 0 to M, where zero means one line, one means two lines, etc. */ +//} scaled_blit_params; +//} + +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--) + { + gx00_acc_transparent_blit + ( + list[i].src_left, + list[i].src_top, + list[i].dest_left, + list[i].dest_top, + list[i].width, + list[i].height, + transparent_colour + ); + i++; + } +} + +void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) { + int i; + + /*draw each rectangle*/ + i=0; + while (count--) + { + gx00_acc_rectangle + ( + list[i].left, + (list[i].right)+1, + list[i].top, + (list[i].bottom-list[i].top)+1, + colorIndex + ); + i++; + } +} + +void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) { + int i; + + /*draw each rectangle*/ + i=0; + while (count--) + { + gx00_acc_rectangle_invert + ( + list[i].left, + (list[i].right)+1, + list[i].top, + (list[i].bottom-list[i].top)+1, + 0 + ); + i++; + } +} + +void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) { + int i; + + /*draw each span*/ + i=0; + while (count--) + { + gx00_acc_rectangle + ( + list[i+1], + list[i+2]+1, + list[i], + 1, + colorIndex + ); + i+=3; + } +} diff --git a/src/add-ons/accelerants/matrox/Cursor.c b/src/add-ons/accelerants/matrox/Cursor.c new file mode 100644 index 0000000000..f8e902e9ba --- /dev/null +++ b/src/add-ons/accelerants/matrox/Cursor.c @@ -0,0 +1,112 @@ +/* + 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 +*/ + +#define MODULE_BIT 0x20000000 + +/*DUALHEAD notes - + No hardware cursor possible:( + Reasons: + CRTC1 has a cursor, can be displayed on DAC or MAVEN + CRTC2 has no cursor + Can not switch CRTC in one vblank (has to resync) + CRTC2 does not support split screen + app_server does not support some modes with and some without cursor + virtual not supported, because of MAVEN blanking issues +*/ + +#include "acc_std.h" + +status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask) +{ + LOG(4,("SET_CURSOR_SHAPE: width %d, height %d\n", width, height)); + if ((width != 16) || (height != 16)) + { + return B_ERROR; + } + else if ((hot_x >= width) || (hot_y >= height)) + { + return B_ERROR; + } + else + { + gx00_crtc_cursor_define(andMask,xorMask); + + /* Update cursor variables appropriately. */ + si->cursor.width = width; + si->cursor.height = height; + si->cursor.hot_x = hot_x; + si->cursor.hot_y = hot_y; + } + + return B_OK; +} + +/* Move the cursor to the specified position on the desktop, taking account of virtual/dual issues */ +void MOVE_CURSOR(uint16 x, uint16 y) +{ + uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */ + uint16 vds = si->dm.v_display_start; /* the current vertical starting line */ + uint16 h_adjust; + + /* clamp cursor to display */ + if (x >= si->dm.virtual_width) x = si->dm.virtual_width-1; + if (y >= si->dm.virtual_height) y = si->dm.virtual_height-1; + + /* store, for our info */ + si->cursor.x=x; + si->cursor.y=y; + + /*set up minimum amount to scroll*/ + switch(si->dm.space) + { + case B_CMAP8: + h_adjust=7; + break; + case B_RGB15_LITTLE:case B_RGB16_LITTLE: + h_adjust=3; + break; + case B_RGB32_LITTLE: + h_adjust=1; + break; + default: + h_adjust=7; + } + + /* adjust h/v_display_start to move cursor onto screen */ + if (x >= (si->dm.timing.h_display + hds)) + hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust; + else if (x < hds) + hds = x & ~h_adjust; + + 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 on the display if required */ + if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start)) + MOVE_DISPLAY(hds,vds); + + /* put cursor in correct physical position */ + x -= hds + si->cursor.hot_x; + y -= vds + si->cursor.hot_y; + + /* position the cursor on the display */ + gx00_crtc_cursor_position(x,y); +} + +void SHOW_CURSOR(bool is_visible) +{ + /* record for our info */ + si->cursor.is_visible = is_visible; + + if (is_visible) + gx00_crtc_cursor_show(); + else + gx00_crtc_cursor_hide(); +} diff --git a/src/add-ons/accelerants/matrox/EngineManagment.c b/src/add-ons/accelerants/matrox/EngineManagment.c new file mode 100644 index 0000000000..e135159080 --- /dev/null +++ b/src/add-ons/accelerants/matrox/EngineManagment.c @@ -0,0 +1,68 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + modification to call G400 functions and mess-ups - Mark Watson +*/ + +#define MODULE_BIT 0x10000000 + +#include "acc_std.h" + + +static engine_token gx00_engine_token = { 1, B_2D_ACCELERATION, NULL }; + +uint32 ACCELERANT_ENGINE_COUNT(void) { + return 1; +} + +status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et) { + /* acquire the shared benaphore */ + AQUIRE_BEN(si->engine.lock) + /* sync if required */ + if (st) SYNC_TO_TOKEN(st); + + /* return an engine token */ + *et = &gx00_engine_token; + return B_OK; +} + +status_t RELEASE_ENGINE(engine_token *et, sync_token *st) { + /* update the sync token, if any */ + if (st) { + GET_SYNC_TOKEN(et,st); + } + + /* release the shared benaphore */ + RELEASE_BEN(si->engine.lock) + return B_OK; +} + +void WAIT_ENGINE_IDLE(void) { + uint32 count; + /*wait for the engine to be totally idle*/ + count = si->engine.count; + gx00_acc_wait_idle(); + + si->engine.last_idle = count; +} + +status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) { + si->engine.count+=4; + st->engine_id = et->engine_id; + st->counter = si->engine.count; + return B_OK; +} + +status_t SYNC_TO_TOKEN(sync_token *st) { + /* a quick out */ + if (st->counter <= si->engine.last_idle) return B_OK; + + /* another quick out! */ + if ((st->counter >0xFFFFFFF) && (si->engine.last_idle <0xFFFF)) return B_OK; /*for when counter wraps*/ + + /* If not we have to wait :-(*/ + WAIT_ENGINE_IDLE(); + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/GetAccelerantHook.c b/src/add-ons/accelerants/matrox/GetAccelerantHook.c new file mode 100644 index 0000000000..9180daa184 --- /dev/null +++ b/src/add-ons/accelerants/matrox/GetAccelerantHook.c @@ -0,0 +1,175 @@ +/* + 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 +*/ + +#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. + +*/ + +void * get_accelerant_hook(uint32 feature, void *data) { + switch (feature) { +/* +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 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 + +/* +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); // apsed + 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); + + /* 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. +*/ + /* 2D acceleration */ + HOOK(SCREEN_TO_SCREEN_BLIT); + HOOK(FILL_RECTANGLE); + HOOK(INVERT_RECTANGLE); + HOOK(FILL_SPAN); + HOOK(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);//remove for pre R5 + + /*HOOK(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT; + Does the G400 support this? I can only think of using texture mapped rectangles, but these seem to have too many restrictions to do this:( e.g. I would need to blit offscreen, into texture format... + */ +#undef HOOK +#undef ZERO + } +/* +Return a null pointer for any feature we don't understand. +*/ + return 0; +} + +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; + } + + switch(si->ps.card_type) + { + case G200: + case G400: /* is also G400MAX in accelerant for now? */ + case G400MAX: /* not used in accelerant yet? */ + case G450: /* is also G550 in accelerant for now */ + case G550: /* not used in accelerant yet */ + /* export video overlay functions */ + LOG(4, ("Overlay: Exporting hook %s.\n", msg)); + return B_OK; + break; + default: + /* do not export video overlay functions */ + LOG(4, ("Overlay: Not exporting hook %s.\n", msg)); + return B_ERROR; + break; + } +} diff --git a/src/add-ons/accelerants/matrox/GetDeviceInfo.c b/src/add-ons/accelerants/matrox/GetDeviceInfo.c new file mode 100644 index 0000000000..b4c6dede20 --- /dev/null +++ b/src/add-ons/accelerants/matrox/GetDeviceInfo.c @@ -0,0 +1,51 @@ +/* + Authors: + Mark Watson - 21/6/00, + Apsed +*/ + +#define MODULE_BIT 0x04000000 + +#include "acc_std.h" + +/* Get some info about the device */ +status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info * adi) +{ + /*no info on version is provided, so presumably this is for my info*/ + LOG(4,("DEVICE_INFO: version 0x%08x\n", adi->version)); + + switch ((si->ps.secondary_head << 4)|si->ps.card_type) + { + case 0x01: + sprintf(adi->name,"Matrox G400 Plain"); + break; + case 0x02: + sprintf(adi->name,"Matrox G400 MAX"); + break; + case 0x11: + sprintf(adi->name,"Matrox Dualhead G400 Plain"); + break; + case 0x12: + sprintf(adi->name,"Matrox Dualhead G400 MAX"); + break; + } + + sprintf(adi->chipset,"MGAG400"); + + sprintf(adi->serial_no,"01134"); /*FIXME*/ + + adi->memory=si->ps.memory_size * 1024 * 1024; + + adi->dac_speed=si->ps.max_dac1_clock; + + // apsed, TODO ?? GET_ACCELERANT_DEVICE_INFO never called and kind of cards + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "version", adi->version, adi->version)); + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "name", adi->name)); + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "chipset", adi->chipset)); + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %s\n", "serial_no", adi->serial_no)); + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s 0x%08x %d\n", "memory", adi->memory, adi->memory)); + LOG(2,("GET_ACCELERANT_DEVICE_INFO %20s %d\n", "dac_speed", adi->dac_speed)); + + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/GetModeInfo.c b/src/add-ons/accelerants/matrox/GetModeInfo.c new file mode 100644 index 0000000000..8670f645b9 --- /dev/null +++ b/src/add-ons/accelerants/matrox/GetModeInfo.c @@ -0,0 +1,134 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson + Rudolf Cornelissen 9/2002 +*/ + +#define MODULE_BIT 0x02000000 + +#include "acc_std.h" + +/* + Return the current display mode. The only time you might return an + error is if a mode hasn't been set. Or if the system hands you a NULL pointer. +*/ +status_t GET_DISPLAY_MODE(display_mode *current_mode) +{ + /* check for NULL pointer */ + if (current_mode == NULL) return B_ERROR; + + *current_mode = si->dm; + return B_OK; +} + +/* Return the frame buffer configuration information. */ +status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) +{ + /* check for NULL pointer */ + if (afb == NULL) return B_ERROR; + + *afb = si->fbc; + return B_OK; +} + +/* Return the maximum and minium pixelclock limits for the specified mode. */ +/* Rewritten / fixed by Rudolf */ +/* NOTE: + * Due to BeOS constraints output for all heads will be limited to the head with + * the least capabilities. (BeOS should ask for seperate constraints for all heads.) */ +status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) +{ + uint32 max_pclk = 0; + + /* 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) + { + case G550: + case G450: + *low = ((si->ps.min_video_vco * 1000) / 16); + break; + default: + *low = ((si->ps.min_video_vco * 1000) / 8); + break; + } + /* find max. value */ + switch (dm->space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac2_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac2_clock_24; + break; + case B_RGB32_LITTLE: + /* specially noted because of RAM speed constraints! */ + max_pclk = si->ps.max_dac2_clock_32dh; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32dh; + break; + } + /* return values in kHz */ + *high = max_pclk * 1000; + } + else + { + /* singlehead mode */ + /* find min. value */ + switch (si->ps.card_type) + { + case G550: + case G450: + *low = ((si->ps.min_pixel_vco * 1000) / 16); + break; + default: + *low = ((si->ps.min_pixel_vco * 1000) / 8); + break; + } + /* find max. value */ + switch (dm->space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac1_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac1_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac1_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac1_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_32; + break; + } + /* return values in kHz */ + *high = max_pclk * 1000; + } + 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/matrox/GetTimingConstraints.c b/src/add-ons/accelerants/matrox/GetTimingConstraints.c new file mode 100644 index 0000000000..29751b96c8 --- /dev/null +++ b/src/add-ons/accelerants/matrox/GetTimingConstraints.c @@ -0,0 +1,30 @@ +/* + Authors: + Mark Watson - 21/6/00, + Apsed +*/ + +#define MODULE_BIT 0x01000000 + +#include "acc_std.h" + +/* Used to help generate mode lines */ +status_t GET_TIMING_CONSTRAINTS(display_timing_constraints * dtc) +{ + // apsed, TODO, is that following card capabilities ?? + LOG(4, ("GET_TIMING_CONSTRAINTS\n")); + + dtc->h_res=8; + dtc->h_sync_min=8; + dtc->h_sync_max=248; + dtc->h_blank_min=8; + dtc->h_blank_max=504; + + dtc->v_res=1; + dtc->v_sync_min=1; + dtc->v_sync_max=15; + dtc->v_blank_min=1; + dtc->v_blank_max=255; + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/GlobalData.c b/src/add-ons/accelerants/matrox/GlobalData.c new file mode 100644 index 0000000000..0edbdbf222 --- /dev/null +++ b/src/add-ons/accelerants/matrox/GlobalData.c @@ -0,0 +1,26 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson +*/ + +#include "acc_std.h" + +int fd; +shared_info *si; +area_id shared_info_area; +vuint32 *regs; +area_id regs_area; +display_mode *my_mode_list; +area_id my_mode_list_area; +int accelerantIsClone; + +gx00_get_set_pci gx00_pci_access= + { + GX00_PRIVATE_DATA_MAGIC, + 0, + 4, + 0 + }; diff --git a/src/add-ons/accelerants/matrox/InitAccelerant.c b/src/add-ons/accelerants/matrox/InitAccelerant.c new file mode 100644 index 0000000000..195fb03cc2 --- /dev/null +++ b/src/add-ons/accelerants/matrox/InitAccelerant.c @@ -0,0 +1,288 @@ +/* + 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. +*/ + +#define MODULE_BIT 0x00800000 + +#include +#include "acc_std.h" + +/* defined in ProposeDisplayMode.c */ +extern status_t create_mode_list(void); + +static status_t init_common(int the_fd); + +/* Initialization code shared between primary and cloned accelerants */ +static status_t init_common(int the_fd) { + status_t result; + gx00_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 = GX00_PRIVATE_DATA_MAGIC; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, GX00_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\n", si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios)); + + /*Check for R4.5.0 and if it is running, use work around*/ + { + if (si->use_clone_bugfix) + { + /*check for R4.5.0 bug and attempt to work around*/ + LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n")); + regs = si->clone_bugfix_regs; + } + else + { + /* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/ + regs_area = clone_area(DRIVER_PREFIX " regs", (void **)®s, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, si->regs_area); + if (regs_area < 0) { + result = regs_area; + goto error1; + } + } + } + + /*FIXME - print dma addresses*/ + //LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area)); + + /* all done */ + goto error0; + +error1: + delete_area(shared_info_area); +error0: + return result; +} + +/* Clean up code shared between primary and cloned accelrants */ +static void uninit_common(void) { + /* release the memory mapped registers */ + delete_area(regs_area); + /* a little cheap paranoia */ + regs = 0; + /* release our copy of the shared info from the kernel driver */ + delete_area(shared_info_area); + /* more cheap paranoia */ + si = 0; +} + +/* +Initialize the accelerant. the_fd is the file handle of the device (in +/dev/graphics) that has been opened by the app_server (or some test harness). +We need to determine if the kernel driver and the accelerant are compatible. +If they are, get the accelerant ready to handle other hook functions and +report success or failure. +*/ +status_t INIT_ACCELERANT(int the_fd) { + status_t result; + int pointer_reservation; //mem reserved for pointer + int cnt; //used for iteration through the overlay buffers + + if (1) { + time_t now = time (NULL); + // LOG not available from here to next LOG: NULL si +// MSG(("INIT_ACCELERANT: booted since %f ms %s\n", system_time()/1000.0, real_time_clock())); + MSG(("INIT_ACCELERANT: %s", ctime (&now))); + } + + /* note that we're the primary accelerant (accelerantIsClone is global) */ + accelerantIsClone = 0; + + /* do the initialization common to both the primary and the clones */ + result = init_common(the_fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error0; + // LOG now available: !NULL si + + /* call the device specific init code */ + result = gx00_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. The typical 64x64 4 color + (black, white, transparent, inverse) takes up 1024 bytes of RAM. + */ + /* Initialize the rest of the cursor information while we're here */ + si->cursor.width = 16; + si->cursor.height = 16; + si->cursor.hot_x = 0; + si->cursor.hot_y = 0; + si->cursor.x = 0; + si->cursor.y = 0; + + /* + Put the frame buffer immediately following the cursor data. We store this + info in a frame_buffer_config structure to make it convienient to return + to the app_server later. + */ + //don't reserve memory at the start of the fb, because this doesn't work on the G100 (no SRCORG/DSTORG) + pointer_reservation = si->settings.hardcursor? 1024: 0; // apsed TODO with G100, see before + si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation); + si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation); + + /* count of issued parameters or commands */ + si->engine.last_idle = si->engine.count = 0; + INIT_BEN(si->engine.lock); + + INIT_BEN(si->overlay.lock); + for (cnt = 0; cnt < MAXBUFFERS; cnt++) + { + /* make sure overlay buffers are 'marked' as being free */ + si->overlay.myBuffer[cnt].buffer = NULL; + si->overlay.myBuffer[cnt].buffer_dma = NULL; + } + /* make sure overlay unit is 'marked' as being free */ + si->overlay.myToken = NULL; + + /* bail out if something failed */ + if (result != B_OK) goto error1; + + /* initialise various cursor stuff*/ + gx00_crtc_cursor_init(); + + /* ensure cursor state */ + SHOW_CURSOR(false); + + /* a winner! */ + result = B_OK; + goto error0; + +error1: + /* + Initialization failed after init_common() succeeded, so we need to clean + up before quiting. + */ + uninit_common(); + +error0: + return result; +} + +/* +Return the number of bytes required to hold the information required +to clone the device. +*/ +ssize_t ACCELERANT_CLONE_INFO_SIZE(void) { + /* + Since we're passing the name of the device as the only required + info, return the size of the name buffer + */ + return B_OS_NAME_LENGTH; // apsed, was MAX_GX00_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) { + gx00_device_name dn; + status_t result; + + /* call the kernel driver to get the device name */ + dn.magic = GX00_PRIVATE_DATA_MAGIC; + /* store the returned info directly into the passed buffer */ + dn.name = (char *)data; + result = ioctl(fd, GX00_DEVICE_NAME, &dn, sizeof(dn)); +} + +/* +Initialize a copy of the accelerant as a clone. void *data points to +a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). +*/ +status_t CLONE_ACCELERANT(void *data) { + status_t result; + char path[MAXPATHLEN]; + + /* the data is the device name */ + strcpy(path, "/dev"); + strcat(path, (const char *)data); + /* open the device, the permissions aren't important */ + fd = open(path, B_READ_WRITE); + if (fd < 0) { + result = fd; + goto error0; + } + + /* note that we're a clone accelerant */ + accelerantIsClone = 1; + + /* call the shared initialization code */ + result = init_common(fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error1; + + /* get shared area for display modes */ + result = my_mode_list_area = clone_area( + DRIVER_PREFIX " cloned display_modes", + (void **)&my_mode_list, + B_ANY_ADDRESS, + B_READ_AREA, + si->mode_area + ); + if (result < B_OK) goto error2; + + /* all done */ + 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) { + /*delete benaphore*/ + DELETE_BEN(si->engine.lock); + DELETE_BEN(si->overlay.lock); + /* free our mode list area */ + delete_area(my_mode_list_area); + /* paranoia */ + my_mode_list = 0; + /* release our cloned data */ + uninit_common(); + /* close the file handle ONLY if we're the clone */ + if (accelerantIsClone) close(fd); +} diff --git a/src/add-ons/accelerants/matrox/Jamfile b/src/add-ons/accelerants/matrox/Jamfile new file mode 100644 index 0000000000..4dcc504fe5 --- /dev/null +++ b/src/add-ons/accelerants/matrox/Jamfile @@ -0,0 +1,26 @@ +SubDir OBOS_TOP src add-ons accelerants matrox ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics matrox ] ; +UseHeaders [ FDirName $(SUBDIR) engine ] ; + + +Addon mga.accelerant : accelerants : + Acceleration.c + Cursor.c + EngineManagment.c + GetAccelerantHook.c + GetDeviceInfo.c + GetModeInfo.c + GetTimingConstraints.c + GlobalData.c + InitAccelerant.c + Overlay.c + ProposeDisplayMode.c + SetDisplayMode.c + : false : libmatrox_engine.a +; + +Depends mga.accelerant : mga.driver ; + +SubInclude OBOS_TOP src add-ons accelerants matrox engine ; diff --git a/src/add-ons/accelerants/matrox/Overlay.c b/src/add-ons/accelerants/matrox/Overlay.c new file mode 100644 index 0000000000..fbf88ff519 --- /dev/null +++ b/src/add-ons/accelerants/matrox/Overlay.c @@ -0,0 +1,664 @@ +/* Written by Rudolf Cornelissen 05/09-2002 V0.13 beta1 */ + +/* 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 + +/* Note: + * In order to enable OVERLAY logging, in file mga.settings include a line with: + * + * logmask 0x08000604 # log OVERLAY use in full + * + * Make sure you copy the resulting file to ~/config/settings/kernel/drivers/ ! + * + * Beware that enabling OVERLAY logging will create a very large logfile quickly in + * your home folder (named mga.accelerant.log) if you use double buffered overlay + * playback (100Mb will be reached in 'no time', like in a few days or so.). + * + * For testing purposes, you might want to have full logging enabled though... + */ + +#include "acc_std.h" + +/* define the supported overlay input colorspaces */ +/* Note: + * G200-G550 can all do YUV4:2:0 2-plane colorspace as well, + * G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering), + * G200 does not support YUV4:2:0 3-plane mode while > G200 do. + * It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace + * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */ +static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE }; + +uint32 OVERLAY_COUNT(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: count called\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + } + /* apparantly overlay count should report the number of 'overlay units' on the card */ + return 1; +} + +const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: supported_spaces called.\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + return NULL; + } + + /* interlaced VGA is not supported by G200-G550 BES */ + if (dm->timing.flags && B_TIMING_INTERLACED) + { + return NULL; + } + /* return a B_NO_COLOR_SPACE terminated list */ + return &overlay_colorspaces[0]; +} + +uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space) +// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported! +{ + LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space)); + + /* check what features (like the keying method) are supported on the current + * Desktop colorspace */ + //fixme? Or are we talking about the overlay input bitmap's colorspace? + switch (a_color_space) + { + default: + /* fixme: for now 'direct 32bit' desktop colorspace assumed */ + return + ( B_OVERLAY_KEYING_USES_ALPHA | + B_OVERLAY_COLOR_KEY | + B_OVERLAY_HORIZONTAL_FILTERING | + B_OVERLAY_VERTICAL_FILTERING ); + } +} + +const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height) +{ + int offset = 0; /* used to determine next buffer to create */ + uint32 adress, adress2, temp32; /* used to calculate buffer adresses */ + uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */ + int cnt; /* loopcounter */ + + /* acquire the shared benaphore */ + AQUIRE_BEN(si->overlay.lock) + + LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer))); + LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci))); + LOG(4,("Overlay: cardRAM_size = %dMb\n",si->ps.memory_size)); + + /* find first empty slot (room for another buffer?) */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == NULL) break; + } + + LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset)); + + if (offset < MAXBUFFERS) + /* setup new scaler input buffer */ + { + switch (cs) + { + case B_YCbCr422: + /* check if slopspace is needed: compatible settings choosen for now: + * G200 can do with ~0x0003 while > G200 need ~x0007. + * Optimized settings for G200 could reduce CPU load a tiny little bit there... */ + if (width == (width & ~0x0007)) + { + si->overlay.myBuffer[offset].width = width; + } + else + { + si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8; + } + si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width; + + /* check if the requested horizontal pitch is supported: + * G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace. + * Compatible check done, has no downside consequences here. */ + if (si->overlay.myBuffer[offset].width > 4088) + { + LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + break; + +// case 0xffff://fixme: which one(s)? + //fixme: 4:2:0 2-plane supported format, should be selected only if detected + /* check if slopspace is needed: compatible settings choosen for now: + * G200 can do with ~0x0007 while > G200 need ~x001f. + * Optimized settings for G200 could reduce CPU load a tiny little bit there... */ +/* if (width == (width & ~0x001f)) + { + si->overlay.myBuffer[offset].width = width; + } + else + { + si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32; + } +*/ /* assuming Y-plane only bytes_per_row are requested here */ +/* si->overlay.myBuffer[offset].bytes_per_row = si->overlay.myBuffer[offset].width; +*/ + /* check if the requested horizontal pitch is supported: + * G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace. + * Compatible check done, has no real downside consequences here. */ +/* if (si->overlay.myBuffer[offset].width > 4064) + { + LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"); +*/ + /* release the shared benaphore */ +/* RELEASE_BEN(si->overlay.lock) + + return NULL; + } + break; +*/ + default: + /* unsupported colorspace! */ + LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs)); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + break; + } + + /* check if the requested buffer width is supported */ + if (si->overlay.myBuffer[offset].width > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + /* check if the requested buffer height is supported */ + if (height > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + + /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */ + si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width; + + si->overlay.myBuffer[offset].space = cs; + si->overlay.myBuffer[offset].height = height; + + /* we define the overlay buffers to reside 'in the back' of the cards RAM */ + /* NOTE to app programmers: + * Beware that an app using overlay needs to track workspace switches and screenprefs + * changes. If such an action is detected, the app needs to reset it's pointers to the + * newly created overlay bitmaps, which will be assigned by BeOS automatically after such + * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!) + * + * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them + * than previously setup by the app might be re-setup. This is due to cardRAM restraints then. + * This means that the app should also check for NULL pointers returned by the bitmaps, + * and if this happens, it needs to fallback to single buffered overlay or even fallback to + * bitmap output for the new situation. */ + + /* Another NOTE for app programmers: + * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the + * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately. + * This *greatly* simplifies tracking such errors! + * Of course such errors may lead to strange effects in the app or driver behaviour if they are + * not hunted down and removed.. */ + + /* calculate first free RAM adress in card: + * Driver setup is as follows: + * card base: - hardware cursor bitmap (if used), + * directly above - screen memory for both heads */ + adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */ + (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */ + LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2)); + + /* calculate 'preliminary' buffer size including slopspace */ + oldsize = si->overlay.myBufInfo[offset].size; + si->overlay.myBufInfo[offset].size = + si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height; + + /* calculate virtual memory adress that would be needed for a new bitmap */ + /* NOTE to app programmers: + * For testing app behaviour regarding workspace switches or screen prefs changes to settings + * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with + * a low amount of RAM. Or you can set in the file mga.settings for example: + * memory 8 #8Mb RAM on card + * and reboot (this simulates 8Mb RAM on the card). + * + * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to + * bitmap output or maybe single buffered overlay output if small bitmaps are used. */ + + adress = (((uint32)((uint8*)si->framebuffer)) + (si->ps.memory_size * 1024 * 1024)); + for (cnt = 0; cnt <= offset; cnt++) + { + adress -= si->overlay.myBufInfo[cnt].size; + } + + /* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with + * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */ + + /* Check if we need to modify the buffers starting adress and thus the size */ + /* calculate 'would be' cardRAM offset */ + temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer))); + /* check if it is aligned */ + if (temp32 != (temp32 & 0xfffffff0)) + { + /* update the (already calculated) buffersize to get it aligned */ + si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0)); + /* update the (already calculated) adress to get it aligned */ + adress -= (temp32 - (temp32 & 0xfffffff0)); + } + LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress)); + + /* First check now if buffer to be defined is 'last one' in memory (speaking backwards): + * this is done to prevent a large buffer getting created in the space a small buffer + * occupied earlier, if not all buffers created were deleted. + * Note also that the app can delete the buffers in any order desired. */ + + /* NOTE to app programmers: + * If you are going to delete a overlay buffer you created, you should delete them *all* and + * then re-create only the new ones needed. This way you are sure not to get unused memory- + * space in between your overlay buffers for instance, so cardRAM is used 'to the max'. + * If you don't, you might not get a buffer at all if you are trying to set up a larger one + * than before. + * (Indeed: not all buffers *have* to be of the same type and size...) */ + + for (cnt = offset; cnt < MAXBUFFERS; cnt++) + { + if (si->overlay.myBuffer[cnt].buffer != NULL) + { + /* Check if the new buffer would fit into the space the single old one used here */ + if (si->overlay.myBufInfo[offset].size <= oldsize) + { + /* It does, so we reset to the old size and adresses to prevent the space from shrinking + * if we get here again... */ + adress -= (oldsize - si->overlay.myBufInfo[offset].size); + si->overlay.myBufInfo[offset].size = oldsize; + LOG(4,("Overlay: 'squeezing' in buffer:\n" + "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize)); + /* force exiting the FOR loop */ + cnt = MAXBUFFERS; + } + else + { + /* nogo, sorry */ + LOG(4,("Overlay: Other buffer(s) exist after this one:\n" + "Overlay: not enough space to 'squeeze' this one in, aborted\n")); + + /* Reset to the old size to prevent the space from 'growing' if we get here again... */ + si->overlay.myBufInfo[offset].size = oldsize; + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + } + } + + /* check if we have enough space to setup this new bitmap + * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */ + if (adress < adress2) + /* nope, sorry */ + { + LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + /* continue buffer setup */ + si->overlay.myBuffer[offset].buffer = (void *) adress; + + /* calculate physical memory adress (for dma use) */ + /* NOTE to app programmers: + * For testing app behaviour regarding workspace switches or screen prefs changes to settings + * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with + * a low amount of RAM. Or you can set in the file mga.settings for example: + * memory 8 #8Mb RAM on card + * and reboot (this simulates 8Mb RAM on the card). + * + * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to + * bitmap output or maybe single buffered overlay output if small bitmaps are used. */ + + adress = (((uint32)((uint8*)si->framebuffer_pci)) + (si->ps.memory_size * 1024 * 1024)); + for (cnt = 0; cnt <= offset; cnt++) + { + adress -= si->overlay.myBufInfo[cnt].size; + } + /* this adress is already aligned to the scaler's requirements (via the already modified sizes) */ + si->overlay.myBuffer[offset].buffer_dma = (void *) adress; + + LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n", + (uint32)((uint8*)si->overlay.myBuffer[offset].buffer), + (uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs)); + LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size)); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return &si->overlay.myBuffer[offset]; + } + else + /* sorry, no more room for buffers */ + { + LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } +} + +status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob) +/* Note that the user can delete the buffers in any order desired! */ +{ + int offset = 0; + + if (ob != NULL) + { + /* find the buffer */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + /* delete current buffer */ + { + si->overlay.myBuffer[offset].buffer = NULL; + si->overlay.myBuffer[offset].buffer_dma = NULL; + + LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset)); + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n")); + + return B_ERROR; + } + } + else + /* no buffer specified! */ + { + LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n")); + + return B_ERROR; + } +} + +status_t GET_OVERLAY_CONSTRAINTS + (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc) +{ + int offset = 0; + + LOG(4,("Overlay: Get_overlay_constraints called\n")); + + /* check for NULL pointers */ + if ((dm == NULL) || (ob == NULL) || (oc == NULL)) + { + LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n")); + return B_ERROR; + } + + /* find the buffer */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + { + /* scaler input (values are in pixels) */ + oc->view.h_alignment = 0; + oc->view.v_alignment = 0; + + switch (ob->space) + { + case B_YCbCr422: + /* G200 can work with 3, > G200 need 7. Compatible setting returned for now. + * Note: this has to be in sync with the slopspace setup during buffer allocation.. */ + oc->view.width_alignment = 7; + break; + +// case 0xffff://fixme: which one(s)? (4:2:0 supported formats. Not yet used...) + /* G200 can work with 7, > G200 need 31. Compatible setting returned for now. + * Note: this has to be in sync with the slopspace setup during buffer allocation.. */ +/* oc->view.width_alignment = 31; + break; +*/ + default: + /* we should not be here, but set the worst-case value just to be safe anyway */ + oc->view.width_alignment = 31; + break; + } + + oc->view.height_alignment = 0; + oc->view.width.min = 1; + oc->view.height.min = 2; /* two fields */ + oc->view.width.max = ob->width; + oc->view.height.max = ob->height; + + /* scaler output restrictions */ + oc->window.h_alignment = 0; + oc->window.v_alignment = 0; + oc->window.width_alignment = 0; + oc->window.height_alignment = 0; + oc->window.width.min = 2; + /* G200-G550 can output upto and including 2048 pixels in width */ + if (dm->virtual_width > 2048) + { + oc->window.width.max = 2048; + } + else + { + oc->window.width.max = dm->virtual_width; + } + oc->window.height.min = 2; + /* G200-G550 can output upto and including 2048 pixels in height */ + if (dm->virtual_height > 2048) + { + oc->window.height.max = 2048; + } + else + { + oc->window.height.max = dm->virtual_height; + } + + /* G200-G550 scaling restrictions */ + /* Adjust horizontal restrictions if pixelclock is above BES max. speed! */ + /* Note: If RGB32 is implemented no scaling is supported! */ + if (si->dm.timing.pixel_clock > BESMAXSPEED) + { + oc->h_scale.min = (1 * 2) / (32 - (1 / (float)16384)); + oc->h_scale.max = (16384 * 2)/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace); + } + else + { + oc->h_scale.min = 1 / (32 - (1 / (float)16384)); + oc->h_scale.max = 16384/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace); + } + oc->v_scale.min = 1 / (32 - (1 / (float)16384)); + oc->v_scale.max = 16384/(float)ob->height; + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n")); + + return B_ERROR; + } +} + +overlay_token ALLOCATE_OVERLAY(void) +{ + uint32 tmpToken; + LOG(4,("Overlay: Allocate_overlay called: ")); + + /* come up with a token */ + tmpToken = 0x12345678; + + /* acquire the shared benaphore */ + AQUIRE_BEN(si->overlay.lock) + + /* overlay unit already in use? */ + if (si->overlay.myToken == NULL) + /* overlay unit is available */ + { + LOG(4,("succesfull\n")); + + si->overlay.myToken = &tmpToken; + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return si->overlay.myToken; + } + else + /* sorry, overlay unit is occupied */ + { + LOG(4,("failed: already in use!\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } +} + +status_t RELEASE_OVERLAY(overlay_token ot) +{ + LOG(4,("Overlay: Release_overlay called: ")); + + /* is this call for real? */ + if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) + /* nope, abort */ + { + LOG(4,("failed, not in use!\n")); + + return B_ERROR; + } + else + /* call is for real */ + { + + gx00_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 */ + + /* in BeOS R5.0.3 (maybe DANO works different): + * '*ov' is the output size on the desktop: does not change if clipped. + * h_start and v_start are always 0, width and heigth are the size of the window. + * Because the width and height can also be found in '*ow', '*ov' is not used. */ + + 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)); + + gx00_configure_bes(ob, ow, 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/matrox/ProposeDisplayMode.c b/src/add-ons/accelerants/matrox/ProposeDisplayMode.c new file mode 100644 index 0000000000..429af2309e --- /dev/null +++ b/src/add-ons/accelerants/matrox/ProposeDisplayMode.c @@ -0,0 +1,409 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors for MGA driver: + Mark Watson, + Rudolf Cornelissen 9/2002 +*/ + +#define MODULE_BIT 0x00400000 + +#include "acc_std.h" + +#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) +#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS) +#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode)) + +/*some monitors only handle a fixed set of modes*/ +#include "valid_mode_list" + +/*Standard VESA modes*/ +static const display_mode mode_list[] = { +{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ +{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ +{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ +{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ +{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ +{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ +{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ +{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */ +{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */ +{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */ +{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */ +{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */ +{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */ +{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ +{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ +{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 108000, 1152, 1216, 1344, 1550, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 120000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ +{ { 120000, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ +{ { 108000, 1280, 1328, 1440, 1680, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */ +{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */ +{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */ +{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */ +{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */ +{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */ +{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */ +{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */ +{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */ +}; + +// apsed, adjust virtual width for CRTC offset constraints +// PB with MIl2 800*600 with bpp < 32 +static status_t adjust_width (display_mode *target, bool want_same_width) +{ + uint32 video_pitch = target->virtual_width; + uint32 multiple; + + if (si->ps.card_type < G100) switch (target->space & 0x0fff) { // MIL2 + case B_CMAP8: multiple = 128; break; + case B_RGB15: multiple = 64; break; + case B_RGB16: multiple = 64; break; + case B_RGB24: multiple = 128; break; + case B_RGB32: multiple = 32; break; + default: + LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } else switch (target->space & 0x0fff) { // G100, G200, G400 + case B_CMAP8: multiple = 16; break; + case B_RGB15: multiple = 8; break; + case B_RGB16: multiple = 8; break; + case B_RGB24: multiple = 16; break; + case B_RGB32: multiple = 4; break; + default: + LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + video_pitch = (video_pitch+multiple-1)/multiple; + video_pitch *= multiple; + if (target->virtual_width != video_pitch) { + LOG(2,("PROPOSEMODE: color space 0x%08x, virtual_width %d adjusted to %d \n", + target->space, target->virtual_width, video_pitch)); + target->virtual_width = video_pitch; + if (want_same_width) target->timing.h_display = video_pitch; + } + return B_OK; +} + +/*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 +*/ +status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) +{ + status_t status; + float pix_clock_found; + uint8 m,n,p; + status_t result = B_OK; + uint32 row_bytes, limit_clock, max_vclk; + 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; + +// // apsed, adjust virtual width for CRTC offset constraints +// status = adjust_width (target, want_same_width); +// if (status != B_OK) return status; + + /*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; + + 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*/ + { + 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 = gx00_crtc_validate_timing + ( + &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total, + &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total + ); + if (result == B_ERROR) return result; + + /*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) + ) result = B_BAD_VALUE; + + /*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) || // apsed + (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) + ) result = B_BAD_VALUE; + + //rudolf + /* 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 */ + if (si->ps.card_type >= G100) + { + /* calculate settings, but do not actually test anything (that costs too much time!) */ + status = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0); + } + else + { + //fixme: implement pixelclock limits check (and modify if needed) for target mode inside mil2_find routine! + //temp until then: + limit_clock = si->ps.max_dac1_clock * 1000; + if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock; + + status = mil2_dac_pix_pll_find((float)target->timing.pixel_clock/1000.0,&pix_clock_found,&m,&n,&p); + } + target->timing.pixel_clock = pix_clock_found*1000; + //end rudolf + + /* note if we fell outside the limits */ + if ( + (target->timing.pixel_clock < low->timing.pixel_clock) || + (target->timing.pixel_clock > high->timing.pixel_clock) + ) result = B_BAD_VALUE; + + /* 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; + if (target->virtual_width > 4096) + target->virtual_width = 4096; + if (target->virtual_height > 2048) + target->virtual_height = 2048; + + /* adjust virtual width for engine limitations - must be multiple of 8 */ + target->virtual_width = (target->virtual_width + 7) & ~7; + if ( + (target->virtual_width < low->virtual_width) || + (target->virtual_width > high->virtual_width) + ) result = B_BAD_VALUE; + + // apsed, adjust virtual width for CRTC offset constraints + status = adjust_width (target, want_same_width); + if (status != B_OK) return status; + + /* calculate rowbytes after we've nailed the virtual width */ + switch (target->space & 0x0fff) { + case B_CMAP8: + row_bytes = 1; + break; + case B_RGB15: + case B_RGB16: + row_bytes = 2; + break; + case B_RGB32: + row_bytes = 4; + break; + default: + /* no amount of adjusting will fix not being able to support the pixel format */ + LOG(8,("PROPOSEMODE: unknown target space: 0x%08x\n", target->space)); + return B_ERROR; + } + row_bytes *= target->virtual_width; + + /* memory requirement for frame buffer */ + if ((row_bytes * target->virtual_height) > (si->ps.memory_size * 1024 * 1024)) + target->virtual_height = (si->ps.memory_size * 1024 * 1024) / row_bytes; + if (target->virtual_height < target->timing.v_display) + { + LOG(8,("PROPOSEMODE: virtual_height required %d < %d\n", target->virtual_height, target->timing.v_display)); + return B_ERROR; + } + else if ( + (target->virtual_height < low->virtual_height) || + (target->virtual_height > high->virtual_height) + ) result = B_BAD_VALUE; + + /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */ + switch (target->space) + { + case B_CMAP8: + max_vclk = si->ps.max_dac2_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_vclk = si->ps.max_dac2_clock_16; + break; + case B_RGB24_LITTLE: + max_vclk = si->ps.max_dac2_clock_24; + break; + case B_RGB32_LITTLE: + max_vclk = si->ps.max_dac2_clock_32dh; + break; + default: + /* use fail-safe value */ + max_vclk = si->ps.max_dac2_clock_32dh; + break; + } + + /*clear DUALHEAD_CAPABLE if any problems*/ + if + ( + ((target->flags)& DUALHEAD_CAPABLE ) && + ( + (!si->ps.secondary_head) || + ((1024 + (row_bytes * (target->virtual_height+1) * 2)) > (si->ps.memory_size * 1024 * 1024)) || /*note: extra line for maven vblank!*/ + (target->space == B_CMAP8) || + (target->space == B_RGB15_LITTLE) || + (target->timing.pixel_clock > (max_vclk * 1000)) + ) + ) + { + target->flags&=~DUALHEAD_CAPABLE; + } + + /*set tv capable suitable*/ + if (target->flags&DUALHEAD_CAPABLE) + { + if ((target->timing.pixel_clock <= 120000 ) && (target->timing.pixel_clock >= 40000)) + { + target->flags|=TV_CAPABLE; + } + } + + return result; +} + +/* 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) { + return si->mode_count; +} + +/* Copy the list of guaranteed supported video modes to the location provided.*/ +status_t GET_MODE_LIST(display_mode *dm) { + 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("G400 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 */ + 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 for single head (propose will return if capable)*/ + *dst = *src; + /* poke the specific space*/ + dst->space = low.space = high.space = spaces[j]; + dst->flags |= DUALHEAD_CAPABLE; + + dst->flags |= B_SUPPORTS_OVERLAYS; + //fixme: we need to distinquish somehow between head 1 and head 2, as overlay only works on head 1... + + /* ask for a compatible mode */ + if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) { + /* 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/matrox/SetDisplayMode.c b/src/add-ons/accelerants/matrox/SetDisplayMode.c new file mode 100644 index 0000000000..553317f6c9 --- /dev/null +++ b/src/add-ons/accelerants/matrox/SetDisplayMode.c @@ -0,0 +1,577 @@ +/* + 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 10/2002 +*/ + +#define MODULE_BIT 0x00200000 + +#include "acc_std.h" + +#include "matroxfb_maven_hack.h" //a port of the matroxfb code to do TVout - used with permission + +/* + Enable/Disable interrupts. Just a wrapper around the + ioctl() to the kernel driver. +*/ +static void interrupt_enable(bool flag) { + status_t result; + gx00_set_bool_state sbs; + + /* set the magic number so the driver knows we're for real */ + sbs.magic = GX00_PRIVATE_DATA_MAGIC; + sbs.do_it = flag; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, GX00_RUN_INTERRUPTS, &sbs, sizeof(sbs)); +} + +// apsed TODO gx00_crtc_mem_priority() ?? +// /*calculate if high priority request are needed and how many*/ +// Tpix = 1000000.0/(dm->timing.pixel_clock); +// Tmclk = si->ps.mem_clk_period; +// temp = (128/colour_depth); +// HIPRILVL = 64*Tmclk + (1-46*(temp))*Tpix; +// HIPRILVL/= -8*Tpix*temp; +// gx00_crtc_mem_priority((uint8)HIPRILVL); +// /*XXX - memory priority*/ + +/* 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) +{ + display_mode bounds, target; + + uint8 colour_depth=32; + status_t result; + uint32 startadd,startadd_right; +// double HIPRILVL; +// double Tmclk,Tpix,temp; +// apsed TODO startadd is 19 bits if < g200 + + uint8 display,h,v; + + struct my_timming tv_timing; + struct mavenregs tv_regs; + + bool switched_crtcs = false; + + /* Adjust mode to valid one and fail if invalid */ + target = bounds = *mode_to_set; + /* show the mode bits */ + LOG(1, ("SetDisplayMode - initial flags: %x\n", target.flags)); + LOG(1, ("SetDisplayMode - %20s %08x %d\n", "timing.pixel_clock", mode_to_set->timing.pixel_clock, mode_to_set->timing.pixel_clock)); + LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_width", mode_to_set->virtual_width, mode_to_set->virtual_width)); + LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_height", mode_to_set->virtual_height, mode_to_set->virtual_height)); + + if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR) + return B_ERROR; + + /* if not dualhead capable be sure mode is set to single head */ + if ((!si->ps.secondary_head) || (!(target.flags&DUALHEAD_CAPABLE))) + { + target.flags&=~DUALHEAD_BITS; + target.flags&=~TV_BITS; + } + else if (!(target.flags&TV_CAPABLE)) + { + target.flags&=~TV_BITS; + } + + LOG(1, ("SetDisplayMode - validated flags: %x\n", target.flags)); + + /* disable interrupts using the kernel driver */ + interrupt_enable(false); + + /*find current DPMS state, then turn off screen*/ + gx00_crtc_dpms_fetch(&display,&h,&v); + gx00_crtc_dpms(0,0,0); + if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken + g400_crtc2_dpms(0,0,0); + if (si->ps.secondary_head) + gx00_maven_dpms(0,0,0); + + /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ + startadd=(si->fbc.frame_buffer)-(si->framebuffer); + + /*Perform the very long mode switch!*/ + LOG(1,("DUALHEAD: %d\n",target.flags&DUALHEAD_BITS)); + if ((target.flags&DUALHEAD_BITS)) /*if some dualhead mode*/ + { + + /*set the pixel clock PLL(s)*/ + if (gx00_dac_set_pix_pll(target)==B_ERROR) + LOG(8,("SET: error setting pixel clock (internal DAC)\n")); + if (si->ps.secondary_head) + { + if (gx00_maven_set_pix_pll((target.timing.pixel_clock)/1000.0)==B_ERROR) + LOG(8,("SET: error setting pixel clock (MAVEN)\n")); + } + else + { + LOG(8,("SET: not setting maven clock (G450?)\n")); + } + + /*set the colour depth for CRTC1, CRTC2 and the DAC*/ + switch(target.space) + { + case B_RGB16_LITTLE: + colour_depth=16; + gx00_dac_mode(BPP16,1.0); + gx00_crtc_depth(BPP16); + g400_crtc2_depth(BPP16); + break; + case B_RGB32_LITTLE: + colour_depth=32; + gx00_dac_mode(BPP32,1.0); + gx00_crtc_depth(BPP32); + g400_crtc2_depth(BPP32DIR); + break; + default: + LOG(8,("SET: Invalid dualhead colour depth 0x%08x - should never happen!\n", target.space)); + } + + /*set the display(s) pitches*/ + gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); + g400_crtc2_set_display_pitch (target.virtual_width, colour_depth); + + /*work out where the "right" screen starts*/ + startadd_right=startadd+(target.timing.h_display*(colour_depth>>3)); + + /*set the output DAC*/ + switch (si->ps.card_type) + { + case G450: + gx00_general_dac_select(DS_CRTCDAC_CRTC2DAC2); + switched_crtcs = false; + break; + case G400:case G400MAX: + gx00_general_dac_select(DS_CRTCMAVEN_CRTC2DAC); + switched_crtcs = false; + break; + default: + break; + } + + if (switched_crtcs) + { + int temp = startadd; + startadd = startadd_right; + startadd_right = temp; + } + + /*Tell card what memory to display*/ + si->crtc_delay=17+4*(colour_depth==16); + switch (target.flags&DUALHEAD_BITS) + { + case DUALHEAD_ON: + gx00_crtc_set_display_start(startadd_right,colour_depth); + g400_crtc2_set_display_start(startadd,colour_depth); + break; + case DUALHEAD_CLONE: + gx00_crtc_set_display_start(startadd,colour_depth); + g400_crtc2_set_display_start(startadd,colour_depth); + break; + case DUALHEAD_SWITCH: + gx00_crtc_set_display_start(startadd,colour_depth); + g400_crtc2_set_display_start(startadd_right,colour_depth); + break; + } + + /*set the timing*/ + result = gx00_crtc_set_timing /*crtc1*/ + ( + target.timing.h_display, + target.timing.h_sync_start, + target.timing.h_sync_end, + target.timing.h_total, + (target.timing.v_display+1), /*extra "blanking" line for MAVEN*/ + target.timing.v_sync_start, + target.timing.v_sync_end, + target.timing.v_total, + target.timing.flags&B_POSITIVE_HSYNC, + target.timing.flags&B_POSITIVE_VSYNC + ); + + result = g400_crtc2_set_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, + target.timing.flags&B_POSITIVE_HSYNC, + target.timing.flags&B_POSITIVE_VSYNC + ); + if (si->ps.secondary_head) + { + result = gx00_maven_set_timing /*maven*/ + ( + target.timing.h_display, + target.timing.h_sync_start, + target.timing.h_sync_end, + target.timing.h_total, + (target.timing.v_display+1), /*extra "blanking" line*/ + target.timing.v_sync_start, + target.timing.v_sync_end, + target.timing.v_total, + target.timing.flags&B_POSITIVE_HSYNC, + target.timing.flags&B_POSITIVE_VSYNC + ); + } + + /*turn screen one on and screen two on*/ + gx00_crtc_dpms(display,h,v); + g400_crtc2_dpms(display,h,v); + if (si->ps.secondary_head) + gx00_maven_dpms(display,h,v); + + /*TVout support*/ + if (si->ps.secondary_tvout && (target.flags&TV_BITS)) + { + si->crtc_delay+=5; + + /*create a my tim(m)ing structure... for tvout*/ + tv_timing.pixclock = target.timing.pixel_clock; + tv_timing.HDisplay = target.timing.h_display; + tv_timing.HSyncStart = target.timing.h_sync_start; + tv_timing.HSyncEnd = target.timing.h_sync_end; + tv_timing.HTotal = target.timing.h_total; + tv_timing.VDisplay = target.timing.v_display; + tv_timing.VSyncStart = target.timing.v_sync_start; + tv_timing.VSyncEnd = target.timing.v_sync_end; + tv_timing.VTotal = target.timing.v_total; + tv_timing.delay=si->crtc_delay; + + if (target.flags&TV_PAL) + { + LOG(2, ("OUTMODE: PAL\n")); + maven_set_mode(2); + } + else + { + LOG(2, ("OUTMODE: NTSC\n")); + maven_set_mode(1); + } + + maven_out_compute(&tv_timing, &tv_regs); + maven_out_program(&tv_regs); + maven_out_start(); + } + } + else /*single head mode*/ + { + status_t status; + int colour_mode = BPP32; + + switch(target.space) + { + case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break; + case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break; + case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break; + case B_RGB32_LITTLE: colour_depth = 32; colour_mode = BPP32; break; + default: + LOG(8,("SET: Invalid singlehead colour depth 0x%08x\n", target.space)); + return B_ERROR; + } + + /*set the pixel clock PLL*/ + if (si->ps.card_type >= G100) + status = gx00_dac_set_pix_pll(target); + else status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth); + if (status==B_ERROR) + LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); + + /*set the colour depth for CRTC1 and the DAC*/ + if (si->ps.card_type >= G100) gx00_dac_mode(colour_mode,1.0); + else mil2_dac_mode(colour_mode,1.0, + target.timing.flags&B_POSITIVE_HSYNC, + target.timing.flags&B_POSITIVE_VSYNC, + target.timing.flags&B_SYNC_ON_GREEN); + + gx00_crtc_depth(colour_mode); + + /*set the display pitch*/ + gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); + + /*tell the card what memory to display*/ + gx00_crtc_set_display_start(startadd,colour_depth); + if (si->ps.card_type >= G100) + gx00_general_dac_select(DS_CRTCDAC_CRTC2MAVEN); + + /*set the timing*/ + result = gx00_crtc_set_timing /*crtc1*/ + ( + 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, + target.timing.flags&B_POSITIVE_HSYNC, + target.timing.flags&B_POSITIVE_VSYNC + ); + + /*turn screen one on and screen two off*/ + gx00_crtc_dpms(display,h,v); + if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken + g400_crtc2_dpms(0,0,0); + if (si->ps.secondary_head) + gx00_maven_dpms(0,0,0); + } + + /*update driver's mode store*/ + si->dm=target; + si->fbc.bytes_per_row=target.virtual_width*(colour_depth>>3); + + /*set up acceleration for this mode*/ + si->dm.virtual_height+=1;//for clipping! + gx00_acc_init(); + si->dm.virtual_height-=1; + + /*clear line at bottom of screen (For maven) if dualhead mode*/ + gx00_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0); + + MSG(("INIT_ACCELERANT: booted since %f ms\n", system_time()/1000.0)); + + /* enable interrupts using the kernel driver */ + interrupt_enable(true); + + /* Tune RAM CAS-latency if needed. Must be done *here*! */ + mga_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)); + + /* G400 CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit + G400 CRTC2 handles multiples of 32 for 16-bit and 16 for 32-bit - must stoop to this in dualhead + */ + + /* reset lower bits, don't return an error! */ + if (si->dm.flags&DUALHEAD_BITS) + { + switch(si->dm.space) + { + case B_RGB16_LITTLE: + colour_depth=16; + h_display_start &= ~0x1f; + break; + case B_RGB32_LITTLE: + colour_depth=32; + h_display_start &= ~0x0f; + break; + default: + LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space)); + return B_ERROR; + } + } + else + { + switch(si->dm.space) + { + case B_CMAP8: + colour_depth=8; + h_display_start &= ~0x07; + break; + case B_RGB15_LITTLE: case B_RGB16_LITTLE: + colour_depth=16; + h_display_start &= ~0x03; + break; + case B_RGB32_LITTLE: + colour_depth=32; + h_display_start &= ~0x01; + break; + default: + return B_ERROR; + } + } + + /* do not run past end of display */ + if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) + return B_ERROR; + 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 */ + startadd=v_display_start*(si->dm.virtual_width*colour_depth)>>3; + startadd+=h_display_start; + startadd+=(si->fbc.frame_buffer)-(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: + gx00_crtc_set_display_start(startadd,colour_depth); + g400_crtc2_set_display_start(startadd_right,colour_depth); + break; + case DUALHEAD_OFF: + gx00_crtc_set_display_start(startadd,colour_depth); + break; + case DUALHEAD_CLONE: + gx00_crtc_set_display_start(startadd,colour_depth); + g400_crtc2_set_display_start(startadd,colour_depth); + break; + case DUALHEAD_SWITCH: + g400_crtc2_set_display_start(startadd,colour_depth); + gx00_crtc_set_display_start(startadd_right,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++; + } + if (si->ps.card_type >= G100) gx00_dac_palette(r,g,b); + else mil2_dac_palette(r,g,b); +} + + +/* masks for DPMS control bits */ +enum { + H_SYNC_OFF = 0x01, + V_SYNC_OFF = 0x02, + DISPLAY_OFF = 0x04, + BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF +}; + +/* + Put the display into one of the Display Power Management modes. +*/ +status_t SET_DPMS_MODE(uint32 dpms_flags) { + interrupt_enable(false); + + LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags)); + + if (si->dm.flags&DUALHEAD_BITS) /*dualhead*/ + { + switch(dpms_flags) + { + case B_DPMS_ON: /* H: on, V: on */ + gx00_crtc_dpms(1,1,1); + g400_crtc2_dpms(1,1,1); + if (si->ps.secondary_head) + gx00_maven_dpms(1,1,1); + break; + case B_DPMS_STAND_BY: + gx00_crtc_dpms(0,0,1); + g400_crtc2_dpms(0,0,1); + if (si->ps.secondary_head) + gx00_maven_dpms(0,0,1); + break; + case B_DPMS_SUSPEND: + gx00_crtc_dpms(0,1,0); + g400_crtc2_dpms(0,1,0); + if (si->ps.secondary_head) + gx00_maven_dpms(0,1,0); + break; + case B_DPMS_OFF: /* H: off, V: off, display off */ + gx00_crtc_dpms(0,0,0); + g400_crtc2_dpms(0,0,0); + if (si->ps.secondary_head) + gx00_maven_dpms(0,0,0); + break; + default: + LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); + interrupt_enable(true); + return B_ERROR; + } + } + else /*singlehead*/ + { + switch(dpms_flags) + { + case B_DPMS_ON: /* H: on, V: on */ + gx00_crtc_dpms(1,1,1); + break; + case B_DPMS_STAND_BY: + gx00_crtc_dpms(0,0,1); + break; + case B_DPMS_SUSPEND: + gx00_crtc_dpms(0,1,0); + break; + case B_DPMS_OFF: /* H: off, V: off, display off */ + gx00_crtc_dpms(0,0,0); + 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) { + uint8 display,h,v; + + interrupt_enable(false); + gx00_crtc_dpms_fetch(&display,&h,&v); + interrupt_enable(true); + + if (display&h&v) + return B_DPMS_ON; + else if(v) + return B_DPMS_STAND_BY; + else if(h) + return B_DPMS_SUSPEND; + else + return B_DPMS_OFF; +} diff --git a/src/add-ons/accelerants/matrox/acc_std.h b/src/add-ons/accelerants/matrox/acc_std.h new file mode 100644 index 0000000000..d6718968cf --- /dev/null +++ b/src/add-ons/accelerants/matrox/acc_std.h @@ -0,0 +1,17 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#if !defined(GLOBALDATA_H) +#define GLOBALDATA_H + +#include +#include +#include "DriverInterface.h" +#include "global.h" +//apsed #include "mga_extern.h" +#include "mga_proto.h" +#include "be_driver_proto.h" + +#endif diff --git a/src/add-ons/accelerants/matrox/be_driver_proto.h b/src/add-ons/accelerants/matrox/be_driver_proto.h new file mode 100644 index 0000000000..c3dc1b9c2c --- /dev/null +++ b/src/add-ons/accelerants/matrox/be_driver_proto.h @@ -0,0 +1,66 @@ +/* + 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 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); + +#endif diff --git a/src/add-ons/accelerants/matrox/engine/Jamfile b/src/add-ons/accelerants/matrox/engine/Jamfile new file mode 100644 index 0000000000..1380162af2 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/Jamfile @@ -0,0 +1,20 @@ +SubDir OBOS_TOP src add-ons accelerants matrox engine ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics matrox ] ; +UseHeaders [ FDirName $(SUBDIR) .. ] ; + +StaticLibrary matrox_engine : + matroxfb_maven_hack.c + mga_acc.c + mga_bes.c + mga_crtc.c + mga_crtc2.c + mga_dac.c + mga_general.c + mga_i2c.c + mga_info.c + mga_maven.c + mga_support.c + tvp3026.c + ; diff --git a/src/add-ons/accelerants/matrox/engine/LICENSE b/src/add-ons/accelerants/matrox/engine/LICENSE new file mode 100644 index 0000000000..9def45195d --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/LICENSE @@ -0,0 +1,9 @@ +The files in this directory (and any other files beginning with "mga_") are independent from Be's sample code + +Basically, freely copy them, edit them etc. Just do not claim you wrote them. + +Will think of something more official to put here later:) + +Mark Watson + +Notes: This excludes the maven_hack port of matroxfb's maven stuff - see notes in that file for info. diff --git a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c new file mode 100644 index 0000000000..081d0d0f86 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c @@ -0,0 +1,879 @@ +#define MODULE_BIT 0x00100000 + +#include "mga_std.h" +#include "matroxfb_maven_hack.h" + +#define MODE_PAL 1 +#define MODE_NTSC 2 +#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC)) +#define MODE_MONITOR 128 + +static int mode = MODE_PAL; + +static const struct matrox_pll_features maven_pll = { + 50000, + 27000, + 4, 127, + 2, 31, + 3 +}; + +static const struct matrox_pll_features2 maven1000_pll = { + 50000000, + 300000000, + 5, 128, + 3, 32, + 3 +}; + +static const struct matrox_pll_ctl maven_PAL = { + 540000, + 50 +}; + +static const struct matrox_pll_ctl maven_NTSC = { + 450450, /* 27027000/60 == 27000000/59.94005994 */ + 60 +}; + + +int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int bestdiff = ~0; + unsigned int bestvco = 0; + unsigned int fxtal = pll->ref_freq; + unsigned int fwant; + unsigned int p; + + LOG(4,("PLL_calcclock")); + + fwant = freq; + + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; + if (fwant > fmax) fwant = fmax; + for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { + unsigned int m; + + if (fwant < pll->vco_freq_min) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int diff, fvco; + unsigned int n; + + n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; + if (n > pll->feed_div_max) + break; + if (n < pll->feed_div_min) + n = pll->feed_div_min; + fvco = (fxtal * (n + 1)) / (m + 1); + if (fvco < fwant) + diff = fwant - fvco; + else + diff = fvco - fwant; + if (diff < bestdiff) { + bestdiff = diff; + *post = p; + *in = m; + *feed = n; + bestvco = fvco; + } + } + } + LOG(4,("clk: %x %x %x %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant)); + return bestvco; +} + +int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, + const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* h2) { + unsigned int besth2 = 0; + unsigned int fxtal = ctl->ref_freq; + unsigned int fmin = pll->vco_freq_min / ctl->den; + unsigned int fwant; + unsigned int p; + unsigned int scrlen; + unsigned int fmax; + + LOG(4,("PLL_calcclock")); + + scrlen = htotal * (vtotal - 1); + fwant = htotal * vtotal; + fmax = pll->vco_freq_max / ctl->den; + + LOG(2, ("FVMAB:want: %x, xtal: %x, h: %x, v: %x, fmax: %x\n", + fwant, fxtal, htotal, vtotal, fmax)); + for (p = 1; p <= pll->post_shift_max; p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant > fmax) + return 0; + for (; p-- > 0; fwant >>= 1) { + unsigned int m; + + if (fwant < fmin) break; + for (m = pll->in_div_min; m <= pll->in_div_max; m++) { + unsigned int n; + unsigned int dvd; + unsigned int ln; + + n = (fwant * m) / fxtal; + if (n < pll->feed_div_min) + continue; + if (n > pll->feed_div_max) + break; + + ln = fxtal * n; + dvd = m << p; + + if (ln % dvd) + continue; + ln = ln / dvd; + + if (ln < scrlen + 2) + continue; + ln = ln - scrlen; + if (ln > htotal) + continue; + LOG(2,("FBMAV:Match: %x / %x / %x / %x\n", n, m, p, ln)); + if (ln > besth2) { + LOG(2, ("FBMAV:Better...\n")); + *h2 = besth2 = ln; + *post = p; + *in = m; + *feed = n; + } + } + } + if (besth2 < 2) + return 0; + LOG(4,("FBMAV:clk: %x %x %x %d %d\n", *in, *feed, *post, fxtal, fwant)); + return fxtal * (*feed) / (*in) * ctl->den; +} + +unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* htotal2) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); + if (!fvco) + return -EINVAL; + p = (1 << p) - 1; + if (fvco <= 100000000) + ; + else if (fvco <= 140000000) + p |= 0x08; + else if (fvco <= 180000000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return 0; +} + +void DAC1064_calcclock(unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; + return; +} + +void maven_init_TVdata +( + struct mavenregs* data +) +{ + static struct mavenregs palregs = { { + 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x44, /* 09 */ + 0x9C, /* 0A */ + 0x2E, /* 0B */ + 0x21, /* 0C */ + 0x00, /* ? not written */ + 0x3F, 0x03, /* 0E-0F */ + 0x3F, 0x03, /* 10-11 */ + 0x1A, /* 12 */ + 0x2A, /* 13 */ + 0x1C, 0x3D, 0x14, /* 14-16 */ + 0x9C, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0xFE, /* 1A */ + 0x7E, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x03, /* 1E-1F */ + 0x72, /* 20 */ + 0x07, /* 21 */ + 0x72, /* 22 */ + 0x00, /* 23 */ + 0x00, /* 24 */ + 0x00, /* 25 */ + 0x08, /* 26 */ + 0x04, /* 27 */ + 0x00, /* 28 */ + 0x1A, /* 29 */ + 0x55, 0x01, /* 2A-2B */ + 0x26, /* 2C */ + 0x07, 0x7E, /* 2D-2E */ + 0x02, 0x54, /* 2F-30 */ + 0xB0, 0x00, /* 31-32 */ + 0x14, /* 33 */ + 0x49, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x22, /* 39 */ + 0x02, /* 3A */ + 0x22, /* 3B */ + 0x3F, 0x03, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* 3F not written */ + }, MODE_PAL, 625, 50 }; + static struct mavenregs ntscregs = { { + 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ + 0x00, + 0x00, /* ? not written */ + 0x00, /* modified by code (F9 written...) */ + 0x00, /* ? not written */ + 0x7E, /* 08 */ + 0x43, /* 09 */ + 0x7E, /* 0A */ + 0x3D, /* 0B */ + 0x00, /* 0C */ + 0x00, /* ? not written */ + 0x41, 0x00, /* 0E-0F */ + 0x3C, 0x00, /* 10-11 */ + 0x17, /* 12 */ + 0x21, /* 13 */ + 0x1B, 0x1B, 0x24, /* 14-16 */ + 0x83, 0x01, /* 17-18 */ + 0x00, /* 19 */ + 0x0F, /* 1A */ + 0x0F, /* 1B */ + 0x60, /* 1C */ + 0x05, /* 1D */ + 0x89, 0x02, /* 1E-1F */ + 0x5F, /* 20 */ + 0x04, /* 21 */ + 0x5F, /* 22 */ + 0x01, /* 23 */ + 0x02, /* 24 */ + 0x00, /* 25 */ + 0x0A, /* 26 */ + 0x05, /* 27 */ + 0x00, /* 28 */ + 0x10, /* 29 */ + 0xFF, 0x03, /* 2A-2B */ + 0x24, /* 2C */ + 0x0F, 0x78, /* 2D-2E */ + 0x00, 0x00, /* 2F-30 */ + 0xB2, 0x04, /* 31-32 */ + 0x14, /* 33 */ + 0x02, /* 34 */ + 0x00, /* 35 written multiple times */ + 0x00, /* 36 not written */ + 0xA3, /* 37 */ + 0xC8, /* 38 */ + 0x15, /* 39 */ + 0x05, /* 3A */ + 0x3B, /* 3B */ + 0x3C, 0x00, /* 3C-3D */ + 0x00, /* 3E written multiple times */ + 0x00, /* never written */ + }, MODE_NTSC, 525, 60 }; + + if (mode & MODE_PAL) + *data = palregs; + else + *data = ntscregs; + + data->regs[0x93] = 0xA2; + + /* gamma correction registers */ + data->regs[0x83] = 0x00; + data->regs[0x84] = 0x00; + data->regs[0x85] = 0x00; + data->regs[0x86] = 0x1F; + data->regs[0x87] = 0x10; + data->regs[0x88] = 0x10; + data->regs[0x89] = 0x10; + data->regs[0x8A] = 0x64; /* 100 */ + data->regs[0x8B] = 0xC8; /* 200 */ + + return; +} + +#define LR(x) i2c_maven_write((x), m->regs[(x)]) +#define LRP(x) MAVWWP((x), (m->regs[(x)]|m->regs[(x+1)]<<8)) +void maven_init_TV +( + const struct mavenregs* m +) +{ + int val; + + + i2c_maven_write( 0x3E, 0x01); + i2c_maven_read( 0x82); /* fetch oscillator state? */ + i2c_maven_write( 0x8C, 0x00); + i2c_maven_read( 0x94); /* get 0x82 */ + i2c_maven_write( 0x94, 0xA2); + /* xmiscctrl */ + + MAVWWP(0x8E, 0x1EFF); + i2c_maven_write( 0xC6, 0x01); + + /* removed code... */ + + i2c_maven_read( 0x06); + i2c_maven_write( 0x06, 0xF9); /* or read |= 0xF0 ? */ + + /* removed code here... */ + + /* real code begins here? */ + /* chroma subcarrier */ + LR(0x00); LR(0x01); LR(0x02); LR(0x03); + + LR(0x04); + + LR(0x2C); + LR(0x08); + LR(0x0A); + LR(0x09); + LR(0x29); + LRP(0x31); + LRP(0x17); + LR(0x0B); + LR(0x0C); + if (m->mode & MODE_PAL) { + i2c_maven_write( 0x35, 0x10); /* ... */ + } else { + i2c_maven_write( 0x35, 0x0F); /* ... */ + } + + LRP(0x10); + + LRP(0x0E); + LRP(0x1E); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x25); /* hue */ + LR(0x34); + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode & MODE_PAL) + i2c_maven_write( 0x35, 0x1D); /* ... */ + else + i2c_maven_write( 0x35, 0x1C); + + LRP(0x3C); + LR(0x37); + LR(0x38); + i2c_maven_write( 0xB3, 0x01); + + i2c_maven_read( 0xB0); /* read 0x80 */ + i2c_maven_write( 0xB0, 0x08); /* ugh... */ + i2c_maven_read( 0xB9); /* read 0x7C */ + i2c_maven_write( 0xB9, 0x78); + i2c_maven_read( 0xBF); /* read 0x00 */ + i2c_maven_write( 0xBF, 0x02); + i2c_maven_read( 0x94); /* read 0x82 */ + i2c_maven_write( 0x94, 0xB3); + + LR(0x80); /* 04 1A 91 or 05 21 91 */ + LR(0x81); + LR(0x82); + + i2c_maven_write( 0x8C, 0x20); + i2c_maven_read( 0x8D); + i2c_maven_write( 0x8D, 0x10); + + LR(0x90); /* 4D 50 52 or 4E 05 45 */ + LR(0x91); + LR(0x92); + + LRP(0x9A); /* 0049 or 004F */ + LRP(0x9C); /* 0004 or 0004 */ + LRP(0x9E); /* 0458 or 045E */ + LRP(0xA0); /* 05DA or 051B */ + LRP(0xA2); /* 00CC or 00CF */ + LRP(0xA4); /* 007D or 007F */ + LRP(0xA6); /* 007C or 007E */ + LRP(0xA8); /* 03CB or 03CE */ + LRP(0x98); /* 0000 or 0000 */ + LRP(0xAE); /* 0044 or 003A */ + LRP(0x96); /* 05DA or 051B */ + LRP(0xAA); /* 04BC or 046A */ + LRP(0xAC); /* 004D or 004E */ + + LR(0xBE); + LR(0xC2); + + i2c_maven_read( 0x8D); + i2c_maven_write( 0x8D, 0x00); + + LR(0x20); /* saturation #1 */ + LR(0x22); /* saturation #2 */ + LR(0x93); /* whoops */ + LR(0x20); /* oh, saturation #1 again */ + LR(0x22); /* oh, saturation #2 again */ + LR(0x25); /* hue */ + LRP(0x0E); + LRP(0x1E); + LRP(0x0E); /* problems with memory? */ + LRP(0x1E); /* yes, matrox must have problems in memory area... */ + + /* load gamma correction stuff */ + LR(0x83); + LR(0x84); + LR(0x85); + LR(0x86); + LR(0x87); + LR(0x88); + LR(0x89); + LR(0x8A); + LR(0x8B); + + val = i2c_maven_read( 0x8D); + val &= 0x10; /* 0x10 or anything ored with it */ + i2c_maven_write( 0x8D, val); + + LR(0x33); + LR(0x19); + LR(0x12); + LR(0x3B); + LR(0x13); + LR(0x39); + LR(0x1D); + LR(0x3A); + LR(0x24); + LR(0x14); + LR(0x15); + LR(0x16); + LRP(0x2D); + LRP(0x2F); + LR(0x1A); + LR(0x1B); + LR(0x1C); + LR(0x23); + LR(0x26); + LR(0x28); + LR(0x27); + LR(0x21); + LRP(0x2A); + if (m->mode & MODE_PAL) + i2c_maven_write( 0x35, 0x1D); + else + i2c_maven_write( 0x35, 0x1C); + LRP(0x3C); + LR(0x37); + LR(0x38); + + i2c_maven_read( 0xB0); + LR(0xB0); /* output mode */ + LR(0x90); + LR(0xBE); + LR(0xC2); + + LRP(0x9A); + LRP(0xA2); + LRP(0x9E); + LRP(0xA6); + LRP(0xAA); + LRP(0xAC); + i2c_maven_write( 0x3E, 0x00); + i2c_maven_write( 0x95, 0x20); +} + +int maven_find_exact_clocks(unsigned int ht, unsigned int vt, + struct mavenregs* m) { + unsigned int x; + unsigned int err = ~0; + + /* 1:1 */ + m->regs[0x80] = 0x0F; + m->regs[0x81] = 0x07; + m->regs[0x82] = 0x81; + + for (x = 0; x < 8; x++) { + unsigned int a, b, c, h2; + unsigned int h = ht + 2 + x; + + if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { + unsigned int diff = h - h2; + + if (diff < err) { + err = diff; + m->regs[0x80] = a - 1; + m->regs[0x81] = b - 1; + m->regs[0x82] = c | 0x80; + m->hcorr = h2 - 2; + m->htotal = h - 2; + } + } + } + return err != ~0U; +} + +//called from main access points... +inline int maven_compute_timing +( + struct my_timming* mt, + struct mavenregs* m +) +{ + unsigned int tmpi; + unsigned int a, bv, c; + + m->mode = mode; + if (MODE_TV(mode)) { + unsigned int lmargin; + unsigned int umargin; + unsigned int vslen; + unsigned int hcrt; + unsigned int slen; + + maven_init_TVdata(m); + + if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) + return -EINVAL; + + lmargin = mt->HTotal - mt->HSyncEnd; + slen = mt->HSyncEnd - mt->HSyncStart; + hcrt = mt->HTotal - slen - mt->delay; + umargin = mt->VTotal - mt->VSyncEnd; + vslen = mt->VSyncEnd - mt->VSyncStart; + + if (m->hcorr < mt->HTotal) + hcrt += m->hcorr; + if (hcrt > mt->HTotal) + hcrt -= mt->HTotal; + if (hcrt + 2 > mt->HTotal) + hcrt = 0; /* or issue warning? */ + + /* last (first? middle?) line in picture can have different length */ + /* hlen - 2 */ + m->regs[0x96] = m->hcorr; + m->regs[0x97] = m->hcorr >> 8; + /* ... */ + m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; + /* hblanking end */ + m->regs[0x9A] = lmargin; /* 100% */ + m->regs[0x9B] = lmargin >> 8; /* 100% */ + /* who knows */ + m->regs[0x9C] = 0x04; + m->regs[0x9D] = 0x00; + /* htotal - 2 */ + m->regs[0xA0] = m->htotal; + m->regs[0xA1] = m->htotal >> 8; + /* vblanking end */ + m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ + m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; + /* something end... [A6]+1..[A8] */ + m->regs[0xA4] = 0x01; + m->regs[0xA5] = 0x00; + /* something start... 0..[A4]-1 */ + m->regs[0xA6] = 0x00; + m->regs[0xA7] = 0x00; + /* vertical line count - 1 */ + m->regs[0xA8] = mt->VTotal - 1; + m->regs[0xA9] = (mt->VTotal - 1) >> 8; + /* horizontal vidrst pos */ + m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ + m->regs[0xAB] = hcrt >> 8; + /* vertical vidrst pos */ + m->regs[0xAC] = mt->VTotal - 2; + m->regs[0xAD] = (mt->VTotal - 2) >> 8; + /* moves picture up/down and so on... */ + m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ + m->regs[0xAF] = 0x00; + { + int hdec; + int hlen; + unsigned int ibmin = 4 + lmargin + mt->HDisplay; + unsigned int ib; + int i; + + /* Verify! */ + /* Where 94208 came from? */ + if (mt->HTotal) + hdec = 94208 / (mt->HTotal); + else + hdec = 0x81; + if (hdec > 0x81) + hdec = 0x81; + if (hdec < 0x41) + hdec = 0x41; + hdec--; + hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); + if (hlen < 0) + hlen = 0; + hlen = hlen >> 8; + if (hlen > 0xFF) + hlen = 0xFF; + /* Now we have to compute input buffer length. + If you want any picture, it must be between + 4 + lmargin + xres + and + 94208 / hdec + If you want perfect picture even on the top + of screen, it must be also + 0x3C0000 * i / hdec + Q - R / hdec + where + R Qmin Qmax + 0x07000 0x5AE 0x5BF + 0x08000 0x5CF 0x5FF + 0x0C000 0x653 0x67F + 0x10000 0x6F8 0x6FF + */ + i = 1; + do { + ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; + i++; + } while (ib < ibmin); + if (ib >= m->htotal + 2) { + ib = ibmin; + } + + m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ + m->regs[0xC2] = hlen; + /* 'valid' input line length */ + m->regs[0x9E] = ib; + m->regs[0x9F] = ib >> 8; + } + { + int vdec; + int vlen; + + if (mt->VTotal) { + double f1; + uint32 a; + uint32 b; + + // Unsure of how to do 64-bit integer maths on Be, so use FPU! + a = m->vlines * (m->htotal + 2); + b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; + f1 = (double)a * (double)32768; + f1 /= (double) b; + vdec = (uint32) f1; + } else + vdec = 0x8000; + if (vdec > 0x8000) + vdec = 0x8000; + vlen = (vslen + umargin + mt->VDisplay) * vdec; + vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ + if (vlen < 0) + vlen = 0; + if (vlen > 0xFF) + vlen = 0xFF; + vdec--; + m->regs[0x91] = vdec; + m->regs[0x92] = vdec >> 8; + m->regs[0xBE] = vlen; + } + m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ + return 0; + } + + DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); + m->regs[0x80] = a; + m->regs[0x81] = bv; + m->regs[0x82] = c | 0x80; + + m->regs[0xB3] = 0x01; + m->regs[0x94] = 0xB2; + + /* htotal... */ + m->regs[0x96] = mt->HTotal; + m->regs[0x97] = mt->HTotal >> 8; + /* ?? */ + m->regs[0x98] = 0x00; + m->regs[0x99] = 0x00; + /* hsync len */ + tmpi = mt->HSyncEnd - mt->HSyncStart; + m->regs[0x9A] = tmpi; + m->regs[0x9B] = tmpi >> 8; + /* hblank end */ + tmpi = mt->HTotal - mt->HSyncStart; + m->regs[0x9C] = tmpi; + m->regs[0x9D] = tmpi >> 8; + /* hblank start */ + tmpi += mt->HDisplay; + m->regs[0x9E] = tmpi; + m->regs[0x9F] = tmpi >> 8; + /* htotal + 1 */ + tmpi = mt->HTotal + 1; + m->regs[0xA0] = tmpi; + m->regs[0xA1] = tmpi >> 8; + /* vsync?! */ + tmpi = mt->VSyncEnd - mt->VSyncStart - 1; + m->regs[0xA2] = tmpi; + m->regs[0xA3] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - mt->VSyncStart; + m->regs[0xA4] = tmpi; + m->regs[0xA5] = tmpi >> 8; + /* ignored? */ + tmpi = mt->VTotal - 1; + m->regs[0xA6] = tmpi; + m->regs[0xA7] = tmpi >> 8; + /* vtotal - 1 */ + m->regs[0xA8] = tmpi; + m->regs[0xA9] = tmpi >> 8; + /* hor vidrst */ + tmpi = mt->HTotal - mt->delay; + m->regs[0xAA] = tmpi; + m->regs[0xAB] = tmpi >> 8; + /* vert vidrst */ + tmpi = mt->VTotal - 2; + m->regs[0xAC] = tmpi; + m->regs[0xAD] = tmpi >> 8; + /* ignored? */ + m->regs[0xAE] = 0x00; + m->regs[0xAF] = 0x00; + + m->regs[0xB0] = 0x03; /* output: monitor */ + m->regs[0xB1] = 0xA0; /* ??? */ + m->regs[0x8C] = 0x20; /* must be set... */ + m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */ + m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ + m->regs[0xBF] = 0x22; /* makes picture stable */ + + return 0; +} + +inline int maven_program_timing +( + const struct mavenregs* m +) +{ + if (m->mode & MODE_MONITOR) { + LR(0x80); + LR(0x81); + LR(0x82); + + LR(0xB3); + LR(0x94); + + LRP(0x96); + LRP(0x98); + LRP(0x9A); + LRP(0x9C); + LRP(0x9E); + LRP(0xA0); + LRP(0xA2); + LRP(0xA4); + LRP(0xA6); + LRP(0xA8); + LRP(0xAA); + LRP(0xAC); + LRP(0xAE); + + LR(0xB0); /* output: monitor */ + LR(0xB1); /* ??? */ + LR(0x8C); /* must be set... */ + LR(0x8D); /* defaults to 0x10: test signal */ + LR(0xB9); /* defaults to 0x2C: too bright */ + LR(0xBF); /* makes picture stable */ + } else { + maven_init_TV(m); + } + return 0; +} + +inline int maven_resync() +{ + i2c_maven_write( 0x95, 0x20); /* start whole thing */ + return 0; +} + +/******************************************************/ + +/////////////////////////////////////////////////////////////////////////////////////// +//Main entry points... - sequence is compute, program, start +int maven_set_mode(int mod) +{ + switch (mode) + { + case MODE_NTSC: + case MODE_PAL: + case MODE_MONITOR: + mode = mod; + break; + default: + return -1; + } + return 0; +} + +int maven_out_compute(struct my_timming* mt, struct mavenregs* maven) +{ + return maven_compute_timing(mt, maven); +} + +int maven_out_program(const struct mavenregs* maven) +{ + return maven_program_timing(maven); +} + +int maven_out_start() +{ + return maven_resync(); +} + +/* ************************** */ +//Used with Petr's permission (many thanks) +//Any bugs with this code contact me (MarkWatson@bcs.org.uk) not Petr +//----------------------------------------------- +//MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec "); +//MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); diff --git a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h new file mode 100644 index 0000000000..3d1af8d445 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h @@ -0,0 +1,88 @@ +struct matrox_pll_features { + unsigned int vco_freq_min; + unsigned int ref_freq; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matrox_pll_features2 { + unsigned int vco_freq_min; + unsigned int vco_freq_max; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matrox_pll_ctl { + unsigned int ref_freq; + unsigned int den; +}; + +struct mavenregs { + uint8 regs[256]; + int mode; + int vlines; + int xtal; + int fv; + + uint16 htotal; + uint16 hcorr; +}; + +struct my_timming { + unsigned int pixclock; + unsigned int HDisplay; + unsigned int HSyncStart; + unsigned int HSyncEnd; + unsigned int HTotal; + unsigned int VDisplay; + unsigned int VSyncStart; + unsigned int VSyncEnd; + unsigned int VTotal; + unsigned int sync; + int dblscan; + int interlaced; + unsigned int delay; /* CRTC delay */ +}; + +int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, + const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* h2); + +unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, + unsigned int htotal, unsigned int vtotal, + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int* htotal2); + +void DAC1064_calcclock(unsigned int freq, unsigned int fmax, + unsigned int* in, unsigned int* feed, unsigned int* post); + +void maven_init_TVdata ( struct mavenregs* data); +void maven_init_TV ( const struct mavenregs* m); + +int maven_find_exact_clocks(unsigned int ht, unsigned int vt, + struct mavenregs* m); + +int maven_compute_timing ( struct my_timming* mt, struct mavenregs* m) ; + + +int maven_program_timing ( const struct mavenregs* m); + +int maven_resync(); + + +//MY INTERFACE +int maven_set_mode(int mode); + +int maven_out_compute(struct my_timming* mt, struct mavenregs* mr) ; + +int maven_out_program(const struct mavenregs* mr) ; + +int maven_out_start() ; diff --git a/src/add-ons/accelerants/matrox/engine/mga_acc.c b/src/add-ons/accelerants/matrox/engine/mga_acc.c new file mode 100644 index 0000000000..763c415c96 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_acc.c @@ -0,0 +1,341 @@ +/* MGA Acceleration functions */ +/* Authors: + Mark Watson 2/2000, + Rudolf Cornelissen 10/2002 +*/ + +#define MODULE_BIT 0x00080000 + +#include "mga_std.h" + +/*acceleration notes*/ + +/*functions Be needs: +fill span (horizontal only) +fill rectangle (these 2 are very similar) +invert rectangle +blit +*/ + +/* G100 pre SRCORG/DSTORG registers */ +static uint32 src_dst; + +// needed by MIL2 in 800x600 8bpp +#define ACCW_YDSTLEN(dst, len) do { \ +/* if (si->ylin) { */ \ + if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { \ + ACCW(YDST,((dst)*si->dm.virtual_width) >> 5); \ + ACCW(LEN,len); \ + } else ACCW(YDSTLEN,((dst)<<16)|(len)); \ +} while (0) + +status_t gx00_acc_wait_idle() +{ + volatile int i; + while (ACCR(STATUS)&(1<<16)) + { + for (i=0;i<10000;i++); /*spin in place so I do not hammer the bus*/ + }; + return B_OK; +} + +/*AFAIK this must be done for every new screenmode*/ +status_t gx00_acc_init() +{ + ACCW(OPMODE,0); // cleanup bitblt + + /*Set the Z origin to the start of FB (otherwise lockup on blits)*/ + if (si->ps.card_type>=G100) + ACCW(ZORG,0); + + /*MACCESS - for 2D, only pixel width is important > all others can be 0*/ + switch(si->dm.space) + { + case B_CMAP8: + ACCW(MACCESS,0); + break; + case B_RGB15_LITTLE:case B_RGB16_LITTLE: + ACCW(MACCESS,1); + break; + case B_RGB32_LITTLE:case B_RGBA32_LITTLE: + ACCW(MACCESS,2); + break; + default: + LOG(8,("ACC: init, invalid bit depth\n")); + return B_ERROR; + } + + /*PITCH*/ + // TODO apsed 3-129 32 or 64 following depth (or 128 if MIl2) + if (si->dm.virtual_width&0x1F) + { + LOG(8,("ACC: can not accelerate, pitch is not multiple of 32 pixels\n")); + return B_ERROR; + } + if (si->ps.card_type>=G200) + ACCW(PITCH,(si->dm.virtual_width)&0x1FFF); /* use hardware Y decoding */ + else + ACCW(PITCH,(si->dm.virtual_width)&0x0FFF); /* use hardware Y decoding */ + +if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { + // ylin shall be 1 if 800x600 + ACCW(PITCH, (1<<15) | (si->dm.virtual_width&0x0FFF)); +} + /*PLNWT - plane write mask*/ +// if (si->ps.card_type>=G200) // apsed: PLNWT exists also in MIL2, G100 + ACCW(PLNWT,0xFFFFFFFF); /*all planes are written*/ + + if (si->ps.card_type>=G200) { + /*DSTORG - location of active screen in framebuffer*/ + ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer)); + + /*SRCORG - init source address - same as dest*/ + ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer)); + } + + /*YDSTORG - apsed, if not inited, BitBlts may fails on g200, see YTOP/BOT after */ + /* Used for G100, included in acceleration routines also: */ + src_dst = 0; + ACCW(YDSTORG, src_dst); + + /* G100 uses this register as SRCORG/DSTORG replacement */ + if ((si->ps.card_type == G100) && (si->settings.hardcursor)) + { + switch (si->dm.space) + { + case B_CMAP8: + src_dst = 1024 / 1; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + src_dst = 1024 / 2; + break; + case B_RGB32_LITTLE: + src_dst = 1024 / 4; + break; + default: + LOG(8,("ACC: G100 hardcursor not supported for current colorspace\n")); + return B_ERROR; + } + } + ACCW(YDSTORG,src_dst); + + /*clipping*/ + ACCW(CXBNDRY,((si->dm.virtual_width -1)<<16)|(0)); /*i.e. highest and lowest right pixel value*/ + + // apsed TODO g200 shall be YDSTORG + value + // apsed TODO why -1, must be a multiple of 32 since MIl2 + ACCW(YTOP,0); + ACCW(YBOT,(si->dm.virtual_height*si->dm.virtual_width)-1); /*y address must be linear*/ + + return B_OK; +} + +/*screen to screen blit - i.e. move windows around*/ +status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h) +{ + uint32 t_start,t_end,offset; + uint32 b_start,b_end; + + /*find where the top,bottom and offset are*/ + offset = si->dm.virtual_width; + + t_end = t_start = xs + (offset*ys) + src_dst; + t_end += w; + + b_end = b_start = xs + (offset*(ys+h)) + src_dst; + b_end +=w; + + /*find which quadrant */ + switch((yd>ys)|((xd>xs)<<1)) + { + case 0: /*L->R,down*/ + ACCW(SGN,0); + + ACCW(AR3,t_start); + ACCW(AR0,t_end); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 1: /*L->R,up*/ + ACCW(SGN,4); + + ACCW(AR3,b_start); + ACCW(AR0,b_end); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + case 2: /*R->L,down*/ + ACCW(SGN,1); + + ACCW(AR3,t_end); + ACCW(AR0,t_start); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 3: /*R->L,up*/ + ACCW(SGN,5); + + ACCW(AR3,b_end); + ACCW(AR0,b_start); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + } + ACCW(FXBNDRY,((xd+w)<<16)|xd); + + /*do the blit*/ + ACCGO(DWGCTL,0x040C4018); + + return B_OK; +} + +/*screen to screen tranparent blit - not sure what uses this...*/ +status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour) +{ + uint32 t_start,t_end,offset; + uint32 b_start,b_end; + + return B_ERROR; + + /*find where the top,bottom and offset are*/ + offset = si->dm.virtual_width; + + t_end = t_start = xs + (offset*ys) + src_dst; + t_end += w; + + b_end = b_start = xs + (offset*(ys+h)) + src_dst; + b_end +=w; + + /*find which quadrant */ + switch((yd>ys)|((xd>xs)<<1)) + { + case 0: /*L->R,down*/ + ACCW(SGN,0); + + ACCW(AR3,t_start); + ACCW(AR0,t_end); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 1: /*L->R,up*/ + ACCW(SGN,4); + + ACCW(AR3,b_start); + ACCW(AR0,b_end); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + case 2: /*R->L,down*/ + ACCW(SGN,1); + + ACCW(AR3,t_end); + ACCW(AR0,t_start); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 3: /*R->L,up*/ + ACCW(SGN,5); + + ACCW(AR3,b_end); + ACCW(AR0,b_start); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + } + ACCW(FXBNDRY,((xd+w)<<16)|xd); + + /*do the blit*/ + ACCW(FCOL,colour); + ACCW(BCOL,0xffffffff); + ACCGO(DWGCTL,0x440C4018); + return B_OK; +} + +/*rectangle fill*/ +/*colorIndex,fill_rect_params,count*/ +status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) +{ +/* + FXBNDRY - left and right coordinates a + YDSTLEN - y start and no of lines a + (or YDST and LEN) + DWGCTL - atype must be RSTR or BLK a + FCOL - foreground colour a +*/ + + ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/ + ACCW_YDSTLEN(ys,yl); /*set y start and length*/ + ACCW(FCOL,col); /*set colour*/ + + if (si->dm.space==B_CMAP8 || si->ps.sdram) + { + ACCGO(DWGCTL,0x400C7814); // atype RSTR + } + else + { + ACCGO(DWGCTL,0x400C7844); // atype BLK + } + return B_OK; +} + +/*rectangle invert*/ +/*colorIndex,fill_rect_params,count*/ +status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) +{ +// int i; +// uint32 * dma; +// uint32 pci; +/* + FXBNDRY - left and right coordinates a + YDSTLEN - y start and no of lines a + (or YDST and LEN) + DWGCTL - atype must be RSTR or BLK a + FCOL - foreground colour a +*/ + + ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/ + ACCW_YDSTLEN(ys,yl); /*set y start and length*/ + ACCW(FCOL,col); /*set colour*/ + + ACCGO(DWGCTL,0x40057814); /*draw it! top nibble is c is clipping enabled*/ + + /*pseudo_dma version!*/ +//MGAACC_DWGCTL =0x1C00, +//MGAACC_FCOL =0x1C24, +//MGAACC_FXBNDRY =0x1C84, +//MGAACC_YDSTLEN =0x1C88, +// +//40,09,21,22 (ordered as registers) + +// dma = (uint32 *)si->pseudo_dma; +// *dma++=0x40092221; +// *dma++=(xe<<16)|xs; +// *dma++=(ys<<16)|yl; +// *dma++=col; +// *dma++=0x40057814; + + /*real dma version!*/ +// dma = (vuint32 *)si->dma_buffer; +// *dma++=0x40092221;/*indices*/ +// *dma++=(xe<<16)|xs; +// *dma++=(ys<<16)|yl; +// *dma++=col; +// *dma++=0x40057814; + +// pci = si->dma_buffer_pci; +// ACCW(PRIMADDRESS,(pci)); +// ACCW(PRIMEND,(20+pci)); + +// delay(100); + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_bes.c b/src/add-ons/accelerants/matrox/engine/mga_bes.c new file mode 100644 index 0000000000..af5405ea7d --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_bes.c @@ -0,0 +1,628 @@ +/* G200-G550 Back End Scaler functions V0.13 beta1 */ +/* Written by Rudolf Cornelissen 05/08-2002 */ + +#define MODULE_BIT 0x00000200 + +#include "mga_std.h" + +status_t gx00_configure_bes(const overlay_buffer *ob, const overlay_window *ow, int offset) +{ + /* yuy2 (4:2:2) colorspace calculations */ + /* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */ + + /* Note: + * in BeOS R5.0.3 (maybe DANO works different): + * '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. */ + + /* misc used variables */ + uint32 temp32; + uint16 temp1, temp2; + /* interval representation, used for scaling calculations */ + uint16 intrep; + /* inverse scaling factor, used for source positioning */ + uint32 ifactor; + /* used for vertical weight starting value */ + uint32 weight; + + /* Slowdown the G200-G550 BES if the pixelclock is too high for it to cope. + * This will in fact half the horizontal resolution of the BES with high + * pixelclocks (by setting a BES hardware 'zoom' = 2x). + * If you want optimal output quality better make sure you set the refreshrate/resolution + * of your monitor not too high ... */ + uint16 acczoom = 1; + LOG(4,("Overlay: pixelclock is %dkHz, ", si->dm.timing.pixel_clock)); + if (si->dm.timing.pixel_clock > BESMAXSPEED) + { + /* BES running at half speed and resolution */ + /* This is how it works (BES slowing down): + * - Activate BES internal horizontal hardware scaling = 4x (in GLOBCTL below), + * - This also sets up BES only getting half the amount of pixels per line from + * the input picture buffer (in effect half-ing the BES pixelclock input speed). + * Now in order to get the picture back to original size, we need to also double + * the inverse horizontal scaling factor here (x4 /2 /2 = 1x again). + * Note that every other pixel is now doubled or interpolated, according to another + * GLOBCTL bit. */ + acczoom = 2; + LOG(4,("slowing down BES!\n")); + } + else + { + /* BES running at full speed and resolution */ + LOG(4,("BES is running at full speed\n")); + } + + + /************************************* + *** sync to BES (Back End Scaler) *** + *************************************/ + + /* Make sure reprogramming the BES completes before the next retrace occurs, to prevent + * register-update glitches (double buffer feature). + * Programming the BES needs about 50 lines with a 1600 x 1200 x 90Hz screen with + * logging mostly disabled on a P3-500. */ + + LOG(3,("Overlay: entering at Vcount %d\n", CR1R(VCOUNT))); + while (CR1R(VCOUNT) > (si->dm.timing.v_total - 100)); + LOG(3,("Overlay: starting at Vcount %d\n", CR1R(VCOUNT))); + + /**************************************** + *** setup all edges of output window *** + ****************************************/ + + /* setup left and right edges of output window */ + temp32 = 0; + /* left edge coordinate of output window, must be inside desktop */ + /* clipping on the left side */ + if (ow->h_start < 0) + { + temp1 = 0; + } + else + { + /* clipping on the right side */ + if (ow->h_start >= (si->dm.virtual_width - 1)) + { + /* width < 2 is not allowed */ + temp1 = (si->dm.virtual_width - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (uint16)ow->h_start & 0x7ff; + } + } + temp32 |= temp1 << 16; + /* right edge coordinate of output window, must be inside desktop */ + /* width < 2 is not allowed */ + if (ow->width < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the right side */ + if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1)) + { + temp2 = (si->dm.virtual_width - 1) & 0x7ff; + } + else + { + /* clipping on the left side */ + if ((ow->h_start + ow->width - 1) < 1) + { + /* width < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(ow->h_start + ow->width - 1)) & 0x7ff; + } + } + } + temp32 |= temp2 << 0; + BESW(HCOORD, temp32); + LOG(4,("Overlay: left-edge output %d, right-edge output %d\n",temp1, temp2)); + + /* setup top and bottom edges of output window */ + temp32 = 0; + /* top edge coordinate of output window, must be inside desktop */ + /* clipping on the top side */ + if (ow->v_start < 0) + { + temp1 = 0; + } + else + { + /* clipping on the bottom side */ + if (ow->v_start >= (si->dm.virtual_height - 1)) + { + /* height < 2 is not allowed */ + temp1 = (si->dm.virtual_height - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (uint16)ow->v_start & 0x7ff; + } + } + temp32 |= temp1 << 16; + /* bottom edge coordinate of output window, must be inside desktop */ + /* height < 2 is not allowed */ + if (ow->height < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the bottom side */ + if ((ow->v_start + ow->height - 1) > (si->dm.virtual_height - 1)) + { + temp2 = (si->dm.virtual_height - 1) & 0x7ff; + } + else + { + /* clipping on the top side */ + if ((ow->v_start + ow->height - 1) < 1) + { + /* height < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(ow->v_start + ow->height - 1)) & 0x7ff; + } + } + } + temp32 |= temp2 << 0; + BESW(VCOORD, temp32); + LOG(4,("Overlay: top-edge output %d, bottom-edge output %d\n",temp1, temp2)); + + + /********************************************* + *** setup horizontal scaling and clipping *** + *********************************************/ + + LOG(4,("Overlay: 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)); + + /* do horizontal scaling... */ + /* determine interval representation value */ + if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) + { + /* horizontal filtering is ON */ + if (((ob->width - si->overlay.myBufInfo[offset].slopspace) == 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 < (ob->width - si->overlay.myBufInfo[offset].slopspace)) & (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 */ + /* (using standard scaling formula: neglecting round-off var as extra error is very small..) */ + ifactor = ((ob->width - si->overlay.myBufInfo[offset].slopspace - intrep) << 16) / + (ow->width - intrep); + LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor)); + + /* compensate for accelerated 2x zoom (slowdown BES if pixelclock is too high) */ + temp32 = ifactor * acczoom; + LOG(4,("Overlay: horizontal speed compensated factor is %f\n", (float)65536 / temp32)); + + /* check scaling factor (and modify if needed) to be within scaling limits */ + if ((((ob->width - si->overlay.myBufInfo[offset].slopspace) << 16) / 16384) > temp32) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + temp32 = (((ob->width - si->overlay.myBufInfo[offset].slopspace) << 16) / 16384); + LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / temp32)); + } + if (temp32 >= (32 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + temp32 = 0x1ffffc; + LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / temp32)); + } + /* AND below is required by hardware */ + temp32 &= 0x001ffffc; + BESW(HISCAL, temp32); + + + /* do horizontal clipping... */ + /* Setup horizontal source start: first (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * 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.! */ + + temp32 = 0; + /* check for destination horizontal clipping at left side */ + if (ow->h_start < 0) + { + /* check if entire destination picture is clipping left: + * (2 pixels will be clamped onscreen at least) */ + if ((ow->h_start + ow->width - 1) < 1) + { + /* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */ + temp32 += (ow->width - 2); + } + else + { + /* increase 'first contributing pixel' with actual number of dest. clipping pixels */ + temp32 += (0 - 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! */ + temp32 *= ifactor; + } + /* AND below required by hardware */ + temp32 &= 0x03fffffc; + BESW(HSRCST, temp32); + LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", temp32 / (float)65536)); + + + /* Setup horizontal source end: last (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */ + + temp32 = 0; + /* check for destination horizontal clipping at right side */ + if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1)) + { + /* check if entire destination picture is clipping right: + * (2 pixels will be clamped onscreen at least) */ + if (ow->h_start > (si->dm.virtual_width - 2)) + { + /* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */ + temp32 += (ow->width - 2); + } + else + { + /* increase 'number of clipping pixels' with actual number of dest. clipping pixels */ + temp32 += ((ow->h_start + ow->width - 1) - (si->dm.virtual_width - 1)); + } + LOG(4,("Overlay: clipping right...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + temp32 *= ifactor; + + /* now subtract this value from the last used pixel in inputbuffer, aligned to BES */ + temp32 = (((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16) - temp32; + } + else + { + /* set last contributing pixel to last used pixel in inputbuffer, aligned to BES */ + temp32 = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16; + } + /* AND below required by hardware */ + temp32 &= 0x03fffffc; + BESW(HSRCEND, temp32); + LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", temp32 / (float)65536)); + + + /* setup horizontal source last position excluding slopspace */ + temp32 = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16; + /* AND below required by hardware */ + temp32 &= 0x03ff0000; + BESW(HSRCLST, temp32); + + + /******************************************* + *** setup vertical scaling and clipping *** + *******************************************/ + + /* do vertical scaling... */ + /* determine interval representation value */ + if (ow->flags & B_OVERLAY_VERTICAL_FILTERING) + { + /* vertical filtering is ON */ + if ((ob->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 < ob->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 */ + /* (using standard scaling formula: neglecting round-off var as extra error is very small..) */ + ifactor = ((ob->height - intrep) << 16) / (ow->height - intrep); + LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor)); + + /* preserve ifactor for source positioning calculations later on */ + temp32 = ifactor; + + /* check scaling factor (and modify if needed) to be within scaling limits */ + if (((ob->height << 16) / 16384) > temp32) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + temp32 = ((ob->height << 16) / 16384); + LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / temp32)); + } + if (temp32 >= (32 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + temp32 = 0x1ffffc; + LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / temp32)); + } + /* AND below is required by hardware */ + temp32 &= 0x001ffffc; + BESW(VISCAL, temp32); + + + /* do vertical clipping... */ + /* Setup vertical source start: first (sub)pixel contributing to output picture. + * Note: this exists of two parts: + * 1. setup fractional part (sign is always 'positive'); + * 2. setup relative base_adress, taking clipping on top into account. + * Both parts are done intertwined below. */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * 'After' this is done, include the scaling factor so you get a value based on the input bitmap. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + + /* calculate relative base_adress and 'vertical weight fractional part' */ + weight = 0; + temp32 = (uint32)((vuint32 *)ob->buffer); + temp32 -= (uint32)((vuint32 *)si->framebuffer); + LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",temp32)); + /* calculate origin adress */ + /* check for destination vertical clipping at top side */ + if (ow->v_start < 0) + { + /* check if entire destination picture is clipping at top: + * (2 pixels will be clamped onscreen at least) */ + if ((ow->v_start + ow->height - 1) < 1) + { + /* increase source buffer origin with 'fixed value': + * (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) * + * bytes per row source picture */ + temp32 += ((((ow->height - 2) * ifactor) >> 16) * ob->bytes_per_row); + weight = (ow->height - 2) * ifactor; + } + else + { + /* increase source buffer origin with: + * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) * + * bytes per row source picture */ + temp32 += ((((0 - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row); + weight = (0 - ow->v_start) * ifactor; + } + LOG(4,("Overlay: clipping at top: buffer origin is (cardRAM offset) $%08x\n",temp32)); + } + LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", weight / (float)65536)); + + /* Note: + * Because later G200 and all > G200 overlay units will ignore b0-3 of the calculated adress, + * we do not use the above way for horizontal source positioning. + * (Early G200 cards ignore b0-2.) + * If we did, 8 source-image pixel jumps (in 4:2:2 colorspace) will occur if the picture + * is shifted horizontally during left clipping on later G200 and all > G200 cards, while + * early G200 cards will have 4 source-image pixel jumps occuring. */ + + /* AND below is required by G200-G550 hardware. All cards can have max. 32Mb RAM on board + * (incl. later G200 cards!). Compatible setting used (between early G200 and the rest), + * this has no downside consequences here. */ + temp32 &= 0x01fffff0; + /* buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */ + BESW(A1ORG, temp32); + + /* field 1 weight: AND below required by hardware, also make sure 'sign' is always 'positive' */ + temp32 = weight & 0x0000fffc; + BESW(V1WGHT, temp32); + + + /* setup field 1 (is our complete frame) vertical source contributing height - 1. + * Note: + * This value is bottom-unclipped! (as it should be according to the MGA specs...) */ + temp32 = (ob->height - 1) - (weight >> 16); + /* AND below required by hardware */ + temp32 &= 0x000003ff; + BESW(V1SRCLST, temp32); + LOG(4,("Overlay: input bitmap bottom-unclipped contributing height (integer part) %d\n", temp32 + 1)); + + + /************************** + *** setup color keying *** + **************************/ + + 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)); + + /* setup colorkeying */ + DXIW(COLKEY, (ow->alpha.value & ow->alpha.mask)); + + DXIW(COLKEY0RED, (ow->red.value & ow->red.mask)); + DXIW(COLKEY0GREEN, (ow->green.value & ow->green.mask)); + DXIW(COLKEY0BLUE, (ow->blue.value & ow->blue.mask)); + + DXIW(COLMSK, ow->alpha.mask); + + DXIW(COLMSK0RED, ow->red.mask); + DXIW(COLMSK0GREEN, ow->green.mask); + DXIW(COLMSK0BLUE, ow->blue.mask); + + /* enable colorkeying */ + DXIW(KEYOPMODE,0x01); + + + /************************* + *** setup misc. stuff *** + *************************/ + + /* setup brightness and contrast to be 'neutral' (this is not implemented on G200) */ + BESW(LUMACTL, 0x00000080); + + /* setup source pitch including slopspace (in pixels) */ + temp32 = ob->width; + /* AND below required by hardware */ + temp32 &= 0x00000fff; + BESW(PITCH, temp32); + + + /************************* + *** setup BES control *** + *************************/ + + /* BES global control: setup functions */ + temp32 = 0; + + /* slowdown BES if nessesary */ + if (acczoom == 1) + { + /* run at full speed and resolution */ + temp32 |= 0 << 0; + /* disable filtering for half speed interpolation */ + temp32 |= 0 << 1; + } + else + { + /* run at half speed and resolution */ + temp32 |= 1 << 0; + /* enable filtering for half speed interpolation */ + temp32 |= 1 << 1; + } + + /* 4:2:0 specific setup: not needed here */ + temp32 |= 0 << 3; + /* BES testregister: keep zero */ + temp32 |= 0 << 4; + /* the following bits marked (> G200) *must* be zero on G200: */ + /* 4:2:0 specific setup: not needed here (> G200) */ + temp32 |= 0 << 5; + /* select yuy2 byte-order to B_YCbCr422 (> G200) */ + temp32 |= 0 << 6; + /* BES internal contrast and brighness controls are not used, disabled (> G200) */ + temp32 |= 0 << 7; + /* RGB specific setup: not needed here, so disabled (> G200) */ + temp32 |= 0 << 8; + temp32 |= 0 << 9; + /* 4:2:0 specific setup: not needed here (> G200) */ + temp32 |= 0 << 10; + /* Tell BES when to copy the new register values to the actual active registers. + * bits 16-27 (12 bits) are the CRTC vert. count value at which copying takes + * place. + * (This is the double buffering feature: programming must be completed *before* + * the CRTC vert count value set here!) */ + /* CRTC vert count for copying = $000, so during retrace, line 0. */ + temp32 |= 0x000 << 16; + BESW(GLOBCTL, temp32); + + /* BES control: enable scaler and setup functions */ + /* pre-reset all bits */ + temp32 = 0; + /* enable BES */ + temp32 |= 1 << 0; + /* we start displaying at an even startline (zero) in 'field 1' (no hardware de-interlacing is used) */ + temp32 |= 0 << 6; + /* we don't use field 2, so its startline is not important */ + temp32 |= 0 << 7; + + LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags)); + /* enable horizontal filtering on scaling if asked for */ + if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) + { + temp32 |= 1 << 10; + LOG(4,("Overlay: using horizontal filtering\n")); + } + else + { + temp32 |= 0 << 10; + } + /* enable vertical filtering on scaling if asked for */ + if (ow->flags & B_OVERLAY_VERTICAL_FILTERING) + { + temp32 |= 1 << 11; + LOG(4,("Overlay: using vertical filtering\n")); + } + else + { + temp32 |= 0 << 11; + } + + /* use actual calculated weight for horizontal interpolation if scaling */ + temp32 |= 0 << 12; + /* use horizontal chroma interpolation upsampling on BES input picture */ + temp32 |= 1 << 16; + /* select 4:2:2 BES input format */ + temp32 |= 0 << 17; + /* dithering is not used */ + temp32 |= 0 << 18; + /* horizontal mirroring is not used */ + temp32 |= 0 << 19; + /* BES output should be in color */ + temp32 |= 0 << 20; + /* BES output blanking is disabled: we want a picture, no 'black box'! */ + temp32 |= 0 << 21; + /* we do software field select (field select is not used) */ + temp32 |= 0 << 24; + /* we always display field 1 in buffer A, this contains our full frames */ + /* select field 1 */ + temp32 |= 0 << 25; + /* select buffer A */ + temp32 |= 0 << 26; + BESW(CTL, temp32); + + LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT))); + + return B_OK; +} + +status_t gx00_release_bes() +{ + /* setup BES control: disable scaler */ + BESW(CTL, 0x00000000); + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_crtc.c b/src/add-ons/accelerants/matrox/engine/mga_crtc.c new file mode 100644 index 0000000000..3d3f357f0c --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_crtc.c @@ -0,0 +1,404 @@ +/* CTRC functionality */ +/* Authors: + Mark Watson 2/2000, + Apsed, + Rudolf Cornelissen 10/2002 +*/ + +#define MODULE_BIT 0x00040000 + +#include "mga_std.h" + +/*Adjust passed parameters to a valid mode line*/ +status_t gx00_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 and confine to required number of bits*/ + *hd_e&=0x7F8; + *hs_s&=0xFF8; + *hs_e&=0xFF8; + *ht &=0xFF8; + + /*confine to a reasonable width*/ + if (*hd_e<640) *hd_e=640; + if (*hd_e>2048) *hd_e=2048; + + /*if horizontal total does not leave room for a sensible sync pulse, increase it!*/ + if (*ht<(*hd_e+80)) *ht=*hd_e+80; + + /*make sure sync pulse is not during display*/ + if (*hs_e>(*ht-0x8)) *hs_e=*ht-0x8; + if (*hs_s<(*hd_e+0x8)) *hs_e=*hd_e+0x8; + + /*correct sync pulse if it is too long*/ + if (*hs_e>(*hs_s+0xF8)) *hs_e=*hs_s+0xF8; + + /*fail if they are now outside required number of bits*/ + if ( + *hd_e!=(*hd_e&0x7F8) || + *hs_s!=(*hs_s&0xFF8) || + *hs_e!=(*hs_e&0xFF8) || + *ht !=(*ht &0xFF8) + ) + { + LOG(8,("CRTC:Horizontal timing fell out of bits\n")); + return B_ERROR; + } + +/*vertical*/ + /*squish to required number of bits*/ + *vd_e&=0x7FF; + *vs_s&=0xFFF; + *vs_e&=0xFFF; + *vt &=0xFFF; + + /*confine to a reasonable height*/ + if (*vd_e<400) *vd_e=400; + if (*vd_e>2048) *vd_e=2048; + + /*if vertical total does not leave room for a sync pulse, increase it!*/ + if (*vt<(*vd_e+3)) *vt=*vd_e+3; + + /*make sure sync pulse if 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*/ + if (*vs_e>(*vs_s+0xF)) *vs_e=*vs_s+0xF; + + /*fail if now outside required number of bits*/ + if ( + *vd_e!=(*vd_e&0x7FF) || + *vs_s!=(*vs_s&0xFFF) || + *vs_e!=(*vs_e&0xFFF) || + *vt !=(*vt &0xFFF) + ) + { + LOG(8,("CRTC:Vertical timing fell out of bits\n")); + return B_ERROR; + } + return B_OK; +} + + +/*set a mode line - inputs are in pixels*/ +status_t gx00_crtc_set_timing( + uint16 hd_e,uint16 hs_s,uint16 hs_e,uint16 ht, + uint16 vd_e,uint16 vs_s,uint16 vs_e,uint16 vt, + uint8 hsync_pos,uint8 vsync_pos +) +{ + uint32 htotal; /*total horizontal total VCLKs*/ + uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ + uint32 hsync_s; /*begin of horizontal sync pulse*/ + uint32 hsync_e; /*end of horizontal sync pulse*/ + uint32 hblnk_s; /*begin horizontal blanking*/ + uint32 hblnk_e; /*end horizontal blanking*/ + + uint32 vtotal; /*total vertical total scanlines*/ + uint32 vdisp_e; /*end of vertical display*/ + uint32 vsync_s; /*begin of vertical sync pulse*/ + uint32 vsync_e; /*end of vertical sync pulse*/ + uint32 vblnk_s; /*begin vertical blanking*/ + uint32 vblnk_e; /*end vertical blanking*/ + + uint32 linecomp; /*split screen and vdisp_e interrupt*/ + + LOG(4,("CRTC: setting timing\n")); + + /*Modify parameters as required by the G400/G200*/ + htotal=(ht>>3)-5; + hdisp_e=(hd_e>>3)-1; + hsync_s=(hs_s>>3); + hsync_e=(hs_e>>3); + hblnk_s=hdisp_e; + hblnk_e=htotal+4; + + vtotal=vt-2; + vdisp_e=vd_e-1; + vsync_s=vs_s-1; + vsync_e=vs_e-1; + vblnk_s=vdisp_e; + vblnk_e=vtotal+1; + + linecomp=256; /*should display half the screen!*/ + + /*log the mode I am setting*/ + 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! Note linecomp is programmed to vblnk_s for VBI*/ + /*horizontal - VGA regs*/ + + VGAW_I(CRTC,0,htotal&0xFF); + VGAW_I(CRTC,1,hdisp_e&0xFF); + VGAW_I(CRTC,2,hblnk_s&0xFF); + VGAW_I(CRTC,3,(hblnk_e&0x1F)|0x80); + VGAW_I(CRTC,4,hsync_s&0xFF); + VGAW_I(CRTC,5,(hsync_e&0x1F)|((hblnk_e&0x20)<<2)); + + /*vertical - VGA regs*/ + VGAW_I(CRTC,6,vtotal&0xFF); + VGAW_I(CRTC,7, + ( + ((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)) + )); + VGAW_I(CRTC,0x9,((vblnk_s&0x200)>>(9-5))|((linecomp&0x200)>>(9-6))); + VGAW_I(CRTC,0x10,vsync_s&0xFF); + VGAW_I(CRTC,0x11,((VGAR_I(CRTC,0x11))&0xF0)|(vsync_e&0xF)); + VGAW_I(CRTC,0x12,vdisp_e&0xFF); + VGAW_I(CRTC,0x15,vblnk_s&0xFF); + VGAW_I(CRTC,0x16,vblnk_e&0xFF); + VGAW_I(CRTC,0x18,linecomp&0xFF); + + /*horizontal - extended regs*/ + VGAW_I(CRTCEXT,1, + ( + ((htotal&0x100)>>8)| + ((hblnk_s&0x100)>>7)| + ((hsync_s&0x100)>>6)| + (hblnk_e&0x40)| + (VGAR_I(CRTCEXT,1)&0xb8) + )); + + /*vertical - extended regs*/ + VGAW_I(CRTCEXT,2, + ( + ((vtotal&0xC00)>>10)| + ((vdisp_e&0x400)>>8)| + ((vblnk_s&0xC00)>>7)| + ((vsync_s&0xC00)>>5)| + ((linecomp&0x400)>>3) + )); + + /*set up HSYNC & VSYNC polarity*/ + VGAW(MISCW,(VGAR(MISCR)&0x3F)|((!vsync_pos)<<7)|((!hsync_pos)<<6)); + LOG(2,("HSYNC/VSYNC pol:%x %x MISC dump:%x\n",hsync_pos,vsync_pos,VGAR(MISCR))); + + return B_OK; +} + +status_t gx00_crtc_depth(int mode) +{ + uint8 viddelay = 0; // in CRTCEXT3, reserved if >= G100 + + if (si->ps.card_type < G100) do { // apsed TODO in caller + if (si->ps.memory_size <= 2) { viddelay = 1<<3; break;} + if (si->ps.memory_size <= 4) { viddelay = 0<<3; break;} + viddelay = 2<<3; // for 8 to 16Mb of memory + } while (0); + + /*set VCLK scaling*/ + switch(mode) + { + case BPP8: + VGAW_I(CRTCEXT,3,viddelay|0x80); + break; + case BPP15:case BPP16: + VGAW_I(CRTCEXT,3,viddelay|0x81); + break; + case BPP24: + VGAW_I(CRTCEXT,3,viddelay|0x82); + break; + case BPP32:case BPP32DIR: + VGAW_I(CRTCEXT,3,viddelay|0x83); + break; + } + return B_OK; +} + +status_t gx00_crtc_dpms(uint8 display,uint8 h,uint8 v) // MIL2 +{ + LOG(4,("gx00_crtc_dpms (%d,%d,%d)\n", display,h,v)); + VGAW_I(SEQ,1,(!display)<<5); + VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0xCF)|((!v)<<5))|((!h)<<4); + + VGAW_I(CRTC,0x17,0xC3);/*do not force disable all syncs and other stuff*/ + VGAW_I(CRTC,0x14,0x00); + + return B_OK; +} + +status_t gx00_crtc_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) // MIL2 +{ + *display=!((VGAR_I(SEQ,1)&0x20)>>5); + *h=!((VGAR_I(CRTCEXT,1)&0x10)>>4); + *v=!((VGAR_I(CRTCEXT,1)&0x20)>>5); + + LOG(4,("gx00_crtc_dpms_fetch (%d,%d,%d)\n", *display,*h,*v)); + return B_OK; +} + +status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp) +{ + uint32 offset; + + LOG(4,("CRTC: setting card pitch (offset between lines)\n")); + + /*figure out offset value hardware needs*/ + offset = (pitch*bpp)/128; + + LOG(2,("CRTC: offset: 0x%04x\n",offset)); + + /*program the card!*/ + VGAW_I(CRTC,0x13,(offset&0xFF)); + VGAW_I(CRTCEXT,0,(VGAR_I(CRTCEXT,0)&0xCF)|((offset&0x300)>>4)); + return B_OK; +} + +status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp) +{ + uint32 ext0; + + LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp)); + + /*figure out startadd value hardware needs*/ + /*switch(bpp) + { + case 8:case 24: + startadd>>=1; + case 16: + startadd>>=1; + case 32: + startadd>>=1; + break; + }*/ + startadd>>=3; // apsed, TODO doc Matrox g200 g400 4.6.5 is false? + + LOG(2,("CRTC: startadd: %x\n",startadd)); + LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer)); + LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer)); + + /*set standard registers*/ + VGAW_I(CRTC,0xD,startadd&0xFF); + VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8); + + //calculate extra bits that are standard over Gx00 series + ext0 = VGAR_I(CRTCEXT,0)&0xB0; + ext0|= (startadd&0xF0000)>>16; + + //if card is a G200 or G400 then do first extension bit + if (si->ps.card_type>=G200) + ext0|=(startadd&0x100000)>>14; + + //if card is a G400 then do write to its extension register + if (si->ps.card_type>=G400) + VGAW_I(CRTCEXT,8,((startadd&0x200000)>>21)); + + //write the extension bits + VGAW_I(CRTCEXT,0,ext0); + + return B_OK; +} + +status_t gx00_crtc_mem_priority(uint8 HIPRILVL) +{ + if (si->ps.card_type taken care off. + + /*store cursor at the start of the framebuffer*/ + DXIW(CURADDL,curadd >> 10); /*data at curadd in framebuffer*/ + DXIW(CURADDH,curadd >> 18); + DXIW(CURCTRL,1); + + /*set cursor colour*/ + DXIW(CURCOL0RED,0XFF); + DXIW(CURCOL0GREEN,0xFF); + DXIW(CURCOL0BLUE,0xFF); + DXIW(CURCOL1RED,0); + DXIW(CURCOL1GREEN,0); + DXIW(CURCOL1BLUE,0); + DXIW(CURCOL2RED,0); + DXIW(CURCOL2GREEN,0); + DXIW(CURCOL2BLUE,0); + + /*clear cursor*/ + fb = (uint32 *) si->framebuffer + curadd; + for (i=0;i<(1024/4);i++) + { + fb[i]=0; + } + return B_OK; +} + +status_t gx00_crtc_cursor_show() +{ + DXIW(CURCTRL,1); + return B_OK; +} + +status_t gx00_crtc_cursor_hide() +{ + DXIW(CURCTRL,0); + return B_OK; +} + +/*set up cursor shape*/ +status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask) +{ + uint8 * cursor; + int y; + + /*get a pointer to the cursor*/ + cursor = (uint8*) si->framebuffer; + + /*draw the cursor*/ + for(y=0;y<16;y++) + { + cursor[y*16+7]=~*andMask++; + cursor[y*16+15]=*xorMask++; + cursor[y*16+6]=~*andMask++; + cursor[y*16+14]=*xorMask++; + } + + return B_OK; +} + +/*position the cursor*/ +status_t gx00_crtc_cursor_position(uint16 x ,uint16 y) +{ + int i=64; +// LOG(4,("DAC: cursor-> %d %d\n",x,y)); + + x+=i; + y+=i; + + DACW(CURSPOSXL,x&0xFF); + DACW(CURSPOSXH,x>>8); + DACW(CURSPOSYL,y&0xFF); + DACW(CURSPOSYH,y>>8); + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_crtc2.c b/src/add-ons/accelerants/matrox/engine/mga_crtc2.c new file mode 100644 index 0000000000..1fa174917e --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_crtc2.c @@ -0,0 +1,96 @@ +/* second CTRC functionality */ +/* Mark Watson 6/2000 */ + +#define MODULE_BIT 0x00020000 + +#include "mga_std.h" + +/*set a mode line - inputs are in pixels/scanlines*/ +status_t g400_crtc2_set_timing( + uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, + uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, + uint8 hsync_pos,uint8 vsync_pos + ) +{ + LOG(4,("CRTC2: setting timing\n")); + + /*check horizontal timing parameters are to nearest 8 pixels*/ + if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7)) + { + LOG(8,("CRTC2:Horizontal timings are not multiples of 8 pixels\n")); + return B_ERROR; + } + + /*program the second CRTC*/ + CR2W(HPARAM,(((hdisp_e-8)<<16) | (htotal-8))); + CR2W(HSYNC,(((hsync_e-8)<<16) | (hsync_s-8))); + CR2W(VPARAM,(((vdisp_e-1)<<16) | (vtotal-1))); + CR2W(VSYNC,(((vsync_e-1)<<16) | (vsync_s-1))); + CR2W(PRELOAD,(((vsync_s)<<16) | (hsync_s))); + CR2W(MISC,((0xfff<<16) | ((!hsync_pos)<<8) | ((!vsync_pos)<<9))); + + return B_OK; +} + +status_t g400_crtc2_depth(int mode) +{ + /*validate bit depth and set mode*/ + switch(mode) + { + case BPP16:case BPP32DIR: + CR2W(CTL,(CR2R(CTL)&0xFF10077F)|(mode<<21)); + break; + case BPP8:case BPP15:case BPP24:case BPP32:default: + LOG(8,("CRTC2:Invalid bit depth\n")); + return B_ERROR; + break; + } + + return B_OK; +} + +status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v) +{ + CR2W(CTL,(CR2R(CTL)&0xFFF0077E)|(display&h&v)); /*enable second CRTC if required*/ + + /*ignore h,v because they are not supported*/ + return B_OK; +} + +status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) +{ + *display=CR2R(CTL)&1; + + *h=*v=1; /*h/vsync always enabled on second CRTC, does not support other*/ + + return B_OK; +} + +status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp) +{ + uint32 offset; + + LOG(4,("CRTC2: setting card pitch 0x%08x bpp %d\n", pitch, bpp)); + + /*figure out offset value hardware needs*/ + offset = pitch*(bpp>>3); + + LOG(2,("CRTC2: offset: %x\n",offset)); + + /*program the card!*/ + CR2W(OFFSET,offset); + return B_OK; +} + +status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp) +{ + LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp)); + + LOG(2,("CRTC2: startadd: %x\n",startadd)); + LOG(2,("CRTC2: frameRAM: %x\n",si->framebuffer)); + LOG(2,("CRTC2: framebuffer: %x\n",si->fbc.frame_buffer)); + + /*program the card!*/ + CR2W(STARTADD0,startadd); + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_dac.c b/src/add-ons/accelerants/matrox/engine/mga_dac.c new file mode 100644 index 0000000000..4edde0b5c5 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_dac.c @@ -0,0 +1,837 @@ +/* program the DAC */ +/* Authors: + Mark Watson 2/2000, + Apsed 2002, + Rudolf Cornelissen 9/2002 +*/ + +#define MODULE_BIT 0x00010000 + +#include "mga_std.h" + +static status_t g100_g400max_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); +static status_t g450_g550_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); +static status_t g100_g400max_dac_sys_pll_find( + float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); + +/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ +status_t gx00_dac_mode(int mode,float brightness) +{ + uint8 *r,*g,*b,t[64]; + int i; + + /*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 a basic palette for brightness specified*/ + for (i=0;i<256;i++) + { + int ri = i*brightness; // apsed + if (ri > 255) ri = 255; + r[i]=ri; + } + + /*modify the palette for the specified mode (&validate mode)*/ + switch(mode) + { + case BPP8: + case BPP24:case BPP32: + for (i=0;i<256;i++) + { + b[i]=g[i]=r[i]; + } + break; + case BPP16: + for (i=0;i<64;i++) + { + t[i]=r[i<<2]; + } + for (i=0;i<64;i++) + { + g[i]=t[i]; + } + for (i=0;i<32;i++) + { + b[i]=r[i]=t[i<<1]; + } + break; + case BPP15: + for (i=0;i<32;i++) + { + t[i]=r[i<<3]; + } + for (i=0;i<32;i++) + { + g[i]=r[i]=b[i]=t[i]; + } + break; + case BPP32DIR: + break; + default: + LOG(8,("DAC:Invalid bit depth requested\n")); + return B_ERROR; + break; + } + + if (gx00_dac_palette(r,g,b)!=B_OK) return B_ERROR; + + /*set the mode - also sets VCLK dividor*/ + DXIW(MULCTRL,mode); + DACW(PIXRDMSK,0xff); // apsed, palette addressing not masked + + LOG(2,("DAC: mulctrl=%x, pixrdmsk=%x\n",DXIR(MULCTRL), DACR(PIXRDMSK))); + + return B_OK; +} + +/*program the DAC palette using the given r,g,b values*/ +status_t gx00_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256]) +{ + int i; + + LOG(4,("DAC: setting palette\n")); + + /*clear palwtadd to start programming*/ + DACW(PALWTADD,0); + + /*loop through all 256 to program DAC*/ + for (i=0;i<256;i++) + { + DACW(PALDATA,r[i]); + DACW(PALDATA,g[i]); + DACW(PALDATA,b[i]); + } + if (DACR(PALWTADD)!=0) + { + LOG(8,("DAC: PALWTADD is not 0 after programming\n")); + return B_ERROR; + } +if (0) {// apsed: reread LUT + uint8 R, G, B; + DACW(PALRDADD,0); + for (i=0;i<256;i++) { + R = DACR(PALDATA); + G = DACR(PALDATA); + B = DACR(PALDATA); + if ((r[i] != R) || (g[i] != G) || (b[i] != B)) + LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed + } +} + return B_OK; +} + +/*program the pixpll - frequency in kHz*/ +/*important notes: + * MISC(clksel) = select A,B,C PIXPLL (25,28,none) + * PIXPLLC is used - others should be kept as is + * VCLK is quadword clock (max is PIXPLL/2) - set according to DEPTH + * BESCLK,CRTC2 are not touched + */ +status_t gx00_dac_set_pix_pll(display_mode target) +{ + uint8 m=0,n=0,p=0; + uint time = 0; + + float pix_setting, req_pclk; + status_t result; + + req_pclk = (target.timing.pixel_clock)/1000.0; + LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); + + result = gx00_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*/ + VGAW(MISCW,((VGAR(MISCR)&0xF3)|0x8)); /*select PIXPLLC*/ + DXIW(PIXPLLCM,(m)); /*set m value*/ + DXIW(PIXPLLCN,(n)); /*set n value*/ + DXIW(PIXPLLCP,(p)); /*set p value*/ + + /* Wait for the PIXPLL frequency to lock until timeout occurs */ + 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*/ + + return B_OK; +} + +status_t gx50_dac_check_pix_pll(uint8 m, uint8 n, uint8 p) +{ + uint time = 0, count = 0; + + /*reprogram (disable,select,wait for stability,enable)*/ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ + VGAW(MISCW,((VGAR(MISCR)&0xF3)|0x8)); /*select PIXPLLC*/ + DXIW(PIXPLLCM,(m)); /*set m value*/ + DXIW(PIXPLLCN,(n)); /*set n value*/ + DXIW(PIXPLLCP,(p)); /*set p value*/ + + /* give the PLL 1mS at least to get a lock */ + time = 0; + while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 1000)) + { + time++; + snooze(1); + } + + /* no lock aquired, not useable */ + if (time > 1000) return B_ERROR; + + /* check if lock holds for at least 90% of the time */ + for (time = 0, count = 0; time <= 1000; time++) + { + if(DXIR(PIXPLLSTAT)&0x40) count++; + snooze(1); + } + /* we have a winner */ + if (count >= 900) return B_OK; + + /* nogo, the PLL does not stabilize */ + return B_ERROR; +} + +status_t gx50_dac_check_pix_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q) +{ + uint8 s=0, p_backup = *p; + + /* preset no candidate, non working setting */ + *q = 0; + /* preset lowest range filter */ + *p &= 0x47; + + /* iterate through all possible filtersettings */ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ + + for (s = 0; s < 8 ;s++) + { + if (gx50_dac_check_pix_pll(m, n, *p)== B_OK) + { + /* now check 3 closest lower and higher settings */ + if ((gx50_dac_check_pix_pll(m, n - 3, *p)== B_OK) && + (gx50_dac_check_pix_pll(m, n - 2, *p)== B_OK) && + (gx50_dac_check_pix_pll(m, n - 1, *p)== B_OK) && + (gx50_dac_check_pix_pll(m, n + 1, *p)== B_OK) && + (gx50_dac_check_pix_pll(m, n + 2, *p)== B_OK) && + (gx50_dac_check_pix_pll(m, n + 3, *p)== B_OK)) + { + LOG(2,("DAC: found optimal working VCO filter: #%d\n",s)); + /* preset first choice setting found */ + *q = 1; + /* we are done */ + DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/ + return B_OK; + } + else + { + LOG(2,("DAC: found critical but working VCO filter: #%d\n",s)); + /* preset backup setting found */ + *q = 2; + /* remember this setting */ + p_backup = *p; + /* let's continue to see if a better filter exists */ + } + } + /* new filtersetting to try */ + *p += (1 << 3); + } + + /* return the (last found) backup result, or the original p value */ + *p = p_backup; + DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/ + /* we found only a non-optimal value */ + if (*q == 2) return B_OK; + + /* nothing worked at all */ + LOG(2,("DAC: no working VCO filter found!\n")); + return B_ERROR; +} + +/* find nearest valid pix pll */ +status_t gx00_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) { + case G550: + case G450: return g450_g550_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); + default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result); + } + return B_ERROR; +} + +/* find nearest valid pixel PLL setting: rewritten by rudolf */ +static status_t g100_g400max_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result) +{ + int m = 0, n = 0, p = 0, m_max; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + /* determine the max. reference-frequency postscaler setting for the + * current card (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; + } + + /* 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 / 8.0)) + req_pclk = (si->ps.min_pixel_vco / 8.0); + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) req_pclk = max_pclk; + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= m_max; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + /* ..and check for validity */ + if ((n < 8) || (n > 128)) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m=best[0] - 1; + n=best[1] - 1; + p=best[2] - 1; + + /* calc the needed PLL loopbackfilter setting belonging to current VCO speed, + * for the current card (see G100, G200 and G400 specs). */ + f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); + LOG(2,("DAC: pix VCO frequency found %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 the results */ + *calc_pclk = f_vco / ((p & 0x07) + 1); + *m_result = m; + *n_result = n; + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("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 pixel PLL setting: rewritten by rudolf */ +static status_t g450_g550_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; + uint8 p = 0, q = 0; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + LOG(4,("DAC: G450/G550 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)) + 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) req_pclk = max_pclk; + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x20; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= 32; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5); + /* ..and check for validity, BUT: + * Keep in mind that we need to be able to test n-3 ... n+3! */ + if ((n < (8 + 3)) || (n > (128 - 3))) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m=best[0] - 1; + n=best[1] - 1; + switch(best[2]) + { + case 1: + p = 0x40; + break; + case 2: + p = 0x00; + break; + case 4: + p = 0x01; + break; + case 8: + p = 0x02; + break; + case 16: + p = 0x03; + break; + } + + /* log the closest VCO speed found */ + f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1); + LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco)); + + /* now find the filtersetting that matches best with this frequency by testing. + * for now we assume this routine succeeds to get us a stable setting */ + if (test) + gx50_dac_check_pix_pll_range(m, n, &p, &q); + else + LOG(2,("DAC: Not testing G450/G550 VCO feedback filters\n")); + + /* return the results */ + *calc_pclk = f_vco / best[2]; + *m_result = m; + *n_result = n; + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); + + return B_OK; +} + +/* find nearest valid system PLL setting */ +static status_t g100_g400max_dac_sys_pll_find( + float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result) +{ + int m = 0, n = 0, p = 0, m_max; + float error, error_best = 999999999; + int best[3]; + float f_vco; + + /* determine the max. reference-frequency postscaler setting for the + * current card (see G100, G200 and G400 specs). */ + switch(si->ps.card_type) + { + case G100: + LOG(4,("DAC: G100 restrictions apply\n")); + m_max = 7; + break; + case G200: + LOG(4,("DAC: G200 restrictions apply\n")); + m_max = 7; + break; + default: + LOG(4,("DAC: G400/G400MAX restrictions apply\n")); + m_max = 32; + break; + } + + /* Make sure the requested systemclock is within the PLL's operational limits */ + /* lower limit is min_system_vco divided by highest postscaler-factor */ + if (req_sclk < (si->ps.min_system_vco / 8.0)) + req_sclk = (si->ps.min_system_vco / 8.0); + /* upper limit is max_system_vco */ + if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco; + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_sclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_system_vco) && (f_vco <= si->ps.max_system_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= m_max; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + /* ..and check for validity */ + if ((n < 8) || (n > 128)) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_sclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m=best[0] - 1; + n=best[1] - 1; + p=best[2] - 1; + + /* calc the needed PLL loopbackfilter setting belonging to current VCO speed, + * for the current card (see G100, G200 and G400 specs). */ + f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); + LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco)); + + switch(si->ps.card_type) + { + 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 the results */ + *calc_sclk = f_vco / ((p & 0x07) + 1); + *m_result = m; + *n_result = n; + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC: sys PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_sclk, *calc_sclk, *m_result, *n_result, *p_result)); + + return B_OK; +} + +/*set up system pll - NB mclk is memory clock, */ +status_t g100_dac_set_sys_pll() +{ + /* values for DAC sys pll registers */ + uint8 m, n, p; + uint time = 0; + uint32 temp; + float calc_sclk; + + LOG(1,("DAC: Setting up G100 system clock\n")); + //zodra gclk, mclk en fmclk DIV ingesteld is via PINS en hieronder: + g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p); + + /* reprogram the clock - set PCI/AGP, program, set to programmed */ + /* disable the SYSPLL */ + CFGW(OPTION, CFGR(OPTION) | 0x04); + /* select the PCI/AGP clock */ + CFGW(OPTION, CFGR(OPTION) & 0xfffffffc); + /* enable the SYSPLL */ + CFGW(OPTION, CFGR(OPTION) & 0xfffffffb); + + /* program the new clock */ + DXIW(SYSPLLM, m); + DXIW(SYSPLLN, n); + DXIW(SYSPLLP, p); + + /* Wait for the SYSPLL frequency to lock until timeout occurs */ + while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: sys PLL frequency not locked!\n")); + else + LOG(2,("DAC: sys PLL frequency locked\n")); + + /* disable the SYSPLL */ + CFGW(OPTION, CFGR(OPTION) | 0x04); + /* setup Gclk, Mclk and FMclk divisors according to PINS */ + temp = (CFGR(OPTION) & 0xffffff27); + if (si->ps.v3_clk_div & 0x01) temp |= 0x08; + if (si->ps.v3_clk_div & 0x02) temp |= 0x10; + if (si->ps.v3_clk_div & 0x04) temp |= 0x80; + /* fixme: swapPLL can only be done when the rest of the driver respects this also! */ + //never used AFAIK: + //if (si->ps.v3_clk_div & 0x08) temp |= 0x40; + /* select the SYSPLL as system clock source */ + temp |= 0x01; + CFGW(OPTION, temp); + /* enable the SYSPLL (and make sure the SYSPLL is indeed powered up) */ + CFGW(OPTION, (CFGR(OPTION) & 0xfffffffb) | 0x20); + + return B_OK; +} + +/*set up system pll - NB mclk is memory clock, */ +status_t g200_dac_set_sys_pll() +{ + uint8 m, n, p;/*values for DAC sys pll registers*/ + uint time = 0; + float calc_sclk; + + LOG(1,("DAC: Setting up G200 system clock\n")); + //zodra gclk, mclk en fmclk DIV ingesteld is via PINS !EN OPTION2! en hieronder: + //g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p); + //voor nu: + g100_g400max_dac_sys_pll_find(124.2, &calc_sclk, &m, &n, &p); + + /*reprogram the clock - set PCI/AGP, program, set to programmed*/ + //fixme: PINS.. + CFGW(OPTION2,0x8000); /*no memory clock divider (pinced from win)*/ + + CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/ + CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFC); /*select the PCI/AGP clock*/ + CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/ + + DXIW(SYSPLLM,m); + DXIW(SYSPLLN,n); + DXIW(SYSPLLP,p); + + /* Wait for the SYSPLL frequency to lock until timeout occurs */ + while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: sys PLL frequency not locked!\n")); + else + LOG(2,("DAC: sys PLL frequency locked\n")); + + CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/ + //fixme: PINS.. + CFGW(OPTION,(CFGR(OPTION)&0xFFFFFF27)|0x1); /*select the SYSPLLs chosen*/ + CFGW(OPTION,(CFGR(OPTION)&0xFFFFFFFB)|0x20); /*enable the SYSPLL*/ + + return B_OK; +} + +/*set up system pll - NB mclk is memory clock, */ +status_t g400_dac_set_sys_pll() + +{ + uint32 scalers; /*value for option 3*/ + uint8 m, n, p;/*values for DAC sys pll registers*/ + uint8 mclk_duty,oclk_duty; + + uint time = 0; + float mclk,oclk; + float temp_f; + float calc_sclk; + + /* fixme? get from PINS */ + int mclk_div = 4; + int oclk_div = 3; + + float div[8]={0.3333,0.4,0.4444,0.5,0.6666,0,0,0}; + + LOG(1,("DAC: Setting up G400/G400MAX system clock\n")); + g100_g400max_dac_sys_pll_find(si->ps.std_engine_clock, &calc_sclk, &m, &n, &p); + + /* calculate the real clock speeds derivated from SYSPLL */ + mclk = div[mclk_div] * calc_sclk; + oclk = div[oclk_div] * calc_sclk; + + /*work out the duty cycle correction*/ + temp_f=1/(float)oclk; + temp_f*=1000; + LOG(2,("DAC:oclk correction ns: %f\n",temp_f)); + temp_f-=2.25; + temp_f/=0.5; + oclk_duty=(uint8)temp_f; + + temp_f=1/(float)mclk; + temp_f*=1000; + LOG(2,("DAC:mclk correction ns: %f\n",temp_f)); + temp_f-=2.25; + temp_f/=0.5; + mclk_duty=(uint8)temp_f; + + /*calculate OPTION3*/ + scalers=(0x1<<0)|(0x1<<10)|(0x1<<20); + scalers|=(oclk_div<<3)|(mclk_div<<13)|(oclk_div<<23); + scalers|=(oclk_duty<<6)|(mclk_duty<<16)|(oclk_duty<<26); + + /*print out the results*/ + LOG(2,("DAC: MCLK:%f\tOCLK:%f\n",mclk,oclk)); + LOG(2,("DAC: mclk_div:0x%x mclk_duty:0x%x\noclk_div:0x%x oclk_duty:0x%x\nOPTION3: 0x%x\n", + mclk_div,mclk_duty,oclk_div,oclk_duty,scalers)); + + /*reprogram the clock - set PCI/AGP, program, set to programmed*/ + CFGW(OPTION2,0); /*clear so don't o/clock add ons*/ + CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/ + CFGW(OPTION3,0); /*select the PCI/AGP clock*/ + CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/ + + DXIW(SYSPLLM,m); + DXIW(SYSPLLN,n); + DXIW(SYSPLLP,p); + + /* Wait for the SYSPLL frequency to lock until timeout occurs */ + while((!(DXIR(SYSPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: sys PLL frequency not locked!\n")); + else + LOG(2,("DAC: sys PLL frequency locked\n")); + + CFGW(OPTION,CFGR(OPTION)|0x04); /*disable the SYSPLL*/ + CFGW(OPTION3,scalers); /*select the SYSPLLs chosen*/ + CFGW(OPTION,CFGR(OPTION)&0xFFFFFFFB); /*enable the SYSPLL*/ + + return B_OK; +} + +/*set up system pll - NB mclk is memory clock, */ +//fixme: implement this routine for coldstart: +//status_t g450_dac_set_sys_pll(int m,int n,int mclk_div,int oclk_div) diff --git a/src/add-ons/accelerants/matrox/engine/mga_general.c b/src/add-ons/accelerants/matrox/engine/mga_general.c new file mode 100644 index 0000000000..2662e7f926 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_general.c @@ -0,0 +1,735 @@ +/* Authors: + Mark Watson 12/1999, + Apsed, + Rudolf Cornelissen 10/2002 +*/ + +#define MODULE_BIT 0x00008000 + +#include "mga_std.h" +//apsed #include "memory" +//#include "mga_init.c" //Nicole's test stuff. + +status_t test_ram(); +static status_t mil2_general_powerup (void); +static status_t g100_general_powerup (void); +static status_t g200_general_powerup (void); +static status_t g400_general_powerup (void); +static status_t g450_general_powerup (void); +static status_t gx00_general_bios_to_powergraphics(void); + +static void mga_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", \ + MGACFG_##reg, #reg, value)); \ +} while (0) + DUMP_CFG (DEVID, 0); + DUMP_CFG (DEVCTRL, 0); + DUMP_CFG (CLASS, 0); + DUMP_CFG (HEADER, 0); + DUMP_CFG (MGABASE2, 0); + DUMP_CFG (MGABASE1, 0); + DUMP_CFG (MGABASE3, MYST); + DUMP_CFG (SUBSYSIDR, MYST); + DUMP_CFG (ROMBASE, 0); + DUMP_CFG (CAP_PTR, MIL2); + DUMP_CFG (INTCTRL, 0); + DUMP_CFG (OPTION, 0); + DUMP_CFG (MGA_INDEX, 0); + DUMP_CFG (MGA_DATA, 0); + DUMP_CFG (SUBSYSIDW, MYST); + DUMP_CFG (OPTION2, G100); + DUMP_CFG (OPTION3, G400); + DUMP_CFG (OPTION4, G400); + DUMP_CFG (PM_IDENT, G100); + DUMP_CFG (PM_CSR, G100); + DUMP_CFG (AGP_IDENT, MIL2); + DUMP_CFG (AGP_STS, MIL2); + DUMP_CFG (AGP_CMD, MIL2); +#undef DUMP_CFG +} + +status_t gx00_general_powerup() +{ + status_t status; + uint32 class; + + //detect card type and powerup + switch(CFGR(DEVID)) + { + case 0x0519102b: //MGA-2064 Millenium PCI + case 0x051a102b: //MGA-1064 Mystic PCI + LOG(8,("POWERUP: unimplemented Matrox device %08x\n",CFGR(DEVID))); + return B_ERROR; + case 0x051b102b:case 0x051f102b: //MGA-2164 Millenium 2 PCI/AGP + si->ps.card_type=MIL2; + LOG(4,("POWERUP:Detected MGA-2164 Millennium 2\n")); + status = mil2_general_powerup(); + break; + case 0x1000102b:case 0x1001102b: //G100 + si->ps.card_type=G100; + LOG(4,("POWERUP:Detected G100\n")); + status = g100_general_powerup(); + break; + case 0x0520102b:case 0x0521102b: //G200 + si->ps.card_type=G200; + LOG(4,("POWERUP:Detected G200\n")); + status = g200_general_powerup(); + break; + case 0x0525102b: //G400 + LOG(4,("POWERUP:Detected G4")); + //Check if it is a G450... + class = 0xff&CFGR(CLASS); + if (class & 0x80) //G450 + { + si->ps.card_type=G450; + LOG(4, ("50 revision %x\n", class&0x7f)); + status = g450_general_powerup(); + } + else //G400 + { + si->ps.card_type=G400; + LOG(4, ("00 revision %x\n", class&0x7f)); + status = g400_general_powerup(); + } + break; + case 0x2527102b://G550 patch from Jean-Michel Batto + si->ps.card_type=G450; + LOG(4,("POWERUP:Detected G550\n")); + status = g450_general_powerup(); + break; + default: + LOG(8,("POWERUP:Failed to detect valid card 0x%08x\n",CFGR(DEVID))); + return B_ERROR; + } + + /*override memory if requested by user*/ + // even if detection works on the G400 + if (si->settings.memory != 0) // apsed + si->ps.memory_size = si->settings.memory; + + return status; +} + +status_t test_ram() +{ + uint32 value, offset; + status_t result = B_OK; + + /* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */ + if (si->fbc.frame_buffer == NULL) + { + LOG(8,("INIT: test_ram detected NULL pointer.\n")); + return B_ERROR; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* write testpattern to cardRAM */ + ((uint32 *)si->fbc.frame_buffer)[offset] = value; + /* toggle testpattern */ + value = 0xffffffff - value; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* readback and verify testpattern from cardRAM */ + if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR; + /* toggle testpattern */ + value = 0xffffffff - value; + } + return result; +} + +/* NOTE: + * This routine *has* to be done *after* SetDispplayMode has been executed, + * or test results will not be representative! + * (CAS latency is dependant on MGA setup on some (DRAM) boards) */ +status_t mga_set_cas_latency() +{ + status_t result = B_ERROR; + uint8 latency = 0; + + /* check current RAM access to see if we need to change anything */ + if (test_ram() == B_OK) + { + LOG(4,("INIT: RAM access OK.\n")); + return B_OK; + } + + /* check if we read PINS at starttime so we have valid registersettings at our disposal */ + if (si->ps.pins_status != B_OK) + { + LOG(4,("INIT: RAM access errors; not fixable: PINS was not read from cardBIOS.\n")); + return B_ERROR; + } + + /* OK. We might have a problem, try to fix it now.. */ + LOG(4,("INIT: RAM access errors; tuning CAS latency if prudent...\n")); + + switch(si->ps.card_type) + { + case G100: + if (!si->ps.sdram) + { + LOG(4,("INIT: G100 SGRAM CAS tuning not permitted, aborting.\n")); + return B_OK; + } + /* SDRAM card */ + for (latency = 4; latency >= 2; latency-- ) + { + /* MCTLWTST is a write-only register! */ + ACCW(MCTLWTST, ((si->ps.mctlwtst_reg & 0xfffffffc) | (latency - 2))); + result = test_ram(); + if (result == B_OK) break; + } + break; + case G200: + /* fixme: implement this */ + LOG(4,("INIT: G200 RAM CAS tuning not implemented, aborting.\n")); + return B_OK; + break; + case G400: + case G400MAX: + /* fixme: implement this if needed */ + LOG(4,("INIT: G400/G400MAX RAM CAS tuning not implemented, aborting.\n")); + return B_OK; + break; + case G450: + case G550: + /* G450 and G550 tune CAS latency via a predefined table at powerup time */ + LOG(4,("INIT: G450/G550 RAM CAS tuning not implemented, aborting.\n")); + return B_OK; + break; + default: + /* fixme: Millenium2 and others if needed */ + LOG(4,("INIT: RAM CAS tuning not implemented for this card, aborting.\n")); + return B_OK; + break; + } + if (result == B_OK) + LOG(4,("INIT: RAM access OK. CAS latency set to %d cycles.\n", latency)); + else + LOG(4,("INIT: RAM access not fixable. CAS latency set to %d cycles.\n", latency)); + + return result; +} + +static +status_t mil2_general_powerup() +{ + status_t result; + + LOG(4, ("INIT: Millenium II powerup\n")); + if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); + + /* initialize the shared_info PINS struct */ + result = parse_pins(); + if (result != B_OK) fake_pins(); + + /* log the PINS struct settings */ + dump_pins(); + +//remove this: + // various sensible defaults for MIL2 + si->ps.sdram = true; + si->ps.memory_size = 2; //can override + si->ps.memory_size = 4; //can override my mil2 + + // apsed TODO MIL2 TVP 3026 may be 135, 175, 220 or 250MHz + // chip on my Millenium2 is TVP3026-250CPCE, 250MHz + // rudolf: works in Mhz now + si->ps.max_dac1_clock=250; // TVP3026 +//end remove this. + + /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ +//restore this line: +// if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics(); + + //set to powergraphics etc. + LOG(2, ("INIT: Skipping card coldstart!\n")); + mil2_dac_init(); + + VGAW_I(SEQ,1,0x00); + /*enable screen*/ +return B_OK; + + return B_ERROR; // apsed TODO MIL2 taken from G100, avoid DXIR/W DACR/W + + /*power up the PLLs,LUT,DAC*/ + /*this bit should not be needed if BIOS has initialised it*/ + LOG(2,("INIT:PLL/LUT/DAC powerup\n")); + DXIW(VREFCTRL,0x3F); /*set voltage reference - using DAC reference block*/ + delay(100000); /*wait for 100ms for voltage reference to stabalise*/ + CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/ + while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/ + LOG(2,("INIT: SYS PLL locked\n")); + DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/ + while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/ + LOG(2,("INIT: PIX PLL locked\n")); + DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ + + /* setup i2c bus */ + i2c_init(); + + /*make sure card is in powergraphics mode*/ + VGAW_I(CRTCEXT,3,0x80); + + /*set the system clocks to powergraphics speed*/ + LOG(2,("INIT:Setting SYS/PIX plls to powergraphics speeds\n")); + g100_dac_set_sys_pll(); + + /*RAM initialisation*/ + LOG(2,("INIT:RAM init\n")); + gx00_crtc_dpms(0,0,0); /*turn off both displays*/ + ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/ + CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/ + CFGW(OPTION2,(CFGR(OPTION2)&0xC100)|(si->ps.mem_rd)); /*set MEMRDCLK*/ + CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|(si->ps.membuf<<12)); /*set the memory buffer type*/ + delay(250); /*wait for 250microseconds*/ + ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/ + delay(250); + ACCW(MACCESS,ACCR(MACCESS)|0xC000); /*sets JEDEC as well*/ + delay(250); /*wait for 250microseconds*/ + ACCW(MACCESS,ACCR(MACCESS)&0xFFFF3FFF); + delay(250); + ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/ + CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/ + + /*Bus parameters*/ + CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/ + + /*enable writing to crtc registers*/ + VGAW_I(CRTC,0x11,0); + + /*turn on display one*/ + gx00_crtc_dpms(1,1,1); + + return B_OK; +} + +static +status_t g100_general_powerup() +{ + status_t result; + + LOG(4, ("INIT: G100 powerup\n")); + if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); + + /* initialize the shared_info PINS struct */ + result = parse_pins(); + if (result != B_OK) fake_pins(); + + /* log the PINS struct settings */ + dump_pins(); + + /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ + if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics(); + + /*power up the PLLs,LUT,DAC*/ + /*this bit should not be needed if BIOS has initialised it*/ + LOG(2,("INIT: PLL/LUT/DAC powerup\n")); + /* G100 SGRAM and SDRAM use external pix and dac refs, do *not* activate internals! + * (this would create electrical shortcuts, + * resulting in extra chip heat and distortions visible on screen */ + DXIW(VREFCTRL,0x03); /*set voltage reference - using DAC reference block partly */ + delay(100000); /*wait for 100ms for voltage reference to stabalise*/ + CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/ + while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/ + LOG(2,("INIT: SYS PLL locked\n")); + DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/ + while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/ + LOG(2,("INIT: PIX PLL locked\n")); + DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ + + /* setup i2c bus */ + i2c_init(); + + /*make sure card is in powergraphics mode*/ + VGAW_I(CRTCEXT,3,0x80); + + /*set the system clocks to powergraphics speed*/ + LOG(2,("INIT: Setting system PLL to powergraphics speeds\n")); + g100_dac_set_sys_pll(); + + /* 'official' RAM initialisation */ + LOG(2,("INIT: RAM init\n")); + /* turn off both displays (also disables transfers) */ + gx00_crtc_dpms(0,0,0); + /* disable plane write mask (needed for SDRAM) */ + ACCW(PLNWT,0xffffffff); + /* program memory control waitstates */ + ACCW(MCTLWTST,si->ps.mctlwtst_reg); + /* set memory configuration: + * - no split framebuffer, + * - Mark says b14 (G200) should be done also though not defined for G100 in spec, + * - b3 v3_mem_type was included by Mark for memconfig setup: but looks like not defined */ + CFGW(OPTION,(CFGR(OPTION)&0xFFFF8FFF) | ((si->ps.v3_mem_type & 0x04) << 10)); + /* set memory buffer type: + * - Mark says: if((v3_mem_type & 0x03) == 0x03) then do not or-in bits in option2; + * but looks like v3_mem_type b1 is not defined, + * - Mark also says: place v3_mem_type b1 in option2 bit13 (if not 0x03) but b13 = reserved. */ + CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|((si->ps.v3_mem_type & 0x01) << 12)); + /* set mode register opcode to $0 */ +// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xE1FFFFFF)); /* G200 only */ + /* set RAM read tap delay G100 */ + CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFFFF0) | ((si->ps.v3_mem_type & 0xf0) >> 4)); +// ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|the_setting); /* G200 version */ + /* wait 200uS minimum */ + snooze(250); + + /* reset memory */ + ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); + /* select JEDEC reset method */ + ACCW(MACCESS,ACCR(MACCESS)|0x4000); + /* perform actual RAM reset */ + ACCW(MACCESS,ACCR(MACCESS)|0x8000); + snooze(250); + /* start memory refresh */ + CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); + /* set memory control waitstate again AFTER the RAM reset */ + ACCW(MCTLWTST,si->ps.mctlwtst_reg); + /* end 'official' RAM initialisation. */ + + /* Bus parameters: enable retries, use advanced read */ + CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); + + /*enable writing to crtc registers*/ + VGAW_I(CRTC,0x11,0); + + /*turn on display one*/ + gx00_crtc_dpms(1,1,1); + + return B_OK; +} + +static +status_t g200_general_powerup() +{ + status_t result; + + LOG(4, ("INIT: G200 powerup\n")); + if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); + + /* initialize the shared_info PINS struct */ + result = parse_pins(); + if (result != B_OK) fake_pins(); + + /* log the PINS struct settings */ + dump_pins(); + + /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ + if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics(); + + /*power up the PLLs,LUT,DAC*/ + /*this bit should not be needed if BIOS has initialised it*/ + LOG(2,("INIT: PLL/LUT/DAC powerup\n")); +//rudolf: check from here on: + DXIW(VREFCTRL,0x3f); /*set voltage reference - using DAC reference block*/ + delay(100000); /*wait for 100ms for voltage reference to stabalise*/ + CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/ + while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/ + LOG(2,("INIT: SYS PLL locked\n")); + DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/ + while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/ + LOG(2,("INIT: PIX PLL locked\n")); + DXIW(MISCCTRL,0x1b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ +//until here + + /* setup i2c bus */ + i2c_init(); + +//rudolf: remove: + /*read the PINS and other stuff*/ + if (g200_card_info()==B_ERROR) + return B_ERROR; +//until here + + /*make sure card is in powergraphics mode*/ + VGAW_I(CRTCEXT,3,0x80); + + /*set the system clocks to powergraphics speed*/ + LOG(2,("INIT: Setting SYS/PIX plls to powergraphics speeds\n")); + g200_dac_set_sys_pll(); + + /*RAM initialisation*/ + LOG(2,("INIT:RAM init\n")); + gx00_crtc_dpms(0,0,0); /*turn off both displays*/ + ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/ + CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/ + ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF)|(si->ps.mem_rd&0xFFFF0000));/*set MEMRDBK - mrsopcode*/ + CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFCFFF)|(si->ps.membuf<<12)); /*set the memory buffer type*/ + delay(250); /*wait for 250microseconds*/ + ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/ + ACCW(MACCESS,ACCR(MACCESS)|0x8000); + delay(250); /*wait for 250microseconds*/ + ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/ + CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/ + + /*Bus parameters*/ + CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/ + + /*enable writing to crtc registers*/ + VGAW_I(CRTC,0x11,0); + + /*turn on display one*/ + gx00_crtc_dpms(1,1,1); + + return B_OK; +} + +static +status_t g400_general_powerup() +{ + status_t result; + + //fully functional G400 powerup -> uses settings from my card if no PINS + LOG(4, ("INIT: G400 powerup\n")); + if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); + + /* initialize the shared_info PINS struct */ + result = parse_pins(); + if (result != B_OK) fake_pins(); + + /* log the PINS struct settings */ + dump_pins(); + + /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ + if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics(); + + /*power up the PLLs,LUT,DAC*/ + /*this bit should not be needed if BIOS has initialised it*/ + LOG(4,("INIT: G400 PLL/LUT/DAC powerup\n")); + DXIW(VREFCTRL,0x30); /*set voltage reference - using DAC reference block*/ + delay(100000); /*wait for 100ms for voltage reference to stabalise*/ + CFGW(OPTION,CFGR(OPTION)|0x20); /*power up the SYSPLL - sets syspllpdN to 1*/ + while(!(DXIR(SYSPLLSTAT)&0x40)); /*wait for the SYSPLL frequency to lock*/ + LOG(2,("INIT: SYS PLL locked\n")); + DXIW(PIXCLKCTRL,0x08); /*power up the PIXPLL - sets pixpllpdN to 1*/ + while(!(DXIR(PIXPLLSTAT)&0x40)); /*wait for the PIXPLL frequency to lock*/ + LOG(2,("INIT: PIX PLL locked\n")); + DXIW(MISCCTRL,0x9b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ + DXIW(MAFCDEL,0x2); /*makes CRTC2 stable! Matrox specify 8, but use 4 - grrrr!*/ + DXIW(PANELMODE,0x00); /*eclipse panellink*/ + + /* setup i2c bus */ + i2c_init(); + +//rudolf: remove + /*read the PINS and other stuff*/ + if (g400_card_info()==B_ERROR) + return B_ERROR; +//end remove + + /*make sure card is in powergraphics mode*/ + VGAW_I(CRTCEXT,3,0x80); + + /*set the system clocks to powergraphics speed*/ + LOG(2,("INIT: Setting SYS/PIX plls to powergraphics speeds\n")); + g400_dac_set_sys_pll(); + + /*RAM initialisation*/ + LOG(2,("INIT:RAM init\n")); + gx00_crtc_dpms(0,0,0); /*turn off both displays*/ + g400_crtc2_dpms(0,0,0); + ACCW(MCTLWTST,si->ps.mem_ctl); /*set memory wait states*/ + CFGW(OPTION,(CFGR(OPTION)&0xFFFF83FF)|si->ps.mem_type); /*set RAM type and config*/ + ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF)|(si->ps.mem_rd&0xFFFF0000));/*set MEMRDBK - mrsopcode*/ + delay(250); /*wait for 250microseconds*/ + ACCW(MACCESS,ACCR(MACCESS)&0xFFFF7FFF); /*reset memory*/ + ACCW(MACCESS,ACCR(MACCESS)|0x8000); + delay(250); /*wait for 250microseconds*/ + ACCW(MEMRDBK,(ACCR(MEMRDBK)&0xFFFF0000)|(si->ps.mem_rd&0xFFFF));/*set tap delays*/ + CFGW(OPTION,(CFGR(OPTION)&0xffe07fff)|(si->ps.mem_rfhcnt<<15)); /*start memory refresh*/ + + /*Bus parameters*/ + CFGW(OPTION,(CFGR(OPTION)|(1<<22)|(0<<29))); /*enable retries, use advanced read*/ + + /*enable writing to crtc registers*/ + VGAW_I(CRTC,0x11,0); + if (si->ps.secondary_head) + { + MAVW(LOCK,0x01); + CR2W(DATACTL,0x00000000); + } + + /*turn on display one*/ + gx00_crtc_dpms(1,1,1); + return B_OK; +} + +static +status_t g450_general_powerup() +{ + uint32 temp; + status_t result; + + LOG(4, ("INIT: G450 powerup\n")); + if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); + + /* initialize the shared_info PINS struct */ + result = parse_pins(); + if (result != B_OK) fake_pins(); + + /* log the PINS struct settings */ + dump_pins(); + +//rudolf: remove if impl in PINS above: + // various sensible defaults for G450 + si->ps.sdram = true; +//end remove + + /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ + if (si->settings.usebios || (result != B_OK)) return gx00_general_bios_to_powergraphics(); + + /*power up the PLLs,LUT,DAC*/ +//rudolf: checkout coldstart from here: + + //In case you are interested here is some of the G450 powerup stuff -> nonfunction as yet + + //These are the values of OPTION->OPTION4 used in Linux + //rudolf: get from PINS... + CFGW(OPTION, 0x400a1160); + CFGW(OPTION2, 0x100ac00); + CFGW(OPTION3, 0x90a409); + CFGW(OPTION4, 0x80000004); + +//rudolf: remove + /*read the PINS and other stuff*/ + if (g450_card_info()==B_ERROR) + return B_ERROR; +//end remove + + //various init (as bios) + CFGW(OPTION, ((CFGR(OPTION)&0xf8404164) | (si->ps.option&0x207e00)) ); + CFGW(OPTION2, (CFGR(OPTION2) | (0xfc00&si->ps.option2))); + ACCW(MCTLWTST, si->ps.mem_ctl); + CFGW(OPTION4, (si->ps.option4&0x6000000f)); + ACCW(MEMRDBK, si->ps.mem_rd); + + ACCW(MACCESS, ((si->ps.maccess&0x80)>>1) ); + + CFGW(OPTION4,((si->ps.option4&0x60000004)|0x80000000)); + + delay(250); + + if + ( + ((si->ps.option&0x200000) == 0) && + ((si->ps.maccess&0x200) == 0) + ) + { + ACCW(MEMRDBK, ((si->ps.mem_rd)&0xffffefff)); + + if ((si->ps.maccess&0x100) == 0) + { + ACCW(MACCESS, ACCR(MACCESS)&0xffff00ff); + } + } + + temp = ACCR(MACCESS); + temp &=0xffff80ff; + temp = temp|((temp&0x8000)>>1)|0x8000; + ACCW(MACCESS, temp); + + temp &= 0xffff7fff; + ACCW(MACCESS, temp); + + delay(250); + + if ((si->ps.maccess&0x400) == 0) + { + temp = si->ps.mem_ctl; + temp = (temp &0x7) + 3; + temp |= si->ps.mem_ctl &0xfffffff8; + ACCW(MCTLWTST, temp); + } + + temp = CFGR(OPTION); + temp &=0xffe07fff; + temp |= si->ps.option&0x1f8000; + CFGW(OPTION, temp); + + return B_OK; +} + +/*connect CRTC1 to the specified DAC*/ +status_t gx00_general_dac_select(int dac) +{ + if (!si->ps.secondary_head) + return B_ERROR; + + /*MISCCTRL, clock src,...*/ + switch(dac) + { + case DS_CRTCDAC_CRTC2MAVEN: /*CRTC->DAC,CRTC2->MAFC*/ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ + CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); /*external clk*/ + VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77)); + DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82); + break; + case DS_CRTCMAVEN_CRTC2DAC: /*CRTC->MAVEN,CRTC2->DAC*/ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); /*external clk*/ + CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk*/ + VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88)); + DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02); + break; + case DS_CRTCDAC_CRTC2DAC2: + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ + CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk - gets DAC*/ + //FIXME VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77)); + //FIXME DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82); + break; + case DS_CRTCDAC_CRTCDAC2: + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ + CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x0<<20)); /*internal clk - no DAC PTR*/ + break; + default: + return B_ERROR; + } + return B_OK; +} + +/*busy wait until retrace!*/ +status_t gx00_general_wait_retrace() +{ + while (!(ACCR(STATUS)&0x8)); + return B_OK; +} + +/* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/ +static +status_t gx00_general_bios_to_powergraphics() +{ + LOG(2, ("INIT: Skipping card coldstart!\n")); + + //set to powergraphics etc. + CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); + /*enable device response (already enabled here!)*/ + + VGAW_I(CRTC,0x11,0); + /*allow me to change CRTC*/ + + VGAW_I(CRTCEXT,3,0x80); + /*use powergraphix (+ trash other bits, they are set later)*/ + + VGAW(MISCW,0x08); + /*set only MGA pixel clock in MISC - I don't want to map VGA stuff under this OS*/ + + if (si->ps.card_type >= G100) { + DXIW(MISCCTRL,0x9b); + /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ + + DXIW(MULCTRL,0x4); + /*RGBA direct mode*/ + } else { + LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR))); + } // apsed TODO MIL2 + + VGAW_I(SEQ,1,0x00); + /*enable screen*/ + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_i2c.c b/src/add-ons/accelerants/matrox/engine/mga_i2c.c new file mode 100644 index 0000000000..da1d8e3dd0 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_i2c.c @@ -0,0 +1,291 @@ +/* + * i2c interface for the G400 MAVEN under BeOS + * Mark Watson 06/2000 + * + * Provides I2CR,I2CW - functions to parallel DACW,DACR + * Bus is run slowly because I do not know how fast the MAVEN is! + * + * Much help was provided by observing the Linux i2c code, + * so thanks go to: Gerd Knorr + */ +#define MODULE_BIT 0x00004000 + +#include "mga_std.h" + +/*which device on the bus is the MAVEN?*/ +#define MAVEN_WRITE (0x1B<<1) +#define MAVEN_READ ((0x1B<<1)|1) + +#define I2C_CLOCK 0x20 +#define I2C_DATA 0x10 + +/*----------------------------- + *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; + 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/matrox/engine/mga_info.c b/src/add-ons/accelerants/matrox/engine/mga_info.c new file mode 100644 index 0000000000..7e6e999261 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_info.c @@ -0,0 +1,990 @@ +/* Read initialisation information from card */ +/* some bits are hacks, where PINS is not known */ +/* Authors: + Mark Watson 2/2000, + Rudolf Cornelissen 10/2002 +*/ + +#define MODULE_BIT 0x00002000 + +#include "mga_std.h" + +//general pins stuff! +enum { + id=0x00, + length=0x02, + version=0x04, + location=0x7FFC +}; + +//pins v5(!) (as used by G450) +enum { + p5_option=0x30, + p5_option2=0x34, + p5_memctl=0x3e, + p5_option4=0x42, + p5_memrd=0x46, + p5_maccess=0x72 +}; + +//pins v4 (as used by G400) +enum { + p4_memtype=0x35, + p4_memctl=0x3d, + p4_memrd=0x56, + p4_sdram=0x5c, +}; + +//pins v3 (as used by G200/G100?) +enum { + p3_memtype=0x36, + p3_memctl=0x30, + p3_memrd=0x38, + p3_sdram=0x34, + p3_membuf=0x3a //G200 extra? + }; + +static void dump_card_infos (void) +{ + MSG(("g200_card_info:Memory control word: 0x%08x\n",si->ps.mem_ctl)); + if (si->ps.sdram) MSG(("g200_card_info:is SDRAM card: 1\n")); + else MSG(("g200_card_info:is SDRAM card: 0\n")); + MSG(("g200_card_info:Memory config: 0x%08x\n",si->ps.mem_type)); + MSG(("g200_card_info:MEMRDBK setting: 0x%08x\n",si->ps.mem_rd)); + MSG(("g200_card_info:Membuftype: 0x%08x\n",si->ps.membuf)); + MSG(("g200_card_info:mem_rfhcnt: %d\n", si->ps.mem_rfhcnt)); +} + +/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/ +status_t g200_card_info() +{ + uint8 * rom; + uint8 * pins; + int i; + int chksum = 0; + + /*check the validity of PINS*/ + LOG(4,("g200_card_info: Reading PINS info\n")); + rom = (uint8 *) si->rom_mirror; + + //check sig + if (rom[0]!=0x55 || rom[1]!=0xaa) + { + LOG(8,("g200_card_info:BIOS bad signiture: 0x%02x%02x, expected 0x55aa\n",rom[0],rom[1])); + } + LOG(2,("g200_card_info: BIOS signiture $AA55 found OK\n")); + pins = rom + (rom[location]|(rom[location+1]<<8)); + LOG(2,("g200_card_info: Using PINS v%d.%d structure at 0x%04x\n",pins[version+1],pins[version],pins-rom)); + //check valid + for (i=0;ips.mem_ctl=0x4244ca1; + si->ps.mem_type=(4<<10)|(0<<14); //SDRAM memory config 4 + si->ps.mem_rd=0x108; + si->ps.membuf=0; + } + else + { + LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n")); + + /*read memory control word*/ + si->ps.mem_ctl=*((uint32 *)(pins + p3_memctl)); + + /*read memory config*/ + si->ps.mem_type=(pins[p3_memtype]&0x7)<<10; + if (!si->ps.sdram) si->ps.mem_type|= (0x01<<14); + + /*figure out memrdbk settings*/ + si->ps.mem_rd=((pins[p3_memrd+1]&0xf0)>>3)<<24|((pins[p3_memrd+1]&0x03)>>2)<<16; //FIXME - ROR + si->ps.mem_rd|=((pins[p3_memrd]&0xf0)<<1)|(pins[p3_memrd]&0x0f); + + //memory buffer type setting + si->ps.membuf=pins[p3_membuf]&0x3; + } + + /*FIXME hardcode a few required values, i.e. ones not found in PINS*/ + /*memory refresh settings (values pinched from windows)*/ + si->ps.mem_rfhcnt=0x78000>>15; + + if (si->settings.logmask & 0x80000000) dump_card_infos(); + return B_OK; +} + +/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/ +status_t g400_card_info() +{ + uint8 * rom; + uint8 * pins; + int i; + int chksum = 0; + + LOG(4,("INFO:Getting G400 card info\n")); + /*check the validity of PINS*/ + LOG(2,("INFO:Reading PINS info\n")); + rom = (uint8 *) si->rom_mirror; + //check sig + if (rom[0]!=0x55 || rom[1]!=0xaa) + { + LOG(8,("INFO:BIOS signiture not found\n")); + } + LOG(2,("INFO:BIOS signiture $AA55 found OK\n")); + pins = rom + (rom[location]|(rom[location+1]<<8)); + LOG(2,("INFO:Using PINS v%d.%d structure at: %x\n",pins[version+1],pins[version],pins-rom)); + //check valid + for (i=0;ips.mem_ctl=0x24045491; + si->ps.mem_type=1<<14; //SDRAM memory config 0 + si->ps.mem_rd=0x108; + si->ps.sdram=true; + } + else + { + LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n")); + + /*read memory control word*/ + si->ps.mem_ctl=*((uint32 *)(pins + p4_memctl)); + LOG(2,("INFO:Memory control word: %x\n",si->ps.mem_ctl)); + + /*read memory config*/ + si->ps.sdram = (pins[p4_sdram]&0x10); + si->ps.mem_type=(pins[p4_memtype]&0x38)<<7; + if (!si->ps.sdram) si->ps.mem_type |= (0x01 << 14); + LOG(2,("INFO:Memory config: %x\n",si->ps.mem_type)); + + /*figure out memrdbk settings*/ + si->ps.mem_rd=((pins[p4_memrd+1]&0xf0)>>3)<<24|((pins[p4_memrd+1]&0x03)>>2)<<16; //FIXME - ROR + si->ps.mem_rd|=((pins[p4_memrd]&0xf0)<<1)|(pins[p4_memrd]&0x0f); + LOG(2,("INFO:MEMRDBK setting: %x\n",si->ps.mem_rd)); + + /*figure out if it is a G400MAX*/ + /*FIXME, use the correct ID method!*/ + if (si->ps.mem_ctl==0x20049911) + { + LOG(2,("INFO:MAX\n")); + si->ps.card_type=G400MAX; + } + } + + /*FIXME hardcode a few required values, i.e. ones not found in PINS*/ + /*memory refresh settings (values pinched from windows)*/ + if (si->ps.card_type==G400) + { + si->ps.mem_rfhcnt=0x27; + } + else if (si->ps.card_type==G400MAX) + { + si->ps.mem_rfhcnt=0x2e; + } + if (si->settings.logmask & 0x80000000) dump_card_infos(); + + return B_OK; +} + +/*word out card specific information - using PINS where possible (if not substitute sensible defaults)*/ +status_t g450_card_info() +{ + uint8 * rom; + uint8 * pins; + int i; + int chksum = 0; + + LOG(4,("INFO:Getting G450 card info\n")); + /*check the validity of PINS*/ + LOG(2,("INFO:Reading PINS info\n")); + rom = (uint8 *) si->rom_mirror; + //check sig + if (rom[0]!=0x55 || rom[1]!=0xaa) + { + LOG(8,("INFO:BIOS signiture not found\n")); + } + LOG(2,("INFO:BIOS signiture $AA55 found OK\n")); + pins = rom + (rom[location]|(rom[location+1]<<8)); + LOG(2,("INFO:Using PINS v%d.%d structure at: %x\n",pins[version+1],pins[version],pins-rom)); + //check valid + for (i=0;ips.mem_ctl=0x24045491; + si->ps.mem_type=1<<14; //SDRAM memory config 0 + si->ps.mem_rd=0x108; + si->ps.sdram=true; + } + else + { + LOG(2,("INFO:PINS checksum is correct - grabbing PINS values\n")); + + /*read memory control word*/ + si->ps.mem_ctl=*((uint32 *)(pins + p5_memctl)); + LOG(2,("INFO:Memory control word: %x\n",si->ps.mem_ctl)); + + /*read useful registers*/ + si->ps.option=*((uint32 *)(pins + p5_option)); + si->ps.option2=*((uint32 *)(pins + p5_option2)); + si->ps.option4=*((uint32 *)(pins + p5_option4)); + si->ps.maccess=*((uint32 *)(pins + p5_maccess)); + + /*figure out memrdbk settings*/ + si->ps.mem_rd=*((uint32 *)(pins + p5_memrd)); + } + + if (si->settings.logmask & 0x80000000) dump_card_infos(); + return B_OK; +} + +/* Parse the BIOS PINS structure if there */ +status_t parse_pins () +{ + uint8 pins_len = 0; + uint8 *rom; + uint8 *pins; + uint8 chksum = 0; + int i; + status_t result = B_ERROR; + + /* preset PINS read status to failed */ + si->ps.pins_status = B_ERROR; + + /* check the validity of PINS */ + LOG(2,("INFO: Reading PINS info\n")); + rom = (uint8 *) si->rom_mirror; + /* check BIOS signature */ + if (rom[0]!=0x55 || rom[1]!=0xaa) + { + LOG(8,("INFO: BIOS signiture not found\n")); + return B_ERROR; + } + LOG(2,("INFO: BIOS signiture $AA55 found OK\n")); + /* check for a valid PINS struct adress */ + pins = rom + (rom[0x7FFC]|(rom[0x7FFD]<<8)); + if ((pins - rom) > 0x7F80) + { + LOG(8,("INFO: invalid PINS adress\n")); + return B_ERROR; + } + /* checkout new PINS struct version if there */ + if ((pins[0] == 0x2E) && (pins[1] == 0x41)) + { + pins_len = pins[2]; + if (pins_len < 3 || pins_len > 128) + { + LOG(8,("INFO: invalid PINS size\n")); + return B_ERROR; + } + + /* calculate PINS checksum */ + for (i = 0; i < pins_len; i++) + { + chksum += pins[i]; + } + if (chksum) + { + LOG(8,("INFO: PINS checksum error\n")); + return B_ERROR; + } + LOG(2,("INFO: new PINS, version %u.%u, length %u\n", pins[5], pins[4], pins[2])); + /* fill out the si->ps struct if possible */ + switch (pins[5]) + { + case 2: + result = pins2_read(pins, pins_len); + break; + case 3: + result = pins3_read(pins, pins_len); + break; + case 4: + result = pins4_read(pins, pins_len); + break; + case 5: + result = pins5_read(pins, pins_len); + break; + default: + LOG(8,("INFO: unknown PINS version\n")); + return B_ERROR; + break; + } + } + /* checkout old 64 byte PINS struct version if there */ + else if ((pins[0] == 0x40) && (pins[1] == 0x00)) + { + pins_len = 0x40; + /* this PINS version has no checksum */ + + LOG(2,("INFO: old PINS found\n")); + /* fill out the si->ps struct */ + result = pins1_read(pins, pins_len); + } + /* no valid PINS signature found */ + else + { + LOG(8,("INFO: no PINS signature found\n")); + return B_ERROR; + } + /* check PINS read result */ + if (result == B_ERROR) + { + LOG(8,("INFO: PINS read/decode error\n")); + return B_ERROR; + } + /* PINS scan succeeded */ + si->ps.pins_status = B_OK; + LOG(2,("INFO: PINS scan completed succesfully\n")); + return B_OK; +} + +status_t pins1_read(uint8 *pins, uint8 length) +{ +//remove later on here: +// float f_ref; /* PLL reference-oscillator frequency */ +// uint32 max_system_vco; /* graphics engine PLL VCO limits */ +// uint32 min_system_vco; +// uint32 max_pixel_vco; /* dac1 PLL VCO limits */ +// uint32 min_pixel_vco; +// uint32 max_video_vco; /* dac2, maven PLL VCO limits */ +// uint32 min_video_vco; +// uint32 std_engine_clock; /* graphics engine clock speed needed */ +// uint32 std_engine_clock_dh; +// uint32 max_dac1_clock; /* dac1 limits */ +// uint32 max_dac1_clock_8; /* dac1 limits correlated to RAMspeed limits */ +// uint32 max_dac1_clock_16; +// uint32 max_dac1_clock_24; +// uint32 max_dac1_clock_32; +// uint32 max_dac1_clock_32dh; +// uint32 max_dac2_clock; /* dac2 limits */ +// uint32 max_dac2_clock_8; /* dac2, maven limits correlated to RAMspeed limits */ +// uint32 max_dac2_clock_16; +// uint32 max_dac2_clock_24; +// uint32 max_dac2_clock_32; +// uint32 max_dac2_clock_32dh; +// bool secondary_head; /* presence of functions */ +// bool secondary_tvout; +// bool primary_dvi; +// bool secondary_dvi; +// uint32 memory_size; /* memory in Mb */ +// uint32 mctlwtst_reg; /* memory control waitstate register */ +// uint32 option_reg; /* option register */ +// uint8 v3_clk_div; /* pins v3 memory and system clock division factors */ +// uint8 v3_mem_type; /* pins v3 memory type info */ +// bool sdram; +//end remove later on here. + + //fixme: implement this.. + return B_ERROR; +} + +status_t pins2_read(uint8 *pins, uint8 length) +{ + LOG(2,("INFO: PINS version 2 details not yet known\n")); + return B_ERROR; +} + +/* pins v3 is used by G100 and G200. */ +status_t pins3_read(uint8 *pins, uint8 length) +{ + /* used to calculate RAM refreshrate */ + float mclk_period; + uint32 rfhcnt; + + if (length != 64) + { + LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length)); + return B_ERROR; + } + + /* fill out the shared info si->ps struct */ + si->ps.max_pixel_vco = pins[36] + 100; + + si->ps.max_dac1_clock_8 = pins[37] + 100; + si->ps.max_dac1_clock_16 = pins[38] + 100; + si->ps.max_dac1_clock_24 = pins[39] + 100; + si->ps.max_dac1_clock_32 = pins[40] + 100; + + si->ps.std_engine_clock = pins[44]; + if (pins [45] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[45]; + if (pins [46] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[46]; + if (pins [47] < si->ps.std_engine_clock) si->ps.std_engine_clock = pins[47]; + if (pins[52] & 0x01) + si->ps.std_engine_clock *= 3; + else + si->ps.std_engine_clock *= 2; + + if (pins[52] & 0x20) si->ps.f_ref = 14.31818; + else si->ps.f_ref = 27.00000; + + /* G100 and G200 support 2-16Mb RAM */ + si->ps.memory_size = 2 << ((pins[55] & 0xc0) >> 6); + /* more memory specifics */ + si->ps.mctlwtst_reg = (pins[51] << 24) | (pins[50] << 16) | (pins[49] << 8) | pins [48]; + si->ps.v3_clk_div = pins[52]; + si->ps.v3_mem_type = pins[54]; + + /* for cards using this version of PINS both functions are in maven */ + si->ps.secondary_head = !(pins[59] & 0x01); + si->ps.secondary_tvout = !(pins[59] & 0x01); + + /* setup via gathered info from pins with some fixed values added which are not in pins */ + si->ps.option_reg = 0; + /* calculate refresh timer info-bits for 15uS interval (or shorter). See G100/G200 specs */ + /* calculate std memory clock period (nS) */ + if (pins[52] & 0x02) + /* only used on G200, not on G100 */ + mclk_period = 3000.0 / si->ps.std_engine_clock; + else + mclk_period = 2000.0 / si->ps.std_engine_clock; + /* calculate needed setting, 'round-down' result! */ + rfhcnt = (uint32)(((15000 / mclk_period) - 1) / 64); + /* check for register limit */ + if (rfhcnt > 0x3f) rfhcnt = 0x3f; + /* add to option register */ + si->ps.option_reg |= (rfhcnt << 15); + /* the rest of the OPTION info currently comes via 'v3_clk_div' and 'v3_mem_type'. */ + + /* assuming the only possible panellink will be on the first head */ + si->ps.primary_dvi = !(pins[59] & 0x40); + /* logical consequence of the above */ + si->ps.secondary_dvi = false; + + /* indirect logical consequences, see also G100 and G200 specs */ + si->ps.max_system_vco = si->ps.max_pixel_vco; + si->ps.max_dac1_clock = si->ps.max_dac1_clock_8; + si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32; + si->ps.std_engine_clock_dh = si->ps.std_engine_clock; + si->ps.sdram = (si->ps.v3_clk_div & 0x10); + /* not supported: */ + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_24 = 0; + /* see G100, G200 and G400 specs */ + si->ps.min_system_vco = 50; + si->ps.min_pixel_vco = 50; + /* fixme: ehhh, no specs: confirm/tune these by testing?! */ + si->ps.max_video_vco = si->ps.max_pixel_vco; + si->ps.min_video_vco = 50; + /* assuming G100, G200 MAVEN has same specs as G400 MAVEN */ + si->ps.max_dac2_clock = 136; + si->ps.max_dac2_clock_16 = 136; + si->ps.max_dac2_clock_32dh = 136; + si->ps.max_dac2_clock_32 = 136; + return B_OK; +} + +/* pins v4 is used by G400 */ +status_t pins4_read(uint8 *pins, uint8 length) +{ + if (length != 128) + { + LOG(8,("INFO: wrong PINS length, expected 128, got %d\n", length)); + return B_ERROR; + } + + /* fill out the shared info si->ps struct */ + if (pins[39] == 0xff) si->ps.max_pixel_vco = 230; + else si->ps.max_pixel_vco = 4 * pins[39]; + + if (pins[38] == 0xff) si->ps.max_system_vco = si->ps.max_pixel_vco; + else si->ps.max_system_vco = 4 * pins[38]; + + if (pins[40] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco; + else si->ps.max_dac1_clock_8 = 4 * pins[40]; + + if (pins[41] == 0xff) si->ps.max_dac1_clock_16 = si->ps.max_dac1_clock_8; + else si->ps.max_dac1_clock_16 = 4 * pins[41]; + + if (pins[42] == 0xff) si->ps.max_dac1_clock_24 = si->ps.max_dac1_clock_16; + else si->ps.max_dac1_clock_24 = 4 * pins[42]; + + if (pins[43] == 0xff) si->ps.max_dac1_clock_32 = si->ps.max_dac1_clock_24; + else si->ps.max_dac1_clock_32 = 4 * pins[43]; + + if (pins[44] == 0xff) si->ps.max_dac2_clock_16 = si->ps.max_pixel_vco; + else si->ps.max_dac2_clock_16 = 4 * pins[44]; + + if (pins[45] == 0xff) si->ps.max_dac2_clock_32 = si->ps.max_dac2_clock_16; + else si->ps.max_dac2_clock_32 = 4 * pins[45]; + + /* verified against windows driver: */ + si->ps.std_engine_clock = 2 * pins[65]; + + if (pins[92] & 0x01) si->ps.f_ref = 14.31818; + else si->ps.f_ref = 27.00000; + + si->ps.memory_size = 4 << ((pins[92] >> 2) & 0x03); + + /* for cards using this version of PINS both functions are in maven */ + si->ps.secondary_head = !(pins[91] & 0x01); + si->ps.secondary_tvout = !(pins[91] & 0x01); + + /* assuming the only possible panellink will be on the first head */ + si->ps.primary_dvi = !(pins[91] & 0x40); + /* logical consequence of the above */ + si->ps.secondary_dvi = false; + + /* indirect logical consequences, see also G100, G200 and G400 specs */ + si->ps.max_dac1_clock = si->ps.max_dac1_clock_8; + si->ps.max_dac2_clock = si->ps.max_dac2_clock_16; + si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32; + si->ps.max_dac2_clock_32dh = si->ps.max_dac2_clock_32; + si->ps.std_engine_clock_dh = si->ps.std_engine_clock; + /* not supported: */ + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_24 = 0; + /* see G100, G200 and G400 specs */ + si->ps.min_system_vco = 50; + si->ps.min_pixel_vco = 50; + /* fixme: ehhh, no specs: confirm/tune these by testing?! */ + si->ps.max_video_vco = si->ps.max_pixel_vco; + si->ps.min_video_vco = 50; + +//todo: +// uint32 mctlwtst_reg; +// uint32 option_reg; +// bool sdram; + + /* not used here: */ + si->ps.v3_clk_div = 0; + si->ps.v3_mem_type = 0; + return B_OK; +} + +/* pins v5 is used by G450 and G550 */ +status_t pins5_read(uint8 *pins, uint8 length) +{ + unsigned int m_factor = 6; + + if (length != 128) + { + LOG(8,("INFO: wrong PINS length, expected 128, got %d\n", length)); + return B_ERROR; + } + + /* fill out the shared info si->ps struct */ + if (pins[4]) m_factor = 8; + + si->ps.max_system_vco = m_factor * pins[36]; + si->ps.max_video_vco = m_factor * pins[37]; + /* pixelVCO multiplier is 10 if pins V5.2 */ + if (pins[4] == 0x02) si->ps.max_pixel_vco = 10 * pins[38]; + else si->ps.max_pixel_vco = m_factor * pins[38]; + si->ps.min_system_vco = m_factor * pins[121]; + si->ps.min_video_vco = m_factor * pins[122]; + /* pixelVCO multiplier is 10 if pins V5.2 */ + if (pins[4] == 0x02) si->ps.min_pixel_vco = 10 * pins[123]; + else si->ps.min_pixel_vco = m_factor * pins[123]; + + if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco; + else si->ps.max_dac1_clock_8 = 4 * pins[39]; + + if (pins[40] == 0xff) si->ps.max_dac1_clock_16 = si->ps.max_dac1_clock_8; + else si->ps.max_dac1_clock_16 = 4 * pins[40]; + + if (pins[41] == 0xff) si->ps.max_dac1_clock_24 = si->ps.max_dac1_clock_16; + else si->ps.max_dac1_clock_24 = 4 * pins[41]; + + if (pins[42] == 0xff) si->ps.max_dac1_clock_32 = si->ps.max_dac1_clock_24; + else si->ps.max_dac1_clock_32 = 4 * pins[42]; + + if (pins[124] == 0xff) si->ps.max_dac1_clock_32dh = si->ps.max_dac1_clock_32; + else si->ps.max_dac1_clock_32dh = 4 * pins[124]; + + if (pins[43] == 0xff) si->ps.max_dac2_clock_16 = si->ps.max_video_vco; + else si->ps.max_dac2_clock_16 = 4 * pins[43]; + + if (pins[44] == 0xff) si->ps.max_dac2_clock_32 = si->ps.max_dac2_clock_16; + else si->ps.max_dac2_clock_32 = 4 * pins[44]; + + if (pins[125] == 0xff) si->ps.max_dac2_clock_32dh = si->ps.max_dac2_clock_32; + else si->ps.max_dac2_clock_32dh = 4 * pins[125]; + + if (pins[118] == 0xff) si->ps.max_dac1_clock = si->ps.max_dac1_clock_8; + else si->ps.max_dac1_clock = 4 * pins[118]; + + if (pins[119] == 0xff) si->ps.max_dac2_clock = si->ps.max_dac1_clock; + else si->ps.max_dac2_clock = 4 * pins[119]; + + si->ps.std_engine_clock = 4 * pins[74]; + si->ps.std_engine_clock_dh = 4 * pins[92]; + + si->ps.memory_size = ((pins[114] & 0x03) + 1) * 8; + if ((pins[114] & 0x07) > 3) + { + LOG(2,("INFO: unknown RAM size, defaulting to 8Mb\n")); + si->ps.memory_size = 8; + } + + if (pins[110] & 0x01) si->ps.f_ref = 14.31818; + else si->ps.f_ref = 27.00000; + + si->ps.secondary_head = (pins[117] & 0x70); + si->ps.secondary_tvout = (pins[117] & 0x40); + si->ps.primary_dvi = (pins[117] & 0x02); + si->ps.secondary_dvi = (pins[117] & 0x20); + + /* not supported: */ + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_24 = 0; + +//todo: +// uint32 mctlwtst_reg; +// uint32 option_reg; +// bool sdram; + + /* not used here: */ + si->ps.v3_clk_div = 0; + si->ps.v3_mem_type = 0; + return B_OK; +} + +/* fake_pins presumes the card was coldstarted by it's BIOS */ +void fake_pins(void) +{ + LOG(8,("INFO: faking PINS\n")); + + switch (si->ps.card_type) + { + case MIL2: + pinsmil2_fake(); + break; + case G100: + pinsg100_fake(); + break; + case G200: + pinsg200_fake(); + break; + case G400: + pinsg400_fake(); + break; + case G400MAX: + pinsg400max_fake(); + break; + case G450: + pinsg450_fake(); + break; + case G550: + pinsg550_fake(); + break; + } + + /* find out if the card has a maven */ + if (i2c_maven_probe() == B_OK) + { + si->ps.secondary_tvout = true; + si->ps.secondary_head = true; + } + else + { + si->ps.secondary_tvout = false; + si->ps.secondary_head = false; + } + + /* not used because no coldstart will be attempted */ + si->ps.std_engine_clock = 0; + si->ps.std_engine_clock_dh = 0; + si->ps.mctlwtst_reg = 0; + si->ps.option_reg = 0; + si->ps.v3_clk_div = 0; + si->ps.v3_mem_type = 0; +} + +void pinsmil2_fake(void) +{ +} + +void pinsg100_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G100 specs */ + si->ps.max_system_vco = 230; + si->ps.min_system_vco = 50; + si->ps.max_pixel_vco = 230; + si->ps.min_pixel_vco = 50; + /* no specs, assuming these */ + si->ps.max_video_vco = 230; + si->ps.min_video_vco = 50; + /* see G100 specs */ + si->ps.max_dac1_clock = 230; + si->ps.max_dac1_clock_8 = 230; + si->ps.max_dac1_clock_16 = 230; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 180; + si->ps.max_dac1_clock_32 = 136; + si->ps.max_dac1_clock_32dh = 136; + /* see specs */ + si->ps.max_dac2_clock = 136; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 136; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 136; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 136; + /* assuming the only possible panellink will be on the first head */ + //fixme: primary_dvi should be overrule-able via mga.settings for G100. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 2Mb RAM mounted */ + si->ps.memory_size = 2; + //fixme: should be overrule-able via mga.settings for G100. + si->ps.sdram = true; +} + +void pinsg200_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G200 specs */ + si->ps.max_system_vco = 250; + si->ps.min_system_vco = 50; + si->ps.max_pixel_vco = 250; + si->ps.min_pixel_vco = 50; + /* no specs, assuming these */ + si->ps.max_video_vco = 250; + si->ps.min_video_vco = 50; + /* see G200 specs */ + 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 = 180; + si->ps.max_dac1_clock_32 = 136; + si->ps.max_dac1_clock_32dh = 136; + /* see specs */ + si->ps.max_dac2_clock = 136; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 136; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 136; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 136; + /* assuming the only possible panellink will be on the first head */ + //fixme: primary_dvi should be overrule-able via mga.settings for G100. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 2Mb RAM mounted */ + si->ps.memory_size = 2; + /* ask the G200 what type of RAM it has been set to by it's BIOS */ + si->ps.sdram = !(CFGR(OPTION) & 0x00004000); +} + +void pinsg400_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G400 specs */ + si->ps.max_system_vco = 300; + si->ps.min_system_vco = 50; + si->ps.max_pixel_vco = 300; + si->ps.min_pixel_vco = 50; + /* no specs, assuming these */ + si->ps.max_video_vco = 300; + si->ps.min_video_vco = 50; + /* see G400 specs */ + 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 = 230; + si->ps.max_dac1_clock_32 = 180; + si->ps.max_dac1_clock_32dh = 136; + /* see specs */ + si->ps.max_dac2_clock = 136; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 136; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 136; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 136; + /* assuming the only possible panellink will be on the first head */ + //fixme: primary_dvi should be overrule-able via mga.settings for G400. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 4Mb RAM mounted */ + si->ps.memory_size = 4; + /* ask the G400 what type of RAM it has been set to by it's BIOS */ +//todo: +// si->ps.sdram = !(CFGR(OPTION) & 0x00004000); +//end todo. +} + +void pinsg400max_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G400MAX specs */ + si->ps.max_system_vco = 360; + si->ps.min_system_vco = 50; + si->ps.max_pixel_vco = 360; + si->ps.min_pixel_vco = 50; + /* no specs, assuming these */ + si->ps.max_video_vco = 360; + si->ps.min_video_vco = 50; + /* see G400MAX specs */ + si->ps.max_dac1_clock = 360; + si->ps.max_dac1_clock_8 = 360; + si->ps.max_dac1_clock_16 = 360; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 280; + si->ps.max_dac1_clock_32 = 230; + si->ps.max_dac1_clock_32dh = 136; + /* see specs */ + si->ps.max_dac2_clock = 136; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 136; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 136; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 136; + /* assuming the only possible panellink will be on the first head */ + //fixme: primary_dvi should be overrule-able via mga.settings for G400MAX. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 4Mb RAM mounted */ + si->ps.memory_size = 4; + /* ask the G400MAX what type of RAM it has been set to by it's BIOS */ +//todo: +// si->ps.sdram = !(CFGR(OPTION) & 0x00004000); +} + +void pinsg450_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G450 pins readouts for max ranges, then use a bit smaller ones */ + /* carefull not to take to high lower limits, and high should be >= 2x low. */ + si->ps.max_system_vco = 600; + si->ps.min_system_vco = 256; + si->ps.max_pixel_vco = 640; + si->ps.min_pixel_vco = 320; + si->ps.max_video_vco = 600; + si->ps.min_video_vco = 256; + si->ps.max_dac1_clock = 360; + si->ps.max_dac1_clock_8 = 360; + si->ps.max_dac1_clock_16 = 360; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 280; + si->ps.max_dac1_clock_32 = 230; + si->ps.max_dac1_clock_32dh = 180; + /* see G450 pins readouts */ + si->ps.max_dac2_clock = 232; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 232; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 232; + /* 'failsave' values */ + si->ps.max_dac2_clock_32dh = 180; + //fixme: primary & secondary_dvi should be overrule-able via mga.settings for G450. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 8Mb RAM mounted */ + si->ps.memory_size = 8; + /* ask the G450 what type of RAM it has been set to by it's BIOS */ +//todo: +// si->ps.sdram = !(CFGR(OPTION) & 0x00004000); +} + +void pinsg550_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + //fixme: should be overrule-able via mga.settings. + si->ps.f_ref = 27.000; + /* see G550 pins readouts for max ranges, then use a bit smaller ones */ + /* carefull not to take to high lower limits, and high should be >= 2x low. */ + si->ps.max_system_vco = 768; + si->ps.min_system_vco = 384; + si->ps.max_pixel_vco = 960; + si->ps.min_pixel_vco = 320; + si->ps.max_video_vco = 600; + si->ps.min_video_vco = 256; + si->ps.max_dac1_clock = 360; + si->ps.max_dac1_clock_8 = 360; + si->ps.max_dac1_clock_16 = 360; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 280; + si->ps.max_dac1_clock_32 = 230; + si->ps.max_dac1_clock_32dh = 180; + /* see G550 pins readouts */ + si->ps.max_dac2_clock = 232; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 232; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 232; + /* 'failsave' values */ + si->ps.max_dac2_clock_32dh = 180; + //fixme: primary & secondary_dvi should be overrule-able via mga.settings for G550. + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 8Mb RAM mounted */ + si->ps.memory_size = 8; + /* ask the G550 what type of RAM it has been set to by it's BIOS */ +//todo: +// si->ps.sdram = !(CFGR(OPTION) & 0x00004000); +} + +void dump_pins(void) +{ + LOG(2,("INFO: pinsdump follows:\n")); + LOG(2,("f_ref: %fMhz\n", si->ps.f_ref)); + LOG(2,("max_system_vco: %dMhz\n", si->ps.max_system_vco)); + LOG(2,("min_system_vco: %dMhz\n", si->ps.min_system_vco)); + LOG(2,("max_pixel_vco: %dMhz\n", si->ps.max_pixel_vco)); + LOG(2,("min_pixel_vco: %dMhz\n", si->ps.min_pixel_vco)); + LOG(2,("max_video_vco: %dMhz\n", si->ps.max_video_vco)); + LOG(2,("min_video_vco: %dMhz\n", si->ps.min_video_vco)); + LOG(2,("std_engine_clock: %dMhz\n", si->ps.std_engine_clock)); + LOG(2,("std_engine_clock_dh: %dMhz\n", si->ps.std_engine_clock_dh)); + 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,("secondary_tvout: ")); + if (si->ps.secondary_tvout) LOG(2,("present\n")); else LOG(2,("absent\n")); + LOG(2,("primary_dvi: ")); + if (si->ps.primary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n")); + LOG(2,("secondary_dvi: ")); + if (si->ps.secondary_dvi) LOG(2,("present\n")); else LOG(2,("absent\n")); + LOG(2,("card memory_size: %dMb\n", si->ps.memory_size)); + LOG(2,("mctlwtst register: $%08x\n", si->ps.mctlwtst_reg)); + LOG(2,("option register: $%08x\n", si->ps.option_reg)); + LOG(2,("v3_clock_div: $%02x\n", si->ps.v3_clk_div)); + LOG(2,("v3_mem_type: $%02x\n", si->ps.v3_mem_type)); + LOG(2,("sdram: ")); + if (si->ps.sdram) LOG(2,("SDRAM card\n")); else LOG(2,("SGRAM card\n")); + LOG(2,("INFO: end pinsdump.\n")); +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_maven.c b/src/add-ons/accelerants/matrox/engine/mga_maven.c new file mode 100644 index 0000000000..d6058700bb --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_maven.c @@ -0,0 +1,172 @@ +/* program the MAVEN in monitor mode */ +/* Thanx to Petr Vandrovec for info on the MAVEN */ +/* Mark Watson 6/2000 */ + +#define MODULE_BIT 0x00001000 + +#include "mga_std.h" + +status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v) +{ + if (display&h&v) + { + MAVW(MONEN,0xb2); + MAVW(MONSET,0x20); /*must be set to this in monitor mode*/ + MAVW(OUTMODE,3); /*monitor mode*/ + MAVW(STABLE,0x22); /*makes picture stable?*/ + MAVW(TEST,0x00); /*turn off test signal*/ + } + else + { + /*turn off screen using a few methods!*/ + MAVW(STABLE,0x6a); +// MAVW(TEST,0x3); + MAVW(OUTMODE,0x00); + } + + return B_OK; +} + +/*set a mode line - inputs are in pixels/scanlines*/ +status_t gx00_maven_set_timing( + uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, + uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, + uint8 hsync_pos,uint8 vsync_pos + ) +{ + LOG(4,("MAVEN: setting timing\n")); + + /*check horizontal timing parameters are to nearest 8 pixels*/ + if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7)) + { + LOG(8,("MAVEN:Horizontal timings are not multiples of 8 pixels\n")); + return B_ERROR; + } + + /*program the MAVEN*/ + MAVWW(LASTLINEL,htotal); + MAVWW(HSYNCLENL,(hsync_e-hsync_s)); + MAVWW(HSYNCSTRL,(htotal-hsync_s)); + MAVWW(HDISPLAYL,(htotal-hsync_s+hdisp_e)); + MAVWW(HTOTALL,(htotal+1)); + + MAVWW(VSYNCLENL,(vsync_e-vsync_s-1)); + MAVWW(VSYNCSTRL,(vtotal-vsync_s)); + MAVWW(VDISPLAYL,(vtotal-1)); + MAVWW(VTOTALL,(vtotal-1)); + + MAVWW(HVIDRSTL,(htotal-si->crtc_delay)); + MAVWW(VVIDRSTL,(vtotal-2)); + + return B_OK; +} + +void gx00_maven_delay(int number) +{ + MAVWW(HVIDRSTL,(si->dm.timing.h_total-number)); +} + +/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ +status_t gx00_maven_mode(int mode,float brightness) +{ + uint8 luma; + + /*set luma to a suitable value for brightness*/ + /*assuming 1A is a sensible value*/ + luma = (uint8)(0x1a * brightness); + MAVW(LUMA,luma); + LOG(4,("MAVEN: LUMA setting - %x\n",luma)); + + return B_OK; +} + +/*program the pixpll on the maven - frequency in kHz*/ +status_t gx00_maven_set_pix_pll(float f_vco) +{ + uint8 m=0,n=0,p=0; + + float pix_setting; + status_t result; + + LOG(4,("MAVEN:Setting PIX PLL %fMHz\n", f_vco)); + + result = gx00_maven_pix_pll_find(f_vco,&pix_setting,&m,&n,&p); + if (result != B_OK) + { + return result; + } + + /*reprogram (select,wait for stability)*/ + MAVW(PIXPLLM,(m)); /*set m value*/ + MAVW(PIXPLLN,(n)); /*set n value*/ + MAVW(PIXPLLP,(p|0x80)); /*set p value*/ + LOG(2,("MAVEN: Clocks found: %x %x %x\n",m,n,p)); + delay(1000); /*wait 1000us for PIXPLL to lock (no way of knowing)*/ + LOG(2,("MAVEN: PIX PLL frequency locked\n")); + + return B_OK; +} + +/*find nearest valid pix pll*/ +status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uint8 * n_result,uint8 * p_result) +{ + float f_ref=27.000; + int n_min=4; + int n_max=127; + int m_min=2; + int m_max=31; + int m=0,n=0,p=0; + float error; + float error_best; + int best[3]; + float f_rat; + + LOG(4,("MAVEN:Checking PIX PLL %fMHz\n", f_vco)); + + /*f_rat.m/p=n where m=M+1,n=N+1,p=P+1,f_rat=f_vco/f_ref*/ + f_rat = f_vco/f_ref; + error_best = 999999999; + for (p=0x2 -1*(f_vco>80.0);p<0x10;p=p<<1) + { + for (m=m_min;mn_max || n spot the Perl coder :-)*/ + { + if(f_vco>180) {p|=0x18;break;}; + if(f_vco>140) {p|=0x10;break;}; + if(f_vco>100) {p|=0x08;break;}; + break; + } + + /*set the result*/ + *result = (float) (f_ref*n)/(m*(p&0x7)); + *m_result = m-1; + *n_result = n-1; + *p_result = p-1; + + /*display the found value*/ + LOG(4,("MAVEN: pixpllcheck - requested %fMHz got %fMHz\n",(double)f_vco,*result)); + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_proto.h b/src/add-ons/accelerants/matrox/engine/mga_proto.h new file mode 100644 index 0000000000..13d829fcd8 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_proto.h @@ -0,0 +1,131 @@ +/*general card functions*/ +status_t gx00_general_powerup(); +status_t mga_set_cas_latency(); +status_t gx00_general_dac_select(int); +status_t gx00_general_wait_retrace(); +//status_t gx00_general_bios_to_powergraphics(); + +/* apsed: logging macros */ +#define MSG(args) do { /* if needed or si->settings with si NULL */ \ + mga_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) mga_log args; \ +} while (0) + +/*support functions*/ +void delay(bigtime_t i); +void mga_log(char *format, ...); + +/*i2c maven 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 g450_card_info(); +status_t g400_card_info(); +status_t g200_card_info(); +status_t parse_pins(void); +status_t pins1_read(uint8 *pins, uint8 length); +status_t pins2_read(uint8 *pins, uint8 length); +status_t pins3_read(uint8 *pins, uint8 length); +status_t pins4_read(uint8 *pins, uint8 length); +status_t pins5_read(uint8 *pins, uint8 length); +void fake_pins(void); +void pinsmil2_fake(void); +void pinsg100_fake(void); +void pinsg200_fake(void); +void pinsg400_fake(void); +void pinsg400max_fake(void); +void pinsg450_fake(void); +void pinsg550_fake(void); +void dump_pins(void); + +/*DAC functions*/ +status_t gx00_dac_mode(int,float); +status_t gx00_dac_palette(uint8*,uint8*,uint8*); + +status_t gx00_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *, uint8); +status_t gx00_dac_set_pix_pll(display_mode target); + +status_t g400_dac_set_sys_pll(); +status_t g200_dac_set_sys_pll(); +status_t g100_dac_set_sys_pll(); + +status_t mil2_dac_init(void); +status_t mil2_dac_mode(int,float, int hsync_pos,int vsync_pos, int sync_green); +status_t mil2_dac_palette(uint8*,uint8*,uint8*); +status_t mil2_dac_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *); +status_t mil2_dac_set_pix_pll(float f_vco,int bpp); + +/*MAVEN functions*/ +status_t gx00_maven_dpms(uint8,uint8,uint8); +status_t gx00_maven_set_timing( + uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, + uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, + uint8 hsync_pos,uint8 vsync_pos + ); +status_t gx00_maven_mode(int,float); + +status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *); +status_t gx00_maven_set_pix_pll(float f_vco); + +/*CRTC1 functions*/ +status_t gx00_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 gx00_crtc_set_timing( + uint16 hd_e,uint16 hs_s,uint16 hs_e,uint16 ht, + uint16 vd_e,uint16 vs_s,uint16 vs_e,uint16 vt, + uint8 hsync_pos,uint8 vsync_pos +); +status_t gx00_crtc_depth(int mode); +status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp); +status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp); + +status_t gx00_crtc_dpms(uint8,uint8,uint8); +status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*); +status_t gx00_crtc_mem_priority(uint8); + +status_t gx00_crtc_cursor_init(); /*Yes, cursor follows CRTC1 - not the DAC!*/ +status_t gx00_crtc_cursor_define(uint8*,uint8*); +status_t gx00_crtc_cursor_position(uint16 x ,uint16 y); +status_t gx00_crtc_cursor_show(); +status_t gx00_crtc_cursor_hide(); + +/*CRTC2 functions*/ +/*XXX - validate_timing*/ +status_t g400_crtc2_set_timing( + uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, + uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, + uint8 hsync_pos,uint8 vsync_pos + ); +status_t g400_crtc2_depth(int mode); +status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp); +status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp); + +status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v); +status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v); + +/*acceleration functions*/ +status_t gx00_acc_init(); +status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); +status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); +status_t gx00_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 ); +status_t gx00_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32); +status_t gx00_acc_wait_idle(); + +/*backend scaler functions*/ +status_t check_overlay_capability(uint32 feature); +status_t gx00_configure_bes(const overlay_buffer *ob, const overlay_window *ow, int offset); +status_t gx00_release_bes(); + +/*driver structures and enums*/ +enum{BPP8=0,BPP15=1,BPP16=2,BPP24=3,BPP32DIR=4,BPP32=7}; +enum{DS_CRTCDAC_CRTC2MAVEN, DS_CRTCMAVEN_CRTC2DAC, DS_CRTCDAC_CRTC2DAC2, DS_CRTCDAC_CRTCDAC2}; diff --git a/src/add-ons/accelerants/matrox/engine/mga_std.h b/src/add-ons/accelerants/matrox/engine/mga_std.h new file mode 100644 index 0000000000..bfffb19902 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_std.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include "DriverInterface.h" +#include "global.h" +//apsed #include "mga_extern.h" +#include "mga_proto.h" +#include "mga_macros.h" diff --git a/src/add-ons/accelerants/matrox/engine/mga_support.c b/src/add-ons/accelerants/matrox/engine/mga_support.c new file mode 100644 index 0000000000..1c8473c794 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_support.c @@ -0,0 +1,30 @@ +/* Some commmon support functions */ +/* Mark Watson 2/2000 */ + +#define MODULE_BIT 0x00000800 + +#include +#include "mga_std.h" + +/*delays in multiple of microseconds*/ +void delay(bigtime_t i) +{ + bigtime_t start=system_time(); + while(system_time()-start