drm/radeon: fix support for vline relocations.
authorDave Airlie <airlied@redhat.com>
Mon, 29 Jun 2009 01:21:25 +0000 (11:21 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 15 Jul 2009 07:13:08 +0000 (17:13 +1000)
Userspace sends us a special relocation type to sync video/exa
to vlines to avoid tearing, this deals with the relocation
in the kernel, it picks the correct crtc and avoids issues
where crtcs are disabled.

This version also parses the wait until to make sure it isn't
trying to do anything evil.

Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r500_reg.h
drivers/gpu/drm/radeon/rv515.c

index a3db56bb013da80f140a59e126acec4eea69c983..154648a2c0277910fc0bc247249485110a75880f 100644 (file)
@@ -751,6 +751,102 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p,
        return 0;
 }
 
+/**
+ * r100_cs_packet_next_vline() - parse userspace VLINE packet
+ * @parser:            parser structure holding parsing context.
+ *
+ * Userspace sends a special sequence for VLINE waits.
+ * PACKET0 - VLINE_START_END + value
+ * PACKET0 - WAIT_UNTIL +_value
+ * RELOC (P3) - crtc_id in reloc.
+ *
+ * This function parses this and relocates the VLINE START END
+ * and WAIT UNTIL packets to the correct crtc.
+ * It also detects a switched off crtc and nulls out the
+ * wait in that case.
+ */
+int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       struct radeon_crtc *radeon_crtc;
+       struct radeon_cs_packet p3reloc, waitreloc;
+       int crtc_id;
+       int r;
+       uint32_t header, h_idx, reg;
+
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+
+       /* parse the wait until */
+       r = r100_cs_packet_parse(p, &waitreloc, p->idx);
+       if (r)
+               return r;
+
+       /* check its a wait until and only 1 count */
+       if (waitreloc.reg != RADEON_WAIT_UNTIL ||
+           waitreloc.count != 0) {
+               DRM_ERROR("vline wait had illegal wait until segment\n");
+               r = -EINVAL;
+               return r;
+       }
+
+       if (ib_chunk->kdata[waitreloc.idx + 1] != RADEON_WAIT_CRTC_VLINE) {
+               DRM_ERROR("vline wait had illegal wait until\n");
+               r = -EINVAL;
+               return r;
+       }
+
+       /* jump over the NOP */
+       r = r100_cs_packet_parse(p, &p3reloc, p->idx);
+       if (r)
+               return r;
+
+       h_idx = p->idx - 2;
+       p->idx += waitreloc.count;
+       p->idx += p3reloc.count;
+
+       header = ib_chunk->kdata[h_idx];
+       crtc_id = ib_chunk->kdata[h_idx + 5];
+       reg = ib_chunk->kdata[h_idx] >> 2;
+       mutex_lock(&p->rdev->ddev->mode_config.mutex);
+       obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_ERROR("cannot find crtc %d\n", crtc_id);
+               r = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+       radeon_crtc = to_radeon_crtc(crtc);
+       crtc_id = radeon_crtc->crtc_id;
+
+       if (!crtc->enabled) {
+               /* if the CRTC isn't enabled - we need to nop out the wait until */
+               ib_chunk->kdata[h_idx + 2] = PACKET2(0);
+               ib_chunk->kdata[h_idx + 3] = PACKET2(0);
+       } else if (crtc_id == 1) {
+               switch (reg) {
+               case AVIVO_D1MODE_VLINE_START_END:
+                       header &= R300_CP_PACKET0_REG_MASK;
+                       header |= AVIVO_D2MODE_VLINE_START_END >> 2;
+                       break;
+               case RADEON_CRTC_GUI_TRIG_VLINE:
+                       header &= R300_CP_PACKET0_REG_MASK;
+                       header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2;
+                       break;
+               default:
+                       DRM_ERROR("unknown crtc reloc\n");
+                       r = -EINVAL;
+                       goto out;
+               }
+               ib_chunk->kdata[h_idx] = header;
+               ib_chunk->kdata[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1;
+       }
+out:
+       mutex_unlock(&p->rdev->ddev->mode_config.mutex);
+       return r;
+}
+
 /**
  * r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3
  * @parser:            parser structure holding parsing context.
@@ -824,6 +920,15 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
        }
        for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
                switch (reg) {
+               case RADEON_CRTC_GUI_TRIG_VLINE:
+                       r = r100_cs_packet_parse_vline(p);
+                       if (r) {
+                               DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                               idx, reg);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       break;
                /* FIXME: only allow PACKET3 blit? easier to check for out of
                 * range access */
                case RADEON_DST_PITCH_OFFSET:
