]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/gpu/drm/radeon/radeon_cp.c
drm/radeon: prep for r6xx/r7xx support
[mv-sheeva.git] / drivers / gpu / drm / radeon / radeon_cp.c
index 63212d7bbc287a36ef9bcc3cba45b3ac6cd97deb..e42b6a2a7e8ed8cf5873b650fceefd965aea1da4 100644 (file)
 static int radeon_do_cleanup_cp(struct drm_device * dev);
 static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);
 
+static u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
+{
+       u32 val;
+
+       if (dev_priv->flags & RADEON_IS_AGP) {
+               val = DRM_READ32(dev_priv->ring_rptr, off);
+       } else {
+               val = *(((volatile u32 *)
+                        dev_priv->ring_rptr->handle) +
+                       (off / sizeof(u32)));
+               val = le32_to_cpu(val);
+       }
+       return val;
+}
+
+u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv)
+{
+       if (dev_priv->writeback_works)
+               return radeon_read_ring_rptr(dev_priv, 0);
+       else
+               return RADEON_READ(RADEON_CP_RB_RPTR);
+}
+
+static void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
+{
+       if (dev_priv->flags & RADEON_IS_AGP)
+               DRM_WRITE32(dev_priv->ring_rptr, off, val);
+       else
+               *(((volatile u32 *) dev_priv->ring_rptr->handle) +
+                 (off / sizeof(u32))) = cpu_to_le32(val);
+}
+
+void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val)
+{
+       radeon_write_ring_rptr(dev_priv, 0, val);
+}
+
+u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index)
+{
+       if (dev_priv->writeback_works)
+               return radeon_read_ring_rptr(dev_priv,
+                                            RADEON_SCRATCHOFF(index));
+       else
+               return RADEON_READ(RADEON_SCRATCH_REG0 + 4*index);
+}
+
+u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr)
+{
+       u32 ret;
+
+       if (addr < 0x10000)
+               ret = DRM_READ32(dev_priv->mmio, addr);
+       else {
+               DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, addr);
+               ret = DRM_READ32(dev_priv->mmio, RADEON_MM_DATA);
+       }
+
+       return ret;
+}
+
 static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
        u32 ret;
@@ -145,6 +205,25 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
        }
 }
 
+static void radeon_enable_bm(struct drm_radeon_private *dev_priv)
+{
+       u32 tmp;
+       /* Turn on bus mastering */
+       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
+               /* rs600/rs690/rs740 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
+               /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
+               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
+       } /* PCIE cards appears to not need this */
+}
+
 static int RADEON_READ_PLL(struct drm_device * dev, int addr)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -557,10 +636,11 @@ static int radeon_do_engine_reset(struct drm_device * dev)
 }
 
 static void radeon_cp_init_ring_buffer(struct drm_device * dev,
-                                      drm_radeon_private_t * dev_priv)
+                                      drm_radeon_private_t *dev_priv,
+                                      struct drm_file *file_priv)
 {
+       struct drm_radeon_master_private *master_priv;
        u32 ring_start, cur_read_ptr;
-       u32 tmp;
 
        /* Initialize the memory controller. With new memory map, the fb location
         * is not changed, it should have been properly initialized already. Part
@@ -609,17 +689,10 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        } else
 #endif
        {
-               struct drm_sg_mem *entry = dev->sg;
-               unsigned long tmp_ofs, page_ofs;
-
-               tmp_ofs = dev_priv->ring_rptr->offset -
-                               (unsigned long)dev->sg->virtual;
-               page_ofs = tmp_ofs >> PAGE_SHIFT;
-
-               RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]);
-               DRM_DEBUG("ring rptr: offset=0x%08lx handle=0x%08lx\n",
-                         (unsigned long)entry->busaddr[page_ofs],
-                         entry->handle + tmp_ofs);
+               RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
+                            dev_priv->ring_rptr->offset
+                            - ((unsigned long) dev->sg->virtual)
+                            + dev_priv->gart_vm_start);
        }
 
        /* Set ring buffer size */
@@ -647,36 +720,27 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
                     + RADEON_SCRATCH_REG_OFFSET);
 
