From b408aaf70ae331b21e3928c90e917ebb2a053405 Mon Sep 17 00:00:00 2001 From: shatty Date: Tue, 2 Dec 2003 22:05:11 +0000 Subject: [PATCH] openBeOS_Matrox_V0.14_src git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5541 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../private/graphics/matrox/DriverInterface.h | 18 +- headers/private/graphics/matrox/mga_macros.h | 100 +- src/add-ons/accelerants/matrox/Acceleration.c | 37 +- src/add-ons/accelerants/matrox/Cursor.c | 95 +- .../accelerants/matrox/GetAccelerantHook.c | 149 +- .../accelerants/matrox/InitAccelerant.c | 22 +- src/add-ons/accelerants/matrox/Overlay.c | 5 +- .../accelerants/matrox/ProposeDisplayMode.c | 396 +++--- .../accelerants/matrox/SetDisplayMode.c | 419 +++--- src/add-ons/accelerants/matrox/engine/Jamfile | 2 +- .../matrox/engine/matroxfb_maven_hack.c | 879 ------------ .../matrox/engine/matroxfb_maven_hack.h | 88 -- .../accelerants/matrox/engine/mga_acc.c | 175 ++- .../accelerants/matrox/engine/mga_bes.c | 78 +- .../accelerants/matrox/engine/mga_crtc.c | 209 ++- .../accelerants/matrox/engine/mga_crtc2.c | 216 ++- .../accelerants/matrox/engine/mga_dac.c | 263 +++- .../accelerants/matrox/engine/mga_general.c | 358 ++++- .../accelerants/matrox/engine/mga_info.c | 229 +++- .../accelerants/matrox/engine/mga_maven.c | 571 ++++++-- .../accelerants/matrox/engine/mga_maventv.c | 1210 +++++++++++++++++ .../accelerants/matrox/engine/mga_proto.h | 37 +- .../accelerants/matrox/engine/tvp3026.c | 577 +------- 23 files changed, 3743 insertions(+), 2390 deletions(-) delete mode 100644 src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c delete mode 100644 src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h create mode 100644 src/add-ons/accelerants/matrox/engine/mga_maventv.c diff --git a/headers/private/graphics/matrox/DriverInterface.h b/headers/private/graphics/matrox/DriverInterface.h index bc683e21f2..74d2c961a7 100644 --- a/headers/private/graphics/matrox/DriverInterface.h +++ b/headers/private/graphics/matrox/DriverInterface.h @@ -5,7 +5,7 @@ Other authors: Mark Watson; Apsed; - Rudolf Cornelissen 10/2002. + Rudolf Cornelissen 10/2002-4/2003. */ #ifndef DRIVERINTERFACE_H @@ -87,6 +87,7 @@ typedef struct settings { // apsed, see comments in mga.settings uint32 memory; bool usebios; bool hardcursor; + bool greensync; } settings; /*shared info*/ @@ -136,28 +137,33 @@ typedef struct { uint16 width; /* Width and height of the cursor shape (always 16!) */ uint16 height; bool is_visible; /* Is the cursor currently displayed? */ - }cursor; + } cursor; /*colour lookup table*/ uint8 color_data[3 * 256]; /* Colour lookup table - as used by DAC */ /*more display mode stuff*/ - display_mode dm; /* current display mode configuration */ + display_mode dm; /* current display mode configuration: head1 */ + display_mode dm2; /* current display mode configuration: head2 */ + bool switched_crtcs; /* dualhead stretch and switch mode info */ + bool acc_mode; /* signals (non)accelerated mode */ + bool interlaced_tv_mode;/* signals interlaced CRTC TV output mode */ /*frame buffer config - for BDirectScreen*/ - frame_buffer_config fbc; /* bytes_per_row and start of frame buffer */ + frame_buffer_config fbc; /* bytes_per_row and start of frame buffer: head1 */ + frame_buffer_config fbc2; /* bytes_per_row and start of frame buffer: head2 */ /*acceleration engine*/ struct { uint32 count; /* last dwgsync slot used */ uint32 last_idle; /* last dwgsync slot we *know* the engine was idle after */ benaphore lock; /* for serializing access to the acceleration engine */ - } engine; + } engine; /* card info - information gathered from PINS (and other sources) */ enum { // card_type in order of date of MGA chip design - MILL=0, + MIL1 = 0, MYST, MIL2, G100, diff --git a/headers/private/graphics/matrox/mga_macros.h b/headers/private/graphics/matrox/mga_macros.h index 0500d6b367..7fe8382774 100644 --- a/headers/private/graphics/matrox/mga_macros.h +++ b/headers/private/graphics/matrox/mga_macros.h @@ -27,7 +27,7 @@ #define MGACFG_AGP_STS 0xf4 // >= MIL2 #define MGACFG_AGP_CMD 0xf8 // >= MIL2 -/*VGA registers - these are byte wide*/ +/* VGA registers - these are byte wide */ #define MGAVGA_ATTR_I 0x1FC0 // apsed as SEQ #define MGAVGA_ATTR_D 0x1FC1 // apsed as SEQ #define MGAVGA_MISCW 0x1FC2 @@ -45,7 +45,38 @@ #define MGAVGA_CRTCEXT_I 0x1FDE #define MGAVGA_CRTCEXT_D 0x1FDF -/*DAC registers (>= g100) */ +/* TVP3026 'non-std' DAC registers (>= MIL1) */ +#define MGADAC_TVP_CUROVRWTADD 0x3c04 +#define MGADAC_TVP_CUROVRDATA 0x3c05 +#define MGADAC_TVP_CUROVRRDADD 0x3c07 +#define MGADAC_TVP_DIRCURCTRL 0x3c09 +#define MGADAC_TVP_CURRAMDATA 0x3c0b + +/* TVP3026 'non'std' (D)AC (X) (I)ndexed registers (>= MIL1) */ +#define MGADXI_TVP_SILICONREV 0x01 +#define MGADXI_TVP_LATCHCTRL 0x0f +#define MGADXI_TVP_TCOLCTRL 0x18 +#define MGADXI_TVP_CLOCKSEL 0x1a +#define MGADXI_TVP_PALPAGE 0x1c +#define MGADXI_TVP_PLLADDR 0x2c +#define MGADXI_TVP_PIXPLLDATA 0x2d +#define MGADXI_TVP_MEMPLLDATA 0x2e +#define MGADXI_TVP_LOOPLLDATA 0x2f +#define MGADXI_TVP_COLKEYOL 0x30 +#define MGADXI_TVP_COLKEYOH 0x31 +#define MGADXI_TVP_COLKEYRL 0x32 +#define MGADXI_TVP_COLKEYRH 0x33 +#define MGADXI_TVP_COLKEYGL 0x34 +#define MGADXI_TVP_COLKEYGH 0x35 +#define MGADXI_TVP_COLKEYBL 0x36 +#define MGADXI_TVP_COLKEYBH 0x37 +#define MGADXI_TVP_COLKEYCTRL 0x38 +#define MGADXI_TVP_MEMCLKCTRL 0x39 +#define MGADXI_TVP_TESTMODEDATA 0x3b +#define MGADXI_TVP_ID 0x3f +#define MGADXI_TVP_RESET 0xff + +/* DAC registers (>= G100) */ #define MGADAC_PALWTADD 0x3C00 #define MGADAC_PALDATA 0x3C01 #define MGADAC_PIXRDMSK 0x3C02 @@ -56,7 +87,7 @@ #define MGADAC_CURSPOSYL 0x3C0E #define MGADAC_CURSPOSYH 0x3C0F -/*(D)AC (X) (I)ndexed registers (>= g100) */ +/* (D)AC (X) (I)ndexed registers (>= G100) */ #define MGADXI_CURADDL 0x04 #define MGADXI_CURADDH 0x05 #define MGADXI_CURCTRL 0x06 @@ -101,7 +132,7 @@ #define MGADXI_PIXPLLSTAT 0x4F #define MGADXI_CURCOLEXT 0x60 /*sequential from CURCOL3->15, RGB*/ -/*(D)AC (X) (I)ndexed registers (>= g200) */ +/* (D)AC (X) (I)ndexed registers (>= G200) */ #define MGADXI_KEYOPMODE 0x51 #define MGADXI_COLMSK0RED 0x52 #define MGADXI_COLMSK0GREEN 0x53 @@ -110,7 +141,7 @@ #define MGADXI_COLKEY0GREEN 0x56 #define MGADXI_COLKEY0BLUE 0x57 -/*(D)AC (X) (I)ndexed registers (>= g450?) */ +/* (D)AC (X) (I)ndexed registers (>= G450) */ #define MGADXI_TVO_IDX 0x87 #define MGADXI_TVO_DATA 0x88 #define MGADXI_OUTPUTCONN 0x8A @@ -122,11 +153,10 @@ #define MGADXI_PWRCTRL 0xA0 #define MGADXI_PANMODE 0xA2 -/*MGA 1st CRTC registers */ +/* MGA 1st CRTC registers */ #define MGACR1_VCOUNT 0x1E20 -//end rudolf. -/*MGA 2nd CRTC registers >= ?? TODO */ +/* MGA 2nd CRTC registers (>= G400) */ #define MGACR2_CTL 0x3C10 #define MGACR2_HPARAM 0x3C14 #define MGACR2_HSYNC 0x3C18 @@ -134,12 +164,13 @@ #define MGACR2_VSYNC 0x3C20 #define MGACR2_PRELOAD 0x3C24 #define MGACR2_STARTADD0 0x3C28 +#define MGACR2_STARTADD1 0x3C2C #define MGACR2_OFFSET 0x3C40 #define MGACR2_MISC 0x3C44 #define MGACR2_VCOUNT 0x3C48 #define MGACR2_DATACTL 0x3C4C -/*MGA ACCeleration registers*/ +/* MGA ACCeleration registers */ #define MGAACC_DWGCTL 0x1C00 #define MGAACC_MACCESS 0x1C04 #define MGAACC_MCTLWTST 0x1C08 @@ -183,7 +214,7 @@ #define MGAACC_SRCORG 0x2CB4 // >= G200 #define MGAACC_DSTORG 0x2CB8 // >= G200 -/*MGA BES (Back End Scaler) registers >= TODO */ +/*MGA BES (Back End Scaler) registers (>= G200) */ #define MGABES_A1ORG 0x3D00 #define MGABES_A2ORG 0x3D04 #define MGABES_B1ORG 0x3D08 @@ -213,15 +244,34 @@ #define MGABES_GLOBCTL 0x3DC0 #define MGABES_STATUS 0x3DC4 -/*MAVEN registers >= TODO */ +/*MAVEN registers (<= G400) */ +#define MGAMAV_PGM 0x3E #define MGAMAV_PIXPLLM 0x80 #define MGAMAV_PIXPLLN 0x81 #define MGAMAV_PIXPLLP 0x82 +#define MGAMAV_GAMMA1 0x83 +#define MGAMAV_GAMMA2 0x84 +#define MGAMAV_GAMMA3 0x85 +#define MGAMAV_GAMMA4 0x86 +#define MGAMAV_GAMMA5 0x87 +#define MGAMAV_GAMMA6 0x88 +#define MGAMAV_GAMMA7 0x89 +#define MGAMAV_GAMMA8 0x8A +#define MGAMAV_GAMMA9 0x8B #define MGAMAV_MONSET 0x8C #define MGAMAV_TEST 0x8D +#define MGAMAV_WREG_0X8E_L 0x8E +#define MGAMAV_WREG_0X8E_H 0x8F +#define MGAMAV_HSCALETV 0x90 +#define MGAMAV_TSCALETVL 0x91 +#define MGAMAV_TSCALETVH 0x92 +#define MGAMAV_FFILTER 0x93 #define MGAMAV_MONEN 0x94 +#define MGAMAV_RESYNC 0x95 #define MGAMAV_LASTLINEL 0x96 #define MGAMAV_LASTLINEH 0x97 +#define MGAMAV_WREG_0X98_L 0x98 +#define MGAMAV_WREG_0X98_H 0x99 #define MGAMAV_HSYNCLENL 0x9A #define MGAMAV_HSYNCLENH 0x9B #define MGAMAV_HSYNCSTRL 0x9C @@ -242,56 +292,60 @@ #define MGAMAV_HVIDRSTH 0xAB #define MGAMAV_VVIDRSTL 0xAC #define MGAMAV_VVIDRSTH 0xAD +#define MGAMAV_VSOMETHINGL 0xAE +#define MGAMAV_VSOMETHINGH 0xAF #define MGAMAV_OUTMODE 0xB0 #define MGAMAV_LOCK 0xB3 #define MGAMAV_LUMA 0xB9 +#define MGAMAV_VDISPLAYTV 0xBE #define MGAMAV_STABLE 0xBF +#define MGAMAV_HDISPLAYTV 0xC2 +#define MGAMAV_BREG_0XC6 0xC6 -/*Macros for convenient accesses to the G400*/ +/* Macros for convenient accesses to the MGA chips */ #define MGA_REG8(r_) ((vuint8 *)regs)[(r_)] #define MGA_REG32(r_) ((vuint32 *)regs)[(r_) >> 2] -/*read and write to PCI config space*/ +/* read and write to PCI config space */ #define CFGR(A) (gx00_pci_access.offset=MGACFG_##A, ioctl(fd,GX00_GET_PCI, &gx00_pci_access,sizeof(gx00_pci_access)), gx00_pci_access.value) #define CFGW(A,B) (gx00_pci_access.offset=MGACFG_##A, gx00_pci_access.value = B, ioctl(fd,GX00_SET_PCI,&gx00_pci_access,sizeof(gx00_pci_access))) -/*read and write from the dac registers*/ +/* read and write from the dac registers */ #define DACR(A) (MGA_REG8(MGADAC_##A)) #define DACW(A,B) (MGA_REG8(MGADAC_##A)=B) -/*read and write from the dac index register*/ +/* read and write from the dac index register */ #define DXIR(A) (DACW(PALWTADD,MGADXI_##A),DACR(X_DATAREG)) #define DXIW(A,B) (DACW(PALWTADD,MGADXI_##A),DACW(X_DATAREG,B)) -/*read and write from the vga registers*/ +/* read and write from the vga registers */ #define VGAR(A) (MGA_REG8(MGAVGA_##A)) #define VGAW(A,B) (MGA_REG8(MGAVGA_##A)=B) -/*read and write from the indexed vga registers*/ +/* read and write from the indexed vga registers */ #define VGAR_I(A,B) (VGAW(A##_I,B),VGAR(A##_D)) #define VGAW_I(A,B,C) (VGAW(A##_I,B),VGAW(A##_D,C)) -/*read and write from the powergraphics registers*/ +/* read and write from the powergraphics registers */ #define ACCR(A) (MGA_REG32(MGAACC_##A)) #define ACCW(A,B) (MGA_REG32(MGAACC_##A)=B) #define ACCGO(A,B) (MGA_REG32(MGAACC_##A + 0x0100)=B) -/*read and write from the backend scaler registers*/ +/* read and write from the backend scaler registers */ #define BESR(A) (MGA_REG32(MGABES_##A)) #define BESW(A,B) (MGA_REG32(MGABES_##A)=B) -/*read and write from first CRTC*/ +/* read and write from first CRTC */ #define CR1R(A) (MGA_REG32(MGACR1_##A)) #define CR1W(A,B) (MGA_REG32(MGACR1_##A)=B) -/*read and write from second CRTC*/ +/* read and write from second CRTC */ #define CR2R(A) (MGA_REG32(MGACR2_##A)) #define CR2W(A,B) (MGA_REG32(MGACR2_##A)=B) -/*read and write from maven*/ +/* read and write from maven (<= G400) */ #define MAVR(A) (i2c_maven_read (MGAMAV_##A )) #define MAVW(A,B) (i2c_maven_write(MGAMAV_##A ,B)) #define MAVRW(A) (i2c_maven_read (MGAMAV_##A )|(i2c_maven_read(MGAMAV_##A +1)<<8)) #define MAVWW(A,B) (i2c_maven_write(MGAMAV_##A ,B &0xFF),i2c_maven_write(MGAMAV_##A +1,B >>8)) -#define MAVWWP(A,B) (i2c_maven_write(A ,B &0xFF),i2c_maven_write(A +1,B >>8)) diff --git a/src/add-ons/accelerants/matrox/Acceleration.c b/src/add-ons/accelerants/matrox/Acceleration.c index fa070846e2..06d08e3a80 100644 --- a/src/add-ons/accelerants/matrox/Acceleration.c +++ b/src/add-ons/accelerants/matrox/Acceleration.c @@ -4,7 +4,8 @@ Other authors: Mark Watson, - Apsed. + Apsed, + Rudolf Cornelissen 2/2003. */ #define MODULE_BIT 0x40000000 @@ -33,19 +34,27 @@ void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) { } } -//Not possible with G400 AFAIK (if anyone knows otherwise then please contact me) -//void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { -//typedef struct { -// uint16 src_left; /* guaranteed constrained to virtual width and height */ -// uint16 src_top; -// uint16 src_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ -// uint16 src_height; /* 0 to M, where zero means one line, one means two lines, etc. */ -// uint16 dest_left; -// uint16 dest_top; -// uint16 dest_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ -// uint16 dest_height; /* 0 to M, where zero means one line, one means two lines, etc. */ -//} scaled_blit_params; -//} +void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { + int i; + + /*do each blit*/ + i=0; + while (count--) + { + gx00_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; diff --git a/src/add-ons/accelerants/matrox/Cursor.c b/src/add-ons/accelerants/matrox/Cursor.c index f8e902e9ba..72536dca7c 100644 --- a/src/add-ons/accelerants/matrox/Cursor.c +++ b/src/add-ons/accelerants/matrox/Cursor.c @@ -3,13 +3,14 @@ This file may be used under the terms of the Be Sample Code License. Other authors: - Mark Watson + Mark Watson, + Rudolf Cornelissen 4/2003 */ #define MODULE_BIT 0x20000000 /*DUALHEAD notes - - No hardware cursor possible:( + No hardware cursor possible on the secondary head :( Reasons: CRTC1 has a cursor, can be displayed on DAC or MAVEN CRTC2 has no cursor @@ -54,48 +55,96 @@ void MOVE_CURSOR(uint16 x, uint16 y) uint16 h_adjust; /* clamp cursor to display */ - if (x >= si->dm.virtual_width) x = si->dm.virtual_width-1; - if (y >= si->dm.virtual_height) y = si->dm.virtual_height-1; + 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; + si->cursor.x = x; + si->cursor.y = y; /*set up minimum amount to scroll*/ - switch(si->dm.space) + if (si->dm.flags & DUALHEAD_BITS) { - case B_CMAP8: - h_adjust=7; - break; - case B_RGB15_LITTLE:case B_RGB16_LITTLE: - h_adjust=3; - break; - case B_RGB32_LITTLE: - h_adjust=1; - break; - default: - h_adjust=7; + switch(si->dm.space) + { + case B_RGB16_LITTLE: + h_adjust = 0x1f; + break; + case B_RGB32_LITTLE: + h_adjust = 0x0f; + break; + default: + h_adjust = 0x1f; + break; + } + } + else + { + switch(si->dm.space) + { + case B_CMAP8: + h_adjust = 0x07; + break; + case B_RGB15_LITTLE:case B_RGB16_LITTLE: + h_adjust = 0x03; + break; + case B_RGB32_LITTLE: + h_adjust = 0x01; + break; + default: + h_adjust = 0x07; + break; + } } /* adjust h/v_display_start to move cursor onto screen */ - if (x >= (si->dm.timing.h_display + hds)) - hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust; - else if (x < hds) - hds = x & ~h_adjust; + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (x >= ((si->dm.timing.h_display * 2) + hds)) + { + hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust; + /* make sure we stay within the display! */ + if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width) + hds -= (h_adjust + 1); + } + else if (x < hds) + hds = x & ~h_adjust; + break; + default: + if (x >= (si->dm.timing.h_display + hds)) + { + hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust; + /* make sure we stay within the display! */ + if ((hds + si->dm.timing.h_display) > si->dm.virtual_width) + hds -= (h_adjust + 1); + } + else if (x < hds) + hds = x & ~h_adjust; + break; + } if (y >= (si->dm.timing.v_display + vds)) vds = y - si->dm.timing.v_display + 1; else if (y < vds) vds = y; - /* reposition the desktop on the display if required */ + /* reposition the desktop _and_ the overlay on the display if required */ if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start)) + { MOVE_DISPLAY(hds,vds); + //fixme: implement: + //move_overlay(hds,vds); + } /* put cursor in correct physical position */ x -= hds + si->cursor.hot_x; y -= vds + si->cursor.hot_y; + /* account for switched CRTC's */ + if (si->switched_crtcs) x -= si->dm.timing.h_display; + /* position the cursor on the display */ gx00_crtc_cursor_position(x,y); } diff --git a/src/add-ons/accelerants/matrox/GetAccelerantHook.c b/src/add-ons/accelerants/matrox/GetAccelerantHook.c index 89a2089de5..30fc30e307 100644 --- a/src/add-ons/accelerants/matrox/GetAccelerantHook.c +++ b/src/add-ons/accelerants/matrox/GetAccelerantHook.c @@ -4,7 +4,7 @@ Other authors: Mark Watson, - Rudolf Cornelissen 10/2002 + Rudolf Cornelissen 10/2002-4/2003 */ #define MODULE_BIT 0x08000000 @@ -12,7 +12,6 @@ #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 @@ -20,26 +19,30 @@ function. The extra information (which is specific to the feature) is pointed at by the void *data parameter. By default, no extra information is available. Any extra information available to choose the function will be noted on a case by case below. - */ -void * get_accelerant_hook(uint32 feature, void *data) { - switch (feature) { /* These definitions are out of pure lazyness. */ #define CHKO(x) case B_##x: \ if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 +#define CHKA(x) case B_##x: \ + if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 #define HOOK(x) case B_##x: return (void *)x #define ZERO(x) case B_##x: return (void *)0 #define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed -/* -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. -*/ +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); @@ -67,7 +70,7 @@ initialization process. HOOK(SET_DPMS_MODE); /* cursor managment */ - HRDC(SET_CURSOR_SHAPE); // apsed + HRDC(SET_CURSOR_SHAPE); HRDC(MOVE_CURSOR); HRDC(SHOW_CURSOR); @@ -79,6 +82,13 @@ initialization process. 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); @@ -90,31 +100,36 @@ initialization process. CHKO(RELEASE_OVERLAY); CHKO(CONFIGURE_OVERLAY); -/* -When requesting an acceleration hook, the calling application provides a -pointer to the display_mode for which the acceleration function will be used. -Depending on the engine architecture, you may choose to provide a different -function to be used with each bit-depth. In the sample driver we return -the same function all the time. -*/ - /* 2D acceleration */ - HOOK(SCREEN_TO_SCREEN_BLIT); - HOOK(FILL_RECTANGLE); - HOOK(INVERT_RECTANGLE); - HOOK(FILL_SPAN); - HOOK(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);//remove for pre R5 + /* + 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. - /*HOOK(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT; - Does the G400 support this? I can only think of using texture mapped rectangles, but these seem to have too many restrictions to do this:( e.g. I would need to blit offscreen, into texture format... - */ -#undef HOOK -#undef ZERO + 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 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) { @@ -155,21 +170,71 @@ status_t check_overlay_capability(uint32 feature) break; } - switch(si->ps.card_type) + if (si->ps.card_type >= G200) { - case G200: - case G400: - case G400MAX: - case G450: /* is also G550 in accelerant for now */ - case G550: /* not used in accelerant yet */ /* export video overlay functions */ LOG(4, ("Overlay: Exporting hook %s.\n", msg)); return B_OK; + } + + /* 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: - /* do not export video overlay functions */ - LOG(4, ("Overlay: Not exporting hook %s.\n", msg)); - return B_ERROR; + 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/matrox/InitAccelerant.c b/src/add-ons/accelerants/matrox/InitAccelerant.c index 195fb03cc2..d20ae2fa45 100644 --- a/src/add-ons/accelerants/matrox/InitAccelerant.c +++ b/src/add-ons/accelerants/matrox/InitAccelerant.c @@ -4,7 +4,7 @@ Other authors: Mark Watson, - Rudolf Cornelissen 10/2002. + Rudolf Cornelissen 10/2002-3/2003. */ #define MODULE_BIT 0x00800000 @@ -40,7 +40,8 @@ static status_t init_common(int the_fd) { 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)); + LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, greensync %d\n", + si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync)); /*Check for R4.5.0 and if it is running, use work around*/ { @@ -151,8 +152,11 @@ status_t INIT_ACCELERANT(int the_fd) { info in a frame_buffer_config structure to make it convienient to return to the app_server later. */ - //don't reserve memory at the start of the fb, because this doesn't work on the G100 (no SRCORG/DSTORG) - pointer_reservation = si->settings.hardcursor? 1024: 0; // apsed TODO with G100, see before + pointer_reservation = 0; + /* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */ + if ((si->ps.card_type >= G100) && si->settings.hardcursor) + pointer_reservation = 1024; + si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation); si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation); @@ -260,6 +264,8 @@ status_t CLONE_ACCELERANT(void *data) { if (result < B_OK) goto error2; /* all done */ + LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n")); + result = B_OK; goto error0; @@ -273,7 +279,13 @@ error0: return result; } -void UNINIT_ACCELERANT(void) { +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); diff --git a/src/add-ons/accelerants/matrox/Overlay.c b/src/add-ons/accelerants/matrox/Overlay.c index fd5a05fbd5..1f269521ee 100644 --- a/src/add-ons/accelerants/matrox/Overlay.c +++ b/src/add-ons/accelerants/matrox/Overlay.c @@ -1,4 +1,4 @@ -/* Written by Rudolf Cornelissen 05/10-2002 */ +/* 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' @@ -106,6 +106,9 @@ const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint /* 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; diff --git a/src/add-ons/accelerants/matrox/ProposeDisplayMode.c b/src/add-ons/accelerants/matrox/ProposeDisplayMode.c index 429af2309e..ba728da42b 100644 --- a/src/add-ons/accelerants/matrox/ProposeDisplayMode.c +++ b/src/add-ons/accelerants/matrox/ProposeDisplayMode.c @@ -4,7 +4,7 @@ Other authors for MGA driver: Mark Watson, - Rudolf Cornelissen 9/2002 + Rudolf Cornelissen 9/2002-4/2003 */ #define MODULE_BIT 0x00400000 @@ -12,7 +12,8 @@ #include "acc_std.h" #define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) -#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS) +/* 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*/ @@ -36,8 +37,8 @@ static const display_mode mode_list[] = { { { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ { { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ { { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ -{ { 108000, 1152, 1216, 1344, 1550, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ -{ { 120000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ +{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ +{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ { { 120000, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ { { 108000, 1280, 1328, 1440, 1680, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */ { { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */ @@ -50,56 +51,32 @@ static const display_mode mode_list[] = { { { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */ }; -// apsed, adjust virtual width for CRTC offset constraints -// PB with MIl2 800*600 with bpp < 32 -static status_t adjust_width (display_mode *target, bool want_same_width) -{ - uint32 video_pitch = target->virtual_width; - uint32 multiple; - - if (si->ps.card_type < G100) switch (target->space & 0x0fff) { // MIL2 - case B_CMAP8: multiple = 128; break; - case B_RGB15: multiple = 64; break; - case B_RGB16: multiple = 64; break; - case B_RGB24: multiple = 128; break; - case B_RGB32: multiple = 32; break; - default: - LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space)); - return B_ERROR; - } else switch (target->space & 0x0fff) { // G100, G200, G400 - case B_CMAP8: multiple = 16; break; - case B_RGB15: multiple = 8; break; - case B_RGB16: multiple = 8; break; - case B_RGB24: multiple = 16; break; - case B_RGB32: multiple = 4; break; - default: - LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space)); - return B_ERROR; - } - video_pitch = (video_pitch+multiple-1)/multiple; - video_pitch *= multiple; - if (target->virtual_width != video_pitch) { - LOG(2,("PROPOSEMODE: color space 0x%08x, virtual_width %d adjusted to %d \n", - target->space, target->virtual_width, video_pitch)); - target->virtual_width = video_pitch; - if (want_same_width) target->timing.h_display = video_pitch; - } - return B_OK; -} - -/*Check mode is between low and high limits - returns: - B_OK - found one - B_BAD_VALUE - mode can be made, but outside limits - B_ERROR - not possible +/* +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; + status_t status = B_OK; float pix_clock_found; uint8 m,n,p; - status_t result = B_OK; - uint32 row_bytes, limit_clock, max_vclk; + status_t result; + uint32 max_vclk, row_bytes, pointer_reservation; double target_refresh = ((double)target->timing.pixel_clock * 1000.0) / ( (double)target->timing.h_total * @@ -109,9 +86,8 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con want_same_width = target->timing.h_display == target->virtual_width, want_same_height = target->timing.v_display == target->virtual_height; -// // apsed, adjust virtual width for CRTC offset constraints -// status = adjust_width (target, want_same_width); -// if (status != B_OK) return status; + 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) @@ -132,6 +108,8 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con 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=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 - ); + ((double)target->timing.h_total * (double)target->timing.v_total); } } #endif @@ -175,113 +151,149 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total, &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total ); - if (result == B_ERROR) return result; - - /*check if timing found is within the requested horizontal limits*/ - if ( - (target->timing.h_display < low->timing.h_display) || - (target->timing.h_display > high->timing.h_display) || - (target->timing.h_sync_start < low->timing.h_sync_start) || - (target->timing.h_sync_start > high->timing.h_sync_start) || - (target->timing.h_sync_end < low->timing.h_sync_end) || - (target->timing.h_sync_end > high->timing.h_sync_end) || - (target->timing.h_total < low->timing.h_total) || - (target->timing.h_total > high->timing.h_total) - ) result = B_BAD_VALUE; - - /*check if timing found is within the requested vertical limits*/ - if ( - (target->timing.v_display < low->timing.v_display) || - (target->timing.v_display > high->timing.v_display) || - (target->timing.v_sync_start < low->timing.v_sync_start) || - (target->timing.v_sync_start > high->timing.v_sync_start) || // apsed - (target->timing.v_sync_end < low->timing.v_sync_end) || - (target->timing.v_sync_end > high->timing.v_sync_end) || - (target->timing.v_total < low->timing.v_total) || - (target->timing.v_total > high->timing.v_total) - ) result = B_BAD_VALUE; - - //rudolf - /* adjust pixelclock for possible timing modifications done above */ - target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0; - - /* Now find the nearest valid pixelclock we actually can setup for the target mode, - * this also makes sure we don't generate more pixel bandwidth than the device can handle */ - if (si->ps.card_type >= G100) + if (result == B_ERROR) { - /* calculate settings, but do not actually test anything (that costs too much time!) */ - status = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0); + LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n")); + return result; } - else - { - //fixme: implement pixelclock limits check (and modify if needed) for target mode inside mil2_find routine! - //temp until then: - limit_clock = si->ps.max_dac1_clock * 1000; - if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock; - - status = mil2_dac_pix_pll_find((float)target->timing.pixel_clock/1000.0,&pix_clock_found,&m,&n,&p); - } - target->timing.pixel_clock = pix_clock_found*1000; - //end rudolf - - /* note if we fell outside the limits */ - if ( - (target->timing.pixel_clock < low->timing.pixel_clock) || - (target->timing.pixel_clock > high->timing.pixel_clock) - ) result = B_BAD_VALUE; /* validate display vs. virtual */ if ((target->timing.h_display > target->virtual_width) || want_same_width) target->virtual_width = target->timing.h_display; if ((target->timing.v_display > target->virtual_height) || want_same_height) target->virtual_height = target->timing.v_display; - if (target->virtual_width > 4096) - target->virtual_width = 4096; - if (target->virtual_height > 2048) - target->virtual_height = 2048; - /* adjust virtual width for engine limitations - must be multiple of 8 */ - target->virtual_width = (target->virtual_width + 7) & ~7; - if ( - (target->virtual_width < low->virtual_width) || - (target->virtual_width > high->virtual_width) - ) result = B_BAD_VALUE; - - // apsed, adjust virtual width for CRTC offset constraints - status = adjust_width (target, want_same_width); - if (status != B_OK) return status; - - /* calculate rowbytes after we've nailed the virtual width */ - switch (target->space & 0x0fff) { - case B_CMAP8: - row_bytes = 1; - break; - case B_RGB15: - case B_RGB16: - row_bytes = 2; - break; - case B_RGB32: - row_bytes = 4; - break; - default: - /* no amount of adjusting will fix not being able to support the pixel format */ - LOG(8,("PROPOSEMODE: unknown target space: 0x%08x\n", target->space)); - return B_ERROR; + /* nail virtual size and 'subsequently' calculate rowbytes */ + result = gx00_general_validate_pic_size (target, &row_bytes); + if (result == B_ERROR) + { + LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n")); + return result; } - row_bytes *= target->virtual_width; + /*check if virtual_width is still within the requested limits*/ + if ((target->virtual_width < low->virtual_width) || + (target->virtual_width > high->virtual_width)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n")); + } + + /*check if timing found is within the requested horizontal limits*/ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display) || + (target->timing.h_sync_start < low->timing.h_sync_start) || + (target->timing.h_sync_start > high->timing.h_sync_start) || + (target->timing.h_sync_end < low->timing.h_sync_end) || + (target->timing.h_sync_end > high->timing.h_sync_end) || + (target->timing.h_total < low->timing.h_total) || + (target->timing.h_total > high->timing.h_total)) + { + /* BWindowScreen workaround: we accept everything except h_display deviations */ + if ((target->timing.h_display < low->timing.h_display) || + (target->timing.h_display > high->timing.h_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n")); + } + + /*check if timing found is within the requested vertical limits*/ + if ( + (target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display) || + (target->timing.v_sync_start < low->timing.v_sync_start) || + (target->timing.v_sync_start > high->timing.v_sync_start) || + (target->timing.v_sync_end < low->timing.v_sync_end) || + (target->timing.v_sync_end > high->timing.v_sync_end) || + (target->timing.v_total < low->timing.v_total) || + (target->timing.v_total > high->timing.v_total) + ) + { + /* BWindowScreen workaround: we accept everything except v_display deviations */ + if ((target->timing.v_display < low->timing.v_display) || + (target->timing.v_display > high->timing.v_display)) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n")); + } + + /* adjust pixelclock for possible timing modifications done above */ + target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0; + + /* Now find the nearest valid pixelclock we actually can setup for the target mode, + * this also makes sure we don't generate more pixel bandwidth than the device can handle */ + /* calculate settings, but do not actually test anything (that costs too much time!) */ + result = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0); + /* update the target mode */ + target->timing.pixel_clock = (pix_clock_found * 1000); + + /* note if we fell outside the limits */ + if ((target->timing.pixel_clock < low->timing.pixel_clock) || + (target->timing.pixel_clock > high->timing.pixel_clock) + ) + { + /* BWindowScreen workaround: we accept deviations <= 1Mhz */ + if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) || + (target->timing.pixel_clock > (high->timing.pixel_clock + 1000))) + { + status = B_BAD_VALUE; + } + else + { + status = B_OK; + } + LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n")); + } + + /* checkout space needed for hardcursor (if any) */ + pointer_reservation = 0; + /* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */ + if ((si->ps.card_type >= G100) && si->settings.hardcursor) pointer_reservation = 1024; /* memory requirement for frame buffer */ - if ((row_bytes * target->virtual_height) > (si->ps.memory_size * 1024 * 1024)) - target->virtual_height = (si->ps.memory_size * 1024 * 1024) / row_bytes; + if ((row_bytes * target->virtual_height) > + ((si->ps.memory_size * 1024 * 1024) - pointer_reservation)) + { + target->virtual_height = + ((si->ps.memory_size * 1024 * 1024) - pointer_reservation) / row_bytes; + } if (target->virtual_height < target->timing.v_display) { - LOG(8,("PROPOSEMODE: virtual_height required %d < %d\n", target->virtual_height, target->timing.v_display)); + LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n")); return B_ERROR; } - else if ( - (target->virtual_height < low->virtual_height) || - (target->virtual_height > high->virtual_height) - ) result = B_BAD_VALUE; + LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n", + target->virtual_width, target->virtual_height)); + + if ((target->virtual_height < low->virtual_height) || + (target->virtual_height > high->virtual_height)) + { + status = B_BAD_VALUE; + LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n")); + } + + /* setup status flags */ + LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags)); + /* preset to singlehead card without TVout, no overlay support and no hardcursor. + * also advice system that app_server and acc engine may touch the framebuffer + * simultaneously (fixed). */ + target->flags &= + ~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA); + /* we always allow parallel access (fixed), the DAC is always in 'enhanced' + * mode (fixed), and all modes support DPMS (fixed); + * We support scrolling and panning in every mode, so we 'send a signal' to + * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */ + //fixme: secondary head does not support DPMS... + target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL); /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */ switch (target->space) @@ -305,43 +317,68 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con break; } - /*clear DUALHEAD_CAPABLE if any problems*/ - if - ( - ((target->flags)& DUALHEAD_CAPABLE ) && - ( - (!si->ps.secondary_head) || - ((1024 + (row_bytes * (target->virtual_height+1) * 2)) > (si->ps.memory_size * 1024 * 1024)) || /*note: extra line for maven vblank!*/ - (target->space == B_CMAP8) || - (target->space == B_RGB15_LITTLE) || - (target->timing.pixel_clock > (max_vclk * 1000)) - ) - ) + /* set DUALHEAD_CAPABLE if suitable */ + //fixme: update for independant secondary head use! (reserve fixed memory then) + if (si->ps.secondary_head && + (((si->ps.memory_size * 1024 * 1024) - pointer_reservation) >= + /* note: extra line for maven vblank included here! */ + (row_bytes * (target->virtual_height + 1) * 2)) && + ((target->space == B_RGB16_LITTLE) || (target->space == B_RGB32_LITTLE)) && + (target->timing.pixel_clock <= (max_vclk * 1000))) { - target->flags&=~DUALHEAD_CAPABLE; + target->flags |= DUALHEAD_CAPABLE; } - /*set tv capable suitable*/ - if (target->flags&DUALHEAD_CAPABLE) + /* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */ + //fixme: modify for G100 and G200 TVout later on... + if (target->flags & DUALHEAD_CAPABLE) { - if ((target->timing.pixel_clock <= 120000 ) && (target->timing.pixel_clock >= 40000)) + if (si->ps.secondary_tvout && + (target->timing.h_display <= 1024) && + (target->timing.v_display <= 768)) { - target->flags|=TV_CAPABLE; + target->flags |= TV_CAPABLE; } } - return result; + /* 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 >= G200) + target->flags |= B_SUPPORTS_OVERLAYS; + + LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags)); + + /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE, + * progressive scan (fixed), and setup sync_on_green flag according to + * mga.settings options file */ + target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN); + if (si->settings.greensync) + target->timing.flags |= B_SYNC_ON_GREEN; + /* The HSYNC and VSYNC command flags are actually executed by the driver. */ + + if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n")); + else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n")); + return status; } /* Return the number of modes this device will return from GET_MODE_LIST(). This is precalculated in create_mode_list (called from InitAccelerant stuff) */ -uint32 ACCELERANT_MODE_COUNT(void) { +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) { +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; } @@ -366,7 +403,7 @@ status_t create_mode_list(void) { max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1); /* create an area to hold the info */ si->mode_area = my_mode_list_area = - create_area("G400 accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + create_area("MGA 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 */ @@ -380,22 +417,25 @@ status_t create_mode_list(void) { pix_clk_range = low.timing.pixel_clock >> 5; low.timing.pixel_clock -= pix_clk_range; high.timing.pixel_clock += pix_clk_range; - /* some cards need wider virtual widths for certain modes */ - high.virtual_width = 4096; + /* '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 for single head (propose will return if capable)*/ + /* set target values */ *dst = *src; - /* poke the specific space*/ + /* poke the specific space */ dst->space = low.space = high.space = spaces[j]; - dst->flags |= DUALHEAD_CAPABLE; - - dst->flags |= B_SUPPORTS_OVERLAYS; - //fixme: we need to distinquish somehow between head 1 and head 2, as overlay only works on head 1... - /* ask for a compatible mode */ - if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) { + /* 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++; diff --git a/src/add-ons/accelerants/matrox/SetDisplayMode.c b/src/add-ons/accelerants/matrox/SetDisplayMode.c index f900f64cd8..d2e1ab7b56 100644 --- a/src/add-ons/accelerants/matrox/SetDisplayMode.c +++ b/src/add-ons/accelerants/matrox/SetDisplayMode.c @@ -5,15 +5,13 @@ Other authors: Mark Watson, Apsed, - Rudolf Cornelissen 11-12/2002 + Rudolf Cornelissen 11/2002-4/2003 */ #define MODULE_BIT 0x00200000 #include "acc_std.h" -#include "matroxfb_maven_hack.h" //a port of the matroxfb code to do TVout - used with permission - /* Enable/Disable interrupts. Just a wrapper around the ioctl() to the kernel driver. @@ -32,155 +30,188 @@ static void interrupt_enable(bool flag) { /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) { - display_mode bounds, target; + /* 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=32; + uint8 colour_depth1 = 32; status_t result; uint32 startadd,startadd_right; // apsed TODO startadd is 19 bits if < g200 uint8 display,h,v; - - struct my_timming tv_timing; - struct mavenregs tv_regs; - - bool switched_crtcs = false; + si->switched_crtcs = false; /* Adjust mode to valid one and fail if invalid */ - target = bounds = *mode_to_set; + target /*= bounds*/ = *mode_to_set; /* show the mode bits */ - LOG(1, ("SetDisplayMode - initial flags: %x\n", target.flags)); - LOG(1, ("SetDisplayMode - %20s %08x %d\n", "timing.pixel_clock", mode_to_set->timing.pixel_clock, mode_to_set->timing.pixel_clock)); - LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_width", mode_to_set->virtual_width, mode_to_set->virtual_width)); - LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_height", mode_to_set->virtual_height, mode_to_set->virtual_height)); + 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)); - if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR) - return B_ERROR; + /* See BOUNDS WARNING above... */ + if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; - /* if not dualhead capable be sure mode is set to single head */ - if ((!si->ps.secondary_head) || (!(target.flags&DUALHEAD_CAPABLE))) + /* if not dualhead capable card clear dualhead flags */ + if (!(target.flags & DUALHEAD_CAPABLE)) { - target.flags&=~DUALHEAD_BITS; - target.flags&=~TV_BITS; + target.flags &= ~DUALHEAD_BITS; } - else if (!(target.flags&TV_CAPABLE)) + /* if not TVout capable card clear TVout flags */ + if (!(target.flags & TV_CAPABLE)) { - target.flags&=~TV_BITS; + target.flags &= ~TV_BITS; } - - LOG(1, ("SetDisplayMode - validated flags: %x\n", target.flags)); + LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags)); /* disable interrupts using the kernel driver */ interrupt_enable(false); - /*find current DPMS state, then turn off screen*/ + /* find current DPMS state, then turn off screen(s) */ gx00_crtc_dpms_fetch(&display,&h,&v); gx00_crtc_dpms(0,0,0); - if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken - g400_crtc2_dpms(0,0,0); - if (si->ps.secondary_head) - gx00_maven_dpms(0,0,0); + if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0); /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ - startadd=(si->fbc.frame_buffer)-(si->framebuffer); + startadd = si->fbc.frame_buffer - si->framebuffer; + + /* calculate and set new mode bytes_per_row */ + gx00_general_validate_pic_size (&target, &si->fbc.bytes_per_row); /*Perform the very long mode switch!*/ - LOG(1,("DUALHEAD: %d\n",target.flags&DUALHEAD_BITS)); - if ((target.flags&DUALHEAD_BITS)) /*if some dualhead mode*/ + if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ { - uint16 crtc1_vdisplay, crtc2_vdisplay; + uint8 colour_depth2 = colour_depth1; - /*set the pixel clock PLL(s)*/ - if (gx00_dac_set_pix_pll(target)==B_ERROR) - LOG(8,("SET: error setting pixel clock (internal DAC)\n")); - if (si->ps.secondary_head) + /* init display mode for secondary head */ + display_mode target2 = target; + + LOG(1,("SETMODE: setting DUALHEAD mode\n")); + + /* validate flags for secondary TVout */ + if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS)) { - if (gx00_maven_set_pix_pll((target.timing.pixel_clock)/1000.0)==B_ERROR) - LOG(8,("SET: error setting pixel clock (MAVEN)\n")); - } - else - { - LOG(8,("SET: not setting maven clock (G450?)\n")); + target.flags &= ~TV_BITS;//still needed for some routines... + target2.flags &= ~TV_BITS; + LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); } - /*set the colour depth for CRTC1, CRTC2, the DAC and the MAVEN */ + /* set the pixel clock PLL(s) */ + LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); + if (gx00_dac_set_pix_pll(target) == B_ERROR) + LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); + + /* we do not need to set the pixelclock here for a head that's in TVout mode */ + if (!(target2.flags & TV_BITS)) + { + LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); + if (gx00_maven_set_vid_pll(target2) == B_ERROR) + LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n")); + } + + /*set the colour depth for CRTC1 and the DAC */ switch(target.space) { case B_RGB16_LITTLE: - colour_depth=16; + colour_depth1 = 16; gx00_dac_mode(BPP16, 1.0); - gx00_maven_mode(BPP16, 1.0); gx00_crtc_depth(BPP16); + break; + case B_RGB32_LITTLE: + colour_depth1 = 32; + gx00_dac_mode(BPP32, 1.0); + gx00_crtc_depth(BPP32); + break; + } + /*set the colour depth for CRTC2 and the MAVEN */ + switch(target2.space) + { + case B_RGB16_LITTLE: + colour_depth2 = 16; + gx00_maven_mode(BPP16, 1.0); g400_crtc2_depth(BPP16); break; case B_RGB32_LITTLE: - colour_depth=32; - gx00_dac_mode(BPP32, 1.0); + colour_depth2 = 32; gx00_maven_mode(BPP32DIR, 1.0); - gx00_crtc_depth(BPP32); g400_crtc2_depth(BPP32DIR); break; - default: - LOG(8,("SET: Invalid dualhead colour depth 0x%08x - should never happen!\n", target.space)); } + /* check if we are doing interlaced TVout mode */ + si->interlaced_tv_mode = false; + if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450)) + si->interlaced_tv_mode = true; + /*set the display(s) pitches*/ - gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); - g400_crtc2_set_display_pitch (target.virtual_width, colour_depth); + gx00_crtc_set_display_pitch (); + //fixme: seperate for real dualhead modes: + //we need a secondary si->fbc! + g400_crtc2_set_display_pitch (); /*work out where the "right" screen starts*/ - startadd_right=startadd+(target.timing.h_display*(colour_depth>>3)); + startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3)); /* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */ - si->crtc_delay = 44 + 0 * (colour_depth == 16); + si->crtc_delay = 44 + 0 * (colour_depth2 == 16); /* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */ - crtc1_vdisplay = target.timing.v_display; /* (extra "blanking" line for MAVEN) */ - crtc2_vdisplay = target.timing.v_display + 1; + target2.timing.v_display++; /* set the outputs */ switch (si->ps.card_type) { case G400: case G400MAX: - switch (target.flags&DUALHEAD_BITS) + switch (target.flags & DUALHEAD_BITS) { case DUALHEAD_ON: case DUALHEAD_CLONE: gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); - switched_crtcs = false; + si->switched_crtcs = false; break; case DUALHEAD_SWITCH: if (i2c_sec_tv_adapter() == B_OK) { /* Don't switch CRTC's because MAVEN YUV is impossible then, * and primary head output will be limited to 135Mhz pixelclock. */ - LOG(4,("SET: secondary TV-adapter detected, switching buffers\n")); + LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); - switched_crtcs = true; + si->switched_crtcs = true; } else { /* This limits the pixelclocks on both heads to 135Mhz, * but you can use overlay on the other output now. */ - LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n")); + LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); gx00_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC); - switched_crtcs = false; + si->switched_crtcs = false; /* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */ - si->crtc_delay = 17 + 4 * (colour_depth == 16); + si->crtc_delay = 17 + 4 * (colour_depth1 == 16); /* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */ /* (extra "blanking" line for MAVEN) */ - crtc1_vdisplay = target.timing.v_display + 1; - crtc2_vdisplay = target.timing.v_display; + target.timing.v_display++; + target2.timing.v_display--; } break; } break; //fixme: - //use current SETMODE MAVEN programming only on G400/G400MAX; - //and copy & modify/resetup this stuff for G450(?)/G550 cards! - //warning: //setup crtc_delay and vertical timing adjust for G450(?)/G550, //and remove the '+1' in crtc2 vertical timing(?) case G450: @@ -189,29 +220,29 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) /* output connector use is always 'straight-through' */ //fixme: re-evaluate when DVI is setup... { - switch (target.flags&DUALHEAD_BITS) + switch (target.flags & DUALHEAD_BITS) { case DUALHEAD_ON: case DUALHEAD_CLONE: gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); - switched_crtcs = false; + si->switched_crtcs = false; break; case DUALHEAD_SWITCH: if (i2c_sec_tv_adapter() == B_OK) { /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, * and primary head output will be limited to 235Mhz pixelclock. */ - LOG(4,("SET: secondary TV-adapter detected, switching buffers\n")); + LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); - switched_crtcs = true; + si->switched_crtcs = true; } else { /* This limits the pixelclocks on both heads to 235Mhz, * but you can use overlay on the other output now. */ - LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n")); + LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1); - switched_crtcs = false; + si->switched_crtcs = false; } break; } @@ -220,21 +251,21 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) /* output connector use is cross-linked if no TV cable connected! */ //fixme: re-evaluate when DVI is setup... { - switch (target.flags&DUALHEAD_BITS) + switch (target.flags & DUALHEAD_BITS) { case DUALHEAD_ON: case DUALHEAD_CLONE: if (i2c_sec_tv_adapter() == B_OK) { gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); - switched_crtcs = false; + si->switched_crtcs = false; } else { /* This limits the pixelclocks on both heads to 235Mhz, * but you can use overlay on the other output now. */ gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1); - switched_crtcs = false; + si->switched_crtcs = false; } break; case DUALHEAD_SWITCH: @@ -242,15 +273,15 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) { /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, * and primary head output will be limited to 235Mhz pixelclock. */ - LOG(4,("SET: secondary TV-adapter detected, switching buffers\n")); + LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); - switched_crtcs = true; + si->switched_crtcs = true; } else { - LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n")); + LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); - switched_crtcs = false; + si->switched_crtcs = false; } break; } @@ -260,149 +291,87 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) break; } - if (switched_crtcs) + if (si->switched_crtcs) { - int temp = startadd; + uint32 temp = startadd; startadd = startadd_right; startadd_right = temp; } /*Tell card what memory to display*/ - switch (target.flags&DUALHEAD_BITS) + switch (target.flags & DUALHEAD_BITS) { case DUALHEAD_ON: case DUALHEAD_SWITCH: - gx00_crtc_set_display_start(startadd,colour_depth); - g400_crtc2_set_display_start(startadd_right,colour_depth); + gx00_crtc_set_display_start(startadd,colour_depth1); + g400_crtc2_set_display_start(startadd_right,colour_depth2); break; case DUALHEAD_CLONE: - gx00_crtc_set_display_start(startadd,colour_depth); - g400_crtc2_set_display_start(startadd,colour_depth); + gx00_crtc_set_display_start(startadd,colour_depth1); + g400_crtc2_set_display_start(startadd,colour_depth2); break; } - /*set the timing*/ + /* set the timing */ result = gx00_crtc_set_timing /*crtc1*/ ( target.timing.h_display, target.timing.h_sync_start, target.timing.h_sync_end, target.timing.h_total, - crtc1_vdisplay, + target.timing.v_display, target.timing.v_sync_start, target.timing.v_sync_end, target.timing.v_total, target.timing.flags&B_POSITIVE_HSYNC, target.timing.flags&B_POSITIVE_VSYNC ); + /* we do not need to setup CRTC2 here for a head that's in TVout mode */ + if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2); - result = g400_crtc2_set_timing - ( - target.timing.h_display, - target.timing.h_sync_start, - target.timing.h_sync_end, - target.timing.h_total, - crtc2_vdisplay, - target.timing.v_sync_start, - target.timing.v_sync_end, - target.timing.v_total, - target.timing.flags&B_POSITIVE_HSYNC, - target.timing.flags&B_POSITIVE_VSYNC - ); - if (si->ps.secondary_head) + /* TVout support: setup CRTC2 and it's pixelclock */ + if (si->ps.secondary_tvout && (target2.flags & TV_BITS)) { - result = gx00_maven_set_timing /*maven*/ - ( - target.timing.h_display, - target.timing.h_sync_start, - target.timing.h_sync_end, - target.timing.h_total, - (target.timing.v_display+1), /* The extra "blanking" line */ - target.timing.v_sync_start, - target.timing.v_sync_end, - target.timing.v_total, - target.timing.flags&B_POSITIVE_HSYNC, - target.timing.flags&B_POSITIVE_VSYNC - ); - } - - /*turn screen one on and screen two on*/ - gx00_crtc_dpms(display,h,v); - g400_crtc2_dpms(display,h,v); - if (si->ps.secondary_head) - gx00_maven_dpms(display,h,v); - - /*TVout support*/ - if (si->ps.secondary_tvout && (target.flags&TV_BITS)) - { - //fixme: re-tune if needed, checkout cross and straight crtc's seperately.. - si->crtc_delay+=5; - - /*create a my tim(m)ing structure... for tvout*/ - tv_timing.pixclock = target.timing.pixel_clock; - tv_timing.HDisplay = target.timing.h_display; - tv_timing.HSyncStart = target.timing.h_sync_start; - tv_timing.HSyncEnd = target.timing.h_sync_end; - tv_timing.HTotal = target.timing.h_total; - tv_timing.VDisplay = target.timing.v_display; - tv_timing.VSyncStart = target.timing.v_sync_start; - tv_timing.VSyncEnd = target.timing.v_sync_end; - tv_timing.VTotal = target.timing.v_total; - tv_timing.delay=si->crtc_delay; - - if (target.flags&TV_PAL) - { - LOG(2, ("OUTMODE: PAL\n")); - maven_set_mode(1); - } - else - { - LOG(2, ("OUTMODE: NTSC\n")); - maven_set_mode(2); - } - - maven_out_compute(&tv_timing, &tv_regs); - maven_out_program(&tv_regs); - maven_out_start(); + si->crtc_delay += 5; + maventv_init(target2); } } - else /*single head mode*/ + else /* single head mode */ { status_t status; - int colour_mode = BPP32; + int colour_mode = BPP32; switch(target.space) { - case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break; - case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break; - case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break; - case B_RGB32_LITTLE: colour_depth = 32; colour_mode = BPP32; break; + case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; + case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; + case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; + case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; default: - LOG(8,("SET: Invalid singlehead colour depth 0x%08x\n", target.space)); + LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); return B_ERROR; } - /*set the pixel clock PLL*/ + /* set the pixel clock PLL */ if (si->ps.card_type >= G100) status = gx00_dac_set_pix_pll(target); - else status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth); + else + { + status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth1); + } if (status==B_ERROR) LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); - /*set the colour depth for CRTC1 and the DAC*/ - if (si->ps.card_type >= G100) gx00_dac_mode(colour_mode,1.0); - else mil2_dac_mode(colour_mode,1.0, - target.timing.flags&B_POSITIVE_HSYNC, - target.timing.flags&B_POSITIVE_VSYNC, - target.timing.flags&B_SYNC_ON_GREEN); - + /* set the colour depth for CRTC1 and the DAC */ + gx00_dac_mode(colour_mode,1.0); gx00_crtc_depth(colour_mode); - /*set the display pitch*/ - gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); + /* set the display pitch */ + gx00_crtc_set_display_pitch(); + + /* tell the card what memory to display */ + gx00_crtc_set_display_start(startadd,colour_depth1); - /*tell the card what memory to display*/ - gx00_crtc_set_display_start(startadd,colour_depth); /* enable primary analog output */ switch (si->ps.card_type) { @@ -421,7 +390,7 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) break; } - /*set the timing*/ + /* set the timing */ result = gx00_crtc_set_timing /*crtc1*/ ( target.timing.h_display, @@ -436,33 +405,32 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set) target.timing.flags&B_POSITIVE_VSYNC ); - /*turn screen one on and screen two off*/ - gx00_crtc_dpms(display,h,v); - if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken - g400_crtc2_dpms(0,0,0); - if (si->ps.secondary_head) - gx00_maven_dpms(0,0,0); + //fixme: shut-off the videoPLL if it exists... } - /*update driver's mode store*/ - si->dm=target; - si->fbc.bytes_per_row=target.virtual_width*(colour_depth>>3); + /* update driver's mode store */ + si->dm = target; - /*set up acceleration for this mode*/ - si->dm.virtual_height+=1;//for clipping! + /* turn screen one on */ + gx00_crtc_dpms(display,h,v); + /* turn screen two on if a dualhead mode is active */ + if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v); + + /* set up acceleration for this mode */ + si->dm.virtual_height += 1;//for clipping! gx00_acc_init(); - si->dm.virtual_height-=1; + si->dm.virtual_height -= 1; - /*clear line at bottom of screen (For maven) if dualhead mode*/ + /* clear line at bottom of screen (for maven) if dualhead mode */ gx00_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0); - MSG(("INIT_ACCELERANT: booted since %f ms\n", system_time()/1000.0)); + MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0)); /* enable interrupts using the kernel driver */ interrupt_enable(true); /* optimize memory-access if needed */ - gx00_crtc_mem_priority(colour_depth); + gx00_crtc_mem_priority(colour_depth1); /* Tune RAM CAS-latency if needed. Must be done *here*! */ mga_set_cas_latency(); @@ -486,7 +454,7 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { */ /* reset lower bits, don't return an error! */ - if (si->dm.flags&DUALHEAD_BITS) + if (si->dm.flags & DUALHEAD_BITS) { switch(si->dm.space) { @@ -525,8 +493,18 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { } /* do not run past end of display */ - if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) - return B_ERROR; + switch (si->dm.flags & DUALHEAD_BITS) + { + case DUALHEAD_ON: + case DUALHEAD_SWITCH: + if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) + return B_ERROR; + break; + default: + if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) + return B_ERROR; + break; + } if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) return B_ERROR; @@ -535,16 +513,26 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { si->dm.v_display_start = v_display_start; /* actually set the registers */ - startadd=v_display_start*(si->dm.virtual_width*colour_depth)>>3; - startadd+=h_display_start; - startadd+=(si->fbc.frame_buffer)-(si->framebuffer); - startadd_right=startadd+si->dm.timing.h_display*(colour_depth>>3); + //fixme: seperate both heads: we need a secondary si->fbc! + startadd = v_display_start * si->fbc.bytes_per_row; + startadd += h_display_start * (colour_depth >> 3); + startadd += si->fbc.frame_buffer - si->framebuffer; + startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); + + /* account for switched CRTC's */ + if (si->switched_crtcs) + { + uint32 temp = startadd; + startadd = startadd_right; + startadd_right = temp; + } interrupt_enable(false); switch (si->dm.flags&DUALHEAD_BITS) { case DUALHEAD_ON: + case DUALHEAD_SWITCH: gx00_crtc_set_display_start(startadd,colour_depth); g400_crtc2_set_display_start(startadd_right,colour_depth); break; @@ -555,10 +543,6 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { gx00_crtc_set_display_start(startadd,colour_depth); g400_crtc2_set_display_start(startadd,colour_depth); break; - case DUALHEAD_SWITCH: - g400_crtc2_set_display_start(startadd,colour_depth); - gx00_crtc_set_display_start(startadd_right,colour_depth); - break; } interrupt_enable(true); @@ -587,8 +571,7 @@ void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags b[i]=*color_data++; i++; } - if (si->ps.card_type >= G100) gx00_dac_palette(r,g,b); - else mil2_dac_palette(r,g,b); + gx00_dac_palette(r,g,b); } @@ -600,9 +583,7 @@ enum { BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF }; -/* - Put the display into one of the Display Power Management modes. -*/ +/* Put the display into one of the Display Power Management modes. */ status_t SET_DPMS_MODE(uint32 dpms_flags) { interrupt_enable(false); @@ -614,27 +595,19 @@ status_t SET_DPMS_MODE(uint32 dpms_flags) { { case B_DPMS_ON: /* H: on, V: on */ gx00_crtc_dpms(1,1,1); - g400_crtc2_dpms(1,1,1); - if (si->ps.secondary_head) - gx00_maven_dpms(1,1,1); + if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1); break; case B_DPMS_STAND_BY: gx00_crtc_dpms(0,0,1); - g400_crtc2_dpms(0,0,1); - if (si->ps.secondary_head) - gx00_maven_dpms(0,0,1); + if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1); break; case B_DPMS_SUSPEND: gx00_crtc_dpms(0,1,0); - g400_crtc2_dpms(0,1,0); - if (si->ps.secondary_head) - gx00_maven_dpms(0,1,0); + if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0); break; case B_DPMS_OFF: /* H: off, V: off, display off */ gx00_crtc_dpms(0,0,0); - g400_crtc2_dpms(0,0,0); - if (si->ps.secondary_head) - gx00_maven_dpms(0,0,0); + if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0); break; default: LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); diff --git a/src/add-ons/accelerants/matrox/engine/Jamfile b/src/add-ons/accelerants/matrox/engine/Jamfile index 1380162af2..5ac0a0653e 100644 --- a/src/add-ons/accelerants/matrox/engine/Jamfile +++ b/src/add-ons/accelerants/matrox/engine/Jamfile @@ -5,7 +5,6 @@ UsePrivateHeaders [ FDirName graphics matrox ] ; UseHeaders [ FDirName $(SUBDIR) .. ] ; StaticLibrary matrox_engine : - matroxfb_maven_hack.c mga_acc.c mga_bes.c mga_crtc.c @@ -15,6 +14,7 @@ StaticLibrary matrox_engine : mga_i2c.c mga_info.c mga_maven.c + mga_maventv.c mga_support.c tvp3026.c ; diff --git a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c deleted file mode 100644 index 081d0d0f86..0000000000 --- a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.c +++ /dev/null @@ -1,879 +0,0 @@ -#define MODULE_BIT 0x00100000 - -#include "mga_std.h" -#include "matroxfb_maven_hack.h" - -#define MODE_PAL 1 -#define MODE_NTSC 2 -#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC)) -#define MODE_MONITOR 128 - -static int mode = MODE_PAL; - -static const struct matrox_pll_features maven_pll = { - 50000, - 27000, - 4, 127, - 2, 31, - 3 -}; - -static const struct matrox_pll_features2 maven1000_pll = { - 50000000, - 300000000, - 5, 128, - 3, 32, - 3 -}; - -static const struct matrox_pll_ctl maven_PAL = { - 540000, - 50 -}; - -static const struct matrox_pll_ctl maven_NTSC = { - 450450, /* 27027000/60 == 27000000/59.94005994 */ - 60 -}; - - -int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax, - unsigned int* in, unsigned int* feed, unsigned int* post) { - unsigned int bestdiff = ~0; - unsigned int bestvco = 0; - unsigned int fxtal = pll->ref_freq; - unsigned int fwant; - unsigned int p; - - LOG(4,("PLL_calcclock")); - - fwant = freq; - - for (p = 1; p <= pll->post_shift_max; p++) { - if (fwant * 2 > fmax) - break; - fwant *= 2; - } - if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min; - if (fwant > fmax) fwant = fmax; - for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { - unsigned int m; - - if (fwant < pll->vco_freq_min) break; - for (m = pll->in_div_min; m <= pll->in_div_max; m++) { - unsigned int diff, fvco; - unsigned int n; - - n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; - if (n > pll->feed_div_max) - break; - if (n < pll->feed_div_min) - n = pll->feed_div_min; - fvco = (fxtal * (n + 1)) / (m + 1); - if (fvco < fwant) - diff = fwant - fvco; - else - diff = fvco - fwant; - if (diff < bestdiff) { - bestdiff = diff; - *post = p; - *in = m; - *feed = n; - bestvco = fvco; - } - } - } - LOG(4,("clk: %x %x %x %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant)); - return bestvco; -} - -int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, - const struct matrox_pll_ctl* ctl, - unsigned int htotal, unsigned int vtotal, - unsigned int* in, unsigned int* feed, unsigned int* post, - unsigned int* h2) { - unsigned int besth2 = 0; - unsigned int fxtal = ctl->ref_freq; - unsigned int fmin = pll->vco_freq_min / ctl->den; - unsigned int fwant; - unsigned int p; - unsigned int scrlen; - unsigned int fmax; - - LOG(4,("PLL_calcclock")); - - scrlen = htotal * (vtotal - 1); - fwant = htotal * vtotal; - fmax = pll->vco_freq_max / ctl->den; - - LOG(2, ("FVMAB:want: %x, xtal: %x, h: %x, v: %x, fmax: %x\n", - fwant, fxtal, htotal, vtotal, fmax)); - for (p = 1; p <= pll->post_shift_max; p++) { - if (fwant * 2 > fmax) - break; - fwant *= 2; - } - if (fwant > fmax) - return 0; - for (; p-- > 0; fwant >>= 1) { - unsigned int m; - - if (fwant < fmin) break; - for (m = pll->in_div_min; m <= pll->in_div_max; m++) { - unsigned int n; - unsigned int dvd; - unsigned int ln; - - n = (fwant * m) / fxtal; - if (n < pll->feed_div_min) - continue; - if (n > pll->feed_div_max) - break; - - ln = fxtal * n; - dvd = m << p; - - if (ln % dvd) - continue; - ln = ln / dvd; - - if (ln < scrlen + 2) - continue; - ln = ln - scrlen; - if (ln > htotal) - continue; - LOG(2,("FBMAV:Match: %x / %x / %x / %x\n", n, m, p, ln)); - if (ln > besth2) { - LOG(2, ("FBMAV:Better...\n")); - *h2 = besth2 = ln; - *post = p; - *in = m; - *feed = n; - } - } - } - if (besth2 < 2) - return 0; - LOG(4,("FBMAV:clk: %x %x %x %d %d\n", *in, *feed, *post, fxtal, fwant)); - return fxtal * (*feed) / (*in) * ctl->den; -} - -unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, - unsigned int htotal, unsigned int vtotal, - unsigned int* in, unsigned int* feed, unsigned int* post, - unsigned int* htotal2) { - unsigned int fvco; - unsigned int p; - - fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); - if (!fvco) - return -EINVAL; - p = (1 << p) - 1; - if (fvco <= 100000000) - ; - else if (fvco <= 140000000) - p |= 0x08; - else if (fvco <= 180000000) - p |= 0x10; - else - p |= 0x18; - *post = p; - return 0; -} - -void DAC1064_calcclock(unsigned int freq, unsigned int fmax, - unsigned int* in, unsigned int* feed, unsigned int* post) { - unsigned int fvco; - unsigned int p; - - fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); - p = (1 << p) - 1; - if (fvco <= 100000) - ; - else if (fvco <= 140000) - p |= 0x08; - else if (fvco <= 180000) - p |= 0x10; - else - p |= 0x18; - *post = p; - return; -} - -void maven_init_TVdata -( - struct mavenregs* data -) -{ - static struct mavenregs palregs = { { - 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ - 0x00, - 0x00, /* ? not written */ - 0x00, /* modified by code (F9 written...) */ - 0x00, /* ? not written */ - 0x7E, /* 08 */ - 0x44, /* 09 */ - 0x9C, /* 0A */ - 0x2E, /* 0B */ - 0x21, /* 0C */ - 0x00, /* ? not written */ - 0x3F, 0x03, /* 0E-0F */ - 0x3F, 0x03, /* 10-11 */ - 0x1A, /* 12 */ - 0x2A, /* 13 */ - 0x1C, 0x3D, 0x14, /* 14-16 */ - 0x9C, 0x01, /* 17-18 */ - 0x00, /* 19 */ - 0xFE, /* 1A */ - 0x7E, /* 1B */ - 0x60, /* 1C */ - 0x05, /* 1D */ - 0x89, 0x03, /* 1E-1F */ - 0x72, /* 20 */ - 0x07, /* 21 */ - 0x72, /* 22 */ - 0x00, /* 23 */ - 0x00, /* 24 */ - 0x00, /* 25 */ - 0x08, /* 26 */ - 0x04, /* 27 */ - 0x00, /* 28 */ - 0x1A, /* 29 */ - 0x55, 0x01, /* 2A-2B */ - 0x26, /* 2C */ - 0x07, 0x7E, /* 2D-2E */ - 0x02, 0x54, /* 2F-30 */ - 0xB0, 0x00, /* 31-32 */ - 0x14, /* 33 */ - 0x49, /* 34 */ - 0x00, /* 35 written multiple times */ - 0x00, /* 36 not written */ - 0xA3, /* 37 */ - 0xC8, /* 38 */ - 0x22, /* 39 */ - 0x02, /* 3A */ - 0x22, /* 3B */ - 0x3F, 0x03, /* 3C-3D */ - 0x00, /* 3E written multiple times */ - 0x00, /* 3F not written */ - }, MODE_PAL, 625, 50 }; - static struct mavenregs ntscregs = { { - 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ - 0x00, - 0x00, /* ? not written */ - 0x00, /* modified by code (F9 written...) */ - 0x00, /* ? not written */ - 0x7E, /* 08 */ - 0x43, /* 09 */ - 0x7E, /* 0A */ - 0x3D, /* 0B */ - 0x00, /* 0C */ - 0x00, /* ? not written */ - 0x41, 0x00, /* 0E-0F */ - 0x3C, 0x00, /* 10-11 */ - 0x17, /* 12 */ - 0x21, /* 13 */ - 0x1B, 0x1B, 0x24, /* 14-16 */ - 0x83, 0x01, /* 17-18 */ - 0x00, /* 19 */ - 0x0F, /* 1A */ - 0x0F, /* 1B */ - 0x60, /* 1C */ - 0x05, /* 1D */ - 0x89, 0x02, /* 1E-1F */ - 0x5F, /* 20 */ - 0x04, /* 21 */ - 0x5F, /* 22 */ - 0x01, /* 23 */ - 0x02, /* 24 */ - 0x00, /* 25 */ - 0x0A, /* 26 */ - 0x05, /* 27 */ - 0x00, /* 28 */ - 0x10, /* 29 */ - 0xFF, 0x03, /* 2A-2B */ - 0x24, /* 2C */ - 0x0F, 0x78, /* 2D-2E */ - 0x00, 0x00, /* 2F-30 */ - 0xB2, 0x04, /* 31-32 */ - 0x14, /* 33 */ - 0x02, /* 34 */ - 0x00, /* 35 written multiple times */ - 0x00, /* 36 not written */ - 0xA3, /* 37 */ - 0xC8, /* 38 */ - 0x15, /* 39 */ - 0x05, /* 3A */ - 0x3B, /* 3B */ - 0x3C, 0x00, /* 3C-3D */ - 0x00, /* 3E written multiple times */ - 0x00, /* never written */ - }, MODE_NTSC, 525, 60 }; - - if (mode & MODE_PAL) - *data = palregs; - else - *data = ntscregs; - - data->regs[0x93] = 0xA2; - - /* gamma correction registers */ - data->regs[0x83] = 0x00; - data->regs[0x84] = 0x00; - data->regs[0x85] = 0x00; - data->regs[0x86] = 0x1F; - data->regs[0x87] = 0x10; - data->regs[0x88] = 0x10; - data->regs[0x89] = 0x10; - data->regs[0x8A] = 0x64; /* 100 */ - data->regs[0x8B] = 0xC8; /* 200 */ - - return; -} - -#define LR(x) i2c_maven_write((x), m->regs[(x)]) -#define LRP(x) MAVWWP((x), (m->regs[(x)]|m->regs[(x+1)]<<8)) -void maven_init_TV -( - const struct mavenregs* m -) -{ - int val; - - - i2c_maven_write( 0x3E, 0x01); - i2c_maven_read( 0x82); /* fetch oscillator state? */ - i2c_maven_write( 0x8C, 0x00); - i2c_maven_read( 0x94); /* get 0x82 */ - i2c_maven_write( 0x94, 0xA2); - /* xmiscctrl */ - - MAVWWP(0x8E, 0x1EFF); - i2c_maven_write( 0xC6, 0x01); - - /* removed code... */ - - i2c_maven_read( 0x06); - i2c_maven_write( 0x06, 0xF9); /* or read |= 0xF0 ? */ - - /* removed code here... */ - - /* real code begins here? */ - /* chroma subcarrier */ - LR(0x00); LR(0x01); LR(0x02); LR(0x03); - - LR(0x04); - - LR(0x2C); - LR(0x08); - LR(0x0A); - LR(0x09); - LR(0x29); - LRP(0x31); - LRP(0x17); - LR(0x0B); - LR(0x0C); - if (m->mode & MODE_PAL) { - i2c_maven_write( 0x35, 0x10); /* ... */ - } else { - i2c_maven_write( 0x35, 0x0F); /* ... */ - } - - LRP(0x10); - - LRP(0x0E); - LRP(0x1E); - - LR(0x20); /* saturation #1 */ - LR(0x22); /* saturation #2 */ - LR(0x25); /* hue */ - LR(0x34); - LR(0x33); - LR(0x19); - LR(0x12); - LR(0x3B); - LR(0x13); - LR(0x39); - LR(0x1D); - LR(0x3A); - LR(0x24); - LR(0x14); - LR(0x15); - LR(0x16); - LRP(0x2D); - LRP(0x2F); - LR(0x1A); - LR(0x1B); - LR(0x1C); - LR(0x23); - LR(0x26); - LR(0x28); - LR(0x27); - LR(0x21); - LRP(0x2A); - if (m->mode & MODE_PAL) - i2c_maven_write( 0x35, 0x1D); /* ... */ - else - i2c_maven_write( 0x35, 0x1C); - - LRP(0x3C); - LR(0x37); - LR(0x38); - i2c_maven_write( 0xB3, 0x01); - - i2c_maven_read( 0xB0); /* read 0x80 */ - i2c_maven_write( 0xB0, 0x08); /* ugh... */ - i2c_maven_read( 0xB9); /* read 0x7C */ - i2c_maven_write( 0xB9, 0x78); - i2c_maven_read( 0xBF); /* read 0x00 */ - i2c_maven_write( 0xBF, 0x02); - i2c_maven_read( 0x94); /* read 0x82 */ - i2c_maven_write( 0x94, 0xB3); - - LR(0x80); /* 04 1A 91 or 05 21 91 */ - LR(0x81); - LR(0x82); - - i2c_maven_write( 0x8C, 0x20); - i2c_maven_read( 0x8D); - i2c_maven_write( 0x8D, 0x10); - - LR(0x90); /* 4D 50 52 or 4E 05 45 */ - LR(0x91); - LR(0x92); - - LRP(0x9A); /* 0049 or 004F */ - LRP(0x9C); /* 0004 or 0004 */ - LRP(0x9E); /* 0458 or 045E */ - LRP(0xA0); /* 05DA or 051B */ - LRP(0xA2); /* 00CC or 00CF */ - LRP(0xA4); /* 007D or 007F */ - LRP(0xA6); /* 007C or 007E */ - LRP(0xA8); /* 03CB or 03CE */ - LRP(0x98); /* 0000 or 0000 */ - LRP(0xAE); /* 0044 or 003A */ - LRP(0x96); /* 05DA or 051B */ - LRP(0xAA); /* 04BC or 046A */ - LRP(0xAC); /* 004D or 004E */ - - LR(0xBE); - LR(0xC2); - - i2c_maven_read( 0x8D); - i2c_maven_write( 0x8D, 0x00); - - LR(0x20); /* saturation #1 */ - LR(0x22); /* saturation #2 */ - LR(0x93); /* whoops */ - LR(0x20); /* oh, saturation #1 again */ - LR(0x22); /* oh, saturation #2 again */ - LR(0x25); /* hue */ - LRP(0x0E); - LRP(0x1E); - LRP(0x0E); /* problems with memory? */ - LRP(0x1E); /* yes, matrox must have problems in memory area... */ - - /* load gamma correction stuff */ - LR(0x83); - LR(0x84); - LR(0x85); - LR(0x86); - LR(0x87); - LR(0x88); - LR(0x89); - LR(0x8A); - LR(0x8B); - - val = i2c_maven_read( 0x8D); - val &= 0x10; /* 0x10 or anything ored with it */ - i2c_maven_write( 0x8D, val); - - LR(0x33); - LR(0x19); - LR(0x12); - LR(0x3B); - LR(0x13); - LR(0x39); - LR(0x1D); - LR(0x3A); - LR(0x24); - LR(0x14); - LR(0x15); - LR(0x16); - LRP(0x2D); - LRP(0x2F); - LR(0x1A); - LR(0x1B); - LR(0x1C); - LR(0x23); - LR(0x26); - LR(0x28); - LR(0x27); - LR(0x21); - LRP(0x2A); - if (m->mode & MODE_PAL) - i2c_maven_write( 0x35, 0x1D); - else - i2c_maven_write( 0x35, 0x1C); - LRP(0x3C); - LR(0x37); - LR(0x38); - - i2c_maven_read( 0xB0); - LR(0xB0); /* output mode */ - LR(0x90); - LR(0xBE); - LR(0xC2); - - LRP(0x9A); - LRP(0xA2); - LRP(0x9E); - LRP(0xA6); - LRP(0xAA); - LRP(0xAC); - i2c_maven_write( 0x3E, 0x00); - i2c_maven_write( 0x95, 0x20); -} - -int maven_find_exact_clocks(unsigned int ht, unsigned int vt, - struct mavenregs* m) { - unsigned int x; - unsigned int err = ~0; - - /* 1:1 */ - m->regs[0x80] = 0x0F; - m->regs[0x81] = 0x07; - m->regs[0x82] = 0x81; - - for (x = 0; x < 8; x++) { - unsigned int a, b, c, h2; - unsigned int h = ht + 2 + x; - - if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { - unsigned int diff = h - h2; - - if (diff < err) { - err = diff; - m->regs[0x80] = a - 1; - m->regs[0x81] = b - 1; - m->regs[0x82] = c | 0x80; - m->hcorr = h2 - 2; - m->htotal = h - 2; - } - } - } - return err != ~0U; -} - -//called from main access points... -inline int maven_compute_timing -( - struct my_timming* mt, - struct mavenregs* m -) -{ - unsigned int tmpi; - unsigned int a, bv, c; - - m->mode = mode; - if (MODE_TV(mode)) { - unsigned int lmargin; - unsigned int umargin; - unsigned int vslen; - unsigned int hcrt; - unsigned int slen; - - maven_init_TVdata(m); - - if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) - return -EINVAL; - - lmargin = mt->HTotal - mt->HSyncEnd; - slen = mt->HSyncEnd - mt->HSyncStart; - hcrt = mt->HTotal - slen - mt->delay; - umargin = mt->VTotal - mt->VSyncEnd; - vslen = mt->VSyncEnd - mt->VSyncStart; - - if (m->hcorr < mt->HTotal) - hcrt += m->hcorr; - if (hcrt > mt->HTotal) - hcrt -= mt->HTotal; - if (hcrt + 2 > mt->HTotal) - hcrt = 0; /* or issue warning? */ - - /* last (first? middle?) line in picture can have different length */ - /* hlen - 2 */ - m->regs[0x96] = m->hcorr; - m->regs[0x97] = m->hcorr >> 8; - /* ... */ - m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; - /* hblanking end */ - m->regs[0x9A] = lmargin; /* 100% */ - m->regs[0x9B] = lmargin >> 8; /* 100% */ - /* who knows */ - m->regs[0x9C] = 0x04; - m->regs[0x9D] = 0x00; - /* htotal - 2 */ - m->regs[0xA0] = m->htotal; - m->regs[0xA1] = m->htotal >> 8; - /* vblanking end */ - m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ - m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; - /* something end... [A6]+1..[A8] */ - m->regs[0xA4] = 0x01; - m->regs[0xA5] = 0x00; - /* something start... 0..[A4]-1 */ - m->regs[0xA6] = 0x00; - m->regs[0xA7] = 0x00; - /* vertical line count - 1 */ - m->regs[0xA8] = mt->VTotal - 1; - m->regs[0xA9] = (mt->VTotal - 1) >> 8; - /* horizontal vidrst pos */ - m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ - m->regs[0xAB] = hcrt >> 8; - /* vertical vidrst pos */ - m->regs[0xAC] = mt->VTotal - 2; - m->regs[0xAD] = (mt->VTotal - 2) >> 8; - /* moves picture up/down and so on... */ - m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ - m->regs[0xAF] = 0x00; - { - int hdec; - int hlen; - unsigned int ibmin = 4 + lmargin + mt->HDisplay; - unsigned int ib; - int i; - - /* Verify! */ - /* Where 94208 came from? */ - if (mt->HTotal) - hdec = 94208 / (mt->HTotal); - else - hdec = 0x81; - if (hdec > 0x81) - hdec = 0x81; - if (hdec < 0x41) - hdec = 0x41; - hdec--; - hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); - if (hlen < 0) - hlen = 0; - hlen = hlen >> 8; - if (hlen > 0xFF) - hlen = 0xFF; - /* Now we have to compute input buffer length. - If you want any picture, it must be between - 4 + lmargin + xres - and - 94208 / hdec - If you want perfect picture even on the top - of screen, it must be also - 0x3C0000 * i / hdec + Q - R / hdec - where - R Qmin Qmax - 0x07000 0x5AE 0x5BF - 0x08000 0x5CF 0x5FF - 0x0C000 0x653 0x67F - 0x10000 0x6F8 0x6FF - */ - i = 1; - do { - ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; - i++; - } while (ib < ibmin); - if (ib >= m->htotal + 2) { - ib = ibmin; - } - - m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ - m->regs[0xC2] = hlen; - /* 'valid' input line length */ - m->regs[0x9E] = ib; - m->regs[0x9F] = ib >> 8; - } - { - int vdec; - int vlen; - - if (mt->VTotal) { - double f1; - uint32 a; - uint32 b; - - // Unsure of how to do 64-bit integer maths on Be, so use FPU! - a = m->vlines * (m->htotal + 2); - b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; - f1 = (double)a * (double)32768; - f1 /= (double) b; - vdec = (uint32) f1; - } else - vdec = 0x8000; - if (vdec > 0x8000) - vdec = 0x8000; - vlen = (vslen + umargin + mt->VDisplay) * vdec; - vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ - if (vlen < 0) - vlen = 0; - if (vlen > 0xFF) - vlen = 0xFF; - vdec--; - m->regs[0x91] = vdec; - m->regs[0x92] = vdec >> 8; - m->regs[0xBE] = vlen; - } - m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ - return 0; - } - - DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); - m->regs[0x80] = a; - m->regs[0x81] = bv; - m->regs[0x82] = c | 0x80; - - m->regs[0xB3] = 0x01; - m->regs[0x94] = 0xB2; - - /* htotal... */ - m->regs[0x96] = mt->HTotal; - m->regs[0x97] = mt->HTotal >> 8; - /* ?? */ - m->regs[0x98] = 0x00; - m->regs[0x99] = 0x00; - /* hsync len */ - tmpi = mt->HSyncEnd - mt->HSyncStart; - m->regs[0x9A] = tmpi; - m->regs[0x9B] = tmpi >> 8; - /* hblank end */ - tmpi = mt->HTotal - mt->HSyncStart; - m->regs[0x9C] = tmpi; - m->regs[0x9D] = tmpi >> 8; - /* hblank start */ - tmpi += mt->HDisplay; - m->regs[0x9E] = tmpi; - m->regs[0x9F] = tmpi >> 8; - /* htotal + 1 */ - tmpi = mt->HTotal + 1; - m->regs[0xA0] = tmpi; - m->regs[0xA1] = tmpi >> 8; - /* vsync?! */ - tmpi = mt->VSyncEnd - mt->VSyncStart - 1; - m->regs[0xA2] = tmpi; - m->regs[0xA3] = tmpi >> 8; - /* ignored? */ - tmpi = mt->VTotal - mt->VSyncStart; - m->regs[0xA4] = tmpi; - m->regs[0xA5] = tmpi >> 8; - /* ignored? */ - tmpi = mt->VTotal - 1; - m->regs[0xA6] = tmpi; - m->regs[0xA7] = tmpi >> 8; - /* vtotal - 1 */ - m->regs[0xA8] = tmpi; - m->regs[0xA9] = tmpi >> 8; - /* hor vidrst */ - tmpi = mt->HTotal - mt->delay; - m->regs[0xAA] = tmpi; - m->regs[0xAB] = tmpi >> 8; - /* vert vidrst */ - tmpi = mt->VTotal - 2; - m->regs[0xAC] = tmpi; - m->regs[0xAD] = tmpi >> 8; - /* ignored? */ - m->regs[0xAE] = 0x00; - m->regs[0xAF] = 0x00; - - m->regs[0xB0] = 0x03; /* output: monitor */ - m->regs[0xB1] = 0xA0; /* ??? */ - m->regs[0x8C] = 0x20; /* must be set... */ - m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */ - m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ - m->regs[0xBF] = 0x22; /* makes picture stable */ - - return 0; -} - -inline int maven_program_timing -( - const struct mavenregs* m -) -{ - if (m->mode & MODE_MONITOR) { - LR(0x80); - LR(0x81); - LR(0x82); - - LR(0xB3); - LR(0x94); - - LRP(0x96); - LRP(0x98); - LRP(0x9A); - LRP(0x9C); - LRP(0x9E); - LRP(0xA0); - LRP(0xA2); - LRP(0xA4); - LRP(0xA6); - LRP(0xA8); - LRP(0xAA); - LRP(0xAC); - LRP(0xAE); - - LR(0xB0); /* output: monitor */ - LR(0xB1); /* ??? */ - LR(0x8C); /* must be set... */ - LR(0x8D); /* defaults to 0x10: test signal */ - LR(0xB9); /* defaults to 0x2C: too bright */ - LR(0xBF); /* makes picture stable */ - } else { - maven_init_TV(m); - } - return 0; -} - -inline int maven_resync() -{ - i2c_maven_write( 0x95, 0x20); /* start whole thing */ - return 0; -} - -/******************************************************/ - -/////////////////////////////////////////////////////////////////////////////////////// -//Main entry points... - sequence is compute, program, start -int maven_set_mode(int mod) -{ - switch (mode) - { - case MODE_NTSC: - case MODE_PAL: - case MODE_MONITOR: - mode = mod; - break; - default: - return -1; - } - return 0; -} - -int maven_out_compute(struct my_timming* mt, struct mavenregs* maven) -{ - return maven_compute_timing(mt, maven); -} - -int maven_out_program(const struct mavenregs* maven) -{ - return maven_program_timing(maven); -} - -int maven_out_start() -{ - return maven_resync(); -} - -/* ************************** */ -//Used with Petr's permission (many thanks) -//Any bugs with this code contact me (MarkWatson@bcs.org.uk) not Petr -//----------------------------------------------- -//MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec "); -//MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); diff --git a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h b/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h deleted file mode 100644 index 3d1af8d445..0000000000 --- a/src/add-ons/accelerants/matrox/engine/matroxfb_maven_hack.h +++ /dev/null @@ -1,88 +0,0 @@ -struct matrox_pll_features { - unsigned int vco_freq_min; - unsigned int ref_freq; - unsigned int feed_div_min; - unsigned int feed_div_max; - unsigned int in_div_min; - unsigned int in_div_max; - unsigned int post_shift_max; -}; - -struct matrox_pll_features2 { - unsigned int vco_freq_min; - unsigned int vco_freq_max; - unsigned int feed_div_min; - unsigned int feed_div_max; - unsigned int in_div_min; - unsigned int in_div_max; - unsigned int post_shift_max; -}; - -struct matrox_pll_ctl { - unsigned int ref_freq; - unsigned int den; -}; - -struct mavenregs { - uint8 regs[256]; - int mode; - int vlines; - int xtal; - int fv; - - uint16 htotal; - uint16 hcorr; -}; - -struct my_timming { - unsigned int pixclock; - unsigned int HDisplay; - unsigned int HSyncStart; - unsigned int HSyncEnd; - unsigned int HTotal; - unsigned int VDisplay; - unsigned int VSyncStart; - unsigned int VSyncEnd; - unsigned int VTotal; - unsigned int sync; - int dblscan; - int interlaced; - unsigned int delay; /* CRTC delay */ -}; - -int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, - const struct matrox_pll_ctl* ctl, - unsigned int htotal, unsigned int vtotal, - unsigned int* in, unsigned int* feed, unsigned int* post, - unsigned int* h2); - -unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, - unsigned int htotal, unsigned int vtotal, - unsigned int* in, unsigned int* feed, unsigned int* post, - unsigned int* htotal2); - -void DAC1064_calcclock(unsigned int freq, unsigned int fmax, - unsigned int* in, unsigned int* feed, unsigned int* post); - -void maven_init_TVdata ( struct mavenregs* data); -void maven_init_TV ( const struct mavenregs* m); - -int maven_find_exact_clocks(unsigned int ht, unsigned int vt, - struct mavenregs* m); - -int maven_compute_timing ( struct my_timming* mt, struct mavenregs* m) ; - - -int maven_program_timing ( const struct mavenregs* m); - -int maven_resync(); - - -//MY INTERFACE -int maven_set_mode(int mode); - -int maven_out_compute(struct my_timming* mt, struct mavenregs* mr) ; - -int maven_out_program(const struct mavenregs* mr) ; - -int maven_out_start() ; diff --git a/src/add-ons/accelerants/matrox/engine/mga_acc.c b/src/add-ons/accelerants/matrox/engine/mga_acc.c index 759196f2aa..829171f0db 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_acc.c +++ b/src/add-ons/accelerants/matrox/engine/mga_acc.c @@ -1,7 +1,7 @@ /* MGA Acceleration functions */ /* Authors: Mark Watson 2/2000, - Rudolf Cornelissen 10-12/2002 + Rudolf Cornelissen 10/2002-4/2003. */ #define MODULE_BIT 0x00080000 @@ -10,7 +10,7 @@ /*acceleration notes*/ -/*functions Be needs: +/*functions Be's app_server uses: fill span (horizontal only) fill rectangle (these 2 are very similar) invert rectangle @@ -19,12 +19,14 @@ 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 MIL2 in 800x600 8bpp +/* needed by MIL 1/2 because of adress linearisation constraints */ #define ACCW_YDSTLEN(dst, len) do { \ -/* if (si->ylin) { */ \ - if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { \ - ACCW(YDST,((dst)*si->dm.virtual_width) >> 5); \ + 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) @@ -39,52 +41,120 @@ status_t gx00_acc_wait_idle() return B_OK; } -/*AFAIK this must be done for every new screenmode*/ +/* AFAIK this must be done for every new screenmode. + * Engine required init. */ status_t gx00_acc_init() { - ACCW(OPMODE,0); // cleanup bitblt + /* used for convenience: MACCESS is a write only register! */ + uint32 maccess = 0x00000000; + /* if we were unable to read PINS, we have to assume something (keeping bit6 zero) */ + if ((si->ps.card_type >= G450) && (si->ps.pins_status = B_OK)) + { + /* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */ + maccess |= ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1); + } + + /* preset using hardware adress linearisation */ + y_lin = 0x00; + /* reset depth */ + depth = 0; + + /* cleanup bitblt */ + ACCW(OPMODE,0); /* Set the Z origin to the start of FB (otherwise lockup on blits) */ - if (si->ps.card_type>=G100) ACCW(ZORG,0); + ACCW(ZORG,0); /* Set pixel width */ switch(si->dm.space) { case B_CMAP8: - ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x00)); + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00)); + depth = 8; break; case B_RGB15_LITTLE:case B_RGB16_LITTLE: - ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x01)); + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01)); + depth = 16; break; case B_RGB32_LITTLE:case B_RGBA32_LITTLE: - ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x02)); + ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02)); + depth = 32; break; default: LOG(8,("ACC: init, invalid bit depth\n")); return B_ERROR; } - /*PITCH*/ - // TODO apsed 3-129 32 or 64 following depth (or 128 if MIl2) - if (si->dm.virtual_width&0x1F) + /* setup PITCH: very cardtype specific! */ + switch (si->ps.card_type) { - LOG(8,("ACC: can not accelerate, pitch is not multiple of 32 pixels\n")); - return B_ERROR; + case MIL1: + switch (si->fbc.bytes_per_row / (depth >> 3)) + { + case 640: + case 768: + case 800: + case 960: + case 1024: + case 1152: + case 1280: + case 1600: + case 1920: + case 2048: + /* we are using hardware adress linearisation */ + break; + default: + /* we are using software adress linearisation */ + y_lin = 0x01; + LOG(8,("ACC: using software adress linearisation\n")); + break; + } + ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF)); + break; + case MIL2: + switch (si->fbc.bytes_per_row / (depth >> 3)) + { + case 512: + case 640: + case 768: + case 800: + case 832: + case 960: + case 1024: + case 1152: + case 1280: + case 1600: + case 1664: + case 1920: + case 2048: + /* we are using hardware adress linearisation */ + break; + default: + /* we are using software adress linearisation */ + y_lin = 0x01; + LOG(8,("ACC: using software adress linearisation\n")); + break; + } + ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF)); + break; + case G100: + /* always using hardware adress linearisation, because 2D/3D + * engine works on every pitch multiple of 32 */ + ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF)); + break; + default: + /* G200 and up are equal.. */ + /* always using hardware adress linearisation, because 2D/3D + * engine works on every pitch multiple of 32 */ + ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF)); + break; } - if (si->ps.card_type>=G200) - ACCW(PITCH,(si->dm.virtual_width)&0x1FFF); /* use hardware Y decoding */ - else - ACCW(PITCH,(si->dm.virtual_width)&0x0FFF); /* use hardware Y decoding */ -if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { - // ylin shall be 1 if 800x600 - ACCW(PITCH, (1<<15) | (si->dm.virtual_width&0x0FFF)); -} /* 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) { + if (si->ps.card_type >= G200) { /*DSTORG - location of active screen in framebuffer*/ ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer)); @@ -92,11 +162,12 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer)); } - /* init YDSTORG - apsed, if not inited, BitBlts may fails on g200 */ + /* 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 */ + /* <= 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) @@ -120,25 +191,27 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { /* clipping */ /* i.e. highest and lowest X pixel adresses */ - ACCW(CXBNDRY,((si->dm.virtual_width - 1) << 16) | (0)); + 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->dm.virtual_width) + src_dst); + 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*/ +/* screen to screen blit - i.e. move windows around. + * Engine function bitblit, paragraph 4.5.7.2 */ status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h) { uint32 t_start,t_end,offset; uint32 b_start,b_end; /*find where the top,bottom and offset are*/ - offset = si->dm.virtual_width; + offset = (si->fbc.bytes_per_row / (depth >> 3)); t_end = t_start = xs + (offset*ys) + src_dst; t_end += w; @@ -146,6 +219,9 @@ status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h 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)) { @@ -189,12 +265,13 @@ status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h ACCW(FXBNDRY,((xd+w)<<16)|xd); /*do the blit*/ - ACCGO(DWGCTL,0x040C4018); + ACCGO(DWGCTL,0x040C4018); // atype RSTR return B_OK; } -/*screen to screen tranparent blit - not sure what uses this...*/ +/* screen to screen tranparent blit - not sure what uses this. + * Engine function bitblit, paragraph 4.5.7.2 */ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour) { uint32 t_start,t_end,offset; @@ -203,7 +280,7 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1 return B_ERROR; /*find where the top,bottom and offset are*/ - offset = si->dm.virtual_width; + offset = (si->fbc.bytes_per_row / (depth >> 3)); t_end = t_start = xs + (offset*ys) + src_dst; t_end += w; @@ -211,6 +288,9 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1 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)) { @@ -256,11 +336,12 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1 /*do the blit*/ ACCW(FCOL,colour); ACCW(BCOL,0xffffffff); - ACCGO(DWGCTL,0x440C4018); + ACCGO(DWGCTL,0x440C4018); // atype RSTR return B_OK; } -/*rectangle fill*/ +/* rectangle fill. + * Engine function rectangle_fill: paragraph 4.5.5.2 */ /*colorIndex,fill_rect_params,count*/ status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) { @@ -276,6 +357,9 @@ status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) ACCW_YDSTLEN(ys,yl); /*set y start and length*/ ACCW(FCOL,col); /*set colour*/ +//acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode +// for other functions, and use fastblt on MIL1/2 if possible... +//or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?) if (si->dm.space==B_CMAP8 || si->ps.sdram) { ACCGO(DWGCTL,0x400C7814); // atype RSTR @@ -287,7 +371,8 @@ status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) return B_OK; } -/*rectangle invert*/ +/* rectangle invert. + * Engine function rectangle_fill: paragraph 4.5.5.2 */ /*colorIndex,fill_rect_params,count*/ status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) { @@ -306,7 +391,8 @@ status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint3 ACCW_YDSTLEN(ys,yl); /*set y start and length*/ ACCW(FCOL,col); /*set colour*/ - ACCGO(DWGCTL,0x40057814); /*draw it! top nibble is c is clipping enabled*/ + /*draw it! top nibble is c is clipping enabled*/ + ACCGO(DWGCTL,0x40057814); // atype RSTR /*pseudo_dma version!*/ //MGAACC_DWGCTL =0x1C00, @@ -339,3 +425,14 @@ status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint3 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 gx00_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd) +{ + //fixme: implement. Used for G450/G550 Desktop TVout... + //fixme: see if MIL1 - G200 support this function as well... + + return B_OK; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_bes.c b/src/add-ons/accelerants/matrox/engine/mga_bes.c index e0c15b9730..a0eef592ea 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_bes.c +++ b/src/add-ons/accelerants/matrox/engine/mga_bes.c @@ -1,10 +1,13 @@ /* G200-G550 Back End Scaler functions */ -/* Written by Rudolf Cornelissen 05/11-2002 */ +/* Written by Rudolf Cornelissen 05/2002-04/2003 */ #define MODULE_BIT 0x00000200 #include "mga_std.h" +//fixme: implement: (used for virtual screens!) +//void move_overlay(uint16 hdisp_start, uint16 vdisp_start); + status_t gx00_configure_bes (const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset) { @@ -29,7 +32,7 @@ status_t gx00_configure_bes /* misc used variables */ uint16 temp1, temp2; /* interval representation, used for scaling calculations */ - uint16 intrep; + 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 */ @@ -84,6 +87,20 @@ status_t gx00_configure_bes LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n", my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height)); + /* the BES does not respect virtual_workspaces, but adheres to CRTC + * constraints only */ + crtc_hstart = si->dm.h_display_start; + /* make dualhead switch mode with TVout enabled work while we're at it.. */ + if (si->switched_crtcs) + { + crtc_hstart += si->dm.timing.h_display; + } + /* horizontal end is the first position beyond the displayed range on the CRTC */ + crtc_hend = crtc_hstart + si->dm.timing.h_display; + crtc_vstart = si->dm.v_display_start; + /* vertical end is the first position beyond the displayed range on the CRTC */ + crtc_vend = crtc_vstart + si->dm.timing.v_display; + /**************************************** *** setup all edges of output window *** @@ -93,22 +110,22 @@ status_t gx00_configure_bes hcoordv = 0; /* left edge coordinate of output window, must be inside desktop */ /* clipping on the left side */ - if (ow->h_start < 0) + if (ow->h_start < crtc_hstart) { temp1 = 0; } else { /* clipping on the right side */ - if (ow->h_start >= (si->dm.virtual_width - 1)) + if (ow->h_start >= (crtc_hend - 1)) { /* width < 2 is not allowed */ - temp1 = (si->dm.virtual_width - 2) & 0x7ff; + temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff; } else /* no clipping here */ { - temp1 = (uint16)ow->h_start & 0x7ff; + temp1 = (ow->h_start - crtc_hstart) & 0x7ff; } } hcoordv |= temp1 << 16; @@ -121,14 +138,14 @@ status_t gx00_configure_bes else { /* clipping on the right side */ - if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1)) + if ((ow->h_start + ow->width - 1) > (crtc_hend - 1)) { - temp2 = (si->dm.virtual_width - 1) & 0x7ff; + temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff; } else { /* clipping on the left side */ - if ((ow->h_start + ow->width - 1) < 1) + if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1)) { /* width < 2 is not allowed */ temp2 = 1; @@ -136,33 +153,33 @@ status_t gx00_configure_bes else /* no clipping here */ { - temp2 = ((uint16)(ow->h_start + ow->width - 1)) & 0x7ff; + temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1)) & 0x7ff; } } } hcoordv |= temp2 << 0; - LOG(4,("Overlay: left-edge output %d, right-edge output %d\n",temp1, temp2)); + 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 < 0) + if (ow->v_start < crtc_vstart) { temp1 = 0; } else { /* clipping on the bottom side */ - if (ow->v_start >= (si->dm.virtual_height - 1)) + if (ow->v_start >= (crtc_vend - 1)) { /* height < 2 is not allowed */ - temp1 = (si->dm.virtual_height - 2) & 0x7ff; + temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff; } else /* no clipping here */ { - temp1 = (uint16)ow->v_start & 0x7ff; + temp1 = (ow->v_start - crtc_vstart) & 0x7ff; } } vcoordv |= temp1 << 16; @@ -175,14 +192,14 @@ status_t gx00_configure_bes else { /* clipping on the bottom side */ - if ((ow->v_start + ow->height - 1) > (si->dm.virtual_height - 1)) + if ((ow->v_start + ow->height - 1) > (crtc_vend - 1)) { - temp2 = (si->dm.virtual_height - 1) & 0x7ff; + temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff; } else { /* clipping on the top side */ - if ((ow->v_start + ow->height - 1) < 1) + if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1)) { /* height < 2 is not allowed */ temp2 = 1; @@ -190,12 +207,12 @@ status_t gx00_configure_bes else /* no clipping here */ { - temp2 = ((uint16)(ow->v_start + ow->height - 1)) & 0x7ff; + temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1)) & 0x7ff; } } } vcoordv |= temp2 << 0; - LOG(4,("Overlay: top-edge output %d, bottom-edge output %d\n",temp1, temp2)); + LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2)); /********************************************* @@ -274,14 +291,13 @@ status_t gx00_configure_bes * 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 < 0) + 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) < 1) + 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); @@ -289,7 +305,7 @@ status_t gx00_configure_bes else { /* increase 'first contributing pixel' with actual number of dest. clipping pixels */ - hsrcstv += (0 - ow->h_start); + hsrcstv += (crtc_hstart - ow->h_start); } LOG(4,("Overlay: clipping left...\n")); @@ -314,11 +330,11 @@ status_t gx00_configure_bes hsrcendv = 0; /* check for destination horizontal clipping at right side */ - if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1)) + 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 > (si->dm.virtual_width - 2)) + if (ow->h_start > (crtc_hend - 2)) { /* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */ hsrcendv += (ow->width - 2); @@ -326,7 +342,7 @@ status_t gx00_configure_bes else { /* increase 'number of clipping pixels' with actual number of dest. clipping pixels */ - hsrcendv += ((ow->h_start + ow->width - 1) - (si->dm.virtual_width - 1)); + hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 1)); } LOG(4,("Overlay: clipping right...\n")); @@ -435,11 +451,11 @@ status_t gx00_configure_bes /* 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 < 0) + 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) < 1) + 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)) * @@ -452,8 +468,8 @@ status_t gx00_configure_bes /* increase source buffer origin with: * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) * * bytes per row source picture */ - a1orgv += ((((0 - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row); - weight = (0 - ow->v_start) * ifactor; + 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")); } diff --git a/src/add-ons/accelerants/matrox/engine/mga_crtc.c b/src/add-ons/accelerants/matrox/engine/mga_crtc.c index d81e2c98b2..d9e9d55711 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_crtc.c +++ b/src/add-ons/accelerants/matrox/engine/mga_crtc.c @@ -2,7 +2,7 @@ /* Authors: Mark Watson 2/2000, Apsed, - Rudolf Cornelissen 11-12/2002 + Rudolf Cornelissen 11/2002-4/2003 */ #define MODULE_BIT 0x00040000 @@ -196,6 +196,30 @@ status_t gx00_crtc_depth(int mode) viddelay = 2<<3; // for 8 to 16Mb of memory } while (0); + /* setup green_sync if requested */ + if (si->settings.greensync) + { + /* enable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */ + if (si->ps.card_type <= MIL2) + DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20)); + else + DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20)); + /* select horizontal _and_ vertical sync */ + viddelay |= 0x40; + + LOG(4,("CRTC: sync_on_green enabled\n")); + } + else + { + /* disable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */ + if (si->ps.card_type <= MIL2) + DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20)); + else + DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20)); + + LOG(4,("CRTC: sync_on_green disabled\n")); + } + /*set VCLK scaling*/ switch(mode) { @@ -238,16 +262,17 @@ status_t gx00_crtc_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) // MIL2 return B_OK; } -status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp) +status_t gx00_crtc_set_display_pitch() { uint32 offset; LOG(4,("CRTC: setting card pitch (offset between lines)\n")); - /*figure out offset value hardware needs*/ - offset = (pitch*bpp)/128; + /* figure out offset value hardware needs: + * same for MIL1-G550 cards assuming MIL1/2 uses the TVP3026 64-bits DAC etc. */ + offset = si->fbc.bytes_per_row / 16; - LOG(2,("CRTC: offset: 0x%04x\n",offset)); + LOG(2,("CRTC: offset register: 0x%04x\n",offset)); /*program the card!*/ VGAW_I(CRTC,0x13,(offset&0xFF)); @@ -268,6 +293,20 @@ status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp) LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer)); LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer)); + /* make sure we are in retrace on MIL cards (if possible), because otherwise + * distortions might occur during our reprogramming them (no double buffering) */ + if (si->ps.card_type < G100) + { + /* we might have no retraces during setmode! */ + uint32 timeout = 0; + /* wait 25mS max. for retrace to occur (refresh > 40Hz) */ + while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4))) + { + snooze(4); + timeout++; + } + } + /*set standard registers*/ VGAW_I(CRTC,0xD,startadd&0xFF); VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8); @@ -389,43 +428,91 @@ status_t gx00_crtc_mem_priority(uint8 colordepth) status_t gx00_crtc_cursor_init() { int i; - uint32 * fb; - /* cursor bitmap will be stored at the start of the framebuffer */ - const uint32 curadd = 0; - /* set cursor bitmap adress ... */ - DXIW(CURADDL,curadd >> 10); - DXIW(CURADDH,curadd >> 18); - /* ... and repeat that: G100 requires other programming order than other cards!?! */ - DXIW(CURADDL,curadd >> 10); - DXIW(CURADDH,curadd >> 18); + if (si->ps.card_type >= G100) + { + uint32 * fb; + /* cursor bitmap will be stored at the start of the framebuffer on >= G100 */ + const uint32 curadd = 0; + + /* set cursor bitmap adress ... */ + DXIW(CURADDL,curadd >> 10); + DXIW(CURADDH,curadd >> 18); + /* ... and repeat that: G100 requires other programming order than later cards!?! */ + DXIW(CURADDL,curadd >> 10); + DXIW(CURADDH,curadd >> 18); + + /*set cursor colour*/ + DXIW(CURCOL0RED,0XFF); + DXIW(CURCOL0GREEN,0xFF); + DXIW(CURCOL0BLUE,0xFF); + DXIW(CURCOL1RED,0); + DXIW(CURCOL1GREEN,0); + DXIW(CURCOL1BLUE,0); + DXIW(CURCOL2RED,0); + DXIW(CURCOL2GREEN,0); + DXIW(CURCOL2BLUE,0); + + /*clear cursor*/ + fb = (uint32 *) si->framebuffer + curadd; + for (i=0;i<(1024/4);i++) + { + fb[i]=0; + } + } + else + /* <= G100 cards have serial cursor color registers, + * and dedicated cursor bitmap RAM (in TVP3026 DAC) + */ + { + /* select first colorRAM adress */ + DACW(TVP_CUROVRWTADD,0x00); + /* overscan/border color is black, order of colors set is R,G,B */ + DACW(TVP_CUROVRDATA,0xff); + DACW(TVP_CUROVRDATA,0xff); + DACW(TVP_CUROVRDATA,0xff); + /* set sursor color 0 */ + DACW(TVP_CUROVRDATA,0xff); + DACW(TVP_CUROVRDATA,0xff); + DACW(TVP_CUROVRDATA,0xff); + /* set sursor color 1 */ + DACW(TVP_CUROVRDATA,0x00); + DACW(TVP_CUROVRDATA,0x00); + DACW(TVP_CUROVRDATA,0x00); + /* set sursor color 2 */ + DACW(TVP_CUROVRDATA,0x00); + DACW(TVP_CUROVRDATA,0x00); + DACW(TVP_CUROVRDATA,0x00); + + /* select first cursor pattern DAC-internal RAM adress, and + * make sure indirect cursor control register is selected as active register */ + DXIW(CURCTRL,(DXIR(CURCTRL) & 0x73)); + DACW(PALWTADD,0x00); + /* now clear it, auto-incrementing the adress */ + for(i=0;i<1024;i++) + { + DACW(TVP_CURRAMDATA,0x00); + } + } /* activate hardware cursor */ DXIW(CURCTRL,1); - /*set cursor colour*/ - DXIW(CURCOL0RED,0XFF); - DXIW(CURCOL0GREEN,0xFF); - DXIW(CURCOL0BLUE,0xFF); - DXIW(CURCOL1RED,0); - DXIW(CURCOL1GREEN,0); - DXIW(CURCOL1BLUE,0); - DXIW(CURCOL2RED,0); - DXIW(CURCOL2GREEN,0); - DXIW(CURCOL2BLUE,0); - - /*clear cursor*/ - fb = (uint32 *) si->framebuffer + curadd; - for (i=0;i<(1024/4);i++) - { - fb[i]=0; - } return B_OK; } status_t gx00_crtc_cursor_show() { - DXIW(CURCTRL,1); + if ((si->ps.card_type < G100) && (si->dm.timing.h_total > 2048)) + { + /* MIL1/2 DAC needs to be told if h_total for the active mode gets above 2048 */ + DXIW(CURCTRL, 0x11); + } + else + { + DXIW(CURCTRL, 0x01); + } + return B_OK; } @@ -438,19 +525,56 @@ status_t gx00_crtc_cursor_hide() /*set up cursor shape*/ status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask) { - uint8 * cursor; int y; - /*get a pointer to the cursor*/ - cursor = (uint8*) si->framebuffer; - - /*draw the cursor*/ - for(y=0;y<16;y++) + if(si->ps.card_type >= G100) { - cursor[y*16+7]=~*andMask++; - cursor[y*16+15]=*xorMask++; - cursor[y*16+6]=~*andMask++; - cursor[y*16+14]=*xorMask++; + uint8 * cursor; + + /*get a pointer to the cursor*/ + cursor = (uint8*) si->framebuffer; + + /*draw the cursor*/ + for(y=0;y<16;y++) + { + cursor[y*16+7]=~*andMask++; + cursor[y*16+15]=*xorMask++; + cursor[y*16+6]=~*andMask++; + cursor[y*16+14]=*xorMask++; + } + } + else + /* <= G100 cards have dedicated cursor bitmap RAM (in TVP3026 DAC) */ + { + uint8 curctrl; + + /* disable the cursor to prevent distortions in screen output */ + curctrl = (DXIR(CURCTRL)); + DXIW(CURCTRL, (curctrl & 0xfc)); + /* select first cursor pattern DAC-internal RAM adress for plane 0 */ + DXIW(CURCTRL, (DXIR(CURCTRL) & ~0x0c)); + DACW(PALWTADD, 0x00); + /* now fill it, partly auto-incrementing the adress */ + for(y = 0; y < 16; y++) + { + DACW(PALWTADD, (y * 8)); + DACW(TVP_CURRAMDATA, ~*andMask++); + DACW(TVP_CURRAMDATA, ~*andMask++); + } + /* select first cursor pattern DAC-internal RAM adress for plane 1 */ + DXIW(CURCTRL, (DXIR(CURCTRL) | 0x08)); + DACW(PALWTADD, 0x00); + /* now fill it, partly auto-incrementing the adress */ + for(y = 0; y < 16; y++) + { + DACW(PALWTADD, y*8); + DACW(TVP_CURRAMDATA, *xorMask++); + DACW(TVP_CURRAMDATA, *xorMask++); + } + /* delay restoring the cursor to prevent distortions in screen output */ + snooze(5); + /* restore the cursor */ + DXIW(CURCTRL, curctrl); } return B_OK; @@ -460,7 +584,6 @@ status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask) status_t gx00_crtc_cursor_position(uint16 x ,uint16 y) { int i=64; -// LOG(4,("DAC: cursor-> %d %d\n",x,y)); x+=i; y+=i; diff --git a/src/add-ons/accelerants/matrox/engine/mga_crtc2.c b/src/add-ons/accelerants/matrox/engine/mga_crtc2.c index e40a4c2bab..921e596c72 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_crtc2.c +++ b/src/add-ons/accelerants/matrox/engine/mga_crtc2.c @@ -2,7 +2,7 @@ Authors: Mark Watson 6/2000, - Rudolf Cornelissen 12/2002 + Rudolf Cornelissen 12/2002 - 4/2003 */ #define MODULE_BIT 0x00020000 @@ -10,37 +10,139 @@ #include "mga_std.h" /*set a mode line - inputs are in pixels/scanlines*/ -status_t g400_crtc2_set_timing( - uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, - uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, - uint8 hsync_pos,uint8 vsync_pos - ) +status_t g400_crtc2_set_timing(display_mode target) { + uint32 temp; + LOG(4,("CRTC2: setting timing\n")); - /*check horizontal timing parameters are to nearest 8 pixels*/ - if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7)) + if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX)) { - LOG(8,("CRTC2:Horizontal timings are not multiples of 8 pixels\n")); - return B_ERROR; - } + /* G450/G550 monitor mode, and all modes on older cards */ - /*program the second CRTC*/ - CR2W(HPARAM, ((((hdisp_e - 8) & 0x0fff) << 16) | ((htotal - 8) & 0x0fff))); - CR2W(HSYNC, ((((hsync_e - 8) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff))); - CR2W(VPARAM, ((((vdisp_e - 1) & 0x0fff) << 16) | ((vtotal - 1) & 0x0fff))); - CR2W(VSYNC, ((((vsync_e - 1) & 0x0fff) << 16) | ((vsync_s - 1) & 0x0fff))); - //Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!) - //CR2W(PRELOAD, (((vsync_s & 0x0fff) << 16) | (hsync_s & 0x0fff))); - CR2W(PRELOAD, ((((vsync_s - 1) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff))); - CR2W(MISC, ((0xfff << 16) | (((!hsync_pos) & 0x01) << 8) | (((!vsync_pos) & 0x01) << 9))); + /* check horizontal timing parameters are to nearest 8 pixels */ + if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) | + (target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07)) + { + LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n")); + return B_ERROR; + } + + /* make sure NTSC clock killer circuitry is disabled */ + CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010)); + + /* make sure CRTC2 is set to progressive scan for monitor mode */ + CR2W(CTL, (CR2R(CTL) & ~0x02001000)); + + /* program the second CRTC */ + CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) | + ((target.timing.h_total - 8) & 0x0fff))); + CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) | + ((target.timing.h_sync_start - 8) & 0x0fff))); + CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) | + ((target.timing.v_total - 1) & 0x0fff))); + CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) | + ((target.timing.v_sync_start - 1) & 0x0fff))); + //Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!) + //CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) | + // (target.timing.h_sync_start & 0x0fff))); + CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) | + ((target.timing.h_sync_start - 8) & 0x0fff))); + + temp = (0xfff << 16); + if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8); + if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9); + CR2W(MISC, temp); + + /* On <= G400MAX dualhead cards we need to send a copy to the MAVEN; + * unless TVout is active */ + if ((si->ps.secondary_head) && (!(target.flags & TV_BITS))) + gx00_maven_set_timing(target); + } + else + { + /* G450/G550 TVout mode */ + display_mode tv_mode = target; + uint8 frame; + unsigned int vcount, prev_vcount; + + LOG(4,("CRTC2: setting up G450/G550 TVout mode\n")); + + /* check horizontal timing parameters are to nearest 8 pixels */ + if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) | + (tv_mode.timing.h_sync_end & 0x07)) + { + LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n")); + return B_ERROR; + } + + /* disable NTSC clock killer circuitry */ + CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010)); + + if (tv_mode.timing.h_total & 0x07) + { + /* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */ + LOG(4,("CRTC2: enabling clock killer circuitry\n")); + CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010)); + } + + /* make sure h_total is valid for TVout mode */ + tv_mode.timing.h_total &= ~0x07; + + /* modify tv_mode for interlaced use */ + tv_mode.timing.v_display >>= 1; + tv_mode.timing.v_sync_start >>= 1; + tv_mode.timing.v_sync_end >>= 1; + tv_mode.timing.v_total >>= 1; + + /*program the second CRTC*/ + CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) | + ((tv_mode.timing.h_total - 8) & 0x0fff))); + CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) | + ((tv_mode.timing.h_sync_start - 8) & 0x0fff))); + CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) | + ((tv_mode.timing.v_total - 1) & 0x0fff))); + CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) | + ((tv_mode.timing.v_sync_start - 1) & 0x0fff))); + //Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!) + //CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) | + // (tv_mode.timing.h_sync_start & 0x0fff))); + CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) | + ((tv_mode.timing.h_sync_start - 8) & 0x0fff))); + + /* set CRTC2 to interlaced mode: + * First enable progressive scan mode while making sure + * CRTC2 is setup for TVout mode use... */ + CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000)); + /* now synchronize to the start of a frame... */ + prev_vcount = 0; + for (frame = 0; frame < 2; frame++) + { + for (;;) + { + vcount = (CR2R(VCOUNT) & 0x00000fff); + if (vcount >= prev_vcount) + prev_vcount = vcount; + else + break; + } + } + /* and start interlaced mode now! */ + CR2W(CTL, (CR2R(CTL) | 0x02000000)); + + temp = (0xfff << 16); + if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8); + if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9); + CR2W(MISC, temp); + } return B_OK; } status_t g400_crtc2_depth(int mode) { - /*validate bit depth and set mode*/ + /* validate bit depth and set mode */ + /* also clears TVout mode (b12) */ switch(mode) { case BPP16:case BPP32DIR: @@ -57,10 +159,29 @@ status_t g400_crtc2_depth(int mode) status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v) { - //fixme: CTL b0=1 is CRTC2 enabled, 0 is disabled. This code is dangerous... - CR2W(CTL,(CR2R(CTL)&0xFFF0077E)|(display&h&v)); /*enable second CRTC if required*/ + if (display & h & v) + { + /* enable CRTC2 and don't touch the rest */ + CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01)); + } + else + { + /* disable CRTC2 and don't touch the rest */ + CR2W(CTL, (CR2R(CTL) & 0xFFF0177E)); + } + + if (si->ps.card_type >= G450) + { + //fixme: + /* setup monitor mode DPMS: G450 and later fully support this on CRTC2 */ + //for now: + //enable 'straight-through' sync outputs on both analog output connectors... + DXIW(SYNCCTRL,0x00); + } + + /* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */ + if (si->ps.secondary_head) gx00_maven_dpms(display, h, v); - /*ignore h,v because they are not supported*/ return B_OK; } @@ -73,31 +194,54 @@ status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) return B_OK; } -status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp) +status_t g400_crtc2_set_display_pitch() { uint32 offset; - LOG(4,("CRTC2: setting card pitch 0x%08x bpp %d\n", pitch, bpp)); + LOG(4,("CRTC2: setting card pitch (offset between lines)\n")); - /*figure out offset value hardware needs*/ - offset = pitch*(bpp>>3); + /* figure out offset value hardware needs */ + offset = si->fbc.bytes_per_row; + if (si->interlaced_tv_mode) + { + LOG(4,("CRTC2: setting interlaced mode\n")); + /* double the CRTC2 linelength so fields are displayed instead of frames */ + offset *= 2; + } + else + LOG(4,("CRTC2: setting progressive scan mode\n")); - LOG(2,("CRTC2: offset: %x\n",offset)); + LOG(2,("CRTC2: offset set to %d bytes\n", offset)); - /*program the card!*/ + /* program the head */ CR2W(OFFSET,offset); return B_OK; } status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp) { - LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp)); + LOG(4,("CRTC2: setting card RAM to be displayed for %d bits per pixel\n", bpp)); - LOG(2,("CRTC2: startadd: %x\n",startadd)); - LOG(2,("CRTC2: frameRAM: %x\n",si->framebuffer)); - LOG(2,("CRTC2: framebuffer: %x\n",si->fbc.frame_buffer)); + LOG(2,("CRTC2: startadd: $%x\n",startadd)); + LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer)); + LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer)); + + if (si->interlaced_tv_mode) + { + LOG(4,("CRTC2: setting up fields for interlaced mode\n")); + /* program the head for interlaced use */ + //fixme: seperate both heads: we need a secondary si->fbc! + /* setup field 0 startadress in buffer to read picture's odd lines */ + CR2W(STARTADD0, (startadd + si->fbc.bytes_per_row)); + /* setup field 1 startadress in buffer to read picture's even lines */ + CR2W(STARTADD1, startadd); + } + else + { + LOG(4,("CRTC2: setting up frames for progressive scan mode\n")); + /* program the head for non-interlaced use */ + CR2W(STARTADD0, startadd); + } - /*program the card!*/ - CR2W(STARTADD0,startadd); return B_OK; } diff --git a/src/add-ons/accelerants/matrox/engine/mga_dac.c b/src/add-ons/accelerants/matrox/engine/mga_dac.c index 16c039db80..576b066fb1 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_dac.c +++ b/src/add-ons/accelerants/matrox/engine/mga_dac.c @@ -2,19 +2,23 @@ /* Authors: Mark Watson 2/2000, Apsed 2002, - Rudolf Cornelissen 9-12/2002 + Rudolf Cornelissen 9/2002-4/2003 */ #define MODULE_BIT 0x00010000 #include "mga_std.h" -static status_t g100_g400max_dac_pix_pll_find( +static status_t milx_dac_pix_pll_find( display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); +static status_t g100_g400max_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); static status_t g450_g550_dac_pix_pll_find( display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); static status_t g100_g400max_dac_sys_pll_find( float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); +static status_t g450_g550_dac_sys_pll_find( + float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ status_t gx00_dac_mode(int mode,float brightness) @@ -81,10 +85,59 @@ status_t gx00_dac_mode(int mode,float brightness) if (gx00_dac_palette(r,g,b)!=B_OK) return B_ERROR; /*set the mode - also sets VCLK dividor*/ - DXIW(MULCTRL,mode); - DACW(PIXRDMSK,0xff); // apsed, palette addressing not masked + if (si->ps.card_type >= G100) + { + DXIW(MULCTRL, mode); + LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL))); + } + else + { + /* MIL1/2 differs here (TVP3026DAC) */ + uint8 miscctrl = 0, latchctrl = 0; + uint8 tcolctrl = 0, mulctrl = 0; - LOG(2,("DAC: mulctrl=%x, pixrdmsk=%x\n",DXIR(MULCTRL), DACR(PIXRDMSK))); + /* set the mode */ + switch (mode) + { + /* presetting mulctrl for DAC pixelbus_width of 32 */ + case BPP8: + miscctrl=0x00; latchctrl=0x06; tcolctrl=0x80; mulctrl=0x4b; + break; + case BPP15: + miscctrl=0x20; latchctrl=0x06; tcolctrl=0x04; mulctrl=0x53; + break; + case BPP16: + miscctrl=0x20; latchctrl=0x06; tcolctrl=0x05; mulctrl=0x53; + break; + case BPP24: + miscctrl=0x20; latchctrl=0x06; tcolctrl=0x1f; mulctrl=0x5b; + break; + case BPP32: + miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; + break; + case BPP32DIR: + miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; + break; + } + + /* modify mulctrl if DAC pixelbus_width is 64 */ + //fixme? do 32bit DACbus MIL 1/2 cards exist? if so, setup via si->ps... + if (true) mulctrl += 1; + + DXIW(MISCCTRL, (DXIR(MISCCTRL) & 0x1d) | miscctrl); + DXIW(TVP_LATCHCTRL, latchctrl); + DXIW(TVP_TCOLCTRL, tcolctrl); + DXIW(MULCTRL, mulctrl); + + LOG(2,("DAC: TVP miscctrl 0x%02x, TVP latchctrl 0x%02x\n", + DXIR(MISCCTRL), DXIR(TVP_LATCHCTRL))); + LOG(2,("DAC: TVP tcolctrl 0x%02x, TVP mulctrl 0x%02x\n", + DXIR(TVP_TCOLCTRL), DXIR(MULCTRL))); + } + + /* disable palette RAM adressing mask */ + DACW(PIXRDMSK,0xff); + LOG(2,("DAC: pixrdmsk 0x%02x\n", DACR(PIXRDMSK))); return B_OK; } @@ -96,10 +149,8 @@ status_t gx00_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256]) LOG(4,("DAC: setting palette\n")); - /* clear palwtadd to start programming (LUT index?) */ + /* clear palwtadd before starting programming (LUT index) */ DACW(PALWTADD,0); - /* just for safety (specs are somewhat unclear) (LUT color?) */ - DACW(PALRDADD,0); /*loop through all 256 to program DAC*/ for (i=0;i<256;i++) @@ -128,10 +179,6 @@ if (0) 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 } } - /* reset to LUT start just for safety (LUT index?) */ - DACW(PALWTADD,0); - /* (specs are somewhat unclear) (LUT color?) */ - DACW(PALRDADD,0); return B_OK; } @@ -154,6 +201,7 @@ status_t gx00_dac_set_pix_pll(display_mode target) req_pclk = (target.timing.pixel_clock)/1000.0; LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); + /* signal that we actually want to set the mode */ result = gx00_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1); if (result != B_OK) { @@ -282,14 +330,134 @@ status_t gx00_dac_pix_pll_find switch (si->ps.card_type) { case G550: case G450: return g450_g550_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); - default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result); + case MIL2: + case MIL1: return milx_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result); + default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); } return B_ERROR; } /* find nearest valid pixel PLL setting: rewritten by rudolf */ -static status_t g100_g400max_dac_pix_pll_find( +static status_t milx_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; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + LOG(4,("DAC: MIL1/MIL2 TVP restrictions apply\n")); + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_CMAP8: + max_pclk = si->ps.max_dac1_clock_8; + break; + case B_RGB15_LITTLE: + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac1_clock_16; + break; + case B_RGB24_LITTLE: + max_pclk = si->ps.max_dac1_clock_24; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac1_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac1_clock_32; + break; + } + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_pixel_vco divided by highest postscaler-factor */ + if (req_pclk < (si->ps.min_pixel_vco / 8.0)) + { + LOG(4,("DAC: TVP clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_pixel_vco / 8.0))); + req_pclk = (si->ps.min_pixel_vco / 8.0); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("DAC: TVP clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (n = 3; n <= 25; n++) + { + /* calculate VCO postscaler setting for current setup.. */ + m = (int)(((f_vco * n) / (8 * si->ps.f_ref)) + 0.5); + /* ..and check for validity */ + if ((m < 3) || (m > 64)) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - ((((8 * si->ps.f_ref) / n) * m) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + m = best[0]; + n = best[1]; + p = best[2]; + + f_vco = (((8 * si->ps.f_ref) / n) * m); + LOG(2,("DAC: TVP pix VCO frequency found %fMhz\n", f_vco)); + + /* setup the scalers programming values for found optimum setting */ + *calc_pclk = (f_vco / p); + *m_result = (65 - m); + *n_result = (65 - n); + + switch(p) + { + case 1: + p = 0x00; + break; + case 2: + p = 0x01; + break; + case 4: + p = 0x02; + break; + case 8: + p = 0x03; + break; + } + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("DAC: TVP pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); + + return B_OK; +} + +/* find nearest valid pixel PLL setting: rewritten by rudolf */ +static status_t g100_g400max_dac_pix_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) { int m = 0, n = 0, p = 0, m_max; float error, error_best = 999999999; @@ -315,6 +483,17 @@ static status_t g100_g400max_dac_pix_pll_find( break; } + /* make sure the pixelPLL and the videoPLL have a little different settings to + * minimize distortions in the outputs due to crosstalk: + * do *not* change the videoPLL setting because it must be exact if TVout is enabled! */ + /* Note: + * only modify the clock if we are actually going to set the mode */ + if ((target.flags & DUALHEAD_BITS) && test) + { + LOG(4,("DAC: dualhead mode active: modified requested pixelclock +1.5%%\n")); + req_pclk *= 1.015; + } + /* determine the max. pixelclock for the current videomode */ switch (target.space) { @@ -343,9 +522,18 @@ static status_t g100_g400max_dac_pix_pll_find( /* Make sure the requested pixelclock is within the PLL's operational limits */ /* lower limit is min_pixel_vco divided by highest postscaler-factor */ if (req_pclk < (si->ps.min_pixel_vco / 8.0)) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_pixel_vco / 8.0))); req_pclk = (si->ps.min_pixel_vco / 8.0); + } /* upper limit is given by pins in combination with current active mode */ - if (req_pclk > max_pclk) req_pclk = max_pclk; + if (req_pclk > max_pclk) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } /* iterate through all valid PLL postscaler settings */ for (p=0x01; p < 0x10; p = p<<1) @@ -466,9 +654,18 @@ static status_t g450_g550_dac_pix_pll_find /* Make sure the requested pixelclock is within the PLL's operational limits */ /* lower limit is min_pixel_vco divided by highest postscaler-factor */ if (req_pclk < (si->ps.min_pixel_vco / 16.0)) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_pixel_vco / 16.0))); req_pclk = (si->ps.min_pixel_vco / 16.0); + } /* upper limit is given by pins in combination with current active mode */ - if (req_pclk > max_pclk) req_pclk = max_pclk; + if (req_pclk > max_pclk) + { + LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } /* iterate through all valid PLL postscaler settings */ for (p=0x01; p < 0x20; p = p<<1) @@ -505,7 +702,7 @@ static status_t g450_g550_dac_pix_pll_find /* setup the scalers programming values for found optimum setting */ m=best[0] - 1; - n=best[1] - 1; + n=best[1] - 2; switch(best[2]) { case 1: @@ -526,7 +723,7 @@ static status_t g450_g550_dac_pix_pll_find } /* log the closest VCO speed found */ - f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1); + f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2); LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco)); /* now find the filtersetting that matches best with this frequency by testing. @@ -579,9 +776,18 @@ static status_t g100_g400max_dac_sys_pll_find( /* Make sure the requested systemclock is within the PLL's operational limits */ /* lower limit is min_system_vco divided by highest postscaler-factor */ if (req_sclk < (si->ps.min_system_vco / 8.0)) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (float)(si->ps.min_system_vco / 8.0))); req_sclk = (si->ps.min_system_vco / 8.0); + } /* upper limit is max_system_vco */ - if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco; + if (req_sclk > si->ps.max_system_vco) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (float)si->ps.max_system_vco)); + req_sclk = si->ps.max_system_vco; + } /* iterate through all valid PLL postscaler settings */ for (p=0x01; p < 0x10; p = p<<1) @@ -666,7 +872,6 @@ status_t gx50_dac_check_sys_pll(uint8 m, uint8 n, uint8 p) uint time = 0, count = 0; /* program the new clock */ -// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ DXIW(SYSPLLM, m); DXIW(SYSPLLN, n); DXIW(SYSPLLP, p); @@ -705,7 +910,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q) *p &= 0x47; /* iterate through all possible filtersettings */ -// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ for (s = 0; s < 8 ;s++) { if (gx50_dac_check_sys_pll(m, n, *p)== B_OK) @@ -722,7 +926,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q) /* preset first choice setting found */ *q = 1; /* we are done */ -// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/ return B_OK; } else @@ -741,7 +944,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q) /* return the (last found) backup result, or the original p value */ *p = p_backup; -// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/ /* we found only a non-optimal value */ if (*q == 2) return B_OK; @@ -765,9 +967,18 @@ static status_t g450_g550_dac_sys_pll_find( /* Make sure the requested pixelclock is within the PLL's operational limits */ /* lower limit is min_system_vco divided by highest postscaler-factor */ if (req_sclk < (si->ps.min_system_vco / 16.0)) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (float)(si->ps.min_system_vco / 16.0))); req_sclk = (si->ps.min_system_vco / 16.0); + } /* upper limit is max_system_vco */ - if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco; + if (req_sclk > si->ps.max_system_vco) + { + LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n", + req_sclk, (float)si->ps.max_system_vco)); + req_sclk = si->ps.max_system_vco; + } /* iterate through all valid PLL postscaler settings */ for (p=0x01; p < 0x20; p = p<<1) @@ -804,7 +1015,7 @@ static status_t g450_g550_dac_sys_pll_find( /* setup the scalers programming values for found optimum setting */ m=best[0] - 1; - n=best[1] - 1; + n=best[1] - 2; switch(best[2]) { case 1: @@ -825,7 +1036,7 @@ static status_t g450_g550_dac_sys_pll_find( } /* log the closest VCO speed found */ - f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1); + f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2); LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco)); /* now find the filtersetting that matches best with this frequency by testing. diff --git a/src/add-ons/accelerants/matrox/engine/mga_general.c b/src/add-ons/accelerants/matrox/engine/mga_general.c index c1fb8a8366..5c127f9373 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_general.c +++ b/src/add-ons/accelerants/matrox/engine/mga_general.c @@ -1,7 +1,7 @@ /* Authors: Mark Watson 12/1999, Apsed, - Rudolf Cornelissen 10-12/2002 + Rudolf Cornelissen 10/2002-4/2003 */ #define MODULE_BIT 0x00008000 @@ -11,7 +11,7 @@ //#include "mga_init.c" //Nicole's test stuff. status_t test_ram(); -static status_t mil2_general_powerup (void); +static status_t mil_general_powerup (void); static status_t g100_general_powerup (void); static status_t g200_general_powerup (void); static status_t g400_general_powerup (void); @@ -56,17 +56,23 @@ status_t gx00_general_powerup() status_t status; uint32 card_class; + LOG(1,("POWERUP: Matrox (open)BeOS Accelerant 0.14 running.\n")); + /* detect card type and power it up */ switch(CFGR(DEVID)) { - case 0x0519102b: //MGA-2064 Millenium PCI case 0x051a102b: //MGA-1064 Mystic PCI LOG(8,("POWERUP: Unimplemented Matrox device %08x\n",CFGR(DEVID))); return B_ERROR; + case 0x0519102b: //MGA-2064 Millenium PCI + si->ps.card_type = MIL1; + LOG(4,("POWERUP: Detected MGA-2064 Millennium 1\n")); + status = mil_general_powerup(); + break; case 0x051b102b:case 0x051f102b: //MGA-2164 Millenium 2 PCI/AGP si->ps.card_type = MIL2; LOG(4,("POWERUP: Detected MGA-2164 Millennium 2\n")); - status = mil2_general_powerup(); + status = mil_general_powerup(); break; case 0x1000102b:case 0x1001102b: //G100 si->ps.card_type = G100; @@ -201,7 +207,7 @@ status_t mga_set_cas_latency() break; case G450: case G550: - /* G450 and G550 tune CAS latency via a predefined table at powerup time */ + /* fixme: implement this if needed */ LOG(4,("INIT: G450/G550 RAM CAS tuning not implemented, aborting.\n")); return B_OK; break; @@ -220,11 +226,11 @@ status_t mga_set_cas_latency() } static -status_t mil2_general_powerup() +status_t mil_general_powerup() { status_t result; - LOG(4, ("INIT: Millenium II powerup\n")); + LOG(4, ("INIT: Millenium I/II powerup\n")); if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); /* initialize the shared_info PINS struct */ @@ -235,15 +241,9 @@ status_t mil2_general_powerup() dump_pins(); //remove this: - // various sensible defaults for MIL2 - si->ps.sdram = true; - si->ps.memory_size = 2; //can override - si->ps.memory_size = 4; //can override my mil2 - - // apsed TODO MIL2 TVP 3026 may be 135, 175, 220 or 250MHz - // chip on my Millenium2 is TVP3026-250CPCE, 250MHz - // rudolf: works in Mhz now - si->ps.max_dac1_clock=250; // TVP3026 + fake_pins(); + LOG(2, ("INIT: Using faked PINS for now:\n")); + dump_pins(); //end remove this. /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ @@ -254,20 +254,20 @@ status_t mil2_general_powerup() LOG(2, ("INIT: Skipping card coldstart!\n")); mil2_dac_init(); -//rudolf: sync on green test: - /* disable 15bit mode CLUT-overlay function */ - //enable 'sync on green' option -// DXIW(GENCTRL, DXIR(GENCTRL | 0x20)); - /* enable composite sync instead of Hsync only */ -// VGAW_I(CRTCEXT,3,(VGAR_I(CRTCEXT,3) | 0x40)); -//end sync on green test. +//ok: + /* disable overscan, select 0 IRE, select straight-through sync signals from CRTC */ + DXIW (GENCTRL, (DXIR (GENCTRL) & 0x0c)); + /* fixme: checkout if we need this sync inverting stuff: already done via CRTC!?! + | (vsync_pos? 0x00:0x02) + | (hsync_pos? 0x00:0x01)); */ + + /* 8-bit DAC, enable DAC */ + DXIW(MISCCTRL, 0x0c); +// VGAW_I(SEQ,1,0x00); /*enable screen*/ -return B_OK; - // apsed TODO MIL2 taken from G100, avoid DXIR/W DACR/W - //rudolf: G100 version that was here nolonger exists, look at new implementation... return B_OK; } @@ -309,7 +309,6 @@ status_t g100_general_powerup() /* disable pixelclock oscillations before switching on CLUT */ DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); /* disable 15bit mode CLUT-overlay function */ - //fixme: setup b5 later for 'sync on green' option DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ DXIW(MISCCTRL,0x1b); @@ -349,12 +348,12 @@ status_t g100_general_powerup() /* wait 200uS minimum */ snooze(250); - /* reset memory */ + /* reset memory (MACCESS is a write only register!) */ ACCW(MACCESS, 0x00000000); /* select JEDEC reset method */ - ACCW(MACCESS,ACCR(MACCESS)|0x4000); + ACCW(MACCESS, 0x00004000); /* perform actual RAM reset */ - ACCW(MACCESS,ACCR(MACCESS)|0x8000); + ACCW(MACCESS, 0x0000c000); snooze(250); /* start memory refresh */ CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); @@ -412,7 +411,6 @@ status_t g200_general_powerup() /* disable pixelclock oscillations before switching on CLUT */ DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); /* disable 15bit mode CLUT-overlay function */ - //fixme: setup b5 later for 'sync on green' option DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ DXIW(MISCCTRL,0x1b); @@ -452,10 +450,10 @@ status_t g200_general_powerup() /* wait 200uS minimum */ snooze(250); - /* reset memory */ + /* reset memory (MACCESS is a write only register!) */ ACCW(MACCESS, 0x00000000); /* perform actual RAM reset */ - ACCW(MACCESS,ACCR(MACCESS)|0x8000); + ACCW(MACCESS, 0x00008000); snooze(250); /* start memory refresh */ CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); @@ -512,7 +510,6 @@ status_t g400_general_powerup() /* disable pixelclock oscillations before switching on CLUT */ DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); /* disable 15bit mode CLUT-overlay function */ - //fixme: setup b5 later for 'sync on green' option DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ DXIW(MISCCTRL,0x9b); @@ -553,10 +550,10 @@ status_t g400_general_powerup() /* wait 200uS minimum */ snooze(250); - /* reset memory */ + /* reset memory (MACCESS is a write only register!) */ ACCW(MACCESS, 0x00000000); /* perform actual RAM reset */ - ACCW(MACCESS,ACCR(MACCESS)|0x8000); + ACCW(MACCESS, 0x00008000); snooze(250); /* start memory refresh */ CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); @@ -584,10 +581,12 @@ status_t g400_general_powerup() static status_t g450_general_powerup() { - //fixme: check if g450 and g550 powerup should be the same! (DAC outputconnector?) status_t result; uint32 pwr_cas[] = {0, 1, 5, 6, 7, 5, 2, 3}; + /* used for convenience: MACCESS is a write only register! */ + uint32 maccess = 0x00000000; + LOG(4, ("INIT: G450/G550 powerup\n")); if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); @@ -607,8 +606,7 @@ status_t g450_general_powerup() DXIW(OUTPUTCONN,0x00); /* turn off both displays and the hardcursor (also disables transfers) */ gx00_crtc_dpms(0,0,0); - //fixme: - //g400_crtc2_dpms(0,0,0); + g400_crtc2_dpms(0,0,0); gx00_crtc_cursor_hide(); /* power up everything except DVI electronics (for now) */ @@ -625,7 +623,6 @@ status_t g450_general_powerup() /* disable pixelclock oscillations before switching on CLUT */ DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); /* disable 15bit mode CLUT-overlay function */ - //fixme: setup b5 later for 'sync on green' option DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ DXIW(MISCCTRL,0x9b); @@ -663,7 +660,8 @@ status_t g450_general_powerup() /* set RAM read tap delays and mode register opcode / streamer flow control */ ACCW(MEMRDBK, si->ps.memrdbk_reg); /* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */ - ACCW(MACCESS, ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1)); + maccess = ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1); + ACCW(MACCESS, maccess); /* clear b0-1 and 3, and set b31 in option4: re-enable memory clock */ CFGW(OPTION4, ((si->ps.option4_reg & 0x60000004) | 0x80000000)); snooze(250); @@ -675,7 +673,8 @@ status_t g450_general_powerup() if (!(si->ps.v5_mem_type & 0x0100)) { /* clear unknown bits */ - ACCW(MACCESS, 0x00000000); + maccess = 0x00000000; + ACCW(MACCESS, maccess); /* clear b12: unknown bit */ ACCW(MEMRDBK, (si->ps.memrdbk_reg & 0xffffefff)); } @@ -689,8 +688,8 @@ status_t g450_general_powerup() } /* create positive flank to generate memory reset */ - ACCW(MACCESS,ACCR(MACCESS) & 0xffff7fff); - ACCW(MACCESS,ACCR(MACCESS) | 0x00008000); + ACCW(MACCESS, (maccess & 0xffff7fff)); + ACCW(MACCESS, (maccess | 0x00008000)); snooze(250); /* start memory refresh */ @@ -724,6 +723,9 @@ status_t g450_general_powerup() /*turn on display one*/ gx00_crtc_dpms(1,1,1); + /* enable 'straight-through' sync outputs on both analog output connectors */ + DXIW(SYNCCTRL,0x00); + return B_OK; } @@ -763,27 +765,62 @@ status_t gx00_general_dac_select(int dac) /*MISCCTRL, clock src,...*/ switch(dac) { + /* G400 */ case DS_CRTC1DAC_CRTC2MAVEN: - DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ - CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); /*external clk*/ - VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77)); + /* connect CRTC1 to pixPLL */ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); + /* connect CRTC2 to vidPLL, connect CRTC1 to internal DAC and + * enable CRTC2 external video timing reset signal. + * (Setting for MAVEN 'master mode' TVout signal generation.) */ + CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); + /* disable CRTC1 external video timing reset signal */ + VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77)); + /* select CRTC2 RGB24 MAFC mode: connects CRTC2 to MAVEN DAC */ DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82); break; case DS_CRTC1MAVEN_CRTC2DAC: - DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); /*external clk*/ - CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk*/ + /* connect CRTC1 to vidPLL */ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); + /* connect CRTC2 to pixPLL and internal DAC and + * disable CRTC2 external video timing reset signal */ + CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); + /* enable CRTC1 external video timing reset signal. + * note: this is nolonger used as G450/G550 cannot do TVout on CRTC1 */ VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88)); + /* select CRTC1 RGB24 MAFC mode: connects CRTC1 to MAVEN DAC */ DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02); break; + /* G450/G550 */ case DS_CRTC1CON1_CRTC2CON2: - DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ - CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x0<<20)); /*internal clk - no DAC PTR*/ + /* connect CRTC1 to pixPLL */ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); + /* connect CRTC2 to vidPLL, connect CRTC1 to DAC1, disable CRTC2 + * external video timing reset signal, set CRTC2 progressive scan mode + * and disable TVout mode (b12). + * (Setting for MAVEN 'slave mode' TVout signal generation.) */ + //fixme: enable timing resets if TVout is used in master mode! + //otherwise keep it disabled. + CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x0<<20)); + /* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (monitor mode) */ DXIW(OUTPUTCONN,0x09); + /* Select 1.5 Volt MAVEN DAC ref. for monitor mode */ + DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40); + DXIW(GENIODATA, 0x00); break; + //fixme: toggle PLL's below if possible: + // otherwise toggle PLL's for G400 2nd case? case DS_CRTC1CON2_CRTC2CON1: - DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ - CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk - gets DAC*/ + /* connect CRTC1 to pixPLL */ + DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); + /* connect CRTC2 to vidPLL and DAC1, disable CRTC2 external + * video timing reset signal, and set CRTC2 progressive scan mode and + * disable TVout mode (b12). */ + CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x1<<20)); + /* connect DAC1 to CON2 (monitor mode), CRTC2/'DAC2' to CON1 */ DXIW(OUTPUTCONN,0x05); + /* Select 1.5 Volt MAVEN DAC ref. for monitor mode */ + DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40); + DXIW(GENIODATA, 0x00); break; default: return B_ERROR; @@ -817,13 +854,34 @@ status_t gx00_general_bios_to_powergraphics() VGAW(MISCW,0x08); /*set only MGA pixel clock in MISC - I don't want to map VGA stuff under this OS*/ - if (si->ps.card_type >= G100) { + switch (si->ps.card_type) + { + case G400: + case G400MAX: + /* makes CRTC2 stable! Matrox specify 8, but use 4 - grrrr! */ + DXIW(MAFCDEL,0x02); + break; + case G450: + case G550: + /* power up everything except DVI electronics (for now) */ + DXIW(PWRCTRL,0x1b); + /* enable 'straight-through' sync outputs on both analog output connectors */ + DXIW(SYNCCTRL,0x00); + break; + default: + break; + } + + if (si->ps.card_type >= G100) + { DXIW(MISCCTRL,0x9b); /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ DXIW(MULCTRL,0x4); /*RGBA direct mode*/ - } else { + } + else + { LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR))); } // apsed TODO MIL2 @@ -832,3 +890,193 @@ status_t gx00_general_bios_to_powergraphics() return B_OK; } + +/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify + * virtual_size to the nearest valid maximum for the mode on the card if not so. + * Then: check if virtual_width adheres to the cards _multiple_ constraints, and + * create mode slopspace if not so. + * We use acc multiple constraints here if we expect we can use acceleration, because + * acc constraints are worse than CRTC constraints. + * + * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ +//fixme: seperate heads for real dualhead modes: +//CRTC1 and 2 constraints differ! +status_t gx00_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row) +{ + /* Note: + * This routine assumes that the CRTC memory pitch granularity is 'smaller than', + * or 'equals' the acceleration engine memory pitch granularity! */ + + uint32 video_pitch; + uint32 acc_mask, crtc_mask; + uint8 depth = 8; + + /* determine pixel multiple based on 2D/3D engine constraints */ + switch (si->ps.card_type) + { + case MIL1: + case MIL2: + /* see MIL1/2 specs: + * these cards always use a 64bit RAMDAC (TVP3026) and interleaved memory */ + switch (target->space) + { + case B_CMAP8: acc_mask = 0x7f; depth = 8; break; + case B_RGB15: acc_mask = 0x3f; depth = 16; break; + case B_RGB16: acc_mask = 0x3f; depth = 16; break; + case B_RGB24: acc_mask = 0x7f; depth = 24; break; + case B_RGB32: acc_mask = 0x1f; depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + default: + /* see G100 and up specs: + * these cards can do 2D as long as multiples of 32 are used. + * (Note: don't mix this up with adress linearisation!) */ + switch (target->space) + { + case B_CMAP8: depth = 8; break; + case B_RGB15: depth = 16; break; + case B_RGB16: depth = 16; break; + case B_RGB24: depth = 24; break; + case B_RGB32: depth = 32; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + acc_mask = 0x1f; + break; + } + + /* determine pixel multiple based on CRTC memory pitch constraints. + * (Note: Don't mix this up with CRTC timing contraints! Those are + * multiples of 8 for horizontal, 1 for vertical timing.) */ + switch (si->ps.card_type) + { + case MIL1: + case MIL2: + /* see MIL1/2 specs: + * these cards always use a 64bit RAMDAC and interleaved memory */ + switch (target->space) + { + case B_CMAP8: crtc_mask = 0x7f; break; + case B_RGB15: crtc_mask = 0x3f; break; + case B_RGB16: crtc_mask = 0x3f; break; + /* for B_RGB24 crtc_mask 0x7f is worst case scenario (MIL2 constraint) */ + case B_RGB24: crtc_mask = 0x7f; break; + case B_RGB32: crtc_mask = 0x1f; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + break; + default: + /* see G100 and up specs */ + switch (target->space) + { + case B_CMAP8: crtc_mask = 0x0f; break; + case B_RGB15: crtc_mask = 0x07; break; + case B_RGB16: crtc_mask = 0x07; break; + case B_RGB24: crtc_mask = 0x0f; break; + case B_RGB32: crtc_mask = 0x03; break; + default: + LOG(8,("INIT: unknown color space: 0x%08x\n", target->space)); + return B_ERROR; + } + /* see G400 specs: CRTC2 has different constraints */ + /* Note: + * set for RGB and B_YCbCr422 modes. Other modes need larger multiples! */ + if (target->flags & DUALHEAD_BITS) + { + switch (target->space) + { + case B_RGB16: crtc_mask = 0x1f; break; + case B_RGB32: crtc_mask = 0x0f; break; + default: + LOG(8,("INIT: illegal DH color space: 0x%08x\n", target->space)); + return B_ERROR; + } + } + break; + } + + /* check if we can setup this mode with acceleration: + * Max sizes need to adhere to both the acceleration engine _and_ the CRTC constraints! */ + si->acc_mode = true; + /* check virtual_width */ + switch (si->ps.card_type) + { + case MIL1: + case MIL2: + 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; + + /* 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. */ + { + /* 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; + case B_RGB32_LITTLE: + if (target->virtual_width > (4092 & ~crtc_mask)) + target->virtual_width = (4092 & ~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/matrox/engine/mga_info.c b/src/add-ons/accelerants/matrox/engine/mga_info.c index 288af4dc64..95b0bf1847 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_info.c +++ b/src/add-ons/accelerants/matrox/engine/mga_info.c @@ -2,7 +2,7 @@ /* some bits are hacks, where PINS is not known */ /* Authors: Mark Watson 2/2000, - Rudolf Cornelissen 10-11/2002 + Rudolf Cornelissen 10/2002-4/2003 */ #define MODULE_BIT 0x00002000 @@ -111,52 +111,80 @@ status_t parse_pins () status_t pins1_read(uint8 *pins, uint8 length) { -//remove later on here: -// float f_ref; /* PLL reference-oscillator frequency */ -// uint32 max_system_vco; /* graphics engine PLL VCO limits */ -// uint32 min_system_vco; -// uint32 max_pixel_vco; /* dac1 PLL VCO limits */ -// uint32 min_pixel_vco; -// uint32 max_video_vco; /* dac2, maven PLL VCO limits */ -// uint32 min_video_vco; -// uint32 std_engine_clock; /* graphics engine clock speed needed */ -// uint32 std_engine_clock_dh; -// uint32 max_dac1_clock; /* dac1 limits */ -// uint32 max_dac1_clock_8; /* dac1 limits correlated to RAMspeed limits */ -// uint32 max_dac1_clock_16; -// uint32 max_dac1_clock_24; -// uint32 max_dac1_clock_32; -// uint32 max_dac1_clock_32dh; -// uint32 max_dac2_clock; /* dac2 limits */ -// uint32 max_dac2_clock_8; /* dac2, maven limits correlated to RAMspeed limits */ -// uint32 max_dac2_clock_16; -// uint32 max_dac2_clock_24; -// uint32 max_dac2_clock_32; -// uint32 max_dac2_clock_32dh; -// bool secondary_head; /* presence of functions */ -// bool secondary_tvout; -// bool primary_dvi; -// bool secondary_dvi; -// uint32 memory_size; /* memory in Mb */ -// uint32 mctlwtst_reg; /* memory control waitstate register */ -// uint32 memrdbk_reg; /* memory readback register */ -// uint32 option_reg; /* option register */ -// uint32 option2_reg; /* option2 register */ -// uint32 option3_reg; /* option3 register */ -// uint32 option4_reg; /* option4 register */ -// uint8 v3_option2_reg; -// uint8 v3_clk_div; /* pins v3 memory and system clock division factors */ -// uint8 v3_mem_type; /* pins v3 memory type info */ -// uint16 v5_mem_type; /* pins v5 memory type info */ -// bool sdram; -//end remove later on here. + if (length != 64) + { + LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length)); + return B_ERROR; + } - //fixme: implement this.. - return B_ERROR; +//reset all for test: +//float: + si->ps.f_ref = 0; +//uint32: + si->ps.max_system_vco = 0; + si->ps.min_system_vco = 0; + si->ps.min_pixel_vco = 0; + si->ps.min_video_vco = 0; + si->ps.std_engine_clock_dh = 0; + si->ps.max_dac1_clock_32 = 0; + si->ps.max_dac1_clock_32dh = 0; + si->ps.memory_size = 0; + si->ps.mctlwtst_reg = 0; + si->ps.memrdbk_reg = 0; + si->ps.option2_reg = 0; + si->ps.option3_reg = 0; + si->ps.option4_reg = 0; +//uint8: + si->ps.v3_option2_reg = 0; + si->ps.v3_clk_div = 0; + si->ps.v3_mem_type = 0; +//uint16: + si->ps.v5_mem_type = 0; +//bools: + si->ps.secondary_head = false; + si->ps.secondary_tvout = false; + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + si->ps.sdram = true; + +//experimental: checkout! + si->ps.max_dac1_clock_32 = pins[22];//ramdac + si->ps.max_pixel_vco = (pins[25] << 8) | pins[24];//PCLK + si->ps.std_engine_clock = (pins[29] << 8) | pins[28]; + if (((pins[31] << 8) | pins[30]) < si->ps.std_engine_clock) + si->ps.std_engine_clock = (pins[31] << 8) | pins[30]; + if (((pins[33] << 8) | pins[32]) < si->ps.std_engine_clock) + si->ps.std_engine_clock = (pins[33] << 8) | pins[32]; + +//temp. test to see some vals.. + si->ps.max_video_vco = (pins[27] << 8) | pins[26];//LCLK + //feature flags: + si->ps.option_reg = (pins[53] << 24) | (pins[52] << 16) | (pins[51] << 8) | pins [50]; + + si->ps.max_dac2_clock = (pins[35] << 8) | pins[34];//clkmod + si->ps.max_dac2_clock_8 = (pins[37] << 8) | pins[36];//testclk + si->ps.max_dac2_clock_16 = (pins[39] << 8) | pins[38];//vgafreq1 + si->ps.max_dac2_clock_24 = (pins[41] << 8) | pins[40];//vgafreq2 + si->ps.max_dac2_clock_32 = (pins[55] << 8) | pins[54];//vga clock + si->ps.max_dac2_clock_32dh = pins[58];//vid ctrl + + si->ps.max_dac1_clock = (pins[29] << 8) | pins[28];//clkbase + si->ps.max_dac1_clock_8 = (pins[31] << 8) | pins[30];//4mb + si->ps.max_dac1_clock_16 = (pins[33] << 8) | pins[32];//8mb + si->ps.max_dac1_clock_24 = pins[23];//ramdac type + +//test! Don't actually use the reported settings for now... + return B_OK; } status_t pins2_read(uint8 *pins, uint8 length) { + if (length != 64) + { + LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length)); + return B_ERROR; + } + LOG(2,("INFO: PINS version 2 details not yet known\n")); return B_ERROR; } @@ -424,18 +452,15 @@ status_t pins5_read(uint8 *pins, uint8 length) } /* fill out the shared info si->ps struct */ - if (pins[4]) m_factor = 8; + if (pins[4] == 0x01) m_factor = 8; + if (pins[4] >= 0x02) m_factor = 10; si->ps.max_system_vco = m_factor * pins[36]; si->ps.max_video_vco = m_factor * pins[37]; - /* pixelVCO multiplier is 10 if pins V5.2 */ - if (pins[4] == 0x02) si->ps.max_pixel_vco = 10 * pins[38]; - else si->ps.max_pixel_vco = m_factor * pins[38]; + si->ps.max_pixel_vco = m_factor * pins[38]; si->ps.min_system_vco = m_factor * pins[121]; si->ps.min_video_vco = m_factor * pins[122]; - /* pixelVCO multiplier is 10 if pins V5.2 */ - if (pins[4] == 0x02) si->ps.min_pixel_vco = 10 * pins[123]; - else si->ps.min_pixel_vco = m_factor * pins[123]; + si->ps.min_pixel_vco = m_factor * pins[123]; if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco; else si->ps.max_dac1_clock_8 = 4 * pins[39]; @@ -517,6 +542,9 @@ void fake_pins(void) switch (si->ps.card_type) { + case MIL1: + pinsmil1_fake(); + break; case MIL2: pinsmil2_fake(); break; @@ -541,15 +569,16 @@ void fake_pins(void) } /* find out if the card has a maven */ - if (i2c_maven_probe() == B_OK) + si->ps.secondary_tvout = false; + si->ps.secondary_head = false; + /* only do I2C probe if the card has a chance */ + if (si->ps.card_type >= G100) { - si->ps.secondary_tvout = true; - si->ps.secondary_head = true; - } - else - { - si->ps.secondary_tvout = false; - si->ps.secondary_head = false; + if (i2c_maven_probe() == B_OK) + { + si->ps.secondary_tvout = true; + si->ps.secondary_head = true; + } } /* not used because no coldstart will be attempted */ @@ -567,8 +596,82 @@ void fake_pins(void) si->ps.v5_mem_type = 0; } +void pinsmil1_fake(void) +{ + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + si->ps.f_ref = 14.31818; + /* see MIL1 specs */ + si->ps.max_system_vco = 220; + si->ps.min_system_vco = 110; + si->ps.max_pixel_vco = 220; + si->ps.min_pixel_vco = 110; + /* no specs, assuming these */ + si->ps.max_video_vco = 0; + si->ps.min_video_vco = 0; + /* see MIL1 specs */ + si->ps.max_dac1_clock = 220; + si->ps.max_dac1_clock_8 = 220; + si->ps.max_dac1_clock_16 = 200; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 180; + si->ps.max_dac1_clock_32 = 136; + si->ps.max_dac1_clock_32dh = 0; + /* see specs */ + si->ps.max_dac2_clock = 0; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 0; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 0; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 0; + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 2Mb RAM mounted */ + //fixme: see if we can get this from OPTION or so... + si->ps.memory_size = 2; + //fixme: should be overrule-able via mga.settings for MIL1. + //fail-safe mode for now: + si->ps.sdram = true; +} + void pinsmil2_fake(void) { + /* 'worst case' scenario defaults, overrule-able via mga.settings if needed */ + + si->ps.f_ref = 14.31818; + /* see MIL2 specs */ + si->ps.max_system_vco = 220; + si->ps.min_system_vco = 110; + si->ps.max_pixel_vco = 220; + si->ps.min_pixel_vco = 110; + /* no specs, assuming these */ + si->ps.max_video_vco = 0; + si->ps.min_video_vco = 0; + /* see MIL2 specs */ + si->ps.max_dac1_clock = 220; + si->ps.max_dac1_clock_8 = 220; + si->ps.max_dac1_clock_16 = 200; + /* 'failsave' values */ + si->ps.max_dac1_clock_24 = 180; + si->ps.max_dac1_clock_32 = 136; + si->ps.max_dac1_clock_32dh = 0; + /* see specs */ + si->ps.max_dac2_clock = 0; + si->ps.max_dac2_clock_8 = 0; + si->ps.max_dac2_clock_16 = 0; + si->ps.max_dac2_clock_24 = 0; + si->ps.max_dac2_clock_32 = 0; + /* 'failsave' value */ + si->ps.max_dac2_clock_32dh = 0; + si->ps.primary_dvi = false; + si->ps.secondary_dvi = false; + /* presume 4Mb RAM mounted */ + //fixme: see if we can get this from OPTION or so... + si->ps.memory_size = 4; + //fixme: should be overrule-able via mga.settings for MIL2. + //fail-safe mode for now: + si->ps.sdram = true; } void pinsg100_fake(void) @@ -741,12 +844,12 @@ void pinsg450_fake(void) si->ps.f_ref = 27.000; /* see G450 pins readouts for max ranges, then use a bit smaller ones */ /* carefull not to take to high lower limits, and high should be >= 2x low. */ - si->ps.max_system_vco = 600; - si->ps.min_system_vco = 256; + si->ps.max_system_vco = 640; + si->ps.min_system_vco = 320; si->ps.max_pixel_vco = 640; si->ps.min_pixel_vco = 320; - si->ps.max_video_vco = 600; - si->ps.min_video_vco = 256; + si->ps.max_video_vco = 640; + si->ps.min_video_vco = 320; si->ps.max_dac1_clock = 360; si->ps.max_dac1_clock_8 = 360; si->ps.max_dac1_clock_16 = 360; @@ -786,8 +889,8 @@ void pinsg550_fake(void) si->ps.min_system_vco = 384; si->ps.max_pixel_vco = 960; si->ps.min_pixel_vco = 320; - si->ps.max_video_vco = 600; - si->ps.min_video_vco = 256; + si->ps.max_video_vco = 960; + si->ps.min_video_vco = 320; si->ps.max_dac1_clock = 360; si->ps.max_dac1_clock_8 = 360; si->ps.max_dac1_clock_16 = 360; diff --git a/src/add-ons/accelerants/matrox/engine/mga_maven.c b/src/add-ons/accelerants/matrox/engine/mga_maven.c index d6058700bb..3c48cbabdf 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_maven.c +++ b/src/add-ons/accelerants/matrox/engine/mga_maven.c @@ -1,76 +1,114 @@ /* program the MAVEN in monitor mode */ -/* Thanx to Petr Vandrovec for info on the MAVEN */ -/* Mark Watson 6/2000 */ + +/* Authors: + Mark Watson 6/2000, + Rudolf Cornelissen 1/2003-4/2003 + + Thanx to Petr Vandrovec for writing matroxfb. +*/ #define MODULE_BIT 0x00001000 #include "mga_std.h" +status_t g450_g550_maven_set_vid_pll(display_mode target); +status_t g100_g400max_maven_set_vid_pll(display_mode target); + status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v) { - if (display&h&v) + /* this function is nolonger needed on G450/G550 cards */ + if (si->ps.card_type > G400MAX) return B_OK; + + if (display & h & v) { - MAVW(MONEN,0xb2); - MAVW(MONSET,0x20); /*must be set to this in monitor mode*/ - MAVW(OUTMODE,3); /*monitor mode*/ - MAVW(STABLE,0x22); /*makes picture stable?*/ - MAVW(TEST,0x00); /*turn off test signal*/ + /* turn on screen */ + if (!(si->dm.flags & TV_BITS)) + { + /* monitor mode */ + MAVW(MONEN, 0xb2); + MAVW(MONSET, 0x20); /* must be set to this in monitor mode */ + MAVW(OUTMODE, 0x03); /* output: monitor mode */ + MAVW(STABLE, 0x22); /* makes picture stable? */ + MAVW(TEST, 0x00); /* turn off test signal */ + } + else + { + /* TVout mode */ + MAVW(MONEN, 0xb3); + MAVW(MONSET, 0x20); + MAVW(OUTMODE, 0x08); /* output: SVideo/Composite */ + MAVW(STABLE, 0x02); /* makes picture stable? */ + //fixme? linux uses 0x14... + MAVW(TEST, (MAVR(TEST) & 0x10)); + } } else { - /*turn off screen using a few methods!*/ - MAVW(STABLE,0x6a); -// MAVW(TEST,0x3); - MAVW(OUTMODE,0x00); + /* turn off screen using a few methods! */ + MAVW(STABLE, 0x6a); +// MAVW(TEST, 0x03); + MAVW(OUTMODE, 0x00); } return B_OK; } /*set a mode line - inputs are in pixels/scanlines*/ -status_t gx00_maven_set_timing( - uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, - uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, - uint8 hsync_pos,uint8 vsync_pos - ) +status_t gx00_maven_set_timing(display_mode target) { + /* this function is nolonger needed on G450/G550 cards */ + if (si->ps.card_type > G400MAX) return B_OK; + LOG(4,("MAVEN: setting timing\n")); /*check horizontal timing parameters are to nearest 8 pixels*/ - if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7)) + if ((target.timing.h_display & 0x07) | + (target.timing.h_sync_start & 0x07) | + (target.timing.h_sync_end & 0x07) | + (target.timing.h_total & 0x07)) { - LOG(8,("MAVEN:Horizontal timings are not multiples of 8 pixels\n")); + LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n")); return B_ERROR; } /*program the MAVEN*/ - MAVWW(LASTLINEL,htotal); - MAVWW(HSYNCLENL,(hsync_e-hsync_s)); - MAVWW(HSYNCSTRL,(htotal-hsync_s)); - MAVWW(HDISPLAYL,(htotal-hsync_s+hdisp_e)); - MAVWW(HTOTALL,(htotal+1)); + MAVWW(LASTLINEL, target.timing.h_total); + MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start)); + MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start)); + MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) + + target.timing.h_display)); + MAVWW(HTOTALL, (target.timing.h_total + 1)); - MAVWW(VSYNCLENL,(vsync_e-vsync_s-1)); - MAVWW(VSYNCSTRL,(vtotal-vsync_s)); - MAVWW(VDISPLAYL,(vtotal-1)); - MAVWW(VTOTALL,(vtotal-1)); + MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1)); + MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start)); + MAVWW(VDISPLAYL, (target.timing.v_total - 1)); + MAVWW(VTOTALL, (target.timing.v_total - 1)); - MAVWW(HVIDRSTL,(htotal-si->crtc_delay)); - MAVWW(VVIDRSTL,(vtotal-2)); + MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay)); + MAVWW(VVIDRSTL, (target.timing.v_total - 2)); return B_OK; } +//not used: +/* void gx00_maven_delay(int number) { + // this function is nolonger needed on G450/G550 cards + if (si->ps.card_type > G400MAX) return; + MAVWW(HVIDRSTL,(si->dm.timing.h_total-number)); } +*/ /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ status_t gx00_maven_mode(int mode,float brightness) { uint8 luma; + /* this function is nolonger needed on G450/G550 cards */ + if (si->ps.card_type > G400MAX) return B_OK; + /*set luma to a suitable value for brightness*/ /*assuming 1A is a sensible value*/ luma = (uint8)(0x1a * brightness); @@ -80,93 +118,442 @@ status_t gx00_maven_mode(int mode,float brightness) return B_OK; } -/*program the pixpll on the maven - frequency in kHz*/ -status_t gx00_maven_set_pix_pll(float f_vco) +status_t gx00_maven_set_vid_pll(display_mode target) +{ + switch (si->ps.card_type) + { + case G450: + case G550: + return g450_g550_maven_set_vid_pll(target); + break; + default: + return g100_g400max_maven_set_vid_pll(target); + break; + } + return B_ERROR; +} + +status_t g450_g550_maven_set_vid_pll(display_mode target) { uint8 m=0,n=0,p=0; + uint time = 0; - float pix_setting; + float pix_setting, req_pclk; status_t result; - LOG(4,("MAVEN:Setting PIX PLL %fMHz\n", f_vco)); + req_pclk = (target.timing.pixel_clock)/1000.0; + LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk)); - result = gx00_maven_pix_pll_find(f_vco,&pix_setting,&m,&n,&p); + result = g450_g550_maven_vid_pll_find(target,&pix_setting,&m,&n,&p, 1); if (result != B_OK) { return result; } - - /*reprogram (select,wait for stability)*/ - MAVW(PIXPLLM,(m)); /*set m value*/ - MAVW(PIXPLLN,(n)); /*set n value*/ - MAVW(PIXPLLP,(p|0x80)); /*set p value*/ - LOG(2,("MAVEN: Clocks found: %x %x %x\n",m,n,p)); - delay(1000); /*wait 1000us for PIXPLL to lock (no way of knowing)*/ - LOG(2,("MAVEN: PIX PLL frequency locked\n")); + + /*reprogram (disable,select,wait for stability,enable)*/ + CR2W(CTL, (CR2R(CTL) | 0x08)); /* disable the VIDPLL */ + CR2W(CTL, (CR2R(CTL) | 0x06)); /* select the VIDPLL */ + DXIW(VIDPLLM,(m)); /* set m value */ + DXIW(VIDPLLN,(n)); /* set n value */ + DXIW(VIDPLLP,(p)); /* set p value */ + + /* Wait for the VIDPLL frequency to lock until timeout occurs */ + while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 2000)) + { + time++; + snooze(1); + } + + if (time > 2000) + LOG(2,("MAVEN: VID PLL frequency not locked!\n")); + else + LOG(2,("MAVEN: VID PLL frequency locked\n")); + CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */ return B_OK; } -/*find nearest valid pix pll*/ -status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uint8 * n_result,uint8 * p_result) +/* program the video PLL in the MAVEN */ +status_t g100_g400max_maven_set_vid_pll(display_mode target) { - float f_ref=27.000; - int n_min=4; - int n_max=127; - int m_min=2; - int m_max=31; - int m=0,n=0,p=0; - float error; - float error_best; - int best[3]; - float f_rat; + uint8 m=0,n=0,p=0; - LOG(4,("MAVEN:Checking PIX PLL %fMHz\n", f_vco)); + float pix_setting, req_pclk; + status_t result; - /*f_rat.m/p=n where m=M+1,n=N+1,p=P+1,f_rat=f_vco/f_ref*/ - f_rat = f_vco/f_ref; - error_best = 999999999; - for (p=0x2 -1*(f_vco>80.0);p<0x10;p=p<<1) + req_pclk = (target.timing.pixel_clock)/1000.0; + LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk)); + + result = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p); + if (result != B_OK) { - for (m=m_min;mn_max || n spot the Perl coder :-)*/ + /*reprogram (select,wait for stability)*/ + MAVW(PIXPLLM,(m)); /* set m value */ + MAVW(PIXPLLN,(n)); /* set n value */ + MAVW(PIXPLLP,(p | 0x80)); /* set p value enabling PLL */ + + /* Wait for the VIDPLL frequency to lock: detection is not possible it seems */ + snooze(2000); + + LOG(2,("MAVEN: VID PLL frequency should be locked now...\n")); + + return B_OK; +} + +/* find nearest valid video PLL setting */ +status_t g100_g400max_maven_vid_pll_find( + display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result) +{ + int m = 0, n = 0, p = 0, m_max; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + /* determine the max. reference-frequency postscaler setting for the current card */ + //fixme: check G100 and G200 m_max if possible... + switch(si->ps.card_type) { - if(f_vco>180) {p|=0x18;break;}; - if(f_vco>140) {p|=0x10;break;}; - if(f_vco>100) {p|=0x08;break;}; + case G100: + LOG(4,("MAVEN: G100 restrictions apply\n")); + m_max = 32; + break; + case G200: + LOG(4,("MAVEN: G200 restrictions apply\n")); + m_max = 32; + break; + default: + LOG(4,("MAVEN: G400/G400MAX restrictions apply\n")); + m_max = 32; break; } - /*set the result*/ - *result = (float) (f_ref*n)/(m*(p&0x7)); - *m_result = m-1; - *n_result = n-1; - *p_result = p-1; + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac2_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclk = si->ps.max_dac2_clock_32dh; - /*display the found value*/ - LOG(4,("MAVEN: pixpllcheck - requested %fMHz got %fMHz\n",(double)f_vco,*result)); + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_video_vco divided by highest postscaler-factor */ + if (req_pclk < (si->ps.min_video_vco / 8.0)) + { + LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_video_vco / 8.0))); + req_pclk = (si->ps.min_video_vco / 8.0); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= m_max; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); + /* ..and check for validity */ + if ((n < 8) || (n > 128)) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m=best[0] - 1; + n=best[1] - 1; + p=best[2] - 1; + + /* calc the needed PLL loopbackfilter setting belonging to current VCO speed */ + f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); + LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco)); + + switch(si->ps.card_type) + { + case G100: + case G200: + for(;;) + { + if (f_vco >= 180) {p |= (0x03 << 3); break;}; + if (f_vco >= 140) {p |= (0x02 << 3); break;}; + if (f_vco >= 100) {p |= (0x01 << 3); break;}; + break; + } + break; + default: + for(;;) + { + if (f_vco >= 240) {p |= (0x03 << 3); break;}; + if (f_vco >= 170) {p |= (0x02 << 3); break;}; + if (f_vco >= 110) {p |= (0x01 << 3); break;}; + break; + } + break; + } + + /* return the results */ + *calc_pclk = f_vco / ((p & 0x07) + 1); + *m_result = m; + *n_result = n; + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); + + return B_OK; +} + +status_t gx50_maven_check_vid_pll(uint8 m, uint8 n, uint8 p) +{ + uint time = 0, count = 0; + + /* reprogram (disable,select,wait for stability,enable) */ + CR2W(CTL, (CR2R(CTL) | 0x06)); /* select the VIDPLL */ + DXIW(VIDPLLM,(m)); /* set m value */ + DXIW(VIDPLLN,(n)); /* set n value */ + DXIW(VIDPLLP,(p)); /* set p value */ + + /* give the PLL 1mS at least to get a lock */ + time = 0; + while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 1000)) + { + time++; + snooze(1); + } + + /* no lock aquired, not useable */ + if (time > 1000) return B_ERROR; + + /* check if lock holds for at least 90% of the time */ + for (time = 0, count = 0; time <= 1000; time++) + { + if(DXIR(VIDPLLSTAT) & 0x40) count++; + snooze(1); + } + /* we have a winner */ + if (count >= 900) return B_OK; + + /* nogo, the PLL does not stabilize */ + return B_ERROR; +} + +status_t gx50_maven_check_vid_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q) +{ + uint8 s=0, p_backup = *p; + + /* preset no candidate, non working setting */ + *q = 0; + /* preset lowest range filter */ + *p &= 0x47; + + /* iterate through all possible filtersettings */ + CR2W(CTL, (CR2R(CTL) | 0x08)); /* disable the VIDPLL */ + + for (s = 0; s < 8 ;s++) + { + if (gx50_maven_check_vid_pll(m, n, *p)== B_OK) + { + /* now check 3 closest lower and higher settings */ + if ((gx50_maven_check_vid_pll(m, n - 3, *p)== B_OK) && + (gx50_maven_check_vid_pll(m, n - 2, *p)== B_OK) && + (gx50_maven_check_vid_pll(m, n - 1, *p)== B_OK) && + (gx50_maven_check_vid_pll(m, n + 1, *p)== B_OK) && + (gx50_maven_check_vid_pll(m, n + 2, *p)== B_OK) && + (gx50_maven_check_vid_pll(m, n + 3, *p)== B_OK)) + { + LOG(2,("MAVEN: found optimal working VCO filter: #%d\n",s)); + /* preset first choice setting found */ + *q = 1; + /* we are done */ + CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */ + return B_OK; + } + else + { + LOG(2,("MAVEN: found critical but working VCO filter: #%d\n",s)); + /* preset backup setting found */ + *q = 2; + /* remember this setting */ + p_backup = *p; + /* let's continue to see if a better filter exists */ + } + } + /* new filtersetting to try */ + *p += (1 << 3); + } + + /* return the (last found) backup result, or the original p value */ + *p = p_backup; + CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */ + /* we found only a non-optimal value */ + if (*q == 2) return B_OK; + + /* nothing worked at all */ + LOG(2,("MAVEN: no working VCO filter found!\n")); + return B_ERROR; +} + +/* find nearest valid video PLL setting */ +status_t g450_g550_maven_vid_pll_find + (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test) +{ + int m = 0, n = 0; + uint8 p = 0, q = 0; + float error, error_best = 999999999; + int best[3]; + float f_vco, max_pclk; + float req_pclk = target.timing.pixel_clock/1000.0; + + LOG(4,("MAVEN: G450/G550 restrictions apply\n")); + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_RGB16_LITTLE: + max_pclk = si->ps.max_dac2_clock_16; + break; + case B_RGB32_LITTLE: + max_pclk = si->ps.max_dac2_clock_32; + break; + default: + /* use fail-safe value */ + max_pclk = si->ps.max_dac2_clock_32; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclk = si->ps.max_dac2_clock_32dh; + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_pixel_vco divided by highest postscaler-factor */ + if (req_pclk < (si->ps.min_video_vco / 16.0)) + { + LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)(si->ps.min_video_vco / 16.0))); + req_pclk = (si->ps.min_video_vco / 16.0); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclk > max_pclk) + { + LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n", + req_pclk, (float)max_pclk)); + req_pclk = max_pclk; + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x20; p = p<<1) + { + /* calculate the needed VCO frequency for this postscaler setting */ + f_vco = req_pclk * p; + + /* check if this is within range of the VCO specs */ + if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco)) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= 32; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5); + /* ..and check for validity, BUT: + * Keep in mind that we need to be able to test n-3 ... n+3! */ + if ((n < (8 + 3)) || (n > (128 - 3))) continue; + + /* find error in frequency this setting gives */ + error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p)); + + /* note the setting if best yet */ + if (error < error_best) + { + error_best = error; + best[0]=m; + best[1]=n; + best[2]=p; + } + } + } + } + + /* setup the scalers programming values for found optimum setting */ + m=best[0] - 1; + n=best[1] - 2; + switch(best[2]) + { + case 1: + p = 0x40; + break; + case 2: + p = 0x00; + break; + case 4: + p = 0x01; + break; + case 8: + p = 0x02; + break; + case 16: + p = 0x03; + break; + } + + /* log the closest VCO speed found */ + f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2); + LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco)); + + /* now find the filtersetting that matches best with this frequency by testing. + * for now we assume this routine succeeds to get us a stable setting */ + if (test) + gx50_maven_check_vid_pll_range(m, n, &p, &q); + else + LOG(2,("MAVEN: Not testing G450/G550 VCO feedback filters\n")); + + /* return the results */ + *calc_pclk = f_vco / best[2]; + *m_result = m; + *n_result = n; + *p_result = p; + + /* display the found pixelclock values */ + LOG(2,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + req_pclk, *calc_pclk, *m_result, *n_result, *p_result)); return B_OK; } diff --git a/src/add-ons/accelerants/matrox/engine/mga_maventv.c b/src/add-ons/accelerants/matrox/engine/mga_maventv.c new file mode 100644 index 0000000000..7a86ca80d8 --- /dev/null +++ b/src/add-ons/accelerants/matrox/engine/mga_maventv.c @@ -0,0 +1,1210 @@ +/* Authors: + Mark Watson 2000, + Rudolf Cornelissen 1/2003-3/2003 + + Thanx to Petr Vandrovec for writing matroxfb. +*/ + +#define MODULE_BIT 0x00100000 + +#include "mga_std.h" + +typedef struct { + uint32 h_total; + uint32 h_display; + uint32 h_sync_length; + uint32 front_porch; + uint32 back_porch; + uint32 color_burst; + uint32 v_total; + float chroma_subcarrier; +} gx50_maven_timing; + +//fixme: setup fixed CRTC2 modes for all modes and block other modes: +// - 640x480, 800x600, 1024x768 NTSC and PAL overscan compensated modes (desktop) +// - 640x480, 720x480 NTSC and 768x576, 720x576 non-overscan compensated modes (video) +//fixme: try to implement 'fast' and 'slow' settings for all modes, +// so buffer duplication or skipping won't be neccesary for realtime video. +//fixme: try to setup the CRTC2 in interlaced mode for the video modes on <= G400MAX cards. + +/* find 'exact' valid video PLL setting */ +status_t g100_g400max_maventv_vid_pll_find( + display_mode target, unsigned int * ht_new, unsigned int * ht_last_line, + uint8 * m_result, uint8 * n_result, uint8 * p_result) +{ + int m = 0, n = 0, p = 0, m_max; + float diff, diff_smallest = 999999999; + int best[5], h_total_mod; + float fields_sec, f_vco; + /* We need to be exact, so work with clockperiods per field instead of with frequency. + * Make sure however we truncate these clocks to be integers! + * (The NTSC field frequency would otherwise prevent the 'whole number of clocks per field' + * check done in this routine later on...) */ + uint32 vco_clks_field, max_pclks_field, req_pclks_field; + /* We need this variable to be a float, because we need to be able to verify if this + * represents a whole number of clocks per field later on! */ + float calc_pclks_field; + + LOG(2,("MAVENTV: searching for EXACT videoclock match\n")); + + /* determine the max. reference-frequency postscaler setting for the current card */ + //fixme: check G100 and G200 m_max if exist and possible... + switch(si->ps.card_type) + { + case G100: + LOG(2,("MAVENTV: G100 restrictions apply\n")); + m_max = 32; + break; + case G200: + LOG(2,("MAVENTV: G200 restrictions apply\n")); + m_max = 32; + break; + default: + LOG(2,("MAVENTV: G400/G400MAX restrictions apply\n")); + m_max = 32; + break; + } + + /* set number of fields per second to generate */ + if ((target.flags & TV_BITS) == TV_PAL) + fields_sec = 50.0; + else + fields_sec = 59.94; + + /* determine the max. pixelclock for the current videomode */ + switch (target.space) + { + case B_RGB16_LITTLE: + max_pclks_field = (si->ps.max_dac2_clock_16 * 1000000) / fields_sec; + break; + case B_RGB32_LITTLE: + max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; + break; + default: + /* use fail-safe value */ + max_pclks_field = (si->ps.max_dac2_clock_32 * 1000000) / fields_sec; + break; + } + /* if some dualhead mode is active, an extra restriction might apply */ + if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE)) + max_pclks_field = (si->ps.max_dac2_clock_32dh * 1000000) / fields_sec; + + /* Checkout all possible Htotal settings within the current granularity step + * of CRTC2 to get a real close videoclock match! + * (The MAVEN apparantly has a granularity of 1 pixel, while CRTC2 has 8 pixels) */ + for (h_total_mod = 0; h_total_mod < 8; h_total_mod++) + { + LOG(2,("MAVENTV: trying h_total modification of +%d...\n", h_total_mod)); + + /* Calculate videoclock to be a bit to high so we can compensate for an exact + * match via h_total_lastline.. */ + *ht_new = target.timing.h_total + h_total_mod + 2; + + /* Make sure the requested pixelclock is within the PLL's operational limits */ + /* lower limit is min_video_vco divided by highest postscaler-factor */ + req_pclks_field = *ht_new * target.timing.v_total; + if (req_pclks_field < (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0)) + { + req_pclks_field = (((si->ps.min_video_vco * 1000000) / fields_sec) / 8.0); + LOG(4,("MAVENTV: WARNING, clamping at lowest possible videoclock\n")); + } + /* upper limit is given by pins in combination with current active mode */ + if (req_pclks_field > max_pclks_field) + { + req_pclks_field = max_pclks_field; + LOG(4,("MAVENTV: WARNING, clamping at highest possible videoclock\n")); + } + + /* iterate through all valid PLL postscaler settings */ + for (p=0x01; p < 0x10; p = p<<1) + { + /* calc the needed number of VCO clocks per field for this postscaler setting */ + vco_clks_field = req_pclks_field * p; + + /* check if this is within range of the VCO specs */ + if ((vco_clks_field >= ((si->ps.min_video_vco * 1000000) / fields_sec)) && + (vco_clks_field <= ((si->ps.max_video_vco * 1000000) / fields_sec))) + { + /* iterate trough all valid reference-frequency postscaler settings */ + for (m = 2; m <= m_max; m++) + { + /* calculate VCO postscaler setting for current setup.. */ + n = (int)(((vco_clks_field * m) / ((si->ps.f_ref * 1000000) / fields_sec)) + 0.5); + /* ..and check for validity */ + if ((n < 8) || (n > 128)) continue; + + /* special TVmode stuff starts here (rest is in fact standard): */ + /* calculate number of videoclocks per field */ + calc_pclks_field = + (((uint32)((si->ps.f_ref * 1000000) / fields_sec)) * n) / ((float)(m * p)); + + /* we need a whole number of clocks per field, otherwise it won't work correctly. + * (TVout will flicker, green fields will occur) */ + if (calc_pclks_field != (uint32)calc_pclks_field) continue; + + /* check if we have the min. needed number of clocks per field for a sync lock */ + if (calc_pclks_field < ((*ht_new * (target.timing.v_total - 1)) + 2)) continue; + + /* calc number of clocks we have for the last field line */ + *ht_last_line = calc_pclks_field - (*ht_new * (target.timing.v_total - 1)); + + /* check if we haven't got too much clocks in the last field line for a sync lock */ + if (*ht_last_line > *ht_new) continue; + + /* we have a match! */ + /* calculate the difference between a full line and the last line */ + diff = *ht_new - *ht_last_line; + + /* if this last_line comes closer to a full line than earlier 'hits' then use it */ + if (diff < diff_smallest) + { + /* log results */ + if (diff_smallest == 999999999) + LOG(2,("MAVENTV: MATCH, ")); + else + LOG(2,("MAVENTV: better MATCH,")); + f_vco = (si->ps.f_ref / m) * n; + LOG(2,("found vid VCO freq %fMhz, pixclk %fMhz\n", f_vco, (f_vco / p))); + LOG(2,("MAVENTV: mnp(ex. filter) 0x%02x 0x%02x 0x%02x, h_total %d, ht_lastline %d\n", + (m - 1), (n - 1), (p - 1), (*ht_new - 2), (*ht_last_line - 2))); + + /* remember this best match */ + diff_smallest = diff; + best[0] = m; + best[1] = n; + best[2] = p; + /* h_total to use for this setting: + * exclude the 'calculate clock a bit too high' trick */ + best[3] = *ht_new - 2; + /* ht_last_line to use for this setting: + * exclude the 'calculate clock a bit too high' trick */ + best[4] = *ht_last_line - 2; + } + } + } + } + } + LOG(2,("MAVENTV: search completed.\n")); + + /* setup the scalers programming values for found optimum setting */ + m = best[0] - 1; + n = best[1] - 1; + p = best[2] - 1; + + /* if no match was found set fixed PLL frequency so we have something valid at least */ + if (diff_smallest == 999999999) + { + LOG(4,("MAVENTV: WARNING, no MATCH found!\n")); + + if (si->ps.f_ref == 27.000) + { + /* set 13.5Mhz */ + m = 0x03; + n = 0x07; + p = 0x03; + } + else + { + /* set 14.31818Mhz */ + m = 0x01; + n = 0x07; + p = 0x03; + } + best[3] = target.timing.h_total; + best[4] = target.timing.h_total; + } + + /* calc the needed PLL loopbackfilter setting belonging to current VCO speed */ + f_vco = (si->ps.f_ref / (m + 1)) * (n + 1); + LOG(2,("MAVENTV: using vid VCO frequency %fMhz\n", f_vco)); + + switch(si->ps.card_type) + { + case G100: + case G200: + for(;;) + { + if (f_vco >= 180) {p |= (0x03 << 3); break;}; + if (f_vco >= 140) {p |= (0x02 << 3); break;}; + if (f_vco >= 100) {p |= (0x01 << 3); break;}; + break; + } + break; + default: + for(;;) + { + if (f_vco >= 240) {p |= (0x03 << 3); break;}; + if (f_vco >= 170) {p |= (0x02 << 3); break;}; + if (f_vco >= 110) {p |= (0x01 << 3); break;}; + break; + } + break; + } + + /* return results */ + *m_result = m; + *n_result = n; + *p_result = p; + *ht_new = best[3]; + *ht_last_line = best[4]; + + /* display the found pixelclock values */ + LOG(2,("MAVENTV: vid PLL check: got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n", + (f_vco / ((p & 0x07) + 1)), m, n, p)); + LOG(2,("MAVENTV: new h_total %d, ht_lastline %d\n", *ht_new, *ht_last_line)); + + /* return status */ + if (diff_smallest == 999999999) return B_ERROR; + return B_OK; +} + + /* Notes about timing: + * Note: + * all horizontal timing is measured in pixelclock periods; + * all? vertical timing is measured in field? lines. */ + + /* Note: + * <= G400MAX cards have a fixed 27Mhz(?) clock for TV timing register values, + * while on G450/G550 these need to be calculated based on the video pixelclock. */ + + + /* Notes about signal strengths: + * Note: + * G400 and earlier cards have a fixed reference voltage of +2.6 Volt; + * G450 and G550 cards MAVEN DACs have a switchable ref voltage of +1.5/+2.0 Volt. + * + * This voltage is used to feed the videosignals: + * - Hsync pulse level; + * - Lowest active video output level; + * - Highest active video output level. + * These actual voltages are set via 10bit DACs. + * + * G450/G550: + * The color burst amplitude videosignal is fed by 80% of the above mentioned + * ref. voltage, and is set via an 8bit DAC. + * On G400 and earlier cards the ref. voltage is different, and also differs + * for PAL and NTSC mode. */ + + /* Note: + * Increasing the distance between the highest and lowest active video output + * level increases contrast; decreasing it decreases contrast. */ + + /* Note: + * Increasing both the highest and lowest active video output level with the + * same amount increases brightness; decreasing it decreases brightness. */ + + /* Note: + * Increasing the Hsync pulse level increases the black level, so decreases + * brightness and contrast. */ + +/* Preset maven PAL output (625lines, 50Hz mode) */ +void gxx0_maventv_PAL_init(uint8* buffer) +{ + uint16 value; + + /* Chroma subcarrier divider */ + buffer[0x00] = 0x2A; + buffer[0x01] = 0x09; + buffer[0x02] = 0x8A; + buffer[0x03] = 0xCB; + + buffer[0x04] = 0x00; + buffer[0x05] = 0x00; + buffer[0x06] = 0xF9; + buffer[0x07] = 0x00; + /* Hsync pulse length */ + buffer[0x08] = 0x7E; + /* color burst length */ + buffer[0x09] = 0x44; + /* back porch length */ + buffer[0x0a] = 0x9C; + + /* color burst amplitude */ + if (si->ps.card_type <= G400MAX) + { + buffer[0x0b] = 0x3e; + } + else + { + buffer[0x0b] = 0x48; + } + + buffer[0x0c] = 0x21; + buffer[0x0d] = 0x00; + + if (si->ps.card_type <= G400MAX) + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x0ea; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + else + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x130; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + + buffer[0x12] = 0x1A; + buffer[0x13] = 0x2A; + + /* functional unit */ + buffer[0x14] = 0x1C; + buffer[0x15] = 0x3D; + buffer[0x16] = 0x14; + + /* vertical total */ //(=625) + /* b9-2 */ + buffer[0x17] = 0x9C; + /* b1-0 in b1-0 */ + buffer[0x18] = 0x01; + + buffer[0x19] = 0x00; + buffer[0x1a] = 0xFE; + buffer[0x1b] = 0x7E; + buffer[0x1c] = 0x60; + buffer[0x1d] = 0x05; + + /* Highest active video output level. + * Warning: make sure this stays above the lowest active video output level! */ + if (si->ps.card_type <= G400MAX) + { + value = 0x24f; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + else + { + value = 0x300; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + + /* saturation (field?) #1 */ + if (si->ps.card_type <= G400MAX) + buffer[0x20] = 0x72; + else + buffer[0x20] = 0xA5; + + buffer[0x21] = 0x07; + + /* saturation (field?) #2 */ + if (si->ps.card_type <= G400MAX) + buffer[0x22] = 0x72; + else + buffer[0x22] = 0xA5; + + buffer[0x23] = 0x00; + buffer[0x24] = 0x00; + /* hue? */ + buffer[0x25] = 0x00; + + buffer[0x26] = 0x08; + buffer[0x27] = 0x04; + buffer[0x28] = 0x00; + buffer[0x29] = 0x1A; + + /* functional unit */ + buffer[0x2a] = 0x55; + buffer[0x2b] = 0x01; + + /* front porch length */ + buffer[0x2c] = 0x26; + + /* functional unit */ + buffer[0x2d] = 0x07; + buffer[0x2e] = 0x7E; + + /* functional unit */ + buffer[0x2f] = 0x02; + buffer[0x30] = 0x54; + + /* horizontal visible */ + value = 0x580; + buffer[0x31] = ((value >> 3) & 0xff); + buffer[0x32] = (value & 0x07); + + /* upper blanking (in field lines) */ + buffer[0x33] = 0x14; //=((v_total - v_sync_end)/2) -1 + + buffer[0x34] = 0x49; + buffer[0x35] = 0x00; + buffer[0x36] = 0x00; + buffer[0x37] = 0xA3; + buffer[0x38] = 0xC8; + buffer[0x39] = 0x22; + buffer[0x3a] = 0x02; + buffer[0x3b] = 0x22; + + /* functional unit */ + buffer[0x3c] = 0x3F; + buffer[0x3d] = 0x03; +} + +/* Preset maven NTSC output (525lines, 59.94Hz mode) */ +void gxx0_maventv_NTSC_init(uint8* buffer) +{ + uint16 value; + + /* Chroma subcarrier frequency */ + buffer[0x00] = 0x21; + buffer[0x01] = 0xF0; + buffer[0x02] = 0x7C; + buffer[0x03] = 0x1F; + + buffer[0x04] = 0x00; + buffer[0x05] = 0x00;//b1 = ON enables colorbar testimage + buffer[0x06] = 0xF9;//b0 = ON enables MAVEN TV output + buffer[0x07] = 0x00;//influences the colorburst signal amplitude somehow + + /* Hsync pulse length */ + buffer[0x08] = 0x7E; + /* color burst length */ + buffer[0x09] = 0x43; + /* back porch length */ + buffer[0x0a] = 0x7E; + + /* color burst amplitude */ + if (si->ps.card_type <= G400MAX) + { + buffer[0x0b] = 0x46; + } + else + { + buffer[0x0b] = 0x48; + } + + buffer[0x0c] = 0x00; + buffer[0x0d] = 0x00; + + if (si->ps.card_type <= G400MAX) + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x0ea; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + else + { + /* Lowest active video output level. + * Warning: make sure this stays above (or equals) the sync pulse level! */ + value = 0x130; + buffer[0x0e] = ((value >> 2) & 0xff); + buffer[0x0f] = (value & 0x03); + /* horizontal sync pulse level */ + buffer[0x10] = ((value >> 2) & 0xff); + buffer[0x11] = (value & 0x03); + } + + buffer[0x12] = 0x17; + buffer[0x13] = 0x21; + + /* functional unit */ + buffer[0x14] = 0x1B; + buffer[0x15] = 0x1B; + buffer[0x16] = 0x24; + + /* vertical total */ + /* b9-2 */ + buffer[0x17] = 0x83; + /* b1-0 in b1-0 */ + buffer[0x18] = 0x01; + + buffer[0x19] = 0x00;//mv register? + buffer[0x1a] = 0x0F; + buffer[0x1b] = 0x0F; + buffer[0x1c] = 0x60; + buffer[0x1d] = 0x05; + + /* Highest active video output level. + * Warning: make sure this stays above the lowest active video output level! */ + if (si->ps.card_type <= G400MAX) + { + value = 0x24f; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + else + { + value = 0x300; + buffer[0x1e] = ((value >> 2) & 0xff); + buffer[0x1f] = (value & 0x03); + } + + /* color saturation #1 (Y-B ?) */ + if (si->ps.card_type <= G400MAX) + buffer[0x20] = 0x5F; + else + buffer[0x20] = 0x9C; + + buffer[0x21] = 0x04; + + /* color saturation #2 (Y-R ?) */ + if (si->ps.card_type <= G400MAX) + buffer[0x22] = 0x5F; + else + buffer[0x22] = 0x9C; + + buffer[0x23] = 0x01; + buffer[0x24] = 0x02; + + /* hue: preset at 0 degrees */ + buffer[0x25] = 0x00; + + buffer[0x26] = 0x0A; + buffer[0x27] = 0x05;//sync stuff + buffer[0x28] = 0x00; + buffer[0x29] = 0x10;//field line-length stuff + + /* functional unit */ + buffer[0x2a] = 0xFF; + buffer[0x2b] = 0x03; + + /* front porch length */ + buffer[0x2c] = 0x24; + + /* functional unit */ + buffer[0x2d] = 0x0F; + buffer[0x2e] = 0x78; + + /* functional unit */ + buffer[0x2f] = 0x00; + buffer[0x30] = 0x00; + + /* horizontal visible */ + /* b10-3 */ + buffer[0x31] = 0xB2; + /* b2-0 in b2-0 */ + buffer[0x32] = 0x04; + + /* upper blanking (in field lines) */ + buffer[0x33] = 0x14; + + buffer[0x34] = 0x02;//colorphase or so stuff. + buffer[0x35] = 0x00; + buffer[0x36] = 0x00; + buffer[0x37] = 0xA3; + buffer[0x38] = 0xC8; + buffer[0x39] = 0x15; + buffer[0x3a] = 0x05; + buffer[0x3b] = 0x3B; + + /* functional unit */ + buffer[0x3c] = 0x3C; + buffer[0x3d] = 0x00; +} + +void gx50_maventv_PAL_timing(gx50_maven_timing *m_timing) +{ + /* values are given in picoseconds */ + m_timing->h_total = 64000000; + /* the sum of the signal duration below should match h_total! */ + m_timing->h_display = 52148148; + m_timing->h_sync_length = 4666667; + m_timing->front_porch = 1407407; + m_timing->back_porch = 5777778; + /* colorburst is 'superimposed' on the above timing */ + m_timing->color_burst = 2518518; + /* number of lines per frame */ + m_timing->v_total = 625; + /* color carrier frequency in Mhz */ + m_timing->chroma_subcarrier = 4.43361875; +} + +void gx50_maventv_NTSC_timing(gx50_maven_timing *m_timing) +{ + /* values are given in picoseconds */ + m_timing->h_total = 63555556; + /* the sum of the signal duration below should match h_total! */ + m_timing->h_display = 52888889; + m_timing->h_sync_length = 4666667; + m_timing->front_porch = 1333333; + m_timing->back_porch = 4666667; + /* colorburst is 'superimposed' on the above timing */ + m_timing->color_burst = 2418418; + /* number of lines per frame */ + m_timing->v_total = 525; + /* color carrier frequency in Mhz */ + m_timing->chroma_subcarrier = 3.579545454; +} + +int maventv_init(display_mode target) +{ + uint8 val; + uint8 m_result, n_result, p_result; + unsigned int ht_new, ht_last_line; + float calc_pclk; + /* use a display_mode copy because we might tune it for TVout compatibility */ + display_mode tv_target = target; + /* used as buffer for TVout signal to generate */ + uint8 maventv_regs[64]; + /* used in G450/G550 to calculate TVout signal timing dependant on pixelclock; + * <= G400MAX use fixed settings because base-clock here is the fixed crystal + * frequency. */ + //fixme: if <=G400 cards with MAVEN and crystal of 14.31818Mhz exist, modify!?! + gx50_maven_timing m_timing; + + /* preset new TVout mode */ + if ((tv_target.flags & TV_BITS) == TV_PAL) + { + LOG(4, ("MAVENTV: PAL TVout\n")); + gxx0_maventv_PAL_init(maventv_regs); + gx50_maventv_PAL_timing(&m_timing); + } + else + { + LOG(4, ("MAVENTV: NTSC TVout\n")); + gxx0_maventv_NTSC_init(maventv_regs); + gx50_maventv_NTSC_timing(&m_timing); + } + + /* enter mode-program mode */ + if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x01); + else + { + DXIW(TVO_IDX, MGAMAV_PGM); + DXIW(TVO_DATA, 0x01); + } + + /* tune new TVout mode */ + if (si->ps.card_type <= G400MAX) + { + /* setup TV-mode 'copy' of CRTC2, setup PLL, inputs, outputs and sync-locks */ + MAVW(MONSET, 0x00); + MAVW(MONEN, 0xA2); + + /* xmiscctrl */ + //unknown regs: + MAVWW(WREG_0X8E_L, 0x1EFF); + MAVW(BREG_0XC6, 0x01); + + MAVW(LOCK, 0x01); + MAVW(OUTMODE, 0x08); + MAVW(LUMA, 0x78); + MAVW(STABLE, 0x02); + MAVW(MONEN, 0xB3); + + /* setup video PLL */ + g100_g400max_maventv_vid_pll_find( + tv_target, &ht_new, &ht_last_line, &m_result, &n_result, &p_result); + MAVW(PIXPLLM, m_result); + MAVW(PIXPLLN, n_result); + MAVW(PIXPLLP, (p_result | 0x80)); + + MAVW(MONSET, 0x20); + + MAVW(TEST, 0x10); + + /* htotal - 2 */ + MAVWW(HTOTALL, ht_new); + + /* last line in field can have different length */ + /* hlen - 2 */ + MAVWW(LASTLINEL, ht_last_line); + + /* horizontal vidrst pos: 0 <= vidrst pos <= htotal - 2 */ + MAVWW(HVIDRSTL, (ht_last_line - si->crtc_delay - + (tv_target.timing.h_sync_end - tv_target.timing.h_sync_start))); + //ORG (does the same but with limit checks but these limits should never occur!): +// slen = tv_target.timing.h_sync_end - tv_target.timing.h_sync_start; +// hcrt = tv_target.timing.h_total - slen - si->crtc_delay; +// if (ht_last_line < tv_target.timing.h_total) hcrt += ht_last_line; +// if (hcrt > tv_target.timing.h_total) hcrt -= tv_target.timing.h_total; +// if (hcrt + 2 > tv_target.timing.h_total) hcrt = 0; /* or issue warning? */ +// MAVWW(HVIDRSTL, hcrt); + + /* who knows */ + MAVWW(HSYNCSTRL, 0x0004);//must be 4!! + + /* hblanking end: 100% */ + MAVWW(HSYNCLENL, (tv_target.timing.h_total - tv_target.timing.h_sync_end)); + + /* vertical line count - 1 */ + MAVWW(VTOTALL, (tv_target.timing.v_total - 1)); + + /* vertical vidrst pos */ + MAVWW(VVIDRSTL, (tv_target.timing.v_total - 2)); + + /* something end... [A6]+1..[A8] */ + MAVWW(VSYNCSTRL, 0x0001); + + /* vblanking end: stop vblanking */ + MAVWW(VSYNCLENL, (tv_target.timing.v_sync_end - tv_target.timing.v_sync_start - 1)); + //org: no visible diff: + //MAVWW(VSYNCLENL, (tv_target.timing.v_total - tv_target.timing.v_sync_start - 1)); + + /* something start... 0..[A4]-1 */ + MAVWW(VDISPLAYL, 0x0000); + //std setmode (no visible difference) + //MAVWW(VDISPLAYL, (tv_target.timing.v_total - 1)); + + /* ... */ + MAVWW(WREG_0X98_L, 0x0000); + + /* moves picture up/down and so on... */ + MAVWW(VSOMETHINGL, 0x0001); /* Fix this... 0..VTotal */ + + { + uint32 h_display_tv; + uint8 h_scale_tv; + + unsigned int ib_min_length; + unsigned int ib_length; + int index; + + /* calc hor scale-back factor from input to output picture (in 1.7 format) + * the MAVEN has 736 pixels fixed visible? outputline length for TVout */ + //fixme: shouldn't this be 768 (= PAL 1:1 output 4:3 ratio format)?!? + h_scale_tv = (736 << 7) / tv_target.timing.h_total;//should be PLL corrected + LOG(4,("MAVENTV: horizontal scale-back factor is: %f\n", (h_scale_tv / 128.0))); + + /* limit values to MAVEN capabilities (scale-back factor is 0.5-1.0) */ + //fixme: how about lowres upscaling? + if (h_scale_tv > 0x80) + { + h_scale_tv = 0x80; + LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); + } + if (h_scale_tv < 0x40) + { + h_scale_tv = 0x40; + LOG(4,("MAVENTV: limiting horizontal scale-back factor to: %f\n", (h_scale_tv / 128.0))); + } + /* make sure we get no round-off error artifacts on screen */ + h_scale_tv--; + + /* calc difference in (wanted output picture width (excl. hsync_length)) and + * (fixed total output line length (=768)), + * based on input picture and scaling factor */ + /* (MAVEN trick (part 1) to get output picture width to fit into just 8 bits) */ + h_display_tv = ((768 - 1) << 7) - + (((tv_target.timing.h_total - tv_target.timing.h_sync_end) /* is left margin */ + + tv_target.timing.h_display - 8) + * h_scale_tv); + /* convert result from 25.7 to 32.0 format */ + h_display_tv = h_display_tv >> 7; + LOG(4,("MAVENTV: displaying output on %d picture pixels\n", + ((768 - 1) - h_display_tv))); + + /* half result: MAVEN trick (part 2) + * (258 - 768 pixels, only even number per line is possible) */ + h_display_tv = h_display_tv >> 1; + /* limit value to register contraints */ + if (h_display_tv > 0xFF) h_display_tv = 0xFF; + MAVW(HSCALETV, h_scale_tv); + MAVW(HDISPLAYTV, h_display_tv); + + + /* calculate line inputbuffer length */ + /* It must be between (including): + * ((input picture left margin) + (input picture hor. resolution) + 4) + * AND + * (input picture total line length) (PLL corrected) */ + + /* calculate minimal line input buffer length */ + ib_min_length = ((tv_target.timing.h_total - tv_target.timing.h_sync_end) + + tv_target.timing.h_display + 4); + + /* calculate optimal line input buffer length (so top of picture is OK too) */ + /* The following formula applies: + * optimal buffer length = ((((0x78 * i) - R) / hor. scaling factor) + Q) + * + * where (in 4.8 format!) + * R Qmin Qmax + * 0x0E0 0x5AE 0x5BF + * 0x100 0x5CF 0x5FF + * 0x180 0x653 0x67F + * 0x200 0x6F8 0x6FF + */ + index = 1; + do + { + ib_length = ((((((0x7800 << 7) * index) - (0x100 << 7)) / h_scale_tv) + 0x05E7) >> 8); + index++; + } while (ib_length < ib_min_length); + LOG(4,("MAVENTV: optimal line inputbuffer length: %d\n", ib_length)); + + if (ib_length >= ht_new + 2) + { + ib_length = ib_min_length; + LOG(4,("MAVENTV: limiting line inputbuffer length, setting minimal usable: %d\n", ib_length)); + } + MAVWW(HDISPLAYL, ib_length); + } + + { + uint16 t_scale_tv; + uint32 v_display_tv; + + /* calc total scale-back factor from input to output picture */ + { + uint32 out_clocks; + uint32 in_clocks; + + //takes care of green stripes: + /* calc output clocks per frame */ + out_clocks = m_timing.v_total * (ht_new + 2); + + /* calc input clocks per frame */ + in_clocks = (tv_target.timing.v_total - 1) * (ht_new + 2) + ht_last_line + 2; + + /* calc total scale-back factor from input to output picture in 1.15 format */ + t_scale_tv = ((((uint64)out_clocks) << 15) / in_clocks); + LOG(4,("MAVENTV: total scale-back factor is: %f\n", (t_scale_tv / 32768.0))); + + /* min. scale-back factor is 1.0 for 1:1 output */ + if (t_scale_tv > 0x8000) + { + t_scale_tv = 0x8000; + LOG(4,("MAVENTV: limiting total scale-back factor to: %f\n", (t_scale_tv / 32768.0))); + } + } + + /*calc output picture height based on input picture and scaling factor */ + //warning: v_display was 'one' lower originally! + v_display_tv = + ((tv_target.timing.v_sync_end - tv_target.timing.v_sync_start) /* is sync length */ + + (tv_target.timing.v_total - tv_target.timing.v_sync_end) /* is upper margin */ + + tv_target.timing.v_display) + * t_scale_tv; + /* convert result from 17.15 to 32.0 format */ + v_display_tv = (v_display_tv >> 15); + LOG(4,("MAVENTV: displaying output on %d picture frame-lines\n", v_display_tv)); + + /* half result, and compensate for internal register offset + * (MAVEN trick to get it to fit into just 8 bits). + * (allowed output frame height is 292 - 802 lines, only even numbers) */ + v_display_tv = (v_display_tv >> 1) - 146; + /* limit value to register contraints */ + if (v_display_tv > 0xFF) v_display_tv = 0xFF; + /* make sure we get no round-off error artifacts on screen */ + t_scale_tv--; + + MAVWW(TSCALETVL, t_scale_tv); + MAVW(VDISPLAYTV, v_display_tv); + } + + MAVW(TEST, 0x00); + + /* gamma correction registers */ + MAVW(GAMMA1, 0x00); + MAVW(GAMMA2, 0x00); + MAVW(GAMMA3, 0x00); + MAVW(GAMMA4, 0x1F); + MAVW(GAMMA5, 0x10); + MAVW(GAMMA6, 0x10); + MAVW(GAMMA7, 0x10); + MAVW(GAMMA8, 0x64); /* 100 */ + MAVW(GAMMA9, 0xC8); /* 200 */ + + /* set flickerfilter */ + /* OFF: is dependant on MAVEN chip version(?): MGA_TVO_B = $40, else $00. + * ON : always set $a2. */ + MAVW(FFILTER, 0xa2); + + /* 0x10 or anything ored with it */ + //fixme? linux uses 0x14... + MAVW(TEST, (MAVR(TEST) & 0x10)); + + /* output: SVideo/Composite */ + MAVW(OUTMODE, 0x08); + } + else /* card_type is >= G450 */ + { + //fixme: setup an intermediate buffer if vertical res is different than settings below! + //fixme: setup 2D or 3D engine to do screen_to_screen_scaled_filtered_blit between the buffers + // during vertical retrace! + if ((tv_target.flags & TV_BITS) == TV_PAL) + { + int diff; + + /* defined by the PAL standard */ + tv_target.timing.v_total = m_timing.v_total; + /* we need to center the image on TV vertically. + * note that 576 is the maximum supported resolution for the PAL standard, + * this is already overscanning by approx 8-10% */ + diff = 576 - tv_target.timing.v_display; + /* if we cannot display the current vertical resolution fully, clip it */ + if (diff < 0) + { + tv_target.timing.v_display = 576; + diff = 0; + } + /* now center the image on TV by centering the vertical sync pulse */ + tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); + tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; + } + else + { + int diff; + + /* defined by the NTSC standard */ + tv_target.timing.v_total = m_timing.v_total; + /* we need to center the image on TV vertically. + * note that 480 is the maximum supported resolution for the NTSC standard, + * this is already overscanning by approx 8-10% */ + diff = 480 - tv_target.timing.v_display; + /* if we cannot display the current vertical resolution fully, clip it */ + if (diff < 0) + { + tv_target.timing.v_display = 480; + diff = 0; + } + /* now center the image on TV by centering the vertical sync pulse */ + tv_target.timing.v_sync_start = tv_target.timing.v_display + 1 + (diff / 2); + tv_target.timing.v_sync_end = tv_target.timing.v_sync_start + 1; + } + + /* setup video PLL for G450/G550: + * this can be done in the normal way because the MAVEN works in slave mode! + * NOTE: must be done before programming CRTC2, or interlaced startup may fail. */ + + //fixme: make sure videoPLL is powered up: XPWRCTRL b1=1 + { + uint16 front_porch, back_porch, h_sync_length, burst_length, h_total, h_display; + uint32 chromasc; + uint64 pix_period; + uint16 h_total_wanted, leftover; + + /* calculate tv_h_display in 'half pixelclocks' and adhere to MAVEN restrictions. + * ('half pixelclocks' exist because the MAVEN uses them...) */ + h_display = (((tv_target.timing.h_display << 1) + 3) & ~0x03); + if (h_display > 2044) h_display = 2044; + /* copy result to MAVEN TV mode */ + maventv_regs[0x31] = (h_display >> 3); + maventv_regs[0x32] = (h_display & 0x07); + + /* calculate needed video pixelclock in kHz. + * NOTE: + * The clock calculated is based on MAVEN output, so each pixelclock period + * is in fact a 'half pixelclock' period compared to monitor mode use. */ + tv_target.timing.pixel_clock = + ((((uint64)h_display) * 1000000000) / m_timing.h_display); + + /* tune display_mode adhering to CRTC2 restrictions */ + /* (truncate h_display to 'whole pixelclocks') */ + tv_target.timing.h_display = ((h_display >> 1) & ~0x07); + tv_target.timing.h_sync_start = tv_target.timing.h_display + 8; + + g450_g550_maven_vid_pll_find(tv_target, &calc_pclk, &m_result, &n_result, &p_result, 1); + /* adjust mode to actually used pixelclock */ + tv_target.timing.pixel_clock = (calc_pclk * 1000); + + /* program videoPLL */ + DXIW(VIDPLLM, m_result); + DXIW(VIDPLLN, n_result); + DXIW(VIDPLLP, p_result); + + /* calculate videoclock 'half' period duration in picoseconds */ + pix_period = (1000000000 / ((float)tv_target.timing.pixel_clock)) + 0.5; + LOG(4,("MAVENTV: TV videoclock period is %d picoseconds\n", pix_period)); + + /* calculate number of 'half' clocks per line according to pixelclock set */ + /* fixme: try to setup the modes in such a way that + * (h_total_clk % 16) == 0 because of the CRTC2 restrictions: + * we want to loose the truncating h_total trick below if possible! */ + /* Note: + * This is here so we can see the wanted and calc'd timing difference. */ + h_total_wanted = ((m_timing.h_total / ((float)pix_period)) + 0.5); + LOG(4,("MAVENTV: TV h_total should be %d units\n", h_total_wanted)); + + /* calculate chroma subcarrier value to setup: + * do this as exact as possible because this signal is very sensitive.. */ + chromasc = + ((((uint64)0x100000000) * (m_timing.chroma_subcarrier / calc_pclk)) + 0.5); + /* copy result to MAVEN TV mode */ + maventv_regs[0] = ((chromasc >> 24) & 0xff); + maventv_regs[1] = ((chromasc >> 16) & 0xff); + maventv_regs[2] = ((chromasc >> 8) & 0xff); + maventv_regs[3] = ((chromasc >> 0) & 0xff); + LOG(4,("MAVENTV: TV chroma subcarrier divider set is $%08x\n", chromasc)); + + /* calculate front porch in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + front_porch = ((m_timing.front_porch / ((float)pix_period)) + 1); + /* value must be even */ + front_porch &= ~0x01; + + /* calculate back porch in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + back_porch = ((m_timing.back_porch / ((float)pix_period)) + 1); + /* value must be even */ + back_porch &= ~0x01; + + /* calculate h_sync length in 'half pixelclocks' */ + /* we always round up because of the h_total truncating 'trick' below, + * which works in combination with the existing difference between + * h_total_clk and h_total */ + //fixme: prevent this if possible! + h_sync_length = ((m_timing.h_sync_length / ((float)pix_period)) + 1); + /* value must be even */ + h_sync_length &= ~0x01; + + /* calculate h_total in 'half pixelclocks' */ + h_total = h_display + front_porch + back_porch + h_sync_length; + + LOG(4,("MAVENTV: TV front_porch is %d clocks\n", front_porch)); + LOG(4,("MAVENTV: TV back_porch is %d clocks\n", back_porch)); + LOG(4,("MAVENTV: TV h_sync_length is %d clocks\n", h_sync_length)); + LOG(4,("MAVENTV: TV h_display is %d clocks \n", h_display)); + LOG(4,("MAVENTV: TV h_total is %d clocks\n", h_total)); + + /* calculate color_burst length in 'half pixelclocks' */ + burst_length = (((m_timing.color_burst /*- 1*/) / ((float)pix_period)) + 0.5); + LOG(4,("MAVENTV: TV color_burst is %d clocks.\n", burst_length)); + + /* copy result to MAVEN TV mode */ + maventv_regs[0x09] = burst_length; + + /* Calculate line length 'rest' that remains after truncating + * h_total to adhere to the CRTC2 timing restrictions. */ + leftover = h_total & 0x0F; + /* if some 'rest' exists, we need to compensate for it... */ + /* Note: + * It's much better to prevent this from happening because this + * 'trick' will decay TVout timing! (timing is nolonger official) */ + if (leftover) + { + /* truncate line length to adhere to CRTC2 restrictions */ + front_porch -= leftover; + h_total -= leftover; + + /* now set line length to closest CRTC2 valid match */ + if (leftover < 3) + { + /* 1 <= old rest <= 2: + * Truncated line length is closest match. */ + LOG(4,("MAVENTV: CRTC2 h_total leftover discarded (< 3)\n")); + } + else + { + if (leftover < 10) + { + /* 3 <= old rest <= 9: + * We use the NTSC killer circuitry to get closest match. + * (The 'g400_crtc2_set_timing' routine will enable it + * because of the illegal h_total timing we create here.) */ + front_porch += 4; + h_total += 4; + LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via killer (> 2, < 10)\n")); + } + else + { + /* 10 <= old rest <= 15: + * Set closest valid CRTC2 match. */ + front_porch += 16; + h_total += 16; + LOG(4,("MAVENTV: CRTC2 h_total leftover corrected via increase (> 9, < 16)\n")); + } + } + } + + /* (linux) fixme: maybe MAVEN has requirement 800 < h_total < 1184 */ + maventv_regs[0x2C] = front_porch; + maventv_regs[0x0A] = back_porch; + maventv_regs[0x08] = h_sync_length; + + /* change h_total to represent 'whole pixelclocks' */ + h_total = h_total >> 1; + + /* tune display_mode adhering to CRTC2 restrictions */ + tv_target.timing.h_sync_end = (h_total & ~0x07) - 8; + /* h_total is checked before being programmed! (NTSC killer circuitry) */ + tv_target.timing.h_total = h_total; + } + + /* output Y/C and CVBS signals (| $40 needed for SCART) */ + DXIW(TVO_IDX, 0x80); + DXIW(TVO_DATA, 0x03); + + /* select input colorspace */ + //fixme?: has no effect on output picture on monitor or TV... + //DXIW(TVO_IDX, 0x81); + //DXIW(TVO_DATA, 0x00); + + /* calculate vertical sync point */ + { + int upper; + + /* set 625 lines for PAL or 525 lines for NTSC */ + maventv_regs[0x17] = m_timing.v_total / 4; + maventv_regs[0x18] = m_timing.v_total & 3; + + /* calculate upper blanking range in field lines */ + upper = (m_timing.v_total - tv_target.timing.v_sync_end) >> 1; + + /* blank TVout above the line number calculated */ + maventv_regs[0x33] = upper - 1; + + /* set calculated vertical sync point */ + DXIW(TVO_IDX, 0x82); + DXIW(TVO_DATA, (upper & 0xff)); + DXIW(TVO_IDX, 0x83); + DXIW(TVO_DATA, ((upper >> 8) & 0xff)); + LOG(4,("MAVENTV: TV upper blanking range set is %d\n", upper)); + } + + /* set fized horizontal sync point */ + DXIW(TVO_IDX, 0x84); + DXIW(TVO_DATA, 0x01); + DXIW(TVO_IDX, 0x85); + DXIW(TVO_DATA, 0x00); + + /* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (TVout mode) */ + DXIW(OUTPUTCONN,0x0d); + } + + /* program new TVout mode */ + for (val = 0x00; val <= 0x3D; val++) + { + if (si->ps.card_type <= G400MAX) + { + i2c_maven_write(val, maventv_regs[val]); + } + else + { + DXIW(TVO_IDX, val); + DXIW(TVO_DATA, maventv_regs[val]); + } + } + + /* leave mode-program mode */ + if (si->ps.card_type <= G400MAX) MAVW(PGM, 0x00); + else + { + DXIW(TVO_IDX, MGAMAV_PGM); + DXIW(TVO_DATA, 0x00); + + /* Select 2.0 Volt MAVEN DAC ref. so we have enough contrast/brightness range */ + DXIW(GENIOCTRL, DXIR(GENIOCTRL) | 0x40); + DXIW(GENIODATA, 0x00); + } + + /* setup CRTC2 timing */ + g400_crtc2_set_timing(tv_target); + + /* start whole thing if needed */ + if (si->ps.card_type <= G400MAX) MAVW(RESYNC, 0x20); + + return 0; +} diff --git a/src/add-ons/accelerants/matrox/engine/mga_proto.h b/src/add-ons/accelerants/matrox/engine/mga_proto.h index 84a36dddfc..b5f2da126e 100644 --- a/src/add-ons/accelerants/matrox/engine/mga_proto.h +++ b/src/add-ons/accelerants/matrox/engine/mga_proto.h @@ -4,6 +4,7 @@ status_t mga_set_cas_latency(); status_t gx50_general_output_select(); status_t gx00_general_dac_select(int); status_t gx00_general_wait_retrace(); +status_t gx00_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row); //status_t gx00_general_bios_to_powergraphics(); /* apsed: logging macros */ @@ -35,6 +36,7 @@ status_t pins3_read(uint8 *pins, uint8 length); status_t pins4_read(uint8 *pins, uint8 length); status_t pins5_read(uint8 *pins, uint8 length); void fake_pins(void); +void pinsmil1_fake(void); void pinsmil2_fake(void); void pinsg100_fake(void); void pinsg200_fake(void); @@ -57,22 +59,24 @@ status_t g200_dac_set_sys_pll(); status_t g100_dac_set_sys_pll(); status_t mil2_dac_init(void); -status_t mil2_dac_mode(int,float, int hsync_pos,int vsync_pos, int sync_green); -status_t mil2_dac_palette(uint8*,uint8*,uint8*); -status_t mil2_dac_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *); status_t mil2_dac_set_pix_pll(float f_vco,int bpp); /*MAVEN functions*/ status_t gx00_maven_dpms(uint8,uint8,uint8); -status_t gx00_maven_set_timing( - uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, - uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, - uint8 hsync_pos,uint8 vsync_pos - ); +status_t gx00_maven_set_timing(display_mode target); status_t gx00_maven_mode(int,float); -status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *); -status_t gx00_maven_set_pix_pll(float f_vco); +status_t g100_g400max_maven_vid_pll_find(display_mode target,float * calc_pclk, + uint8 * m_result,uint8 * n_result,uint8 * p_result); +status_t g450_g550_maven_vid_pll_find(display_mode target,float * calc_pclk, + uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test); +status_t gx00_maven_set_vid_pll(display_mode target); + +/*MAVENTV functions*/ +status_t g100_g400max_maventv_vid_pll_find( + display_mode target, unsigned int * ht_new, unsigned int * ht_last_line, + uint8 * m_result, uint8 * n_result, uint8 * p_result); +int maventv_init(display_mode target); /*CRTC1 functions*/ status_t gx00_crtc_validate_timing( @@ -86,7 +90,7 @@ status_t gx00_crtc_set_timing( ); status_t gx00_crtc_depth(int mode); status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp); -status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp); +status_t gx00_crtc_set_display_pitch(); status_t gx00_crtc_dpms(uint8,uint8,uint8); status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*); @@ -100,24 +104,23 @@ status_t gx00_crtc_cursor_hide(); /*CRTC2 functions*/ /*XXX - validate_timing*/ -status_t g400_crtc2_set_timing( - uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal, - uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal, - uint8 hsync_pos,uint8 vsync_pos - ); +status_t g400_crtc2_set_timing(display_mode target); status_t g400_crtc2_depth(int mode); -status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp); +status_t g400_crtc2_set_display_pitch(); status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp); status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v); status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v); /*acceleration functions*/ +status_t check_acc_capability(uint32 feature); status_t gx00_acc_init(); status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col); status_t gx00_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 ); status_t gx00_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32); +status_t gx00_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, + uint16 xd,uint16 yd,uint16 wd,uint16 hd); status_t gx00_acc_wait_idle(); /*backend scaler functions*/ diff --git a/src/add-ons/accelerants/matrox/engine/tvp3026.c b/src/add-ons/accelerants/matrox/engine/tvp3026.c index 9588b7e834..eb980e1f38 100644 --- a/src/add-ons/accelerants/matrox/engine/tvp3026.c +++ b/src/add-ons/accelerants/matrox/engine/tvp3026.c @@ -2,10 +2,9 @@ Program the Texas TVP3026 using Texas Instrument TVP3026 manual SLA098B July 1996 - Author: - Apsed May 2002 a lot of time after ... - - NB BPP24 and BPP32DIR not tested + Authors: + Apsed May 2002 plus a lot of time after; + Rudolf Cornelissen 3/2003. */ #define MODULE_BIT 0x00010000 @@ -13,76 +12,12 @@ #include // system_time, snooze #include "mga_std.h" -#define PIXEL_BUS_WIDTH64 0 // if 0: 32 bits width, else 64 -#define PIXEL_BUS_WIDTH64 1 // if 0: 32 bits width, else 64 - -#define FPLL_REF 14.31818 // MHz -#define FVCO_MAX 220.00000 // MHz, may be 220 or 250, see 3.5 #define FVCO_MIN 110.00000 // MHz #define FPLL_MCLK 100.00000 // MHz +//r: ?? #define MGAVGA_INSTS0 0x1FC2 -// access the TVP3026, this is near G200 DAC but ... - -/* direct registers */ -#define TVP_PALWTADD 0x3c00 -#define TVP_PALDATA 0x3c01 -#define TVP_PIXRDMSK 0x3c02 -#define TVP_PALRDADD 0x3c03 -#define TVP_CUROVRWTADD 0x3c04 -#define TVP_CUROVRDATA 0x3c05 -#define TVP_CUROVRRDADD 0x3c07 -#define TVP_DIRCURCTRL 0x3c09 -#define TVP_X_DATAREG 0x3c0a -#define TVP_CURRAMDATA 0x3c0b -#define TVP_CURPOSXL 0x3c0c -#define TVP_CURPOSXH 0x3c0d -#define TVP_CURPOSYL 0x3c0e -#define TVP_CURPOSYH 0x3c0f - -/* indirect registers */ -#define TVPI_SILICONREV 0x01 -#define TVPI_INDCURCTRL 0x06 -#define TVPI_LATCHCTRL 0x0f -#define TVPI_TCOLCTRL 0x18 -#define TVPI_MULCTRL 0x19 -#define TVPI_CLOCKSEL 0x1a -#define TVPI_PALPAGE 0x1c -#define TVPI_GENCTRL 0x1d -#define TVPI_MISCCTRL 0x1e -#define TVPI_GENIOCTRL 0x2a -#define TVPI_GENIODATA 0x2b -#define TVPI_PLLADDR 0x2c -#define TVPI_PIXPLLDATA 0x2d -#define TVPI_MEMPLLDATA 0x2e -#define TVPI_LOOPLLDATA 0x2f -#define TVPI_COLKEYOL 0x30 -#define TVPI_COLKEYOH 0x31 -#define TVPI_COLKEYRL 0x32 -#define TVPI_COLKEYRH 0x33 -#define TVPI_COLKEYGL 0x34 -#define TVPI_COLKEYGH 0x35 -#define TVPI_COLKEYBL 0x36 -#define TVPI_COLKEYBH 0x37 -#define TVPI_COLKEYCTRL 0x38 -#define TVPI_MEMCLKCTRL 0x39 -#define TVPI_SENSETEST 0x3a -#define TVPI_TESTMODEDATA 0x3b -#define TVPI_CRCREML 0x3c -#define TVPI_CRCREMH 0x3d -#define TVPI_CRCBITSEL 0x3e -#define TVPI_ID 0x3f -#define TVPI_RESET 0xff - -/*read and write from the TVP3026 registers*/ -#define TVPR(A) (MGA_REG8(TVP_##A)) -#define TVPW(A,B) (MGA_REG8(TVP_##A)=B) - -/*read and write from the TVP3026 indirect register*/ -#define TVPIR(A) (TVPW(PALWTADD,TVPI_##A),TVPR(X_DATAREG)) -#define TVPIW(A,B) (TVPW(PALWTADD,TVPI_##A),TVPW(X_DATAREG,B)) - #define WAIT_FOR_PLL_LOCK( pll, on_error) do { \ bigtime_t start, now; \ float delay; \ @@ -90,7 +25,7 @@ \ start = system_time(); \ for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \ - int status = TVPIR (pll ## PLLDATA); \ + int status = DXIR (pll ## PLLDATA); \ if (status & 0x40) break; \ /* snooze(10); */ \ } \ @@ -103,369 +38,6 @@ } \ } while (0) -#define REREAD_PLL( pll) do { \ - uint8 n, m, p; \ - float f, vco; \ - \ - TVPIW(PLLADDR, 0x00); \ - n = TVPIR(pll ## PLLDATA); \ - TVPIW(PLLADDR, 0x15); \ - m = TVPIR(pll ## PLLDATA); \ - TVPIW(PLLADDR, 0x2a); \ - p = TVPIR(pll ## PLLDATA); \ - vco = 8 * FPLL_REF * (65 - (m & 0x3f)) / (65 - (n & 0x3f)); \ - f = vco / (1 << (p & 0x03)); \ - LOG(2,("mil2 reread %s PLL, nmp 0x%02x 0x%02x 0x%02x, %fMHz, vco %fMHz\n", \ - #pll, n, m, p, f, vco)); \ -} while (0) - -#define DUMP_CFG(reg) MSG(( \ - "PCI CONFIG register 0x%04x %20s 0x%08x\n", MGACFG_##reg, #reg, CFGR(reg))) -#define DUMP_VGA(reg) MSG(( \ - "MGA VGA register 0x%04x %20s 0x%02x\n", MGAVGA_##reg, #reg, VGAR(reg))) -#define DUMP_VGA_ATTR(reg) MSG(( \ - "MGA VGA ATTR register 0x%04x %20s 0x%02x\n", 0x##reg, "ATTR" #reg, VGAR_I(ATTR, 0x##reg))) -#define DUMP_VGA_SEQ(reg) MSG(( \ - "MGA VGA SEQ register 0x%04x %20s 0x%02x\n", 0x##reg, "SEQ" #reg, VGAR_I(SEQ, 0x##reg))) -#define DUMP_VGA_GCTL(reg) MSG(( \ - "MGA VGA GCTL register 0x%04x %20s 0x%02x\n", 0x##reg, "GCTL" #reg, VGAR_I(GCTL, 0x##reg))) -#define DUMP_VGA_CRTC(reg) MSG(( \ - "MGA VGA CRTC register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTC" #reg, VGAR_I(CRTC, 0x##reg))) -#define DUMP_VGA_CRTCEXT(reg) MSG(( \ - "MGA VGA CRTCEXT register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTCEXT" #reg, VGAR_I(CRTCEXT, 0x##reg))) -#define DUMP_TVP(reg) MSG(( \ - "TVP3028 register 0x%04x %20s 0x%02x\n", TVP_##reg, #reg, TVPR(reg))) -#define DUMP_TVPI(reg) MSG(( \ - "TVP3028 INDIRECT register 0x%04x %20s 0x%02x\n", TVPI_##reg, #reg, TVPIR(reg))) -#define DUMP_MGA(reg) MSG(( \ - "MGA register 0x%04x %20s 0x%08x\n", MGAACC_##reg, #reg, ACCR(reg))) - -static void dump_tvp3026 (void) -{ - /* TVP3026 DAC direct registers */ -// DUMP_TVP (PALWTADD); -// DUMP_TVP (PALDATA ); - DUMP_TVP (PIXRDMSK); -// DUMP_TVP (PALRDADD); - DUMP_TVP (CUROVRWTADD); - DUMP_TVP (CUROVRDATA); - DUMP_TVP (CUROVRRDADD); - DUMP_TVP (DIRCURCTRL); -// DUMP_TVP (X_DATAREG); - DUMP_TVP (CURRAMDATA); - DUMP_TVP (CURPOSXL); - DUMP_TVP (CURPOSXH); - DUMP_TVP (CURPOSYL); - DUMP_TVP (CURPOSYH); - - /* TVP3026 DAC indirect registers */ - DUMP_TVPI (SILICONREV); - DUMP_TVPI (INDCURCTRL); - DUMP_TVPI (LATCHCTRL); - DUMP_TVPI (TCOLCTRL); - DUMP_TVPI (MULCTRL); - DUMP_TVPI (CLOCKSEL); - DUMP_TVPI (PALPAGE); - DUMP_TVPI (GENCTRL); - DUMP_TVPI (MISCCTRL); - DUMP_TVPI (GENIOCTRL); - DUMP_TVPI (GENIODATA); -// DUMP_TVPI (PLLADDR); -// DUMP_TVPI (PIXPLLDATA); -// DUMP_TVPI (MEMPLLDATA); -// DUMP_TVPI (LOOPLLDATA); - REREAD_PLL (PIX); - REREAD_PLL (MEM); - REREAD_PLL (LOO); - DUMP_TVPI (COLKEYOL); - DUMP_TVPI (COLKEYOH); - DUMP_TVPI (COLKEYRL); - DUMP_TVPI (COLKEYRH); - DUMP_TVPI (COLKEYGL); - DUMP_TVPI (COLKEYGH); - DUMP_TVPI (COLKEYBL); - DUMP_TVPI (COLKEYBH); - DUMP_TVPI (COLKEYCTRL); - DUMP_TVPI (MEMCLKCTRL); - DUMP_TVPI (SENSETEST); - DUMP_TVPI (TESTMODEDATA); - DUMP_TVPI (CRCREML); - DUMP_TVPI (CRCREMH); -// DUMP_TVPI (CRCBITSEL); // WO - DUMP_TVPI (ID); -// DUMP_TVPI (RESET); // WO -} - -static void dump_mil2 (void) -{ - /* PCI_config_space */ - DUMP_CFG (DEVID); - DUMP_CFG (DEVCTRL); - DUMP_CFG (CLASS); - DUMP_CFG (HEADER); - DUMP_CFG (MGABASE2); - DUMP_CFG (MGABASE1); - DUMP_CFG (MGABASE3); - DUMP_CFG (SUBSYSIDR); - DUMP_CFG (ROMBASE); - DUMP_CFG (CAP_PTR); - DUMP_CFG (INTCTRL); - DUMP_CFG (OPTION); - DUMP_CFG (MGA_INDEX); - DUMP_CFG (MGA_DATA); - DUMP_CFG (SUBSYSIDW); - DUMP_CFG (AGP_IDENT); - DUMP_CFG (AGP_STS); - DUMP_CFG (AGP_CMD); - - /*VGA registers - these are byte wide*/ -// DUMP_VGA (ATTR_I); -// DUMP_VGA (ATTR_D); - DUMP_VGA_ATTR (0); - DUMP_VGA_ATTR (1); - DUMP_VGA_ATTR (3); - DUMP_VGA_ATTR (3); - DUMP_VGA_ATTR (4); - DUMP_VGA_ATTR (5); - DUMP_VGA_ATTR (6); - DUMP_VGA_ATTR (7); - DUMP_VGA_ATTR (8); - DUMP_VGA_ATTR (9); - DUMP_VGA_ATTR (A); - DUMP_VGA_ATTR (B); - DUMP_VGA_ATTR (C); - DUMP_VGA_ATTR (D); - DUMP_VGA_ATTR (E); - DUMP_VGA_ATTR (F); - DUMP_VGA_ATTR (10); - DUMP_VGA_ATTR (11); - DUMP_VGA_ATTR (12); - DUMP_VGA_ATTR (13); - DUMP_VGA_ATTR (14); -// DUMP_VGA (CRTC_I); -// DUMP_VGA (CRTC_D); - DUMP_VGA_CRTC (0); - DUMP_VGA_CRTC (1); - DUMP_VGA_CRTC (2); - DUMP_VGA_CRTC (3); - DUMP_VGA_CRTC (4); - DUMP_VGA_CRTC (5); - DUMP_VGA_CRTC (6); - DUMP_VGA_CRTC (7); - DUMP_VGA_CRTC (8); - DUMP_VGA_CRTC (9); - DUMP_VGA_CRTC (A); - DUMP_VGA_CRTC (B); - DUMP_VGA_CRTC (C); - DUMP_VGA_CRTC (D); - DUMP_VGA_CRTC (E); - DUMP_VGA_CRTC (F); - DUMP_VGA_CRTC (10); - DUMP_VGA_CRTC (11); - DUMP_VGA_CRTC (12); - DUMP_VGA_CRTC (13); - DUMP_VGA_CRTC (14); - DUMP_VGA_CRTC (15); - DUMP_VGA_CRTC (16); - DUMP_VGA_CRTC (17); - DUMP_VGA_CRTC (18); - DUMP_VGA_CRTC (22); - DUMP_VGA_CRTC (24); - DUMP_VGA_CRTC (26); -// DUMP_VGA (CRTCEXT_I); -// DUMP_VGA (CRTCEXT_D); - DUMP_VGA_CRTCEXT (0); - DUMP_VGA_CRTCEXT (1); - DUMP_VGA_CRTCEXT (2); - DUMP_VGA_CRTCEXT (3); - DUMP_VGA_CRTCEXT (4); - DUMP_VGA_CRTCEXT (5); - DUMP_VGA (DACSTAT); -// DUMP_VGA (FEATW); - DUMP_VGA (FEATR); -// DUMP_VGA (GCTL_I); -// DUMP_VGA (GCTL_D); - DUMP_VGA_GCTL (0); - DUMP_VGA_GCTL (1); - DUMP_VGA_GCTL (2); - DUMP_VGA_GCTL (3); - DUMP_VGA_GCTL (4); - DUMP_VGA_GCTL (5); - DUMP_VGA_GCTL (6); - DUMP_VGA_GCTL (7); - DUMP_VGA_GCTL (8); - DUMP_VGA (INSTS0); - DUMP_VGA (INSTS1); - DUMP_VGA (MISCR); - DUMP_VGA (MISCW); -// DUMP_VGA (SEQ_I); -// DUMP_VGA (SEQ_D); - DUMP_VGA_SEQ (0); - DUMP_VGA_SEQ (1); - DUMP_VGA_SEQ (2); - DUMP_VGA_SEQ (3); - DUMP_VGA_SEQ (4); - - /* MGA registers, only the readable*/ - DUMP_MGA (IEN); - DUMP_MGA (RST); - DUMP_MGA (OPMODE); - DUMP_MGA (STATUS); - - /* TVP3026 registers */ - dump_tvp3026(); -} - -/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ -status_t mil2_dac_mode (int mode, float brightness, int hsync_pos, int vsync_pos, int sync_green) -{ - uint8 *r, *g, *b, t[64]; - int i; - uint8 miscctrl = 0, latchctrl = 0; - uint8 tcolctrl = 0, mulctrl = 0; - - LOG(4,("TVP:Setting screen mode %d brightness %f\n", mode, brightness)); - if (si->settings.logmask & 0x80000000) dump_tvp3026(); - - /*set colour arrays to point to space reserved in shared info*/ - r = si->color_data; - g = r + 256; - b = g + 256; - - /*init a basic palette for brightness specified*/ -brightness = 2.0; // TODO - for (i=0;i<256;i++) { - int ri = i*brightness; - if (ri > 255) ri = 255; - r[i]=ri; - } - - /*modify the palette for the specified mode (&validate mode)*/ - switch(mode) { - case BPP8: - case BPP24:case BPP32: - for (i=0;i<256;i++) b[i]=g[i]=r[i]; - break; - case BPP16: - for (i=0;i<64;i++) t[i]=r[i<<2]; - for (i=0;i<64;i++) g[i]=t[i]; - for (i=0;i<32;i++) b[i]=r[i]=t[i<<1]; - break; - case BPP15: - for (i=0;i<32;i++) t[i]=r[i<<3]; - for (i=0;i<32;i++) g[i]=r[i]=b[i]=t[i]; - break; - case BPP32DIR: - break; - default: - LOG(8,("TVP:Invalid bit depth requested\n")); - return B_ERROR; - break; - } - - if (mil2_dac_palette (r, g, b) != B_OK) return B_ERROR; - - // set the mode - switch (mode) { // mulctrl for PIXEL_BUS_WIDTH 32 - case BPP8: miscctrl=0x0c; latchctrl=0x06; tcolctrl=0x80; mulctrl=0x4b; break; - case BPP15: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x04; mulctrl=0x53; break; - case BPP16: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x05; mulctrl=0x53; break; - case BPP24: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x1f; mulctrl=0x5b; break; - case BPP32: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break; - case BPP32DIR: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break; - } - if (PIXEL_BUS_WIDTH64) mulctrl += 1; - TVPIW(MISCCTRL,(TVPIR(MISCCTRL) & 0xd3) | miscctrl); - TVPIW(LATCHCTRL, latchctrl); - TVPIW(TCOLCTRL, tcolctrl); - TVPIW(MULCTRL, mulctrl); - - // synchros - TVPIW (GENCTRL, (TVPIR (GENCTRL) & 0xdc) - | (sync_green? 0x00:0x20) // apsed TODO ? - | (vsync_pos? 0x00:0x02) - | (hsync_pos? 0x00:0x01)); - -//VGAW (MISCW, VGAR(MISCR) & 0x3f); // TODO -//TVPIW (GENCTRL, TVPIR (GENCTRL) & 0xdf); // TODO - - LOG(2,("TVP: clocksel 0x%02x, miscctrl 0x%02x\n", - TVPIR(CLOCKSEL), TVPIR(MISCCTRL))); - LOG(2,("TVP: tcolctrl 0x%02x, mulctrl 0x%02x, pixrdmsk 0x%02x, genctrl 0x%02x\n", - TVPIR(TCOLCTRL), TVPIR(MULCTRL), TVPR(PIXRDMSK), TVPIR (GENCTRL))); - return B_OK; -} - -// program the palette using the given r,g,b values -status_t mil2_dac_palette (uint8 r[256], uint8 g[256], uint8 b[256]) -{ - int i; - - LOG(4,("TVP: setting palette\n")); - - /*clear palwtadd to start programming*/ - TVPW(PALWTADD,0); - - /*loop through all 256 to program LUT*/ - for (i=0;i<256;i++) { - TVPW(PALDATA,r[i]); - TVPW(PALDATA,g[i]); - TVPW(PALDATA,b[i]); - } - if (TVPR(PALWTADD)!=0) { - LOG(8,("TVP: PALWTADD is not 0 after programming\n")); - return B_ERROR; - } -if (0) { // apsed: reread LUT - uint8 R, G, B; - TVPW(PALRDADD,0); - for (i=0;i<256;i++) { - R = TVPR(PALDATA); - G = TVPR(PALDATA); - B = TVPR(PALDATA); - if ((r[i] != R) || (g[i] != G) || (b[i] != B)) { - LOG(8,("TVP: palette 0x%02x: w %02x %02x %02x, r %02x %02x %02x\n", - i, r[i], g[i], b[i], R, G, B)); - } - } -} - return B_OK; -} - -// find nearest valid pll parameters, TVP3026 2.4.1 -status_t mil2_dac_pix_pll_find (float f_need, float *f_result, uint8 *m_result, uint8 *n_result, uint8 *p_result) -{ - int m, n, p; - float error, best, best_vco; - float f_vco, f_pll; - - LOG(0,("mil2_dac_pix_pll_find for %fMHz\n", f_need)); - best = 999999999; - // stupid implementation of 2.4.1 and 2.4.2 - for (m = 1; m <= 62; m++) { - for (n = 40; n <= 62; n++) { - f_vco = (8.0 * FPLL_REF * (65 - m)) / (65 - n); - if ((f_vco < FVCO_MIN) || (f_vco >= FVCO_MAX)) continue; - for (p = 0; p <= 3; p++) { - f_pll = f_vco / (float)(1 << p); - error = fabs (f_need - f_pll) / f_need; - if (error > best) continue; - best = error; - best_vco = f_vco; - *f_result = f_pll; - *m_result = m; - *n_result = n; - *p_result = p; - LOG (0,("mil2_dac_pix_pll_find nmp %fMHz %fMHz 0x%02x 0x%02x 0x%02x\n", - f_pll, f_vco, *n_result, *m_result, *p_result)); - } - } - } - LOG(0,("mil2_dac_pix_pll_find requested %fMHz got %fMHz, vco %fMHz, nmp 0x%02x 0x%02x 0x%02x\n", - f_need, *f_result, best_vco, *n_result, *m_result, *p_result)); - return B_OK; -} - /*program the pixpll - frequency in MHz*/ status_t mil2_dac_set_pix_pll (float f_need, int bpp) { @@ -474,39 +46,41 @@ status_t mil2_dac_set_pix_pll (float f_need, int bpp) float fd; status_t result; + display_mode target; + target.timing.pixel_clock = (f_need * 1000); + LOG(4,("mil2_dac_set_pix_pll need %fMHz, %dbpp\n", f_need, bpp)); - result = mil2_dac_pix_pll_find(f_need,&fd,&m,&n,&p); + result = gx00_dac_pix_pll_find(target, &fd, &m, &n, &p, 0); if (result != B_OK) return result; - LOG(2,("mil2_dac_set_pix_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n", - f_need, fd, n, m, p)); // follows (!strictly) Appendix C, extended mode setup // 1st stop the PLLs, switch (bpp) { - case 8: TVPIW(CLOCKSEL, 0x25); break; - case 16: TVPIW(CLOCKSEL, 0x15); break; - case 24: TVPIW(CLOCKSEL, 0x25); break; - case 32: TVPIW(CLOCKSEL, 0x05); break; + case 8: DXIW(TVP_CLOCKSEL, 0x25); break; + case 16: DXIW(TVP_CLOCKSEL, 0x15); break; + case 24: DXIW(TVP_CLOCKSEL, 0x25); break; + case 32: DXIW(TVP_CLOCKSEL, 0x05); break; default: return B_ERROR; } - TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... - TVPIW(LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL - TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL + DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... + DXIW(TVP_LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL + DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x // 2nd setup the pixel PLL LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n", n, m, p)); - TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... - TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... - TVPIW(PIXPLLDATA, m); - TVPIW(PIXPLLDATA, p | 0xb0); - WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock - if (1) REREAD_PLL (PIX); + DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ... + DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... + DXIW(TVP_PIXPLLDATA, m); + DXIW(TVP_PIXPLLDATA, p | 0xb0); + WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock // now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1 k = 1; // ?? external division factor between RCLK and LCLK - n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp); +// does 32bit DAC path exists for MIL1/2? if so, do this via si->ps... +// n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp); + n = (65 - (4 * 64) / bpp); m = 61; z = (FVCO_MIN * (65 - n)) / (4 * fd * k); q = 0; @@ -520,19 +94,18 @@ status_t mil2_dac_set_pix_pll (float f_need, int bpp) } LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n", n, m, p, q)); - TVPIW(MEMCLKCTRL, (TVPIR(MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13 + DXIW(TVP_MEMCLKCTRL, (DXIR(TVP_MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13 LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n", n, m, p, q)); // now setup the loop PLL LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n", n, m, p, q)); - TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... - TVPIW(LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ... - TVPIW(LOOPLLDATA, m); - TVPIW(LOOPLLDATA, p | 0xf0); - WAIT_FOR_PLL_LOCK (LOO, return B_ERROR); // ... wait for PLL lock - if (1) REREAD_PLL (LOO); + DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ... + DXIW(TVP_LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ... + DXIW(TVP_LOOPLLDATA, m); + DXIW(TVP_LOOPLLDATA, p | 0xf0); + WAIT_FOR_PLL_LOCK (TVP_LOO, return B_ERROR); // ... wait for PLL lock return B_OK; } @@ -544,68 +117,63 @@ static status_t mil2_dac_set_mem_pll (float f_need, float *mclk) uint8 n, m, p; uint8 n_pix, m_pix, p_pix; uint8 memclkctrl; + + display_mode target; + target.timing.pixel_clock = (f_need * 1000); - status = mil2_dac_pix_pll_find (f_need, mclk, &m, &n, &p); + LOG(4,("mil2_dac_set_sys_pll need %fMHz\n", f_need)); + //fixme: MIL has same restrictions for pixel and system PLL, so Apsed did this: + status = gx00_dac_pix_pll_find(target, mclk, &m, &n, &p, 0); if (status != B_OK) return status; - LOG(2,("mil2_dac_set_mem_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n", - f_need, *mclk, n, m, p)); // follows (!strictly) TVP3026 2.4.2.1, extended mode setup // 0) save PIXPLL nmp to restore it at end - TVPIW(PLLADDR, 0x00); - n_pix = TVPIR(PIXPLLDATA); - TVPIW(PLLADDR, 0x15); - m_pix = TVPIR(PIXPLLDATA); - TVPIW(PLLADDR, 0x2a); - p_pix = TVPIR(PIXPLLDATA); - if (1) REREAD_PLL (PIX); + DXIW(TVP_PLLADDR, 0x00); + n_pix = DXIR(TVP_PIXPLLDATA); + DXIW(TVP_PLLADDR, 0x15); + m_pix = DXIR(TVP_PIXPLLDATA); + DXIW(TVP_PLLADDR, 0x2a); + p_pix = DXIR(TVP_PIXPLLDATA); // 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock - TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... - TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL - TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... - TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... - TVPIW(PIXPLLDATA, m); - TVPIW(PIXPLLDATA, p | 0xb0); - WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock - if (1) REREAD_PLL (PIX); + DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... + DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL + DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ... + DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... + DXIW(TVP_PIXPLLDATA, m); + DXIW(TVP_PIXPLLDATA, p | 0xb0); + WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock // 2) select pixel clock as dot clock source VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x // 3) output dot clock on MCLK pin - memclkctrl = TVPIR(MEMCLKCTRL) & 0xe7; - TVPIW(MEMCLKCTRL, memclkctrl | (0x00 << 3)); - TVPIW(MEMCLKCTRL, memclkctrl | (0x01 << 3)); + memclkctrl = DXIR(TVP_MEMCLKCTRL) & 0xe7; + DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x00 << 3)); + DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x01 << 3)); // 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock - if (1) REREAD_PLL (MEM); - TVPIW(PLLADDR, 0x2a); - TVPIW(MEMPLLDATA, 0x00); - TVPIW(PLLADDR, 0x00); - TVPIW(MEMPLLDATA, n | 0xc0); - TVPIW(MEMPLLDATA, m); - TVPIW(MEMPLLDATA, p | 0xb0); - WAIT_FOR_PLL_LOCK (MEM, return B_ERROR); - if (1) REREAD_PLL (MEM); + DXIW(TVP_PLLADDR, 0x2a); + DXIW(TVP_MEMPLLDATA, 0x00); + DXIW(TVP_PLLADDR, 0x00); + DXIW(TVP_MEMPLLDATA, n | 0xc0); + DXIW(TVP_MEMPLLDATA, m); + DXIW(TVP_MEMPLLDATA, p | 0xb0); + WAIT_FOR_PLL_LOCK (TVP_MEM, return B_ERROR); // 5) output mem clock on MCLK pin - TVPIW(MEMCLKCTRL, memclkctrl | (0x02 << 3)); - TVPIW(MEMCLKCTRL, memclkctrl | (0x03 << 3)); + DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x02 << 3)); + DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x03 << 3)); // 6) restaure pixel clock as it was - TVPIW(PLLADDR, 0x2a); - TVPIW(PIXPLLDATA, 0x00); - TVPIW(PLLADDR, 0x00); -// TVPIW(PIXPLLDATA, n_pix); -// TVPIW(PIXPLLDATA, m_pix); -// TVPIW(PIXPLLDATA, p_pix); - TVPIW(PIXPLLDATA, n_pix | 0xc0); - TVPIW(PIXPLLDATA, m_pix); - TVPIW(PIXPLLDATA, p_pix | 0xb0); - WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); - if (1) REREAD_PLL (PIX); + DXIW(TVP_PLLADDR, 0x2a); + DXIW(TVP_PIXPLLDATA, 0x00); + DXIW(TVP_PLLADDR, 0x00); + DXIW(TVP_PIXPLLDATA, n_pix | 0xc0); + DXIW(TVP_PIXPLLDATA, m_pix); + DXIW(TVP_PIXPLLDATA, p_pix | 0xb0); + WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); return B_OK; } @@ -619,8 +187,6 @@ status_t mil2_dac_init (void) uint32 option; uint32 rfhcnt, nogscale, memconfig; - dump_mil2(); - LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR))); CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!) VGAW_I(CRTC,0x11,0); // allow me to change CRTC @@ -658,11 +224,12 @@ rfhcnt_found: LOG(2,("mil2_dac_init: found refresh count %d nogscale %d for %fMHz\n", rfhcnt, nogscale, mclk)); - memconfig = 0x00; // 32 bits RAMDAC - memconfig = 0x01; // 64 bits RAMDAC + memconfig = 0x01; // worst case scenario: 64 bits RAMDAC (= tvp3026m) with >2Mb RAM. option = CFGR(OPTION) & 0xffd0cfff; CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12)); LOG(2,("mil2_dac_init: OPTION 0x%08x\n", CFGR(OPTION))); - + + //r: select indirect cursor control register and set defaults + DXIW(CURCTRL, 0x00); return B_OK; }