From 77680cef2a516c2ae69ec6cbf9c11e8c212da886 Mon Sep 17 00:00:00 2001 From: shatty Date: Mon, 1 Dec 2003 06:02:10 +0000 Subject: [PATCH] openBeOS_Neomagic_V0.03_src git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5514 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/accelerants/Jamfile | 1 + .../accelerants/neomagic/Acceleration.c | 131 ++++ src/add-ons/accelerants/neomagic/Cursor.c | 123 ++++ .../accelerants/neomagic/EngineManagment.c | 68 ++ .../accelerants/neomagic/GetAccelerantHook.c | 239 ++++++ .../accelerants/neomagic/GetDeviceInfo.c | 44 ++ .../accelerants/neomagic/GetModeInfo.c | 90 +++ .../neomagic/GetTimingConstraints.c | 30 + src/add-ons/accelerants/neomagic/GlobalData.c | 35 + .../accelerants/neomagic/InitAccelerant.c | 313 ++++++++ src/add-ons/accelerants/neomagic/Jamfile | 26 + src/add-ons/accelerants/neomagic/Overlay.c | 648 ++++++++++++++++ .../accelerants/neomagic/ProposeDisplayMode.c | 389 ++++++++++ .../accelerants/neomagic/SetDisplayMode.c | 309 ++++++++ src/add-ons/accelerants/neomagic/acc_std.h | 16 + .../accelerants/neomagic/be_driver_proto.h | 66 ++ .../accelerants/neomagic/engine/Jamfile | 15 + .../accelerants/neomagic/engine/nm_acc.c | 350 +++++++++ .../accelerants/neomagic/engine/nm_bes.c | 694 +++++++++++++++++ .../accelerants/neomagic/engine/nm_crtc.c | 696 ++++++++++++++++++ .../accelerants/neomagic/engine/nm_dac.c | 319 ++++++++ .../accelerants/neomagic/engine/nm_general.c | 514 +++++++++++++ .../accelerants/neomagic/engine/nm_info.c | 284 +++++++ .../accelerants/neomagic/engine/nm_proto.h | 75 ++ .../accelerants/neomagic/engine/nm_std.h | 8 + .../accelerants/neomagic/engine/nm_support.c | 30 + src/add-ons/accelerants/neomagic/global.h | 11 + .../accelerants/neomagic/valid_mode_list | 34 + 28 files changed, 5558 insertions(+) create mode 100644 src/add-ons/accelerants/neomagic/Acceleration.c create mode 100644 src/add-ons/accelerants/neomagic/Cursor.c create mode 100644 src/add-ons/accelerants/neomagic/EngineManagment.c create mode 100644 src/add-ons/accelerants/neomagic/GetAccelerantHook.c create mode 100644 src/add-ons/accelerants/neomagic/GetDeviceInfo.c create mode 100644 src/add-ons/accelerants/neomagic/GetModeInfo.c create mode 100644 src/add-ons/accelerants/neomagic/GetTimingConstraints.c create mode 100644 src/add-ons/accelerants/neomagic/GlobalData.c create mode 100644 src/add-ons/accelerants/neomagic/InitAccelerant.c create mode 100644 src/add-ons/accelerants/neomagic/Jamfile create mode 100644 src/add-ons/accelerants/neomagic/Overlay.c create mode 100644 src/add-ons/accelerants/neomagic/ProposeDisplayMode.c create mode 100644 src/add-ons/accelerants/neomagic/SetDisplayMode.c create mode 100644 src/add-ons/accelerants/neomagic/acc_std.h create mode 100644 src/add-ons/accelerants/neomagic/be_driver_proto.h create mode 100644 src/add-ons/accelerants/neomagic/engine/Jamfile create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_acc.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_bes.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_crtc.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_dac.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_general.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_info.c create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_proto.h create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_std.h create mode 100644 src/add-ons/accelerants/neomagic/engine/nm_support.c create mode 100644 src/add-ons/accelerants/neomagic/global.h create mode 100644 src/add-ons/accelerants/neomagic/valid_mode_list diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index cacf5aedcf..3baecdc624 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -1,3 +1,4 @@ SubDir OBOS_TOP src add-ons accelerants ; +SubInclude OBOS_TOP src add-ons accelerants neomagic ; SubInclude OBOS_TOP src add-ons accelerants nvidia ; diff --git a/src/add-ons/accelerants/neomagic/Acceleration.c b/src/add-ons/accelerants/neomagic/Acceleration.c new file mode 100644 index 0000000000..b3ba08e8d0 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/Acceleration.c @@ -0,0 +1,131 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 4/2003- +*/ + +#define MODULE_BIT 0x40000000 + +#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--) + { + mn_acc_blit + ( + list[i].src_left, + list[i].src_top, + list[i].dest_left, + list[i].dest_top, + list[i].width, + list[i].height + ); + i++; + } +} + +void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { + int i; + + /*do each blit*/ + i=0; + while (count--) + { + mn_acc_video_blit + ( + list[i].src_left, + list[i].src_top, + list[i].src_width, + list[i].src_height, + list[i].dest_left, + list[i].dest_top, + list[i].dest_width, + list[i].dest_height + ); + i++; + } +} + +void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) { + int i; + + /*do each blit*/ + i=0; + while (count--) + { + mn_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--) + { + mn_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--) + { + mn_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--) + { + mn_acc_rectangle + ( + list[i+1], + list[i+2]+1, + list[i], + 1, + colorIndex + ); + i+=3; + } +} diff --git a/src/add-ons/accelerants/neomagic/Cursor.c b/src/add-ons/accelerants/neomagic/Cursor.c new file mode 100644 index 0000000000..416f673403 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/Cursor.c @@ -0,0 +1,123 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x20000000 + +#include "acc_std.h" + +status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask) +{ + LOG(4,("SET_CURSOR_SHAPE: width %d, height %d, hot_x %d, hot_y %d\n", + width, height, hot_x, hot_y)); + + if ((width != 16) || (height != 16)) + { + return B_ERROR; + } + else if ((hot_x >= width) || (hot_y >= height)) + { + return B_ERROR; + } + else + { + mn_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; + uint16 h_display = si->dm.timing.h_display; /* local copy needed for flatpanel */ + uint16 v_display = si->dm.timing.v_display; /* local copy needed for flatpanel */ + + /* 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; + + switch(si->dm.space) + { + case B_CMAP8: + h_adjust = 0x03; + break; + case B_RGB15_LITTLE:case B_RGB16_LITTLE: + h_adjust = 0x01; + break; + case B_RGB32_LITTLE: + h_adjust = 0x00; + break; + default: + h_adjust = 0x03; + break; + } + + /* if internal panel is active correct visible screensize! */ + if (nm_general_output_read() & 0x02) + { + if (h_display > si->ps.panel_width) h_display = si->ps.panel_width; + if (v_display > si->ps.panel_height) v_display = si->ps.panel_height; + } + + /* adjust h/v_display_start to move cursor onto screen */ + if (x >= (h_display + hds)) + { + hds = ((x - h_display) + 1 + h_adjust) & ~h_adjust; + /* make sure we stay within the display! */ + if ((hds + h_display) > si->dm.virtual_width) + hds -= (h_adjust + 1); + } + else if (x < hds) + hds = x & ~h_adjust; + + if (y >= (v_display + vds)) + vds = y - v_display + 1; + else if (y < vds) + vds = y; + + /* reposition the desktop _and_ the overlay on the display if required */ + if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start)) + { + MOVE_DISPLAY(hds,vds); + //fixme: implement: + //move_overlay(hds,vds); + } + + /* put cursor in correct physical position */ + if (x > (hds + si->cursor.hot_x)) x -= hds + si->cursor.hot_x; + else x = 0; + if (y > (vds + si->cursor.hot_y)) y -= vds + si->cursor.hot_y; + else y = 0; + + /* position the cursor on the display */ + mn_crtc_cursor_position(x,y); +} + +void SHOW_CURSOR(bool is_visible) +{ + /* record for our info */ + si->cursor.is_visible = is_visible; + + if (is_visible) + mn_crtc_cursor_show(); + else + mn_crtc_cursor_hide(); +} diff --git a/src/add-ons/accelerants/neomagic/EngineManagment.c b/src/add-ons/accelerants/neomagic/EngineManagment.c new file mode 100644 index 0000000000..0a80b6dac1 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/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 mn_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 = &mn_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; + mn_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/neomagic/GetAccelerantHook.c b/src/add-ons/accelerants/neomagic/GetAccelerantHook.c new file mode 100644 index 0000000000..c52135a4a5 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/GetAccelerantHook.c @@ -0,0 +1,239 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 10/2002-4/2003 +*/ + +#define MODULE_BIT 0x08000000 + +#include "acc_std.h" + +/* +The standard entry point. Given a uint32 feature identifier, this routine +returns a pointer to the function that implements the feature. Some features +require more information than just the identifier to select the proper +function. The extra information (which is specific to the feature) is +pointed at by the void *data parameter. By default, no extra information +is available. Any extra information available to choose the function will be +noted on a case by case below. +*/ + +/* +These definitions are out of pure lazyness. +*/ +#define CHKO(x) case B_##x: \ + if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 +#define CHKA(x) case B_##x: \ + if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 +#define HOOK(x) case B_##x: return (void *)x +#define ZERO(x) case B_##x: return (void *)0 +#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; + +void * get_accelerant_hook(uint32 feature, void *data) +{ + switch (feature) + { + /* + One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and + subsequently called before any other hook is requested. All other feature + hook selections can be predicated on variables assigned during the accelerant + initialization process. + */ + + /* initialization */ + HOOK(INIT_ACCELERANT); + HOOK(CLONE_ACCELERANT); + + HOOK(ACCELERANT_CLONE_INFO_SIZE); + HOOK(GET_ACCELERANT_CLONE_INFO); + HOOK(UNINIT_ACCELERANT); + HOOK(GET_ACCELERANT_DEVICE_INFO); + HOOK(ACCELERANT_RETRACE_SEMAPHORE); + + /* mode configuration */ + HOOK(ACCELERANT_MODE_COUNT); + HOOK(GET_MODE_LIST); + HOOK(PROPOSE_DISPLAY_MODE); + HOOK(SET_DISPLAY_MODE); + HOOK(GET_DISPLAY_MODE); + HOOK(GET_FRAME_BUFFER_CONFIG); + HOOK(GET_PIXEL_CLOCK_LIMITS); + HOOK(MOVE_DISPLAY); + HOOK(SET_INDEXED_COLORS); + HOOK(GET_TIMING_CONSTRAINTS); + + HOOK(DPMS_CAPABILITIES); + HOOK(DPMS_MODE); + HOOK(SET_DPMS_MODE); + + /* cursor managment */ + HRDC(SET_CURSOR_SHAPE); + HRDC(MOVE_CURSOR); + HRDC(SHOW_CURSOR); + + /* synchronization */ + HOOK(ACCELERANT_ENGINE_COUNT); + HOOK(ACQUIRE_ENGINE); + HOOK(RELEASE_ENGINE); + HOOK(WAIT_ENGINE_IDLE); + HOOK(GET_SYNC_TOKEN); + HOOK(SYNC_TO_TOKEN); + + /* + Depending on the engine architecture, you may choose to provide a different + function to be used with each bit-depth for example. + + Note: These hooks are re-acquired by the app_server after each mode switch. + */ + + /* only export video overlay functions if card is capable of it */ + CHKO(OVERLAY_COUNT); + CHKO(OVERLAY_SUPPORTED_SPACES); + CHKO(OVERLAY_SUPPORTED_FEATURES); + CHKO(ALLOCATE_OVERLAY_BUFFER); + CHKO(RELEASE_OVERLAY_BUFFER); + CHKO(GET_OVERLAY_CONSTRAINTS); + CHKO(ALLOCATE_OVERLAY); + CHKO(RELEASE_OVERLAY); + CHKO(CONFIGURE_OVERLAY); + + /* + When requesting an acceleration hook, the calling application provides a + pointer to the display_mode for which the acceleration function will be used. + Depending on the engine architecture, you may choose to provide a different + function to be used with each bit-depth. In the sample driver we return + the same function all the time. + + Note: These hooks are re-acquired by the app_server after each mode switch. + */ + + /* only export 2D acceleration functions in modes that are capable of it */ + /* used by the app_server and applications (BWindowScreen) */ + CHKA(SCREEN_TO_SCREEN_BLIT); + CHKA(FILL_RECTANGLE); + CHKA(INVERT_RECTANGLE); + CHKA(FILL_SPAN); + /* not (yet) used by the app_server: + * so just for application use (BWindowScreen) */ + CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT); + //CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT; + } + + /* Return a null pointer for any feature we don't understand. */ + return 0; +} +#undef CHKO +#undef CHKA +#undef HOOK +#undef ZERO +#undef HRDC + +status_t check_overlay_capability(uint32 feature) +{ + char *msg = ""; + + /* setup logmessage text */ + switch (feature) + { + case B_OVERLAY_COUNT: + msg = "B_OVERLAY_COUNT"; + break; + case B_OVERLAY_SUPPORTED_SPACES: + msg = "B_OVERLAY_SUPPORTED_SPACES"; + break; + case B_OVERLAY_SUPPORTED_FEATURES: + msg = "B_OVERLAY_SUPPORTED_FEATURES"; + break; + case B_ALLOCATE_OVERLAY_BUFFER: + msg = "B_ALLOCATE_OVERLAY_BUFFER"; + break; + case B_RELEASE_OVERLAY_BUFFER: + msg = "B_RELEASE_OVERLAY_BUFFER"; + break; + case B_GET_OVERLAY_CONSTRAINTS: + msg = "B_GET_OVERLAY_CONSTRAINTS"; + break; + case B_ALLOCATE_OVERLAY: + msg = "B_ALLOCATE_OVERLAY"; + break; + case B_RELEASE_OVERLAY: + msg = "B_RELEASE_OVERLAY"; + break; + case B_CONFIGURE_OVERLAY: + msg = "B_CONFIGURE_OVERLAY"; + break; + default: + msg = "UNKNOWN"; + break; + } + +// if (si->ps.card_type > NM2070) +// { + /* export video overlay functions */ +// LOG(4, ("Overlay: Exporting hook %s.\n", msg)); +// return B_OK; +// } + + /* do not export video overlay functions */ + LOG(4, ("Overlay: Not exporting hook %s.\n", msg)); + return B_ERROR; +} + +status_t check_acc_capability(uint32 feature) +{ + bool fill = false; + char *msg = ""; + + /* setup logmessage text */ + switch (feature) + { + case B_SCREEN_TO_SCREEN_BLIT: + msg = "B_SCREEN_TO_SCREEN_BLIT"; + break; + case B_FILL_RECTANGLE: + msg = "B_FILL_RECTANGLE"; + fill = true; + break; + case B_INVERT_RECTANGLE: + msg = "B_INVERT_RECTANGLE"; + fill = true; + break; + case B_FILL_SPAN: + msg = "B_FILL_SPAN"; + fill = true; + break; + case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT: + msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT"; + break; + case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT: + msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT"; + break; + default: + msg = "UNKNOWN"; + break; + } + + /* hardware acceleration is only supported in modes with upto a certain + * memory pitch.. */ + if (si->acc_mode) + { + /* see if we support hardware rectangle fills in the current mode: + * the Matrox card's acc engine can adress upto 16Mbyte memory for this cmd! */ + if (fill && + ((si->fbc.bytes_per_row * si->dm.virtual_height) > (16 * 1024 * 1024))) + { + LOG(4, ("Acc: Not exporting hook %s.\n", msg)); + return B_ERROR; + } + + LOG(4, ("Acc: Exporting hook %s.\n", msg)); + return B_OK; + } + else + { + LOG(4, ("Acc: Not exporting hook %s.\n", msg)); + return B_ERROR; + } +} diff --git a/src/add-ons/accelerants/neomagic/GetDeviceInfo.c b/src/add-ons/accelerants/neomagic/GetDeviceInfo.c new file mode 100644 index 0000000000..52f3756dcf --- /dev/null +++ b/src/add-ons/accelerants/neomagic/GetDeviceInfo.c @@ -0,0 +1,44 @@ +/* + Authors: + Rudolf Cornelissen 4/2003- +*/ + +#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.card_type) + { + case 0x01: + sprintf(adi->name,"Neomagic Plain"); + break; + case 0x02: + sprintf(adi->name,"Neomagic MAX"); + break; + } + + sprintf(adi->chipset,"Neomagic"); + + sprintf(adi->serial_no,"01134"); /*FIXME*/ + + adi->memory=si->ps.memory_size * 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/neomagic/GetModeInfo.c b/src/add-ons/accelerants/neomagic/GetModeInfo.c new file mode 100644 index 0000000000..6a1f4de45d --- /dev/null +++ b/src/add-ons/accelerants/neomagic/GetModeInfo.c @@ -0,0 +1,90 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x02000000 + +#include "acc_std.h" + +/* + Return the current display mode. The only time you might return an + error is if a mode hasn't been set. Or if the system hands you a NULL pointer. +*/ +status_t GET_DISPLAY_MODE(display_mode *current_mode) +{ + /* check for NULL pointer */ + if (current_mode == NULL) return B_ERROR; + + *current_mode = si->dm; + return B_OK; +} + +/* Return the frame buffer configuration information. */ +status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) +{ + /* check for NULL pointer */ + if (afb == NULL) return B_ERROR; + + *afb = si->fbc; + return B_OK; +} + +/* Return the maximum and minium pixelclock limits for the specified mode. */ +status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) +{ + uint32 max_pclk = 0; + uint32 min_pclk = 0; + + /* check for NULL pointers */ + if ((dm == NULL) || (low == NULL) || (high == NULL)) return B_ERROR; + + /* specify requested info assuming CRT-only mode + * (if panel is active, CRTC and pixelclock are not programmed!) */ + { + /* find min. value */ + switch (si->ps.card_type) + { + default: + *low = (si->ps.min_pixel_vco * 1000); + 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; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_24; + break; + } + /* return values in kHz */ + *high = max_pclk * 1000; + } + + /* clamp lower limit to 48Hz vertical refresh for now. + * Apparantly the BeOS screenprefs app does limit the upper refreshrate to 90Hz, + * while it does not limit the lower refreshrate. */ + min_pclk = ((uint32)dm->timing.h_total * (uint32)dm->timing.v_total * 48) / 1000; + if (min_pclk > *low) *low = min_pclk; + + return B_OK; +} + +/* Return the semaphore id that will be used to signal a vertical sync occured. */ +sem_id ACCELERANT_RETRACE_SEMAPHORE(void) +{ + return si->vblank; +} diff --git a/src/add-ons/accelerants/neomagic/GetTimingConstraints.c b/src/add-ons/accelerants/neomagic/GetTimingConstraints.c new file mode 100644 index 0000000000..29751b96c8 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/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/neomagic/GlobalData.c b/src/add-ons/accelerants/neomagic/GlobalData.c new file mode 100644 index 0000000000..242ad68286 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/GlobalData.c @@ -0,0 +1,35 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Mark Watson, + Rudolf Cornelissen 4/2003- +*/ + +#include "acc_std.h" + +int fd; +shared_info *si; +area_id shared_info_area; +vuint32 *regs, *regs2; +area_id regs_area, regs2_area; +display_mode *my_mode_list; +area_id my_mode_list_area; +int accelerantIsClone; + +mn_get_set_pci mn_pci_access= + { + MN_PRIVATE_DATA_MAGIC, + 0, + 4, + 0 + }; + +mn_in_out_isa mn_isa_access= + { + MN_PRIVATE_DATA_MAGIC, + 0, + 1, + 0 + }; diff --git a/src/add-ons/accelerants/neomagic/InitAccelerant.c b/src/add-ons/accelerants/neomagic/InitAccelerant.c new file mode 100644 index 0000000000..3f1bc8a8a9 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/InitAccelerant.c @@ -0,0 +1,313 @@ +/* + 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-3/2003. +*/ + +#define MODULE_BIT 0x00800000 + +#include +#include "acc_std.h" + +/* defined in ProposeDisplayMode.c */ +extern status_t create_mode_list(void); + +static status_t init_common(int the_fd); + +/* Initialization code shared between primary and cloned accelerants */ +static status_t init_common(int the_fd) { + status_t result; + mn_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 = MN_PRIVATE_DATA_MAGIC; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, MN_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; + regs2 = si->clone_bugfix_regs2; + } + 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; + } + else + { + regs2_area = clone_area(DRIVER_PREFIX " regs2", (void **)®s2, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, si->regs2_area); + if (regs2_area < 0) + { + result = regs2_area; + goto error2; + } + } + } + } + + /*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; + +error2: + delete_area(regs_area); +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(regs2_area); + delete_area(regs_area); + /* a little cheap paranoia */ + regs = 0; + regs2 = 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: %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 = mn_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. + */ + pointer_reservation = 0; + if (si->settings.hardcursor) pointer_reservation = si->ps.curmem_size; + + 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*/ + mn_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_mn_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) { + mn_device_name dn; + status_t result; + + /* call the kernel driver to get the device name */ + dn.magic = MN_PRIVATE_DATA_MAGIC; + /* store the returned info directly into the passed buffer */ + dn.name = (char *)data; + result = ioctl(fd, MN_DEVICE_NAME, &dn, sizeof(dn)); +} + +/* +Initialize a copy of the accelerant as a clone. void *data points to +a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). +*/ +status_t CLONE_ACCELERANT(void *data) { + status_t result; + char path[MAXPATHLEN]; + + /* the data is the device name */ + strcpy(path, "/dev"); + strcat(path, (const char *)data); + /* open the device, the permissions aren't important */ + fd = open(path, B_READ_WRITE); + if (fd < 0) { + result = fd; + goto error0; + } + + /* note that we're a clone accelerant */ + accelerantIsClone = 1; + + /* call the shared initialization code */ + result = init_common(fd); + + /* bail out if the common initialization failed */ + if (result != B_OK) goto error1; + + /* get shared area for display modes */ + result = my_mode_list_area = clone_area( + DRIVER_PREFIX " cloned display_modes", + (void **)&my_mode_list, + B_ANY_ADDRESS, + B_READ_AREA, + si->mode_area + ); + if (result < B_OK) goto error2; + + /* all done */ + LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n")); + + result = B_OK; + goto error0; + +error2: + /* free up the areas we cloned */ + uninit_common(); +error1: + /* close the device we opened */ + close(fd); +error0: + return result; +} + +void UNINIT_ACCELERANT(void) +{ + if (accelerantIsClone) + LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n")); + else + LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n")); + + /*delete benaphore*/ + DELETE_BEN(si->engine.lock); + DELETE_BEN(si->overlay.lock); + /* free our mode list area */ + delete_area(my_mode_list_area); + /* paranoia */ + my_mode_list = 0; + /* release our cloned data */ + uninit_common(); + /* close the file handle ONLY if we're the clone */ + if (accelerantIsClone) close(fd); +} diff --git a/src/add-ons/accelerants/neomagic/Jamfile b/src/add-ons/accelerants/neomagic/Jamfile new file mode 100644 index 0000000000..91d4b980f0 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/Jamfile @@ -0,0 +1,26 @@ +SubDir OBOS_TOP src add-ons accelerants neomagic ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics neomagic ] ; +UseHeaders [ FDirName $(SUBDIR) engine ] ; + + +Addon nm.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 : libneomagic_engine.a +; + +Depends nm.accelerant : nm.driver ; + +SubInclude OBOS_TOP src add-ons accelerants neomagic engine ; diff --git a/src/add-ons/accelerants/neomagic/Overlay.c b/src/add-ons/accelerants/neomagic/Overlay.c new file mode 100644 index 0000000000..2a6cb6335c --- /dev/null +++ b/src/add-ons/accelerants/neomagic/Overlay.c @@ -0,0 +1,648 @@ +/* Written by Rudolf Cornelissen 05-2002/03-2003 */ + +/* Note on 'missing features' in BeOS 5.0.3 and DANO: + * BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions' + * of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?) + */ + +#define MODULE_BIT 0x00000400 + +#include "acc_std.h" + +/* define the supported overlay input colorspaces */ +/* Note: + * G200-G550 can all do YUV4:2:0 2-plane colorspace as well, + * G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering), + * G200 does not support YUV4:2:0 3-plane mode while > G200 do. + * It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace + * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */ +static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE }; + +uint32 OVERLAY_COUNT(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: count called\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + } + /* apparantly overlay count should report the number of 'overlay units' on the card */ + return 1; +} + +const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm) +// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. +// Does someone know howto invoke it? +{ + LOG(4,("Overlay: supported_spaces called.\n")); + + /* check for NULL pointer */ + if (dm == NULL) + { + LOG(4,("Overlay: No display mode specified!\n")); + return NULL; + } + + /* interlaced VGA is not supported by G200-G550 BES */ + if (dm->timing.flags && B_TIMING_INTERLACED) + { + return NULL; + } + /* return a B_NO_COLOR_SPACE terminated list */ + return &overlay_colorspaces[0]; +} + +uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space) +// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported! +{ + LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space)); + + /* check what features (like the keying method) are supported on the current + * Desktop colorspace */ + //fixme? Or are we talking about the overlay input bitmap's colorspace? + switch (a_color_space) + { + default: + /* fixme: for now 'direct 32bit' desktop colorspace assumed */ + return + ( B_OVERLAY_KEYING_USES_ALPHA | + B_OVERLAY_COLOR_KEY | + B_OVERLAY_HORIZONTAL_FILTERING | + B_OVERLAY_VERTICAL_FILTERING ); + } +} + +const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height) +{ + int offset = 0; /* used to determine next buffer to create */ + uint32 adress, adress2, temp32; /* used to calculate buffer adresses */ + uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */ + int cnt; /* loopcounter */ + + /* acquire the shared benaphore */ + AQUIRE_BEN(si->overlay.lock) + + LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer))); + LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci))); + LOG(4,("Overlay: cardRAM_size = %dKb\n",si->ps.memory_size)); + + /* find first empty slot (room for another buffer?) */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == NULL) break; + } + + LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset)); + + if (offset < MAXBUFFERS) + /* setup new scaler input buffer */ + { + switch (cs) + { + case B_YCbCr422: + /* check if slopspace is needed: compatible settings choosen for now: + * G200 can do with ~0x0003 while > G200 need ~x0007. + * Optimized settings for G200 could reduce CPU load a tiny little bit there... */ + /* fixme: update needed for DVDmax support to adhere to CRTC2 constraints: + * case display_mode == B_RGB16: multiple = 32 + * case display_mode == B_RGB32: multiple = 16 */ + if (width == (width & ~0x0007)) + { + si->overlay.myBuffer[offset].width = width; + } + else + { + si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8; + } + si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width; + + /* check if the requested horizontal pitch is supported: + * G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace. + * Compatible check done, has no downside consequences here. */ + if (si->overlay.myBuffer[offset].width > 4088) + { + LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + break; + +// case 0xffff://fixme: which one(s)? + //fixme: 4:2:0 2-plane supported format, should be selected only if detected + /* check if slopspace is needed: compatible settings choosen for now: + * G200 can do with ~0x0007 while > G200 need ~x001f. + * Optimized settings for G200 could reduce CPU load a tiny little bit there... */ +/* if (width == (width & ~0x001f)) + { + si->overlay.myBuffer[offset].width = width; + } + else + { + si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32; + } +*/ /* assuming Y-plane only bytes_per_row are requested here */ +/* si->overlay.myBuffer[offset].bytes_per_row = si->overlay.myBuffer[offset].width; +*/ + /* check if the requested horizontal pitch is supported: + * G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace. + * Compatible check done, has no real downside consequences here. */ +/* if (si->overlay.myBuffer[offset].width > 4064) + { + LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"); +*/ + /* release the shared benaphore */ +/* RELEASE_BEN(si->overlay.lock) + + return NULL; + } + break; +*/ + default: + /* unsupported colorspace! */ + LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs)); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + break; + } + + /* check if the requested buffer width is supported */ + if (si->overlay.myBuffer[offset].width > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + /* check if the requested buffer height is supported */ + if (height > 1024) + { + LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n")); + + /* release the shared benaphore */ + RELEASE_BEN(si->overlay.lock) + + return NULL; + } + + /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */ + si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width; + + si->overlay.myBuffer[offset].space = cs; + si->overlay.myBuffer[offset].height = height; + + /* we define the overlay buffers to reside 'in the back' of the cards RAM */ + /* NOTE to app programmers: + * Beware that an app using overlay needs to track workspace switches and screenprefs + * changes. If such an action is detected, the app needs to reset it's pointers to the + * newly created overlay bitmaps, which will be assigned by BeOS automatically after such + * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!) + * + * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them + * than previously setup by the app might be re-setup. This is due to cardRAM restraints then. + * This means that the app should also check for NULL pointers returned by the bitmaps, + * and if this happens, it needs to fallback to single buffered overlay or even fallback to + * bitmap output for the new situation. */ + + /* Another NOTE for app programmers: + * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the + * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately. + * This *greatly* simplifies tracking such errors! + * Of course such errors may lead to strange effects in the app or driver behaviour if they are + * not hunted down and removed.. */ + + /* calculate first free RAM adress in card: + * Driver setup is as follows: + * card base: - hardware cursor bitmap (if used), + * directly above - screen memory for both heads */ + adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */ + (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */ + LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2)); + + /* calculate 'preliminary' buffer size including slopspace */ + oldsize = si->overlay.myBufInfo[offset].size; + si->overlay.myBufInfo[offset].size = + si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height; + + /* calculate virtual memory adress that would be needed for a new bitmap */ + /* NOTE to app programmers: + * For testing app behaviour regarding workspace switches or screen prefs changes to settings + * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with + * a low amount of RAM. Or you can set in the file nm.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)); + 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 nm.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)); + 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 */ + { + + mn_release_bes(); + + LOG(4,("succesfull\n")); + + si->overlay.myToken = NULL; + return B_OK; + } +} + +status_t CONFIGURE_OVERLAY + (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov) +{ + int offset = 0; /* used for buffer index */ + + LOG(4,("Overlay: Configure_overlay called: ")); + + /* Note: + * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will + * release all overlay buffers. The buffer currently displayed at that moment, may need some + * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets + * called one more time then, with a null pointer for overlay_window and overlay_view, while + * the currently displayed overlay_buffer is given. + * The G200-G550 do not need to do anything on such an occasion, so we simply return if we + * get called then. */ + if ((ow == NULL) || (ov == NULL)) + { + LOG(4,("output properties changed\n")); + + return B_OK; + } + + /* Note: + * If during overlay use the screen prefs are changed, or the workspace has changed, it + * may be that we were not able to re-allocate the requested overlay buffers (or only partly) + * due to lack of cardRAM. If the app does not respond properly to this, we might end up + * with a NULL pointer instead of a overlay_buffer to work with here. + * Of course, we need to abort then to prevent the system from 'going down'. + * The app will probably crash because it will want to write into this non-existant buffer + * at some point. */ + if (ob == NULL) + { + LOG(4,("no overlay buffer specified\n")); + + return B_ERROR; + } + + /* is this call done by the app that owns us? */ + if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) + /* nope, abort */ + { + LOG(4,("failed\n")); + + return B_ERROR; + } + else + /* call is for real */ + { + /* find the buffer's offset */ + for (offset = 0; offset < MAXBUFFERS; offset++) + { + if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; + } + + if (offset < MAXBUFFERS) + { + LOG(4,("succesfull, switching to buffer %d\n", offset)); + + mn_configure_bes(ob, ow, ov, offset); + + return B_OK; + } + else + { + /* this is no buffer of ours! */ + LOG(4,("buffer is not ours, aborted!\n")); + + return B_ERROR; + } + } +} diff --git a/src/add-ons/accelerants/neomagic/ProposeDisplayMode.c b/src/add-ons/accelerants/neomagic/ProposeDisplayMode.c new file mode 100644 index 0000000000..4e38fe3b6b --- /dev/null +++ b/src/add-ons/accelerants/neomagic/ProposeDisplayMode.c @@ -0,0 +1,389 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors for nm driver: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x00400000 + +#include "acc_std.h" + +#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) +/* mode flags will be setup as status info by PROPOSEMODE! */ +#define MODE_FLAGS 0 +#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode)) + +/*some monitors only handle a fixed set of modes*/ +#include "valid_mode_list" + +/* Standard VESA modes */ +static const display_mode mode_list[] = { +{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ +{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ +{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ +{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ +{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ +{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ +{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ +{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */ +{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */ +{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */ +{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */ +{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */ +{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */ +{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ +{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ +{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ +{ { 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) */ +}; + +/* +Check mode is between low and high limits +returns: + B_OK - found one + B_BAD_VALUE - mode can be made, but outside limits + B_ERROR - not possible +*/ +/* BOUNDS WARNING: + * BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE + * returns B_BAD_VALUE. It's called by the OS with target, low and high set to + * have the same settings for BWindowScreen! + * Which means we should not return B_BAD_VALUE on anything except for deviations on: + * display_mode.virtual_width; + * display_mode.virtual_height; + * display_mode.timing.h_display; + * display_mode.timing.v_display; + */ +/* Note: + * The target mode should be modified to correspond to the mode as it can be made. */ +status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) +{ + status_t status = B_OK; + float pix_clock_found; + uint8 m,n,p; + status_t result; + uint32 row_bytes, pointer_reservation; + double target_refresh = ((double)target->timing.pixel_clock * 1000.0) / + ( + (double)target->timing.h_total * + (double)target->timing.v_total + ); + bool + want_same_width = target->timing.h_display == target->virtual_width, + want_same_height = target->timing.v_display == target->virtual_height; + + LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n", + target->virtual_width, target->virtual_height)); + + /*check valid list: + if (VALID_REQUIRED is set) + { + if (find modes with same size) + { + pick one with nearest pixel clock + } + else + { + pick next largest with nearest pixel clock and modify visible portion as far as possible + } + } + */ + #ifdef VALID_MODE_REQUIRED + { + int i; + int closest_mode_ptr; + uint32 closest_mode_clock; + + LOG(1, ("PROPOSEMODE: valid mode required!\n")); + + closest_mode_ptr = 0xbad; + closest_mode_clock = 0; + for (i=0;itiming.h_display==valid_mode_list[i].h_display && + target->timing.v_display==valid_mode_list[i].v_display + ) + { + if ( + abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)< + abs(closest_mode_clock-target->timing.pixel_clock) + ) + { + closest_mode_clock=valid_mode_list[i].pixel_clock; + closest_mode_ptr=i; + } + } + } + + if (closest_mode_ptr==0xbad)/*if no modes of correct size*/ + { + LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n")); + return B_ERROR; + } + else + { + target->timing=valid_mode_list[closest_mode_ptr]; + target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/ + ((double)target->timing.h_total * (double)target->timing.v_total); + } + } + #endif + + /*find a nearby valid timing from that given*/ + result = mn_crtc_validate_timing + ( + &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total, + &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total + ); + if (result == B_ERROR) + { + LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n")); + return result; + } + + /* validate display vs. virtual */ + if ((target->timing.h_display > target->virtual_width) || want_same_width) + target->virtual_width = target->timing.h_display; + if ((target->timing.v_display > target->virtual_height) || want_same_height) + target->virtual_height = target->timing.v_display; + + /* nail virtual size and 'subsequently' calculate rowbytes */ + result = mn_general_validate_pic_size (target, &row_bytes); + if (result == B_ERROR) + { + LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n")); + return result; + } + + /*check if virtual_width is still within the requested limits*/ + if ((target->virtual_width < low->virtual_width) || + (target->virtual_width > high->virtual_width)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n")); + } + + /*check if timing found is within the requested horizontal limits*/ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display) || + (target->timing.h_sync_start < low->timing.h_sync_start) || + (target->timing.h_sync_start > high->timing.h_sync_start) || + (target->timing.h_sync_end < low->timing.h_sync_end) || + (target->timing.h_sync_end > high->timing.h_sync_end) || + (target->timing.h_total < low->timing.h_total) || + (target->timing.h_total > high->timing.h_total)) + { + /* BWindowScreen workaround: we accept everything except h_display deviations */ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n")); + } + + /*check if timing found is within the requested vertical limits*/ + if ( + (target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display) || + (target->timing.v_sync_start < low->timing.v_sync_start) || + (target->timing.v_sync_start > high->timing.v_sync_start) || + (target->timing.v_sync_end < low->timing.v_sync_end) || + (target->timing.v_sync_end > high->timing.v_sync_end) || + (target->timing.v_total < low->timing.v_total) || + (target->timing.v_total > high->timing.v_total) + ) + { + /* BWindowScreen workaround: we accept everything except v_display deviations */ + if ((target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n")); + } + + /* adjust pixelclock for possible timing modifications done above */ + target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0; + + /* Now find the nearest valid pixelclock we actually can setup for the target mode, + * this also makes sure we don't generate more pixel bandwidth than the device can handle */ + result = mn_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p); + /* update the target mode */ + target->timing.pixel_clock = (pix_clock_found * 1000); + + /* note if we fell outside the limits */ + if ((target->timing.pixel_clock < low->timing.pixel_clock) || + (target->timing.pixel_clock > high->timing.pixel_clock) + ) + { + /* BWindowScreen workaround: we accept deviations <= 1Mhz */ + if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) || + (target->timing.pixel_clock > (high->timing.pixel_clock + 1000))) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n")); + } + + /* checkout space needed for hardcursor (if any) */ + pointer_reservation = 0; + if (si->settings.hardcursor) pointer_reservation = si->ps.curmem_size; + /* memory requirement for frame buffer */ + if ((row_bytes * target->virtual_height) > + ((si->ps.memory_size * 1024) - pointer_reservation)) + { + target->virtual_height = + ((si->ps.memory_size * 1024) - pointer_reservation) / row_bytes; + } + if (target->virtual_height < target->timing.v_display) + { + LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n")); + return B_ERROR; + } + LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n", + target->virtual_width, target->virtual_height)); + + if ((target->virtual_height < low->virtual_height) || + (target->virtual_height > high->virtual_height)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n")); + } + + /* setup status flags */ + LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags)); + /* preset to singlehead card without TVout, no overlay support and no hardcursor. + * also advice system that app_server and acc engine may touch the framebuffer + * simultaneously (fixed). */ +//fixme: introduce dualhead_clone_only flag compatible with matrox so the same prefs +//util can be used + target->flags &= + ~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_IO_FB_NA); + /* we always allow parallel access (fixed), the DAC is always in 'enhanced' + * mode (fixed), and all modes support DPMS (fixed); + * We support scrolling and panning in every mode, so we 'send a signal' to + * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */ + target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL); + + /* set HARDWARE_CURSOR mode if suitable */ + if (si->settings.hardcursor) + target->flags |= B_HARDWARE_CURSOR; + + /* set SUPPORTS_OVERLAYS if suitable */ + if (si->ps.card_type > NM2070) + target->flags |= B_SUPPORTS_OVERLAYS; + + LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags)); + + /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE, + * progressive scan (fixed), and sync_on_green not used */ + target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN); + /* The HSYNC and VSYNC command flags are actually executed by the driver. */ + + if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n")); + else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n")); + return status; +} + +/* Return the number of modes this device will return from GET_MODE_LIST(). + This is precalculated in create_mode_list (called from InitAccelerant stuff) +*/ +uint32 ACCELERANT_MODE_COUNT(void) +{ + LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count)); + + return si->mode_count; +} + +/* Copy the list of guaranteed supported video modes to the location provided.*/ +status_t GET_MODE_LIST(display_mode *dm) +{ + LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n")); + + memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode)); + return B_OK; +} + + +/* Create a list of display_modes to pass back to the caller.*/ +status_t create_mode_list(void) { + size_t max_size; + uint32 + i, j, + pix_clk_range; + const display_mode + *src; + display_mode + *dst, + low, + high; + + color_space spaces[4] = {B_RGB24_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("nm accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (my_mode_list_area < B_OK) return my_mode_list_area; + + /* walk through our predefined list and see which modes fit this device */ + src = mode_list; + dst = my_mode_list; + si->mode_count = 0; + for (i = 0; i < MODE_COUNT; i++) { + /* set ranges for acceptable values */ + low = high = *src; + /* range is 6.25% of default clock: arbitrarily picked */ + pix_clk_range = low.timing.pixel_clock >> 5; + low.timing.pixel_clock -= pix_clk_range; + high.timing.pixel_clock += pix_clk_range; + /* 'some cards need wider virtual widths for certain modes': + * Not true. They might need a wider pitch, but this is _not_ reflected in + * virtual_width, but in fbc.bytes_per_row. */ + //So disable next line: + //high.virtual_width = 4096; + /* do it once for each depth we want to support */ + for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) + { + /* set target values */ + *dst = *src; + /* poke the specific space */ + dst->space = low.space = high.space = spaces[j]; + /* ask for a compatible mode */ + /* We have to check for B_OK, because otherwise the pix_clk_range + * won't be taken into account!! */ + //So don't do this: + //if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) { + //Instead, do this: + if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) { + /* count it, and move on to next mode */ + dst++; + si->mode_count++; + } + } + /* advance to next mode */ + src++; + } + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/SetDisplayMode.c b/src/add-ons/accelerants/neomagic/SetDisplayMode.c new file mode 100644 index 0000000000..d963b7cec9 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/SetDisplayMode.c @@ -0,0 +1,309 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. + + Other authors: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x00200000 + +#include "acc_std.h" + +/* + Enable/Disable interrupts. Just a wrapper around the + ioctl() to the kernel driver. +*/ +static void interrupt_enable(bool flag) { + status_t result; + mn_set_bool_state sbs; + + /* set the magic number so the driver knows we're for real */ + sbs.magic = MN_PRIVATE_DATA_MAGIC; + sbs.do_it = flag; + /* contact driver and get a pointer to the registers and shared data */ + result = ioctl(fd, MN_RUN_INTERRUPTS, &sbs, sizeof(sbs)); +} + +/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ +status_t SET_DISPLAY_MODE(display_mode *mode_to_set) +{ + /* BOUNDS WARNING: + * It's impossible to deviate whatever small amount in a display_mode if the lower + * and upper limits are the same! + * Besides: + * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE + * returns B_BAD_VALUE! + * Which means PROPOSEMODE should not return that on anything except on + * deviations for: + * display_mode.virtual_width; + * display_mode.virtual_height; + * display_mode.timing.h_display; + * display_mode.timing.v_display; + * So: + * We don't use bounds here by making sure bounds and target are the same struct! + * (See the call to PROPOSE_DISPLAY_MODE below) */ + display_mode /*bounds,*/ target; + + uint8 colour_depth = 24; + uint32 startadd; + + bool display, h, v; + + /* if internal panel is active we don't touch the CRTC timing and the pixelPLL */ + bool crt_only = true; + + /* Adjust mode to valid one and fail if invalid */ + target /*= bounds*/ = *mode_to_set; + /* show the mode bits */ + LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); + LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); + LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", + target.virtual_width, target.virtual_height)); + + /* See BOUNDS WARNING above... */ + if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; + + /* if we have the flatpanel turned on modify visible part of mode if nessesary */ + if (nm_general_output_read() & 0x02) + { + LOG(4,("SETMODE: internal flatpanel enabled, skipping CRTC/pixelPLL setup\n")); + crt_only = false; + } + + /* disable interrupts using the kernel driver */ + interrupt_enable(false); + + /* find current DPMS state, then turn off screen(s) */ + mn_crtc_dpms_fetch(&display, &h, &v); + mn_crtc_dpms(false, false, false); + + /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ + startadd = si->fbc.frame_buffer - si->framebuffer; + + /* Perform the mode switch */ + { + status_t status = B_OK; + int colour_mode = BPP24; + + 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_RGB24_LITTLE: colour_depth = 24; colour_mode = BPP24; break; + default: + LOG(8,("SETMODE: Invalid colorspace $%08x\n", target.space)); + return B_ERROR; + } + + /* calculate and set new mode bytes_per_row */ + mn_general_validate_pic_size (&target, &si->fbc.bytes_per_row); + + /* set the pixelclock PLL */ + if (crt_only) + { + status = mn_dac_set_pix_pll(target); + if (status == B_ERROR) + LOG(8,("CRTC: error setting pixelclock\n")); + } + + /* set the colour depth for CRTC1 and the DAC */ + mn_dac_mode(colour_mode, 1.0); + mn_crtc_depth(colour_mode); + + /* set the display pitch */ + mn_crtc_set_display_pitch(); + + /* tell the card what memory to display */ + mn_crtc_set_display_start(startadd,colour_depth); + + /* enable primary analog output */ + //fixme: choose output connector(s) + + /* set the timing */ + mn_crtc_set_timing(target, crt_only); + + /* always setup centering so a KB BIOS switch to flatpanel will go OK... */ + mn_crtc_center(target); + } + + /* update driver's mode store */ + si->dm = target; + + /* turn screen on */ + mn_crtc_dpms(display,h,v); + + /* set up acceleration for this mode */ + si->dm.virtual_height += 1;//for clipping! +// mn_acc_init(); + si->dm.virtual_height -= 1; + + /* log currently selected output */ + nm_general_output_select(); + + MSG(("SETMODE: 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*! */ + nm_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; + + uint16 h_display = si->dm.timing.h_display; /* local copy needed for flatpanel */ + uint16 v_display = si->dm.timing.v_display; /* local copy needed for flatpanel */ + + LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); + + /* reset lower bits, don't return an error! */ + switch(si->dm.space) + { + case B_CMAP8: + colour_depth=8; + h_display_start &= ~0x03; + break; + case B_RGB15_LITTLE: case B_RGB16_LITTLE: + colour_depth=16; + h_display_start &= ~0x01; + break; + case B_RGB24_LITTLE: + colour_depth=24; + h_display_start &= ~0x03; + break; + default: + return B_ERROR; + } + + /* if internal panel is active correct visible screensize! */ + if (nm_general_output_read() & 0x02) + { + if (h_display > si->ps.panel_width) h_display = si->ps.panel_width; + if (v_display > si->ps.panel_height) v_display = si->ps.panel_height; + } + + /* do not run past end of display */ + if ((h_display + h_display_start) > si->dm.virtual_width) + return B_ERROR; + if ((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->fbc.bytes_per_row; + startadd += h_display_start * (colour_depth >> 3); + startadd += si->fbc.frame_buffer - si->framebuffer; + + interrupt_enable(false); + + mn_crtc_set_display_start(startadd,colour_depth); + + 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++; + } + mn_dac_palette(r,g,b, 256); +} + + +/* 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: $%08x\n", dpms_flags)); + + switch(dpms_flags) + { + case B_DPMS_ON: /* H: on, V: on */ + mn_crtc_dpms(true, true , true); + break; + case B_DPMS_STAND_BY: + mn_crtc_dpms(false, false, true); + break; + case B_DPMS_SUSPEND: + mn_crtc_dpms(false, true, false); + break; + case B_DPMS_OFF: /* H: off, V: off, display off */ + mn_crtc_dpms(false, false, false); + break; + default: + LOG(8,("SET_DPMS_MODE: Invalid DPMS settings) $%08x\n", dpms_flags)); + interrupt_enable(true); + return B_ERROR; + } + interrupt_enable(true); + return B_OK; +} + +/* Report device DPMS capabilities. */ +uint32 DPMS_CAPABILITIES(void) +{ + return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF); +} + + +/* Return the current DPMS mode. */ +uint32 DPMS_MODE(void) +{ + bool display, h, v; + + interrupt_enable(false); + mn_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/neomagic/acc_std.h b/src/add-ons/accelerants/neomagic/acc_std.h new file mode 100644 index 0000000000..70307ff6e1 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/acc_std.h @@ -0,0 +1,16 @@ +/* + 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" +#include "nm_proto.h" +#include "be_driver_proto.h" + +#endif diff --git a/src/add-ons/accelerants/neomagic/be_driver_proto.h b/src/add-ons/accelerants/neomagic/be_driver_proto.h new file mode 100644 index 0000000000..c3dc1b9c2c --- /dev/null +++ b/src/add-ons/accelerants/neomagic/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/neomagic/engine/Jamfile b/src/add-ons/accelerants/neomagic/engine/Jamfile new file mode 100644 index 0000000000..ebc682fa81 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/Jamfile @@ -0,0 +1,15 @@ +SubDir OBOS_TOP src add-ons accelerants neomagic engine ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics neomagic ] ; +UseHeaders [ FDirName $(SUBDIR) .. ] ; + +StaticLibrary neomagic_engine : + nm_acc.c + nm_bes.c + nm_crtc.c + nm_dac.c + nm_general.c + nm_info.c + nm_support.c + ; diff --git a/src/add-ons/accelerants/neomagic/engine/nm_acc.c b/src/add-ons/accelerants/neomagic/engine/nm_acc.c new file mode 100644 index 0000000000..18efd62760 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_acc.c @@ -0,0 +1,350 @@ +/* nm Acceleration functions */ +/* Authors: + Mark Watson 2/2000, + Rudolf Cornelissen 10/2002-4/2003. +*/ + +#define MODULE_BIT 0x00080000 + +#include "nm_std.h" + +/*acceleration notes*/ + +/*functions Be's app_server uses: +fill span (horizontal only) +fill rectangle (these 2 are very similar) +invert rectangle +blit +*/ + +/* G100 pre SRCORG/DSTORG registers */ +static uint32 src_dst; +/* MIL1/2 adress linearisation does not always work */ +static uint8 y_lin; +static uint8 depth; + +/* needed by MIL 1/2 because of adress linearisation constraints */ +#define ACCW_YDSTLEN(dst, len) do { \ + if (y_lin) { \ + ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \ + ACCW(LEN,len); \ + } else ACCW(YDSTLEN,((dst)<<16)|(len)); \ +} while (0) + +status_t mn_acc_wait_idle() +{ + volatile int i; + while (ACCR(STATUS)&(1<<16)) + { + for (i=0;i<10000;i++); /*spin in place so I do not hammer the bus*/ + }; + return B_OK; +} + +/* AFAIK this must be done for every new screenmode. + * Engine required init. */ +status_t mn_acc_init() +{ + /* used for convenience: MACCESS is a write only register! */ + uint32 maccess = 0x00000000; + + /* preset using hardware adress linearisation */ + y_lin = 0x00; + /* reset depth */ + depth = 0; + + /* cleanup bitblt */ + ACCW(OPMODE,0); + + /* Set the Z origin to the start of FB (otherwise lockup on blits) */ + ACCW(ZORG,0); + + /* Set pixel width */ + switch(si->dm.space) + { + case B_CMAP8: + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00)); + depth = 8; + break; + case B_RGB15_LITTLE:case B_RGB16_LITTLE: + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01)); + depth = 16; + break; + case B_RGB32_LITTLE:case B_RGBA32_LITTLE: + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02)); + depth = 32; + break; + default: + LOG(8,("ACC: init, invalid bit depth\n")); + return B_ERROR; + } + + /* setup PITCH: very cardtype specific! */ + switch (si->ps.card_type) + { + case G100: + /* always using hardware adress linearisation, because 2D/3D + * engine works on every pitch multiple of 32 */ + ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF)); + break; + default: + /* G200 and up are equal.. */ + /* always using hardware adress linearisation, because 2D/3D + * engine works on every pitch multiple of 32 */ + ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF)); + break; + } + + /* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */ + ACCW(PLNWT,0x00000000); + ACCW(PLNWT,0xffffffff); + + if (si->ps.card_type >= G200) { + /*DSTORG - location of active screen in framebuffer*/ + ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer)); + + /*SRCORG - init source address - same as dest*/ + ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer)); + } + + /* init YDSTORG - apsed, if not inited, BitBlts may fails on <= G200 */ + src_dst = 0; + ACCW(YDSTORG, src_dst); + + /* <= G100 uses this register as SRCORG/DSTORG replacement, but + * MIL 1/2 does not need framebuffer space for the hardcursor! */ + if ((si->ps.card_type == G100) && (si->settings.hardcursor)) + { + switch (si->dm.space) + { + case B_CMAP8: + src_dst = 1024 / 1; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + src_dst = 1024 / 2; + break; + case B_RGB32_LITTLE: + src_dst = 1024 / 4; + break; + default: + LOG(8,("ACC: G100 hardcursor not supported for current colorspace\n")); + return B_ERROR; + } + } + ACCW(YDSTORG,src_dst); + + /* clipping */ + /* i.e. highest and lowest X pixel adresses */ + ACCW(CXBNDRY,(((si->fbc.bytes_per_row / (depth >> 3)) - 1) << 16) | (0)); + + /* Y pixel addresses must be linear */ + /* lowest adress */ + ACCW(YTOP, 0 + src_dst); + /* highest adress */ + ACCW(YBOT,((si->dm.virtual_height - 1) * + (si->fbc.bytes_per_row / (depth >> 3))) + src_dst); + + return B_OK; +} + +/* screen to screen blit - i.e. move windows around. + * Engine function bitblit, paragraph 4.5.7.2 */ +status_t mn_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h) +{ + uint32 t_start,t_end,offset; + uint32 b_start,b_end; + + /*find where the top,bottom and offset are*/ + offset = (si->fbc.bytes_per_row / (depth >> 3)); + + t_end = t_start = xs + (offset*ys) + src_dst; + t_end += w; + + b_end = b_start = xs + (offset*(ys+h)) + src_dst; + b_end +=w; + + /* sgnzero bit _must_ be '0' before accessing SGN! */ + ACCW(DWGCTL,0x00000000); + + /*find which quadrant */ + switch((yd>ys)|((xd>xs)<<1)) + { + case 0: /*L->R,down*/ + ACCW(SGN,0); + + ACCW(AR3,t_start); + ACCW(AR0,t_end); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 1: /*L->R,up*/ + ACCW(SGN,4); + + ACCW(AR3,b_start); + ACCW(AR0,b_end); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + case 2: /*R->L,down*/ + ACCW(SGN,1); + + ACCW(AR3,t_end); + ACCW(AR0,t_start); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 3: /*R->L,up*/ + ACCW(SGN,5); + + ACCW(AR3,b_end); + ACCW(AR0,b_start); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + } + ACCW(FXBNDRY,((xd+w)<<16)|xd); + + /*do the blit*/ + ACCGO(DWGCTL,0x040C4018); // atype RSTR + + return B_OK; +} + +/* screen to screen tranparent blit - not sure what uses this. + * Engine function bitblit, paragraph 4.5.7.2 */ +status_t mn_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour) +{ + uint32 t_start,t_end,offset; + uint32 b_start,b_end; + + return B_ERROR; + + /*find where the top,bottom and offset are*/ + offset = (si->fbc.bytes_per_row / (depth >> 3)); + + t_end = t_start = xs + (offset*ys) + src_dst; + t_end += w; + + b_end = b_start = xs + (offset*(ys+h)) + src_dst; + b_end +=w; + + /* sgnzero bit _must_ be '0' before accessing SGN! */ + ACCW(DWGCTL,0x00000000); + + /*find which quadrant */ + switch((yd>ys)|((xd>xs)<<1)) + { + case 0: /*L->R,down*/ + ACCW(SGN,0); + + ACCW(AR3,t_start); + ACCW(AR0,t_end); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 1: /*L->R,up*/ + ACCW(SGN,4); + + ACCW(AR3,b_start); + ACCW(AR0,b_end); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + case 2: /*R->L,down*/ + ACCW(SGN,1); + + ACCW(AR3,t_end); + ACCW(AR0,t_start); + ACCW(AR5,offset); + + ACCW_YDSTLEN(yd,h+1); + break; + case 3: /*R->L,up*/ + ACCW(SGN,5); + + ACCW(AR3,b_end); + ACCW(AR0,b_start); + ACCW(AR5,-offset); + + ACCW_YDSTLEN(yd+h,h+1); + break; + } + ACCW(FXBNDRY,((xd+w)<<16)|xd); + + /*do the blit*/ + ACCW(FCOL,colour); + ACCW(BCOL,0xffffffff); + ACCGO(DWGCTL,0x440C4018); // atype RSTR + return B_OK; +} + +/* rectangle fill. + * Engine function rectangle_fill: paragraph 4.5.5.2 */ +/*colorIndex,fill_rect_params,count*/ +status_t mn_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) +{ +/* + FXBNDRY - left and right coordinates a + YDSTLEN - y start and no of lines a + (or YDST and LEN) + DWGCTL - atype must be RSTR or BLK a + FCOL - foreground colour a +*/ + + ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/ + ACCW_YDSTLEN(ys,yl); /*set y start and length*/ + ACCW(FCOL,col); /*set colour*/ + +//acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode +// for other functions, and use fastblt on MIL1/2 if possible... +//or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?) + if (si->dm.space==B_CMAP8) + { + ACCGO(DWGCTL,0x400C7814); // atype RSTR + } + else + { + ACCGO(DWGCTL,0x400C7844); // atype BLK + } + return B_OK; +} + +/* rectangle invert. + * Engine function rectangle_fill: paragraph 4.5.5.2 */ +/*colorIndex,fill_rect_params,count*/ +status_t mn_acc_rectangle_invert(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*/ + + /*draw it! top nibble is c is clipping enabled*/ + ACCGO(DWGCTL,0x40057814); // atype RSTR + + return B_OK; +} + +/* screen to screen scaled filtered blit - i.e. scale video in memory. + * Engine function texture mapping for video, paragraphs 4.5.5.5 - 4.5.5.9 */ +status_t mn_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd) +{ + //fixme: implement. + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_bes.c b/src/add-ons/accelerants/neomagic/engine/nm_bes.c new file mode 100644 index 0000000000..ea7264fa71 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_bes.c @@ -0,0 +1,694 @@ +/* G200-G550 Back End Scaler functions */ +/* Written by Rudolf Cornelissen 05/2002-04/2003 */ + +#define MODULE_BIT 0x00000200 + +#include "nm_std.h" + +//fixme: implement: (used for virtual screens!) +//void move_overlay(uint16 hdisp_start, uint16 vdisp_start); + +status_t mn_configure_bes + (const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset) +{ + /* yuy2 (4:2:2) colorspace calculations */ + /* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */ + + /* Note: + * in BeOS R5.0.3 and DANO: + * 'ow->offset_xxx' is always 0, so not used; + * 'ow->width' and 'ow->height' are the output window size: does not change + * if window is clipping; + * 'ow->h_start' and 'ow->v_start' are the left-top position of the output + * window. These values can be negative: this means the window is clipping + * at the left or the top of the display, respectively. */ + + /* 'ov' is the view in the source bitmap, so which part of the bitmap is actually + * displayed on screen. This is used for the 'hardware zoom' function. */ + + /* calculated BES register values */ + uint32 hcoordv, vcoordv, hiscalv, hsrcstv, hsrcendv, hsrclstv, + viscalv, a1orgv, v1wghtv, v1srclstv, globctlv, ctlv; + /* misc used variables */ + uint16 temp1, temp2; + /* interval representation, used for scaling calculations */ + uint16 intrep, crtc_hstart, crtc_vstart, crtc_hend, crtc_vend; + /* inverse scaling factor, used for source positioning */ + uint32 ifactor; + /* used for vertical weight starting value */ + uint32 weight; + /* copy of overlay view which has checked valid values */ + overlay_view my_ov; + + /* Slowdown the G200-G550 BES if the pixelclock is too high for it to cope. + * This will in fact half the horizontal resolution of the BES with high + * pixelclocks (by setting a BES hardware 'zoom' = 2x). + * If you want optimal output quality better make sure you set the refreshrate/resolution + * of your monitor not too high ... */ + uint16 acczoom = 1; + LOG(4,("Overlay: pixelclock is %dkHz, ", si->dm.timing.pixel_clock)); + if (si->dm.timing.pixel_clock > BESMAXSPEED) + { + /* BES running at half speed and resolution */ + /* This is how it works (BES slowing down): + * - Activate BES internal horizontal hardware scaling = 4x (in GLOBCTL below), + * - This also sets up BES only getting half the amount of pixels per line from + * the input picture buffer (in effect half-ing the BES pixelclock input speed). + * Now in order to get the picture back to original size, we need to also double + * the inverse horizontal scaling factor here (x4 /2 /2 = 1x again). + * Note that every other pixel is now doubled or interpolated, according to another + * GLOBCTL bit. */ + acczoom = 2; + LOG(4,("slowing down BES!\n")); + } + else + { + /* BES running at full speed and resolution */ + LOG(4,("BES is running at full speed\n")); + } + + + /************************************************************************************** + *** copy, check and limit if needed the user-specified view into the intput bitmap *** + **************************************************************************************/ + my_ov = *ov; + /* check for valid 'coordinates' */ + if (my_ov.width == 0) my_ov.width++; + if (my_ov.height == 0) my_ov.height++; + if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1)) + my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1); + if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1)) + my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1); + if (my_ov.v_start > (ob->height - 1)) + my_ov.v_start = (ob->height - 1); + if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1)) + my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1); + + LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n", + my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height)); + + /* the BES does not respect virtual_workspaces, but adheres to CRTC + * constraints only */ + crtc_hstart = si->dm.h_display_start; + /* horizontal end is the first position beyond the displayed range on the CRTC */ + crtc_hend = crtc_hstart + si->dm.timing.h_display; + crtc_vstart = si->dm.v_display_start; + /* vertical end is the first position beyond the displayed range on the CRTC */ + crtc_vend = crtc_vstart + si->dm.timing.v_display; + + + /**************************************** + *** setup all edges of output window *** + ****************************************/ + + /* setup left and right edges of output window */ + hcoordv = 0; + /* left edge coordinate of output window, must be inside desktop */ + /* clipping on the left side */ + if (ow->h_start < crtc_hstart) + { + temp1 = 0; + } + else + { + /* clipping on the right side */ + if (ow->h_start >= (crtc_hend - 1)) + { + /* width < 2 is not allowed */ + temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (ow->h_start - crtc_hstart) & 0x7ff; + } + } + hcoordv |= temp1 << 16; + /* right edge coordinate of output window, must be inside desktop */ + /* width < 2 is not allowed */ + if (ow->width < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the right side */ + if ((ow->h_start + ow->width - 1) > (crtc_hend - 1)) + { + temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff; + } + else + { + /* clipping on the left side */ + if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1)) + { + /* width < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1)) & 0x7ff; + } + } + } + hcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2)); + + /* setup top and bottom edges of output window */ + vcoordv = 0; + /* top edge coordinate of output window, must be inside desktop */ + /* clipping on the top side */ + if (ow->v_start < crtc_vstart) + { + temp1 = 0; + } + else + { + /* clipping on the bottom side */ + if (ow->v_start >= (crtc_vend - 1)) + { + /* height < 2 is not allowed */ + temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff; + } + else + /* no clipping here */ + { + temp1 = (ow->v_start - crtc_vstart) & 0x7ff; + } + } + vcoordv |= temp1 << 16; + /* bottom edge coordinate of output window, must be inside desktop */ + /* height < 2 is not allowed */ + if (ow->height < 2) + { + temp2 = (temp1 + 1) & 0x7ff; + } + else + { + /* clipping on the bottom side */ + if ((ow->v_start + ow->height - 1) > (crtc_vend - 1)) + { + temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff; + } + else + { + /* clipping on the top side */ + if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1)) + { + /* height < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1)) & 0x7ff; + } + } + } + vcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2)); + + + /********************************************* + *** setup horizontal scaling and clipping *** + *********************************************/ + + LOG(6,("Overlay: total input picture width = %d, height = %d\n", + (ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height)); + LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height)); + + /* do horizontal scaling... */ + /* determine interval representation value, taking zoom into account */ + if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) + { + /* horizontal filtering is ON */ + if ((my_ov.width == ow->width) | (ow->width < 2)) + { + /* no horizontal scaling used, OR destination width < 2 */ + intrep = 0; + } + else + { + intrep = 1; + } + } + else + { + /* horizontal filtering is OFF */ + if ((ow->width < my_ov.width) & (ow->width >= 2)) + { + /* horizontal downscaling used AND destination width >= 2 */ + intrep = 1; + } + else + { + intrep = 0; + } + } + LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep)); + + /* calculate inverse horizontal scaling factor, taking zoom into account */ + /* standard scaling formula: */ + ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep); + + /* correct factor to prevent most-right visible 'line' from distorting */ + ifactor -= (1 << 2); + LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor)); + + /* compensate for accelerated 2x zoom (slowdown BES if pixelclock is too high) */ + hiscalv = ifactor * acczoom; + LOG(4,("Overlay: horizontal speed compensated factor is %f\n", (float)65536 / hiscalv)); + + /* check scaling factor (and modify if needed) to be within scaling limits */ + if (((((uint32)my_ov.width) << 16) / 16384) > hiscalv) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + hiscalv = ((((uint32)my_ov.width) << 16) / 16384); + LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv)); + } + if (hiscalv >= (32 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + hiscalv = 0x1ffffc; + LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv)); + } + /* AND below is required by hardware */ + hiscalv &= 0x001ffffc; + + + /* do horizontal clipping... */ + /* Setup horizontal source start: first (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the left starting position of the bitmap's view (zoom function) to get the final value needed. + * Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + hsrcstv = 0; + /* check for destination horizontal clipping at left side */ + if (ow->h_start < crtc_hstart) + { + /* check if entire destination picture is clipping left: + * (2 pixels will be clamped onscreen at least) */ + if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1)) + { + /* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */ + hsrcstv += (ow->width - 2); + } + else + { + /* increase 'first contributing pixel' with actual number of dest. clipping pixels */ + hsrcstv += (crtc_hstart - ow->h_start); + } + LOG(4,("Overlay: clipping left...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + hsrcstv *= ifactor; + } + /* take zoom into account */ + hsrcstv += ((uint32)my_ov.h_start) << 16; + /* AND below required by hardware */ + hsrcstv &= 0x03fffffc; + LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", hsrcstv / (float)65536)); + + + /* Setup horizontal source end: last (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */ + + hsrcendv = 0; + /* check for destination horizontal clipping at right side */ + if ((ow->h_start + ow->width - 1) > (crtc_hend - 1)) + { + /* check if entire destination picture is clipping right: + * (2 pixels will be clamped onscreen at least) */ + if (ow->h_start > (crtc_hend - 2)) + { + /* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */ + hsrcendv += (ow->width - 2); + } + else + { + /* increase 'number of clipping pixels' with actual number of dest. clipping pixels */ + hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 1)); + } + LOG(4,("Overlay: clipping right...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + hsrcendv *= ifactor; + /* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */ + hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16) - hsrcendv; + } + else + { + /* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */ + hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16); + } + /* AND below required by hardware */ + hsrcendv &= 0x03fffffc; + LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", hsrcendv / (float)65536)); + + + /* setup horizontal source last position excluding slopspace: + * this is the last pixel that will be used for calculating interpolated pixels */ + hsrclstv = ((ob->width - 1) - si->overlay.myBufInfo[offset].slopspace) << 16; + /* AND below required by hardware */ + hsrclstv &= 0x03ff0000; + + + /******************************************* + *** setup vertical scaling and clipping *** + *******************************************/ + + /* do vertical scaling... */ + /* determine interval representation value, taking zoom into account */ + if (ow->flags & B_OVERLAY_VERTICAL_FILTERING) + { + /* vertical filtering is ON */ + if ((my_ov.height == ow->height) | (ow->height < 2)) + { + /* no vertical scaling used, OR destination height < 2 */ + intrep = 0; + } + else + { + intrep = 1; + } + } + else + { + /* vertical filtering is OFF */ + if ((ow->height < my_ov.height) & (ow->height >= 2)) + { + /* vertical downscaling used AND destination height >= 2 */ + intrep = 1; + } + else + { + intrep = 0; + } + } + LOG(4,("Overlay: vertical interval representation value is %d\n",intrep)); + + /* calculate inverse vertical scaling factor, taking zoom into account */ + /* standard scaling formula: */ + ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep); + + /* correct factor to prevent lowest visible line from distorting */ + ifactor -= (1 << 2); + LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor)); + + /* preserve ifactor for source positioning calculations later on */ + viscalv = ifactor; + + /* check scaling factor (and modify if needed) to be within scaling limits */ + if (((((uint32)my_ov.height) << 16) / 16384) > viscalv) + { + /* (non-inverse) factor too large, set factor to max. valid value */ + viscalv = ((((uint32)my_ov.height) << 16) / 16384); + LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv)); + } + if (viscalv >= (32 << 16)) + { + /* (non-inverse) factor too small, set factor to min. valid value */ + viscalv = 0x1ffffc; + LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv)); + } + /* AND below is required by hardware */ + viscalv &= 0x001ffffc; + + + /* do vertical clipping... */ + /* Setup vertical source start: first (sub)pixel contributing to output picture. + * Note: this exists of two parts: + * 1. setup fractional part (sign is always 'positive'); + * 2. setup relative base_adress, taking clipping on top (and zoom) into account. + * Both parts are done intertwined below. */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * 'After' this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + + /* calculate relative base_adress and 'vertical weight fractional part' */ + weight = 0; + a1orgv = (uint32)((vuint32 *)ob->buffer); + a1orgv -= (uint32)((vuint32 *)si->framebuffer); + /* calculate origin adress */ + LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv)); + /* check for destination vertical clipping at top side */ + if (ow->v_start < crtc_vstart) + { + /* check if entire destination picture is clipping at top: + * (2 pixels will be clamped onscreen at least) */ + if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1)) + { + /* increase source buffer origin with 'fixed value': + * (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) * + * bytes per row source picture */ + a1orgv += ((((ow->height - 2) * ifactor) >> 16) * ob->bytes_per_row); + weight = (ow->height - 2) * ifactor; + } + else + { + /* increase source buffer origin with: + * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) * + * bytes per row source picture */ + a1orgv += ((((crtc_vstart - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row); + weight = (crtc_vstart - ow->v_start) * ifactor; + } + LOG(4,("Overlay: clipping at top...\n")); + } + /* take zoom into account */ + a1orgv += (my_ov.v_start * ob->bytes_per_row); + weight += (((uint32)my_ov.v_start) << 16); + LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n",a1orgv)); + LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", weight / (float)65536)); + + /* Note: + * Because all > G200 overlay units will ignore b0-3 of the calculated adress, + * we do not use the above way for horizontal source positioning. + * (G200 cards ignore b0-2.) + * If we did, 8 source-image pixel jumps (in 4:2:2 colorspace) will occur if the picture + * is shifted horizontally during left clipping on all > G200 cards, while G200 cards + * will have 4 source-image pixel jumps occuring. */ + + /* AND below is required by G200-G550 hardware. > G200 cards can have max. 32Mb RAM on board + * (16Mb on G200 cards). Compatible setting used (between G200 and the rest), this has no + * downside consequences here. */ + /* Buffer A topleft corner of field 1 (origin)(field 1 contains our full frames) */ + a1orgv &= 0x01fffff0; + + /* field 1 weight: AND below required by hardware, also make sure 'sign' is always 'positive' */ + v1wghtv = weight & 0x0000fffc; + + + /* setup field 1 (is our complete frame) vertical source last position. + * this is the last pixel that will be used for calculating interpolated pixels */ + v1srclstv = (ob->height - 1); + /* AND below required by hardware */ + v1srclstv &= 0x000003ff; + + + /***************************** + *** log color keying info *** + *****************************/ + + LOG(6,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n", + ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value)); + LOG(6,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n", + ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask)); + + + /************************* + *** setup BES control *** + *************************/ + + /* BES global control: setup functions */ + globctlv = 0; + + /* slowdown BES if nessesary */ + if (acczoom == 1) + { + /* run at full speed and resolution */ + globctlv |= 0 << 0; + /* disable filtering for half speed interpolation */ + globctlv |= 0 << 1; + } + else + { + /* run at half speed and resolution */ + globctlv |= 1 << 0; + /* enable filtering for half speed interpolation */ + globctlv |= 1 << 1; + } + + /* 4:2:0 specific setup: not needed here */ + globctlv |= 0 << 3; + /* BES testregister: keep zero */ + globctlv |= 0 << 4; + /* the following bits marked (> G200) *must* be zero on G200: */ + /* 4:2:0 specific setup: not needed here (> G200) */ + globctlv |= 0 << 5; + /* select yuy2 byte-order to B_YCbCr422 (> G200) */ + globctlv |= 0 << 6; + /* BES internal contrast and brighness controls are not used, disabled (> G200) */ + globctlv |= 0 << 7; + /* RGB specific setup: not needed here, so disabled (> G200) */ + globctlv |= 0 << 8; + globctlv |= 0 << 9; + /* 4:2:0 specific setup: not needed here (> G200) */ + globctlv |= 0 << 10; + /* Tell BES when to copy the new register values to the actual active registers. + * bits 16-27 (12 bits) are the CRTC vert. count value at which copying takes + * place. + * (This is the double buffering feature: programming must be completed *before* + * the CRTC vert count value set here!) */ + /* CRTC vert count for copying = $000, so during retrace, line 0. */ + globctlv |= 0x000 << 16; + + /* BES control: enable scaler and setup functions */ + /* pre-reset all bits */ + ctlv = 0; + /* enable BES */ + ctlv |= 1 << 0; + /* we start displaying at an even startline (zero) in 'field 1' (no hardware de-interlacing is used) */ + ctlv |= 0 << 6; + /* we don't use field 2, so its startline is not important */ + ctlv |= 0 << 7; + + LOG(6,("Overlay: ow->flags is $%08x\n",ow->flags)); + /* enable horizontal filtering on scaling if asked for: if we *are* actually scaling */ + if ((ow->flags & B_OVERLAY_HORIZONTAL_FILTERING) && (hiscalv != (0x01 << 16))) + { + ctlv |= 1 << 10; + LOG(6,("Overlay: using horizontal interpolation on scaling\n")); + } + else + { + ctlv |= 0 << 10; + LOG(6,("Overlay: using horizontal dropping or replication on scaling\n")); + } + /* enable vertical filtering on scaling if asked for: if we are *upscaling* only */ + if ((ow->flags & B_OVERLAY_VERTICAL_FILTERING) && (viscalv < (0x01 << 16))) + { + ctlv |= 1 << 11; + LOG(6,("Overlay: using vertical interpolation on scaling\n")); + } + else + { + ctlv |= 0 << 11; + LOG(6,("Overlay: using vertical dropping or replication on scaling\n")); + } + + /* use actual calculated weight for horizontal interpolation */ + ctlv |= 0 << 12; + /* use horizontal chroma interpolation upsampling on BES input picture */ + ctlv |= 1 << 16; + /* select 4:2:2 BES input format */ + ctlv |= 0 << 17; + /* dithering is enabled */ + ctlv |= 1 << 18; + /* horizontal mirroring is not used */ + ctlv |= 0 << 19; + /* BES output should be in color */ + ctlv |= 0 << 20; + /* BES output blanking is disabled: we want a picture, no 'black box'! */ + ctlv |= 0 << 21; + /* we do software field select (field select is not used) */ + ctlv |= 0 << 24; + /* we always display field 1 in buffer A, this contains our full frames */ + /* select field 1 */ + ctlv |= 0 << 25; + /* select buffer A */ + ctlv |= 0 << 26; + + + /************************************* + *** sync to BES (Back End Scaler) *** + *************************************/ + + /* Make sure reprogramming the BES completes before the next retrace occurs, + * to prevent register-update glitches (double buffer feature). */ + +// LOG(3,("Overlay: starting register programming beyond Vcount %d\n", CR1R(VCOUNT))); + /* Even at 1600x1200x90Hz, a single line still takes about 9uS to complete: + * this resolution will generate about 180Mhz pixelclock while we can do + * upto 360Mhz. So snooze about 4uS to prevent bus-congestion... + * Appr. 200 lines time will provide enough room even on a 100Mhz CPU if it's + * screen is set to the highest refreshrate/resolution possible. */ +// while (CR1R(VCOUNT) > (si->dm.timing.v_total - 200)) snooze(4); + + + /************************************** + *** actually program the registers *** + **************************************/ +/* + BESW(HCOORD, hcoordv); + BESW(VCOORD, vcoordv); + BESW(HISCAL, hiscalv); + BESW(HSRCST, hsrcstv); + BESW(HSRCEND, hsrcendv); + BESW(HSRCLST, hsrclstv); + BESW(VISCAL, viscalv); + BESW(A1ORG, a1orgv); + BESW(V1WGHT, v1wghtv); + BESW(V1SRCLST, v1srclstv); + BESW(GLOBCTL, globctlv); + BESW(CTL, ctlv); +*/ + + /************************** + *** setup color keying *** + **************************/ + + /* setup colorkeying */ +/* DXIW(COLKEY, (ow->alpha.value & ow->alpha.mask)); + + DXIW(COLKEY0RED, (ow->red.value & ow->red.mask)); + DXIW(COLKEY0GREEN, (ow->green.value & ow->green.mask)); + DXIW(COLKEY0BLUE, (ow->blue.value & ow->blue.mask)); + + DXIW(COLMSK, ow->alpha.mask); + + DXIW(COLMSK0RED, ow->red.mask); + DXIW(COLMSK0GREEN, ow->green.mask); + DXIW(COLMSK0BLUE, ow->blue.mask); +*/ + /* enable colorkeying */ +// DXIW(KEYOPMODE,0x01); + + + /************************* + *** setup misc. stuff *** + *************************/ + + /* setup brightness and contrast to be 'neutral' (this is not implemented on G200) */ +// BESW(LUMACTL, 0x00000080); + + /* setup source pitch including slopspace (in pixels); AND is required by hardware */ +// BESW(PITCH, (ob->width & 0x00000fff)); + + /* on a 500Mhz P3 CPU just logging a line costs 400uS (18-19 vcounts at 1024x768x60Hz)! + * programming the registers above actually costs 180uS here */ +// LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT))); + + return B_OK; +} + +status_t mn_release_bes() +{ + /* setup BES control: disable scaler */ +// BESW(CTL, 0x00000000); + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_crtc.c b/src/add-ons/accelerants/neomagic/engine/nm_crtc.c new file mode 100644 index 0000000000..c469c2e0ce --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_crtc.c @@ -0,0 +1,696 @@ +/* CTRC functionality */ +/* Author: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x00040000 + +#include "nm_std.h" + +/* Adjust passed parameters to a valid mode line */ +//fixme: the order of the sync edges should also be checked, +//just like the sync signal's min. pulse length... +status_t mn_crtc_validate_timing( + uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, + uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt +) +{ +/* horizontal */ + /* make all parameters multiples of 8 */ + *hd_e &= 0xfff8; + *hs_s &= 0xfff8; + *hs_e &= 0xfff8; + *ht &= 0xfff8; + + /* confine to required number of bits, taking logic into account */ + if (*hd_e > ((0xff - 2) << 3)) *hd_e = ((0xff - 2) << 3); + if (*hs_s > ((0xff - 1) << 3)) *hs_s = ((0xff - 1) << 3); + if (*hs_e > ( 0xff << 3)) *hs_e = ( 0xff << 3); + if (*ht > ((0xff + 5) << 3)) *ht = ((0xff + 5) << 3); + + /* NOTE: keep horizontal timing at multiples of 8! */ + /* confine to a reasonable width */ + if (*hd_e < 640) *hd_e = 640; + if (*hd_e > 2000) *hd_e = 2000; + + /* if hor. total does not leave room for a sensible sync pulse, increase it! */ + if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); + + /* make sure sync pulse is not during display */ + if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); + if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); + + /* correct sync pulse if it is too long: + * there are only 5 bits available to save this in the card registers! */ + if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); + +/*vertical*/ + /* confine to required number of bits, taking logic into account */ + if (si->ps.card_type < NM2200) + { + if (*vd_e > (0x3ff - 2)) *vd_e = (0x3ff - 2); + if (*vs_s > (0x3ff - 1)) *vs_s = (0x3ff - 1); + if (*vs_e > 0x3ff ) *vs_e = 0x3ff ; + if (*vt > (0x3ff + 2)) *vt = (0x3ff + 2); + } + else + { + if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); + if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); + if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; + if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); + } + + /* confine to a reasonable height */ + if (*vd_e < 480) *vd_e = 480; + /* (max height was already confined in a reasonable way above) */ + + /*if vertical total does not leave room for a sync pulse, increase it!*/ + if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); + + /* make sure sync pulse is not during display */ + if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); + if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); + + /* correct sync pulse if it is too long: + * there are only 4 bits available to save this in the card registers! */ + if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); + + return B_OK; +} + +/* set a mode line */ +status_t mn_crtc_set_timing(display_mode target, bool crt_only) +{ + uint8 hsync_pos = (target.timing.flags & B_POSITIVE_HSYNC); + uint8 vsync_pos = (target.timing.flags & B_POSITIVE_VSYNC); + + uint8 temp; + + uint32 htotal; /*total horizontal total VCLKs*/ + uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ + uint32 hsync_s; /*begin of horizontal sync pulse*/ + uint32 hsync_e; /*end of horizontal sync pulse*/ + uint32 hblnk_s; /*begin horizontal blanking*/ + uint32 hblnk_e; /*end horizontal blanking*/ + + uint32 vtotal; /*total vertical total scanlines*/ + uint32 vdisp_e; /*end of vertical display*/ + uint32 vsync_s; /*begin of vertical sync pulse*/ + uint32 vsync_e; /*end of vertical sync pulse*/ + uint32 vblnk_s; /*begin vertical blanking*/ + uint32 vblnk_e; /*end vertical blanking*/ + + uint32 linecomp; /*split screen and vdisp_e interrupt*/ + + LOG(4,("CRTC: setting timing\n")); + + /* modify visible sceensize if needed */ + /* (note that MOVE_CURSOR checks for a panning/scrolling mode itself, + * the display_mode as placed in si->dm may _not_ be modified!) */ + if (!(crt_only)) + { + if (target.timing.h_display > si->ps.panel_width) + { + target.timing.h_display = si->ps.panel_width; + LOG(4, ("CRTC: req. width > panel width: setting panning mode\n")); + } + if (target.timing.v_display > si->ps.panel_height) + { + target.timing.v_display = si->ps.panel_height; + LOG(4, ("CRTC: req. height > panel height: setting scrolling mode\n")); + } + } + + /* Modify parameters as required by standard VGA */ + htotal = ((target.timing.h_total >> 3) - 5); + hdisp_e = ((target.timing.h_display >> 3) - 1); + hblnk_s = hdisp_e; + hblnk_e = (htotal + 0); /* this register differs from standard VGA! (says + 4) */ + hsync_s = (target.timing.h_sync_start >> 3); + hsync_e = (target.timing.h_sync_end >> 3); + + vtotal = target.timing.v_total - 2; + vdisp_e = target.timing.v_display - 1; + vblnk_s = vdisp_e; + vblnk_e = (vtotal + 1); + vsync_s = target.timing.v_sync_start;//-1; + vsync_e = target.timing.v_sync_end;//-1; + + /* prevent memory adress counter from being reset (linecomp may not occur) */ + linecomp = target.timing.v_display; + + if (crt_only) + { + LOG(4,("CRTC: CRT only mode, setting full timing...\n")); + + /* log the mode that will be set */ + LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e)); + LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e)); + + /* actually program the card! */ + /* unlock CRTC registers at index 0-7 */ + temp = (ISACRTCR(VSYNCE) & 0x7f); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(VSYNCE, temp); + /* horizontal standard VGA regs */ + ISACRTCW(HTOTAL, (htotal & 0xff)); + ISACRTCW(HDISPE, (hdisp_e & 0xff)); + ISACRTCW(HBLANKS, (hblnk_s & 0xff)); + /* also unlock vertical retrace registers in advance */ + ISACRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); + ISACRTCW(HSYNCS, (hsync_s & 0xff)); + ISACRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); + + /* vertical standard VGA regs */ + ISACRTCW(VTOTAL, (vtotal & 0xff)); + ISACRTCW(OVERFLOW, + ( + ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | + ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | + ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | + ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) + )); + ISACRTCW(PRROWSCN, 0x00); /* not used */ + ISACRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); + ISACRTCW(VSYNCS, (vsync_s & 0xff)); + temp = (ISACRTCR(VSYNCE) & 0xf0); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(VSYNCE, (temp | (vsync_e & 0x0f))); + ISACRTCW(VDISPE, (vdisp_e & 0xff)); + ISACRTCW(VBLANKS, (vblnk_s & 0xff)); + ISACRTCW(VBLANKE, (vblnk_e & 0xff)); +//linux: +// regp->CRTC[23] = 0xC3; + ISACRTCW(LINECOMP, (linecomp & 0xff)); + + /* horizontal - no extended regs available or needed on NeoMagic chips */ + + /* vertical - extended regs */ +//fixme: checkout if b2 or 3 should be switched! (linux contains error here) +//fixme: linecomp should also have an extra bit... testable by setting linecomp +//to 100 for example and then try out writing an '1' to b2, b3(!) and the rest +//for screenorig reset visible on upper half of the screen or not at all.. + if (si->ps.card_type >= NM2200) + ISACRTCW(VEXT, + ( + ((vtotal & 0x400) >> (10 - 0)) | + ((vdisp_e & 0x400) >> (10 - 1)) | + ((vblnk_s & 0x400) >> (10 - 2)) | + ((vsync_s & 0x400) >> (10 - 3))/*| + ((linecomp&0x400)>>3)*/ + )); + + /* setup HSYNC & VSYNC polarity */ + temp = ISARB(MISCR); + if (vsync_pos) temp &= ~0x80; + else temp |= 0x80; + if (hsync_pos) temp &= ~0x40; + else temp |= 0x40; + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISAWB(MISCW, temp); + + LOG(2,("CRTC: HSYNC/VSYNC polarity: %x %x, MISC reg readback: $%02x\n", + hsync_pos, vsync_pos, ISARB(MISCR))); + } + else + { + LOG(4,("CRTC: internal flatpanel active, setting display region only\n")); + + /* actually program the card! */ + /* unlock CRTC registers at index 0-7 */ + temp = (ISACRTCR(VSYNCE) & 0x7f); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(VSYNCE, temp); + /* horizontal standard VGA regs */ + ISACRTCW(HDISPE, (hdisp_e & 0xff)); + + /* vertical standard VGA regs */ + temp = (ISACRTCR(OVERFLOW) & ~0x52); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(OVERFLOW, + ( + temp | + ((vdisp_e & 0x100) >> (8 - 1)) | + ((vdisp_e & 0x200) >> (9 - 6)) | + ((linecomp & 0x100) >> (8 - 4)) + )); + + ISACRTCW(PRROWSCN, 0x00); /* not used */ + + temp = (ISACRTCR(MAXSCLIN) & ~0x40); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(MAXSCLIN, (temp | ((linecomp & 0x200) >> (9 - 6)))); + + ISACRTCW(VDISPE, (vdisp_e & 0xff)); +//linux: +// regp->CRTC[23] = 0xC3; + ISACRTCW(LINECOMP, (linecomp & 0xff)); + + /* horizontal - no extended regs available or needed on NeoMagic chips */ + + /* vertical - extended regs */ +//fixme: linecomp should have an extra bit... testable by setting linecomp +//to 100 for example and then try out writing an '1' to b2, b3(!) and the rest +//for screenorig reset visible on upper half of the screen or not at all.. + if (si->ps.card_type >= NM2200) + { + temp = (ISACRTCR(VEXT) & ~0x02); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISACRTCW(VEXT, + ( + temp | + ((vdisp_e & 0x400) >> (10 - 1))/*| + ((linecomp&0x400)>>3)*/ + )); + } + } + + return B_OK; +} + +status_t mn_crtc_depth(int mode) +{ + uint8 vid_delay = 0; + + LOG(4,("CRTC: setting colordepth to be displayed\n")); + + /* set VCLK scaling */ + switch(mode) + { + case BPP8: + vid_delay = 0x01; + break; + case BPP15: + vid_delay = 0x02; + break; + case BPP16: + vid_delay = 0x03; + break; + case BPP24: + vid_delay = 0x04; + break; + default: + LOG(4,("CRTC: colordepth not supported, aborting!\n")); + return B_ERROR; + break; + } + + switch (si->ps.card_type) + { + case NM2070: + vid_delay |= (ISAGRPHR(COLDEPTH) & 0xf0); + break; + default: + vid_delay |= (ISAGRPHR(COLDEPTH) & 0x70); + break; + } + /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ + snooze(10); + ISAGRPHW(COLDEPTH, vid_delay); + + snooze(10); + LOG(4,("CRTC: colordepth register readback $%02x\n", (ISAGRPHR(COLDEPTH)))); + + return B_OK; +} + +status_t mn_crtc_dpms(bool display, bool h, bool v) +{ + uint8 temp; + + LOG(4,("CRTC: setting DPMS: ")); + + /* start synchronous reset: required before turning screen off! */ + ISASEQW(RESET, 0x01); + + /* turn screen off */ + temp = ISASEQR(CLKMODE); + /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ + snooze(10); + + if (display) + { + ISASEQW(CLKMODE, (temp & ~0x20)); + + /* end synchronous reset if display should be enabled */ + ISASEQW(RESET, 0x03); + + LOG(4,("display on\n")); + } + else + { + ISASEQW(CLKMODE, (temp | 0x20)); + + LOG(4,("display off\n")); + } + +// LOG(4,("CRTC: setting DPMS (%d,%d,%d)\n", display,h,v)); + +// VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0xCF)|((!v)<<5))|((!h)<<4); + + /* set some required fixed values for proper nm mode initialisation */ +// VGAW_I(CRTC,0x17,0xC3); +// VGAW_I(CRTC,0x14,0x00); + + return B_OK; +} + +status_t mn_crtc_dpms_fetch(bool * display, bool * h, bool * v) +{ + *display = !(ISASEQR(CLKMODE) & 0x20); + +// *display=!((VGAR_I(SEQ,1)&0x20)>>5); +// *h=!((VGAR_I(CRTCEXT,1)&0x10)>>4); +// *v=!((VGAR_I(CRTCEXT,1)&0x20)>>5); + + *h = *v = true; + + LOG(4,("CTRC: fetched DPMS state:")); + if (display) LOG(4,("display on\n")); + else LOG(4,("display off\n")); + + return B_OK; +} + +status_t mn_crtc_set_display_pitch() +{ + uint32 offset; + + LOG(4,("CRTC: setting card pitch (offset between lines)\n")); + + /* figure out offset value hardware needs: same for all Neomagic cards */ + offset = si->fbc.bytes_per_row / 8; + + LOG(2,("CRTC: offset register set to: $%04x\n", offset)); + + /* program the card */ + ISACRTCW(PITCHL, (offset & 0xff)); + //fixme: test for max supported pitch if possible, + //not all bits below will be implemented. + //NM2160: confirmed b0 and b1 in register below to exist and work. + ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8)); + + return B_OK; +} + +status_t mn_crtc_set_display_start(uint32 startadd,uint8 bpp) +{ + uint8 val; + uint32 timeout = 0; + + LOG(2,("CRTC: relative startadd: $%06x\n",startadd)); + LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer)); + LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer)); + + /* make sure we are in retrace, because otherwise distortions might occur + * during our reprogramming them (no double buffering) (verified on NM2160) */ + + /* we might have no retraces during setmode! So: + * wait 25mS max. for retrace to occur (refresh > 40Hz) */ + //fixme? move this function to the kernel driver... is much 'faster'. + while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4))) + { + snooze(4); + timeout++; + } + + /* the neomagic framebuffer startadress is given in 32bit words */ + startadd >>= 2; + + /* set standard VGA registers */ + ISACRTCW(FBSTADDH, ((startadd & 0x00FF00) >> 8)); + ISACRTCW(FBSTADDL, (startadd & 0x0000FF)); + + /* set NM extended register */ + //fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!! + //this is testable via virtualscreen in 640x480x8 mode... + //(b4 is >256Kb adresswrap bit, so that's already occupied) + val = ISAGRPHR(FBSTADDE); + /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ + snooze(10); + if (si->ps.card_type < NM2200) + ISAGRPHW(FBSTADDE,(((startadd >> 16) & 0x07) | (val & 0xf8))); + else + ISAGRPHW(FBSTADDE,(((startadd >> 16) & 0x0f) | (val & 0xf0))); + + return B_OK; +} + +/* setup centering mode for current internal or simultaneous flatpanel mode */ +status_t mn_crtc_center(display_mode target) +{ + uint8 vcent1, vcent2, vcent3, vcent4, vcent5; + uint8 hcent1, hcent2, hcent3, hcent4, hcent5; + uint8 ctrl2, ctrl3; + + /* preset no centering */ + uint16 hoffset = 0; + uint16 voffset = 0; + vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00; + hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00; + ctrl2 = ctrl3 = 0x00; + + /* calculate offsets for centering if prudent */ + if (target.timing.h_display < si->ps.panel_width) + { + hoffset = (si->ps.panel_width - target.timing.h_display); + /* adjust for register contraints: + * horizontal center granularity is 16 pixels */ + hoffset = ((hoffset >> 4) - 1); +//fixme: what does this do? + /* turn on horizontal centering? */ + ctrl3 = 0x10; + } + + if (target.timing.v_display < si->ps.panel_height) + { + voffset = (si->ps.panel_height - target.timing.v_display); + /* adjust for register contraints: + * vertical center granularity is 2 pixels */ + voffset = ((voffset >> 1) - 2); +//fixme: what does this do? + /* turn on vertical centering? */ + ctrl2 = 0x01; + } + + switch(target.timing.h_display) + { + case 640: + hcent1 = hoffset; + vcent3 = voffset; + break; + case 800: + hcent2 = hoffset; + switch(target.timing.v_display) + { + case 480: + //Linux fixme: check this out... + vcent3 = voffset; + break; + case 600: + vcent4 = voffset; + break; + } + break; + case 1024: + hcent5 = hoffset; + vcent5 = voffset; + break; + case 1280: + /* this mode equals the largest possible panel on the newest chip: + * so no centering needed here. */ + break; + default: + //fixme?: block non-standard modes? for now: not centered. + break; + } + + /* now program the card's registers */ + ISAGRPHW(PANELVCENT1, vcent1); + ISAGRPHW(PANELVCENT2, vcent2); + ISAGRPHW(PANELVCENT3, vcent3); + if (si->ps.card_type > NM2070) + { + ISAGRPHW(PANELVCENT4, vcent4); + ISAGRPHW(PANELHCENT1, hcent1); + ISAGRPHW(PANELHCENT2, hcent2); + ISAGRPHW(PANELHCENT3, hcent3); + } + if (si->ps.card_type >= NM2160) + { + ISAGRPHW(PANELHCENT4, hcent4); + } + if (si->ps.card_type >= NM2200) + { + ISAGRPHW(PANELVCENT5, vcent5); + ISAGRPHW(PANELHCENT5, hcent5); + } + + /* program panel control register 2: don't touch bit 3-5 */ + ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38); + /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ + snooze(10); + ISAGRPHW(PANELCTRL2, ctrl2); + + if (si->ps.card_type > NM2070) + { + /* program panel control register 3: don't touch bit 7-5 and bit 3-0 */ + ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef); + /* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */ + snooze(10); + ISAGRPHW(PANELCTRL3, ctrl3); + } + + return B_OK; +} + +status_t mn_crtc_cursor_init() +{ + int i; + uint32 * fb; + /* cursor bitmap will be stored at the start of the framebuffer */ + uint32 curadd = 0, curreg; + + /* set cursor bitmap adress on a 1kb boundary, and move the bits around + * so they get placed at the correct registerbits */ + //fixme: NM2380 must have an extra bit for > 4Mb??? + curreg = (((curadd >> 10) & 0x000f) << 8); + curreg |= (((curadd >> 10) & 0x0ff0) >> 4); + + if (si->ps.card_type < NM2200) + CR1W(CURADDRESS, curreg); + else + CR1W(22CURADDRESS, curreg); + + /*set cursor colour*/ + if (si->ps.card_type < NM2200) + { + /* background is black */ + CR1W(CURBGCOLOR, 0x00000000); + /* foreground is white */ + CR1W(CURFGCOLOR, 0x00ffffff); + } + else + { + /* background is black */ + CR1W(22CURBGCOLOR, 0x00000000); + /* foreground is white */ + CR1W(22CURFGCOLOR, 0x00ffffff); + } + + /*clear cursor*/ + fb = (uint32 *) si->framebuffer + curadd; + for (i=0;i<(1024/4);i++) + { + fb[i]=0; + } + + /* activate hardware cursor */ + mn_crtc_cursor_show(); + + return B_OK; +} + +status_t mn_crtc_cursor_show() +{ + if (si->ps.card_type < NM2200) + { + CR1W(CURCTRL, 0x00000001); + } + else + { + CR1W(22CURCTRL, 0x00000001); + } + return B_OK; +} + +status_t mn_crtc_cursor_hide() +{ +//linux fixme: using this kills PCI(?) access sometimes, so use ISA access as below... +/* + if (si->ps.card_type < NM2200) + { + CR1W(CURCTRL, 0x00000000); + } + else + { + CR1W(22CURCTRL, 0x00000000); + } +*/ + /* disable cursor */ + ISAGRPHW(CURCTRL,0x00); + + return B_OK; +} + +/*set up cursor shape*/ +status_t mn_crtc_cursor_define(uint8* andMask,uint8* xorMask) +{ + uint8 y; + uint8 * cursor; + + /*get a pointer to the cursor*/ + cursor = (uint8*) si->framebuffer; + + /*draw the cursor*/ + for(y=0;y<16;y++) + { + cursor[y*16+8]=~*andMask++; + cursor[y*16+0]=*xorMask++; + cursor[y*16+9]=~*andMask++; + cursor[y*16+1]=*xorMask++; + } + + //test.. only valid for ps.f_ref * (n + 1)) / ((m + 1) * x)); + LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk)); + nm_general_output_select(); + } + + return B_OK; +} + +/*position the cursor*/ +status_t mn_crtc_cursor_position(uint16 x ,uint16 y) +{ +//NM2160 is ok without this, still verify the rest..: + /* make sure we are not in retrace, because the register(s) might get copied + * during our reprogramming them (double buffering feature) */ +/* fixme!? + while (ACCR(STATUS) & 0x08) + { + snooze(4); + } +*/ + if (si->ps.card_type < NM2200) + { + CR1W(CURX, (uint32)x); + CR1W(CURY, (uint32)y); + } + else + { + CR1W(22CURX, (uint32)x); + CR1W(22CURY, (uint32)y); + } + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_dac.c b/src/add-ons/accelerants/neomagic/engine/nm_dac.c new file mode 100644 index 0000000000..528b83ba40 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_dac.c @@ -0,0 +1,319 @@ +/* program the DAC */ +/* Author: + Rudolf Cornelissen 4/2003-5/2003 +*/ + +#define MODULE_BIT 0x00010000 + +#include "nm_std.h" + +/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ +status_t mn_dac_mode(int mode,float brightness) +{ + uint8 *r, *g, *b, t[256]; + uint16 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; + if (ri > 255) ri = 255; + t[i] = ri; + } + + /*modify the palette for the specified mode (&validate mode)*/ + /* Note: the Neomagic chips have a 6 bit wide Palette RAM! */ + switch(mode) + { + case BPP8: + LOG(8,("DAC: 8bit mode is indexed by OS, aborting brightness setup.\n")); + return B_OK; + break; + case BPP24: + LOG(8,("DAC: 24bit mode is a direct mode, aborting brightness setup.\n")); + return B_OK; +//fixme: unnessesary? direct mode (6bits PAL RAM is insufficient here!) +/* for (i = 0; i < 256; i++) + { + b[i] = g[i] = r[i] = t[i]; + } +*/ break; + case BPP16: + for (i = 0; i < 32; i++) + { + /* blue and red have only the 5 most significant bits */ + b[i] = r[i] = t[i << 3]; + } + for (i = 0; i < 64; i++) + { + /* the green component has 6 bits */ + g[i] = t[i << 2]; + } + break; + case BPP15: + for (i = 0; i < 32; i++) + { + /* all color components have 5 bits */ + g[i] = r[i] = b[i] = t[i << 3]; + } + break; + default: + LOG(8,("DAC: Invalid colordepth requested, aborting!\n")); + return B_ERROR; + break; + } + + if (mn_dac_palette(r, g, b, i) != B_OK) return B_ERROR; + + /*set the mode - also sets VCLK dividor*/ +// DXIW(MULCTRL, mode); +// LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL))); + + /* disable palette RAM adressing mask */ + ISAWB(PALMASK, 0xff); + LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", ISARB(PALMASK))); + + return B_OK; +} + +/* program the DAC palette using the given r,g,b values */ +status_t mn_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256], uint16 cnt) +{ + int i; + + LOG(4,("DAC: setting palette\n")); + + /* select first PAL adress before starting programming */ + ISAWB(PALINDW, 0x00); + + /* loop through all 256 to program DAC */ + for (i = 0; i < cnt; i++) + { + /* the 6 implemented bits are on b0-b5 of the bus */ + ISAWB(PALDATA, (r[i] >> 2)); + ISAWB(PALDATA, (g[i] >> 2)); + ISAWB(PALDATA, (b[i] >> 2)); + } + if (ISARB(PALINDW) != (cnt & 0x00ff)) + { + LOG(8,("DAC: PAL write index incorrect after programming\n")); + return B_ERROR; + } +if (1) + {//reread LUT + uint8 R, G, B; + + /* select first PAL adress to read (modulo 3 counter) */ + ISAWB(PALINDR, 0x00); + for (i = 0; i < cnt; i++) + { + /* the 6 implemented bits are on b0-b5 of the bus */ + R = (ISARB(PALDATA) << 2); + G = (ISARB(PALDATA) << 2); + B = (ISARB(PALDATA) << 2); + /* only compare the most significant 6 bits */ + if (((r[i] & 0xfc) != R) || ((g[i] & 0xfc) != G) || ((b[i] & 0xfc) != 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 note: + * PIXPLLC is used - others should be kept as is + */ +status_t mn_dac_set_pix_pll(display_mode target) +{ + uint8 m=0,n=0,p=0; + uint8 temp; +// 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 = mn_dac_pix_pll_find(target,&pix_setting,&m,&n,&p); + if (result != B_OK) + { + return result; + } + + /*reprogram (disable,select,wait for stability,enable)*/ +//unknown on Neomagic?: +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ +// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ + + /* select PixelPLL registerset C */ + temp = (ISARB(MISCR) | 0x0c); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISAWB(MISCW, temp); + + /*set VCO divider (lsb) */ + ISAGRPHW(PLLC_NL, n); + /*set VCO divider (msb) if it exists */ + if (si->ps.card_type >= NM2200) + { + temp = (ISAGRPHR(PLLC_NH) & 0x0f); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISAGRPHW(PLLC_NH, (temp | (p & 0xf0))); + } + /*set main reference frequency divider */ + ISAGRPHW(PLLC_M, m); + + /* Wait for the PIXPLL frequency to lock until timeout occurs */ +//unknown on Neomagic?: +/* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("DAC: PIX PLL frequency not locked!\n")); + else + LOG(2,("DAC: PIX PLL frequency locked\n")); + DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL +*/ + +//for now: + /* Give the PIXPLL frequency some time to lock... */ + snooze(1000); + LOG(4,("DAC: PLLSEL $%02x\n", ISARB(MISCR))); + LOG(4,("DAC: PLLN $%02x\n", ISAGRPHR(PLLC_NL))); + LOG(4,("DAC: PLLM $%02x\n", ISAGRPHR(PLLC_M))); + + LOG(2,("DAC: PIX PLL frequency should be locked now...\n")); + + return B_OK; +} + +/* find nearest valid pix pll */ +status_t mn_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, n_max; + float error, error_best = 999999999; + int best[2]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + /* determine the max. VCO oscillator postscaler setting for the current card */ + if (si->ps.card_type < NM2200) + { + LOG(4,("DAC: NM20xx/NM21xx restrictions apply\n")); + n_max = 128; + } + else + { + LOG(4,("DAC: NM22xx/NM23xx restrictions apply\n")); + n_max = 2048; + } + + /* 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; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_24; + break; + } + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_pixel_vco (PLL postscaler does not exist in NM cards) */ + if (req_pclk < si->ps.min_pixel_vco) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)si->ps.min_pixel_vco)); + req_pclk = si->ps.min_pixel_vco; + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* calculate the needed VCO frequency for this postscaler setting + * (NM cards have no PLL postscaler) */ + f_vco = req_pclk; + + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 1; m <= 64; m++) + { + /* only even reference postscaler settings are supported beyond 32 */ + if ((m > 32) && ((m / 2.0) != 0.0)) continue; + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + /* ..and check for validity */ + if ((n < 1) || (n > n_max)) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - ((si->ps.f_ref / m) * n)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0] = m; + best[1] = n; + } + } + + /* setup the scalers programming values for found optimum setting */ + n = best[1] - 1; + /* the reference frequency postscaler are actually two postscalers: + * p can divide by 1 or 2, and m can divide by 1-32. */ + if (best[0] <= 32) + { + m = best[0] - 1; + p = (0 << 7); + } + else + { + m = (best[0] / 2) - 1; + p = (1 << 7); + } + + /* display and return the results */ + *calc_pclk = (si->ps.f_ref / best[0]) * best[1]; + *m_result = m; + if (si->ps.card_type < NM2200) + { + *n_result = ((n & 0x07f) | p); + *p_result = 0; + LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, nm $%02x $%02x\n", + req_pclk, *calc_pclk, *n_result, *m_result)); + } + else + { + *n_result = (n & 0x0ff); + *p_result = (((n & 0x700) >> 4) | p); + LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, pnm $%02x $%02x $%02x\n", + req_pclk, *calc_pclk, *p_result, *n_result, *m_result)); + } + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_general.c b/src/add-ons/accelerants/neomagic/engine/nm_general.c new file mode 100644 index 0000000000..059eea3a61 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_general.c @@ -0,0 +1,514 @@ +/* Author: + Rudolf Cornelissen 4/2003-6/2003 +*/ + +#define MODULE_BIT 0x00008000 + +#include "nm_std.h" + +status_t test_ram(); +static status_t nm_general_powerup (void); +static status_t mn_general_bios_to_powergraphics(void); + +static void nm_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", \ + NMCFG_##reg, #reg, value)); \ +} while (0) + DUMP_CFG (DEVID, 0); + DUMP_CFG (DEVCTRL, 0); + DUMP_CFG (CLASS, 0); + DUMP_CFG (HEADER, 0); + DUMP_CFG (NMBASE2, 0); + DUMP_CFG (NMBASE1, 0); + DUMP_CFG (NMBASE3, 0); + DUMP_CFG (SUBSYSIDR, 0); + DUMP_CFG (ROMBASE, 0); + DUMP_CFG (CAP_PTR, 0); + DUMP_CFG (INTCTRL, 0); + DUMP_CFG (OPTION, 0); + DUMP_CFG (NM_INDEX, 0); + DUMP_CFG (NM_DATA, 0); + DUMP_CFG (SUBSYSIDW, 0); + DUMP_CFG (OPTION2, G100); + DUMP_CFG (OPTION3, 0); + DUMP_CFG (OPTION4, 0); + DUMP_CFG (PM_IDENT, G100); + DUMP_CFG (PM_CSR, G100); + DUMP_CFG (AGP_IDENT, 0); + DUMP_CFG (AGP_STS, 0); + DUMP_CFG (AGP_CMD, 0); +#undef DUMP_CFG +} + +status_t mn_general_powerup() +{ + status_t status; + + LOG(1,("POWERUP: Neomagic (open)BeOS Accelerant 0.03 running.\n")); + + /* detect card type and power it up */ + switch(CFGR(DEVID)) + { + case 0x000110c8: //NM2070 + si->ps.card_type = NM2070; + LOG(4,("POWERUP: Detected MagicGraph 128 (NM2070)\n")); + break; + case 0x000210c8: //NM2090 + si->ps.card_type = NM2090; + LOG(4,("POWERUP: Detected MagicGraph 128V (NM2090)\n")); + break; + case 0x000310c8: //NM2093 + si->ps.card_type = NM2093; + LOG(4,("POWERUP: Detected MagicGraph 128ZV (NM2093)\n")); + break; + case 0x008310c8: //NM2097 PCI + si->ps.card_type = NM2097; + LOG(4,("POWERUP: Detected MagicGraph 128ZV+ (NM2097)\n")); + break; + case 0x000410c8: //NM2160 PCI + si->ps.card_type = NM2160; + LOG(4,("POWERUP: Detected MagicGraph 128XD (NM2160)\n")); + break; + case 0x000510c8: //NM2200 + si->ps.card_type = NM2200; + LOG(4,("POWERUP: Detected MagicMedia 256AV (NM2200)\n")); + break; + case 0x002510c8: //NM2230 + si->ps.card_type = NM2230; + LOG(4,("POWERUP: Detected MagicMedia 256AV+ (NM2230)\n")); + break; + case 0x000610c8: //NM2360 + si->ps.card_type = NM2360; + LOG(4,("POWERUP: Detected MagicMedia 256ZX (NM2360)\n")); + break; + case 0x001610c8: //NM2380 + si->ps.card_type = NM2380; + LOG(4,("POWERUP: Detected MagicMedia 256XL+ (NM2380)\n")); + break; + default: + LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID))); + return B_ERROR; + } + + /* power up the card */ + status = nm_general_powerup(); + + /* override memory detection if requested by user */ + if (si->settings.memory != 0) + si->ps.memory_size = si->settings.memory; + + return status; +} + +status_t test_ram() +{ + uint32 value, offset; + status_t result = B_OK; + + /* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */ + if (si->fbc.frame_buffer == NULL) + { + LOG(8,("INIT: test_ram detected NULL pointer.\n")); + return B_ERROR; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* write testpattern to cardRAM */ + ((uint32 *)si->fbc.frame_buffer)[offset] = value; + /* toggle testpattern */ + value = 0xffffffff - value; + } + + for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) + { + /* readback and verify testpattern from cardRAM */ + if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR; + /* toggle testpattern */ + value = 0xffffffff - value; + } + return result; +} + +/* NOTE: + * This routine *has* to be done *after* SetDispplayMode has been executed, + * or test results will not be representative! + * (CAS latency is dependant on nm setup on some (DRAM) boards) */ +status_t nm_set_cas_latency() +{ + /* 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 */ + LOG(4,("INIT: RAM access errors; not fixable: missing coldstart specs.\n")); + return B_ERROR; +} + +static +status_t nm_general_powerup() +{ + uint8 temp; +// status_t result; + + LOG(4, ("INIT: powerup\n")); + if (si->settings.logmask & 0x80000000) nm_dump_configuration_space(); + + /* set ISA registermapping to VGA colormode */ + temp = (ISARB(MISCR) | 0x01); + /* we need to wait a bit or the card will mess-up it's register values.. */ + snooze(10); + ISAWB(MISCW, temp); + + /* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */ + ISAGRPHW(GRPHXLOCK,0x26); + + /* unlock shadow registers */ +// ISAGRPHW(GENLOCK,0x00);//0x01?? + + /* initialize the shared_info struct */ + set_specs(); + /* log the struct settings */ + dump_specs(); + + /* activate PCI access: b7 = framebuffer, b6 = registers */ + ISAGRPHW(IFACECTRL, 0xc0); + + /* disable VGA-mode cursor (just to be sure) */ + ISACRTCW(VGACURCTRL, 0x00); + + /* 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 mn_general_bios_to_powergraphics(); + + /*power up the PLLs,LUT,DAC*/ + LOG(2,("INIT: powerup\n")); + + /* turn off both displays and the hardcursor (also disables transfers) */ + mn_crtc_dpms(false, false, false); + mn_crtc_cursor_hide(); + + /* setup sequencer clocking mode */ + ISASEQW(CLKMODE, 0x21); + + /* 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 */ + /* set voltage reference - using DAC reference block partly */ +// DXIW(VREFCTRL,0x03); + /* wait for 100ms for voltage reference to stabilize */ + delay(100000); + /* power up the SYSPLL */ +// CFGW(OPTION,CFGR(OPTION)|0x20); + /* power up the PIXPLL */ +// DXIW(PIXCLKCTRL,0x08); + + /* disable pixelclock oscillations before switching on CLUT */ +// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); + /* disable 15bit mode CLUT-overlay function */ +// DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); + /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ +// DXIW(MISCCTRL,0x1b); +// snooze(250); + /* re-enable pixelclock oscillations */ +// DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) & 0xfb)); + + /*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")); + /* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */ +// ACCW(PLNWT,0x00000000); +// ACCW(PLNWT,0xffffffff); + /* program memory control waitstates */ +// ACCW(MCTLWTST,si->ps.mctlwtst_reg); + /* set memory configuration including: + * - 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 RAM read tap delay */ +// CFGW(OPTION2,(CFGR(OPTION2)&0xFFFFFFF0) | ((si->ps.v3_mem_type & 0xf0) >> 4)); + /* wait 200uS minimum */ +// snooze(250); + + /* reset memory (MACCESS is a write only register!) */ +// ACCW(MACCESS, 0x00000000); + /* select JEDEC reset method */ +// ACCW(MACCESS, 0x00004000); + /* perform actual RAM reset */ +// ACCW(MACCESS, 0x0000c000); +// 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 */ + mn_crtc_dpms(true, true, true); + + return B_OK; +} + +status_t nm_general_output_select() +{ + /* log currently selected output */ + switch (nm_general_output_read()) + { + case 0x01: + LOG(2, ("INIT: external CRT only mode active\n")); + break; + case 0x02: + LOG(2, ("INIT: internal LCD only mode active\n")); + break; + case 0x03: + LOG(2, ("INIT: simultaneous LCD/CRT mode active\n")); + break; + } + return B_OK; +} + +uint8 nm_general_output_read() +{ + uint8 output; + + output = (ISAGRPHR(PANELCTRL1) & 0x03); + + if (output == 0) + { + /* using 'failsafe' mode: the flatpanel needs all the protection it can get... */ + LOG(4, ("INIT: illegal outputmode detected, reporting internal mode!\n")); + output = 2; + } + + return output; +} + +/*busy wait until retrace!*/ +status_t mn_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 mn_general_bios_to_powergraphics() +{ + LOG(2, ("INIT: Skipping card coldstart!\n")); + + /* turn off display */ + mn_crtc_dpms(false, false, false); + + /* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */ + /* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */ + ISACRTCW(MODECTL, 0xc3); + /* ... plain sequential memory use, more than 64Kb RAM installed, + * switch to graphics mode ... */ + ISASEQW(MEMMODE, 0x0e); + /* ... disable bitplane tweaking ... */ + ISAGRPHW(ENSETRESET, 0x00); + /* ... no logical function tweaking with display data, no data rotation ... */ + ISAGRPHW(DATAROTATE, 0x00); + /* ... reset read map select to plane 0 ... */ + ISAGRPHW(READMAPSEL, 0x00); + /* ... set standard mode ... */ + ISAGRPHW(MODE, 0x00); + /* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again), + * select standard adressing ... */ + ISAGRPHW(MISC, 0x05); + /* ... disable bit masking ... */ + ISAGRPHW(BITMASK, 0xff); + /* ... attributes are in color, switch to graphics mode (again) ... */ + ISAATBW(MODECTL, 0x01); + /* ... set overscan color to black ... */ + ISAATBW(OSCANCOLOR, 0x00); + /* ... enable all color planes ... */ + ISAATBW(COLPLANE_EN, 0x0f); + /* ... reset horizontal pixelpanning ... */ + ISAATBW(HORPIXPAN, 0x00); + /* ... and reset colorpalette groupselect bits. */ + ISAATBW(COLSEL, 0x00); + + /* setup sequencer clocking mode */ + ISASEQW(CLKMODE, 0x21); + + /* enable memory above 256Kb: set b4 (disables adress wraparound at 256Kb boundary) */ + ISAGRPHW(FBSTADDE, 0x10); + + /* turn on display */ + mn_crtc_dpms(true, true, true); + + return B_OK; +} + +/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify + * virtual_size to the nearest valid maximum for the mode on the card if not so. + * Then: check if virtual_width adheres to the cards _multiple_ constraints, and + * create mode slopspace if not so. + * We use acc multiple constraints here if we expect we can use acceleration, because + * acc constraints are worse than CRTC constraints. + * + * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ +status_t mn_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row) +{ + /* Note: + * This routine assumes that the CRTC memory pitch granularity is 'smaller than', + * or 'equals' the acceleration engine memory pitch granularity! */ + + uint32 video_pitch; + uint32 acc_mask, crtc_mask; + uint8 depth = 8; + +//fixme: checkout the acc pitch constraints for all cards... + /* determine pixel multiple based on 2D/3D engine constraints */ + switch (si->ps.card_type) + { +/* case G100: + switch (target->space) + { + case B_CMAP8: acc_mask = 0x7f; depth = 8; break; + case B_RGB15: acc_mask = 0x3f; depth = 16; break; + case B_RGB16: acc_mask = 0x3f; depth = 16; break; + case B_RGB24: acc_mask = 0x7f; depth = 24; break; + default: + LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); + return B_ERROR; + } + break; +*/ default: + /* see G100 and up specs: + * these cards can do 2D as long as multiples of 32 are used. + * (Note: don't mix this up with adress linearisation!) */ + switch (target->space) + { + case B_CMAP8: depth = 8; break; + case B_RGB15: depth = 16; break; + case B_RGB16: depth = 16; break; + case B_RGB24: depth = 24; break; + default: + LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); + return B_ERROR; + } +//assuming accpitch = 32 for now.. + acc_mask = 0x1f; + break; + } + + /* determine pixel multiple based on CRTC memory pitch constraints. + * (Note: Don't mix this up with CRTC timing contraints! Those are + * multiples of 8 for horizontal, 1 for vertical timing.) + * + * CRTC pitch constraints are the same for all Neomagic cards */ + switch (target->space) + { + case B_CMAP8: crtc_mask = 0x07; break; + case B_RGB15: crtc_mask = 0x03; break; + case B_RGB16: crtc_mask = 0x03; break; + case B_RGB24: crtc_mask = 0x07; break; + default: + LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); + return B_ERROR; + } + + /* check if we can setup this mode with acceleration: + * Max sizes need to adhere to both the acceleration engine _and_ the CRTC constraints! */ + si->acc_mode = true; + /* check virtual_width */ + switch (si->ps.card_type) + { + case G100: + /* acc constraint: */ + if (target->virtual_width > 2048) si->acc_mode = false; + break; + default: + /* G200-G550 */ + /* acc constraint: */ + if (target->virtual_width > 4096) si->acc_mode = false; + /* for 32bit mode a lower CRTC1 restriction applies! */ +// if ((target->space == B_RGB32_LITTLE) && (target->virtual_width > (4092 & ~acc_mask))) +// si->acc_mode = false; + break; + } + /* virtual_height */ + if (target->virtual_height > 2048) si->acc_mode = false; + +//fixme: (temp) +si->acc_mode = false; + + /* now check virtual_size based on CRTC constraints, + * making sure virtual_width stays within the 'mask' constraint: which is only + * nessesary because of an extra constraint in MIL1/2 cards that exists here. */ + +//fixme: checkout cardspecs here!! + + { + /* virtual_width */ + //fixme for CRTC2 (identical on all G400+ cards): + //16bit mode: max. virtual_width == 16352 (no extra mask needed); + //32bit mode: max. virtual_width == 8176 (no extra mask needed); + //other colordepths are unsupported on CRTC2. + switch(target->space) + { + case B_CMAP8: + if (target->virtual_width > (16368 & ~crtc_mask)) + target->virtual_width = (16368 & ~crtc_mask); + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + if (target->virtual_width > (8184 & ~crtc_mask)) + target->virtual_width = (8184 & ~crtc_mask); + break; + case B_RGB24_LITTLE: + if (target->virtual_width > (5456 & ~crtc_mask)) + target->virtual_width = (5456 & ~crtc_mask); + break; + } + + /* virtual_height: The only constraint here is the cards memory size which is + * checked later on in ProposeMode: virtual_height is adjusted then if needed. + * 'Limiting here' to the variable size that's at least available (uint16). */ + if (target->virtual_height > 65535) target->virtual_height = 65535; + } + + /* OK, now we know that virtual_width is valid, and it's needing no slopspace if + * it was confined above, so we can finally calculate safely if we need slopspace + * for this mode... */ + if (si->acc_mode) + video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); + else + video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); + + LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n", + video_pitch, target->space)); + if (target->virtual_width != video_pitch) + LOG(2,("INIT: effective mode slopspace is %d pixels\n", + (video_pitch - target->virtual_width))); + + /* now calculate bytes_per_row for this mode */ + *bytes_per_row = video_pitch * (depth >> 3); + + return B_OK; +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_info.c b/src/add-ons/accelerants/neomagic/engine/nm_info.c new file mode 100644 index 0000000000..b2687cf3f7 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_info.c @@ -0,0 +1,284 @@ +/* setup initialisation information for card */ +/* Authors: + Rudolf Cornelissen 4/2003-5/2003 +*/ + +#define MODULE_BIT 0x00002000 + +#include "nm_std.h" + +void set_nm2070(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 65; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 65; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 65; + si->ps.max_dac1_clock_8 = 65; + si->ps.max_dac1_clock_16 = 65; + /* 24bit color is not supported */ + si->ps.max_dac1_clock_24 = 0; + si->ps.memory_size = 896; + si->ps.curmem_size = 2048; + si->ps.max_crtc_width = 1024; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2090_nm2093(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 80; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 80; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 80; + si->ps.max_dac1_clock_8 = 80; + si->ps.max_dac1_clock_16 = 80; + si->ps.max_dac1_clock_24 = 65; + si->ps.memory_size = 1152; + si->ps.curmem_size = 2048; + si->ps.max_crtc_width = 1024; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2097(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 80; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 80; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 80; + si->ps.max_dac1_clock_8 = 80; + si->ps.max_dac1_clock_16 = 80; + si->ps.max_dac1_clock_24 = 65; + si->ps.memory_size = 1152; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1024; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2160(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 90; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 90; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 90; + si->ps.max_dac1_clock_8 = 90; + si->ps.max_dac1_clock_16 = 90; + si->ps.max_dac1_clock_24 = 70; + si->ps.memory_size = 2048; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1024; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2200(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 110; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 110; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 110; + si->ps.max_dac1_clock_8 = 110; + si->ps.max_dac1_clock_16 = 110; + si->ps.max_dac1_clock_24 = 90; + si->ps.memory_size = 2560; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1280; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2230(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 110; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 110; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 110; + si->ps.max_dac1_clock_8 = 110; + si->ps.max_dac1_clock_16 = 110; + si->ps.max_dac1_clock_24 = 90; + si->ps.memory_size = 3008; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1280; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2360(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 110; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 110; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 110; + si->ps.max_dac1_clock_8 = 110; + si->ps.max_dac1_clock_16 = 110; + si->ps.max_dac1_clock_24 = 90; + si->ps.memory_size = 4096; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1280; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_nm2380(void) +{ + /* setup cardspecs */ + si->ps.f_ref = 14.31818; + si->ps.max_system_vco = 110; + si->ps.min_system_vco = 11; + si->ps.max_pixel_vco = 110; + si->ps.min_pixel_vco = 11; + si->ps.max_dac1_clock = 110; + si->ps.max_dac1_clock_8 = 110; + si->ps.max_dac1_clock_16 = 110; + si->ps.max_dac1_clock_24 = 90; + si->ps.memory_size = 6144; + si->ps.curmem_size = 1024; + si->ps.max_crtc_width = 1280; + si->ps.max_crtc_height = 1024; + si->ps.std_engine_clock = 0; +} + +void set_specs(void) +{ + uint8 size_outputs, type; + + LOG(8,("INFO: setting cardspecs\n")); + + switch (si->ps.card_type) + { + case NM2070: + set_nm2070(); + break; + case NM2090: + case NM2093: + set_nm2090_nm2093(); + break; + case NM2097: + set_nm2097(); + break; + case NM2160: + set_nm2160(); + break; + case NM2200: + set_nm2200(); + break; + case NM2230: + set_nm2230(); + break; + case NM2360: + set_nm2360(); + break; + case NM2380: + set_nm2380(); + break; + } + + /* get output properties: */ + /* read panelsize and preselected outputs (via BIOS) */ + size_outputs = ISAGRPHR(PANELCTRL1); + /* read the panel type */ + type = ISAGRPHR(PANELTYPE); + + /* setup panelspecs */ + switch ((size_outputs & 0x18) >> 3) + { + case 0x00 : + si->ps.panel_width = 640; + si->ps.panel_height = 480; + break; + case 0x01 : + si->ps.panel_width = 800; + si->ps.panel_height = 600; + break; + case 0x02 : + si->ps.panel_width = 1024; + si->ps.panel_height = 768; + break; + case 0x03 : + /* fixme: 1280x1024 panel support still needs to be done */ + si->ps.panel_width = 1280; + si->ps.panel_height = 1024; + } + /* make note of paneltype */ + si->ps.panel_type = (type & 0x12); + /* make note of preselected outputs (via BIOS) */ + si->ps.outputs = (size_outputs & 0x03); + /* check for illegal setting */ + if (si->ps.outputs == 0) + { + LOG(4, ("INFO: illegal outputmode detected, defaulting to internal mode!\n")); + si->ps.outputs = 2; +//fixme: then also activate this mode in the card.... + } +} + +void dump_specs(void) +{ + LOG(2,("INFO: cardspecs and settings follow:\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,("std_engine_clock: %dMhz\n", si->ps.std_engine_clock)); + LOG(2,("max_dac1_clock: %dMhz\n", si->ps.max_dac1_clock)); + LOG(2,("max_dac1_clock_8: %dMhz\n", si->ps.max_dac1_clock_8)); + LOG(2,("max_dac1_clock_16: %dMhz\n", si->ps.max_dac1_clock_16)); + LOG(2,("max_dac1_clock_24: %dMhz\n", si->ps.max_dac1_clock_24)); + LOG(2,("card memory_size: %dKbytes\n", si->ps.memory_size)); + LOG(2,("card curmem_size: %dbytes\n", si->ps.curmem_size)); + LOG(2,("card max_crtc_width: %d\n", si->ps.max_crtc_width)); + LOG(2,("card max_crtc_height: %d\n", si->ps.max_crtc_height)); + switch (si->ps.panel_type) + { + case 0x00: + LOG(2, ("B/W dualscan LCD panel detected\n")); + break; + case 0x02: + LOG(2, ("color dualscan LCD panel detected\n")); + break; + case 0x10: + LOG(2, ("B/W TFT LCD panel detected\n")); + break; + case 0x12: + LOG(2, ("color TFT LCD panel detected\n")); + break; + } + LOG(2,("internal panel width: %d\n", si->ps.panel_width)); + LOG(2,("internal panel height: %d\n", si->ps.panel_height)); + switch (si->ps.outputs) + { + case 0x01: + LOG(2, ("external CRT only mode preset\n")); + break; + case 0x02: + LOG(2, ("internal LCD only mode preset\n")); + break; + case 0x03: + LOG(2, ("simultaneous LCD/CRT mode preset\n")); + break; + } + LOG(2,("INFO: end cardspecs and settings.\n")); +} diff --git a/src/add-ons/accelerants/neomagic/engine/nm_proto.h b/src/add-ons/accelerants/neomagic/engine/nm_proto.h new file mode 100644 index 0000000000..a4b37bf617 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_proto.h @@ -0,0 +1,75 @@ +/*general card functions*/ +status_t mn_general_powerup(); +status_t nm_set_cas_latency(); +status_t nm_general_output_select(); +uint8 nm_general_output_read(); +status_t mn_general_dac_select(int); +status_t mn_general_wait_retrace(); +status_t mn_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row); +//status_t mn_general_bios_to_powergraphics(); + +/* apsed: logging macros */ +#define MSG(args) do { /* if needed or si->settings with si NULL */ \ + nm_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) nm_log args; \ +} while (0) + +/*support functions*/ +void delay(bigtime_t i); +void nm_log(char *format, ...); + +/*card info functions*/ +void set_specs(void); +void dump_specs(void); + +/*DAC functions*/ +status_t mn_dac_mode(int,float); +status_t mn_dac_palette(uint8*,uint8*,uint8*, uint16); +status_t mn_dac_pix_pll_find(display_mode target,float * result,uint8 *,uint8 *,uint8 *); +status_t mn_dac_set_pix_pll(display_mode target); + +/*CRTC1 functions*/ +status_t mn_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 mn_crtc_set_timing(display_mode target, bool crt_only); +status_t mn_crtc_depth(int mode); +status_t mn_crtc_set_display_start(uint32 startadd,uint8 bpp); +status_t mn_crtc_set_display_pitch(); +status_t mn_crtc_center(display_mode target); + +status_t mn_crtc_dpms(bool, bool, bool); +status_t mn_crtc_dpms_fetch(bool*, bool*, bool*); +status_t mn_crtc_mem_priority(uint8); + +status_t mn_crtc_cursor_init(); /*Yes, cursor follows CRTC1 - not the DAC!*/ +status_t mn_crtc_cursor_define(uint8*,uint8*); +status_t mn_crtc_cursor_position(uint16 x ,uint16 y); +status_t mn_crtc_cursor_show(); +status_t mn_crtc_cursor_hide(); + +/*acceleration functions*/ +status_t check_acc_capability(uint32 feature); +status_t mn_acc_init(); +status_t mn_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); +status_t mn_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); +status_t mn_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 ); +status_t mn_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32); +status_t mn_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd); +status_t mn_acc_wait_idle(); + +/*backend scaler functions*/ +status_t check_overlay_capability(uint32 feature); +status_t mn_configure_bes + (const overlay_buffer *ob, const overlay_window *ow,const overlay_view *ov, int offset); +status_t mn_release_bes(); + +/*driver structures and enums*/ +enum{BPP8=0,BPP15=1,BPP16=2,BPP24=3}; +enum{DS_CRTC1DAC_CRTC2MAVEN, DS_CRTC1MAVEN_CRTC2DAC, DS_CRTC1CON1_CRTC2CON2, DS_CRTC1CON2_CRTC2CON1}; diff --git a/src/add-ons/accelerants/neomagic/engine/nm_std.h b/src/add-ons/accelerants/neomagic/engine/nm_std.h new file mode 100644 index 0000000000..70044d2c39 --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_std.h @@ -0,0 +1,8 @@ +#include +#include +#include +#include +#include "DriverInterface.h" +#include "global.h" +#include "nm_proto.h" +#include "nm_macros.h" diff --git a/src/add-ons/accelerants/neomagic/engine/nm_support.c b/src/add-ons/accelerants/neomagic/engine/nm_support.c new file mode 100644 index 0000000000..8fa16ede0b --- /dev/null +++ b/src/add-ons/accelerants/neomagic/engine/nm_support.c @@ -0,0 +1,30 @@ +/* Some commmon support functions */ +/* Mark Watson 2/2000 */ + +#define MODULE_BIT 0x00000800 + +#include +#include "nm_std.h" + +/*delays in multiple of microseconds*/ +void delay(bigtime_t i) +{ + bigtime_t start=system_time(); + while(system_time()-start