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:
Mark Watson;
Apsed;
Rudolf Cornelissen 10/2002.
Rudolf Cornelissen 10/2002-4/2003.
*/
#ifndef DRIVERINTERFACE_H
@@ -87,6 +87,7 @@ typedef struct settings { // apsed, see comments in mga.settings
uint32 memory;
bool usebios;
bool hardcursor;
bool greensync;
} settings;
/*shared info*/
@@ -136,28 +137,33 @@ typedef struct {
uint16 width; /* Width and height of the cursor shape (always 16!) */
uint16 height;
bool is_visible; /* Is the cursor currently displayed? */
}cursor;
} cursor;
/*colour lookup table*/
uint8 color_data[3 * 256]; /* Colour lookup table - as used by DAC */
/*more display mode stuff*/
display_mode dm; /* current display mode configuration */
display_mode dm; /* current display mode configuration: head1 */
display_mode dm2; /* current display mode configuration: head2 */
bool switched_crtcs; /* dualhead stretch and switch mode info */
bool acc_mode; /* signals (non)accelerated mode */
bool interlaced_tv_mode;/* signals interlaced CRTC TV output mode */
/*frame buffer config - for BDirectScreen*/
frame_buffer_config fbc; /* bytes_per_row and start of frame buffer */
frame_buffer_config fbc; /* bytes_per_row and start of frame buffer: head1 */
frame_buffer_config fbc2; /* bytes_per_row and start of frame buffer: head2 */
/*acceleration engine*/
struct {
uint32 count; /* last dwgsync slot used */
uint32 last_idle; /* last dwgsync slot we *know* the engine was idle after */
benaphore lock; /* for serializing access to the acceleration engine */
} engine;
} engine;
/* card info - information gathered from PINS (and other sources) */
enum
{ // card_type in order of date of MGA chip design
MILL=0,
MIL1 = 0,
MYST,
MIL2,
G100,
+77 -23
View File
@@ -27,7 +27,7 @@
#define MGACFG_AGP_STS 0xf4 // >= MIL2
#define MGACFG_AGP_CMD 0xf8 // >= MIL2
/*VGA registers - these are byte wide*/
/* VGA registers - these are byte wide */
#define MGAVGA_ATTR_I 0x1FC0 // apsed as SEQ
#define MGAVGA_ATTR_D 0x1FC1 // apsed as SEQ
#define MGAVGA_MISCW 0x1FC2
@@ -45,7 +45,38 @@
#define MGAVGA_CRTCEXT_I 0x1FDE
#define MGAVGA_CRTCEXT_D 0x1FDF
/*DAC registers (>= g100) */
/* TVP3026 'non-std' DAC registers (>= MIL1) */
#define MGADAC_TVP_CUROVRWTADD 0x3c04
#define MGADAC_TVP_CUROVRDATA 0x3c05
#define MGADAC_TVP_CUROVRRDADD 0x3c07
#define MGADAC_TVP_DIRCURCTRL 0x3c09
#define MGADAC_TVP_CURRAMDATA 0x3c0b
/* TVP3026 'non'std' (D)AC (X) (I)ndexed registers (>= MIL1) */
#define MGADXI_TVP_SILICONREV 0x01
#define MGADXI_TVP_LATCHCTRL 0x0f
#define MGADXI_TVP_TCOLCTRL 0x18
#define MGADXI_TVP_CLOCKSEL 0x1a
#define MGADXI_TVP_PALPAGE 0x1c
#define MGADXI_TVP_PLLADDR 0x2c
#define MGADXI_TVP_PIXPLLDATA 0x2d
#define MGADXI_TVP_MEMPLLDATA 0x2e
#define MGADXI_TVP_LOOPLLDATA 0x2f
#define MGADXI_TVP_COLKEYOL 0x30
#define MGADXI_TVP_COLKEYOH 0x31
#define MGADXI_TVP_COLKEYRL 0x32
#define MGADXI_TVP_COLKEYRH 0x33
#define MGADXI_TVP_COLKEYGL 0x34
#define MGADXI_TVP_COLKEYGH 0x35
#define MGADXI_TVP_COLKEYBL 0x36
#define MGADXI_TVP_COLKEYBH 0x37
#define MGADXI_TVP_COLKEYCTRL 0x38
#define MGADXI_TVP_MEMCLKCTRL 0x39
#define MGADXI_TVP_TESTMODEDATA 0x3b
#define MGADXI_TVP_ID 0x3f
#define MGADXI_TVP_RESET 0xff
/* DAC registers (>= G100) */
#define MGADAC_PALWTADD 0x3C00
#define MGADAC_PALDATA 0x3C01
#define MGADAC_PIXRDMSK 0x3C02
@@ -56,7 +87,7 @@
#define MGADAC_CURSPOSYL 0x3C0E
#define MGADAC_CURSPOSYH 0x3C0F
/*(D)AC (X) (I)ndexed registers (>= g100) */
/* (D)AC (X) (I)ndexed registers (>= G100) */
#define MGADXI_CURADDL 0x04
#define MGADXI_CURADDH 0x05
#define MGADXI_CURCTRL 0x06
@@ -101,7 +132,7 @@
#define MGADXI_PIXPLLSTAT 0x4F
#define MGADXI_CURCOLEXT 0x60 /*sequential from CURCOL3->15, RGB*/
/*(D)AC (X) (I)ndexed registers (>= g200) */
/* (D)AC (X) (I)ndexed registers (>= G200) */
#define MGADXI_KEYOPMODE 0x51
#define MGADXI_COLMSK0RED 0x52
#define MGADXI_COLMSK0GREEN 0x53
@@ -110,7 +141,7 @@
#define MGADXI_COLKEY0GREEN 0x56
#define MGADXI_COLKEY0BLUE 0x57
/*(D)AC (X) (I)ndexed registers (>= g450?) */
/* (D)AC (X) (I)ndexed registers (>= G450) */
#define MGADXI_TVO_IDX 0x87
#define MGADXI_TVO_DATA 0x88
#define MGADXI_OUTPUTCONN 0x8A
@@ -122,11 +153,10 @@
#define MGADXI_PWRCTRL 0xA0
#define MGADXI_PANMODE 0xA2
/*MGA 1st CRTC registers */
/* MGA 1st CRTC registers */
#define MGACR1_VCOUNT 0x1E20
//end rudolf.
/*MGA 2nd CRTC registers >= ?? TODO */
/* MGA 2nd CRTC registers (>= G400) */
#define MGACR2_CTL 0x3C10
#define MGACR2_HPARAM 0x3C14
#define MGACR2_HSYNC 0x3C18
@@ -134,12 +164,13 @@
#define MGACR2_VSYNC 0x3C20
#define MGACR2_PRELOAD 0x3C24
#define MGACR2_STARTADD0 0x3C28
#define MGACR2_STARTADD1 0x3C2C
#define MGACR2_OFFSET 0x3C40
#define MGACR2_MISC 0x3C44
#define MGACR2_VCOUNT 0x3C48
#define MGACR2_DATACTL 0x3C4C
/*MGA ACCeleration registers*/
/* MGA ACCeleration registers */
#define MGAACC_DWGCTL 0x1C00
#define MGAACC_MACCESS 0x1C04
#define MGAACC_MCTLWTST 0x1C08
@@ -183,7 +214,7 @@
#define MGAACC_SRCORG 0x2CB4 // >= G200
#define MGAACC_DSTORG 0x2CB8 // >= G200
/*MGA BES (Back End Scaler) registers >= TODO */
/*MGA BES (Back End Scaler) registers (>= G200) */
#define MGABES_A1ORG 0x3D00
#define MGABES_A2ORG 0x3D04
#define MGABES_B1ORG 0x3D08
@@ -213,15 +244,34 @@
#define MGABES_GLOBCTL 0x3DC0
#define MGABES_STATUS 0x3DC4
/*MAVEN registers >= TODO */
/*MAVEN registers (<= G400) */
#define MGAMAV_PGM 0x3E
#define MGAMAV_PIXPLLM 0x80
#define MGAMAV_PIXPLLN 0x81
#define MGAMAV_PIXPLLP 0x82
#define MGAMAV_GAMMA1 0x83
#define MGAMAV_GAMMA2 0x84
#define MGAMAV_GAMMA3 0x85
#define MGAMAV_GAMMA4 0x86
#define MGAMAV_GAMMA5 0x87
#define MGAMAV_GAMMA6 0x88
#define MGAMAV_GAMMA7 0x89
#define MGAMAV_GAMMA8 0x8A
#define MGAMAV_GAMMA9 0x8B
#define MGAMAV_MONSET 0x8C
#define MGAMAV_TEST 0x8D
#define MGAMAV_WREG_0X8E_L 0x8E
#define MGAMAV_WREG_0X8E_H 0x8F
#define MGAMAV_HSCALETV 0x90
#define MGAMAV_TSCALETVL 0x91
#define MGAMAV_TSCALETVH 0x92
#define MGAMAV_FFILTER 0x93
#define MGAMAV_MONEN 0x94
#define MGAMAV_RESYNC 0x95
#define MGAMAV_LASTLINEL 0x96
#define MGAMAV_LASTLINEH 0x97
#define MGAMAV_WREG_0X98_L 0x98
#define MGAMAV_WREG_0X98_H 0x99
#define MGAMAV_HSYNCLENL 0x9A
#define MGAMAV_HSYNCLENH 0x9B
#define MGAMAV_HSYNCSTRL 0x9C
@@ -242,56 +292,60 @@
#define MGAMAV_HVIDRSTH 0xAB
#define MGAMAV_VVIDRSTL 0xAC
#define MGAMAV_VVIDRSTH 0xAD
#define MGAMAV_VSOMETHINGL 0xAE
#define MGAMAV_VSOMETHINGH 0xAF
#define MGAMAV_OUTMODE 0xB0
#define MGAMAV_LOCK 0xB3
#define MGAMAV_LUMA 0xB9
#define MGAMAV_VDISPLAYTV 0xBE
#define MGAMAV_STABLE 0xBF
#define MGAMAV_HDISPLAYTV 0xC2
#define MGAMAV_BREG_0XC6 0xC6
/*Macros for convenient accesses to the G400*/
/* Macros for convenient accesses to the MGA chips */
#define MGA_REG8(r_) ((vuint8 *)regs)[(r_)]
#define MGA_REG32(r_) ((vuint32 *)regs)[(r_) >> 2]
/*read and write to PCI config space*/
/* read and write to PCI config space */
#define CFGR(A) (gx00_pci_access.offset=MGACFG_##A, ioctl(fd,GX00_GET_PCI, &gx00_pci_access,sizeof(gx00_pci_access)), gx00_pci_access.value)
#define CFGW(A,B) (gx00_pci_access.offset=MGACFG_##A, gx00_pci_access.value = B, ioctl(fd,GX00_SET_PCI,&gx00_pci_access,sizeof(gx00_pci_access)))
/*read and write from the dac registers*/
/* read and write from the dac registers */
#define DACR(A) (MGA_REG8(MGADAC_##A))
#define DACW(A,B) (MGA_REG8(MGADAC_##A)=B)
/*read and write from the dac index register*/
/* read and write from the dac index register */
#define DXIR(A) (DACW(PALWTADD,MGADXI_##A),DACR(X_DATAREG))
#define DXIW(A,B) (DACW(PALWTADD,MGADXI_##A),DACW(X_DATAREG,B))
/*read and write from the vga registers*/
/* read and write from the vga registers */
#define VGAR(A) (MGA_REG8(MGAVGA_##A))
#define VGAW(A,B) (MGA_REG8(MGAVGA_##A)=B)
/*read and write from the indexed vga registers*/
/* read and write from the indexed vga registers */
#define VGAR_I(A,B) (VGAW(A##_I,B),VGAR(A##_D))
#define VGAW_I(A,B,C) (VGAW(A##_I,B),VGAW(A##_D,C))
/*read and write from the powergraphics registers*/
/* read and write from the powergraphics registers */
#define ACCR(A) (MGA_REG32(MGAACC_##A))
#define ACCW(A,B) (MGA_REG32(MGAACC_##A)=B)
#define ACCGO(A,B) (MGA_REG32(MGAACC_##A + 0x0100)=B)
/*read and write from the backend scaler registers*/
/* read and write from the backend scaler registers */
#define BESR(A) (MGA_REG32(MGABES_##A))
#define BESW(A,B) (MGA_REG32(MGABES_##A)=B)
/*read and write from first CRTC*/
/* read and write from first CRTC */
#define CR1R(A) (MGA_REG32(MGACR1_##A))
#define CR1W(A,B) (MGA_REG32(MGACR1_##A)=B)
/*read and write from second CRTC*/
/* read and write from second CRTC */
#define CR2R(A) (MGA_REG32(MGACR2_##A))
#define CR2W(A,B) (MGA_REG32(MGACR2_##A)=B)
/*read and write from maven*/
/* read and write from maven (<= G400) */
#define MAVR(A) (i2c_maven_read (MGAMAV_##A ))
#define MAVW(A,B) (i2c_maven_write(MGAMAV_##A ,B))
#define MAVRW(A) (i2c_maven_read (MGAMAV_##A )|(i2c_maven_read(MGAMAV_##A +1)<<8))
#define MAVWW(A,B) (i2c_maven_write(MGAMAV_##A ,B &0xFF),i2c_maven_write(MGAMAV_##A +1,B >>8))
#define MAVWWP(A,B) (i2c_maven_write(A ,B &0xFF),i2c_maven_write(A +1,B >>8))
+23 -14
View File
@@ -4,7 +4,8 @@
Other authors:
Mark Watson,
Apsed.
Apsed,
Rudolf Cornelissen 2/2003.
*/
#define MODULE_BIT 0x40000000
@@ -33,19 +34,27 @@ void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
}
}
//Not possible with G400 AFAIK (if anyone knows otherwise then please contact me)
//void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
//typedef struct {
// uint16 src_left; /* guaranteed constrained to virtual width and height */
// uint16 src_top;
// uint16 src_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */
// uint16 src_height; /* 0 to M, where zero means one line, one means two lines, etc. */
// uint16 dest_left;
// uint16 dest_top;
// uint16 dest_width; /* 0 to N, where zero means one pixel, one means two pixels, etc. */
// uint16 dest_height; /* 0 to M, where zero means one line, one means two lines, etc. */
//} scaled_blit_params;
//}
void SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT(engine_token *et, scaled_blit_params *list, uint32 count) {
int i;
/*do each blit*/
i=0;
while (count--)
{
gx00_acc_video_blit
(
list[i].src_left,
list[i].src_top,
list[i].src_width,
list[i].src_height,
list[i].dest_left,
list[i].dest_top,
list[i].dest_width,
list[i].dest_height
);
i++;
}
}
void SCREEN_TO_SCREEN_TRANSPARENT_BLIT(engine_token *et, uint32 transparent_colour, blit_params *list, uint32 count) {
int i;
+72 -23
View File
@@ -3,13 +3,14 @@
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson
Mark Watson,
Rudolf Cornelissen 4/2003
*/
#define MODULE_BIT 0x20000000
/*DUALHEAD notes -
No hardware cursor possible:(
No hardware cursor possible on the secondary head :(
Reasons:
CRTC1 has a cursor, can be displayed on DAC or MAVEN
CRTC2 has no cursor
@@ -54,48 +55,96 @@ void MOVE_CURSOR(uint16 x, uint16 y)
uint16 h_adjust;
/* clamp cursor to display */
if (x >= si->dm.virtual_width) x = si->dm.virtual_width-1;
if (y >= si->dm.virtual_height) y = si->dm.virtual_height-1;
if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1;
if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1;
/* store, for our info */
si->cursor.x=x;
si->cursor.y=y;
si->cursor.x = x;
si->cursor.y = y;
/*set up minimum amount to scroll*/
switch(si->dm.space)
if (si->dm.flags & DUALHEAD_BITS)
{
case B_CMAP8:
h_adjust=7;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
h_adjust=3;
break;
case B_RGB32_LITTLE:
h_adjust=1;
break;
default:
h_adjust=7;
switch(si->dm.space)
{
case B_RGB16_LITTLE:
h_adjust = 0x1f;
break;
case B_RGB32_LITTLE:
h_adjust = 0x0f;
break;
default:
h_adjust = 0x1f;
break;
}
}
else
{
switch(si->dm.space)
{
case B_CMAP8:
h_adjust = 0x07;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
h_adjust = 0x03;
break;
case B_RGB32_LITTLE:
h_adjust = 0x01;
break;
default:
h_adjust = 0x07;
break;
}
}
/* adjust h/v_display_start to move cursor onto screen */
if (x >= (si->dm.timing.h_display + hds))
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
else if (x < hds)
hds = x & ~h_adjust;
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (x >= ((si->dm.timing.h_display * 2) + hds))
{
hds = ((x - (si->dm.timing.h_display * 2)) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + (si->dm.timing.h_display * 2)) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
default:
if (x >= (si->dm.timing.h_display + hds))
{
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
/* make sure we stay within the display! */
if ((hds + si->dm.timing.h_display) > si->dm.virtual_width)
hds -= (h_adjust + 1);
}
else if (x < hds)
hds = x & ~h_adjust;
break;
}
if (y >= (si->dm.timing.v_display + vds))
vds = y - si->dm.timing.v_display + 1;
else if (y < vds)
vds = y;
/* reposition the desktop on the display if required */
/* reposition the desktop _and_ the overlay on the display if required */
if ((hds!=si->dm.h_display_start) || (vds!=si->dm.v_display_start))
{
MOVE_DISPLAY(hds,vds);
//fixme: implement:
//move_overlay(hds,vds);
}
/* put cursor in correct physical position */
x -= hds + si->cursor.hot_x;
y -= vds + si->cursor.hot_y;
/* account for switched CRTC's */
if (si->switched_crtcs) x -= si->dm.timing.h_display;
/* position the cursor on the display */
gx00_crtc_cursor_position(x,y);
}
@@ -4,7 +4,7 @@
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002
Rudolf Cornelissen 10/2002-4/2003
*/
#define MODULE_BIT 0x08000000
@@ -12,7 +12,6 @@
#include "acc_std.h"
/*
The standard entry point. Given a uint32 feature identifier, this routine
returns a pointer to the function that implements the feature. Some features
require more information than just the identifier to select the proper
@@ -20,26 +19,30 @@ function. The extra information (which is specific to the feature) is
pointed at by the void *data parameter. By default, no extra information
is available. Any extra information available to choose the function will be
noted on a case by case below.
*/
void * get_accelerant_hook(uint32 feature, void *data) {
switch (feature) {
/*
These definitions are out of pure lazyness.
*/
#define CHKO(x) case B_##x: \
if (check_overlay_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define CHKA(x) case B_##x: \
if (check_acc_capability(B_##x) == B_OK) return (void *)x; else return (void *)0
#define HOOK(x) case B_##x: return (void *)x
#define ZERO(x) case B_##x: return (void *)0
#define HRDC(x) case B_##x: return si->settings.hardcursor? (void *)x: (void *)0; // apsed
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
void * get_accelerant_hook(uint32 feature, void *data)
{
switch (feature)
{
/*
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
subsequently called before any other hook is requested. All other feature
hook selections can be predicated on variables assigned during the accelerant
initialization process.
*/
/* initialization */
HOOK(INIT_ACCELERANT);
HOOK(CLONE_ACCELERANT);
@@ -67,7 +70,7 @@ initialization process.
HOOK(SET_DPMS_MODE);
/* cursor managment */
HRDC(SET_CURSOR_SHAPE); // apsed
HRDC(SET_CURSOR_SHAPE);
HRDC(MOVE_CURSOR);
HRDC(SHOW_CURSOR);
@@ -79,6 +82,13 @@ initialization process.
HOOK(GET_SYNC_TOKEN);
HOOK(SYNC_TO_TOKEN);
/*
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth for example.
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export video overlay functions if card is capable of it */
CHKO(OVERLAY_COUNT);
CHKO(OVERLAY_SUPPORTED_SPACES);
@@ -90,31 +100,36 @@ initialization process.
CHKO(RELEASE_OVERLAY);
CHKO(CONFIGURE_OVERLAY);
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
*/
/* 2D acceleration */
HOOK(SCREEN_TO_SCREEN_BLIT);
HOOK(FILL_RECTANGLE);
HOOK(INVERT_RECTANGLE);
HOOK(FILL_SPAN);
HOOK(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);//remove for pre R5
/*
When requesting an acceleration hook, the calling application provides a
pointer to the display_mode for which the acceleration function will be used.
Depending on the engine architecture, you may choose to provide a different
function to be used with each bit-depth. In the sample driver we return
the same function all the time.
/*HOOK(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
Does the G400 support this? I can only think of using texture mapped rectangles, but these seem to have too many restrictions to do this:( e.g. I would need to blit offscreen, into texture format...
*/
#undef HOOK
#undef ZERO
Note: These hooks are re-acquired by the app_server after each mode switch.
*/
/* only export 2D acceleration functions in modes that are capable of it */
/* used by the app_server and applications (BWindowScreen) */
CHKA(SCREEN_TO_SCREEN_BLIT);
CHKA(FILL_RECTANGLE);
CHKA(INVERT_RECTANGLE);
CHKA(FILL_SPAN);
/* not (yet) used by the app_server:
* so just for application use (BWindowScreen) */
CHKA(SCREEN_TO_SCREEN_TRANSPARENT_BLIT);
//CHKA(SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT;
}
/*
Return a null pointer for any feature we don't understand.
*/
/* Return a null pointer for any feature we don't understand. */
return 0;
}
#undef CHKO
#undef CHKA
#undef HOOK
#undef ZERO
#undef HRDC
status_t check_overlay_capability(uint32 feature)
{
@@ -155,21 +170,71 @@ status_t check_overlay_capability(uint32 feature)
break;
}
switch(si->ps.card_type)
if (si->ps.card_type >= G200)
{
case G200:
case G400:
case G400MAX:
case G450: /* is also G550 in accelerant for now */
case G550: /* not used in accelerant yet */
/* export video overlay functions */
LOG(4, ("Overlay: Exporting hook %s.\n", msg));
return B_OK;
}
/* do not export video overlay functions */
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
return B_ERROR;
}
status_t check_acc_capability(uint32 feature)
{
bool fill = false;
char *msg = "";
/* setup logmessage text */
switch (feature)
{
case B_SCREEN_TO_SCREEN_BLIT:
msg = "B_SCREEN_TO_SCREEN_BLIT";
break;
case B_FILL_RECTANGLE:
msg = "B_FILL_RECTANGLE";
fill = true;
break;
case B_INVERT_RECTANGLE:
msg = "B_INVERT_RECTANGLE";
fill = true;
break;
case B_FILL_SPAN:
msg = "B_FILL_SPAN";
fill = true;
break;
case B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT:
msg = "B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT";
break;
case B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT:
msg = "B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT";
break;
default:
/* do not export video overlay functions */
LOG(4, ("Overlay: Not exporting hook %s.\n", msg));
return B_ERROR;
msg = "UNKNOWN";
break;
}
/* hardware acceleration is only supported in modes with upto a certain
* memory pitch.. */
if (si->acc_mode)
{
/* see if we support hardware rectangle fills in the current mode:
* the Matrox card's acc engine can adress upto 16Mbyte memory for this cmd! */
if (fill &&
((si->fbc.bytes_per_row * si->dm.virtual_height) > (16 * 1024 * 1024)))
{
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
return B_ERROR;
}
LOG(4, ("Acc: Exporting hook %s.\n", msg));
return B_OK;
}
else
{
LOG(4, ("Acc: Not exporting hook %s.\n", msg));
return B_ERROR;
}
}
@@ -4,7 +4,7 @@
Other authors:
Mark Watson,
Rudolf Cornelissen 10/2002.
Rudolf Cornelissen 10/2002-3/2003.
*/
#define MODULE_BIT 0x00800000
@@ -40,7 +40,8 @@ static status_t init_common(int the_fd) {
goto error0;
}
// LOG is now available, si !NULL
LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d\n", si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios));
LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, greensync %d\n",
si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync));
/*Check for R4.5.0 and if it is running, use work around*/
{
@@ -151,8 +152,11 @@ status_t INIT_ACCELERANT(int the_fd) {
info in a frame_buffer_config structure to make it convienient to return
to the app_server later.
*/
//don't reserve memory at the start of the fb, because this doesn't work on the G100 (no SRCORG/DSTORG)
pointer_reservation = si->settings.hardcursor? 1024: 0; // apsed TODO with G100, see before
pointer_reservation = 0;
/* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */
if ((si->ps.card_type >= G100) && si->settings.hardcursor)
pointer_reservation = 1024;
si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
@@ -260,6 +264,8 @@ status_t CLONE_ACCELERANT(void *data) {
if (result < B_OK) goto error2;
/* all done */
LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
result = B_OK;
goto error0;
@@ -273,7 +279,13 @@ error0:
return result;
}
void UNINIT_ACCELERANT(void) {
void UNINIT_ACCELERANT(void)
{
if (accelerantIsClone)
LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
else
LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
/*delete benaphore*/
DELETE_BEN(si->engine.lock);
DELETE_BEN(si->overlay.lock);
+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:
* BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
@@ -106,6 +106,9 @@ const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint
/* check if slopspace is needed: compatible settings choosen for now:
* G200 can do with ~0x0003 while > G200 need ~x0007.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
/* fixme: update needed for DVDmax support to adhere to CRTC2 constraints:
* case display_mode == B_RGB16: multiple = 32
* case display_mode == B_RGB32: multiple = 16 */
if (width == (width & ~0x0007))
{
si->overlay.myBuffer[offset].width = width;
@@ -4,7 +4,7 @@
Other authors for MGA driver:
Mark Watson,
Rudolf Cornelissen 9/2002
Rudolf Cornelissen 9/2002-4/2003
*/
#define MODULE_BIT 0x00400000
@@ -12,7 +12,8 @@
#include "acc_std.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS)
/* mode flags will be setup as status info by PROPOSEMODE! */
#define MODE_FLAGS 0
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
/*some monitors only handle a fixed set of modes*/
@@ -36,8 +37,8 @@ static const display_mode mode_list[] = {
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1550, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 120000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
{ { 120000, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
{ { 108000, 1280, 1328, 1440, 1680, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
@@ -50,56 +51,32 @@ static const display_mode mode_list[] = {
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
};
// apsed, adjust virtual width for CRTC offset constraints
// PB with MIl2 800*600 with bpp < 32
static status_t adjust_width (display_mode *target, bool want_same_width)
{
uint32 video_pitch = target->virtual_width;
uint32 multiple;
if (si->ps.card_type < G100) switch (target->space & 0x0fff) { // MIL2
case B_CMAP8: multiple = 128; break;
case B_RGB15: multiple = 64; break;
case B_RGB16: multiple = 64; break;
case B_RGB24: multiple = 128; break;
case B_RGB32: multiple = 32; break;
default:
LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
} else switch (target->space & 0x0fff) { // G100, G200, G400
case B_CMAP8: multiple = 16; break;
case B_RGB15: multiple = 8; break;
case B_RGB16: multiple = 8; break;
case B_RGB24: multiple = 16; break;
case B_RGB32: multiple = 4; break;
default:
LOG(8,("PROPOSEMODE: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
video_pitch = (video_pitch+multiple-1)/multiple;
video_pitch *= multiple;
if (target->virtual_width != video_pitch) {
LOG(2,("PROPOSEMODE: color space 0x%08x, virtual_width %d adjusted to %d \n",
target->space, target->virtual_width, video_pitch));
target->virtual_width = video_pitch;
if (want_same_width) target->timing.h_display = video_pitch;
}
return B_OK;
}
/*Check mode is between low and high limits
returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
/*
Check mode is between low and high limits
returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
*/
/* BOUNDS WARNING:
* BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE. It's called by the OS with target, low and high set to
* have the same settings for BWindowScreen!
* Which means we should not return B_BAD_VALUE on anything except for deviations on:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
*/
/* Note:
* The target mode should be modified to correspond to the mode as it can be made. */
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
status_t status;
status_t status = B_OK;
float pix_clock_found;
uint8 m,n,p;
status_t result = B_OK;
uint32 row_bytes, limit_clock, max_vclk;
status_t result;
uint32 max_vclk, row_bytes, pointer_reservation;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
(
(double)target->timing.h_total *
@@ -109,9 +86,8 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
want_same_width = target->timing.h_display == target->virtual_width,
want_same_height = target->timing.v_display == target->virtual_height;
// // apsed, adjust virtual width for CRTC offset constraints
// status = adjust_width (target, want_same_width);
// if (status != B_OK) return status;
LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
target->virtual_width, target->virtual_height));
/*check valid list:
if (VALID_REQUIRED is set)
@@ -132,6 +108,8 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
int closest_mode_ptr;
uint32 closest_mode_clock;
LOG(1, ("PROPOSEMODE: valid mode required!\n"));
closest_mode_ptr = 0xbad;
closest_mode_clock = 0;
for (i=0;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*/
{
LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
return B_ERROR;
}
else
{
target->timing=valid_mode_list[closest_mode_ptr];
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
(
(double)target->timing.h_total *
(double)target->timing.v_total
);
((double)target->timing.h_total * (double)target->timing.v_total);
}
}
#endif
@@ -175,113 +151,149 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
&target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
&target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
);
if (result == B_ERROR) return result;
/*check if timing found is within the requested horizontal limits*/
if (
(target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total)
) result = B_BAD_VALUE;
/*check if timing found is within the requested vertical limits*/
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.v_sync_start) || // apsed
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
) result = B_BAD_VALUE;
//rudolf
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
if (si->ps.card_type >= G100)
if (result == B_ERROR)
{
/* calculate settings, but do not actually test anything (that costs too much time!) */
status = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
return result;
}
else
{
//fixme: implement pixelclock limits check (and modify if needed) for target mode inside mil2_find routine!
//temp until then:
limit_clock = si->ps.max_dac1_clock * 1000;
if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock;
status = mil2_dac_pix_pll_find((float)target->timing.pixel_clock/1000.0,&pix_clock_found,&m,&n,&p);
}
target->timing.pixel_clock = pix_clock_found*1000;
//end rudolf
/* note if we fell outside the limits */
if (
(target->timing.pixel_clock < low->timing.pixel_clock) ||
(target->timing.pixel_clock > high->timing.pixel_clock)
) result = B_BAD_VALUE;
/* validate display vs. virtual */
if ((target->timing.h_display > target->virtual_width) || want_same_width)
target->virtual_width = target->timing.h_display;
if ((target->timing.v_display > target->virtual_height) || want_same_height)
target->virtual_height = target->timing.v_display;
if (target->virtual_width > 4096)
target->virtual_width = 4096;
if (target->virtual_height > 2048)
target->virtual_height = 2048;
/* adjust virtual width for engine limitations - must be multiple of 8 */
target->virtual_width = (target->virtual_width + 7) & ~7;
if (
(target->virtual_width < low->virtual_width) ||
(target->virtual_width > high->virtual_width)
) result = B_BAD_VALUE;
// apsed, adjust virtual width for CRTC offset constraints
status = adjust_width (target, want_same_width);
if (status != B_OK) return status;
/* calculate rowbytes after we've nailed the virtual width */
switch (target->space & 0x0fff) {
case B_CMAP8:
row_bytes = 1;
break;
case B_RGB15:
case B_RGB16:
row_bytes = 2;
break;
case B_RGB32:
row_bytes = 4;
break;
default:
/* no amount of adjusting will fix not being able to support the pixel format */
LOG(8,("PROPOSEMODE: unknown target space: 0x%08x\n", target->space));
return B_ERROR;
/* nail virtual size and 'subsequently' calculate rowbytes */
result = gx00_general_validate_pic_size (target, &row_bytes);
if (result == B_ERROR)
{
LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
return result;
}
row_bytes *= target->virtual_width;
/*check if virtual_width is still within the requested limits*/
if ((target->virtual_width < low->virtual_width) ||
(target->virtual_width > high->virtual_width))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
}
/*check if timing found is within the requested horizontal limits*/
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display) ||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
(target->timing.h_total < low->timing.h_total) ||
(target->timing.h_total > high->timing.h_total))
{
/* BWindowScreen workaround: we accept everything except h_display deviations */
if ((target->timing.h_display < low->timing.h_display) ||
(target->timing.h_display > high->timing.h_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
}
/*check if timing found is within the requested vertical limits*/
if (
(target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display) ||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
(target->timing.v_sync_start > high->timing.v_sync_start) ||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
(target->timing.v_total < low->timing.v_total) ||
(target->timing.v_total > high->timing.v_total)
)
{
/* BWindowScreen workaround: we accept everything except v_display deviations */
if ((target->timing.v_display < low->timing.v_display) ||
(target->timing.v_display > high->timing.v_display))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
}
/* adjust pixelclock for possible timing modifications done above */
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
/* Now find the nearest valid pixelclock we actually can setup for the target mode,
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
/* calculate settings, but do not actually test anything (that costs too much time!) */
result = gx00_dac_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
/* update the target mode */
target->timing.pixel_clock = (pix_clock_found * 1000);
/* note if we fell outside the limits */
if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
(target->timing.pixel_clock > high->timing.pixel_clock)
)
{
/* BWindowScreen workaround: we accept deviations <= 1Mhz */
if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
(target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
{
status = B_BAD_VALUE;
}
else
{
status = B_OK;
}
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
}
/* checkout space needed for hardcursor (if any) */
pointer_reservation = 0;
/* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */
if ((si->ps.card_type >= G100) && si->settings.hardcursor) pointer_reservation = 1024;
/* memory requirement for frame buffer */
if ((row_bytes * target->virtual_height) > (si->ps.memory_size * 1024 * 1024))
target->virtual_height = (si->ps.memory_size * 1024 * 1024) / row_bytes;
if ((row_bytes * target->virtual_height) >
((si->ps.memory_size * 1024 * 1024) - pointer_reservation))
{
target->virtual_height =
((si->ps.memory_size * 1024 * 1024) - pointer_reservation) / row_bytes;
}
if (target->virtual_height < target->timing.v_display)
{
LOG(8,("PROPOSEMODE: virtual_height required %d < %d\n", target->virtual_height, target->timing.v_display));
LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
return B_ERROR;
}
else if (
(target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height)
) result = B_BAD_VALUE;
LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
target->virtual_width, target->virtual_height));
if ((target->virtual_height < low->virtual_height) ||
(target->virtual_height > high->virtual_height))
{
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
}
/* setup status flags */
LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
/* preset to singlehead card without TVout, no overlay support and no hardcursor.
* also advice system that app_server and acc engine may touch the framebuffer
* simultaneously (fixed). */
target->flags &=
~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
/* we always allow parallel access (fixed), the DAC is always in 'enhanced'
* mode (fixed), and all modes support DPMS (fixed);
* We support scrolling and panning in every mode, so we 'send a signal' to
* BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
//fixme: secondary head does not support DPMS...
target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
/* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
switch (target->space)
@@ -305,43 +317,68 @@ status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, con
break;
}
/*clear DUALHEAD_CAPABLE if any problems*/
if
(
((target->flags)& DUALHEAD_CAPABLE ) &&
(
(!si->ps.secondary_head) ||
((1024 + (row_bytes * (target->virtual_height+1) * 2)) > (si->ps.memory_size * 1024 * 1024)) || /*note: extra line for maven vblank!*/
(target->space == B_CMAP8) ||
(target->space == B_RGB15_LITTLE) ||
(target->timing.pixel_clock > (max_vclk * 1000))
)
)
/* set DUALHEAD_CAPABLE if suitable */
//fixme: update for independant secondary head use! (reserve fixed memory then)
if (si->ps.secondary_head &&
(((si->ps.memory_size * 1024 * 1024) - pointer_reservation) >=
/* note: extra line for maven vblank included here! */
(row_bytes * (target->virtual_height + 1) * 2)) &&
((target->space == B_RGB16_LITTLE) || (target->space == B_RGB32_LITTLE)) &&
(target->timing.pixel_clock <= (max_vclk * 1000)))
{
target->flags&=~DUALHEAD_CAPABLE;
target->flags |= DUALHEAD_CAPABLE;
}
/*set tv capable suitable*/
if (target->flags&DUALHEAD_CAPABLE)
/* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
//fixme: modify for G100 and G200 TVout later on...
if (target->flags & DUALHEAD_CAPABLE)
{
if ((target->timing.pixel_clock <= 120000 ) && (target->timing.pixel_clock >= 40000))
if (si->ps.secondary_tvout &&
(target->timing.h_display <= 1024) &&
(target->timing.v_display <= 768))
{
target->flags|=TV_CAPABLE;
target->flags |= TV_CAPABLE;
}
}
return result;
/* set HARDWARE_CURSOR mode if suitable */
if (si->settings.hardcursor)
target->flags |= B_HARDWARE_CURSOR;
/* set SUPPORTS_OVERLAYS if suitable */
if (si->ps.card_type >= G200)
target->flags |= B_SUPPORTS_OVERLAYS;
LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
/* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
* progressive scan (fixed), and setup sync_on_green flag according to
* mga.settings options file */
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
if (si->settings.greensync)
target->timing.flags |= B_SYNC_ON_GREEN;
/* The HSYNC and VSYNC command flags are actually executed by the driver. */
if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
return status;
}
/* Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff)
*/
uint32 ACCELERANT_MODE_COUNT(void) {
uint32 ACCELERANT_MODE_COUNT(void)
{
LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
return si->mode_count;
}
/* Copy the list of guaranteed supported video modes to the location provided.*/
status_t GET_MODE_LIST(display_mode *dm) {
status_t GET_MODE_LIST(display_mode *dm)
{
LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK;
}
@@ -366,7 +403,7 @@ status_t create_mode_list(void) {
max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
/* create an area to hold the info */
si->mode_area = my_mode_list_area =
create_area("G400 accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
create_area("MGA accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (my_mode_list_area < B_OK) return my_mode_list_area;
/* walk through our predefined list and see which modes fit this device */
@@ -380,22 +417,25 @@ status_t create_mode_list(void) {
pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
/* some cards need wider virtual widths for certain modes */
high.virtual_width = 4096;
/* 'some cards need wider virtual widths for certain modes':
* Not true. They might need a wider pitch, but this is _not_ reflected in
* virtual_width, but in fbc.bytes_per_row. */
//So disable next line:
//high.virtual_width = 4096;
/* do it once for each depth we want to support */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
{
/* set target values for single head (propose will return if capable)*/
/* set target values */
*dst = *src;
/* poke the specific space*/
/* poke the specific space */
dst->space = low.space = high.space = spaces[j];
dst->flags |= DUALHEAD_CAPABLE;
dst->flags |= B_SUPPORTS_OVERLAYS;
//fixme: we need to distinquish somehow between head 1 and head 2, as overlay only works on head 1...
/* ask for a compatible mode */
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
/* We have to check for B_OK, because otherwise the pix_clk_range
* won't be taken into account!! */
//So don't do this:
//if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
//Instead, do this:
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
/* count it, and move on to next mode */
dst++;
si->mode_count++;
+196 -223
View File
@@ -5,15 +5,13 @@
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 11-12/2002
Rudolf Cornelissen 11/2002-4/2003
*/
#define MODULE_BIT 0x00200000
#include "acc_std.h"
#include "matroxfb_maven_hack.h" //a port of the matroxfb code to do TVout - used with permission
/*
Enable/Disable interrupts. Just a wrapper around the
ioctl() to the kernel driver.
@@ -32,155 +30,188 @@ static void interrupt_enable(bool flag) {
/* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
display_mode bounds, target;
/* BOUNDS WARNING:
* It's impossible to deviate whatever small amount in a display_mode if the lower
* and upper limits are the same!
* Besides:
* BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE!
* Which means PROPOSEMODE should not return that on anything except on
* deviations for:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
* So:
* We don't use bounds here by making sure bounds and target are the same struct!
* (See the call to PROPOSE_DISPLAY_MODE below) */
display_mode /*bounds,*/ target;
uint8 colour_depth=32;
uint8 colour_depth1 = 32;
status_t result;
uint32 startadd,startadd_right;
// apsed TODO startadd is 19 bits if < g200
uint8 display,h,v;
struct my_timming tv_timing;
struct mavenregs tv_regs;
bool switched_crtcs = false;
si->switched_crtcs = false;
/* Adjust mode to valid one and fail if invalid */
target = bounds = *mode_to_set;
target /*= bounds*/ = *mode_to_set;
/* show the mode bits */
LOG(1, ("SetDisplayMode - initial flags: %x\n", target.flags));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "timing.pixel_clock", mode_to_set->timing.pixel_clock, mode_to_set->timing.pixel_clock));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_width", mode_to_set->virtual_width, mode_to_set->virtual_width));
LOG(1, ("SetDisplayMode - %20s %08x %d\n", "virtual_height", mode_to_set->virtual_height, mode_to_set->virtual_height));
LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
target.virtual_width, target.virtual_height));
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR)
return B_ERROR;
/* See BOUNDS WARNING above... */
if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
/* if not dualhead capable be sure mode is set to single head */
if ((!si->ps.secondary_head) || (!(target.flags&DUALHEAD_CAPABLE)))
/* if not dualhead capable card clear dualhead flags */
if (!(target.flags & DUALHEAD_CAPABLE))
{
target.flags&=~DUALHEAD_BITS;
target.flags&=~TV_BITS;
target.flags &= ~DUALHEAD_BITS;
}
else if (!(target.flags&TV_CAPABLE))
/* if not TVout capable card clear TVout flags */
if (!(target.flags & TV_CAPABLE))
{
target.flags&=~TV_BITS;
target.flags &= ~TV_BITS;
}
LOG(1, ("SetDisplayMode - validated flags: %x\n", target.flags));
LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
/* disable interrupts using the kernel driver */
interrupt_enable(false);
/*find current DPMS state, then turn off screen*/
/* find current DPMS state, then turn off screen(s) */
gx00_crtc_dpms_fetch(&display,&h,&v);
gx00_crtc_dpms(0,0,0);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
/*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
startadd=(si->fbc.frame_buffer)-(si->framebuffer);
startadd = si->fbc.frame_buffer - si->framebuffer;
/* calculate and set new mode bytes_per_row */
gx00_general_validate_pic_size (&target, &si->fbc.bytes_per_row);
/*Perform the very long mode switch!*/
LOG(1,("DUALHEAD: %d\n",target.flags&DUALHEAD_BITS));
if ((target.flags&DUALHEAD_BITS)) /*if some dualhead mode*/
if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
{
uint16 crtc1_vdisplay, crtc2_vdisplay;
uint8 colour_depth2 = colour_depth1;
/*set the pixel clock PLL(s)*/
if (gx00_dac_set_pix_pll(target)==B_ERROR)
LOG(8,("SET: error setting pixel clock (internal DAC)\n"));
if (si->ps.secondary_head)
/* init display mode for secondary head */
display_mode target2 = target;
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
/* validate flags for secondary TVout */
if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
{
if (gx00_maven_set_pix_pll((target.timing.pixel_clock)/1000.0)==B_ERROR)
LOG(8,("SET: error setting pixel clock (MAVEN)\n"));
}
else
{
LOG(8,("SET: not setting maven clock (G450?)\n"));
target.flags &= ~TV_BITS;//still needed for some routines...
target2.flags &= ~TV_BITS;
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
}
/*set the colour depth for CRTC1, CRTC2, the DAC and the MAVEN */
/* set the pixel clock PLL(s) */
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
if (gx00_dac_set_pix_pll(target) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
/* we do not need to set the pixelclock here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS))
{
LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
if (gx00_maven_set_vid_pll(target2) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
}
/*set the colour depth for CRTC1 and the DAC */
switch(target.space)
{
case B_RGB16_LITTLE:
colour_depth=16;
colour_depth1 = 16;
gx00_dac_mode(BPP16, 1.0);
gx00_maven_mode(BPP16, 1.0);
gx00_crtc_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth1 = 32;
gx00_dac_mode(BPP32, 1.0);
gx00_crtc_depth(BPP32);
break;
}
/*set the colour depth for CRTC2 and the MAVEN */
switch(target2.space)
{
case B_RGB16_LITTLE:
colour_depth2 = 16;
gx00_maven_mode(BPP16, 1.0);
g400_crtc2_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth=32;
gx00_dac_mode(BPP32, 1.0);
colour_depth2 = 32;
gx00_maven_mode(BPP32DIR, 1.0);
gx00_crtc_depth(BPP32);
g400_crtc2_depth(BPP32DIR);
break;
default:
LOG(8,("SET: Invalid dualhead colour depth 0x%08x - should never happen!\n", target.space));
}
/* check if we are doing interlaced TVout mode */
si->interlaced_tv_mode = false;
if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
si->interlaced_tv_mode = true;
/*set the display(s) pitches*/
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth);
g400_crtc2_set_display_pitch (target.virtual_width, colour_depth);
gx00_crtc_set_display_pitch ();
//fixme: seperate for real dualhead modes:
//we need a secondary si->fbc!
g400_crtc2_set_display_pitch ();
/*work out where the "right" screen starts*/
startadd_right=startadd+(target.timing.h_display*(colour_depth>>3));
startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3));
/* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */
si->crtc_delay = 44 + 0 * (colour_depth == 16);
si->crtc_delay = 44 + 0 * (colour_depth2 == 16);
/* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */
crtc1_vdisplay = target.timing.v_display;
/* (extra "blanking" line for MAVEN) */
crtc2_vdisplay = target.timing.v_display + 1;
target2.timing.v_display++;
/* set the outputs */
switch (si->ps.card_type)
{
case G400:
case G400MAX:
switch (target.flags&DUALHEAD_BITS)
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
switched_crtcs = false;
si->switched_crtcs = false;
break;
case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK)
{
/* Don't switch CRTC's because MAVEN YUV is impossible then,
* and primary head output will be limited to 135Mhz pixelclock. */
LOG(4,("SET: secondary TV-adapter detected, switching buffers\n"));
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
switched_crtcs = true;
si->switched_crtcs = true;
}
else
{
/* This limits the pixelclocks on both heads to 135Mhz,
* but you can use overlay on the other output now. */
LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n"));
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
gx00_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC);
switched_crtcs = false;
si->switched_crtcs = false;
/* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
si->crtc_delay = 17 + 4 * (colour_depth == 16);
si->crtc_delay = 17 + 4 * (colour_depth1 == 16);
/* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */
/* (extra "blanking" line for MAVEN) */
crtc1_vdisplay = target.timing.v_display + 1;
crtc2_vdisplay = target.timing.v_display;
target.timing.v_display++;
target2.timing.v_display--;
}
break;
}
break;
//fixme:
//use current SETMODE MAVEN programming only on G400/G400MAX;
//and copy & modify/resetup this stuff for G450(?)/G550 cards!
//warning:
//setup crtc_delay and vertical timing adjust for G450(?)/G550,
//and remove the '+1' in crtc2 vertical timing(?)
case G450:
@@ -189,29 +220,29 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
/* output connector use is always 'straight-through' */
//fixme: re-evaluate when DVI is setup...
{
switch (target.flags&DUALHEAD_BITS)
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false;
si->switched_crtcs = false;
break;
case DUALHEAD_SWITCH:
if (i2c_sec_tv_adapter() == B_OK)
{
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */
LOG(4,("SET: secondary TV-adapter detected, switching buffers\n"));
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = true;
si->switched_crtcs = true;
}
else
{
/* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */
LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n"));
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
switched_crtcs = false;
si->switched_crtcs = false;
}
break;
}
@@ -220,21 +251,21 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
/* output connector use is cross-linked if no TV cable connected! */
//fixme: re-evaluate when DVI is setup...
{
switch (target.flags&DUALHEAD_BITS)
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_CLONE:
if (i2c_sec_tv_adapter() == B_OK)
{
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false;
si->switched_crtcs = false;
}
else
{
/* This limits the pixelclocks on both heads to 235Mhz,
* but you can use overlay on the other output now. */
gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
switched_crtcs = false;
si->switched_crtcs = false;
}
break;
case DUALHEAD_SWITCH:
@@ -242,15 +273,15 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
* and primary head output will be limited to 235Mhz pixelclock. */
LOG(4,("SET: secondary TV-adapter detected, switching buffers\n"));
LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = true;
si->switched_crtcs = true;
}
else
{
LOG(4,("SET: no secondary TV-adapter detected, switching CRTCs\n"));
LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
switched_crtcs = false;
si->switched_crtcs = false;
}
break;
}
@@ -260,149 +291,87 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
break;
}
if (switched_crtcs)
if (si->switched_crtcs)
{
int temp = startadd;
uint32 temp = startadd;
startadd = startadd_right;
startadd_right = temp;
}
/*Tell card what memory to display*/
switch (target.flags&DUALHEAD_BITS)
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth);
gx00_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd_right,colour_depth2);
break;
case DUALHEAD_CLONE:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
gx00_crtc_set_display_start(startadd,colour_depth1);
g400_crtc2_set_display_start(startadd,colour_depth2);
break;
}
/*set the timing*/
/* set the timing */
result = gx00_crtc_set_timing /*crtc1*/
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
crtc1_vdisplay,
target.timing.v_display,
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
/* we do not need to setup CRTC2 here for a head that's in TVout mode */
if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2);
result = g400_crtc2_set_timing
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
crtc2_vdisplay,
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
if (si->ps.secondary_head)
/* TVout support: setup CRTC2 and it's pixelclock */
if (si->ps.secondary_tvout && (target2.flags & TV_BITS))
{
result = gx00_maven_set_timing /*maven*/
(
target.timing.h_display,
target.timing.h_sync_start,
target.timing.h_sync_end,
target.timing.h_total,
(target.timing.v_display+1), /* The extra "blanking" line */
target.timing.v_sync_start,
target.timing.v_sync_end,
target.timing.v_total,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC
);
}
/*turn screen one on and screen two on*/
gx00_crtc_dpms(display,h,v);
g400_crtc2_dpms(display,h,v);
if (si->ps.secondary_head)
gx00_maven_dpms(display,h,v);
/*TVout support*/
if (si->ps.secondary_tvout && (target.flags&TV_BITS))
{
//fixme: re-tune if needed, checkout cross and straight crtc's seperately..
si->crtc_delay+=5;
/*create a my tim(m)ing structure... for tvout*/
tv_timing.pixclock = target.timing.pixel_clock;
tv_timing.HDisplay = target.timing.h_display;
tv_timing.HSyncStart = target.timing.h_sync_start;
tv_timing.HSyncEnd = target.timing.h_sync_end;
tv_timing.HTotal = target.timing.h_total;
tv_timing.VDisplay = target.timing.v_display;
tv_timing.VSyncStart = target.timing.v_sync_start;
tv_timing.VSyncEnd = target.timing.v_sync_end;
tv_timing.VTotal = target.timing.v_total;
tv_timing.delay=si->crtc_delay;
if (target.flags&TV_PAL)
{
LOG(2, ("OUTMODE: PAL\n"));
maven_set_mode(1);
}
else
{
LOG(2, ("OUTMODE: NTSC\n"));
maven_set_mode(2);
}
maven_out_compute(&tv_timing, &tv_regs);
maven_out_program(&tv_regs);
maven_out_start();
si->crtc_delay += 5;
maventv_init(target2);
}
}
else /*single head mode*/
else /* single head mode */
{
status_t status;
int colour_mode = BPP32;
int colour_mode = BPP32;
switch(target.space)
{
case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth = 32; colour_mode = BPP32; break;
case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
default:
LOG(8,("SET: Invalid singlehead colour depth 0x%08x\n", target.space));
LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
return B_ERROR;
}
/*set the pixel clock PLL*/
/* set the pixel clock PLL */
if (si->ps.card_type >= G100)
status = gx00_dac_set_pix_pll(target);
else status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth);
else
{
status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth1);
}
if (status==B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
/*set the colour depth for CRTC1 and the DAC*/
if (si->ps.card_type >= G100) gx00_dac_mode(colour_mode,1.0);
else mil2_dac_mode(colour_mode,1.0,
target.timing.flags&B_POSITIVE_HSYNC,
target.timing.flags&B_POSITIVE_VSYNC,
target.timing.flags&B_SYNC_ON_GREEN);
/* set the colour depth for CRTC1 and the DAC */
gx00_dac_mode(colour_mode,1.0);
gx00_crtc_depth(colour_mode);
/*set the display pitch*/
gx00_crtc_set_display_pitch (target.virtual_width, colour_depth);
/* set the display pitch */
gx00_crtc_set_display_pitch();
/* tell the card what memory to display */
gx00_crtc_set_display_start(startadd,colour_depth1);
/*tell the card what memory to display*/
gx00_crtc_set_display_start(startadd,colour_depth);
/* enable primary analog output */
switch (si->ps.card_type)
{
@@ -421,7 +390,7 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
break;
}
/*set the timing*/
/* set the timing */
result = gx00_crtc_set_timing /*crtc1*/
(
target.timing.h_display,
@@ -436,33 +405,32 @@ status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
target.timing.flags&B_POSITIVE_VSYNC
);
/*turn screen one on and screen two off*/
gx00_crtc_dpms(display,h,v);
if (si->ps.card_type >= G400) // apsed TODO when g200 pixrdmsk is broken
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
//fixme: shut-off the videoPLL if it exists...
}
/*update driver's mode store*/
si->dm=target;
si->fbc.bytes_per_row=target.virtual_width*(colour_depth>>3);
/* update driver's mode store */
si->dm = target;
/*set up acceleration for this mode*/
si->dm.virtual_height+=1;//for clipping!
/* turn screen one on */
gx00_crtc_dpms(display,h,v);
/* turn screen two on if a dualhead mode is active */
if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v);
/* set up acceleration for this mode */
si->dm.virtual_height += 1;//for clipping!
gx00_acc_init();
si->dm.virtual_height-=1;
si->dm.virtual_height -= 1;
/*clear line at bottom of screen (For maven) if dualhead mode*/
/* clear line at bottom of screen (for maven) if dualhead mode */
gx00_acc_rectangle(0,si->dm.virtual_width+1,si->dm.virtual_height,1,0);
MSG(("INIT_ACCELERANT: booted since %f ms\n", system_time()/1000.0));
MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0));
/* enable interrupts using the kernel driver */
interrupt_enable(true);
/* optimize memory-access if needed */
gx00_crtc_mem_priority(colour_depth);
gx00_crtc_mem_priority(colour_depth1);
/* Tune RAM CAS-latency if needed. Must be done *here*! */
mga_set_cas_latency();
@@ -486,7 +454,7 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
*/
/* reset lower bits, don't return an error! */
if (si->dm.flags&DUALHEAD_BITS)
if (si->dm.flags & DUALHEAD_BITS)
{
switch(si->dm.space)
{
@@ -525,8 +493,18 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
}
/* do not run past end of display */
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
default:
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
}
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR;
@@ -535,16 +513,26 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
si->dm.v_display_start = v_display_start;
/* actually set the registers */
startadd=v_display_start*(si->dm.virtual_width*colour_depth)>>3;
startadd+=h_display_start;
startadd+=(si->fbc.frame_buffer)-(si->framebuffer);
startadd_right=startadd+si->dm.timing.h_display*(colour_depth>>3);
//fixme: seperate both heads: we need a secondary si->fbc!
startadd = v_display_start * si->fbc.bytes_per_row;
startadd += h_display_start * (colour_depth >> 3);
startadd += si->fbc.frame_buffer - si->framebuffer;
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
/* account for switched CRTC's */
if (si->switched_crtcs)
{
uint32 temp = startadd;
startadd = startadd_right;
startadd_right = temp;
}
interrupt_enable(false);
switch (si->dm.flags&DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd_right,colour_depth);
break;
@@ -555,10 +543,6 @@ status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
gx00_crtc_set_display_start(startadd,colour_depth);
g400_crtc2_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_SWITCH:
g400_crtc2_set_display_start(startadd,colour_depth);
gx00_crtc_set_display_start(startadd_right,colour_depth);
break;
}
interrupt_enable(true);
@@ -587,8 +571,7 @@ void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags
b[i]=*color_data++;
i++;
}
if (si->ps.card_type >= G100) gx00_dac_palette(r,g,b);
else mil2_dac_palette(r,g,b);
gx00_dac_palette(r,g,b);
}
@@ -600,9 +583,7 @@ enum {
BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF
};
/*
Put the display into one of the Display Power Management modes.
*/
/* Put the display into one of the Display Power Management modes. */
status_t SET_DPMS_MODE(uint32 dpms_flags) {
interrupt_enable(false);
@@ -614,27 +595,19 @@ status_t SET_DPMS_MODE(uint32 dpms_flags) {
{
case B_DPMS_ON: /* H: on, V: on */
gx00_crtc_dpms(1,1,1);
g400_crtc2_dpms(1,1,1);
if (si->ps.secondary_head)
gx00_maven_dpms(1,1,1);
if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1);
break;
case B_DPMS_STAND_BY:
gx00_crtc_dpms(0,0,1);
g400_crtc2_dpms(0,0,1);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,1);
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1);
break;
case B_DPMS_SUSPEND:
gx00_crtc_dpms(0,1,0);
g400_crtc2_dpms(0,1,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,1,0);
if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0);
break;
case B_DPMS_OFF: /* H: off, V: off, display off */
gx00_crtc_dpms(0,0,0);
g400_crtc2_dpms(0,0,0);
if (si->ps.secondary_head)
gx00_maven_dpms(0,0,0);
if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
break;
default:
LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
@@ -5,7 +5,6 @@ UsePrivateHeaders [ FDirName graphics matrox ] ;
UseHeaders [ FDirName $(SUBDIR) .. ] ;
StaticLibrary matrox_engine :
matroxfb_maven_hack.c
mga_acc.c
mga_bes.c
mga_crtc.c
@@ -15,6 +14,7 @@ StaticLibrary matrox_engine :
mga_i2c.c
mga_info.c
mga_maven.c
mga_maventv.c
mga_support.c
tvp3026.c
;
@@ -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() ;
+136 -39
View File
@@ -1,7 +1,7 @@
/* MGA Acceleration functions */
/* Authors:
Mark Watson 2/2000,
Rudolf Cornelissen 10-12/2002
Rudolf Cornelissen 10/2002-4/2003.
*/
#define MODULE_BIT 0x00080000
@@ -10,7 +10,7 @@
/*acceleration notes*/
/*functions Be needs:
/*functions Be's app_server uses:
fill span (horizontal only)
fill rectangle (these 2 are very similar)
invert rectangle
@@ -19,12 +19,14 @@ blit
/* G100 pre SRCORG/DSTORG registers */
static uint32 src_dst;
/* MIL1/2 adress linearisation does not always work */
static uint8 y_lin;
static uint8 depth;
// needed by MIL2 in 800x600 8bpp
/* needed by MIL 1/2 because of adress linearisation constraints */
#define ACCW_YDSTLEN(dst, len) do { \
/* if (si->ylin) { */ \
if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) { \
ACCW(YDST,((dst)*si->dm.virtual_width) >> 5); \
if (y_lin) { \
ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \
ACCW(LEN,len); \
} else ACCW(YDSTLEN,((dst)<<16)|(len)); \
} while (0)
@@ -39,52 +41,120 @@ status_t gx00_acc_wait_idle()
return B_OK;
}
/*AFAIK this must be done for every new screenmode*/
/* AFAIK this must be done for every new screenmode.
* Engine required init. */
status_t gx00_acc_init()
{
ACCW(OPMODE,0); // cleanup bitblt
/* used for convenience: MACCESS is a write only register! */
uint32 maccess = 0x00000000;
/* if we were unable to read PINS, we have to assume something (keeping bit6 zero) */
if ((si->ps.card_type >= G450) && (si->ps.pins_status = B_OK))
{
/* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */
maccess |= ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1);
}
/* preset using hardware adress linearisation */
y_lin = 0x00;
/* reset depth */
depth = 0;
/* cleanup bitblt */
ACCW(OPMODE,0);
/* Set the Z origin to the start of FB (otherwise lockup on blits) */
if (si->ps.card_type>=G100) ACCW(ZORG,0);
ACCW(ZORG,0);
/* Set pixel width */
switch(si->dm.space)
{
case B_CMAP8:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x00));
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00));
depth = 8;
break;
case B_RGB15_LITTLE:case B_RGB16_LITTLE:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x01));
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01));
depth = 16;
break;
case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
ACCW(MACCESS, ((ACCR(MACCESS) & 0xfffffffc) | 0x02));
ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02));
depth = 32;
break;
default:
LOG(8,("ACC: init, invalid bit depth\n"));
return B_ERROR;
}
/*PITCH*/
// TODO apsed 3-129 32 or 64 following depth (or 128 if MIl2)
if (si->dm.virtual_width&0x1F)
/* setup PITCH: very cardtype specific! */
switch (si->ps.card_type)
{
LOG(8,("ACC: can not accelerate, pitch is not multiple of 32 pixels\n"));
return B_ERROR;
case MIL1:
switch (si->fbc.bytes_per_row / (depth >> 3))
{
case 640:
case 768:
case 800:
case 960:
case 1024:
case 1152:
case 1280:
case 1600:
case 1920:
case 2048:
/* we are using hardware adress linearisation */
break;
default:
/* we are using software adress linearisation */
y_lin = 0x01;
LOG(8,("ACC: using software adress linearisation\n"));
break;
}
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
case MIL2:
switch (si->fbc.bytes_per_row / (depth >> 3))
{
case 512:
case 640:
case 768:
case 800:
case 832:
case 960:
case 1024:
case 1152:
case 1280:
case 1600:
case 1664:
case 1920:
case 2048:
/* we are using hardware adress linearisation */
break;
default:
/* we are using software adress linearisation */
y_lin = 0x01;
LOG(8,("ACC: using software adress linearisation\n"));
break;
}
ACCW(PITCH, (y_lin << 15) | ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
case G100:
/* always using hardware adress linearisation, because 2D/3D
* engine works on every pitch multiple of 32 */
ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
break;
default:
/* G200 and up are equal.. */
/* always using hardware adress linearisation, because 2D/3D
* engine works on every pitch multiple of 32 */
ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF));
break;
}
if (si->ps.card_type>=G200)
ACCW(PITCH,(si->dm.virtual_width)&0x1FFF); /* use hardware Y decoding */
else
ACCW(PITCH,(si->dm.virtual_width)&0x0FFF); /* use hardware Y decoding */
if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
// ylin shall be 1 if 800x600
ACCW(PITCH, (1<<15) | (si->dm.virtual_width&0x0FFF));
}
/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
ACCW(PLNWT,0x00000000);
ACCW(PLNWT,0xffffffff);
if (si->ps.card_type>=G200) {
if (si->ps.card_type >= G200) {
/*DSTORG - location of active screen in framebuffer*/
ACCW(DSTORG,(si->fbc.frame_buffer)-(si->framebuffer));
@@ -92,11 +162,12 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
ACCW(SRCORG,(si->fbc.frame_buffer)-(si->framebuffer));
}
/* init YDSTORG - apsed, if not inited, BitBlts may fails on g200 */
/* init YDSTORG - apsed, if not inited, BitBlts may fails on <= G200 */
src_dst = 0;
ACCW(YDSTORG, src_dst);
/* G100 uses this register as SRCORG/DSTORG replacement */
/* <= G100 uses this register as SRCORG/DSTORG replacement, but
* MIL 1/2 does not need framebuffer space for the hardcursor! */
if ((si->ps.card_type == G100) && (si->settings.hardcursor))
{
switch (si->dm.space)
@@ -120,25 +191,27 @@ if ((si->ps.card_type==MIL2) && (si->dm.space==B_CMAP8)) {
/* clipping */
/* i.e. highest and lowest X pixel adresses */
ACCW(CXBNDRY,((si->dm.virtual_width - 1) << 16) | (0));
ACCW(CXBNDRY,(((si->fbc.bytes_per_row / (depth >> 3)) - 1) << 16) | (0));
/* Y pixel addresses must be linear */
/* lowest adress */
ACCW(YTOP, 0 + src_dst);
/* highest adress */
ACCW(YBOT,((si->dm.virtual_height - 1) * si->dm.virtual_width) + src_dst);
ACCW(YBOT,((si->dm.virtual_height - 1) *
(si->fbc.bytes_per_row / (depth >> 3))) + src_dst);
return B_OK;
}
/*screen to screen blit - i.e. move windows around*/
/* screen to screen blit - i.e. move windows around.
* Engine function bitblit, paragraph 4.5.7.2 */
status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
{
uint32 t_start,t_end,offset;
uint32 b_start,b_end;
/*find where the top,bottom and offset are*/
offset = si->dm.virtual_width;
offset = (si->fbc.bytes_per_row / (depth >> 3));
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
@@ -146,6 +219,9 @@ status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
@@ -189,12 +265,13 @@ status_t gx00_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h
ACCW(FXBNDRY,((xd+w)<<16)|xd);
/*do the blit*/
ACCGO(DWGCTL,0x040C4018);
ACCGO(DWGCTL,0x040C4018); // atype RSTR
return B_OK;
}
/*screen to screen tranparent blit - not sure what uses this...*/
/* screen to screen tranparent blit - not sure what uses this.
* Engine function bitblit, paragraph 4.5.7.2 */
status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
{
uint32 t_start,t_end,offset;
@@ -203,7 +280,7 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1
return B_ERROR;
/*find where the top,bottom and offset are*/
offset = si->dm.virtual_width;
offset = (si->fbc.bytes_per_row / (depth >> 3));
t_end = t_start = xs + (offset*ys) + src_dst;
t_end += w;
@@ -211,6 +288,9 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1
b_end = b_start = xs + (offset*(ys+h)) + src_dst;
b_end +=w;
/* sgnzero bit _must_ be '0' before accessing SGN! */
ACCW(DWGCTL,0x00000000);
/*find which quadrant */
switch((yd>ys)|((xd>xs)<<1))
{
@@ -256,11 +336,12 @@ status_t gx00_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint1
/*do the blit*/
ACCW(FCOL,colour);
ACCW(BCOL,0xffffffff);
ACCGO(DWGCTL,0x440C4018);
ACCGO(DWGCTL,0x440C4018); // atype RSTR
return B_OK;
}
/*rectangle fill*/
/* rectangle fill.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
@@ -276,6 +357,9 @@ status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
//acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode
// for other functions, and use fastblt on MIL1/2 if possible...
//or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?)
if (si->dm.space==B_CMAP8 || si->ps.sdram)
{
ACCGO(DWGCTL,0x400C7814); // atype RSTR
@@ -287,7 +371,8 @@ status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
return B_OK;
}
/*rectangle invert*/
/* rectangle invert.
* Engine function rectangle_fill: paragraph 4.5.5.2 */
/*colorIndex,fill_rect_params,count*/
status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
{
@@ -306,7 +391,8 @@ status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint3
ACCW_YDSTLEN(ys,yl); /*set y start and length*/
ACCW(FCOL,col); /*set colour*/
ACCGO(DWGCTL,0x40057814); /*draw it! top nibble is c is clipping enabled*/
/*draw it! top nibble is c is clipping enabled*/
ACCGO(DWGCTL,0x40057814); // atype RSTR
/*pseudo_dma version!*/
//MGAACC_DWGCTL =0x1C00,
@@ -339,3 +425,14 @@ status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint3
return B_OK;
}
/* screen to screen scaled filtered blit - i.e. scale video in memory.
* Engine function texture mapping for video, paragraphs 4.5.5.5 - 4.5.5.9 */
status_t gx00_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
uint16 xd,uint16 yd,uint16 wd,uint16 hd)
{
//fixme: implement. Used for G450/G550 Desktop TVout...
//fixme: see if MIL1 - G200 support this function as well...
return B_OK;
}
+47 -31
View File
@@ -1,10 +1,13 @@
/* G200-G550 Back End Scaler functions */
/* Written by Rudolf Cornelissen 05/11-2002 */
/* Written by Rudolf Cornelissen 05/2002-04/2003 */
#define MODULE_BIT 0x00000200
#include "mga_std.h"
//fixme: implement: (used for virtual screens!)
//void move_overlay(uint16 hdisp_start, uint16 vdisp_start);
status_t gx00_configure_bes
(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset)
{
@@ -29,7 +32,7 @@ status_t gx00_configure_bes
/* misc used variables */
uint16 temp1, temp2;
/* interval representation, used for scaling calculations */
uint16 intrep;
uint16 intrep, crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
/* inverse scaling factor, used for source positioning */
uint32 ifactor;
/* used for vertical weight starting value */
@@ -84,6 +87,20 @@ status_t gx00_configure_bes
LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
/* the BES does not respect virtual_workspaces, but adheres to CRTC
* constraints only */
crtc_hstart = si->dm.h_display_start;
/* make dualhead switch mode with TVout enabled work while we're at it.. */
if (si->switched_crtcs)
{
crtc_hstart += si->dm.timing.h_display;
}
/* horizontal end is the first position beyond the displayed range on the CRTC */
crtc_hend = crtc_hstart + si->dm.timing.h_display;
crtc_vstart = si->dm.v_display_start;
/* vertical end is the first position beyond the displayed range on the CRTC */
crtc_vend = crtc_vstart + si->dm.timing.v_display;
/****************************************
*** setup all edges of output window ***
@@ -93,22 +110,22 @@ status_t gx00_configure_bes
hcoordv = 0;
/* left edge coordinate of output window, must be inside desktop */
/* clipping on the left side */
if (ow->h_start < 0)
if (ow->h_start < crtc_hstart)
{
temp1 = 0;
}
else
{
/* clipping on the right side */
if (ow->h_start >= (si->dm.virtual_width - 1))
if (ow->h_start >= (crtc_hend - 1))
{
/* width < 2 is not allowed */
temp1 = (si->dm.virtual_width - 2) & 0x7ff;
temp1 = (crtc_hend - crtc_hstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (uint16)ow->h_start & 0x7ff;
temp1 = (ow->h_start - crtc_hstart) & 0x7ff;
}
}
hcoordv |= temp1 << 16;
@@ -121,14 +138,14 @@ status_t gx00_configure_bes
else
{
/* clipping on the right side */
if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1))
if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
{
temp2 = (si->dm.virtual_width - 1) & 0x7ff;
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
}
else
{
/* clipping on the left side */
if ((ow->h_start + ow->width - 1) < 1)
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
{
/* width < 2 is not allowed */
temp2 = 1;
@@ -136,33 +153,33 @@ status_t gx00_configure_bes
else
/* no clipping here */
{
temp2 = ((uint16)(ow->h_start + ow->width - 1)) & 0x7ff;
temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1)) & 0x7ff;
}
}
}
hcoordv |= temp2 << 0;
LOG(4,("Overlay: left-edge output %d, right-edge output %d\n",temp1, temp2));
LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
/* setup top and bottom edges of output window */
vcoordv = 0;
/* top edge coordinate of output window, must be inside desktop */
/* clipping on the top side */
if (ow->v_start < 0)
if (ow->v_start < crtc_vstart)
{
temp1 = 0;
}
else
{
/* clipping on the bottom side */
if (ow->v_start >= (si->dm.virtual_height - 1))
if (ow->v_start >= (crtc_vend - 1))
{
/* height < 2 is not allowed */
temp1 = (si->dm.virtual_height - 2) & 0x7ff;
temp1 = (crtc_vend - crtc_vstart - 2) & 0x7ff;
}
else
/* no clipping here */
{
temp1 = (uint16)ow->v_start & 0x7ff;
temp1 = (ow->v_start - crtc_vstart) & 0x7ff;
}
}
vcoordv |= temp1 << 16;
@@ -175,14 +192,14 @@ status_t gx00_configure_bes
else
{
/* clipping on the bottom side */
if ((ow->v_start + ow->height - 1) > (si->dm.virtual_height - 1))
if ((ow->v_start + ow->height - 1) > (crtc_vend - 1))
{
temp2 = (si->dm.virtual_height - 1) & 0x7ff;
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
}
else
{
/* clipping on the top side */
if ((ow->v_start + ow->height - 1) < 1)
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
{
/* height < 2 is not allowed */
temp2 = 1;
@@ -190,12 +207,12 @@ status_t gx00_configure_bes
else
/* no clipping here */
{
temp2 = ((uint16)(ow->v_start + ow->height - 1)) & 0x7ff;
temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1)) & 0x7ff;
}
}
}
vcoordv |= temp2 << 0;
LOG(4,("Overlay: top-edge output %d, bottom-edge output %d\n",temp1, temp2));
LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
/*********************************************
@@ -274,14 +291,13 @@ status_t gx00_configure_bes
* Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */
/* Note also:
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
hsrcstv = 0;
/* check for destination horizontal clipping at left side */
if (ow->h_start < 0)
if (ow->h_start < crtc_hstart)
{
/* check if entire destination picture is clipping left:
* (2 pixels will be clamped onscreen at least) */
if ((ow->h_start + ow->width - 1) < 1)
if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
{
/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
hsrcstv += (ow->width - 2);
@@ -289,7 +305,7 @@ status_t gx00_configure_bes
else
{
/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
hsrcstv += (0 - ow->h_start);
hsrcstv += (crtc_hstart - ow->h_start);
}
LOG(4,("Overlay: clipping left...\n"));
@@ -314,11 +330,11 @@ status_t gx00_configure_bes
hsrcendv = 0;
/* check for destination horizontal clipping at right side */
if ((ow->h_start + ow->width - 1) > (si->dm.virtual_width - 1))
if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
{
/* check if entire destination picture is clipping right:
* (2 pixels will be clamped onscreen at least) */
if (ow->h_start > (si->dm.virtual_width - 2))
if (ow->h_start > (crtc_hend - 2))
{
/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
hsrcendv += (ow->width - 2);
@@ -326,7 +342,7 @@ status_t gx00_configure_bes
else
{
/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
hsrcendv += ((ow->h_start + ow->width - 1) - (si->dm.virtual_width - 1));
hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 1));
}
LOG(4,("Overlay: clipping right...\n"));
@@ -435,11 +451,11 @@ status_t gx00_configure_bes
/* calculate origin adress */
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",a1orgv));
/* check for destination vertical clipping at top side */
if (ow->v_start < 0)
if (ow->v_start < crtc_vstart)
{
/* check if entire destination picture is clipping at top:
* (2 pixels will be clamped onscreen at least) */
if ((ow->v_start + ow->height - 1) < 1)
if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
{
/* increase source buffer origin with 'fixed value':
* (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) *
@@ -452,8 +468,8 @@ status_t gx00_configure_bes
/* increase source buffer origin with:
* (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
* bytes per row source picture */
a1orgv += ((((0 - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
weight = (0 - ow->v_start) * ifactor;
a1orgv += ((((crtc_vstart - ow->v_start) * ifactor) >> 16) * ob->bytes_per_row);
weight = (crtc_vstart - ow->v_start) * ifactor;
}
LOG(4,("Overlay: clipping at top...\n"));
}
+166 -43
View File
@@ -2,7 +2,7 @@
/* Authors:
Mark Watson 2/2000,
Apsed,
Rudolf Cornelissen 11-12/2002
Rudolf Cornelissen 11/2002-4/2003
*/
#define MODULE_BIT 0x00040000
@@ -196,6 +196,30 @@ status_t gx00_crtc_depth(int mode)
viddelay = 2<<3; // for 8 to 16Mb of memory
} while (0);
/* setup green_sync if requested */
if (si->settings.greensync)
{
/* enable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */
if (si->ps.card_type <= MIL2)
DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
else
DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
/* select horizontal _and_ vertical sync */
viddelay |= 0x40;
LOG(4,("CRTC: sync_on_green enabled\n"));
}
else
{
/* disable sync_on_green: ctrl bit polarity was reversed for Gxxx cards! */
if (si->ps.card_type <= MIL2)
DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
else
DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
LOG(4,("CRTC: sync_on_green disabled\n"));
}
/*set VCLK scaling*/
switch(mode)
{
@@ -238,16 +262,17 @@ status_t gx00_crtc_dpms_fetch(uint8 * display,uint8 * h,uint8 * v) // MIL2
return B_OK;
}
status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp)
status_t gx00_crtc_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
/*figure out offset value hardware needs*/
offset = (pitch*bpp)/128;
/* figure out offset value hardware needs:
* same for MIL1-G550 cards assuming MIL1/2 uses the TVP3026 64-bits DAC etc. */
offset = si->fbc.bytes_per_row / 16;
LOG(2,("CRTC: offset: 0x%04x\n",offset));
LOG(2,("CRTC: offset register: 0x%04x\n",offset));
/*program the card!*/
VGAW_I(CRTC,0x13,(offset&0xFF));
@@ -268,6 +293,20 @@ status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp)
LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer));
/* make sure we are in retrace on MIL cards (if possible), because otherwise
* distortions might occur during our reprogramming them (no double buffering) */
if (si->ps.card_type < G100)
{
/* we might have no retraces during setmode! */
uint32 timeout = 0;
/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4)))
{
snooze(4);
timeout++;
}
}
/*set standard registers*/
VGAW_I(CRTC,0xD,startadd&0xFF);
VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8);
@@ -389,43 +428,91 @@ status_t gx00_crtc_mem_priority(uint8 colordepth)
status_t gx00_crtc_cursor_init()
{
int i;
uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer */
const uint32 curadd = 0;
/* set cursor bitmap adress ... */
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
/* ... and repeat that: G100 requires other programming order than other cards!?! */
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
if (si->ps.card_type >= G100)
{
uint32 * fb;
/* cursor bitmap will be stored at the start of the framebuffer on >= G100 */
const uint32 curadd = 0;
/* set cursor bitmap adress ... */
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
/* ... and repeat that: G100 requires other programming order than later cards!?! */
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
/*set cursor colour*/
DXIW(CURCOL0RED,0XFF);
DXIW(CURCOL0GREEN,0xFF);
DXIW(CURCOL0BLUE,0xFF);
DXIW(CURCOL1RED,0);
DXIW(CURCOL1GREEN,0);
DXIW(CURCOL1BLUE,0);
DXIW(CURCOL2RED,0);
DXIW(CURCOL2GREEN,0);
DXIW(CURCOL2BLUE,0);
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(1024/4);i++)
{
fb[i]=0;
}
}
else
/* <= G100 cards have serial cursor color registers,
* and dedicated cursor bitmap RAM (in TVP3026 DAC)
*/
{
/* select first colorRAM adress */
DACW(TVP_CUROVRWTADD,0x00);
/* overscan/border color is black, order of colors set is R,G,B */
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
/* set sursor color 0 */
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
/* set sursor color 1 */
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
/* set sursor color 2 */
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
/* select first cursor pattern DAC-internal RAM adress, and
* make sure indirect cursor control register is selected as active register */
DXIW(CURCTRL,(DXIR(CURCTRL) & 0x73));
DACW(PALWTADD,0x00);
/* now clear it, auto-incrementing the adress */
for(i=0;i<1024;i++)
{
DACW(TVP_CURRAMDATA,0x00);
}
}
/* activate hardware cursor */
DXIW(CURCTRL,1);
/*set cursor colour*/
DXIW(CURCOL0RED,0XFF);
DXIW(CURCOL0GREEN,0xFF);
DXIW(CURCOL0BLUE,0xFF);
DXIW(CURCOL1RED,0);
DXIW(CURCOL1GREEN,0);
DXIW(CURCOL1BLUE,0);
DXIW(CURCOL2RED,0);
DXIW(CURCOL2GREEN,0);
DXIW(CURCOL2BLUE,0);
/*clear cursor*/
fb = (uint32 *) si->framebuffer + curadd;
for (i=0;i<(1024/4);i++)
{
fb[i]=0;
}
return B_OK;
}
status_t gx00_crtc_cursor_show()
{
DXIW(CURCTRL,1);
if ((si->ps.card_type < G100) && (si->dm.timing.h_total > 2048))
{
/* MIL1/2 DAC needs to be told if h_total for the active mode gets above 2048 */
DXIW(CURCTRL, 0x11);
}
else
{
DXIW(CURCTRL, 0x01);
}
return B_OK;
}
@@ -438,19 +525,56 @@ status_t gx00_crtc_cursor_hide()
/*set up cursor shape*/
status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{
uint8 * cursor;
int y;
/*get a pointer to the cursor*/
cursor = (uint8*) si->framebuffer;
/*draw the cursor*/
for(y=0;y<16;y++)
if(si->ps.card_type >= G100)
{
cursor[y*16+7]=~*andMask++;
cursor[y*16+15]=*xorMask++;
cursor[y*16+6]=~*andMask++;
cursor[y*16+14]=*xorMask++;
uint8 * cursor;
/*get a pointer to the cursor*/
cursor = (uint8*) si->framebuffer;
/*draw the cursor*/
for(y=0;y<16;y++)
{
cursor[y*16+7]=~*andMask++;
cursor[y*16+15]=*xorMask++;
cursor[y*16+6]=~*andMask++;
cursor[y*16+14]=*xorMask++;
}
}
else
/* <= G100 cards have dedicated cursor bitmap RAM (in TVP3026 DAC) */
{
uint8 curctrl;
/* disable the cursor to prevent distortions in screen output */
curctrl = (DXIR(CURCTRL));
DXIW(CURCTRL, (curctrl & 0xfc));
/* select first cursor pattern DAC-internal RAM adress for plane 0 */
DXIW(CURCTRL, (DXIR(CURCTRL) & ~0x0c));
DACW(PALWTADD, 0x00);
/* now fill it, partly auto-incrementing the adress */
for(y = 0; y < 16; y++)
{
DACW(PALWTADD, (y * 8));
DACW(TVP_CURRAMDATA, ~*andMask++);
DACW(TVP_CURRAMDATA, ~*andMask++);
}
/* select first cursor pattern DAC-internal RAM adress for plane 1 */
DXIW(CURCTRL, (DXIR(CURCTRL) | 0x08));
DACW(PALWTADD, 0x00);
/* now fill it, partly auto-incrementing the adress */
for(y = 0; y < 16; y++)
{
DACW(PALWTADD, y*8);
DACW(TVP_CURRAMDATA, *xorMask++);
DACW(TVP_CURRAMDATA, *xorMask++);
}
/* delay restoring the cursor to prevent distortions in screen output */
snooze(5);
/* restore the cursor */
DXIW(CURCTRL, curctrl);
}
return B_OK;
@@ -460,7 +584,6 @@ status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
status_t gx00_crtc_cursor_position(uint16 x ,uint16 y)
{
int i=64;
// LOG(4,("DAC: cursor-> %d %d\n",x,y));
x+=i;
y+=i;
+180 -36
View File
@@ -2,7 +2,7 @@
Authors:
Mark Watson 6/2000,
Rudolf Cornelissen 12/2002
Rudolf Cornelissen 12/2002 - 4/2003
*/
#define MODULE_BIT 0x00020000
@@ -10,37 +10,139 @@
#include "mga_std.h"
/*set a mode line - inputs are in pixels/scanlines*/
status_t g400_crtc2_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
)
status_t g400_crtc2_set_timing(display_mode target)
{
uint32 temp;
LOG(4,("CRTC2: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/
if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7))
if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX))
{
LOG(8,("CRTC2:Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/* G450/G550 monitor mode, and all modes on older cards */
/*program the second CRTC*/
CR2W(HPARAM, ((((hdisp_e - 8) & 0x0fff) << 16) | ((htotal - 8) & 0x0fff)));
CR2W(HSYNC, ((((hsync_e - 8) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff)));
CR2W(VPARAM, ((((vdisp_e - 1) & 0x0fff) << 16) | ((vtotal - 1) & 0x0fff)));
CR2W(VSYNC, ((((vsync_e - 1) & 0x0fff) << 16) | ((vsync_s - 1) & 0x0fff)));
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
//CR2W(PRELOAD, (((vsync_s & 0x0fff) << 16) | (hsync_s & 0x0fff)));
CR2W(PRELOAD, ((((vsync_s - 1) & 0x0fff) << 16) | ((hsync_s - 8) & 0x0fff)));
CR2W(MISC, ((0xfff << 16) | (((!hsync_pos) & 0x01) << 8) | (((!vsync_pos) & 0x01) << 9)));
/* check horizontal timing parameters are to nearest 8 pixels */
if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) |
(target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07))
{
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/* make sure NTSC clock killer circuitry is disabled */
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
/* make sure CRTC2 is set to progressive scan for monitor mode */
CR2W(CTL, (CR2R(CTL) & ~0x02001000));
/* program the second CRTC */
CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) |
((target.timing.h_total - 8) & 0x0fff)));
CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) |
((target.timing.h_sync_start - 8) & 0x0fff)));
CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) |
((target.timing.v_total - 1) & 0x0fff)));
CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) |
((target.timing.v_sync_start - 1) & 0x0fff)));
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
//CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) |
// (target.timing.h_sync_start & 0x0fff)));
CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) |
((target.timing.h_sync_start - 8) & 0x0fff)));
temp = (0xfff << 16);
if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
CR2W(MISC, temp);
/* On <= G400MAX dualhead cards we need to send a copy to the MAVEN;
* unless TVout is active */
if ((si->ps.secondary_head) && (!(target.flags & TV_BITS)))
gx00_maven_set_timing(target);
}
else
{
/* G450/G550 TVout mode */
display_mode tv_mode = target;
uint8 frame;
unsigned int vcount, prev_vcount;
LOG(4,("CRTC2: setting up G450/G550 TVout mode\n"));
/* check horizontal timing parameters are to nearest 8 pixels */
if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) |
(tv_mode.timing.h_sync_end & 0x07))
{
LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
return B_ERROR;
}
/* disable NTSC clock killer circuitry */
CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
if (tv_mode.timing.h_total & 0x07)
{
/* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */
LOG(4,("CRTC2: enabling clock killer circuitry\n"));
CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010));
}
/* make sure h_total is valid for TVout mode */
tv_mode.timing.h_total &= ~0x07;
/* modify tv_mode for interlaced use */
tv_mode.timing.v_display >>= 1;
tv_mode.timing.v_sync_start >>= 1;
tv_mode.timing.v_sync_end >>= 1;
tv_mode.timing.v_total >>= 1;
/*program the second CRTC*/
CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) |
((tv_mode.timing.h_total - 8) & 0x0fff)));
CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) |
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) |
((tv_mode.timing.v_total - 1) & 0x0fff)));
CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) |
((tv_mode.timing.v_sync_start - 1) & 0x0fff)));
//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
//CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) |
// (tv_mode.timing.h_sync_start & 0x0fff)));
CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) |
((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
/* set CRTC2 to interlaced mode:
* First enable progressive scan mode while making sure
* CRTC2 is setup for TVout mode use... */
CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000));
/* now synchronize to the start of a frame... */
prev_vcount = 0;
for (frame = 0; frame < 2; frame++)
{
for (;;)
{
vcount = (CR2R(VCOUNT) & 0x00000fff);
if (vcount >= prev_vcount)
prev_vcount = vcount;
else
break;
}
}
/* and start interlaced mode now! */
CR2W(CTL, (CR2R(CTL) | 0x02000000));
temp = (0xfff << 16);
if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
CR2W(MISC, temp);
}
return B_OK;
}
status_t g400_crtc2_depth(int mode)
{
/*validate bit depth and set mode*/
/* validate bit depth and set mode */
/* also clears TVout mode (b12) */
switch(mode)
{
case BPP16:case BPP32DIR:
@@ -57,10 +159,29 @@ status_t g400_crtc2_depth(int mode)
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v)
{
//fixme: CTL b0=1 is CRTC2 enabled, 0 is disabled. This code is dangerous...
CR2W(CTL,(CR2R(CTL)&0xFFF0077E)|(display&h&v)); /*enable second CRTC if required*/
if (display & h & v)
{
/* enable CRTC2 and don't touch the rest */
CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01));
}
else
{
/* disable CRTC2 and don't touch the rest */
CR2W(CTL, (CR2R(CTL) & 0xFFF0177E));
}
if (si->ps.card_type >= G450)
{
//fixme:
/* setup monitor mode DPMS: G450 and later fully support this on CRTC2 */
//for now:
//enable 'straight-through' sync outputs on both analog output connectors...
DXIW(SYNCCTRL,0x00);
}
/* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */
if (si->ps.secondary_head) gx00_maven_dpms(display, h, v);
/*ignore h,v because they are not supported*/
return B_OK;
}
@@ -73,31 +194,54 @@ status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v)
return B_OK;
}
status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp)
status_t g400_crtc2_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC2: setting card pitch 0x%08x bpp %d\n", pitch, bpp));
LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
/*figure out offset value hardware needs*/
offset = pitch*(bpp>>3);
/* figure out offset value hardware needs */
offset = si->fbc.bytes_per_row;
if (si->interlaced_tv_mode)
{
LOG(4,("CRTC2: setting interlaced mode\n"));
/* double the CRTC2 linelength so fields are displayed instead of frames */
offset *= 2;
}
else
LOG(4,("CRTC2: setting progressive scan mode\n"));
LOG(2,("CRTC2: offset: %x\n",offset));
LOG(2,("CRTC2: offset set to %d bytes\n", offset));
/*program the card!*/
/* program the head */
CR2W(OFFSET,offset);
return B_OK;
}
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp)
{
LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
LOG(4,("CRTC2: setting card RAM to be displayed for %d bits per pixel\n", bpp));
LOG(2,("CRTC2: startadd: %x\n",startadd));
LOG(2,("CRTC2: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC2: framebuffer: %x\n",si->fbc.frame_buffer));
LOG(2,("CRTC2: startadd: $%x\n",startadd));
LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer));
LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer));
if (si->interlaced_tv_mode)
{
LOG(4,("CRTC2: setting up fields for interlaced mode\n"));
/* program the head for interlaced use */
//fixme: seperate both heads: we need a secondary si->fbc!
/* setup field 0 startadress in buffer to read picture's odd lines */
CR2W(STARTADD0, (startadd + si->fbc.bytes_per_row));
/* setup field 1 startadress in buffer to read picture's even lines */
CR2W(STARTADD1, startadd);
}
else
{
LOG(4,("CRTC2: setting up frames for progressive scan mode\n"));
/* program the head for non-interlaced use */
CR2W(STARTADD0, startadd);
}
/*program the card!*/
CR2W(STARTADD0,startadd);
return B_OK;
}
+237 -26
View File
@@ -2,19 +2,23 @@
/* Authors:
Mark Watson 2/2000,
Apsed 2002,
Rudolf Cornelissen 9-12/2002
Rudolf Cornelissen 9/2002-4/2003
*/
#define MODULE_BIT 0x00010000
#include "mga_std.h"
static status_t g100_g400max_dac_pix_pll_find(
static status_t milx_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
static status_t g100_g400max_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
static status_t g450_g550_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
static status_t g100_g400max_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
static status_t g450_g550_dac_sys_pll_find(
float req_sclk,float * calc_sclk,uint8 * m_result,uint8 * n_result,uint8 * p_result);
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t gx00_dac_mode(int mode,float brightness)
@@ -81,10 +85,59 @@ status_t gx00_dac_mode(int mode,float brightness)
if (gx00_dac_palette(r,g,b)!=B_OK) return B_ERROR;
/*set the mode - also sets VCLK dividor*/
DXIW(MULCTRL,mode);
DACW(PIXRDMSK,0xff); // apsed, palette addressing not masked
if (si->ps.card_type >= G100)
{
DXIW(MULCTRL, mode);
LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL)));
}
else
{
/* MIL1/2 differs here (TVP3026DAC) */
uint8 miscctrl = 0, latchctrl = 0;
uint8 tcolctrl = 0, mulctrl = 0;
LOG(2,("DAC: mulctrl=%x, pixrdmsk=%x\n",DXIR(MULCTRL), DACR(PIXRDMSK)));
/* set the mode */
switch (mode)
{
/* presetting mulctrl for DAC pixelbus_width of 32 */
case BPP8:
miscctrl=0x00; latchctrl=0x06; tcolctrl=0x80; mulctrl=0x4b;
break;
case BPP15:
miscctrl=0x20; latchctrl=0x06; tcolctrl=0x04; mulctrl=0x53;
break;
case BPP16:
miscctrl=0x20; latchctrl=0x06; tcolctrl=0x05; mulctrl=0x53;
break;
case BPP24:
miscctrl=0x20; latchctrl=0x06; tcolctrl=0x1f; mulctrl=0x5b;
break;
case BPP32:
miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b;
break;
case BPP32DIR:
miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b;
break;
}
/* modify mulctrl if DAC pixelbus_width is 64 */
//fixme? do 32bit DACbus MIL 1/2 cards exist? if so, setup via si->ps...
if (true) mulctrl += 1;
DXIW(MISCCTRL, (DXIR(MISCCTRL) & 0x1d) | miscctrl);
DXIW(TVP_LATCHCTRL, latchctrl);
DXIW(TVP_TCOLCTRL, tcolctrl);
DXIW(MULCTRL, mulctrl);
LOG(2,("DAC: TVP miscctrl 0x%02x, TVP latchctrl 0x%02x\n",
DXIR(MISCCTRL), DXIR(TVP_LATCHCTRL)));
LOG(2,("DAC: TVP tcolctrl 0x%02x, TVP mulctrl 0x%02x\n",
DXIR(TVP_TCOLCTRL), DXIR(MULCTRL)));
}
/* disable palette RAM adressing mask */
DACW(PIXRDMSK,0xff);
LOG(2,("DAC: pixrdmsk 0x%02x\n", DACR(PIXRDMSK)));
return B_OK;
}
@@ -96,10 +149,8 @@ status_t gx00_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256])
LOG(4,("DAC: setting palette\n"));
/* clear palwtadd to start programming (LUT index?) */
/* clear palwtadd before starting programming (LUT index) */
DACW(PALWTADD,0);
/* just for safety (specs are somewhat unclear) (LUT color?) */
DACW(PALRDADD,0);
/*loop through all 256 to program DAC*/
for (i=0;i<256;i++)
@@ -128,10 +179,6 @@ if (0)
LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed
}
}
/* reset to LUT start just for safety (LUT index?) */
DACW(PALWTADD,0);
/* (specs are somewhat unclear) (LUT color?) */
DACW(PALRDADD,0);
return B_OK;
}
@@ -154,6 +201,7 @@ status_t gx00_dac_set_pix_pll(display_mode target)
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk));
/* signal that we actually want to set the mode */
result = gx00_dac_pix_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
@@ -282,14 +330,134 @@ status_t gx00_dac_pix_pll_find
switch (si->ps.card_type) {
case G550:
case G450: return g450_g550_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result);
case MIL2:
case MIL1: return milx_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result);
default: return g100_g400max_dac_pix_pll_find(target, calc_pclk, m_result, n_result, p_result, test);
}
return B_ERROR;
}
/* find nearest valid pixel PLL setting: rewritten by rudolf */
static status_t g100_g400max_dac_pix_pll_find(
static status_t milx_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
LOG(4,("DAC: MIL1/MIL2 TVP restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_CMAP8:
max_pclk = si->ps.max_dac1_clock_8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac1_clock_16;
break;
case B_RGB24_LITTLE:
max_pclk = si->ps.max_dac1_clock_24;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac1_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac1_clock_32;
break;
}
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 8.0))
{
LOG(4,("DAC: TVP clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_pixel_vco / 8.0)));
req_pclk = (si->ps.min_pixel_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("DAC: TVP clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_pixel_vco) && (f_vco <= si->ps.max_pixel_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (n = 3; n <= 25; n++)
{
/* calculate VCO postscaler setting for current setup.. */
m = (int)(((f_vco * n) / (8 * si->ps.f_ref)) + 0.5);
/* ..and check for validity */
if ((m < 3) || (m > 64)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - ((((8 * si->ps.f_ref) / n) * m) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
m = best[0];
n = best[1];
p = best[2];
f_vco = (((8 * si->ps.f_ref) / n) * m);
LOG(2,("DAC: TVP pix VCO frequency found %fMhz\n", f_vco));
/* setup the scalers programming values for found optimum setting */
*calc_pclk = (f_vco / p);
*m_result = (65 - m);
*n_result = (65 - n);
switch(p)
{
case 1:
p = 0x00;
break;
case 2:
p = 0x01;
break;
case 4:
p = 0x02;
break;
case 8:
p = 0x03;
break;
}
*p_result = p;
/* display the found pixelclock values */
LOG(2,("DAC: TVP pix PLL check: requested %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
/* find nearest valid pixel PLL setting: rewritten by rudolf */
static status_t g100_g400max_dac_pix_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
@@ -315,6 +483,17 @@ static status_t g100_g400max_dac_pix_pll_find(
break;
}
/* make sure the pixelPLL and the videoPLL have a little different settings to
* minimize distortions in the outputs due to crosstalk:
* do *not* change the videoPLL setting because it must be exact if TVout is enabled! */
/* Note:
* only modify the clock if we are actually going to set the mode */
if ((target.flags & DUALHEAD_BITS) && test)
{
LOG(4,("DAC: dualhead mode active: modified requested pixelclock +1.5%%\n"));
req_pclk *= 1.015;
}
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
@@ -343,9 +522,18 @@ static status_t g100_g400max_dac_pix_pll_find(
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 8.0))
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_pixel_vco / 8.0)));
req_pclk = (si->ps.min_pixel_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk) req_pclk = max_pclk;
if (req_pclk > max_pclk)
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
@@ -466,9 +654,18 @@ static status_t g450_g550_dac_pix_pll_find
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_pixel_vco / 16.0))
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_pixel_vco / 16.0)));
req_pclk = (si->ps.min_pixel_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk) req_pclk = max_pclk;
if (req_pclk > max_pclk)
{
LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
@@ -505,7 +702,7 @@ static status_t g450_g550_dac_pix_pll_find
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
n=best[1] - 2;
switch(best[2])
{
case 1:
@@ -526,7 +723,7 @@ static status_t g450_g550_dac_pix_pll_find
}
/* log the closest VCO speed found */
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1);
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2);
LOG(2,("DAC: pix VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing.
@@ -579,9 +776,18 @@ static status_t g100_g400max_dac_sys_pll_find(
/* Make sure the requested systemclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 8.0))
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)(si->ps.min_system_vco / 8.0)));
req_sclk = (si->ps.min_system_vco / 8.0);
}
/* upper limit is max_system_vco */
if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco;
if (req_sclk > si->ps.max_system_vco)
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)si->ps.max_system_vco));
req_sclk = si->ps.max_system_vco;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
@@ -666,7 +872,6 @@ status_t gx50_dac_check_sys_pll(uint8 m, uint8 n, uint8 p)
uint time = 0, count = 0;
/* program the new clock */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/
DXIW(SYSPLLM, m);
DXIW(SYSPLLN, n);
DXIW(SYSPLLP, p);
@@ -705,7 +910,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
*p &= 0x47;
/* iterate through all possible filtersettings */
// DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/
for (s = 0; s < 8 ;s++)
{
if (gx50_dac_check_sys_pll(m, n, *p)== B_OK)
@@ -722,7 +926,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
/* preset first choice setting found */
*q = 1;
/* we are done */
// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
return B_OK;
}
else
@@ -741,7 +944,6 @@ status_t gx50_dac_check_sys_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
/* return the (last found) backup result, or the original p value */
*p = p_backup;
// DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); /*enable the PIXPLL*/
/* we found only a non-optimal value */
if (*q == 2) return B_OK;
@@ -765,9 +967,18 @@ static status_t g450_g550_dac_sys_pll_find(
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_system_vco divided by highest postscaler-factor */
if (req_sclk < (si->ps.min_system_vco / 16.0))
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)(si->ps.min_system_vco / 16.0)));
req_sclk = (si->ps.min_system_vco / 16.0);
}
/* upper limit is max_system_vco */
if (req_sclk > si->ps.max_system_vco) req_sclk = si->ps.max_system_vco;
if (req_sclk > si->ps.max_system_vco)
{
LOG(4,("DAC: clamping sysclock: requested %fMHz, set to %fMHz\n",
req_sclk, (float)si->ps.max_system_vco));
req_sclk = si->ps.max_system_vco;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
@@ -804,7 +1015,7 @@ static status_t g450_g550_dac_sys_pll_find(
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
n=best[1] - 2;
switch(best[2])
{
case 1:
@@ -825,7 +1036,7 @@ static status_t g450_g550_dac_sys_pll_find(
}
/* log the closest VCO speed found */
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 1);
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2);
LOG(2,("DAC: sys VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing.
@@ -1,7 +1,7 @@
/* Authors:
Mark Watson 12/1999,
Apsed,
Rudolf Cornelissen 10-12/2002
Rudolf Cornelissen 10/2002-4/2003
*/
#define MODULE_BIT 0x00008000
@@ -11,7 +11,7 @@
//#include "mga_init.c" //Nicole's test stuff.
status_t test_ram();
static status_t mil2_general_powerup (void);
static status_t mil_general_powerup (void);
static status_t g100_general_powerup (void);
static status_t g200_general_powerup (void);
static status_t g400_general_powerup (void);
@@ -56,17 +56,23 @@ status_t gx00_general_powerup()
status_t status;
uint32 card_class;
LOG(1,("POWERUP: Matrox (open)BeOS Accelerant 0.14 running.\n"));
/* detect card type and power it up */
switch(CFGR(DEVID))
{
case 0x0519102b: //MGA-2064 Millenium PCI
case 0x051a102b: //MGA-1064 Mystic PCI
LOG(8,("POWERUP: Unimplemented Matrox device %08x\n",CFGR(DEVID)));
return B_ERROR;
case 0x0519102b: //MGA-2064 Millenium PCI
si->ps.card_type = MIL1;
LOG(4,("POWERUP: Detected MGA-2064 Millennium 1\n"));
status = mil_general_powerup();
break;
case 0x051b102b:case 0x051f102b: //MGA-2164 Millenium 2 PCI/AGP
si->ps.card_type = MIL2;
LOG(4,("POWERUP: Detected MGA-2164 Millennium 2\n"));
status = mil2_general_powerup();
status = mil_general_powerup();
break;
case 0x1000102b:case 0x1001102b: //G100
si->ps.card_type = G100;
@@ -201,7 +207,7 @@ status_t mga_set_cas_latency()
break;
case G450:
case G550:
/* G450 and G550 tune CAS latency via a predefined table at powerup time */
/* fixme: implement this if needed */
LOG(4,("INIT: G450/G550 RAM CAS tuning not implemented, aborting.\n"));
return B_OK;
break;
@@ -220,11 +226,11 @@ status_t mga_set_cas_latency()
}
static
status_t mil2_general_powerup()
status_t mil_general_powerup()
{
status_t result;
LOG(4, ("INIT: Millenium II powerup\n"));
LOG(4, ("INIT: Millenium I/II powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
/* initialize the shared_info PINS struct */
@@ -235,15 +241,9 @@ status_t mil2_general_powerup()
dump_pins();
//remove this:
// various sensible defaults for MIL2
si->ps.sdram = true;
si->ps.memory_size = 2; //can override
si->ps.memory_size = 4; //can override my mil2
// apsed TODO MIL2 TVP 3026 may be 135, 175, 220 or 250MHz
// chip on my Millenium2 is TVP3026-250CPCE, 250MHz
// rudolf: works in Mhz now
si->ps.max_dac1_clock=250; // TVP3026
fake_pins();
LOG(2, ("INIT: Using faked PINS for now:\n"));
dump_pins();
//end remove this.
/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
@@ -254,20 +254,20 @@ status_t mil2_general_powerup()
LOG(2, ("INIT: Skipping card coldstart!\n"));
mil2_dac_init();
//rudolf: sync on green test:
/* disable 15bit mode CLUT-overlay function */
//enable 'sync on green' option
// DXIW(GENCTRL, DXIR(GENCTRL | 0x20));
/* enable composite sync instead of Hsync only */
// VGAW_I(CRTCEXT,3,(VGAR_I(CRTCEXT,3) | 0x40));
//end sync on green test.
//ok:
/* disable overscan, select 0 IRE, select straight-through sync signals from CRTC */
DXIW (GENCTRL, (DXIR (GENCTRL) & 0x0c));
/* fixme: checkout if we need this sync inverting stuff: already done via CRTC!?!
| (vsync_pos? 0x00:0x02)
| (hsync_pos? 0x00:0x01)); */
/* 8-bit DAC, enable DAC */
DXIW(MISCCTRL, 0x0c);
//
VGAW_I(SEQ,1,0x00);
/*enable screen*/
return B_OK;
// apsed TODO MIL2 taken from G100, avoid DXIR/W DACR/W
//rudolf: G100 version that was here nolonger exists, look at new implementation...
return B_OK;
}
@@ -309,7 +309,6 @@ status_t g100_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x1b);
@@ -349,12 +348,12 @@ status_t g100_general_powerup()
/* wait 200uS minimum */
snooze(250);
/* reset memory */
/* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000);
/* select JEDEC reset method */
ACCW(MACCESS,ACCR(MACCESS)|0x4000);
ACCW(MACCESS, 0x00004000);
/* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
ACCW(MACCESS, 0x0000c000);
snooze(250);
/* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
@@ -412,7 +411,6 @@ status_t g200_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x1b);
@@ -452,10 +450,10 @@ status_t g200_general_powerup()
/* wait 200uS minimum */
snooze(250);
/* reset memory */
/* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000);
/* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
ACCW(MACCESS, 0x00008000);
snooze(250);
/* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
@@ -512,7 +510,6 @@ status_t g400_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x9b);
@@ -553,10 +550,10 @@ status_t g400_general_powerup()
/* wait 200uS minimum */
snooze(250);
/* reset memory */
/* reset memory (MACCESS is a write only register!) */
ACCW(MACCESS, 0x00000000);
/* perform actual RAM reset */
ACCW(MACCESS,ACCR(MACCESS)|0x8000);
ACCW(MACCESS, 0x00008000);
snooze(250);
/* start memory refresh */
CFGW(OPTION,(CFGR(OPTION)&0xffe07fff) | (si->ps.option_reg & 0x001f8000));
@@ -584,10 +581,12 @@ status_t g400_general_powerup()
static
status_t g450_general_powerup()
{
//fixme: check if g450 and g550 powerup should be the same! (DAC outputconnector?)
status_t result;
uint32 pwr_cas[] = {0, 1, 5, 6, 7, 5, 2, 3};
/* used for convenience: MACCESS is a write only register! */
uint32 maccess = 0x00000000;
LOG(4, ("INIT: G450/G550 powerup\n"));
if (si->settings.logmask & 0x80000000) mga_dump_configuration_space();
@@ -607,8 +606,7 @@ status_t g450_general_powerup()
DXIW(OUTPUTCONN,0x00);
/* turn off both displays and the hardcursor (also disables transfers) */
gx00_crtc_dpms(0,0,0);
//fixme:
//g400_crtc2_dpms(0,0,0);
g400_crtc2_dpms(0,0,0);
gx00_crtc_cursor_hide();
/* power up everything except DVI electronics (for now) */
@@ -625,7 +623,6 @@ status_t g450_general_powerup()
/* disable pixelclock oscillations before switching on CLUT */
DXIW(PIXCLKCTRL, (DXIR(PIXCLKCTRL) | 0x04));
/* disable 15bit mode CLUT-overlay function */
//fixme: setup b5 later for 'sync on green' option
DXIW(GENCTRL, DXIR(GENCTRL & 0xfd));
/* CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC */
DXIW(MISCCTRL,0x9b);
@@ -663,7 +660,8 @@ status_t g450_general_powerup()
/* set RAM read tap delays and mode register opcode / streamer flow control */
ACCW(MEMRDBK, si->ps.memrdbk_reg);
/* b7 v5_mem_type = done by Mark Watson. fixme: still confirm! (unknown bits) */
ACCW(MACCESS, ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1));
maccess = ((((uint32)si->ps.v5_mem_type) & 0x80) >> 1);
ACCW(MACCESS, maccess);
/* clear b0-1 and 3, and set b31 in option4: re-enable memory clock */
CFGW(OPTION4, ((si->ps.option4_reg & 0x60000004) | 0x80000000));
snooze(250);
@@ -675,7 +673,8 @@ status_t g450_general_powerup()
if (!(si->ps.v5_mem_type & 0x0100))
{
/* clear unknown bits */
ACCW(MACCESS, 0x00000000);
maccess = 0x00000000;
ACCW(MACCESS, maccess);
/* clear b12: unknown bit */
ACCW(MEMRDBK, (si->ps.memrdbk_reg & 0xffffefff));
}
@@ -689,8 +688,8 @@ status_t g450_general_powerup()
}
/* create positive flank to generate memory reset */
ACCW(MACCESS,ACCR(MACCESS) & 0xffff7fff);
ACCW(MACCESS,ACCR(MACCESS) | 0x00008000);
ACCW(MACCESS, (maccess & 0xffff7fff));
ACCW(MACCESS, (maccess | 0x00008000));
snooze(250);
/* start memory refresh */
@@ -724,6 +723,9 @@ status_t g450_general_powerup()
/*turn on display one*/
gx00_crtc_dpms(1,1,1);
/* enable 'straight-through' sync outputs on both analog output connectors */
DXIW(SYNCCTRL,0x00);
return B_OK;
}
@@ -763,27 +765,62 @@ status_t gx00_general_dac_select(int dac)
/*MISCCTRL, clock src,...*/
switch(dac)
{
/* G400 */
case DS_CRTC1DAC_CRTC2MAVEN:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002); /*external clk*/
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
/* connect CRTC1 to pixPLL */
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL, connect CRTC1 to internal DAC and
* enable CRTC2 external video timing reset signal.
* (Setting for MAVEN 'master mode' TVout signal generation.) */
CR2W(CTL,(CR2R(CTL)&0xffe00779)|0xD0000002);
/* disable CRTC1 external video timing reset signal */
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)&0x77));
/* select CRTC2 RGB24 MAFC mode: connects CRTC2 to MAVEN DAC */
DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x82);
break;
case DS_CRTC1MAVEN_CRTC2DAC:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2); /*external clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk*/
/* connect CRTC1 to vidPLL */
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x2);
/* connect CRTC2 to pixPLL and internal DAC and
* disable CRTC2 external video timing reset signal */
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20));
/* enable CRTC1 external video timing reset signal.
* note: this is nolonger used as G450/G550 cannot do TVout on CRTC1 */
VGAW_I(CRTCEXT,1,(VGAR_I(CRTCEXT,1)|0x88));
/* select CRTC1 RGB24 MAFC mode: connects CRTC1 to MAVEN DAC */
DXIW(MISCCTRL,(DXIR(MISCCTRL)&0x19)|0x02);
break;
/* G450/G550 */
case DS_CRTC1CON1_CRTC2CON2:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x0<<20)); /*internal clk - no DAC PTR*/
/* connect CRTC1 to pixPLL */
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL, connect CRTC1 to DAC1, disable CRTC2
* external video timing reset signal, set CRTC2 progressive scan mode
* and disable TVout mode (b12).
* (Setting for MAVEN 'slave mode' TVout signal generation.) */
//fixme: enable timing resets if TVout is used in master mode!
//otherwise keep it disabled.
CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x0<<20));
/* connect DAC1 to CON1, CRTC2/'DAC2' to CON2 (monitor mode) */
DXIW(OUTPUTCONN,0x09);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
DXIW(GENIODATA, 0x00);
break;
//fixme: toggle PLL's below if possible:
// otherwise toggle PLL's for G400 2nd case?
case DS_CRTC1CON2_CRTC2CON1:
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1); /*internal clk*/
CR2W(CTL,(CR2R(CTL)&0x2fe00779)|0x4|(0x1<<20)); /*internal clk - gets DAC*/
/* connect CRTC1 to pixPLL */
DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0xc)|0x1);
/* connect CRTC2 to vidPLL and DAC1, disable CRTC2 external
* video timing reset signal, and set CRTC2 progressive scan mode and
* disable TVout mode (b12). */
CR2W(CTL,(CR2R(CTL)&0x2de00779)|0x6|(0x1<<20));
/* connect DAC1 to CON2 (monitor mode), CRTC2/'DAC2' to CON1 */
DXIW(OUTPUTCONN,0x05);
/* Select 1.5 Volt MAVEN DAC ref. for monitor mode */
DXIW(GENIOCTRL, DXIR(GENIOCTRL) & ~0x40);
DXIW(GENIODATA, 0x00);
break;
default:
return B_ERROR;
@@ -817,13 +854,34 @@ status_t gx00_general_bios_to_powergraphics()
VGAW(MISCW,0x08);
/*set only MGA pixel clock in MISC - I don't want to map VGA stuff under this OS*/
if (si->ps.card_type >= G100) {
switch (si->ps.card_type)
{
case G400:
case G400MAX:
/* makes CRTC2 stable! Matrox specify 8, but use 4 - grrrr! */
DXIW(MAFCDEL,0x02);
break;
case G450:
case G550:
/* power up everything except DVI electronics (for now) */
DXIW(PWRCTRL,0x1b);
/* enable 'straight-through' sync outputs on both analog output connectors */
DXIW(SYNCCTRL,0x00);
break;
default:
break;
}
if (si->ps.card_type >= G100)
{
DXIW(MISCCTRL,0x9b);
/*CRTC2->MAFC, 8-bit DAC, CLUT enabled, enable DAC*/
DXIW(MULCTRL,0x4);
/*RGBA direct mode*/
} else {
}
else
{
LOG(8, ("INIT: < G100 DAC powerup badly implemented, MISC 0x%02x\n", VGAR(MISCR)));
} // apsed TODO MIL2
@@ -832,3 +890,193 @@ status_t gx00_general_bios_to_powergraphics()
return B_OK;
}
/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
* virtual_size to the nearest valid maximum for the mode on the card if not so.
* Then: check if virtual_width adheres to the cards _multiple_ constraints, and
* create mode slopspace if not so.
* We use acc multiple constraints here if we expect we can use acceleration, because
* acc constraints are worse than CRTC constraints.
*
* Mode slopspace is reflected in fbc->bytes_per_row BTW. */
//fixme: seperate heads for real dualhead modes:
//CRTC1 and 2 constraints differ!
status_t gx00_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row)
{
/* Note:
* This routine assumes that the CRTC memory pitch granularity is 'smaller than',
* or 'equals' the acceleration engine memory pitch granularity! */
uint32 video_pitch;
uint32 acc_mask, crtc_mask;
uint8 depth = 8;
/* determine pixel multiple based on 2D/3D engine constraints */
switch (si->ps.card_type)
{
case MIL1:
case MIL2:
/* see MIL1/2 specs:
* these cards always use a 64bit RAMDAC (TVP3026) and interleaved memory */
switch (target->space)
{
case B_CMAP8: acc_mask = 0x7f; depth = 8; break;
case B_RGB15: acc_mask = 0x3f; depth = 16; break;
case B_RGB16: acc_mask = 0x3f; depth = 16; break;
case B_RGB24: acc_mask = 0x7f; depth = 24; break;
case B_RGB32: acc_mask = 0x1f; depth = 32; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
break;
default:
/* see G100 and up specs:
* these cards can do 2D as long as multiples of 32 are used.
* (Note: don't mix this up with adress linearisation!) */
switch (target->space)
{
case B_CMAP8: depth = 8; break;
case B_RGB15: depth = 16; break;
case B_RGB16: depth = 16; break;
case B_RGB24: depth = 24; break;
case B_RGB32: depth = 32; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
acc_mask = 0x1f;
break;
}
/* determine pixel multiple based on CRTC memory pitch constraints.
* (Note: Don't mix this up with CRTC timing contraints! Those are
* multiples of 8 for horizontal, 1 for vertical timing.) */
switch (si->ps.card_type)
{
case MIL1:
case MIL2:
/* see MIL1/2 specs:
* these cards always use a 64bit RAMDAC and interleaved memory */
switch (target->space)
{
case B_CMAP8: crtc_mask = 0x7f; break;
case B_RGB15: crtc_mask = 0x3f; break;
case B_RGB16: crtc_mask = 0x3f; break;
/* for B_RGB24 crtc_mask 0x7f is worst case scenario (MIL2 constraint) */
case B_RGB24: crtc_mask = 0x7f; break;
case B_RGB32: crtc_mask = 0x1f; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
break;
default:
/* see G100 and up specs */
switch (target->space)
{
case B_CMAP8: crtc_mask = 0x0f; break;
case B_RGB15: crtc_mask = 0x07; break;
case B_RGB16: crtc_mask = 0x07; break;
case B_RGB24: crtc_mask = 0x0f; break;
case B_RGB32: crtc_mask = 0x03; break;
default:
LOG(8,("INIT: unknown color space: 0x%08x\n", target->space));
return B_ERROR;
}
/* see G400 specs: CRTC2 has different constraints */
/* Note:
* set for RGB and B_YCbCr422 modes. Other modes need larger multiples! */
if (target->flags & DUALHEAD_BITS)
{
switch (target->space)
{
case B_RGB16: crtc_mask = 0x1f; break;
case B_RGB32: crtc_mask = 0x0f; break;
default:
LOG(8,("INIT: illegal DH color space: 0x%08x\n", target->space));
return B_ERROR;
}
}
break;
}
/* check if we can setup this mode with acceleration:
* Max sizes need to adhere to both the acceleration engine _and_ the CRTC constraints! */
si->acc_mode = true;
/* check virtual_width */
switch (si->ps.card_type)
{
case MIL1:
case MIL2:
case G100:
/* acc constraint: */
if (target->virtual_width > 2048) si->acc_mode = false;
break;
default:
/* G200-G550 */
/* acc constraint: */
if (target->virtual_width > 4096) si->acc_mode = false;
/* for 32bit mode a lower CRTC1 restriction applies! */
if ((target->space == B_RGB32_LITTLE) && (target->virtual_width > (4092 & ~acc_mask)))
si->acc_mode = false;
break;
}
/* virtual_height */
if (target->virtual_height > 2048) si->acc_mode = false;
/* now check virtual_size based on CRTC constraints,
* making sure virtual_width stays within the 'mask' constraint: which is only
* nessesary because of an extra constraint in MIL1/2 cards that exists here. */
{
/* virtual_width */
//fixme for CRTC2 (identical on all G400+ cards):
//16bit mode: max. virtual_width == 16352 (no extra mask needed);
//32bit mode: max. virtual_width == 8176 (no extra mask needed);
//other colordepths are unsupported on CRTC2.
switch(target->space)
{
case B_CMAP8:
if (target->virtual_width > (16368 & ~crtc_mask))
target->virtual_width = (16368 & ~crtc_mask);
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
if (target->virtual_width > (8184 & ~crtc_mask))
target->virtual_width = (8184 & ~crtc_mask);
break;
case B_RGB24_LITTLE:
if (target->virtual_width > (5456 & ~crtc_mask))
target->virtual_width = (5456 & ~crtc_mask);
break;
case B_RGB32_LITTLE:
if (target->virtual_width > (4092 & ~crtc_mask))
target->virtual_width = (4092 & ~crtc_mask);
break;
}
/* virtual_height: The only constraint here is the cards memory size which is
* checked later on in ProposeMode: virtual_height is adjusted then if needed.
* 'Limiting here' to the variable size that's at least available (uint16). */
if (target->virtual_height > 65535) target->virtual_height = 65535;
}
/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
* it was confined above, so we can finally calculate safely if we need slopspace
* for this mode... */
if (si->acc_mode)
video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
else
video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
video_pitch, target->space));
if (target->virtual_width != video_pitch)
LOG(2,("INIT: effective mode slopspace is %d pixels\n",
(video_pitch - target->virtual_width)));
/* now calculate bytes_per_row for this mode */
*bytes_per_row = video_pitch * (depth >> 3);
return B_OK;
}
+166 -63
View File
@@ -2,7 +2,7 @@
/* some bits are hacks, where PINS is not known */
/* Authors:
Mark Watson 2/2000,
Rudolf Cornelissen 10-11/2002
Rudolf Cornelissen 10/2002-4/2003
*/
#define MODULE_BIT 0x00002000
@@ -111,52 +111,80 @@ status_t parse_pins ()
status_t pins1_read(uint8 *pins, uint8 length)
{
//remove later on here:
// float f_ref; /* PLL reference-oscillator frequency */
// uint32 max_system_vco; /* graphics engine PLL VCO limits */
// uint32 min_system_vco;
// uint32 max_pixel_vco; /* dac1 PLL VCO limits */
// uint32 min_pixel_vco;
// uint32 max_video_vco; /* dac2, maven PLL VCO limits */
// uint32 min_video_vco;
// uint32 std_engine_clock; /* graphics engine clock speed needed */
// uint32 std_engine_clock_dh;
// uint32 max_dac1_clock; /* dac1 limits */
// uint32 max_dac1_clock_8; /* dac1 limits correlated to RAMspeed limits */
// uint32 max_dac1_clock_16;
// uint32 max_dac1_clock_24;
// uint32 max_dac1_clock_32;
// uint32 max_dac1_clock_32dh;
// uint32 max_dac2_clock; /* dac2 limits */
// uint32 max_dac2_clock_8; /* dac2, maven limits correlated to RAMspeed limits */
// uint32 max_dac2_clock_16;
// uint32 max_dac2_clock_24;
// uint32 max_dac2_clock_32;
// uint32 max_dac2_clock_32dh;
// bool secondary_head; /* presence of functions */
// bool secondary_tvout;
// bool primary_dvi;
// bool secondary_dvi;
// uint32 memory_size; /* memory in Mb */
// uint32 mctlwtst_reg; /* memory control waitstate register */
// uint32 memrdbk_reg; /* memory readback register */
// uint32 option_reg; /* option register */
// uint32 option2_reg; /* option2 register */
// uint32 option3_reg; /* option3 register */
// uint32 option4_reg; /* option4 register */
// uint8 v3_option2_reg;
// uint8 v3_clk_div; /* pins v3 memory and system clock division factors */
// uint8 v3_mem_type; /* pins v3 memory type info */
// uint16 v5_mem_type; /* pins v5 memory type info */
// bool sdram;
//end remove later on here.
if (length != 64)
{
LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length));
return B_ERROR;
}
//fixme: implement this..
return B_ERROR;
//reset all for test:
//float:
si->ps.f_ref = 0;
//uint32:
si->ps.max_system_vco = 0;
si->ps.min_system_vco = 0;
si->ps.min_pixel_vco = 0;
si->ps.min_video_vco = 0;
si->ps.std_engine_clock_dh = 0;
si->ps.max_dac1_clock_32 = 0;
si->ps.max_dac1_clock_32dh = 0;
si->ps.memory_size = 0;
si->ps.mctlwtst_reg = 0;
si->ps.memrdbk_reg = 0;
si->ps.option2_reg = 0;
si->ps.option3_reg = 0;
si->ps.option4_reg = 0;
//uint8:
si->ps.v3_option2_reg = 0;
si->ps.v3_clk_div = 0;
si->ps.v3_mem_type = 0;
//uint16:
si->ps.v5_mem_type = 0;
//bools:
si->ps.secondary_head = false;
si->ps.secondary_tvout = false;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
si->ps.sdram = true;
//experimental: checkout!
si->ps.max_dac1_clock_32 = pins[22];//ramdac
si->ps.max_pixel_vco = (pins[25] << 8) | pins[24];//PCLK
si->ps.std_engine_clock = (pins[29] << 8) | pins[28];
if (((pins[31] << 8) | pins[30]) < si->ps.std_engine_clock)
si->ps.std_engine_clock = (pins[31] << 8) | pins[30];
if (((pins[33] << 8) | pins[32]) < si->ps.std_engine_clock)
si->ps.std_engine_clock = (pins[33] << 8) | pins[32];
//temp. test to see some vals..
si->ps.max_video_vco = (pins[27] << 8) | pins[26];//LCLK
//feature flags:
si->ps.option_reg = (pins[53] << 24) | (pins[52] << 16) | (pins[51] << 8) | pins [50];
si->ps.max_dac2_clock = (pins[35] << 8) | pins[34];//clkmod
si->ps.max_dac2_clock_8 = (pins[37] << 8) | pins[36];//testclk
si->ps.max_dac2_clock_16 = (pins[39] << 8) | pins[38];//vgafreq1
si->ps.max_dac2_clock_24 = (pins[41] << 8) | pins[40];//vgafreq2
si->ps.max_dac2_clock_32 = (pins[55] << 8) | pins[54];//vga clock
si->ps.max_dac2_clock_32dh = pins[58];//vid ctrl
si->ps.max_dac1_clock = (pins[29] << 8) | pins[28];//clkbase
si->ps.max_dac1_clock_8 = (pins[31] << 8) | pins[30];//4mb
si->ps.max_dac1_clock_16 = (pins[33] << 8) | pins[32];//8mb
si->ps.max_dac1_clock_24 = pins[23];//ramdac type
//test! Don't actually use the reported settings for now...
return B_OK;
}
status_t pins2_read(uint8 *pins, uint8 length)
{
if (length != 64)
{
LOG(8,("INFO: wrong PINS length, expected 64, got %d\n", length));
return B_ERROR;
}
LOG(2,("INFO: PINS version 2 details not yet known\n"));
return B_ERROR;
}
@@ -424,18 +452,15 @@ status_t pins5_read(uint8 *pins, uint8 length)
}
/* fill out the shared info si->ps struct */
if (pins[4]) m_factor = 8;
if (pins[4] == 0x01) m_factor = 8;
if (pins[4] >= 0x02) m_factor = 10;
si->ps.max_system_vco = m_factor * pins[36];
si->ps.max_video_vco = m_factor * pins[37];
/* pixelVCO multiplier is 10 if pins V5.2 */
if (pins[4] == 0x02) si->ps.max_pixel_vco = 10 * pins[38];
else si->ps.max_pixel_vco = m_factor * pins[38];
si->ps.max_pixel_vco = m_factor * pins[38];
si->ps.min_system_vco = m_factor * pins[121];
si->ps.min_video_vco = m_factor * pins[122];
/* pixelVCO multiplier is 10 if pins V5.2 */
if (pins[4] == 0x02) si->ps.min_pixel_vco = 10 * pins[123];
else si->ps.min_pixel_vco = m_factor * pins[123];
si->ps.min_pixel_vco = m_factor * pins[123];
if (pins[39] == 0xff) si->ps.max_dac1_clock_8 = si->ps.max_pixel_vco;
else si->ps.max_dac1_clock_8 = 4 * pins[39];
@@ -517,6 +542,9 @@ void fake_pins(void)
switch (si->ps.card_type)
{
case MIL1:
pinsmil1_fake();
break;
case MIL2:
pinsmil2_fake();
break;
@@ -541,15 +569,16 @@ void fake_pins(void)
}
/* find out if the card has a maven */
if (i2c_maven_probe() == B_OK)
si->ps.secondary_tvout = false;
si->ps.secondary_head = false;
/* only do I2C probe if the card has a chance */
if (si->ps.card_type >= G100)
{
si->ps.secondary_tvout = true;
si->ps.secondary_head = true;
}
else
{
si->ps.secondary_tvout = false;
si->ps.secondary_head = false;
if (i2c_maven_probe() == B_OK)
{
si->ps.secondary_tvout = true;
si->ps.secondary_head = true;
}
}
/* not used because no coldstart will be attempted */
@@ -567,8 +596,82 @@ void fake_pins(void)
si->ps.v5_mem_type = 0;
}
void pinsmil1_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
si->ps.f_ref = 14.31818;
/* see MIL1 specs */
si->ps.max_system_vco = 220;
si->ps.min_system_vco = 110;
si->ps.max_pixel_vco = 220;
si->ps.min_pixel_vco = 110;
/* no specs, assuming these */
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
/* see MIL1 specs */
si->ps.max_dac1_clock = 220;
si->ps.max_dac1_clock_8 = 220;
si->ps.max_dac1_clock_16 = 200;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 180;
si->ps.max_dac1_clock_32 = 136;
si->ps.max_dac1_clock_32dh = 0;
/* see specs */
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 0;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 2Mb RAM mounted */
//fixme: see if we can get this from OPTION or so...
si->ps.memory_size = 2;
//fixme: should be overrule-able via mga.settings for MIL1.
//fail-safe mode for now:
si->ps.sdram = true;
}
void pinsmil2_fake(void)
{
/* 'worst case' scenario defaults, overrule-able via mga.settings if needed */
si->ps.f_ref = 14.31818;
/* see MIL2 specs */
si->ps.max_system_vco = 220;
si->ps.min_system_vco = 110;
si->ps.max_pixel_vco = 220;
si->ps.min_pixel_vco = 110;
/* no specs, assuming these */
si->ps.max_video_vco = 0;
si->ps.min_video_vco = 0;
/* see MIL2 specs */
si->ps.max_dac1_clock = 220;
si->ps.max_dac1_clock_8 = 220;
si->ps.max_dac1_clock_16 = 200;
/* 'failsave' values */
si->ps.max_dac1_clock_24 = 180;
si->ps.max_dac1_clock_32 = 136;
si->ps.max_dac1_clock_32dh = 0;
/* see specs */
si->ps.max_dac2_clock = 0;
si->ps.max_dac2_clock_8 = 0;
si->ps.max_dac2_clock_16 = 0;
si->ps.max_dac2_clock_24 = 0;
si->ps.max_dac2_clock_32 = 0;
/* 'failsave' value */
si->ps.max_dac2_clock_32dh = 0;
si->ps.primary_dvi = false;
si->ps.secondary_dvi = false;
/* presume 4Mb RAM mounted */
//fixme: see if we can get this from OPTION or so...
si->ps.memory_size = 4;
//fixme: should be overrule-able via mga.settings for MIL2.
//fail-safe mode for now:
si->ps.sdram = true;
}
void pinsg100_fake(void)
@@ -741,12 +844,12 @@ void pinsg450_fake(void)
si->ps.f_ref = 27.000;
/* see G450 pins readouts for max ranges, then use a bit smaller ones */
/* carefull not to take to high lower limits, and high should be >= 2x low. */
si->ps.max_system_vco = 600;
si->ps.min_system_vco = 256;
si->ps.max_system_vco = 640;
si->ps.min_system_vco = 320;
si->ps.max_pixel_vco = 640;
si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600;
si->ps.min_video_vco = 256;
si->ps.max_video_vco = 640;
si->ps.min_video_vco = 320;
si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360;
@@ -786,8 +889,8 @@ void pinsg550_fake(void)
si->ps.min_system_vco = 384;
si->ps.max_pixel_vco = 960;
si->ps.min_pixel_vco = 320;
si->ps.max_video_vco = 600;
si->ps.min_video_vco = 256;
si->ps.max_video_vco = 960;
si->ps.min_video_vco = 320;
si->ps.max_dac1_clock = 360;
si->ps.max_dac1_clock_8 = 360;
si->ps.max_dac1_clock_16 = 360;
+479 -92
View File
@@ -1,76 +1,114 @@
/* program the MAVEN in monitor mode */
/* Thanx to Petr Vandrovec for info on the MAVEN */
/* Mark Watson 6/2000 */
/* Authors:
Mark Watson 6/2000,
Rudolf Cornelissen 1/2003-4/2003
Thanx to Petr Vandrovec for writing matroxfb.
*/
#define MODULE_BIT 0x00001000
#include "mga_std.h"
status_t g450_g550_maven_set_vid_pll(display_mode target);
status_t g100_g400max_maven_set_vid_pll(display_mode target);
status_t gx00_maven_dpms(uint8 display,uint8 h,uint8 v)
{
if (display&h&v)
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G400MAX) return B_OK;
if (display & h & v)
{
MAVW(MONEN,0xb2);
MAVW(MONSET,0x20); /*must be set to this in monitor mode*/
MAVW(OUTMODE,3); /*monitor mode*/
MAVW(STABLE,0x22); /*makes picture stable?*/
MAVW(TEST,0x00); /*turn off test signal*/
/* turn on screen */
if (!(si->dm.flags & TV_BITS))
{
/* monitor mode */
MAVW(MONEN, 0xb2);
MAVW(MONSET, 0x20); /* must be set to this in monitor mode */
MAVW(OUTMODE, 0x03); /* output: monitor mode */
MAVW(STABLE, 0x22); /* makes picture stable? */
MAVW(TEST, 0x00); /* turn off test signal */
}
else
{
/* TVout mode */
MAVW(MONEN, 0xb3);
MAVW(MONSET, 0x20);
MAVW(OUTMODE, 0x08); /* output: SVideo/Composite */
MAVW(STABLE, 0x02); /* makes picture stable? */
//fixme? linux uses 0x14...
MAVW(TEST, (MAVR(TEST) & 0x10));
}
}
else
{
/*turn off screen using a few methods!*/
MAVW(STABLE,0x6a);
// MAVW(TEST,0x3);
MAVW(OUTMODE,0x00);
/* turn off screen using a few methods! */
MAVW(STABLE, 0x6a);
// MAVW(TEST, 0x03);
MAVW(OUTMODE, 0x00);
}
return B_OK;
}
/*set a mode line - inputs are in pixels/scanlines*/
status_t gx00_maven_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
)
status_t gx00_maven_set_timing(display_mode target)
{
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G400MAX) return B_OK;
LOG(4,("MAVEN: setting timing\n"));
/*check horizontal timing parameters are to nearest 8 pixels*/
if ((hdisp_e&7)|(hsync_s&7)|(hsync_e&7)|(htotal&7))
if ((target.timing.h_display & 0x07) |
(target.timing.h_sync_start & 0x07) |
(target.timing.h_sync_end & 0x07) |
(target.timing.h_total & 0x07))
{
LOG(8,("MAVEN:Horizontal timings are not multiples of 8 pixels\n"));
LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n"));
return B_ERROR;
}
/*program the MAVEN*/
MAVWW(LASTLINEL,htotal);
MAVWW(HSYNCLENL,(hsync_e-hsync_s));
MAVWW(HSYNCSTRL,(htotal-hsync_s));
MAVWW(HDISPLAYL,(htotal-hsync_s+hdisp_e));
MAVWW(HTOTALL,(htotal+1));
MAVWW(LASTLINEL, target.timing.h_total);
MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
target.timing.h_display));
MAVWW(HTOTALL, (target.timing.h_total + 1));
MAVWW(VSYNCLENL,(vsync_e-vsync_s-1));
MAVWW(VSYNCSTRL,(vtotal-vsync_s));
MAVWW(VDISPLAYL,(vtotal-1));
MAVWW(VTOTALL,(vtotal-1));
MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
MAVWW(VDISPLAYL, (target.timing.v_total - 1));
MAVWW(VTOTALL, (target.timing.v_total - 1));
MAVWW(HVIDRSTL,(htotal-si->crtc_delay));
MAVWW(VVIDRSTL,(vtotal-2));
MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
MAVWW(VVIDRSTL, (target.timing.v_total - 2));
return B_OK;
}
//not used:
/*
void gx00_maven_delay(int number)
{
// this function is nolonger needed on G450/G550 cards
if (si->ps.card_type > G400MAX) return;
MAVWW(HVIDRSTL,(si->dm.timing.h_total-number));
}
*/
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t gx00_maven_mode(int mode,float brightness)
{
uint8 luma;
/* this function is nolonger needed on G450/G550 cards */
if (si->ps.card_type > G400MAX) return B_OK;
/*set luma to a suitable value for brightness*/
/*assuming 1A is a sensible value*/
luma = (uint8)(0x1a * brightness);
@@ -80,93 +118,442 @@ status_t gx00_maven_mode(int mode,float brightness)
return B_OK;
}
/*program the pixpll on the maven - frequency in kHz*/
status_t gx00_maven_set_pix_pll(float f_vco)
status_t gx00_maven_set_vid_pll(display_mode target)
{
switch (si->ps.card_type)
{
case G450:
case G550:
return g450_g550_maven_set_vid_pll(target);
break;
default:
return g100_g400max_maven_set_vid_pll(target);
break;
}
return B_ERROR;
}
status_t g450_g550_maven_set_vid_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
uint time = 0;
float pix_setting;
float pix_setting, req_pclk;
status_t result;
LOG(4,("MAVEN:Setting PIX PLL %fMHz\n", f_vco));
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = gx00_maven_pix_pll_find(f_vco,&pix_setting,&m,&n,&p);
result = g450_g550_maven_vid_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
/*reprogram (select,wait for stability)*/
MAVW(PIXPLLM,(m)); /*set m value*/
MAVW(PIXPLLN,(n)); /*set n value*/
MAVW(PIXPLLP,(p|0x80)); /*set p value*/
LOG(2,("MAVEN: Clocks found: %x %x %x\n",m,n,p));
delay(1000); /*wait 1000us for PIXPLL to lock (no way of knowing)*/
LOG(2,("MAVEN: PIX PLL frequency locked\n"));
/*reprogram (disable,select,wait for stability,enable)*/
CR2W(CTL, (CR2R(CTL) | 0x08)); /* disable the VIDPLL */
CR2W(CTL, (CR2R(CTL) | 0x06)); /* select the VIDPLL */
DXIW(VIDPLLM,(m)); /* set m value */
DXIW(VIDPLLN,(n)); /* set n value */
DXIW(VIDPLLP,(p)); /* set p value */
/* Wait for the VIDPLL frequency to lock until timeout occurs */
while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("MAVEN: VID PLL frequency not locked!\n"));
else
LOG(2,("MAVEN: VID PLL frequency locked\n"));
CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */
return B_OK;
}
/*find nearest valid pix pll*/
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 * m_result,uint8 * n_result,uint8 * p_result)
/* program the video PLL in the MAVEN */
status_t g100_g400max_maven_set_vid_pll(display_mode target)
{
float f_ref=27.000;
int n_min=4;
int n_max=127;
int m_min=2;
int m_max=31;
int m=0,n=0,p=0;
float error;
float error_best;
int best[3];
float f_rat;
uint8 m=0,n=0,p=0;
LOG(4,("MAVEN:Checking PIX PLL %fMHz\n", f_vco));
float pix_setting, req_pclk;
status_t result;
/*f_rat.m/p=n where m=M+1,n=N+1,p=P+1,f_rat=f_vco/f_ref*/
f_rat = f_vco/f_ref;
error_best = 999999999;
for (p=0x2 -1*(f_vco>80.0);p<0x10;p=p<<1)
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p);
if (result != B_OK)
{
for (m=m_min;m<m_max;m++)
{
/*calculate n for this m & p (and check for validity)*/
n=(int)((f_rat*m*p)+0.5);
if (n>n_max || n<n_min)
continue;
/*find error in frequency this gives*/
error=fabs(((f_ref*n)/(m*p))-f_vco);
if (error<error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
return result;
}
m=best[0];
n=best[1];
p=best[2];
/*calculate value of s for fvco, not sure if these are correct*/
for(;;)/*set loop filter bandwidth -> spot the Perl coder :-)*/
/*reprogram (select,wait for stability)*/
MAVW(PIXPLLM,(m)); /* set m value */
MAVW(PIXPLLN,(n)); /* set n value */
MAVW(PIXPLLP,(p | 0x80)); /* set p value enabling PLL */
/* Wait for the VIDPLL frequency to lock: detection is not possible it seems */
snooze(2000);
LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
return B_OK;
}
/* find nearest valid video PLL setting */
status_t g100_g400max_maven_vid_pll_find(
display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
/* determine the max. reference-frequency postscaler setting for the current card */
//fixme: check G100 and G200 m_max if possible...
switch(si->ps.card_type)
{
if(f_vco>180) {p|=0x18;break;};
if(f_vco>140) {p|=0x10;break;};
if(f_vco>100) {p|=0x08;break;};
case G100:
LOG(4,("MAVEN: G100 restrictions apply\n"));
m_max = 32;
break;
case G200:
LOG(4,("MAVEN: G200 restrictions apply\n"));
m_max = 32;
break;
default:
LOG(4,("MAVEN: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
/*set the result*/
*result = (float) (f_ref*n)/(m*(p&0x7));
*m_result = m-1;
*n_result = n-1;
*p_result = p-1;
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
/*display the found value*/
LOG(4,("MAVEN: pixpllcheck - requested %fMHz got %fMHz\n",(double)f_vco,*result));
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_video_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_video_vco / 8.0))
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 8.0)));
req_pclk = (si->ps.min_video_vco / 8.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x10; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= m_max; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
/* ..and check for validity */
if ((n < 8) || (n > 128)) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
/* calc the needed PLL loopbackfilter setting belonging to current VCO speed */
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
switch(si->ps.card_type)
{
case G100:
case G200:
for(;;)
{
if (f_vco >= 180) {p |= (0x03 << 3); break;};
if (f_vco >= 140) {p |= (0x02 << 3); break;};
if (f_vco >= 100) {p |= (0x01 << 3); break;};
break;
}
break;
default:
for(;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
/* return the results */
*calc_pclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
status_t gx50_maven_check_vid_pll(uint8 m, uint8 n, uint8 p)
{
uint time = 0, count = 0;
/* reprogram (disable,select,wait for stability,enable) */
CR2W(CTL, (CR2R(CTL) | 0x06)); /* select the VIDPLL */
DXIW(VIDPLLM,(m)); /* set m value */
DXIW(VIDPLLN,(n)); /* set n value */
DXIW(VIDPLLP,(p)); /* set p value */
/* give the PLL 1mS at least to get a lock */
time = 0;
while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 1000))
{
time++;
snooze(1);
}
/* no lock aquired, not useable */
if (time > 1000) return B_ERROR;
/* check if lock holds for at least 90% of the time */
for (time = 0, count = 0; time <= 1000; time++)
{
if(DXIR(VIDPLLSTAT) & 0x40) count++;
snooze(1);
}
/* we have a winner */
if (count >= 900) return B_OK;
/* nogo, the PLL does not stabilize */
return B_ERROR;
}
status_t gx50_maven_check_vid_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
{
uint8 s=0, p_backup = *p;
/* preset no candidate, non working setting */
*q = 0;
/* preset lowest range filter */
*p &= 0x47;
/* iterate through all possible filtersettings */
CR2W(CTL, (CR2R(CTL) | 0x08)); /* disable the VIDPLL */
for (s = 0; s < 8 ;s++)
{
if (gx50_maven_check_vid_pll(m, n, *p)== B_OK)
{
/* now check 3 closest lower and higher settings */
if ((gx50_maven_check_vid_pll(m, n - 3, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n - 2, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n - 1, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 1, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 2, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 3, *p)== B_OK))
{
LOG(2,("MAVEN: found optimal working VCO filter: #%d\n",s));
/* preset first choice setting found */
*q = 1;
/* we are done */
CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */
return B_OK;
}
else
{
LOG(2,("MAVEN: found critical but working VCO filter: #%d\n",s));
/* preset backup setting found */
*q = 2;
/* remember this setting */
p_backup = *p;
/* let's continue to see if a better filter exists */
}
}
/* new filtersetting to try */
*p += (1 << 3);
}
/* return the (last found) backup result, or the original p value */
*p = p_backup;
CR2W(CTL, (CR2R(CTL) & ~0x08)); /* enable the VIDPLL */
/* we found only a non-optimal value */
if (*q == 2) return B_OK;
/* nothing worked at all */
LOG(2,("MAVEN: no working VCO filter found!\n"));
return B_ERROR;
}
/* find nearest valid video PLL setting */
status_t g450_g550_maven_vid_pll_find
(display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test)
{
int m = 0, n = 0;
uint8 p = 0, q = 0;
float error, error_best = 999999999;
int best[3];
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
LOG(4,("MAVEN: G450/G550 restrictions apply\n"));
/* determine the max. pixelclock for the current videomode */
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
/* use fail-safe value */
max_pclk = si->ps.max_dac2_clock_32;
break;
}
/* if some dualhead mode is active, an extra restriction might apply */
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
/* Make sure the requested pixelclock is within the PLL's operational limits */
/* lower limit is min_pixel_vco divided by highest postscaler-factor */
if (req_pclk < (si->ps.min_video_vco / 16.0))
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 16.0)));
req_pclk = (si->ps.min_video_vco / 16.0);
}
/* upper limit is given by pins in combination with current active mode */
if (req_pclk > max_pclk)
{
LOG(4,("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
/* iterate through all valid PLL postscaler settings */
for (p=0x01; p < 0x20; p = p<<1)
{
/* calculate the needed VCO frequency for this postscaler setting */
f_vco = req_pclk * p;
/* check if this is within range of the VCO specs */
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
/* iterate trough all valid reference-frequency postscaler settings */
for (m = 2; m <= 32; m++)
{
/* calculate VCO postscaler setting for current setup.. */
n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5);
/* ..and check for validity, BUT:
* Keep in mind that we need to be able to test n-3 ... n+3! */
if ((n < (8 + 3)) || (n > (128 - 3))) continue;
/* find error in frequency this setting gives */
error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p));
/* note the setting if best yet */
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
/* setup the scalers programming values for found optimum setting */
m=best[0] - 1;
n=best[1] - 2;
switch(best[2])
{
case 1:
p = 0x40;
break;
case 2:
p = 0x00;
break;
case 4:
p = 0x01;
break;
case 8:
p = 0x02;
break;
case 16:
p = 0x03;
break;
}
/* log the closest VCO speed found */
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2);
LOG(2,("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
/* now find the filtersetting that matches best with this frequency by testing.
* for now we assume this routine succeeds to get us a stable setting */
if (test)
gx50_maven_check_vid_pll_range(m, n, &p, &q);
else
LOG(2,("MAVEN: Not testing G450/G550 VCO feedback filters\n"));
/* return the results */
*calc_pclk = f_vco / best[2];
*m_result = m;
*n_result = n;
*p_result = p;
/* display the found pixelclock values */
LOG(2,("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
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 gx00_general_dac_select(int);
status_t gx00_general_wait_retrace();
status_t gx00_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row);
//status_t gx00_general_bios_to_powergraphics();
/* apsed: logging macros */
@@ -35,6 +36,7 @@ status_t pins3_read(uint8 *pins, uint8 length);
status_t pins4_read(uint8 *pins, uint8 length);
status_t pins5_read(uint8 *pins, uint8 length);
void fake_pins(void);
void pinsmil1_fake(void);
void pinsmil2_fake(void);
void pinsg100_fake(void);
void pinsg200_fake(void);
@@ -57,22 +59,24 @@ status_t g200_dac_set_sys_pll();
status_t g100_dac_set_sys_pll();
status_t mil2_dac_init(void);
status_t mil2_dac_mode(int,float, int hsync_pos,int vsync_pos, int sync_green);
status_t mil2_dac_palette(uint8*,uint8*,uint8*);
status_t mil2_dac_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *);
status_t mil2_dac_set_pix_pll(float f_vco,int bpp);
/*MAVEN functions*/
status_t gx00_maven_dpms(uint8,uint8,uint8);
status_t gx00_maven_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t gx00_maven_set_timing(display_mode target);
status_t gx00_maven_mode(int,float);
status_t gx00_maven_pix_pll_find(float f_vco,float * result,uint8 *,uint8 *,uint8 *);
status_t gx00_maven_set_pix_pll(float f_vco);
status_t g100_g400max_maven_vid_pll_find(display_mode target,float * calc_pclk,
uint8 * m_result,uint8 * n_result,uint8 * p_result);
status_t g450_g550_maven_vid_pll_find(display_mode target,float * calc_pclk,
uint8 * m_result,uint8 * n_result,uint8 * p_result, uint8 test);
status_t gx00_maven_set_vid_pll(display_mode target);
/*MAVENTV functions*/
status_t g100_g400max_maventv_vid_pll_find(
display_mode target, unsigned int * ht_new, unsigned int * ht_last_line,
uint8 * m_result, uint8 * n_result, uint8 * p_result);
int maventv_init(display_mode target);
/*CRTC1 functions*/
status_t gx00_crtc_validate_timing(
@@ -86,7 +90,7 @@ status_t gx00_crtc_set_timing(
);
status_t gx00_crtc_depth(int mode);
status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp);
status_t gx00_crtc_set_display_pitch(uint32 pitch,uint8 bpp);
status_t gx00_crtc_set_display_pitch();
status_t gx00_crtc_dpms(uint8,uint8,uint8);
status_t gx00_crtc_dpms_fetch(uint8*,uint8*,uint8*);
@@ -100,24 +104,23 @@ status_t gx00_crtc_cursor_hide();
/*CRTC2 functions*/
/*XXX - validate_timing*/
status_t g400_crtc2_set_timing(
uint32 hdisp_e,uint32 hsync_s,uint32 hsync_e,uint32 htotal,
uint32 vdisp_e,uint32 vsync_s,uint32 vsync_e,uint32 vtotal,
uint8 hsync_pos,uint8 vsync_pos
);
status_t g400_crtc2_set_timing(display_mode target);
status_t g400_crtc2_depth(int mode);
status_t g400_crtc2_set_display_pitch(uint32 pitch,uint8 bpp);
status_t g400_crtc2_set_display_pitch();
status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp);
status_t g400_crtc2_dpms(uint8 display,uint8 h,uint8 v);
status_t g400_crtc2_dpms_fetch(uint8 * display,uint8 * h,uint8 * v);
/*acceleration functions*/
status_t check_acc_capability(uint32 feature);
status_t gx00_acc_init();
status_t gx00_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col);
status_t gx00_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col);
status_t gx00_acc_blit(uint16,uint16,uint16, uint16,uint16,uint16 );
status_t gx00_acc_transparent_blit(uint16,uint16,uint16, uint16,uint16,uint16, uint32);
status_t gx00_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
uint16 xd,uint16 yd,uint16 wd,uint16 hd);
status_t gx00_acc_wait_idle();
/*backend scaler functions*/
+72 -505
View File
@@ -2,10 +2,9 @@
Program the Texas TVP3026
using Texas Instrument TVP3026 manual SLA098B July 1996
Author:
Apsed May 2002 a lot of time after ...
NB BPP24 and BPP32DIR not tested
Authors:
Apsed May 2002 plus a lot of time after;
Rudolf Cornelissen 3/2003.
*/
#define MODULE_BIT 0x00010000
@@ -13,76 +12,12 @@
#include <OS.h> // system_time, snooze
#include "mga_std.h"
#define PIXEL_BUS_WIDTH64 0 // if 0: 32 bits width, else 64
#define PIXEL_BUS_WIDTH64 1 // if 0: 32 bits width, else 64
#define FPLL_REF 14.31818 // MHz
#define FVCO_MAX 220.00000 // MHz, may be 220 or 250, see 3.5
#define FVCO_MIN 110.00000 // MHz
#define FPLL_MCLK 100.00000 // MHz
//r: ??
#define MGAVGA_INSTS0 0x1FC2
// access the TVP3026, this is near G200 DAC but ...
/* direct registers */
#define TVP_PALWTADD 0x3c00
#define TVP_PALDATA 0x3c01
#define TVP_PIXRDMSK 0x3c02
#define TVP_PALRDADD 0x3c03
#define TVP_CUROVRWTADD 0x3c04
#define TVP_CUROVRDATA 0x3c05
#define TVP_CUROVRRDADD 0x3c07
#define TVP_DIRCURCTRL 0x3c09
#define TVP_X_DATAREG 0x3c0a
#define TVP_CURRAMDATA 0x3c0b
#define TVP_CURPOSXL 0x3c0c
#define TVP_CURPOSXH 0x3c0d
#define TVP_CURPOSYL 0x3c0e
#define TVP_CURPOSYH 0x3c0f
/* indirect registers */
#define TVPI_SILICONREV 0x01
#define TVPI_INDCURCTRL 0x06
#define TVPI_LATCHCTRL 0x0f
#define TVPI_TCOLCTRL 0x18
#define TVPI_MULCTRL 0x19
#define TVPI_CLOCKSEL 0x1a
#define TVPI_PALPAGE 0x1c
#define TVPI_GENCTRL 0x1d
#define TVPI_MISCCTRL 0x1e
#define TVPI_GENIOCTRL 0x2a
#define TVPI_GENIODATA 0x2b
#define TVPI_PLLADDR 0x2c
#define TVPI_PIXPLLDATA 0x2d
#define TVPI_MEMPLLDATA 0x2e
#define TVPI_LOOPLLDATA 0x2f
#define TVPI_COLKEYOL 0x30
#define TVPI_COLKEYOH 0x31
#define TVPI_COLKEYRL 0x32
#define TVPI_COLKEYRH 0x33
#define TVPI_COLKEYGL 0x34
#define TVPI_COLKEYGH 0x35
#define TVPI_COLKEYBL 0x36
#define TVPI_COLKEYBH 0x37
#define TVPI_COLKEYCTRL 0x38
#define TVPI_MEMCLKCTRL 0x39
#define TVPI_SENSETEST 0x3a
#define TVPI_TESTMODEDATA 0x3b
#define TVPI_CRCREML 0x3c
#define TVPI_CRCREMH 0x3d
#define TVPI_CRCBITSEL 0x3e
#define TVPI_ID 0x3f
#define TVPI_RESET 0xff
/*read and write from the TVP3026 registers*/
#define TVPR(A) (MGA_REG8(TVP_##A))
#define TVPW(A,B) (MGA_REG8(TVP_##A)=B)
/*read and write from the TVP3026 indirect register*/
#define TVPIR(A) (TVPW(PALWTADD,TVPI_##A),TVPR(X_DATAREG))
#define TVPIW(A,B) (TVPW(PALWTADD,TVPI_##A),TVPW(X_DATAREG,B))
#define WAIT_FOR_PLL_LOCK( pll, on_error) do { \
bigtime_t start, now; \
float delay; \
@@ -90,7 +25,7 @@
\
start = system_time(); \
for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \
int status = TVPIR (pll ## PLLDATA); \
int status = DXIR (pll ## PLLDATA); \
if (status & 0x40) break; \
/* snooze(10); */ \
} \
@@ -103,369 +38,6 @@
} \
} while (0)
#define REREAD_PLL( pll) do { \
uint8 n, m, p; \
float f, vco; \
\
TVPIW(PLLADDR, 0x00); \
n = TVPIR(pll ## PLLDATA); \
TVPIW(PLLADDR, 0x15); \
m = TVPIR(pll ## PLLDATA); \
TVPIW(PLLADDR, 0x2a); \
p = TVPIR(pll ## PLLDATA); \
vco = 8 * FPLL_REF * (65 - (m & 0x3f)) / (65 - (n & 0x3f)); \
f = vco / (1 << (p & 0x03)); \
LOG(2,("mil2 reread %s PLL, nmp 0x%02x 0x%02x 0x%02x, %fMHz, vco %fMHz\n", \
#pll, n, m, p, f, vco)); \
} while (0)
#define DUMP_CFG(reg) MSG(( \
"PCI CONFIG register 0x%04x %20s 0x%08x\n", MGACFG_##reg, #reg, CFGR(reg)))
#define DUMP_VGA(reg) MSG(( \
"MGA VGA register 0x%04x %20s 0x%02x\n", MGAVGA_##reg, #reg, VGAR(reg)))
#define DUMP_VGA_ATTR(reg) MSG(( \
"MGA VGA ATTR register 0x%04x %20s 0x%02x\n", 0x##reg, "ATTR" #reg, VGAR_I(ATTR, 0x##reg)))
#define DUMP_VGA_SEQ(reg) MSG(( \
"MGA VGA SEQ register 0x%04x %20s 0x%02x\n", 0x##reg, "SEQ" #reg, VGAR_I(SEQ, 0x##reg)))
#define DUMP_VGA_GCTL(reg) MSG(( \
"MGA VGA GCTL register 0x%04x %20s 0x%02x\n", 0x##reg, "GCTL" #reg, VGAR_I(GCTL, 0x##reg)))
#define DUMP_VGA_CRTC(reg) MSG(( \
"MGA VGA CRTC register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTC" #reg, VGAR_I(CRTC, 0x##reg)))
#define DUMP_VGA_CRTCEXT(reg) MSG(( \
"MGA VGA CRTCEXT register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTCEXT" #reg, VGAR_I(CRTCEXT, 0x##reg)))
#define DUMP_TVP(reg) MSG(( \
"TVP3028 register 0x%04x %20s 0x%02x\n", TVP_##reg, #reg, TVPR(reg)))
#define DUMP_TVPI(reg) MSG(( \
"TVP3028 INDIRECT register 0x%04x %20s 0x%02x\n", TVPI_##reg, #reg, TVPIR(reg)))
#define DUMP_MGA(reg) MSG(( \
"MGA register 0x%04x %20s 0x%08x\n", MGAACC_##reg, #reg, ACCR(reg)))
static void dump_tvp3026 (void)
{
/* TVP3026 DAC direct registers */
// DUMP_TVP (PALWTADD);
// DUMP_TVP (PALDATA );
DUMP_TVP (PIXRDMSK);
// DUMP_TVP (PALRDADD);
DUMP_TVP (CUROVRWTADD);
DUMP_TVP (CUROVRDATA);
DUMP_TVP (CUROVRRDADD);
DUMP_TVP (DIRCURCTRL);
// DUMP_TVP (X_DATAREG);
DUMP_TVP (CURRAMDATA);
DUMP_TVP (CURPOSXL);
DUMP_TVP (CURPOSXH);
DUMP_TVP (CURPOSYL);
DUMP_TVP (CURPOSYH);
/* TVP3026 DAC indirect registers */
DUMP_TVPI (SILICONREV);
DUMP_TVPI (INDCURCTRL);
DUMP_TVPI (LATCHCTRL);
DUMP_TVPI (TCOLCTRL);
DUMP_TVPI (MULCTRL);
DUMP_TVPI (CLOCKSEL);
DUMP_TVPI (PALPAGE);
DUMP_TVPI (GENCTRL);
DUMP_TVPI (MISCCTRL);
DUMP_TVPI (GENIOCTRL);
DUMP_TVPI (GENIODATA);
// DUMP_TVPI (PLLADDR);
// DUMP_TVPI (PIXPLLDATA);
// DUMP_TVPI (MEMPLLDATA);
// DUMP_TVPI (LOOPLLDATA);
REREAD_PLL (PIX);
REREAD_PLL (MEM);
REREAD_PLL (LOO);
DUMP_TVPI (COLKEYOL);
DUMP_TVPI (COLKEYOH);
DUMP_TVPI (COLKEYRL);
DUMP_TVPI (COLKEYRH);
DUMP_TVPI (COLKEYGL);
DUMP_TVPI (COLKEYGH);
DUMP_TVPI (COLKEYBL);
DUMP_TVPI (COLKEYBH);
DUMP_TVPI (COLKEYCTRL);
DUMP_TVPI (MEMCLKCTRL);
DUMP_TVPI (SENSETEST);
DUMP_TVPI (TESTMODEDATA);
DUMP_TVPI (CRCREML);
DUMP_TVPI (CRCREMH);
// DUMP_TVPI (CRCBITSEL); // WO
DUMP_TVPI (ID);
// DUMP_TVPI (RESET); // WO
}
static void dump_mil2 (void)
{
/* PCI_config_space */
DUMP_CFG (DEVID);
DUMP_CFG (DEVCTRL);
DUMP_CFG (CLASS);
DUMP_CFG (HEADER);
DUMP_CFG (MGABASE2);
DUMP_CFG (MGABASE1);
DUMP_CFG (MGABASE3);
DUMP_CFG (SUBSYSIDR);
DUMP_CFG (ROMBASE);
DUMP_CFG (CAP_PTR);
DUMP_CFG (INTCTRL);
DUMP_CFG (OPTION);
DUMP_CFG (MGA_INDEX);
DUMP_CFG (MGA_DATA);
DUMP_CFG (SUBSYSIDW);
DUMP_CFG (AGP_IDENT);
DUMP_CFG (AGP_STS);
DUMP_CFG (AGP_CMD);
/*VGA registers - these are byte wide*/
// DUMP_VGA (ATTR_I);
// DUMP_VGA (ATTR_D);
DUMP_VGA_ATTR (0);
DUMP_VGA_ATTR (1);
DUMP_VGA_ATTR (3);
DUMP_VGA_ATTR (3);
DUMP_VGA_ATTR (4);
DUMP_VGA_ATTR (5);
DUMP_VGA_ATTR (6);
DUMP_VGA_ATTR (7);
DUMP_VGA_ATTR (8);
DUMP_VGA_ATTR (9);
DUMP_VGA_ATTR (A);
DUMP_VGA_ATTR (B);
DUMP_VGA_ATTR (C);
DUMP_VGA_ATTR (D);
DUMP_VGA_ATTR (E);
DUMP_VGA_ATTR (F);
DUMP_VGA_ATTR (10);
DUMP_VGA_ATTR (11);
DUMP_VGA_ATTR (12);
DUMP_VGA_ATTR (13);
DUMP_VGA_ATTR (14);
// DUMP_VGA (CRTC_I);
// DUMP_VGA (CRTC_D);
DUMP_VGA_CRTC (0);
DUMP_VGA_CRTC (1);
DUMP_VGA_CRTC (2);
DUMP_VGA_CRTC (3);
DUMP_VGA_CRTC (4);
DUMP_VGA_CRTC (5);
DUMP_VGA_CRTC (6);
DUMP_VGA_CRTC (7);
DUMP_VGA_CRTC (8);
DUMP_VGA_CRTC (9);
DUMP_VGA_CRTC (A);
DUMP_VGA_CRTC (B);
DUMP_VGA_CRTC (C);
DUMP_VGA_CRTC (D);
DUMP_VGA_CRTC (E);
DUMP_VGA_CRTC (F);
DUMP_VGA_CRTC (10);
DUMP_VGA_CRTC (11);
DUMP_VGA_CRTC (12);
DUMP_VGA_CRTC (13);
DUMP_VGA_CRTC (14);
DUMP_VGA_CRTC (15);
DUMP_VGA_CRTC (16);
DUMP_VGA_CRTC (17);
DUMP_VGA_CRTC (18);
DUMP_VGA_CRTC (22);
DUMP_VGA_CRTC (24);
DUMP_VGA_CRTC (26);
// DUMP_VGA (CRTCEXT_I);
// DUMP_VGA (CRTCEXT_D);
DUMP_VGA_CRTCEXT (0);
DUMP_VGA_CRTCEXT (1);
DUMP_VGA_CRTCEXT (2);
DUMP_VGA_CRTCEXT (3);
DUMP_VGA_CRTCEXT (4);
DUMP_VGA_CRTCEXT (5);
DUMP_VGA (DACSTAT);
// DUMP_VGA (FEATW);
DUMP_VGA (FEATR);
// DUMP_VGA (GCTL_I);
// DUMP_VGA (GCTL_D);
DUMP_VGA_GCTL (0);
DUMP_VGA_GCTL (1);
DUMP_VGA_GCTL (2);
DUMP_VGA_GCTL (3);
DUMP_VGA_GCTL (4);
DUMP_VGA_GCTL (5);
DUMP_VGA_GCTL (6);
DUMP_VGA_GCTL (7);
DUMP_VGA_GCTL (8);
DUMP_VGA (INSTS0);
DUMP_VGA (INSTS1);
DUMP_VGA (MISCR);
DUMP_VGA (MISCW);
// DUMP_VGA (SEQ_I);
// DUMP_VGA (SEQ_D);
DUMP_VGA_SEQ (0);
DUMP_VGA_SEQ (1);
DUMP_VGA_SEQ (2);
DUMP_VGA_SEQ (3);
DUMP_VGA_SEQ (4);
/* MGA registers, only the readable*/
DUMP_MGA (IEN);
DUMP_MGA (RST);
DUMP_MGA (OPMODE);
DUMP_MGA (STATUS);
/* TVP3026 registers */
dump_tvp3026();
}
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
status_t mil2_dac_mode (int mode, float brightness, int hsync_pos, int vsync_pos, int sync_green)
{
uint8 *r, *g, *b, t[64];
int i;
uint8 miscctrl = 0, latchctrl = 0;
uint8 tcolctrl = 0, mulctrl = 0;
LOG(4,("TVP:Setting screen mode %d brightness %f\n", mode, brightness));
if (si->settings.logmask & 0x80000000) dump_tvp3026();
/*set colour arrays to point to space reserved in shared info*/
r = si->color_data;
g = r + 256;
b = g + 256;
/*init a basic palette for brightness specified*/
brightness = 2.0; // TODO
for (i=0;i<256;i++) {
int ri = i*brightness;
if (ri > 255) ri = 255;
r[i]=ri;
}
/*modify the palette for the specified mode (&validate mode)*/
switch(mode) {
case BPP8:
case BPP24:case BPP32:
for (i=0;i<256;i++) b[i]=g[i]=r[i];
break;
case BPP16:
for (i=0;i<64;i++) t[i]=r[i<<2];
for (i=0;i<64;i++) g[i]=t[i];
for (i=0;i<32;i++) b[i]=r[i]=t[i<<1];
break;
case BPP15:
for (i=0;i<32;i++) t[i]=r[i<<3];
for (i=0;i<32;i++) g[i]=r[i]=b[i]=t[i];
break;
case BPP32DIR:
break;
default:
LOG(8,("TVP:Invalid bit depth requested\n"));
return B_ERROR;
break;
}
if (mil2_dac_palette (r, g, b) != B_OK) return B_ERROR;
// set the mode
switch (mode) { // mulctrl for PIXEL_BUS_WIDTH 32
case BPP8: miscctrl=0x0c; latchctrl=0x06; tcolctrl=0x80; mulctrl=0x4b; break;
case BPP15: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x04; mulctrl=0x53; break;
case BPP16: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x05; mulctrl=0x53; break;
case BPP24: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x1f; mulctrl=0x5b; break;
case BPP32: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break;
case BPP32DIR: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break;
}
if (PIXEL_BUS_WIDTH64) mulctrl += 1;
TVPIW(MISCCTRL,(TVPIR(MISCCTRL) & 0xd3) | miscctrl);
TVPIW(LATCHCTRL, latchctrl);
TVPIW(TCOLCTRL, tcolctrl);
TVPIW(MULCTRL, mulctrl);
// synchros
TVPIW (GENCTRL, (TVPIR (GENCTRL) & 0xdc)
| (sync_green? 0x00:0x20) // apsed TODO ?
| (vsync_pos? 0x00:0x02)
| (hsync_pos? 0x00:0x01));
//VGAW (MISCW, VGAR(MISCR) & 0x3f); // TODO
//TVPIW (GENCTRL, TVPIR (GENCTRL) & 0xdf); // TODO
LOG(2,("TVP: clocksel 0x%02x, miscctrl 0x%02x\n",
TVPIR(CLOCKSEL), TVPIR(MISCCTRL)));
LOG(2,("TVP: tcolctrl 0x%02x, mulctrl 0x%02x, pixrdmsk 0x%02x, genctrl 0x%02x\n",
TVPIR(TCOLCTRL), TVPIR(MULCTRL), TVPR(PIXRDMSK), TVPIR (GENCTRL)));
return B_OK;
}
// program the palette using the given r,g,b values
status_t mil2_dac_palette (uint8 r[256], uint8 g[256], uint8 b[256])
{
int i;
LOG(4,("TVP: setting palette\n"));
/*clear palwtadd to start programming*/
TVPW(PALWTADD,0);
/*loop through all 256 to program LUT*/
for (i=0;i<256;i++) {
TVPW(PALDATA,r[i]);
TVPW(PALDATA,g[i]);
TVPW(PALDATA,b[i]);
}
if (TVPR(PALWTADD)!=0) {
LOG(8,("TVP: PALWTADD is not 0 after programming\n"));
return B_ERROR;
}
if (0) { // apsed: reread LUT
uint8 R, G, B;
TVPW(PALRDADD,0);
for (i=0;i<256;i++) {
R = TVPR(PALDATA);
G = TVPR(PALDATA);
B = TVPR(PALDATA);
if ((r[i] != R) || (g[i] != G) || (b[i] != B)) {
LOG(8,("TVP: palette 0x%02x: w %02x %02x %02x, r %02x %02x %02x\n",
i, r[i], g[i], b[i], R, G, B));
}
}
}
return B_OK;
}
// find nearest valid pll parameters, TVP3026 2.4.1
status_t mil2_dac_pix_pll_find (float f_need, float *f_result, uint8 *m_result, uint8 *n_result, uint8 *p_result)
{
int m, n, p;
float error, best, best_vco;
float f_vco, f_pll;
LOG(0,("mil2_dac_pix_pll_find for %fMHz\n", f_need));
best = 999999999;
// stupid implementation of 2.4.1 and 2.4.2
for (m = 1; m <= 62; m++) {
for (n = 40; n <= 62; n++) {
f_vco = (8.0 * FPLL_REF * (65 - m)) / (65 - n);
if ((f_vco < FVCO_MIN) || (f_vco >= FVCO_MAX)) continue;
for (p = 0; p <= 3; p++) {
f_pll = f_vco / (float)(1 << p);
error = fabs (f_need - f_pll) / f_need;
if (error > best) continue;
best = error;
best_vco = f_vco;
*f_result = f_pll;
*m_result = m;
*n_result = n;
*p_result = p;
LOG (0,("mil2_dac_pix_pll_find nmp %fMHz %fMHz 0x%02x 0x%02x 0x%02x\n",
f_pll, f_vco, *n_result, *m_result, *p_result));
}
}
}
LOG(0,("mil2_dac_pix_pll_find requested %fMHz got %fMHz, vco %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
f_need, *f_result, best_vco, *n_result, *m_result, *p_result));
return B_OK;
}
/*program the pixpll - frequency in MHz*/
status_t mil2_dac_set_pix_pll (float f_need, int bpp)
{
@@ -474,39 +46,41 @@ status_t mil2_dac_set_pix_pll (float f_need, int bpp)
float fd;
status_t result;
display_mode target;
target.timing.pixel_clock = (f_need * 1000);
LOG(4,("mil2_dac_set_pix_pll need %fMHz, %dbpp\n", f_need, bpp));
result = mil2_dac_pix_pll_find(f_need,&fd,&m,&n,&p);
result = gx00_dac_pix_pll_find(target, &fd, &m, &n, &p, 0);
if (result != B_OK) return result;
LOG(2,("mil2_dac_set_pix_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
f_need, fd, n, m, p));
// follows (!strictly) Appendix C, extended mode setup
// 1st stop the PLLs,
switch (bpp) {
case 8: TVPIW(CLOCKSEL, 0x25); break;
case 16: TVPIW(CLOCKSEL, 0x15); break;
case 24: TVPIW(CLOCKSEL, 0x25); break;
case 32: TVPIW(CLOCKSEL, 0x05); break;
case 8: DXIW(TVP_CLOCKSEL, 0x25); break;
case 16: DXIW(TVP_CLOCKSEL, 0x15); break;
case 24: DXIW(TVP_CLOCKSEL, 0x25); break;
case 32: DXIW(TVP_CLOCKSEL, 0x05); break;
default: return B_ERROR;
}
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
TVPIW(LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL
DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
DXIW(TVP_LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL
DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
// 2nd setup the pixel PLL
LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n",
n, m, p));
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
TVPIW(PIXPLLDATA, m);
TVPIW(PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (PIX);
DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
DXIW(TVP_PIXPLLDATA, m);
DXIW(TVP_PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
// now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1
k = 1; // ?? external division factor between RCLK and LCLK
n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp);
// does 32bit DAC path exists for MIL1/2? if so, do this via si->ps...
// n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp);
n = (65 - (4 * 64) / bpp);
m = 61;
z = (FVCO_MIN * (65 - n)) / (4 * fd * k);
q = 0;
@@ -520,19 +94,18 @@ status_t mil2_dac_set_pix_pll (float f_need, int bpp)
}
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q));
TVPIW(MEMCLKCTRL, (TVPIR(MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13
DXIW(TVP_MEMCLKCTRL, (DXIR(TVP_MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q));
// now setup the loop PLL
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
n, m, p, q));
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ...
TVPIW(LOOPLLDATA, m);
TVPIW(LOOPLLDATA, p | 0xf0);
WAIT_FOR_PLL_LOCK (LOO, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (LOO);
DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
DXIW(TVP_LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ...
DXIW(TVP_LOOPLLDATA, m);
DXIW(TVP_LOOPLLDATA, p | 0xf0);
WAIT_FOR_PLL_LOCK (TVP_LOO, return B_ERROR); // ... wait for PLL lock
return B_OK;
}
@@ -544,68 +117,63 @@ static status_t mil2_dac_set_mem_pll (float f_need, float *mclk)
uint8 n, m, p;
uint8 n_pix, m_pix, p_pix;
uint8 memclkctrl;
display_mode target;
target.timing.pixel_clock = (f_need * 1000);
status = mil2_dac_pix_pll_find (f_need, mclk, &m, &n, &p);
LOG(4,("mil2_dac_set_sys_pll need %fMHz\n", f_need));
//fixme: MIL has same restrictions for pixel and system PLL, so Apsed did this:
status = gx00_dac_pix_pll_find(target, mclk, &m, &n, &p, 0);
if (status != B_OK) return status;
LOG(2,("mil2_dac_set_mem_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
f_need, *mclk, n, m, p));
// follows (!strictly) TVP3026 2.4.2.1, extended mode setup
// 0) save PIXPLL nmp to restore it at end
TVPIW(PLLADDR, 0x00);
n_pix = TVPIR(PIXPLLDATA);
TVPIW(PLLADDR, 0x15);
m_pix = TVPIR(PIXPLLDATA);
TVPIW(PLLADDR, 0x2a);
p_pix = TVPIR(PIXPLLDATA);
if (1) REREAD_PLL (PIX);
DXIW(TVP_PLLADDR, 0x00);
n_pix = DXIR(TVP_PIXPLLDATA);
DXIW(TVP_PLLADDR, 0x15);
m_pix = DXIR(TVP_PIXPLLDATA);
DXIW(TVP_PLLADDR, 0x2a);
p_pix = DXIR(TVP_PIXPLLDATA);
// 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
TVPIW(PIXPLLDATA, m);
TVPIW(PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock
if (1) REREAD_PLL (PIX);
DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL
DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
DXIW(TVP_PIXPLLDATA, m);
DXIW(TVP_PIXPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
// 2) select pixel clock as dot clock source
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
// 3) output dot clock on MCLK pin
memclkctrl = TVPIR(MEMCLKCTRL) & 0xe7;
TVPIW(MEMCLKCTRL, memclkctrl | (0x00 << 3));
TVPIW(MEMCLKCTRL, memclkctrl | (0x01 << 3));
memclkctrl = DXIR(TVP_MEMCLKCTRL) & 0xe7;
DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x00 << 3));
DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x01 << 3));
// 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock
if (1) REREAD_PLL (MEM);
TVPIW(PLLADDR, 0x2a);
TVPIW(MEMPLLDATA, 0x00);
TVPIW(PLLADDR, 0x00);
TVPIW(MEMPLLDATA, n | 0xc0);
TVPIW(MEMPLLDATA, m);
TVPIW(MEMPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (MEM, return B_ERROR);
if (1) REREAD_PLL (MEM);
DXIW(TVP_PLLADDR, 0x2a);
DXIW(TVP_MEMPLLDATA, 0x00);
DXIW(TVP_PLLADDR, 0x00);
DXIW(TVP_MEMPLLDATA, n | 0xc0);
DXIW(TVP_MEMPLLDATA, m);
DXIW(TVP_MEMPLLDATA, p | 0xb0);
WAIT_FOR_PLL_LOCK (TVP_MEM, return B_ERROR);
// 5) output mem clock on MCLK pin
TVPIW(MEMCLKCTRL, memclkctrl | (0x02 << 3));
TVPIW(MEMCLKCTRL, memclkctrl | (0x03 << 3));
DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x02 << 3));
DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x03 << 3));
// 6) restaure pixel clock as it was
TVPIW(PLLADDR, 0x2a);
TVPIW(PIXPLLDATA, 0x00);
TVPIW(PLLADDR, 0x00);
// TVPIW(PIXPLLDATA, n_pix);
// TVPIW(PIXPLLDATA, m_pix);
// TVPIW(PIXPLLDATA, p_pix);
TVPIW(PIXPLLDATA, n_pix | 0xc0);
TVPIW(PIXPLLDATA, m_pix);
TVPIW(PIXPLLDATA, p_pix | 0xb0);
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR);
if (1) REREAD_PLL (PIX);
DXIW(TVP_PLLADDR, 0x2a);
DXIW(TVP_PIXPLLDATA, 0x00);
DXIW(TVP_PLLADDR, 0x00);
DXIW(TVP_PIXPLLDATA, n_pix | 0xc0);
DXIW(TVP_PIXPLLDATA, m_pix);
DXIW(TVP_PIXPLLDATA, p_pix | 0xb0);
WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR);
return B_OK;
}
@@ -619,8 +187,6 @@ status_t mil2_dac_init (void)
uint32 option;
uint32 rfhcnt, nogscale, memconfig;
dump_mil2();
LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR)));
CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!)
VGAW_I(CRTC,0x11,0); // allow me to change CRTC
@@ -658,11 +224,12 @@ rfhcnt_found:
LOG(2,("mil2_dac_init: found refresh count %d nogscale %d for %fMHz\n",
rfhcnt, nogscale, mclk));
memconfig = 0x00; // 32 bits RAMDAC
memconfig = 0x01; // 64 bits RAMDAC
memconfig = 0x01; // worst case scenario: 64 bits RAMDAC (= tvp3026m) with >2Mb RAM.
option = CFGR(OPTION) & 0xffd0cfff;
CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12));
LOG(2,("mil2_dac_init: OPTION 0x%08x\n", CFGR(OPTION)));
//r: select indirect cursor control register and set defaults
DXIW(CURCTRL, 0x00);
return B_OK;
}