Here's a new version which fixes all problems I detected so far.
Changes:
- CRTC2 interrupt should happen at vdisplay since that's when the hardware
flips the registers. Unfortunately the field bit can toggle at vdisplay+1
earliest so I have to invert it in the interrupt handler to make field
parity work. That gives us 1.6 ms after the interrupt in PAL mode. I'm not
sure if the interrupt handler can be delayed for that long but to avoid
that posssibility I changed the field bit to toggle at vdisplay+8. That's
the maximum value and it gives us 12.8 ms in PAL mode. I would guess
that's more than enough :) Fortunately maven doesn't seem to mind when the
bit toggles. IIRC BT.something says it should toggle at vdisplay+2 for
both fields in PAL mode, and at vdisplay+2 and vdisplay+3 for NTSC fields.
- CRTC1 vline interrupt was coming in one line too early so I changed
that.
- Changed BES to actually flip at CRTC1 vblank.
- Added some protection against programming the hardware exactly on top of
vblank start. This is in the form of pollig the vertical count register in
the kernel. That got rid of the last tearing problems with the BES. Added
the same protection for CRTC2 too although I didn't see any tearing there.
I would appreciate any test reports so I'll know I'm not crazy or blind
for not seeing any tearing :)
--
Ville Syrjälä
[EMAIL PROTECTED]
http://www.sci.fi/~syrjala/
diff -urN linux/drivers/video/matrox/matroxfb_base.c
linux/drivers/video/matrox/matroxfb_base.c
--- linux/drivers/video/matrox/matroxfb_base.c 2005-10-28 11:55:16.000000000
+0300
+++ linux/drivers/video/matrox/matroxfb_base.c 2005-10-28 11:59:42.000000000
+0300
@@ -206,16 +206,29 @@
status = mga_inl(M_STATUS);
+ if (status & 0x220)
+ mga_outl(M_ICLEAR, status & 0x220);
+
if (status & 0x20) {
- mga_outl(M_ICLEAR, 0x20);
ACCESS_FBINFO(crtc1.vsync.cnt)++;
matroxfb_crtc1_panpos(PMINFO2);
wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait));
handled = 1;
}
if (status & 0x200) {
- mga_outl(M_ICLEAR, 0x200);
ACCESS_FBINFO(crtc2.vsync.cnt)++;
+ ACCESS_FBINFO(crtc2.vsync.field) = (mga_inl(0x3C48) >> 24) ^ 1;
+ if (ACCESS_FBINFO(crtc2.pan) &&
+ ACCESS_FBINFO(crtc2.address.field) !=
ACCESS_FBINFO(crtc2.vsync.field)) {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+ mga_outl(0x3C28,
ACCESS_FBINFO(crtc2.address.offset[0]));
+ mga_outl(0x3C2C,
ACCESS_FBINFO(crtc2.address.offset[1]));
+ mga_outl(0x3C30,
ACCESS_FBINFO(crtc2.address.offset[2]));
+ mga_outl(0x3C34,
ACCESS_FBINFO(crtc2.address.offset[3]));
+ mga_outl(0x3C38,
ACCESS_FBINFO(crtc2.address.offset[4]));
+ mga_outl(0x3C3C,
ACCESS_FBINFO(crtc2.address.offset[5]));
+ mga_inl(0x3C3C);
+ }
wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
handled = 1;
}
@@ -300,6 +313,88 @@
return 0;
}
+int matroxfb_address(WPMINFO struct matrox_address *address)
+{
+ if (address->device == MATROX_ADDRESS_DEVICE_CRTC2 &&
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ int diff, c2vlinecomp = (mga_inl(0x3C44) >> 16) & 0xFFF;
+ int err;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ err = matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = c2vlinecomp - mga_inl(0x3C48);
+ } while (-2 < diff && diff < 2);
+
+ if (!err && address->field == ACCESS_FBINFO(crtc2.vsync.field))
{
+ ACCESS_FBINFO(crtc2.address) = *address;
+ ACCESS_FBINFO(crtc2.pan) = 1;
+ } else {
+ ACCESS_FBINFO(crtc2.pan) = 0;
+
+ mga_outl(0x3C28, address->offset[0]);
+ mga_outl(0x3C2C, address->offset[1]);
+ mga_outl(0x3C30, address->offset[2]);
+ mga_outl(0x3C34, address->offset[3]);
+ mga_outl(0x3C38, address->offset[4]);
+ mga_outl(0x3C3C, address->offset[5]);
+ mga_inl(0x3C3C);
+ }
+
+ address->field = ACCESS_FBINFO(crtc2.vsync.field);
+ address->count = ACCESS_FBINFO(crtc2.vsync.cnt);
+
+ return 0;
+ } else if (address->device == MATROX_ADDRESS_DEVICE_BES &&
+ ACCESS_FBINFO(devflags.accelerator) ==
FB_ACCEL_MATROX_MGAG400) {
+ int diff, besvcnt = (mga_inl(0x3DC0) >> 16) & 0xFFF;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = besvcnt - mga_inl(0x1E20);
+ } while (-2 < diff && diff < 2);
+
+ mga_outl(0x3D00, address->offset[0]);
+ mga_outl(0x3D04, address->offset[1]);
+ mga_outl(0x3D10, address->offset[2]);
+ mga_outl(0x3D14, address->offset[3]);
+ mga_outl(0x3D60, address->offset[4]);
+ mga_outl(0x3D64, address->offset[5]);
+ mga_inl(0x3D64);
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ } else if (address->device == MATROX_ADDRESS_DEVICE_BES &&
+ ACCESS_FBINFO(devflags.accelerator) ==
FB_ACCEL_MATROX_MGAG200) {
+ int diff, besvcnt = (mga_inl(0x3DC0) >> 16) & 0xFFF;
+
+ /* Interrupts are always needed to update vsync.cnt. */
+ matroxfb_enable_irq(PMINFO 0);
+
+ do {
+ diff = besvcnt - mga_inl(0x1E20);
+ } while (-2 < diff && diff < 2);
+
+ mga_outl(0x3D00, address->offset[0]);
+ mga_outl(0x3D04, address->offset[1]);
+ mga_outl(0x3D10, address->offset[2]);
+ mga_outl(0x3D14, address->offset[3]);
+ mga_inl(0x3D14);
+
+ address->field = -1; /* N/A */
+ address->count = ACCESS_FBINFO(crtc1.vsync.cnt);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
/* --------------------------------------------------------------------- */
static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
@@ -871,6 +966,8 @@
.name = "Panellink output",
};
+#define MATROXFB_ADDRESS _IOWR('n', 0xFC, struct matrox_address)
+
static int matroxfb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
struct fb_info *info)
@@ -1164,6 +1261,23 @@
up_read(&ACCESS_FBINFO(altout).lock);
return err;
}
+ case MATROXFB_ADDRESS:
+ {
+ struct matrox_address address;
+ int err;
+
+ if (copy_from_user(&address, argp,
sizeof(address)))
+ return -EFAULT;
+
+ err = matroxfb_address(PMINFO &address);
+ if (err)
+ return err;
+
+ if (copy_to_user(argp, &address,
sizeof(address)))
+ return -EFAULT;
+
+ return 0;
+ }
}
return -ENOTTY;
}
diff -urN linux/drivers/video/matrox/matroxfb_base.h
linux/drivers/video/matrox/matroxfb_base.h
--- linux/drivers/video/matrox/matroxfb_base.h 2005-10-28 11:55:16.000000000
+0300
+++ linux/drivers/video/matrox/matroxfb_base.h 2005-10-28 11:59:42.000000000
+0300
@@ -364,6 +364,17 @@
struct matrox_vsync {
wait_queue_head_t wait;
unsigned int cnt;
+ unsigned int field;
+};
+
+#define MATROX_ADDRESS_DEVICE_CRTC1 0
+#define MATROX_ADDRESS_DEVICE_BES 1
+#define MATROX_ADDRESS_DEVICE_CRTC2 2
+struct matrox_address {
+ u32 device;
+ u32 field;
+ u32 count;
+ u32 offset[6];
};
struct matrox_fb_info {
@@ -397,6 +408,8 @@
int mnp;
struct matroxfb_dh_fb_info* info;
struct rw_semaphore lock;
+ int pan;
+ struct matrox_address address;
} crtc2;
struct {
struct rw_semaphore lock;
diff -urN linux/drivers/video/matrox/matroxfb_misc.c
linux/drivers/video/matrox/matroxfb_misc.c
--- linux/drivers/video/matrox/matroxfb_misc.c 2005-10-28 11:55:16.000000000
+0300
+++ linux/drivers/video/matrox/matroxfb_misc.c 2005-10-28 11:59:42.000000000
+0300
@@ -273,7 +273,7 @@
vs = m->VSyncStart - 1;
ve = m->VSyncEnd - 1;
vt = m->VTotal - 2;
- lc = vd;
+ lc = vd + 1;
/* G200 cannot work with (ht & 7) == 6 */
if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
ht++;
Index: matrox.h
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox.h,v
retrieving revision 1.38
diff -u -r1.38 matrox.h
--- matrox.h 26 Oct 2005 06:33:46 -0000 1.38
+++ matrox.h 28 Oct 2005 09:02:41 -0000
@@ -149,4 +149,16 @@
return ret;
}
+#define MATROX_ADDRESS_DEVICE_CRTC1 0
+#define MATROX_ADDRESS_DEVICE_BES 1
+#define MATROX_ADDRESS_DEVICE_CRTC2 2
+struct matrox_address
+{
+ __u32 device;
+ __u32 field;
+ __u32 count;
+ __u32 offset[6];
+};
+#define MATROXFB_ADDRESS _IOWR('n', 0xFC, struct matrox_address)
+
#endif
Index: matrox_bes.c
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox_bes.c,v
retrieving revision 1.58
diff -u -r1.58 matrox_bes.c
--- matrox_bes.c 26 Oct 2005 07:23:16 -0000 1.58
+++ matrox_bes.c 28 Oct 2005 09:02:41 -0000
@@ -54,6 +54,7 @@
#include <direct/mem.h>
+#include <fbdev/fbdev.h>
#include "regs.h"
#include "mmio.h"
@@ -61,6 +62,7 @@
typedef struct {
CoreLayerRegionConfig config;
+ __u32 last_count;
/* Stored registers */
struct {
@@ -260,6 +262,8 @@
{
bes_calc_regs( mdrv, mbes, config, surface );
bes_set_regs( mdrv, mbes, true );
+
+ mbes->last_count = 0;
}
/* set color key */
@@ -316,10 +320,36 @@
MatroxDriverData *mdrv = (MatroxDriverData*) driver_data;
MatroxBesLayerData *mbes = (MatroxBesLayerData*) layer_data;
+#if 0
bes_calc_regs( mdrv, mbes, &mbes->config, surface );
bes_set_regs( mdrv, mbes, flags & DSFLIP_ONSYNC );
dfb_surface_flip_buffers( surface, false );
+#else
+ {
+ FBDev *dfb_fbdev = dfb_system_data();
+ struct matrox_address address;
+
+ bes_calc_regs( mdrv, mbes, &mbes->config, surface );
+
+ address.device = MATROX_ADDRESS_DEVICE_BES;
+ address.field = -1;
+ address.count = mbes->last_count + 1;
+ address.offset[0] = mbes->regs.besA1ORG;
+ address.offset[1] = mbes->regs.besA2ORG;
+ address.offset[2] = mbes->regs.besA1CORG;
+ address.offset[3] = mbes->regs.besA2CORG;
+ address.offset[4] = mbes->regs.besA1C3ORG;
+ address.offset[5] = mbes->regs.besA2C3ORG;
+
+ if (ioctl( dfb_fbdev->fd, MATROXFB_ADDRESS, &address ))
+ D_ERROR( "DirectFB/Matrox/BES Address ioctl() failed!\n" );
+
+ dfb_surface_flip_buffers( surface, address.count == mbes->last_count
);
+
+ mbes->last_count = address.count;
+ }
+#endif
if (flags & DSFLIP_WAIT)
dfb_screen_wait_vsync( mdrv->primary );
@@ -380,23 +410,20 @@
static void bes_set_regs( MatroxDriverData *mdrv, MatroxBesLayerData *mbes,
bool onsync )
{
- int line = 0;
- volatile __u8 *mmio = mdrv->mmio_base;
-
- if (!onsync) {
- VideoMode *current_mode = dfb_system_current_mode();
+ int line = 0;
+ volatile __u8 *mmio = mdrv->mmio_base;
+ VideoMode *current_mode = dfb_system_current_mode();
- if (!current_mode) {
- current_mode = dfb_system_modes();
- if (!current_mode)
- return;
- }
+ if (!current_mode) {
+ current_mode = dfb_system_modes();
+ if (!current_mode)
+ return;
+ }
+ if (!onsync)
line = mga_in32( mmio, MGAREG_VCOUNT ) + 48;
-
- if (line > current_mode->yres)
- line = current_mode->yres;
- }
+ else
+ line = current_mode->yres;
mga_out32( mmio, mbes->regs.besGLOBCTL | (line << 16), BESGLOBCTL);
Index: matrox_crtc2.c
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/matrox/matrox_crtc2.c,v
retrieving revision 1.31
diff -u -r1.31 matrox_crtc2.c
--- matrox_crtc2.c 26 Oct 2005 07:26:16 -0000 1.31
+++ matrox_crtc2.c 28 Oct 2005 09:02:41 -0000
@@ -61,7 +61,10 @@
typedef struct {
CoreLayerRegionConfig config;
DFBColorAdjustment adj;
- int field;
+ __u32 parity;
+ __u32 last_parity;
+ __u32 last_field;
+ __u32 last_count;
/* Stored registers */
struct {
@@ -247,7 +250,7 @@
mcrtc2->config = *config;
if (updated & CLRCF_PARITY)
- mcrtc2->field = !config->parity;
+ mcrtc2->parity = !config->parity;
if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT |
CLRCF_SURFACE_CAPS | CLRCF_ALPHA_RAMP | CLRCF_SURFACE)) {
@@ -257,6 +260,10 @@
ret = crtc2_enable_output( mdrv, mcrtc2 );
if (ret)
return ret;
+
+ mcrtc2->last_parity = 1;
+ mcrtc2->last_field = 0;
+ mcrtc2->last_count = 0;
}
return DFB_OK;
@@ -286,6 +293,7 @@
{
MatroxDriverData *mdrv = (MatroxDriverData*) driver_data;
MatroxCrtc2LayerData *mcrtc2 = (MatroxCrtc2LayerData*) layer_data;
+#if 0
volatile __u8 *mmio = mdrv->mmio_base;
crtc2_calc_buffer( mdrv, mcrtc2, surface );
@@ -293,7 +301,7 @@
if (mcrtc2->config.options & DLOP_FIELD_PARITY) {
int field = (mga_in32( mmio, C2VCOUNT ) & C2FIELD) ? 1 : 0;
- while (field == mcrtc2->field) {
+ while (field == mcrtc2->parity) {
dfb_screen_wait_vsync( mdrv->secondary );
field = (mga_in32( mmio, C2VCOUNT ) & C2FIELD) ? 1 : 0;
@@ -302,6 +310,38 @@
crtc2_set_buffer( mdrv, mcrtc2 );
dfb_surface_flip_buffers( surface, false );
+#else
+ {
+ FBDev *dfb_fbdev = dfb_system_data();
+ struct matrox_address address;
+ __u32 diff;
+
+ crtc2_calc_buffer( mdrv, mcrtc2, surface );
+
+ address.device = MATROX_ADDRESS_DEVICE_CRTC2;
+ address.field = (mcrtc2->config.options & DLOP_FIELD_PARITY) ?
mcrtc2->parity : -1;
+ address.count = mcrtc2->last_count + 2;
+ address.offset[0] = mcrtc2->regs.c2STARTADD0;
+ address.offset[1] = mcrtc2->regs.c2STARTADD1;
+ address.offset[2] = mcrtc2->regs.c2PL2STARTADD0;
+ address.offset[3] = mcrtc2->regs.c2PL2STARTADD1;
+ address.offset[4] = mcrtc2->regs.c2PL3STARTADD0;
+ address.offset[5] = mcrtc2->regs.c2PL3STARTADD1;
+
+ if (ioctl( dfb_fbdev->fd, MATROXFB_ADDRESS, &address ))
+ D_ERROR( "DirectFB/Matrox/CRTC2 Address ioctl() failed!\n" );
+
+ diff = address.count >= mcrtc2->last_count ?
+ address.count - mcrtc2->last_count :
+ 0xFFFFFFFF - mcrtc2->last_count + address.count;
+
+ dfb_surface_flip_buffers( surface, diff == 0 || (diff == 1 &&
mcrtc2->last_field == mcrtc2->last_parity) );
+
+ mcrtc2->last_count = address.count;
+ mcrtc2->last_field = address.field;
+ mcrtc2->last_parity = (mcrtc2->config.options & DLOP_FIELD_PARITY) ?
mcrtc2->parity : !address.field;
+ }
+#endif
if (flags & DSFLIP_WAIT)
dfb_screen_wait_vsync( mdrv->secondary );
@@ -494,7 +534,7 @@
mcrtc2->regs.c2MISC = 0;
/* c2vlinecomp */
- mcrtc2->regs.c2MISC |= (vdisplay + 1) << 16;
+ mcrtc2->regs.c2MISC |= (vdisplay << 16) | 0x77;
}
/* c2bpp15halpha */
_______________________________________________
directfb-dev mailing list
[email protected]
http://mail.directfb.org/cgi-bin/mailman/listinfo/directfb-dev