openBeOS_Matrox_V0.14_src

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5541 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2003-12-02 22:05:11 +00:00
parent a0d81e7674
commit b408aaf70a
23 changed files with 3743 additions and 2390 deletions
@@ -5,7 +5,7 @@
Other authors: Other authors:
Mark Watson; Mark Watson;
Apsed; Apsed;
Rudolf Cornelissen 10/2002. Rudolf Cornelissen 10/2002-4/2003.
*/ */
#ifndef DRIVERINTERFACE_H #ifndef DRIVERINTERFACE_H
@@ -87,6 +87,7 @@ typedef struct settings { // apsed, see comments in mga.settings
uint32 memory; uint32 memory;
bool usebios; bool usebios;
bool hardcursor; bool hardcursor;
bool greensync;
} settings; } settings;
/*shared info*/ /*shared info*/
@@ -142,10 +143,15 @@ typedef struct {
uint8 color_data[3 * 256]; /* Colour lookup table - as used by DAC */ uint8 color_data[3 * 256]; /* Colour lookup table - as used by DAC */
/*more display mode stuff*/ /*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 - 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*/ /*acceleration engine*/
struct { struct {
@@ -157,7 +163,7 @@ typedef struct {
/* card info - information gathered from PINS (and other sources) */ /* card info - information gathered from PINS (and other sources) */
enum enum
{ // card_type in order of date of MGA chip design { // card_type in order of date of MGA chip design
MILL=0, MIL1 = 0,
MYST, MYST,
MIL2, MIL2,
G100, G100,
+65 -11
View File
@@ -45,7 +45,38 @@
#define MGAVGA_CRTCEXT_I 0x1FDE #define MGAVGA_CRTCEXT_I 0x1FDE
#define MGAVGA_CRTCEXT_D 0x1FDF #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_PALWTADD 0x3C00
#define MGADAC_PALDATA 0x3C01 #define MGADAC_PALDATA 0x3C01
#define MGADAC_PIXRDMSK 0x3C02 #define MGADAC_PIXRDMSK 0x3C02
@@ -56,7 +87,7 @@
#define MGADAC_CURSPOSYL 0x3C0E #define MGADAC_CURSPOSYL 0x3C0E
#define MGADAC_CURSPOSYH 0x3C0F #define MGADAC_CURSPOSYH 0x3C0F
/*(D)AC (X) (I)ndexed registers (>= g100) */ /* (D)AC (X) (I)ndexed registers (>= G100) */
#define MGADXI_CURADDL 0x04 #define MGADXI_CURADDL 0x04
#define MGADXI_CURADDH 0x05 #define MGADXI_CURADDH 0x05
#define MGADXI_CURCTRL 0x06 #define MGADXI_CURCTRL 0x06
@@ -101,7 +132,7 @@
#define MGADXI_PIXPLLSTAT 0x4F #define MGADXI_PIXPLLSTAT 0x4F
#define MGADXI_CURCOLEXT 0x60 /*sequential from CURCOL3->15, RGB*/ #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_KEYOPMODE 0x51
#define MGADXI_COLMSK0RED 0x52 #define MGADXI_COLMSK0RED 0x52
#define MGADXI_COLMSK0GREEN 0x53 #define MGADXI_COLMSK0GREEN 0x53
@@ -110,7 +141,7 @@
#define MGADXI_COLKEY0GREEN 0x56 #define MGADXI_COLKEY0GREEN 0x56
#define MGADXI_COLKEY0BLUE 0x57 #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_IDX 0x87
#define MGADXI_TVO_DATA 0x88 #define MGADXI_TVO_DATA 0x88
#define MGADXI_OUTPUTCONN 0x8A #define MGADXI_OUTPUTCONN 0x8A
@@ -124,9 +155,8 @@
/* MGA 1st CRTC registers */ /* MGA 1st CRTC registers */
#define MGACR1_VCOUNT 0x1E20 #define MGACR1_VCOUNT 0x1E20
//end rudolf.
/*MGA 2nd CRTC registers >= ?? TODO */ /* MGA 2nd CRTC registers (>= G400) */
#define MGACR2_CTL 0x3C10 #define MGACR2_CTL 0x3C10
#define MGACR2_HPARAM 0x3C14 #define MGACR2_HPARAM 0x3C14
#define MGACR2_HSYNC 0x3C18 #define MGACR2_HSYNC 0x3C18
@@ -134,6 +164,7 @@
#define MGACR2_VSYNC 0x3C20 #define MGACR2_VSYNC 0x3C20
#define MGACR2_PRELOAD 0x3C24 #define MGACR2_PRELOAD 0x3C24
#define MGACR2_STARTADD0 0x3C28 #define MGACR2_STARTADD0 0x3C28
#define MGACR2_STARTADD1 0x3C2C
#define MGACR2_OFFSET 0x3C40 #define MGACR2_OFFSET 0x3C40
#define MGACR2_MISC 0x3C44 #define MGACR2_MISC 0x3C44
#define MGACR2_VCOUNT 0x3C48 #define MGACR2_VCOUNT 0x3C48
@@ -183,7 +214,7 @@
#define MGAACC_SRCORG 0x2CB4 // >= G200 #define MGAACC_SRCORG 0x2CB4 // >= G200
#define MGAACC_DSTORG 0x2CB8 // >= 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_A1ORG 0x3D00
#define MGABES_A2ORG 0x3D04 #define MGABES_A2ORG 0x3D04
#define MGABES_B1ORG 0x3D08 #define MGABES_B1ORG 0x3D08
@@ -213,15 +244,34 @@
#define MGABES_GLOBCTL 0x3DC0 #define MGABES_GLOBCTL 0x3DC0
#define MGABES_STATUS 0x3DC4 #define MGABES_STATUS 0x3DC4
/*MAVEN registers >= TODO */ /*MAVEN registers (<= G400) */
#define MGAMAV_PGM 0x3E
#define MGAMAV_PIXPLLM 0x80 #define MGAMAV_PIXPLLM 0x80
#define MGAMAV_PIXPLLN 0x81 #define MGAMAV_PIXPLLN 0x81
#define MGAMAV_PIXPLLP 0x82 #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_MONSET 0x8C
#define MGAMAV_TEST 0x8D #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_MONEN 0x94
#define MGAMAV_RESYNC 0x95
#define MGAMAV_LASTLINEL 0x96 #define MGAMAV_LASTLINEL 0x96
#define MGAMAV_LASTLINEH 0x97 #define MGAMAV_LASTLINEH 0x97
#define MGAMAV_WREG_0X98_L 0x98
#define MGAMAV_WREG_0X98_H 0x99
#define MGAMAV_HSYNCLENL 0x9A #define MGAMAV_HSYNCLENL 0x9A
#define MGAMAV_HSYNCLENH 0x9B #define MGAMAV_HSYNCLENH 0x9B
#define MGAMAV_HSYNCSTRL 0x9C #define MGAMAV_HSYNCSTRL 0x9C
@@ -242,12 +292,17 @@
#define MGAMAV_HVIDRSTH 0xAB #define MGAMAV_HVIDRSTH 0xAB
#define MGAMAV_VVIDRSTL 0xAC #define MGAMAV_VVIDRSTL 0xAC
#define MGAMAV_VVIDRSTH 0xAD #define MGAMAV_VVIDRSTH 0xAD
#define MGAMAV_VSOMETHINGL 0xAE
#define MGAMAV_VSOMETHINGH 0xAF
#define MGAMAV_OUTMODE 0xB0 #define MGAMAV_OUTMODE 0xB0
#define MGAMAV_LOCK 0xB3 #define MGAMAV_LOCK 0xB3
#define MGAMAV_LUMA 0xB9 #define MGAMAV_LUMA 0xB9
#define MGAMAV_VDISPLAYTV 0xBE
#define MGAMAV_STABLE 0xBF #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_REG8(r_) ((vuint8 *)regs)[(r_)]
#define MGA_REG32(r_) ((vuint32 *)regs)[(r_) >> 2] #define MGA_REG32(r_) ((vuint32 *)regs)[(r_) >> 2]
@@ -289,9 +344,8 @@
#define CR2R(A) (MGA_REG32(MGACR2_##A)) #define CR2R(A) (MGA_REG32(MGACR2_##A))
#define CR2W(A,B) (MGA_REG32(MGACR2_##A)=B) #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 MAVR(A) (i2c_maven_read (MGAMAV_##A ))
#define MAVW(A,B) (i2c_maven_write(MGAMAV_##A ,B)) #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 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 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))
+23 -14
View File
@@ -4,7 +4,8 @@
Other authors: Other authors:
Mark Watson, Mark Watson,
Apsed. Apsed,
Rudolf Cornelissen 2/2003.
*/ */
#define MODULE_BIT 0x40000000 #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) {
//void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) { int i;
//typedef struct {
// uint16 src_left; /* guaranteed constrained to virtual width and height */ /*do each blit*/
// uint16 src_top; i=0;
// uint16 src_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ while (count--)
// uint16 src_height; /* 0 to M, where zero means one line, one means two lines, etc. */ {
// uint16 dest_left; gx00_acc_video_blit
// uint16 dest_top; (
// uint16 dest_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */ list[i].src_left,
// uint16 dest_height; /* 0 to M, where zero means one line, one means two lines, etc. */ list[i].src_top,
//} scaled_blit_params; 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) { void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) {
int i; int i;
+58 -9
View File
@@ -3,13 +3,14 @@
This file may be used under the terms of the Be Sample Code License. This file may be used under the terms of the Be Sample Code License.
Other authors: Other authors:
Mark Watson Mark Watson,
Rudolf Cornelissen 4/2003
*/ */
#define MODULE_BIT 0x20000000 #define MODULE_BIT 0x20000000
/*DUALHEAD notes - /*DUALHEAD notes -
No hardware cursor possible:( No hardware cursor possible on the secondary head :(
Reasons: Reasons:
CRTC1 has a cursor, can be displayed on DAC or MAVEN CRTC1 has a cursor, can be displayed on DAC or MAVEN
CRTC2 has no cursor CRTC2 has no cursor
@@ -62,40 +63,88 @@ void MOVE_CURSOR(uint16 x, uint16 y)
si->cursor.y = y; si->cursor.y = y;
/*set up minimum amount to scroll*/ /*set up minimum amount to scroll*/
if (si->dm.flags & DUALHEAD_BITS)
{
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) switch(si->dm.space)
{ {
case B_CMAP8: case B_CMAP8:
h_adjust=7; h_adjust = 0x07;
break; break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE: case B_RGB15_LITTLE:case B_RGB16_LITTLE:
h_adjust=3; h_adjust = 0x03;
break; break;
case B_RGB32_LITTLE: case B_RGB32_LITTLE:
h_adjust=1; h_adjust = 0x01;
break; break;
default: default:
h_adjust=7; h_adjust = 0x07;
break;
}
} }
/* adjust h/v_display_start to move cursor onto screen */ /* adjust h/v_display_start to move cursor onto screen */
if (x >= (si->dm.timing.h_display + hds)) switch (si->dm.flags & DUALHEAD_BITS)
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust; {
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) else if (x < hds)
hds = x & ~h_adjust; 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)) if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1; vds = y - si->dm.timing.v_display + 1;
else if (y < vds) else if (y < vds)
vds = y; 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)) if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
{
MOVE_DISPLAY(hds,vds); MOVE_DISPLAY(hds,vds);
//fixme: implement:
//move_overlay(hds,vds);
}
/* put cursor in correct physical position */ /* put cursor in correct physical position */
x -= hds + si->cursor.hot_x; x -= hds + si->cursor.hot_x;
y -= vds + si->cursor.hot_y; 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 */ /* position the cursor on the display */
gx00_crtc_cursor_position(x,y); gx00_crtc_cursor_position(x,y);
} }
@@ -4,7 +4,7 @@
Other authors: Other authors:
Mark Watson, Mark Watson,
Rudolf Cornelissen 10/2002 Rudolf Cornelissen 10/2002-4/2003
*/ */
#define MODULE_BIT 0x08000000 #define MODULE_BIT 0x08000000
@@ -12,7 +12,6 @@
#include "acc_std.h" #include "acc_std.h"
/* /*
The standard entry point. Given a uint32 feature identifier, this routine The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper 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 pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be is available. Any extra information available to choose the function will be
noted on a case by case below. noted on a case by case below.
*/ */
void * get_accelerant_hook(uint32 feature, void *data) {
switch (feature) {
/* /*
These definitions are out of pure lazyness. These definitions are out of pure lazyness.
*/ */
#define CHKO(x) case B_##x: \ #define CHKO(x) case B_##x: \
if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0 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 HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0 #define ZERO(x) case B_##x: return (void *)0
#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed #define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed
void * get_accelerant_hook(uint32 feature, void *data)
{
switch (feature)
{
/* /*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and 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 subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant hook selections can be predicated on variables assigned during the accelerant
initialization process. initialization process.
*/ */
/* initialization */ /* initialization */
HOOK(INIT_ACCELERANT); HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT); HOOK(CLONE_ACCELERANT);
@@ -67,7 +70,7 @@ initialization process.
HOOK(SET_DPMS_MODE); HOOK(SET_DPMS_MODE);
/* cursor managment */ /* cursor managment */
HRDC(SET_CURSOR_SHAPE); // apsed HRDC(SET_CURSOR_SHAPE);
HRDC(MOVE_CURSOR); HRDC(MOVE_CURSOR);
HRDC(SHOW_CURSOR); HRDC(SHOW_CURSOR);
@@ -79,6 +82,13 @@ initialization process.
HOOK(GET_SYNC_TOKEN); HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_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 */ /* only export video overlay functions if card is capable of it */
CHKO(OVERLAY_COUNT); CHKO(OVERLAY_COUNT);
CHKO(OVERLAY_SUPPORTED_SPACES); CHKO(OVERLAY_SUPPORTED_SPACES);
@@ -96,25 +106,30 @@ 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 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 function to be used with each bit-depth. In the sample driver we return
the same function all the time. the same function all the time.
*/
/* 2D acceleration */
HOOK(SCREEN_TO_SCREEN_BLIT);
HOOK(FILL_RECTANGLE);
HOOK(INVERT_RECTANGLE);
HOOK(FILL_SPAN);
HOOK(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);//remove for pre R5
/*HOOK(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT; Note: These hooks are re-acquired by the app_server after each mode switch.
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 /* 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; return 0;
} }
#undef CHKO
#undef CHKA
#undef HOOK
#undef ZERO
#undef HRDC
status_t check_overlay_capability(uint32 feature) status_t check_overlay_capability(uint32 feature)
{ {
@@ -155,21 +170,71 @@ status_t check_overlay_capability(uint32 feature)
break; 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 */ /* export video overlay functions */
LOG(4, ("Overlay: Exporting hook %s.\n", msg)); LOG(4, ("Overlay: Exporting hook %s.\n", msg));
return B_OK; return B_OK;
break; }
default:
/* do not export video overlay functions */ /* do not export video overlay functions */
LOG(4, ("Overlay: Not exporting hook %s.\n", msg)); LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
return B_ERROR; return B_ERROR;
}
status_t check_acc_capability(uint32 feature)
{
bool fill = false;
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_SCREEN_TO_SCREEN_BLIT:
msg = "B_SCREEN_TO_SCREEN_BLIT";
break;
case B_FILL_RECTANGLE:
msg = "B_FILL_RECTANGLE";
fill = true;
break;
case B_INVERT_RECTANGLE:
msg = "B_INVERT_RECTANGLE";
fill = true;
break;
case B_FILL_SPAN:
msg = "B_FILL_SPAN";
fill = true;
break;
case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT:
msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT";
break;
case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT:
msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT";
break;
default:
msg = "UNKNOWN";
break; 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;
}
} }
@@ -4,7 +4,7 @@
Other authors: Other authors:
Mark Watson, Mark Watson,
Rudolf Cornelissen 10/2002. Rudolf Cornelissen 10/2002-3/2003.
*/ */
#define MODULE_BIT 0x00800000 #define MODULE_BIT 0x00800000
@@ -40,7 +40,8 @@ static status_t init_common(int the_fd) {
goto error0; goto error0;
} }
// LOG is now available, si !NULL // 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*/ /*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 info in a frame_buffer_config structure to make it convienient to return
to the app_server later. 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 = 0;
pointer_reservation = si->settings.hardcursor? 1024: 0; // apsed TODO with G100, see before /* 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 = (void *)((char *)si->framebuffer+pointer_reservation);
si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+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; if (result < B_OK) goto error2;
/* all done */ /* all done */
LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
result = B_OK; result = B_OK;
goto error0; goto error0;
@@ -273,7 +279,13 @@ error0:
return result; 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 benaphore*/
DELETE_BEN(si->engine.lock); DELETE_BEN(si->engine.lock);
DELETE_BEN(si->overlay.lock); DELETE_BEN(si->overlay.lock);
+4 -1
View File
@@ -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: /* 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' * 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: /* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0003 while > G200 need ~x0007. * G200 can do with ~0x0003 while > G200 need ~x0007.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */ * 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)) if (width == (width & ~0x0007))
{ {
si->overlay.myBuffer[offset].width = width; si->overlay.myBuffer[offset].width = width;
@@ -4,7 +4,7 @@
Other authors for MGA driver: Other authors for MGA driver:
Mark Watson, Mark Watson,
Rudolf Cornelissen 9/2002 Rudolf Cornelissen 9/2002-4/2003
*/ */
#define MODULE_BIT 0x00400000 #define MODULE_BIT 0x00400000
@@ -12,7 +12,8 @@
#include "acc_std.h" #include "acc_std.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) #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)) #define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
/*some monitors only handle a fixed set of modes*/ /*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) */ { { 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) */ { { 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) */ { { 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) */ { { 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) */
{ { 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) */ { { 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) */ { { 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) */ { { 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) */ { { 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) */ { { 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 Check mode is between low and high limits
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: returns:
B_OK - found one B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible 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 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; float pix_clock_found;
uint8 m,n,p; uint8 m,n,p;
status_t result = B_OK; status_t result;
uint32 row_bytes, limit_clock, max_vclk; uint32 max_vclk, row_bytes, pointer_reservation;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0) / double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
( (
(double)target->timing.h_total * (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_width = target->timing.h_display == target->virtual_width,
want_same_height = target->timing.v_display == target->virtual_height; want_same_height = target->timing.v_display == target->virtual_height;
// // apsed, adjust virtual width for CRTC offset constraints LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
// status = adjust_width (target, want_same_width); target->virtual_width, target->virtual_height));
// if (status != B_OK) return status;
/*check valid list: /*check valid list:
if (VALID_REQUIRED is set) 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; int closest_mode_ptr;
uint32 closest_mode_clock; uint32 closest_mode_clock;
LOG(1, ("PROPOSEMODE: valid mode required!\n"));
closest_mode_ptr = 0xbad; closest_mode_ptr = 0xbad;
closest_mode_clock = 0; closest_mode_clock = 0;
for (i=0;i<VALID_MODES;i++) for (i=0;i<VALID_MODES;i++)
@@ -155,16 +133,14 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
if (closest_mode_ptr==0xbad)/*if no modes of correct size*/ if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
{ {
LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
return B_ERROR; return B_ERROR;
} }
else else
{ {
target->timing=valid_mode_list[closest_mode_ptr]; target->timing=valid_mode_list[closest_mode_ptr];
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/ 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 #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.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
&target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
); );
if (result == B_ERROR) return result; if (result == B_ERROR)
/*check if timing found is within the requested horizontal limits*/
if (
(target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total)
) result = B_BAD_VALUE;
/*check if timing found is within the requested vertical limits*/
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.v_sync_start) || // apsed
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
) result = B_BAD_VALUE;
//rudolf
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
if (si->ps.card_type >= G100)
{ {
/* calculate settings, but do not actually test anything (that costs too much time!) */ LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
status = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0); 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 */ /* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width) if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display; target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height) if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display; 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 */ /* nail virtual size and 'subsequently' calculate rowbytes */
target->virtual_width = (target->virtual_width + 7) & ~7; result = gx00_general_validate_pic_size (target, &row_bytes);
if ( if (result == B_ERROR)
(target->virtual_width < low->virtual_width) || {
(target->virtual_width > high->virtual_width) LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
) result = B_BAD_VALUE; return result;
// apsed, adjust virtual width for CRTC offset constraints
status = adjust_width (target, want_same_width);
if (status != B_OK) return status;
/* calculate rowbytes after we've nailed the virtual width */
switch (target->space & 0x0fff) {
case B_CMAP8:
row_bytes = 1;
break;
case B_RGB15:
case B_RGB16:
row_bytes = 2;
break;
case B_RGB32:
row_bytes = 4;
break;
default:
/* no amount of adjusting will fix not being able to support the pixel format */
LOG(8,("PROPOSEMODE: unknown target space: 0x%08x\n", target->space));
return B_ERROR;
} }
row_bytes *= target->virtual_width;
/*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 */ /* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) > (si->ps.memory_size * 1024 * 1024)) if ((row_bytes * target->virtual_height) >
target->virtual_height = (si->ps.memory_size * 1024 * 1024) / row_bytes; ((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) 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; return B_ERROR;
} }
else if ( LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
(target->virtual_height < low->virtual_height) || target->virtual_width, target->virtual_height));
(target->virtual_height > high->virtual_height)
) result = B_BAD_VALUE; 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 */ /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
switch (target->space) switch (target->space)
@@ -305,43 +317,68 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
break; break;
} }
/*clear DUALHEAD_CAPABLE if any problems*/ /* set DUALHEAD_CAPABLE if suitable */
if //fixme: update for independant secondary head use! (reserve fixed memory then)
( if (si->ps.secondary_head &&
((target->flags)& DUALHEAD_CAPABLE ) && (((si->ps.memory_size * 1024 * 1024) - pointer_reservation) >=
( /* note: extra line for maven vblank included here! */
(!si->ps.secondary_head) || (row_bytes * (target->virtual_height + 1) * 2)) &&
((1024 + (row_bytes * (target->virtual_height+1) * 2)) > (si->ps.memory_size * 1024 * 1024)) || /*note: extra line for maven vblank!*/ ((target->space == B_RGB16_LITTLE) || (target->space == B_RGB32_LITTLE)) &&
(target->space == B_CMAP8) || (target->timing.pixel_clock <= (max_vclk * 1000)))
(target->space == B_RGB15_LITTLE) ||
(target->timing.pixel_clock > (max_vclk * 1000))
)
)
{ {
target->flags&=~DUALHEAD_CAPABLE; target->flags |= DUALHEAD_CAPABLE;
} }
/*set tv capable suitable*/ /* 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->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(). /* Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff) 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; return si->mode_count;
} }
/* Copy the list of guaranteed supported video modes to the location provided.*/ /* 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)); memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK; 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); max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
/* create an area to hold the info */ /* create an area to hold the info */
si->mode_area = my_mode_list_area = 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; if (my_mode_list_area < B_OK) return my_mode_list_area;
/* walk through our predefined list and see which modes fit this device */ /* 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; pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range; low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range; high.timing.pixel_clock += pix_clk_range;
/* some cards need wider virtual widths for certain modes */ /* 'some cards need wider virtual widths for certain modes':
high.virtual_width = 4096; * 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 */ /* do it once for each depth we want to support */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) 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; *dst = *src;
/* poke the specific space */ /* poke the specific space */
dst->space = low.space = high.space = spaces[j]; 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 */ /* 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 */ /* count it, and move on to next mode */
dst++; dst++;
si->mode_count++; si->mode_count++;
+170 -197
View File
@@ -5,15 +5,13 @@
Other authors: Other authors:
Mark Watson, Mark Watson,
Apsed, Apsed,
Rudolf Cornelissen 11-12/2002 Rudolf Cornelissen 11/2002-4/2003
*/ */
#define MODULE_BIT 0x00200000 #define MODULE_BIT 0x00200000
#include "acc_std.h" #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 Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver. ioctl() to the kernel driver.
@@ -32,112 +30,148 @@ static void interrupt_enable(bool flag) {
/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ /* 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) 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; status_t result;
uint32 startadd,startadd_right; uint32 startadd,startadd_right;
// apsed TODO startadd is 19 bits if < g200 // apsed TODO startadd is 19 bits if < g200
uint8 display,h,v; uint8 display,h,v;
si->switched_crtcs = false;
struct my_timming tv_timing;
struct mavenregs tv_regs;
bool switched_crtcs = false;
/* Adjust mode to valid one and fail if invalid */ /* Adjust mode to valid one and fail if invalid */
target = bounds = *mode_to_set; target /*= bounds*/ = *mode_to_set;
/* show the mode bits */ /* show the mode bits */
LOG(1, ("SetDisplayMode - initial flags: %x\n", target.flags)); LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\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, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_width", mode_to_set->virtual_width, mode_to_set->virtual_width)); LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_height", mode_to_set->virtual_height, mode_to_set->virtual_height)); target.virtual_width, target.virtual_height));
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR) /* See BOUNDS WARNING above... */
return B_ERROR; 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 not dualhead capable card clear dualhead flags */
if ((!si->ps.secondary_head) || (!(target.flags&DUALHEAD_CAPABLE))) if (!(target.flags & DUALHEAD_CAPABLE))
{ {
target.flags &= ~DUALHEAD_BITS; target.flags &= ~DUALHEAD_BITS;
target.flags&=~TV_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, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
LOG(1, ("SetDisplayMode - validated flags: %x\n", target.flags));
/* disable interrupts using the kernel driver */ /* disable interrupts using the kernel driver */
interrupt_enable(false); 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_fetch(&display,&h,&v);
gx00_crtc_dpms(0,0,0); gx00_crtc_dpms(0,0,0);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ /*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!*/ /*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;
/* init display mode for secondary head */
display_mode target2 = target;
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
/* validate flags for secondary TVout */
if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
{
target.flags &= ~TV_BITS;//still needed for some routines...
target2.flags &= ~TV_BITS;
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
}
/* set the pixel clock PLL(s) */ /* 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) if (gx00_dac_set_pix_pll(target) == B_ERROR)
LOG(8,("SET: error setting pixel clock (internal DAC)\n")); LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
if (si->ps.secondary_head)
/* we do not need to set the pixelclock here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS))
{ {
if (gx00_maven_set_pix_pll((target.timing.pixel_clock)/1000.0)==B_ERROR) LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
LOG(8,("SET: error setting pixel clock (MAVEN)\n")); if (gx00_maven_set_vid_pll(target2) == B_ERROR)
} LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
else
{
LOG(8,("SET: not setting maven clock (G450?)\n"));
} }
/*set the colour depth for CRTC1, CRTC2, the DAC and the MAVEN */ /*set the colour depth for CRTC1 and the DAC */
switch(target.space) switch(target.space)
{ {
case B_RGB16_LITTLE: case B_RGB16_LITTLE:
colour_depth=16; colour_depth1 = 16;
gx00_dac_mode(BPP16, 1.0); gx00_dac_mode(BPP16, 1.0);
gx00_maven_mode(BPP16, 1.0);
gx00_crtc_depth(BPP16); 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); g400_crtc2_depth(BPP16);
break; break;
case B_RGB32_LITTLE: case B_RGB32_LITTLE:
colour_depth=32; colour_depth2 = 32;
gx00_dac_mode(BPP32, 1.0);
gx00_maven_mode(BPP32DIR, 1.0); gx00_maven_mode(BPP32DIR, 1.0);
gx00_crtc_depth(BPP32);
g400_crtc2_depth(BPP32DIR); g400_crtc2_depth(BPP32DIR);
break; 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*/ /*set the display(s) pitches*/
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); gx00_crtc_set_display_pitch ();
g400_crtc2_set_display_pitch (target.virtual_width, colour_depth); //fixme: seperate for real dualhead modes:
//we need a secondary si->fbc!
g400_crtc2_set_display_pitch ();
/*work out where the "right" screen starts*/ /*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 */ /* 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 */ /* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */
crtc1_vdisplay = target.timing.v_display;
/* (extra "blanking" line for MAVEN) */ /* (extra "blanking" line for MAVEN) */
crtc2_vdisplay = target.timing.v_display + 1; target2.timing.v_display++;
/* set the outputs */ /* set the outputs */
switch (si->ps.card_type) switch (si->ps.card_type)
@@ -149,38 +183,35 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
case DUALHEAD_ON: case DUALHEAD_ON:
case DUALHEAD_CLONE: case DUALHEAD_CLONE:
gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
switched_crtcs = false; si->switched_crtcs = false;
break; break;
case DUALHEAD_SWITCH: case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK) if (i2c_sec_tv_adapter() == B_OK)
{ {
/* Don't switch CRTC's because MAVEN YUV is impossible then, /* Don't switch CRTC's because MAVEN YUV is impossible then,
* and primary head output will be limited to 135Mhz pixelclock. */ * 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); gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
switched_crtcs = true; si->switched_crtcs = true;
} }
else else
{ {
/* This limits the pixelclocks on both heads to 135Mhz, /* This limits the pixelclocks on both heads to 135Mhz,
* but you can use overlay on the other output now. */ * 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); 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 */ /* 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 */ /* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */
/* (extra "blanking" line for MAVEN) */ /* (extra "blanking" line for MAVEN) */
crtc1_vdisplay = target.timing.v_display + 1; target.timing.v_display++;
crtc2_vdisplay = target.timing.v_display; target2.timing.v_display--;
} }
break; break;
} }
break; break;
//fixme: //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, //setup crtc_delay and vertical timing adjust for G450(?)/G550,
//and remove the '+1' in crtc2 vertical timing(?) //and remove the '+1' in crtc2 vertical timing(?)
case G450: case G450:
@@ -194,24 +225,24 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
case DUALHEAD_ON: case DUALHEAD_ON:
case DUALHEAD_CLONE: case DUALHEAD_CLONE:
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false; si->switched_crtcs = false;
break; break;
case DUALHEAD_SWITCH: case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK) if (i2c_sec_tv_adapter() == B_OK)
{ {
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */ * 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); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = true; si->switched_crtcs = true;
} }
else else
{ {
/* This limits the pixelclocks on both heads to 235Mhz, /* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */ * 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); gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
switched_crtcs = false; si->switched_crtcs = false;
} }
break; break;
} }
@@ -227,14 +258,14 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
if (i2c_sec_tv_adapter() == B_OK) if (i2c_sec_tv_adapter() == B_OK)
{ {
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false; si->switched_crtcs = false;
} }
else else
{ {
/* This limits the pixelclocks on both heads to 235Mhz, /* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */ * but you can use overlay on the other output now. */
gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1); gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
switched_crtcs = false; si->switched_crtcs = false;
} }
break; break;
case DUALHEAD_SWITCH: 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, /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */ * 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); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = true; si->switched_crtcs = true;
} }
else 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); gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false; si->switched_crtcs = false;
} }
break; break;
} }
@@ -260,9 +291,9 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
break; break;
} }
if (switched_crtcs) if (si->switched_crtcs)
{ {
int temp = startadd; uint32 temp = startadd;
startadd = startadd_right; startadd = startadd_right;
startadd_right = temp; startadd_right = temp;
} }
@@ -272,12 +303,12 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{ {
case DUALHEAD_ON: case DUALHEAD_ON:
case DUALHEAD_SWITCH: case DUALHEAD_SWITCH:
gx00_crtc_set_display_start(startadd,colour_depth); gx00_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd_right,colour_depth); g400_crtc2_set_display_start(startadd_right,colour_depth2);
break; break;
case DUALHEAD_CLONE: case DUALHEAD_CLONE:
gx00_crtc_set_display_start(startadd,colour_depth); gx00_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd,colour_depth); g400_crtc2_set_display_start(startadd,colour_depth2);
break; break;
} }
@@ -288,82 +319,21 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
target.timing.h_sync_start, target.timing.h_sync_start,
target.timing.h_sync_end, target.timing.h_sync_end,
target.timing.h_total, target.timing.h_total,
crtc1_vdisplay, target.timing.v_display,
target.timing.v_sync_start, target.timing.v_sync_start,
target.timing.v_sync_end, target.timing.v_sync_end,
target.timing.v_total, target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC, target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC 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 /* TVout support: setup CRTC2 and it's pixelclock */
( if (si->ps.secondary_tvout && (target2.flags & TV_BITS))
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)
{ {
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; si->crtc_delay += 5;
maventv_init(target2);
/*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();
} }
} }
else /* single head mode */ else /* single head mode */
@@ -373,36 +343,35 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
switch(target.space) switch(target.space)
{ {
case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break; case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break; case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break; case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth = 32; colour_mode = BPP32; break; case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
default: 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; return B_ERROR;
} }
/* set the pixel clock PLL */ /* set the pixel clock PLL */
if (si->ps.card_type >= G100) if (si->ps.card_type >= G100)
status = gx00_dac_set_pix_pll(target); 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) if (status==B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
/* set the colour depth for CRTC1 and the DAC */ /* set the colour depth for CRTC1 and the DAC */
if (si->ps.card_type >= G100) gx00_dac_mode(colour_mode,1.0); gx00_dac_mode(colour_mode,1.0);
else mil2_dac_mode(colour_mode,1.0,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC,
target.timing.flags&B_SYNC_ON_GREEN);
gx00_crtc_depth(colour_mode); gx00_crtc_depth(colour_mode);
/* set the display pitch */ /* set the display pitch */
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth); gx00_crtc_set_display_pitch();
/* tell the card what memory to display */ /* tell the card what memory to display */
gx00_crtc_set_display_start(startadd,colour_depth); gx00_crtc_set_display_start(startadd,colour_depth1);
/* enable primary analog output */ /* enable primary analog output */
switch (si->ps.card_type) switch (si->ps.card_type)
{ {
@@ -436,33 +405,32 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
target.timing.flags&B_POSITIVE_VSYNC target.timing.flags&B_POSITIVE_VSYNC
); );
/*turn screen one on and screen two off*/ //fixme: shut-off the videoPLL if it exists...
gx00_crtc_dpms(display,h,v);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
} }
/* update driver's mode store */ /* update driver's mode store */
si->dm = target; si->dm = target;
si->fbc.bytes_per_row=target.virtual_width*(colour_depth>>3);
/* 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 */ /* set up acceleration for this mode */
si->dm.virtual_height += 1;//for clipping! si->dm.virtual_height += 1;//for clipping!
gx00_acc_init(); 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); 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 */ /* enable interrupts using the kernel driver */
interrupt_enable(true); interrupt_enable(true);
/* optimize memory-access if needed */ /* 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*! */ /* Tune RAM CAS-latency if needed. Must be done *here*! */
mga_set_cas_latency(); mga_set_cas_latency();
@@ -525,8 +493,18 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
} }
/* do not run past end of display */ /* do not run past end of display */
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
default:
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR; return B_ERROR;
break;
}
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR; 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; si->dm.v_display_start = v_display_start;
/* actually set the registers */ /* actually set the registers */
startadd=v_display_start*(si->dm.virtual_width*colour_depth)>>3; //fixme: seperate both heads: we need a secondary si->fbc!
startadd+=h_display_start; startadd = v_display_start * si->fbc.bytes_per_row;
startadd+=(si->fbc.frame_buffer)-(si->framebuffer); 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); 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); interrupt_enable(false);
switch (si->dm.flags&DUALHEAD_BITS) switch (si->dm.flags&DUALHEAD_BITS)
{ {
case DUALHEAD_ON: case DUALHEAD_ON:
case DUALHEAD_SWITCH:
gx00_crtc_set_display_start(startadd,colour_depth); gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth); g400_crtc2_set_display_start(startadd_right,colour_depth);
break; 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); gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth); g400_crtc2_set_display_start(startadd,colour_depth);
break; 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); interrupt_enable(true);
@@ -587,8 +571,7 @@ void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags
b[i]=*color_data++; b[i]=*color_data++;
i++; i++;
} }
if (si->ps.card_type >= G100) gx00_dac_palette(r,g,b); gx00_dac_palette(r,g,b);
else mil2_dac_palette(r,g,b);
} }
@@ -600,9 +583,7 @@ enum {
BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF 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) { status_t SET_DPMS_MODE(uint32 dpms_flags) {
interrupt_enable(false); interrupt_enable(false);
@@ -614,27 +595,19 @@ status_t SET_DPMS_MODE(uint32 dpms_flags) {
{ {
case B_DPMS_ON: /* H: on, V: on */ case B_DPMS_ON: /* H: on, V: on */
gx00_crtc_dpms(1,1,1); gx00_crtc_dpms(1,1,1);
g400_crtc2_dpms(1,1,1); if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1);
if (si->ps.secondary_head)
gx00_maven_dpms(1,1,1);
break; break;
case B_DPMS_STAND_BY: case B_DPMS_STAND_BY:
gx00_crtc_dpms(0,0,1); gx00_crtc_dpms(0,0,1);
g400_crtc2_dpms(0,0,1); if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,1);
break; break;
case B_DPMS_SUSPEND: case B_DPMS_SUSPEND:
gx00_crtc_dpms(0,1,0); gx00_crtc_dpms(0,1,0);
g400_crtc2_dpms(0,1,0); if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,1,0);
break; break;
case B_DPMS_OFF: /* H: off, V: off, display off */ case B_DPMS_OFF: /* H: off, V: off, display off */
gx00_crtc_dpms(0,0,0); gx00_crtc_dpms(0,0,0);
g400_crtc2_dpms(0,0,0); if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
break; break;
default: default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
@@ -5,7 +5,6 @@ UsePrivateHeaders [ FDirName graphics matrox ] ;
UseHeaders [ FDirName $(SUBDIR) .. ] ; UseHeaders [ FDirName $(SUBDIR) .. ] ;
StaticLibrary matrox_engine : StaticLibrary matrox_engine :
matroxfb_maven_hack.c
mga_acc.c mga_acc.c
mga_bes.c mga_bes.c
mga_crtc.c mga_crtc.c
@@ -15,6 +14,7 @@ StaticLibrary matrox_engine :
mga_i2c.c mga_i2c.c
mga_info.c mga_info.c
mga_maven.c mga_maven.c
mga_maventv.c
mga_support.c mga_support.c
tvp3026.c tvp3026.c
; ;
@@ -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 ([email protected]) not Petr
//-----------------------------------------------
//MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <[email protected]>");
//MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
@@ -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() ;
+135 -38
View File
@@ -1,7 +1,7 @@
/* MGA Acceleration functions */ /* MGA Acceleration functions */
/* Authors: /* Authors:
Mark Watson 2/2000, Mark Watson 2/2000,
Rudolf Cornelissen 10-12/2002 Rudolf Cornelissen 10/2002-4/2003.
*/ */
#define MODULE_BIT 0x00080000 #define MODULE_BIT 0x00080000
@@ -10,7 +10,7 @@
/*acceleration notes*/ /*acceleration notes*/
/*functions Be needs: /*functions Be's app_server uses:
fill span (horizontal only) fill span (horizontal only)
fill rectangle (these 2 are very similar) fill rectangle (these 2 are very similar)
invert rectangle invert rectangle
@@ -19,12 +19,14 @@ blit
/* G100 pre SRCORG/DSTORG registers */ /* G100 pre SRCORG/DSTORG registers */
static uint32 src_dst; 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 { \ #define ACCW_YDSTLEN(dst, len) do { \
/* if (si->ylin) { */ \ if (y_lin) { \
if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { \ ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \
ACCW(YDST,((dst)*si->dm.virtual_width) >> 5); \
ACCW(LEN,len); \ ACCW(LEN,len); \
} else ACCW(YDSTLEN,((dst)<<16)|(len)); \ } else ACCW(YDSTLEN,((dst)<<16)|(len)); \
} while (0) } while (0)
@@ -39,47 +41,115 @@ status_t gx00_acc_wait_idle()
return B_OK; 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() 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) */ /* 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 */ /* Set pixel width */
switch(si->dm.space) switch(si->dm.space)
{ {
case B_CMAP8: case B_CMAP8:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x00)); ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00));
depth = 8;
break; break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE: case B_RGB15_LITTLE:case B_RGB16_LITTLE:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x01)); ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01));
depth = 16;
break; break;
case B_RGB32_LITTLE:case B_RGBA32_LITTLE: case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x02)); ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02));
depth = 32;
break; break;
default: default:
LOG(8,("ACC: init, invalid bit depth\n")); LOG(8,("ACC: init, invalid bit depth\n"));
return B_ERROR; return B_ERROR;
} }
/*PITCH*/ /* setup PITCH: very cardtype specific! */
// TODO apsed 3-129 32 or 64 following depth (or 128 if MIl2) switch (si->ps.card_type)
if (si->dm.virtual_width&0x1F)
{ {
LOG(8,("ACC: can not accelerate, pitch is not multiple of 32 pixels\n")); case MIL1:
return B_ERROR; 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 */ /* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
ACCW(PLNWT,0x00000000); ACCW(PLNWT,0x00000000);
ACCW(PLNWT,0xffffffff); ACCW(PLNWT,0xffffffff);
@@ -92,11 +162,12 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer)); 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; src_dst = 0;
ACCW(YDSTORG, src_dst); 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)) if ((si->ps.card_type == G100) && (si->settings.hardcursor))
{ {
switch (si->dm.space) switch (si->dm.space)
@@ -120,25 +191,27 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
/* clipping */ /* clipping */
/* i.e. highest and lowest X pixel adresses */ /* 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 */ /* Y pixel addresses must be linear */
/* lowest adress */ /* lowest adress */
ACCW(YTOP, 0 + src_dst); ACCW(YTOP, 0 + src_dst);
/* highest adress */ /* 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; 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) status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
{ {
uint32 t_start,t_end,offset; uint32 t_start,t_end,offset;
uint32 b_start,b_end; uint32 b_start,b_end;
/*find where the top,bottom and offset are*/ /*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 = t_start = xs + (offset*ys) + src_dst;
t_end += w; 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 = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w; b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */ /*find which quadrant */
switch((yd>ys)|((xd>xs)<<1)) 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); ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/ /*do the blit*/
ACCGO(DWGCTL,0x040C4018); ACCGO(DWGCTL,0x040C4018); // atype RSTR
return B_OK; 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) status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
{ {
uint32 t_start,t_end,offset; uint32 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; return B_ERROR;
/*find where the top,bottom and offset are*/ /*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 = t_start = xs + (offset*ys) + src_dst;
t_end += w; 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 = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w; b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */ /*find which quadrant */
switch((yd>ys)|((xd>xs)<<1)) 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*/ /*do the blit*/
ACCW(FCOL,colour); ACCW(FCOL,colour);
ACCW(BCOL,0xffffffff); ACCW(BCOL,0xffffffff);
ACCGO(DWGCTL,0x440C4018); ACCGO(DWGCTL,0x440C4018); // atype RSTR
return B_OK; return B_OK;
} }
/*rectangle fill*/ /* rectangle fill.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/ /*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col) 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_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/ 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) if (si->dm.space==B_CMAP8 || si->ps.sdram)
{ {
ACCGO(DWGCTL,0x400C7814); // atype RSTR 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; return B_OK;
} }
/*rectangle invert*/ /* rectangle invert.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/ /*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle_invert(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)
{ {
@@ -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_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/ 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!*/ /*pseudo_dma version!*/
//MGAACC_DWGCTL =0x1C00, //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; 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;
}
+47 -31
View File
@@ -1,10 +1,13 @@
/* G200-G550 Back End Scaler functions */ /* 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 #define MODULE_BIT 0x00000200
#include "mga_std.h" #include "mga_std.h"
//fixme: implement: (used for virtual screens!)
//void move_overlay(uint16 hdisp_start, uint16 vdisp_start);
status_t gx00_configure_bes status_t gx00_configure_bes
(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset) (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 */ /* misc used variables */
uint16 temp1, temp2; uint16 temp1, temp2;
/* interval representation, used for scaling calculations */ /* 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 */ /* inverse scaling factor, used for source positioning */
uint32 ifactor; uint32 ifactor;
/* used for vertical weight starting value */ /* 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", 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)); my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
/* the BES does not respect virtual_workspaces, but adheres to CRTC
* constraints only */
crtc_hstart = si->dm.h_display_start;
/* make dualhead switch mode with TVout enabled work while we're at it.. */
if (si->switched_crtcs)
{
crtc_hstart += si->dm.timing.h_display;
}
/* horizontal end is the first position beyond the displayed range on the CRTC */
crtc_hend = crtc_hstart + si->dm.timing.h_display;
crtc_vstart = si->dm.v_display_start;
/* vertical end is the first position beyond the displayed range on the CRTC */
crtc_vend = crtc_vstart + si->dm.timing.v_display;
/**************************************** /****************************************
*** setup all edges of output window *** *** setup all edges of output window ***
@@ -93,22 +110,22 @@ status_t gx00_configure_bes
hcoordv = 0; hcoordv = 0;
/* left edge coordinate of output window, must be inside desktop */ /* left edge coordinate of output window, must be inside desktop */
/* clipping on the left side */ /* clipping on the left side */
if (ow->h_start < 0) if (ow->h_start < crtc_hstart)
{ {
temp1 = 0; temp1 = 0;
} }
else else
{ {
/* clipping on the right side */ /* 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 */ /* width < 2 is not allowed */
temp1 = (si->dm.virtual_width - 2) & 0x7ff; temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
} }
else else
/* no clipping here */ /* no clipping here */
{ {
temp1 = (uint16)ow->h_start & 0x7ff; temp1 = (ow->h_start - crtc_hstart) & 0x7ff;
} }
} }
hcoordv |= temp1 << 16; hcoordv |= temp1 << 16;
@@ -121,14 +138,14 @@ status_t gx00_configure_bes
else else
{ {
/* clipping on the right side */ /* 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 else
{ {
/* clipping on the left side */ /* 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 */ /* width < 2 is not allowed */
temp2 = 1; temp2 = 1;
@@ -136,33 +153,33 @@ status_t gx00_configure_bes
else else
/* no clipping here */ /* 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; 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 */ /* setup top and bottom edges of output window */
vcoordv = 0; vcoordv = 0;
/* top edge coordinate of output window, must be inside desktop */ /* top edge coordinate of output window, must be inside desktop */
/* clipping on the top side */ /* clipping on the top side */
if (ow->v_start < 0) if (ow->v_start < crtc_vstart)
{ {
temp1 = 0; temp1 = 0;
} }
else else
{ {
/* clipping on the bottom side */ /* 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 */ /* height < 2 is not allowed */
temp1 = (si->dm.virtual_height - 2) & 0x7ff; temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
} }
else else
/* no clipping here */ /* no clipping here */
{ {
temp1 = (uint16)ow->v_start & 0x7ff; temp1 = (ow->v_start - crtc_vstart) & 0x7ff;
} }
} }
vcoordv |= temp1 << 16; vcoordv |= temp1 << 16;
@@ -175,14 +192,14 @@ status_t gx00_configure_bes
else else
{ {
/* clipping on the bottom side */ /* 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 else
{ {
/* clipping on the top side */ /* 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 */ /* height < 2 is not allowed */
temp2 = 1; temp2 = 1;
@@ -190,12 +207,12 @@ status_t gx00_configure_bes
else else
/* no clipping here */ /* 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; 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: The input bitmaps slopspace is automatically excluded from the calculations this way! */
/* Note also: /* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
hsrcstv = 0; hsrcstv = 0;
/* check for destination horizontal clipping at left side */ /* 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: /* check if entire destination picture is clipping left:
* (2 pixels will be clamped onscreen at least) */ * (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) */ /* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
hsrcstv += (ow->width - 2); hsrcstv += (ow->width - 2);
@@ -289,7 +305,7 @@ status_t gx00_configure_bes
else else
{ {
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */ /* 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")); LOG(4,("Overlay: clipping left...\n"));
@@ -314,11 +330,11 @@ status_t gx00_configure_bes
hsrcendv = 0; hsrcendv = 0;
/* check for destination horizontal clipping at right side */ /* 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: /* check if entire destination picture is clipping right:
* (2 pixels will be clamped onscreen at least) */ * (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) */ /* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
hsrcendv += (ow->width - 2); hsrcendv += (ow->width - 2);
@@ -326,7 +342,7 @@ status_t gx00_configure_bes
else else
{ {
/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */ /* 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")); LOG(4,("Overlay: clipping right...\n"));
@@ -435,11 +451,11 @@ status_t gx00_configure_bes
/* calculate origin adress */ /* calculate origin adress */
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv)); LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv));
/* check for destination vertical clipping at top side */ /* 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: /* check if entire destination picture is clipping at top:
* (2 pixels will be clamped onscreen at least) */ * (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': /* increase source buffer origin with 'fixed value':
* (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) * * (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: /* increase source buffer origin with:
* (integer part of (number of destination picture clipping pixels * inverse scaling factor)) * * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
* bytes per row source picture */ * bytes per row source picture */
a1orgv += ((((0 - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row); a1orgv += ((((crtc_vstart - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
weight = (0 - ow->v_start) * ifactor; weight = (crtc_vstart - ow->v_start) * ifactor;
} }
LOG(4,("Overlay: clipping at top...\n")); LOG(4,("Overlay: clipping at top...\n"));
} }
+136 -13
View File
@@ -2,7 +2,7 @@
/* Authors: /* Authors:
Mark Watson 2/2000, Mark Watson 2/2000,
Apsed, Apsed,
Rudolf Cornelissen 11-12/2002 Rudolf Cornelissen 11/2002-4/2003
*/ */
#define MODULE_BIT 0x00040000 #define MODULE_BIT 0x00040000
@@ -196,6 +196,30 @@ status_t gx00_crtc_depth(int mode)
viddelay = 2<<3; // for 8 to 16Mb of memory viddelay = 2<<3; // for 8 to 16Mb of memory
} while (0); } 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*/ /*set VCLK scaling*/
switch(mode) switch(mode)
{ {
@@ -238,16 +262,17 @@ status_t gx00_crtc_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) // MIL2
return B_OK; return B_OK;
} }
status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp) status_t gx00_crtc_set_display_pitch()
{ {
uint32 offset; uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n")); LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
/*figure out offset value hardware needs*/ /* figure out offset value hardware needs:
offset = (pitch*bpp)/128; * 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!*/ /*program the card!*/
VGAW_I(CRTC,0x13,(offset&0xFF)); 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: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer)); 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*/ /*set standard registers*/
VGAW_I(CRTC,0xD,startadd&0xFF); VGAW_I(CRTC,0xD,startadd&0xFF);
VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8); VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8);
@@ -389,20 +428,20 @@ status_t gx00_crtc_mem_priority(uint8 colordepth)
status_t gx00_crtc_cursor_init() status_t gx00_crtc_cursor_init()
{ {
int i; int i;
if (si->ps.card_type >= G100)
{
uint32 * fb; uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer */ /* cursor bitmap will be stored at the start of the framebuffer on >= G100 */
const uint32 curadd = 0; const uint32 curadd = 0;
/* set cursor bitmap adress ... */ /* set cursor bitmap adress ... */
DXIW(CURADDL,curadd >> 10); DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18); DXIW(CURADDH,curadd >> 18);
/* ... and repeat that: G100 requires other programming order than other cards!?! */ /* ... and repeat that: G100 requires other programming order than later cards!?! */
DXIW(CURADDL,curadd >> 10); DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18); DXIW(CURADDH,curadd >> 18);
/* activate hardware cursor */
DXIW(CURCTRL,1);
/*set cursor colour*/ /*set cursor colour*/
DXIW(CURCOL0RED,0XFF); DXIW(CURCOL0RED,0XFF);
DXIW(CURCOL0GREEN,0xFF); DXIW(CURCOL0GREEN,0xFF);
@@ -420,12 +459,60 @@ status_t gx00_crtc_cursor_init()
{ {
fb[i]=0; 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);
return B_OK; return B_OK;
} }
status_t gx00_crtc_cursor_show() 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; return B_OK;
} }
@@ -438,9 +525,12 @@ status_t gx00_crtc_cursor_hide()
/*set up cursor shape*/ /*set up cursor shape*/
status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask) status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{ {
uint8 * cursor;
int y; int y;
if(si->ps.card_type >= G100)
{
uint8 * cursor;
/*get a pointer to the cursor*/ /*get a pointer to the cursor*/
cursor = (uint8*) si->framebuffer; cursor = (uint8*) si->framebuffer;
@@ -452,6 +542,40 @@ status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
cursor[y*16+6]=~*andMask++; cursor[y*16+6]=~*andMask++;
cursor[y*16+14]=*xorMask++; 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; 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) status_t gx00_crtc_cursor_position(uint16 x ,uint16 y)
{ {
int i=64; int i=64;
// LOG(4,("DAC: cursor-> %d %d\n",x,y));
x+=i; x+=i;
y+=i; y+=i;
+171 -27
View File
@@ -2,7 +2,7 @@
Authors: Authors:
Mark Watson 6/2000, Mark Watson 6/2000,
Rudolf Cornelissen 12/2002 Rudolf Cornelissen 12/2002 - 4/2003
*/ */
#define MODULE_BIT 0x00020000 #define MODULE_BIT 0x00020000
@@ -10,30 +10,131 @@
#include "mga_std.h" #include "mga_std.h"
/*set a mode line - inputs are in pixels/scanlines*/ /*set a mode line - inputs are in pixels/scanlines*/
status_t g400_crtc2_set_timing( status_t g400_crtc2_set_timing(display_mode target)
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
)
{ {
uint32 temp;
LOG(4,("CRTC2: setting timing\n")); LOG(4,("CRTC2: setting timing\n"));
if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX))
{
/* G450/G550 monitor mode, and all modes on older cards */
/* check horizontal timing parameters are to nearest 8 pixels */ /* 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,("CRTC2: Horizontal timings are not multiples of 8 pixels\n")); LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR; 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 */ /* program the second CRTC */
CR2W(HPARAM, ((((hdisp_e - 8) & 0x0fff) << 16) | ((htotal - 8) & 0x0fff))); CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) |
CR2W(HSYNC, ((((hsync_e - 8) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff))); ((target.timing.h_total - 8) & 0x0fff)));
CR2W(VPARAM, ((((vdisp_e - 1) & 0x0fff) << 16) | ((vtotal - 1) & 0x0fff))); CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) |
CR2W(VSYNC, ((((vsync_e - 1) & 0x0fff) << 16) | ((vsync_s - 1) & 0x0fff))); ((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!!) //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, (((target.timing.v_sync_start & 0x0fff) << 16) |
CR2W(PRELOAD, ((((vsync_s - 1) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff))); // (target.timing.h_sync_start & 0x0fff)));
CR2W(MISC, ((0xfff << 16) | (((!hsync_pos) & 0x01) << 8) | (((!vsync_pos) & 0x01) << 9))); 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; return B_OK;
} }
@@ -41,6 +142,7 @@ status_t g400_crtc2_set_timing(
status_t g400_crtc2_depth(int mode) 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) switch(mode)
{ {
case BPP16:case BPP32DIR: 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) 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... if (display & h & v)
CR2W(CTL,(CR2R(CTL)&0xFFF0077E)|(display&h&v)); /*enable second CRTC if required*/ {
/* 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; return B_OK;
} }
@@ -73,31 +194,54 @@ status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v)
return B_OK; return B_OK;
} }
status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp) status_t g400_crtc2_set_display_pitch()
{ {
uint32 offset; 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 */ /* figure out offset value hardware needs */
offset = pitch*(bpp>>3); 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); CR2W(OFFSET,offset);
return B_OK; return B_OK;
} }
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp) 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: startadd: $%x\n",startadd));
LOG(2,("CRTC2: frameRAM: %x\n",si->framebuffer)); LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer));
LOG(2,("CRTC2: framebuffer: %x\n",si->fbc.frame_buffer)); LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer));
/*program the card!*/ 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); CR2W(STARTADD0, startadd);
}
return B_OK; return B_OK;
} }
+236 -25
View File
@@ -2,19 +2,23 @@
/* Authors: /* Authors:
Mark Watson 2/2000, Mark Watson 2/2000,
Apsed 2002, Apsed 2002,
Rudolf Cornelissen 9-12/2002 Rudolf Cornelissen 9/2002-4/2003
*/ */
#define MODULE_BIT 0x00010000 #define MODULE_BIT 0x00010000
#include "mga_std.h" #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); 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( 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); 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( static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result); 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)*/ /*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) 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; if (gx00_dac_palette(r,g,b)!=B_OK) return B_ERROR;
/*set the mode - also sets VCLK dividor*/ /*set the mode - also sets VCLK dividor*/
if (si->ps.card_type >= G100)
{
DXIW(MULCTRL, mode); DXIW(MULCTRL, mode);
DACW(PIXRDMSK,0xff); // apsed, palette addressing not masked 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; 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")); LOG(4,("DAC: setting palette\n"));
/* clear palwtadd to start programming (LUT index?) */ /* clear palwtadd before starting programming (LUT index) */
DACW(PALWTADD,0); DACW(PALWTADD,0);
/* just for safety (specs are somewhat unclear) (LUT color?) */
DACW(PALRDADD,0);
/*loop through all 256 to program DAC*/ /*loop through all 256 to program DAC*/
for (i=0;i<256;i++) 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 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; 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; req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); 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); result = gx00_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK) if (result != B_OK)
{ {
@@ -282,14 +330,134 @@ status_t gx00_dac_pix_pll_find
switch (si->ps.card_type) { switch (si->ps.card_type) {
case G550: case G550:
case G450: return g450_g550_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test); 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; return B_ERROR;
} }
/* find nearest valid pixel PLL setting: rewritten by rudolf */ /* 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) 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; int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999; float error, error_best = 999999999;
@@ -315,6 +483,17 @@ static status_t g100_g400max_dac_pix_pll_find(
break; 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 */ /* determine the max. pixelclock for the current videomode */
switch (target.space) 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 */ /* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */ /* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 8.0)) 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); req_pclk = (si->ps.min_pixel_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */ /* 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 */ /* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1) 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 */ /* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */ /* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 16.0)) 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); req_pclk = (si->ps.min_pixel_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */ /* 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 */ /* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1) 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 */ /* setup the scalers programming values for found optimum setting */
m=best[0] - 1; m=best[0] - 1;
n=best[1] - 1; n=best[1] - 2;
switch(best[2]) switch(best[2])
{ {
case 1: case 1:
@@ -526,7 +723,7 @@ static status_t g450_g550_dac_pix_pll_find
} }
/* log the closest VCO speed found */ /* 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)); LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing. /* 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 */ /* Make sure the requested systemclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */ /* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 8.0)) 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); req_sclk = (si->ps.min_system_vco / 8.0);
}
/* upper limit is max_system_vco */ /* 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 */ /* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1) 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; uint time = 0, count = 0;
/* program the new clock */ /* program the new clock */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
DXIW(SYSPLLM, m); DXIW(SYSPLLM, m);
DXIW(SYSPLLN, n); DXIW(SYSPLLN, n);
DXIW(SYSPLLP, p); 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; *p &= 0x47;
/* iterate through all possible filtersettings */ /* iterate through all possible filtersettings */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
for (s = 0; s < 8 ;s++) for (s = 0; s < 8 ;s++)
{ {
if (gx50_dac_check_sys_pll(m, n, *p)== B_OK) 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 */ /* preset first choice setting found */
*q = 1; *q = 1;
/* we are done */ /* we are done */
// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
return B_OK; return B_OK;
} }
else 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 */ /* return the (last found) backup result, or the original p value */
*p = p_backup; *p = p_backup;
// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
/* we found only a non-optimal value */ /* we found only a non-optimal value */
if (*q == 2) return B_OK; 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 */ /* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */ /* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 16.0)) 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); req_sclk = (si->ps.min_system_vco / 16.0);
}
/* upper limit is max_system_vco */ /* 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 */ /* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1) 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 */ /* setup the scalers programming values for found optimum setting */
m=best[0] - 1; m=best[0] - 1;
n=best[1] - 1; n=best[1] - 2;
switch(best[2]) switch(best[2])
{ {
case 1: case 1:
@@ -825,7 +1036,7 @@ static status_t g450_g550_dac_sys_pll_find(
} }
/* log the closest VCO speed found */ /* 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)); LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing. /* now find the filtersetting that matches best with this frequency by testing.
@@ -1,7 +1,7 @@
/* Authors: /* Authors:
Mark Watson 12/1999, Mark Watson 12/1999,
Apsed, Apsed,
Rudolf Cornelissen 10-12/2002 Rudolf Cornelissen 10/2002-4/2003
*/ */
#define MODULE_BIT 0x00008000 #define MODULE_BIT 0x00008000
@@ -11,7 +11,7 @@
//#include "mga_init.c" //Nicole's test stuff. //#include "mga_init.c" //Nicole's test stuff.
status_t test_ram(); 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 g100_general_powerup (void);
static status_t g200_general_powerup (void); static status_t g200_general_powerup (void);
static status_t g400_general_powerup (void); static status_t g400_general_powerup (void);
@@ -56,17 +56,23 @@ status_t gx00_general_powerup()
status_t status; status_t status;
uint32 card_class; uint32 card_class;
LOG(1,("POWERUP: Matrox (open)BeOS Accelerant 0.14 running.\n"));
/* detect card type and power it up */ /* detect card type and power it up */
switch(CFGR(DEVID)) switch(CFGR(DEVID))
{ {
case 0x0519102b: //MGA-2064 Millenium PCI
case 0x051a102b: //MGA-1064 Mystic PCI case 0x051a102b: //MGA-1064 Mystic PCI
LOG(8,("POWERUP: Unimplemented Matrox device %08x\n",CFGR(DEVID))); LOG(8,("POWERUP: Unimplemented Matrox device %08x\n",CFGR(DEVID)));
return B_ERROR; 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 case 0x051b102b:case 0x051f102b: //MGA-2164 Millenium 2 PCI/AGP
si->ps.card_type = MIL2; si->ps.card_type = MIL2;
LOG(4,("POWERUP: Detected MGA-2164 Millennium 2\n")); LOG(4,("POWERUP: Detected MGA-2164 Millennium 2\n"));
status = mil2_general_powerup(); status = mil_general_powerup();
break; break;
case 0x1000102b:case 0x1001102b: //G100 case 0x1000102b:case 0x1001102b: //G100
si->ps.card_type = G100; si->ps.card_type = G100;
@@ -201,7 +207,7 @@ status_t mga_set_cas_latency()
break; break;
case G450: case G450:
case G550: 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")); LOG(4,("INIT: G450/G550 RAM CAS tuning not implemented, aborting.\n"));
return B_OK; return B_OK;
break; break;
@@ -220,11 +226,11 @@ status_t mga_set_cas_latency()
} }
static static
status_t mil2_general_powerup() status_t mil_general_powerup()
{ {
status_t result; 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(); if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */ /* initialize the shared_info PINS struct */
@@ -235,15 +241,9 @@ status_t mil2_general_powerup()
dump_pins(); dump_pins();
//remove this: //remove this:
// various sensible defaults for MIL2 fake_pins();
si->ps.sdram = true; LOG(2, ("INIT: Using faked PINS for now:\n"));
si->ps.memory_size = 2; //can override dump_pins();
si->ps.memory_size = 4; //can override my mil2
// apsed TODO MIL2 TVP 3026 may be 135, 175, 220 or 250MHz
// chip on my Millenium2 is TVP3026-250CPCE, 250MHz
// rudolf: works in Mhz now
si->ps.max_dac1_clock=250; // TVP3026
//end remove this. //end remove this.
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ /* 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")); LOG(2, ("INIT: Skipping card coldstart!\n"));
mil2_dac_init(); mil2_dac_init();
//rudolf: sync on green test: //ok:
/* disable 15bit mode CLUT-overlay function */ /* disable overscan, select 0 IRE, select straight-through sync signals from CRTC */
//enable 'sync on green' option DXIW (GENCTRL, (DXIR (GENCTRL) & 0x0c));
// DXIW(GENCTRL, DXIR(GENCTRL | 0x20)); /* fixme: checkout if we need this sync inverting stuff: already done via CRTC!?!
/* enable composite sync instead of Hsync only */ | (vsync_pos? 0x00:0x02)
// VGAW_I(CRTCEXT,3,(VGAR_I(CRTCEXT,3) | 0x40)); | (hsync_pos? 0x00:0x01)); */
//end sync on green test.
/* 8-bit DAC, enable DAC */
DXIW(MISCCTRL, 0x0c);
//
VGAW_I(SEQ,1,0x00); VGAW_I(SEQ,1,0x00);
/*enable screen*/ /*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; return B_OK;
} }
@@ -309,7 +309,6 @@ status_t g100_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */ /* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */ /* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x1b); DXIW(MISCCTRL,0x1b);
@@ -349,12 +348,12 @@ status_t g100_general_powerup()
/* wait 200uS minimum */ /* wait 200uS minimum */
snooze(250); snooze(250);
/* reset memory */ /* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000); ACCW(MACCESS, 0x00000000);
/* select JEDEC reset method */ /* select JEDEC reset method */
ACCW(MACCESS,ACCR(MACCESS)|0x4000); ACCW(MACCESS, 0x00004000);
/* perform actual RAM reset */ /* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000); ACCW(MACCESS, 0x0000c000);
snooze(250); snooze(250);
/* start memory refresh */ /* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); 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 */ /* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */ /* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x1b); DXIW(MISCCTRL,0x1b);
@@ -452,10 +450,10 @@ status_t g200_general_powerup()
/* wait 200uS minimum */ /* wait 200uS minimum */
snooze(250); snooze(250);
/* reset memory */ /* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000); ACCW(MACCESS, 0x00000000);
/* perform actual RAM reset */ /* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000); ACCW(MACCESS, 0x00008000);
snooze(250); snooze(250);
/* start memory refresh */ /* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); 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 */ /* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */ /* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x9b); DXIW(MISCCTRL,0x9b);
@@ -553,10 +550,10 @@ status_t g400_general_powerup()
/* wait 200uS minimum */ /* wait 200uS minimum */
snooze(250); snooze(250);
/* reset memory */ /* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000); ACCW(MACCESS, 0x00000000);
/* perform actual RAM reset */ /* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000); ACCW(MACCESS, 0x00008000);
snooze(250); snooze(250);
/* start memory refresh */ /* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000)); CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
@@ -584,10 +581,12 @@ status_t g400_general_powerup()
static static
status_t g450_general_powerup() status_t g450_general_powerup()
{ {
//fixme: check if g450 and g550 powerup should be the same! (DAC outputconnector?)
status_t result; status_t result;
uint32 pwr_cas[] = {0, 1, 5, 6, 7, 5, 2, 3}; 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")); LOG(4, ("INIT: G450/G550 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space(); if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
@@ -607,8 +606,7 @@ status_t g450_general_powerup()
DXIW(OUTPUTCONN,0x00); DXIW(OUTPUTCONN,0x00);
/* turn off both displays and the hardcursor (also disables transfers) */ /* turn off both displays and the hardcursor (also disables transfers) */
gx00_crtc_dpms(0,0,0); gx00_crtc_dpms(0,0,0);
//fixme: g400_crtc2_dpms(0,0,0);
//g400_crtc2_dpms(0,0,0);
gx00_crtc_cursor_hide(); gx00_crtc_cursor_hide();
/* power up everything except DVI electronics (for now) */ /* power up everything except DVI electronics (for now) */
@@ -625,7 +623,6 @@ status_t g450_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */ /* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04)); DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */ /* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd)); DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */ /* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x9b); DXIW(MISCCTRL,0x9b);
@@ -663,7 +660,8 @@ status_t g450_general_powerup()
/* set RAM read tap delays and mode register opcode / streamer flow control */ /* set RAM read tap delays and mode register opcode / streamer flow control */
ACCW(MEMRDBK, si->ps.memrdbk_reg); ACCW(MEMRDBK, si->ps.memrdbk_reg);
/* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */ /* 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 */ /* clear b0-1 and 3, and set b31 in option4: re-enable memory clock */
CFGW(OPTION4, ((si->ps.option4_reg & 0x60000004) | 0x80000000)); CFGW(OPTION4, ((si->ps.option4_reg & 0x60000004) | 0x80000000));
snooze(250); snooze(250);
@@ -675,7 +673,8 @@ status_t g450_general_powerup()
if (!(si->ps.v5_mem_type & 0x0100)) if (!(si->ps.v5_mem_type & 0x0100))
{ {
/* clear unknown bits */ /* clear unknown bits */
ACCW(MACCESS, 0x00000000); maccess = 0x00000000;
ACCW(MACCESS, maccess);
/* clear b12: unknown bit */ /* clear b12: unknown bit */
ACCW(MEMRDBK, (si->ps.memrdbk_reg & 0xffffefff)); ACCW(MEMRDBK, (si->ps.memrdbk_reg & 0xffffefff));
} }
@@ -689,8 +688,8 @@ status_t g450_general_powerup()
} }
/* create positive flank to generate memory reset */ /* create positive flank to generate memory reset */
ACCW(MACCESS,ACCR(MACCESS) & 0xffff7fff); ACCW(MACCESS, (maccess & 0xffff7fff));
ACCW(MACCESS,ACCR(MACCESS) | 0x00008000); ACCW(MACCESS, (maccess | 0x00008000));
snooze(250); snooze(250);
/* start memory refresh */ /* start memory refresh */
@@ -724,6 +723,9 @@ status_t g450_general_powerup()
/*turn on display one*/ /*turn on display one*/
gx00_crtc_dpms(1,1,1); gx00_crtc_dpms(1,1,1);
/* enable 'straight-through' sync outputs on both analog output connectors */
DXIW(SYNCCTRL,0x00);
return B_OK; return B_OK;
} }
@@ -763,27 +765,62 @@ status_t gx00_general_dac_select(int dac)
/*MISCCTRL, clock src,...*/ /*MISCCTRL, clock src,...*/
switch(dac) switch(dac)
{ {
/* G400 */
case DS_CRTC1DAC_CRTC2MAVEN: case DS_CRTC1DAC_CRTC2MAVEN:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ /* connect CRTC1 to pixPLL */
CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); /*external clk*/ 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)); 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); DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
break; break;
case DS_CRTC1MAVEN_CRTC2DAC: case DS_CRTC1MAVEN_CRTC2DAC:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); /*external clk*/ /* connect CRTC1 to vidPLL */
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk*/ 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)); 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); DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02);
break; break;
/* G450/G550 */
case DS_CRTC1CON1_CRTC2CON2: case DS_CRTC1CON1_CRTC2CON2:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ /* connect CRTC1 to pixPLL */
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x0<<20)); /*internal clk - no DAC PTR*/ 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); DXIW(OUTPUTCONN,0x09);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
DXIW(GENIODATA, 0x00);
break; break;
//fixme: toggle PLL's below if possible:
// otherwise toggle PLL's for G400 2nd case?
case DS_CRTC1CON2_CRTC2CON1: case DS_CRTC1CON2_CRTC2CON1:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/ /* connect CRTC1 to pixPLL */
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk - gets DAC*/ 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); DXIW(OUTPUTCONN,0x05);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
DXIW(GENIODATA, 0x00);
break; break;
default: default:
return B_ERROR; return B_ERROR;
@@ -817,13 +854,34 @@ status_t gx00_general_bios_to_powergraphics()
VGAW(MISCW,0x08); VGAW(MISCW,0x08);
/*set only MGA pixel clock in MISC - I don't want to map VGA stuff under this OS*/ /*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); DXIW(MISCCTRL,0x9b);
/*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/ /*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
DXIW(MULCTRL,0x4); DXIW(MULCTRL,0x4);
/*RGBA direct mode*/ /*RGBA direct mode*/
} else { }
else
{
LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR))); LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR)));
} // apsed TODO MIL2 } // apsed TODO MIL2
@@ -832,3 +890,193 @@ status_t gx00_general_bios_to_powergraphics()
return B_OK; 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;
}
+162 -59
View File
@@ -2,7 +2,7 @@
/* some bits are hacks, where PINS is not known */ /* some bits are hacks, where PINS is not known */
/* Authors: /* Authors:
Mark Watson 2/2000, Mark Watson 2/2000,
Rudolf Cornelissen 10-11/2002 Rudolf Cornelissen 10/2002-4/2003
*/ */
#define MODULE_BIT 0x00002000 #define MODULE_BIT 0x00002000
@@ -111,52 +111,80 @@ status_t parse_pins ()
status_t pins1_read(uint8 *pins, uint8 length) status_t pins1_read(uint8 *pins, uint8 length)
{ {
//remove later on here: if (length != 64)
// float f_ref; /* PLL reference-oscillator frequency */ {
// uint32 max_system_vco; /* graphics engine PLL VCO limits */ LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length));
// 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.
//fixme: implement this..
return B_ERROR; 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) 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")); LOG(2,("INFO: PINS version 2 details not yet known\n"));
return B_ERROR; return B_ERROR;
} }
@@ -424,18 +452,15 @@ status_t pins5_read(uint8 *pins, uint8 length)
} }
/* fill out the shared info si->ps struct */ /* 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_system_vco = m_factor * pins[36];
si->ps.max_video_vco = m_factor * pins[37]; si->ps.max_video_vco = m_factor * pins[37];
/* pixelVCO multiplier is 10 if pins V5.2 */ si->ps.max_pixel_vco = m_factor * pins[38];
if (pins[4] == 0x02) si->ps.max_pixel_vco = 10 * pins[38];
else si->ps.max_pixel_vco = m_factor * pins[38];
si->ps.min_system_vco = m_factor * pins[121]; si->ps.min_system_vco = m_factor * pins[121];
si->ps.min_video_vco = m_factor * pins[122]; si->ps.min_video_vco = m_factor * pins[122];
/* pixelVCO multiplier is 10 if pins V5.2 */ si->ps.min_pixel_vco = m_factor * pins[123];
if (pins[4] == 0x02) si->ps.min_pixel_vco = 10 * pins[123];
else si->ps.min_pixel_vco = m_factor * pins[123];
if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco; 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]; else si->ps.max_dac1_clock_8 = 4 * pins[39];
@@ -517,6 +542,9 @@ void fake_pins(void)
switch (si->ps.card_type) switch (si->ps.card_type)
{ {
case MIL1:
pinsmil1_fake();
break;
case MIL2: case MIL2:
pinsmil2_fake(); pinsmil2_fake();
break; break;
@@ -541,15 +569,16 @@ void fake_pins(void)
} }
/* find out if the card has a maven */ /* find out if the card has a maven */
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)
{
if (i2c_maven_probe() == B_OK) if (i2c_maven_probe() == B_OK)
{ {
si->ps.secondary_tvout = true; si->ps.secondary_tvout = true;
si->ps.secondary_head = true; si->ps.secondary_head = true;
} }
else
{
si->ps.secondary_tvout = false;
si->ps.secondary_head = false;
} }
/* not used because no coldstart will be attempted */ /* not used because no coldstart will be attempted */
@@ -567,8 +596,82 @@ void fake_pins(void)
si->ps.v5_mem_type = 0; 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) 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) void pinsg100_fake(void)
@@ -741,12 +844,12 @@ void pinsg450_fake(void)
si->ps.f_ref = 27.000; si->ps.f_ref = 27.000;
/* see G450 pins readouts for max ranges, then use a bit smaller ones */ /* 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. */ /* carefull not to take to high lower limits, and high should be >= 2x low. */
si->ps.max_system_vco = 600; si->ps.max_system_vco = 640;
si->ps.min_system_vco = 256; si->ps.min_system_vco = 320;
si->ps.max_pixel_vco = 640; si->ps.max_pixel_vco = 640;
si->ps.min_pixel_vco = 320; si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600; si->ps.max_video_vco = 640;
si->ps.min_video_vco = 256; si->ps.min_video_vco = 320;
si->ps.max_dac1_clock = 360; si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360; si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360; si->ps.max_dac1_clock_16 = 360;
@@ -786,8 +889,8 @@ void pinsg550_fake(void)
si->ps.min_system_vco = 384; si->ps.min_system_vco = 384;
si->ps.max_pixel_vco = 960; si->ps.max_pixel_vco = 960;
si->ps.min_pixel_vco = 320; si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600; si->ps.max_video_vco = 960;
si->ps.min_video_vco = 256; si->ps.min_video_vco = 320;
si->ps.max_dac1_clock = 360; si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360; si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360; si->ps.max_dac1_clock_16 = 360;
+458 -71
View File
@@ -1,26 +1,52 @@
/* program the MAVEN in monitor mode */ /* 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 #define MODULE_BIT 0x00001000
#include "mga_std.h" #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) status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v)
{ {
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G400MAX) return B_OK;
if (display & h & v) if (display & h & v)
{ {
/* turn on screen */
if (!(si->dm.flags & TV_BITS))
{
/* monitor mode */
MAVW(MONEN, 0xb2); MAVW(MONEN, 0xb2);
MAVW(MONSET, 0x20); /* must be set to this in monitor mode */ MAVW(MONSET, 0x20); /* must be set to this in monitor mode */
MAVW(OUTMODE,3); /*monitor mode*/ MAVW(OUTMODE, 0x03); /* output: monitor mode */
MAVW(STABLE, 0x22); /* makes picture stable? */ MAVW(STABLE, 0x22); /* makes picture stable? */
MAVW(TEST, 0x00); /* turn off test signal */ MAVW(TEST, 0x00); /* turn off test signal */
} }
else 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! */ /* turn off screen using a few methods! */
MAVW(STABLE, 0x6a); MAVW(STABLE, 0x6a);
// MAVW(TEST,0x3); // MAVW(TEST, 0x03);
MAVW(OUTMODE, 0x00); MAVW(OUTMODE, 0x00);
} }
@@ -28,49 +54,61 @@ status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v)
} }
/*set a mode line - inputs are in pixels/scanlines*/ /*set a mode line - inputs are in pixels/scanlines*/
status_t gx00_maven_set_timing( status_t gx00_maven_set_timing(display_mode target)
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
)
{ {
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G400MAX) return B_OK;
LOG(4,("MAVEN: setting timing\n")); LOG(4,("MAVEN: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/ /*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; return B_ERROR;
} }
/*program the MAVEN*/ /*program the MAVEN*/
MAVWW(LASTLINEL,htotal); MAVWW(LASTLINEL, target.timing.h_total);
MAVWW(HSYNCLENL,(hsync_e-hsync_s)); MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
MAVWW(HSYNCSTRL,(htotal-hsync_s)); MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
MAVWW(HDISPLAYL,(htotal-hsync_s+hdisp_e)); MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
MAVWW(HTOTALL,(htotal+1)); target.timing.h_display));
MAVWW(HTOTALL, (target.timing.h_total + 1));
MAVWW(VSYNCLENL,(vsync_e-vsync_s-1)); MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
MAVWW(VSYNCSTRL,(vtotal-vsync_s)); MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
MAVWW(VDISPLAYL,(vtotal-1)); MAVWW(VDISPLAYL, (target.timing.v_total - 1));
MAVWW(VTOTALL,(vtotal-1)); MAVWW(VTOTALL, (target.timing.v_total - 1));
MAVWW(HVIDRSTL,(htotal-si->crtc_delay)); MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
MAVWW(VVIDRSTL,(vtotal-2)); MAVWW(VVIDRSTL, (target.timing.v_total - 2));
return B_OK; return B_OK;
} }
//not used:
/*
void gx00_maven_delay(int number) 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)); MAVWW(HVIDRSTL,(si->dm.timing.h_total-number));
} }
*/
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ /*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) status_t gx00_maven_mode(int mode,float brightness)
{ {
uint8 luma; 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*/ /*set luma to a suitable value for brightness*/
/*assuming 1A is a sensible value*/ /*assuming 1A is a sensible value*/
luma = (uint8)(0x1a * brightness); luma = (uint8)(0x1a * brightness);
@@ -80,17 +118,73 @@ status_t gx00_maven_mode(int mode,float brightness)
return B_OK; return B_OK;
} }
/*program the pixpll on the maven - frequency in kHz*/ status_t gx00_maven_set_vid_pll(display_mode target)
status_t gx00_maven_set_pix_pll(float f_vco) {
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, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = g450_g550_maven_vid_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*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;
}
/* program the video PLL in the MAVEN */
status_t g100_g400max_maven_set_vid_pll(display_mode target)
{ {
uint8 m=0,n=0,p=0; uint8 m=0,n=0,p=0;
float pix_setting; float pix_setting, req_pclk;
status_t result; 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 = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p);
if (result != B_OK) if (result != B_OK)
{ {
return result; return result;
@@ -99,44 +193,99 @@ status_t gx00_maven_set_pix_pll(float f_vco)
/*reprogram (select,wait for stability)*/ /*reprogram (select,wait for stability)*/
MAVW(PIXPLLM,(m)); /* set m value */ MAVW(PIXPLLM,(m)); /* set m value */
MAVW(PIXPLLN,(n)); /* set n value */ MAVW(PIXPLLN,(n)); /* set n value */
MAVW(PIXPLLP,(p|0x80)); /*set p value*/ MAVW(PIXPLLP,(p | 0x80)); /* set p value enabling PLL */
LOG(2,("MAVEN: Clocks found: %x %x %x\n",m,n,p));
delay(1000); /*wait 1000us for PIXPLL to lock (no way of knowing)*/ /* Wait for the VIDPLL frequency to lock: detection is not possible it seems */
LOG(2,("MAVEN: PIX PLL frequency locked\n")); snooze(2000);
LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
return B_OK; return B_OK;
} }
/*find nearest valid pix pll*/ /* find nearest valid video PLL setting */
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uint8 * n_result,uint8 * p_result) status_t g100_g400max_maven_vid_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{ {
float f_ref=27.000; int m = 0, n = 0, p = 0, m_max;
int n_min=4; float error, error_best = 999999999;
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]; int best[3];
float f_rat; float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
LOG(4,("MAVEN:Checking PIX PLL %fMHz\n", f_vco)); /* determine the max. reference-frequency postscaler setting for the current card */
//fixme: check G100 and G200 m_max if possible...
/*f_rat.m/p=n where m=M+1,n=N+1,p=P+1,f_rat=f_vco/f_ref*/ switch(si->ps.card_type)
f_rat = f_vco/f_ref;
error_best = 999999999;
for (p=0x2 -1*(f_vco>80.0);p<0x10;p=p<<1)
{ {
for (m=m_min;m<m_max;m++) case G100:
{ LOG(4,("MAVEN: G100 restrictions apply\n"));
/*calculate n for this m & p (and check for validity)*/ m_max = 32;
n=(int)((f_rat*m*p)+0.5); break;
if (n>n_max || n<n_min) case G200:
continue; LOG(4,("MAVEN: G200 restrictions apply\n"));
m_max = 32;
break;
default:
LOG(4,("MAVEN: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/*find error in frequency this gives*/ /* determine the max. pixelclock for the current videomode */
error=fabs(((f_ref*n)/(m*p))-f_vco); switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_video_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_video_vco / 8.0))
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 8.0)));
req_pclk = (si->ps.min_video_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best) if (error < error_best)
{ {
error_best = error; error_best = error;
@@ -146,27 +295,265 @@ status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uin
} }
} }
} }
m=best[0]; }
n=best[1];
p=best[2];
/*calculate value of s for fvco, not sure if these are correct*/ /* setup the scalers programming values for found optimum setting */
for(;;)/*set loop filter bandwidth -> spot the Perl coder :-)*/ 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)
{ {
if(f_vco>180) {p|=0x18;break;}; case G100:
if(f_vco>140) {p|=0x10;break;}; case G200:
if(f_vco>100) {p|=0x08;break;}; 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; break;
} }
/*set the result*/ /* return the results */
*result = (float) (f_ref*n)/(m*(p&0x7)); *calc_pclk = f_vco / ((p & 0x07) + 1);
*m_result = m-1; *m_result = m;
*n_result = n-1; *n_result = n;
*p_result = p-1; *p_result = p;
/*display the found value*/ /* display the found pixelclock values */
LOG(4,("MAVEN: pixpllcheck - requested %fMHz got %fMHz\n",(double)f_vco,*result)); 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; return B_OK;
} }
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,7 @@ status_t mga_set_cas_latency();
status_t gx50_general_output_select(); status_t gx50_general_output_select();
status_t gx00_general_dac_select(int); status_t gx00_general_dac_select(int);
status_t gx00_general_wait_retrace(); 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(); //status_t gx00_general_bios_to_powergraphics();
/* apsed: logging macros */ /* 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 pins4_read(uint8 *pins, uint8 length);
status_t pins5_read(uint8 *pins, uint8 length); status_t pins5_read(uint8 *pins, uint8 length);
void fake_pins(void); void fake_pins(void);
void pinsmil1_fake(void);
void pinsmil2_fake(void); void pinsmil2_fake(void);
void pinsg100_fake(void); void pinsg100_fake(void);
void pinsg200_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 g100_dac_set_sys_pll();
status_t mil2_dac_init(void); 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); status_t mil2_dac_set_pix_pll(float f_vco,int bpp);
/*MAVEN functions*/ /*MAVEN functions*/
status_t gx00_maven_dpms(uint8,uint8,uint8); status_t gx00_maven_dpms(uint8,uint8,uint8);
status_t gx00_maven_set_timing( status_t gx00_maven_set_timing(display_mode target);
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t gx00_maven_mode(int,float); status_t gx00_maven_mode(int,float);
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *); status_t g100_g400max_maven_vid_pll_find(display_mode target,float * calc_pclk,
status_t gx00_maven_set_pix_pll(float f_vco); 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*/ /*CRTC1 functions*/
status_t gx00_crtc_validate_timing( 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_depth(int mode);
status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp); 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(uint8,uint8,uint8);
status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*); status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*);
@@ -100,24 +104,23 @@ status_t gx00_crtc_cursor_hide();
/*CRTC2 functions*/ /*CRTC2 functions*/
/*XXX - validate_timing*/ /*XXX - validate_timing*/
status_t g400_crtc2_set_timing( status_t g400_crtc2_set_timing(display_mode target);
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t g400_crtc2_depth(int mode); status_t g400_crtc2_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_set_display_start(uint32 startadd,uint8 bpp);
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v); status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v);
status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v); status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v);
/*acceleration functions*/ /*acceleration functions*/
status_t check_acc_capability(uint32 feature);
status_t gx00_acc_init(); 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(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_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_blit(uint16,uint16,uint16, uint16,uint16,uint16 );
status_t gx00_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32); 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(); status_t gx00_acc_wait_idle();
/*backend scaler functions*/ /*backend scaler functions*/
+71 -504
View File
@@ -2,10 +2,9 @@
Program the Texas TVP3026 Program the Texas TVP3026
using Texas Instrument TVP3026 manual SLA098B July 1996 using Texas Instrument TVP3026 manual SLA098B July 1996
Author: Authors:
Apsed May 2002 a lot of time after ... Apsed May 2002 plus a lot of time after;
Rudolf Cornelissen 3/2003.
NB BPP24 and BPP32DIR not tested
*/ */
#define MODULE_BIT 0x00010000 #define MODULE_BIT 0x00010000
@@ -13,76 +12,12 @@
#include <OS.h> // system_time, snooze #include <OS.h> // system_time, snooze
#include "mga_std.h" #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 FVCO_MIN 110.00000 // MHz
#define FPLL_MCLK 100.00000 // MHz #define FPLL_MCLK 100.00000 // MHz
//r: ??
#define MGAVGA_INSTS0 0x1FC2 #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 { \ #define WAIT_FOR_PLL_LOCK( pll, on_error) do { \
bigtime_t start, now; \ bigtime_t start, now; \
float delay; \ float delay; \
@@ -90,7 +25,7 @@
\ \
start = system_time(); \ start = system_time(); \
for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \ for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \
int status = TVPIR (pll ## PLLDATA); \ int status = DXIR (pll ## PLLDATA); \
if (status & 0x40) break; \ if (status & 0x40) break; \
/* snooze(10); */ \ /* snooze(10); */ \
} \ } \
@@ -103,369 +38,6 @@
} \ } \
} while (0) } 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*/ /*program the pixpll - frequency in MHz*/
status_t mil2_dac_set_pix_pll (float f_need, int bpp) 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; float fd;
status_t result; 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)); 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; 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 // follows (!strictly) Appendix C, extended mode setup
// 1st stop the PLLs, // 1st stop the PLLs,
switch (bpp) { switch (bpp) {
case 8: TVPIW(CLOCKSEL, 0x25); break; case 8: DXIW(TVP_CLOCKSEL, 0x25); break;
case 16: TVPIW(CLOCKSEL, 0x15); break; case 16: DXIW(TVP_CLOCKSEL, 0x15); break;
case 24: TVPIW(CLOCKSEL, 0x25); break; case 24: DXIW(TVP_CLOCKSEL, 0x25); break;
case 32: TVPIW(CLOCKSEL, 0x05); break; case 32: DXIW(TVP_CLOCKSEL, 0x05); break;
default: return B_ERROR; default: return B_ERROR;
} }
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
TVPIW(LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL DXIW(TVP_LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
// 2nd setup the pixel PLL // 2nd setup the pixel PLL
LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n", LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n",
n, m, p)); n, m, p));
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
TVPIW(PIXPLLDATA, m); DXIW(TVP_PIXPLLDATA, m);
TVPIW(PIXPLLDATA, p | 0xb0); DXIW(TVP_PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (PIX);
// now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1 // now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1
k = 1; // ?? external division factor between RCLK and LCLK 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; m = 61;
z = (FVCO_MIN * (65 - n)) / (4 * fd * k); z = (FVCO_MIN * (65 - n)) / (4 * fd * k);
q = 0; 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", LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q)); 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", LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q)); n, m, p, q));
// now setup the loop PLL // now setup the loop PLL
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n", LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q)); n, m, p, q));
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ... DXIW(TVP_LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ...
TVPIW(LOOPLLDATA, m); DXIW(TVP_LOOPLLDATA, m);
TVPIW(LOOPLLDATA, p | 0xf0); DXIW(TVP_LOOPLLDATA, p | 0xf0);
WAIT_FOR_PLL_LOCK (LOO, return B_ERROR); // ... wait for PLL lock WAIT_FOR_PLL_LOCK (TVP_LOO, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (LOO);
return B_OK; return B_OK;
} }
@@ -545,67 +118,62 @@ static status_t mil2_dac_set_mem_pll (float f_need, float *mclk)
uint8 n_pix, m_pix, p_pix; uint8 n_pix, m_pix, p_pix;
uint8 memclkctrl; uint8 memclkctrl;
status = mil2_dac_pix_pll_find (f_need, mclk, &m, &n, &p); display_mode target;
target.timing.pixel_clock = (f_need * 1000);
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; 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 // follows (!strictly) TVP3026 2.4.2.1, extended mode setup
// 0) save PIXPLL nmp to restore it at end // 0) save PIXPLL nmp to restore it at end
TVPIW(PLLADDR, 0x00); DXIW(TVP_PLLADDR, 0x00);
n_pix = TVPIR(PIXPLLDATA); n_pix = DXIR(TVP_PIXPLLDATA);
TVPIW(PLLADDR, 0x15); DXIW(TVP_PLLADDR, 0x15);
m_pix = TVPIR(PIXPLLDATA); m_pix = DXIR(TVP_PIXPLLDATA);
TVPIW(PLLADDR, 0x2a); DXIW(TVP_PLLADDR, 0x2a);
p_pix = TVPIR(PIXPLLDATA); p_pix = DXIR(TVP_PIXPLLDATA);
if (1) REREAD_PLL (PIX);
// 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock // 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ... DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ... DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ... DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
TVPIW(PIXPLLDATA, m); DXIW(TVP_PIXPLLDATA, m);
TVPIW(PIXPLLDATA, p | 0xb0); DXIW(TVP_PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (PIX);
// 2) select pixel clock as dot clock source // 2) select pixel clock as dot clock source
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
// 3) output dot clock on MCLK pin // 3) output dot clock on MCLK pin
memclkctrl = TVPIR(MEMCLKCTRL) & 0xe7; memclkctrl = DXIR(TVP_MEMCLKCTRL) & 0xe7;
TVPIW(MEMCLKCTRL, memclkctrl | (0x00 << 3)); DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x00 << 3));
TVPIW(MEMCLKCTRL, memclkctrl | (0x01 << 3)); DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x01 << 3));
// 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock // 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock
if (1) REREAD_PLL (MEM); DXIW(TVP_PLLADDR, 0x2a);
TVPIW(PLLADDR, 0x2a); DXIW(TVP_MEMPLLDATA, 0x00);
TVPIW(MEMPLLDATA, 0x00); DXIW(TVP_PLLADDR, 0x00);
TVPIW(PLLADDR, 0x00); DXIW(TVP_MEMPLLDATA, n | 0xc0);
TVPIW(MEMPLLDATA, n | 0xc0); DXIW(TVP_MEMPLLDATA, m);
TVPIW(MEMPLLDATA, m); DXIW(TVP_MEMPLLDATA, p | 0xb0);
TVPIW(MEMPLLDATA, p | 0xb0); WAIT_FOR_PLL_LOCK (TVP_MEM, return B_ERROR);
WAIT_FOR_PLL_LOCK (MEM, return B_ERROR);
if (1) REREAD_PLL (MEM);
// 5) output mem clock on MCLK pin // 5) output mem clock on MCLK pin
TVPIW(MEMCLKCTRL, memclkctrl | (0x02 << 3)); DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x02 << 3));
TVPIW(MEMCLKCTRL, memclkctrl | (0x03 << 3)); DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x03 << 3));
// 6) restaure pixel clock as it was // 6) restaure pixel clock as it was
TVPIW(PLLADDR, 0x2a); DXIW(TVP_PLLADDR, 0x2a);
TVPIW(PIXPLLDATA, 0x00); DXIW(TVP_PIXPLLDATA, 0x00);
TVPIW(PLLADDR, 0x00); DXIW(TVP_PLLADDR, 0x00);
// TVPIW(PIXPLLDATA, n_pix); DXIW(TVP_PIXPLLDATA, n_pix | 0xc0);
// TVPIW(PIXPLLDATA, m_pix); DXIW(TVP_PIXPLLDATA, m_pix);
// TVPIW(PIXPLLDATA, p_pix); DXIW(TVP_PIXPLLDATA, p_pix | 0xb0);
TVPIW(PIXPLLDATA, n_pix | 0xc0); WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR);
TVPIW(PIXPLLDATA, m_pix);
TVPIW(PIXPLLDATA, p_pix | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR);
if (1) REREAD_PLL (PIX);
return B_OK; return B_OK;
} }
@@ -619,8 +187,6 @@ status_t mil2_dac_init (void)
uint32 option; uint32 option;
uint32 rfhcnt, nogscale, memconfig; uint32 rfhcnt, nogscale, memconfig;
dump_mil2();
LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR))); LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR)));
CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!) CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!)
VGAW_I(CRTC,0x11,0); // allow me to change CRTC 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", LOG(2,("mil2_dac_init: found refresh count %d nogscale %d for %fMHz\n",
rfhcnt, nogscale, mclk)); rfhcnt, nogscale, mclk));
memconfig = 0x00; // 32 bits RAMDAC memconfig = 0x01; // worst case scenario: 64 bits RAMDAC (= tvp3026m) with >2Mb RAM.
memconfig = 0x01; // 64 bits RAMDAC
option = CFGR(OPTION) & 0xffd0cfff; option = CFGR(OPTION) & 0xffd0cfff;
CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12)); CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12));
LOG(2,("mil2_dac_init: OPTION 0x%08x\n", CFGR(OPTION))); 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; return B_OK;
} }