-       dev_priv->scratch = ((__volatile__ u32 *)
-                            dev_priv->ring_rptr->handle +
-                            (RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));
-
        RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
 
-       /* Turn on bus mastering */
-       if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
-           ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
-               /* rs600/rs690/rs740 */
-               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
-               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
-                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
-               /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
-               tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
-               RADEON_WRITE(RADEON_BUS_CNTL, tmp);
-       } /* PCIE cards appears to not need this */
+       radeon_enable_bm(dev_priv);
 
-       dev_priv->scratch[0] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(0), 0);
        RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
 
-       dev_priv->scratch[1] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
        RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
 
-       dev_priv->scratch[2] = 0;
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(2), 0);
        RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
 
+       /* reset sarea copies of these */
+       master_priv = file_priv->master->driver_priv;
+       if (master_priv->sarea_priv) {
+               master_priv->sarea_priv->last_frame = 0;
+               master_priv->sarea_priv->last_dispatch = 0;
+               master_priv->sarea_priv->last_clear = 0;
+       }
+
        radeon_do_wait_for_idle(dev_priv);
 
        /* Sync everything up */
@@ -698,12 +762,15 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
        /* Writeback doesn't seem to work everywhere, test it here and possibly
         * enable it if it appears to work
         */
-       DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
+       radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
+
        RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
 
        for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
-               if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
-                   0xdeadbeef)
+               u32 val;
+
+               val = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
+               if (val == 0xdeadbeef)
                        break;
                DRM_UDELAY(1);
        }
@@ -871,6 +938,46 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
        }
 }
 
+static int radeon_setup_pcigart_surface(drm_radeon_private_t *dev_priv)
+{
+       struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
+       struct radeon_virt_surface *vp;
+       int i;
+
+       for (i = 0; i < RADEON_MAX_SURFACES * 2; i++) {
+               if (!dev_priv->virt_surfaces[i].file_priv ||
+                   dev_priv->virt_surfaces[i].file_priv == PCIGART_FILE_PRIV)
+                       break;
+       }
+       if (i >= 2 * RADEON_MAX_SURFACES)
+               return -ENOMEM;
+       vp = &dev_priv->virt_surfaces[i];
+
+       for (i = 0; i < RADEON_MAX_SURFACES; i++) {
+               struct radeon_surface *sp = &dev_priv->surfaces[i];
+               if (sp->refcount)
+                       continue;
+
+               vp->surface_index = i;
+               vp->lower = gart_info->bus_addr;
+               vp->upper = vp->lower + gart_info->table_size;
+               vp->flags = 0;
+               vp->file_priv = PCIGART_FILE_PRIV;
+
+               sp->refcount = 1;
+               sp->lower = vp->lower;
+               sp->upper = vp->upper;
+               sp->flags = 0;
+
+               RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, sp->flags);
+               RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * i, sp->lower);
+               RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * i, sp->upper);
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
 static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                             struct drm_file *file_priv)
 {
@@ -1039,9 +1146,9 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
-               drm_core_ioremap(dev_priv->cp_ring, dev);
-               drm_core_ioremap(dev_priv->ring_rptr, dev);
-               drm_core_ioremap(dev->agp_buffer_map, dev);
+               drm_core_ioremap_wc(dev_priv->cp_ring, dev);
+               drm_core_ioremap_wc(dev_priv->ring_rptr, dev);
+               drm_core_ioremap_wc(dev->agp_buffer_map, dev);
                if (!dev_priv->cp_ring->handle ||
                    !dev_priv->ring_rptr->handle ||
                    !dev->agp_buffer_map->handle) {
@@ -1052,11 +1159,12 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        } else
 #endif
        {
-               dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
+               dev_priv->cp_ring->handle =
+                       (void *)(unsigned long)dev_priv->cp_ring->offset;
                dev_priv->ring_rptr->handle =
-                   (void *)dev_priv->ring_rptr->offset;
+                       (void *)(unsigned long)dev_priv->ring_rptr->offset;
                dev->agp_buffer_map->handle =
-                   (void *)dev->agp_buffer_map->offset;
+                       (void *)(unsigned long)dev->agp_buffer_map->offset;
 
                DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
                          dev_priv->cp_ring->handle);
@@ -1163,11 +1271,14 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        } else
 #endif
        {
+               u32 sctrl;
+               int ret;
+
                dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
                /* if we have an offset set from userspace */
                if (dev_priv->pcigart_offset_set) {
                        dev_priv->gart_info.bus_addr =
-                           dev_priv->pcigart_offset + dev_priv->fb_location;
+                               (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location;
                        dev_priv->gart_info.mapping.offset =
                            dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
                        dev_priv->gart_info.mapping.size =
@@ -1204,18 +1315,31 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                        }
                }
 
-               if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
+               sctrl = RADEON_READ(RADEON_SURFACE_CNTL);
+               RADEON_WRITE(RADEON_SURFACE_CNTL, 0);
+               ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
+               RADEON_WRITE(RADEON_SURFACE_CNTL, sctrl);
+
+               if (!ret) {
                        DRM_ERROR("failed to init PCI GART!\n");
                        radeon_do_cleanup_cp(dev);
                        return -ENOMEM;
                }
 
+               ret = radeon_setup_pcigart_surface(dev_priv);
+               if (ret) {
+                       DRM_ERROR("failed to setup GART surface!\n");
+                       drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
+                       radeon_do_cleanup_cp(dev);
+                       return ret;
+               }
+
                /* Turn on PCI GART */
                radeon_set_pcigart(dev_priv, 1);
        }
 
        radeon_cp_load_microcode(dev_priv);
