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

Reply via email to