index cd9ea98e9c6f38eedc3a5d2ded58f81e4d995f02..656d9238bb0625dbfdd125c0ad1c40c0b25f6c12 100644 (file)
@@ -44,6 +44,7 @@ int r100_gui_wait_for_idle(struct radeon_device *rdev);
 int r100_cs_packet_parse(struct radeon_cs_parser *p,
                         struct radeon_cs_packet *pkt,
                         unsigned idx);
+int r100_cs_packet_parse_vline(struct radeon_cs_parser *p);
 int r100_cs_packet_next_reloc(struct radeon_cs_parser *p,
                              struct radeon_cs_reloc **cs_reloc);
 int r100_cs_parse_packet0(struct radeon_cs_parser *p,
@@ -972,7 +973,7 @@ static inline void r300_cs_track_clear(struct r300_cs_track *track)
 
 static const unsigned r300_reg_safe_bm[159] = {
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-       0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
@@ -1029,6 +1030,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        ib_chunk = &p->chunks[p->chunk_ib_idx];
        track = (struct r300_cs_track*)p->track;
        switch(reg) {
+       case AVIVO_D1MODE_VLINE_START_END:
+       case RADEON_CRTC_GUI_TRIG_VLINE:
+               r = r100_cs_packet_parse_vline(p);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                       idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               break;
        case RADEON_DST_PITCH_OFFSET:
        case RADEON_SRC_PITCH_OFFSET:
                r = r100_cs_packet_next_reloc(p, &reloc);
index 9070a1c2ce238ac2e8534318c6b4fe7a69a96211..036691b38cb7802930a28218229ae025f3128cc5 100644 (file)
 #define AVIVO_D1MODE_DATA_FORMAT                0x6528
 #       define AVIVO_D1MODE_INTERLEAVE_EN       (1 << 0)
 #define AVIVO_D1MODE_DESKTOP_HEIGHT             0x652C
+#define AVIVO_D1MODE_VLINE_START_END            0x6538
 #define AVIVO_D1MODE_VIEWPORT_START             0x6580
 #define AVIVO_D1MODE_VIEWPORT_SIZE              0x6584
 #define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6588
 #define AVIVO_D2CUR_SIZE                        0x6c10
 #define AVIVO_D2CUR_POSITION                    0x6c14
 
+#define AVIVO_D2MODE_VLINE_START_END            0x6d38
 #define AVIVO_D2MODE_VIEWPORT_START             0x6d80
 #define AVIVO_D2MODE_VIEWPORT_SIZE              0x6d84
 #define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6d88
index ffea37b1b3e23db02a8f2f59b480cf9274e7233f..d1384d3991add87d3b7596c98534c1bb232e3370 100644 (file)
@@ -509,9 +509,9 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
 /*
  * Asic initialization
  */
-static const unsigned r500_reg_safe_bm[159] = {
+static const unsigned r500_reg_safe_bm[219] = {
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-       0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
@@ -549,11 +549,24 @@ static const unsigned r500_reg_safe_bm[159] = {
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
-       0x0003FC01, 0x3FFFFCF8, 0xFE800B19,
+       0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
 };
 
-
-
 int rv515_init(struct radeon_device *rdev)
 {
        rdev->config.r300.reg_safe_bm = r500_reg_safe_bm;