-       radeon_cp_init_ring_buffer(dev, dev_priv);
+       radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
 
        dev_priv->last_buf = 0;
 
@@ -1281,7 +1405,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
  *
  * Charl P. Botha <http://cpbotha.net>
  */
-static int radeon_do_resume_cp(struct drm_device * dev)
+static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
@@ -1304,7 +1428,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
        }
 
        radeon_cp_load_microcode(dev_priv);
-       radeon_cp_init_ring_buffer(dev, dev_priv);
+       radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
 
        radeon_do_engine_reset(dev);
        radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
@@ -1479,8 +1603,7 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
  */
 int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-
-       return radeon_do_resume_cp(dev);
+       return radeon_do_resume_cp(dev, file_priv);
 }
 
 int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
@@ -1539,7 +1662,7 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        start = dev_priv->last_buf;
 
        for (t = 0; t < dev_priv->usec_timeout; t++) {
-               u32 done_age = GET_SCRATCH(1);
+               u32 done_age = GET_SCRATCH(dev_priv, 1);
                DRM_DEBUG("done_age = %d\n", done_age);
                for (i = start; i < dma->buf_count; i++) {
                        buf = dma->buflist[i];
@@ -1573,8 +1696,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
        struct drm_buf *buf;
        int i, t;
        int start;
-       u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
+       u32 done_age;
 
+       done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
        if (++dev_priv->last_buf >= dma->buf_count)
                dev_priv->last_buf = 0;
 
@@ -1845,3 +1969,35 @@ int radeon_driver_unload(struct drm_device *dev)
        dev->dev_private = NULL;
        return 0;
 }
+
+void radeon_commit_ring(drm_radeon_private_t *dev_priv)
+{
+       int i;
+       u32 *ring;
+       int tail_aligned;
+
+       /* check if the ring is padded out to 16-dword alignment */
+
+       tail_aligned = dev_priv->ring.tail & 0xf;
+       if (tail_aligned) {
+               int num_p2 = 16 - tail_aligned;
+
+               ring = dev_priv->ring.start;
+               /* pad with some CP_PACKET2 */
+               for (i = 0; i < num_p2; i++)
+                       ring[dev_priv->ring.tail + i] = CP_PACKET2();
+
+               dev_priv->ring.tail += i;
+
+               dev_priv->ring.space -= num_p2 * sizeof(u32);
+       }
+
+       dev_priv->ring.tail &= dev_priv->ring.tail_mask;
+
+       DRM_MEMORYBARRIER();
+       GET_RING_HEAD( dev_priv );
+
+       RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );
+       /* read from PCI bus to ensure correct posting */
+       RADEON_READ( RADEON_CP_RB_RPTR );
+}