preparation patch for radeon permanent mapping registers/framebuffer makes
[profile/ivi/libdrm.git] / shared / radeon_cp.c
index 60da1e4..4efb6c2 100644 (file)
 
 #define RADEON_FIFO_DEBUG      0
 
-#if defined(__alpha__) || defined(__powerpc__)
-# define PCIGART_ENABLED
-#else
-# undef PCIGART_ENABLED
-#endif
-
 
 /* CP microcode (from ATI) */
 static u32 R200_cp_microcode[][2] = {
@@ -777,7 +771,7 @@ static void radeon_do_cp_reset( drm_radeon_private_t *dev_priv )
 
        cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR );
        RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr );
-       *dev_priv->ring.head = cur_read_ptr;
+       SET_RING_HEAD( dev_priv, cur_read_ptr );
        dev_priv->ring.tail = cur_read_ptr;
 }
 
@@ -861,25 +855,24 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
 
        /* Initialize the memory controller */
        RADEON_WRITE( RADEON_MC_FB_LOCATION,
-                     (dev_priv->agp_vm_start - 1) & 0xffff0000 );
+                     ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 )
+                   | ( dev_priv->fb_location >> 16 ) );
 
-       if ( !dev_priv->is_pci ) {
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
                RADEON_WRITE( RADEON_MC_AGP_LOCATION,
-                             (((dev_priv->agp_vm_start - 1 +
-                                dev_priv->agp_size) & 0xffff0000) |
-                              (dev_priv->agp_vm_start >> 16)) );
-       }
+                             (((dev_priv->gart_vm_start - 1 +
+                                dev_priv->gart_size) & 0xffff0000) |
+                              (dev_priv->gart_vm_start >> 16)) );
 
-#if __REALLY_HAVE_AGP
-       if ( !dev_priv->is_pci )
                ring_start = (dev_priv->cp_ring->offset
                              - dev->agp->base
-                             + dev_priv->agp_vm_start);
-       else
+                             + dev_priv->gart_vm_start);
+       else
 #endif
                ring_start = (dev_priv->cp_ring->offset
                              - dev->sg->handle
-                             + dev_priv->agp_vm_start);
+                             + dev_priv->gart_vm_start);
 
        RADEON_WRITE( RADEON_CP_RB_BASE, ring_start );
 
@@ -889,13 +882,20 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
        /* Initialize the ring buffer's read and write pointers */
        cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR );
        RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr );
-       *dev_priv->ring.head = cur_read_ptr;
+       SET_RING_HEAD( dev_priv, cur_read_ptr );
        dev_priv->ring.tail = cur_read_ptr;
 
-       if ( !dev_priv->is_pci ) {
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
+               /* set RADEON_AGP_BASE here instead of relying on X from user space */
+               RADEON_WRITE( RADEON_AGP_BASE, (unsigned int)dev->agp->base );
                RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
-                             dev_priv->ring_rptr->offset );
-       } else {
+                             dev_priv->ring_rptr->offset
+                             - dev->agp->base
+                             + dev_priv->gart_vm_start);
+       } else
+#endif
+       {
                drm_sg_mem_t *entry = dev->sg;
                unsigned long tmp_ofs, page_ofs;
 
@@ -904,8 +904,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
 
                RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
                             entry->busaddr[page_ofs]);
-               DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-                          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 );
        }
 
@@ -920,17 +920,17 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
                                         + RADEON_SCRATCH_REG_OFFSET );
 
        dev_priv->scratch = ((__volatile__ u32 *)
-                            dev_priv->ring.head +
+                            dev_priv->ring_rptr->handle +
                             (RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));
 
        RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 );
 
        /* Writeback doesn't seem to work everywhere, test it first */
-       DRM_WRITE32( &dev_priv->scratch[1], 0 );
+       DRM_WRITE32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0 );
        RADEON_WRITE( RADEON_SCRATCH_REG1, 0xdeadbeef );
 
        for ( tmp = 0 ; tmp < dev_priv->usec_timeout ; tmp++ ) {
-               if ( DRM_READ32( &dev_priv->scratch[1] ) == 0xdeadbeef )
+               if ( DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1) ) == 0xdeadbeef )
                        break;
                DRM_UDELAY( 1 );
        }
@@ -976,34 +976,40 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
                       RADEON_ISYNC_CPSCRATCH_IDLEGUI) );
 }
 
-static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
+/* Enable or disable PCI GART on the chip */
+static void radeon_set_pcigart( drm_radeon_private_t *dev_priv, int on )
 {
-       drm_radeon_private_t *dev_priv;
-       u32 tmp;
-       DRM_DEBUG( "\n" );
+       u32 tmp = RADEON_READ( RADEON_AIC_CNTL );
 
-       dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER );
-       if ( dev_priv == NULL )
-               return DRM_ERR(ENOMEM);
+       if ( on ) {
+               RADEON_WRITE( RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN );
 
-       memset( dev_priv, 0, sizeof(drm_radeon_private_t) );
+               /* set PCI GART page-table base address
+                */
+               RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart );
 
-       dev_priv->is_pci = init->is_pci;
+               /* set address range for PCI address translate
+                */
+               RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->gart_vm_start );
+               RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->gart_vm_start
+                                                 + dev_priv->gart_size - 1);
 
-#if !defined(PCIGART_ENABLED)
-       /* PCI support is not 100% working, so we disable it here.
-        */
-       if ( dev_priv->is_pci ) {
-               DRM_ERROR( "PCI GART not yet supported for Radeon!\n" );
-               dev->dev_private = (void *)dev_priv;
-               radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
+               /* Turn off AGP aperture -- is this required for PCI GART?
+                */
+               RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */
+               RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */
+       } else {
+               RADEON_WRITE( RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN );
        }
-#endif
+}
+
+static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       DRM_DEBUG( "\n" );
 
-       if ( dev_priv->is_pci && !dev->sg ) {
+       if ( (!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg ) {
                DRM_ERROR( "PCI GART memory not allocated!\n" );
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
@@ -1012,13 +1018,12 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
        if ( dev_priv->usec_timeout < 1 ||
             dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) {
                DRM_DEBUG( "TIMEOUT problem!\n" );
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
 
        dev_priv->is_r200 = (init->func == RADEON_INIT_R200_CP);
-       dev_priv->do_boxes = 1;
+       dev_priv->do_boxes = 0;
        dev_priv->cp_mode = init->cp_mode;
 
        /* We don't support anything other than bus-mastering ring mode,
@@ -1028,7 +1033,6 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
        if ( ( init->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) &&
             ( init->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) {
                DRM_DEBUG( "BAD cp_mode (%x)!\n", init->cp_mode );
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
@@ -1059,13 +1063,6 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
        dev_priv->depth_offset  = init->depth_offset;
        dev_priv->depth_pitch   = init->depth_pitch;
 
-       dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
-                                       (dev_priv->front_offset >> 10));
-       dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
-                                      (dev_priv->back_offset >> 10));
-       dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
-                                       (dev_priv->depth_offset >> 10));
-
        /* Hardware state for depth clears.  Remove this if/when we no
         * longer clear the depth buffer with a 3D rectangle.  Hard-code
         * all values to prevent unwanted 3D state from slipping through
@@ -1097,56 +1094,49 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
                                         RADEON_ROUND_PREC_8TH_PIX);
 
        DRM_GETSAREA();
+
+       dev_priv->fb_offset = init->fb_offset;
+       dev_priv->mmio_offset = init->mmio_offset;
+       dev_priv->ring_offset = init->ring_offset;
+       dev_priv->ring_rptr_offset = init->ring_rptr_offset;
+       dev_priv->buffers_offset = init->buffers_offset;
+       dev_priv->gart_textures_offset = init->gart_textures_offset;
        
        if(!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
 
-       DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-       if(!dev_priv->fb) {
-               DRM_ERROR("could not find framebuffer!\n");
-               dev->dev_private = (void *)dev_priv;
-               radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
-       }
        DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
        if(!dev_priv->mmio) {
                DRM_ERROR("could not find mmio region!\n");
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
        DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset );
        if(!dev_priv->cp_ring) {
                DRM_ERROR("could not find cp ring region!\n");
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
        DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset );
        if(!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
        DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
        if(!dev_priv->buffers) {
                DRM_ERROR("could not find dma buffer region!\n");
-               dev->dev_private = (void *)dev_priv;
                radeon_do_cleanup_cp(dev);
                return DRM_ERR(EINVAL);
        }
 
-       if ( !dev_priv->is_pci ) {
-               DRM_FIND_MAP( dev_priv->agp_textures,
-                             init->agp_textures_offset );
-               if(!dev_priv->agp_textures) {
-                       DRM_ERROR("could not find agp texture region!\n");
-                       dev->dev_private = (void *)dev_priv;
+       if ( init->gart_textures_offset ) {
+               DRM_FIND_MAP( dev_priv->gart_textures, init->gart_textures_offset );
+               if ( !dev_priv->gart_textures ) {
+                       DRM_ERROR("could not find GART texture region!\n");
                        radeon_do_cleanup_cp(dev);
                        return DRM_ERR(EINVAL);
                }
@@ -1156,19 +1146,21 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
                (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle +
                                       init->sarea_priv_offset);
 
-       if ( !dev_priv->is_pci ) {
-               DRM_IOREMAP( dev_priv->cp_ring );
-               DRM_IOREMAP( dev_priv->ring_rptr );
-               DRM_IOREMAP( dev_priv->buffers );
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
+               DRM_IOREMAP( dev_priv->cp_ring, dev );
+               DRM_IOREMAP( dev_priv->ring_rptr, dev );
+               DRM_IOREMAP( dev_priv->buffers, dev );
                if(!dev_priv->cp_ring->handle ||
                   !dev_priv->ring_rptr->handle ||
                   !dev_priv->buffers->handle) {
                        DRM_ERROR("could not find ioremap agp regions!\n");
-                       dev->dev_private = (void *)dev_priv;
                        radeon_do_cleanup_cp(dev);
                        return DRM_ERR(EINVAL);
                }
-       } else {
+       } else
+#endif
+       {
                dev_priv->cp_ring->handle =
                        (void *)dev_priv->cp_ring->offset;
                dev_priv->ring_rptr->handle =
@@ -1183,29 +1175,43 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
                           dev_priv->buffers->handle );
        }
 
+       dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION )
+                               & 0xffff ) << 16;
+
+       dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
+                                       ( ( dev_priv->front_offset
+                                         + dev_priv->fb_location ) >> 10 ) );
+
+       dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
+                                      ( ( dev_priv->back_offset
+                                        + dev_priv->fb_location ) >> 10 ) );
+
+       dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
+                                       ( ( dev_priv->depth_offset
+                                         + dev_priv->fb_location ) >> 10 ) );
+
+
+       dev_priv->gart_size = init->gart_size;
+       dev_priv->gart_vm_start = dev_priv->fb_location
+                               + RADEON_READ( RADEON_CONFIG_APER_SIZE );
 
-       dev_priv->agp_size = init->agp_size;
-       dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );
 #if __REALLY_HAVE_AGP
-       if ( !dev_priv->is_pci )
-               dev_priv->agp_buffers_offset = (dev_priv->buffers->offset
+       if (dev_priv->flags & CHIP_IS_AGP)
+               dev_priv->gart_buffers_offset = (dev_priv->buffers->offset
                                                - dev->agp->base
-                                               + dev_priv->agp_vm_start);
+                                               + dev_priv->gart_vm_start);
        else
 #endif
-               dev_priv->agp_buffers_offset = (dev_priv->buffers->offset
+               dev_priv->gart_buffers_offset = (dev_priv->buffers->offset
                                                - dev->sg->handle
-                                               + dev_priv->agp_vm_start);
+                                               + dev_priv->gart_vm_start);
 
-       DRM_DEBUG( "dev_priv->agp_size %d\n",
-                  dev_priv->agp_size );
-       DRM_DEBUG( "dev_priv->agp_vm_start 0x%x\n",
-                  dev_priv->agp_vm_start );
-       DRM_DEBUG( "dev_priv->agp_buffers_offset 0x%lx\n",
-                  dev_priv->agp_buffers_offset );
-
-       dev_priv->ring.head = ((__volatile__ u32 *)
-                              dev_priv->ring_rptr->handle);
+       DRM_DEBUG( "dev_priv->gart_size %d\n",
+                  dev_priv->gart_size );
+       DRM_DEBUG( "dev_priv->gart_vm_start 0x%x\n",
+                  dev_priv->gart_vm_start );
+       DRM_DEBUG( "dev_priv->gart_buffers_offset 0x%lx\n",
+                  dev_priv->gart_buffers_offset );
 
        dev_priv->ring.start = (u32 *)dev_priv->cp_ring->handle;
        dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle
@@ -1218,53 +1224,29 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
 
        dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
 
-#if __REALLY_HAVE_SG
-       if ( dev_priv->is_pci ) {
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
+               /* Turn off PCI GART */
+               radeon_set_pcigart( dev_priv, 0 );
+       } else
+#endif
+       {
                if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
                                            &dev_priv->bus_pci_gart)) {
                        DRM_ERROR( "failed to init PCI GART!\n" );
-                       dev->dev_private = (void *)dev_priv;
                        radeon_do_cleanup_cp(dev);
                        return DRM_ERR(ENOMEM);
                }
-               /* Turn on PCI GART
-                */
-               tmp = RADEON_READ( RADEON_AIC_CNTL )
-                     | RADEON_PCIGART_TRANSLATE_EN;
-               RADEON_WRITE( RADEON_AIC_CNTL, tmp );
 
-               /* set PCI GART page-table base address
-                */
-               RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart );
-
-               /* set address range for PCI address translate
-                */
-               RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->agp_vm_start );
-               RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->agp_vm_start
-                                                 + dev_priv->agp_size - 1);
-
-               /* Turn off AGP aperture -- is this required for PCIGART?
-                */
-               RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */
-               RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */
-       } else {
-#endif /* __REALLY_HAVE_SG */
-               /* Turn off PCI GART
-                */
-               tmp = RADEON_READ( RADEON_AIC_CNTL )
-                     & ~RADEON_PCIGART_TRANSLATE_EN;
-               RADEON_WRITE( RADEON_AIC_CNTL, tmp );
-#if __REALLY_HAVE_SG
+               /* Turn on PCI GART */
+               radeon_set_pcigart( dev_priv, 1 );
        }
-#endif /* __REALLY_HAVE_SG */
 
        radeon_cp_load_microcode( dev_priv );
        radeon_cp_init_ring_buffer( dev, dev_priv );
 
        dev_priv->last_buf = 0;
 
-       dev->dev_private = (void *)dev_priv;
-
        radeon_do_engine_reset( dev );
 
        return 0;
@@ -1272,38 +1254,90 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
 
 int radeon_do_cleanup_cp( drm_device_t *dev )
 {
+       drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG( "\n" );
 
-       if ( dev->dev_private ) {
-               drm_radeon_private_t *dev_priv = dev->dev_private;
-
-               if ( !dev_priv->is_pci ) {
-                       DRM_IOREMAPFREE( dev_priv->cp_ring );
-                       DRM_IOREMAPFREE( dev_priv->ring_rptr );
-                       DRM_IOREMAPFREE( dev_priv->buffers );
-               } else {
-#if __REALLY_HAVE_SG
-                       if (!DRM(ati_pcigart_cleanup)( dev,
-                                               dev_priv->phys_pci_gart,
-                                               dev_priv->bus_pci_gart ))
-                               DRM_ERROR( "failed to cleanup PCI GART!\n" );
-#endif /* __REALLY_HAVE_SG */
-               }
+#if __HAVE_IRQ
+       /* Make sure interrupts are disabled here because the uninstall ioctl
+        * may not have been called from userspace and after dev_private
+        * is freed, it's too late.
+        */
+       if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
+#endif
 
-               DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t),
-                          DRM_MEM_DRIVER );
-               dev->dev_private = NULL;
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
+               if ( dev_priv->cp_ring != NULL )
+                       DRM_IOREMAPFREE( dev_priv->cp_ring, dev );
+               if ( dev_priv->ring_rptr != NULL )
+                       DRM_IOREMAPFREE( dev_priv->ring_rptr, dev );
+               if ( dev_priv->buffers != NULL )
+                       DRM_IOREMAPFREE( dev_priv->buffers, dev );
+       } else
+#endif
+       {
+               if (!DRM(ati_pcigart_cleanup)( dev,
+                                       dev_priv->phys_pci_gart,
+                                       dev_priv->bus_pci_gart ))
+                       DRM_ERROR( "failed to cleanup PCI GART!\n" );
        }
+       {
+               int flags = dev_priv->flags;
+               memset(dev_priv, 0, sizeof(*dev_priv));
+               dev_priv->flags = flags;
+       }
+
+       return 0;
+}
+
+/* This code will reinit the Radeon CP hardware after a resume from disc.  
+ * AFAIK, it would be very difficult to pickle the state at suspend time, so 
+ * here we make sure that all Radeon hardware initialisation is re-done without
+ * affecting running applications.
+ *
+ * Charl P. Botha <http://cpbotha.net>
+ */
+static int radeon_do_resume_cp( drm_device_t *dev )
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if ( !dev_priv ) {
+               DRM_ERROR( "Called with no initialization\n" );
+               return DRM_ERR( EINVAL );
+       }
+
+       DRM_DEBUG("Starting radeon_do_resume_cp()\n");
+
+#if __REALLY_HAVE_AGP
+       if (dev_priv->flags & CHIP_IS_AGP) {
+               /* Turn off PCI GART */
+               radeon_set_pcigart( dev_priv, 0 );
+       } else
+#endif
+       {
+               /* 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_do_engine_reset( dev );
+
+       DRM_DEBUG("radeon_do_resume_cp() complete\n");
 
        return 0;
 }
 
+
 int radeon_cp_init( DRM_IOCTL_ARGS )
 {
        DRM_DEVICE;
        drm_radeon_init_t init;
 
-       DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t *)data, sizeof(init) );
+       LOCK_TEST_WITH_RETURN( dev, filp );
+
+       DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t __user *)data, sizeof(init) );
 
        switch ( init.func ) {
        case RADEON_INIT_CP:
@@ -1322,7 +1356,7 @@ int radeon_cp_start( DRM_IOCTL_ARGS )
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG( "\n" );
 
-       LOCK_TEST_WITH_RETURN( dev );
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
        if ( dev_priv->cp_running ) {
                DRM_DEBUG( "%s while CP running\n", __FUNCTION__ );
@@ -1350,9 +1384,12 @@ int radeon_cp_stop( DRM_IOCTL_ARGS )
        int ret;
        DRM_DEBUG( "\n" );
 
-       LOCK_TEST_WITH_RETURN( dev );
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
-       DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t *)data, sizeof(stop) );
+       DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t __user *)data, sizeof(stop) );
+
+       if (!dev_priv->cp_running)
+               return 0;
 
        /* Flush any pending CP commands.  This ensures any outstanding
         * commands are exectuted by the engine before we turn it off.
@@ -1381,6 +1418,42 @@ int radeon_cp_stop( DRM_IOCTL_ARGS )
        return 0;
 }
 
+
+void radeon_do_release( drm_device_t *dev )
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       int ret;
+       DRM_DEBUG("dev_priv %ptr\n", dev_priv);
+
+       if (dev_priv) {
+
+               if (dev_priv->cp_running) {
+                       /* Stop the cp */
+                       while ((ret = radeon_do_cp_idle( dev_priv )) != 0) {
+                               DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
+#ifdef __linux__
+                               schedule();
+#else
+                               tsleep(&ret, PZERO, "rdnrel", 1);
+#endif
+                       }
+                       radeon_do_cp_stop( dev_priv );
+                       radeon_do_engine_reset( dev );
+               }
+
+               /* Disable *all* interrupts */
+               if (dev_priv->mmio) /* remove this after permanent addmaps */
+                       RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
+
+               /* Free memory heap structures */
+               radeon_mem_takedown( &(dev_priv->gart_heap) );
+               radeon_mem_takedown( &(dev_priv->fb_heap) );
+
+               /* deallocate kernel resources */
+               radeon_do_cleanup_cp( dev );
+       }
+}
+
 /* Just reset the CP ring.  Called as part of an X Server engine reset.
  */
 int radeon_cp_reset( DRM_IOCTL_ARGS )
@@ -1389,7 +1462,7 @@ int radeon_cp_reset( DRM_IOCTL_ARGS )
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG( "\n" );
 
-       LOCK_TEST_WITH_RETURN( dev );
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
        if ( !dev_priv ) {
                DRM_DEBUG( "%s called before init done\n", __FUNCTION__ );
@@ -1410,20 +1483,27 @@ int radeon_cp_idle( DRM_IOCTL_ARGS )
        drm_radeon_private_t *dev_priv = dev->dev_private;
        DRM_DEBUG( "\n" );
 
-       LOCK_TEST_WITH_RETURN( dev );
-
-/*     if (dev->irq)  */
-/*             radeon_emit_and_wait_irq( dev ); */
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
        return radeon_do_cp_idle( dev_priv );
 }
 
+/* Added by Charl P. Botha to call radeon_do_resume_cp().
+ */
+int radeon_cp_resume( DRM_IOCTL_ARGS )
+{
+       DRM_DEVICE;
+
+       return radeon_do_resume_cp(dev);
+}
+
+
 int radeon_engine_reset( DRM_IOCTL_ARGS )
 {
        DRM_DEVICE;
        DRM_DEBUG( "\n" );
 
-       LOCK_TEST_WITH_RETURN( dev );
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
        return radeon_do_engine_reset( dev );
 }
@@ -1482,7 +1562,7 @@ drm_buf_t *radeon_freelist_get( drm_device_t *dev )
                for ( i = start ; i < dma->buf_count ; i++ ) {
                        buf = dma->buflist[i];
                        buf_priv = buf->dev_private;
-                       if ( buf->pid == 0 || (buf->pending && 
+                       if ( buf->filp == 0 || (buf->pending && 
                                               buf_priv->age <= done_age) ) {
                                dev_priv->stats.requested_bufs++;
                                buf->pending = 0;
@@ -1497,7 +1577,7 @@ drm_buf_t *radeon_freelist_get( drm_device_t *dev )
                }
        }
 
-       DRM_ERROR( "returning NULL!\n" );
+       DRM_DEBUG( "returning NULL!\n" );
        return NULL;
 }
 #if 0
@@ -1509,7 +1589,7 @@ drm_buf_t *radeon_freelist_get( drm_device_t *dev )
        drm_buf_t *buf;
        int i, t;
        int start;
-       u32 done_age = DRM_READ32(&dev_priv->scratch[1]);
+       u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
 
        if ( ++dev_priv->last_buf >= dma->buf_count )
                dev_priv->last_buf = 0;
@@ -1521,7 +1601,7 @@ drm_buf_t *radeon_freelist_get( drm_device_t *dev )
                for ( i = start ; i < dma->buf_count ; i++ ) {
                        buf = dma->buflist[i];
                        buf_priv = buf->dev_private;
-                       if ( buf->pid == 0 || (buf->pending && 
+                       if ( buf->filp == 0 || (buf->pending && 
                                               buf_priv->age <= done_age) ) {
                                dev_priv->stats.requested_bufs++;
                                buf->pending = 0;
@@ -1558,10 +1638,10 @@ int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n )
 {
        drm_radeon_ring_buffer_t *ring = &dev_priv->ring;
        int i;
-       u32 last_head = GET_RING_HEAD(ring);
+       u32 last_head = GET_RING_HEAD( dev_priv );
 
        for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-               u32 head = GET_RING_HEAD(ring);
+               u32 head = GET_RING_HEAD( dev_priv );
 
                ring->space = (head - ring->tail) * sizeof(u32);
                if ( ring->space <= 0 )
@@ -1586,7 +1666,7 @@ int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n )
        return DRM_ERR(EBUSY);
 }
 
-static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d )
+static int radeon_cp_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d )
 {
        int i;
        drm_buf_t *buf;
@@ -1595,7 +1675,7 @@ static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d )
                buf = radeon_freelist_get( dev );
                if ( !buf ) return DRM_ERR(EBUSY); /* NOTE: broken client */
 
-               buf->pid = DRM_CURRENTPID;
+               buf->filp = filp;
 
                if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx,
                                   sizeof(buf->idx) ) )
@@ -1614,11 +1694,12 @@ int radeon_cp_buffers( DRM_IOCTL_ARGS )
        DRM_DEVICE;
        drm_device_dma_t *dma = dev->dma;
        int ret = 0;
+       drm_dma_t __user *argp = (void __user *)data;
        drm_dma_t d;
 
-       LOCK_TEST_WITH_RETURN( dev );
+       LOCK_TEST_WITH_RETURN( dev, filp );
 
-       DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) );
+       DRM_COPY_FROM_USER_IOCTL( d, argp, sizeof(d) );
 
        /* Please don't send us buffers.
         */
@@ -1639,10 +1720,87 @@ int radeon_cp_buffers( DRM_IOCTL_ARGS )
        d.granted_count = 0;
 
        if ( d.request_count ) {
-               ret = radeon_cp_get_buffers( dev, &d );
+               ret = radeon_cp_get_buffers( filp, dev, &d );
        }
 
-       DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) );
+       DRM_COPY_TO_USER_IOCTL( argp, d, sizeof(d) );
 
        return ret;
 }
+
+static int radeon_register_regions(struct pci_dev *pdev) {
+       int retcode = -EINVAL;
+
+       /* request the mem regions */
+       if (!request_mem_region (pci_resource_start( pdev, 2 ),
+                                       pci_resource_len(pdev, 2), DRIVER_NAME)) {
+               printk(KERN_ERR DRIVER_NAME ": cannot reserve MMIO region\n");
+               return retcode;
+       }
+       if (!request_mem_region (pci_resource_start( pdev, 0 ),
+                                       pci_resource_len(pdev, 0), DRIVER_NAME)) {
+               printk(KERN_ERR DRIVER_NAME ": cannot reserve FB region\n");
+               return retcode;
+       }
+       return 0;
+}
+
+static void radeon_release_regions(struct pci_dev *pdev) {
+        release_mem_region (pci_resource_start( pdev, 2 ), pci_resource_len(pdev, 2));
+        release_mem_region (pci_resource_start( pdev, 0 ), pci_resource_len(pdev, 0));
+}
+
+/* Always create a map record for MMIO and FB memory, done from DRIVER_POSTINIT */
+int radeon_preinit( drm_device_t *dev, unsigned long flags )
+{
+       int retcode = -EINVAL;
+       u32 save, temp;
+       drm_radeon_private_t *dev_priv;
+
+       dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER );
+       if ( dev_priv == NULL )
+               return DRM_ERR(ENOMEM);
+       DRM_DEBUG("dev_priv %ptr\n", dev_priv);
+
+       memset( dev_priv, 0, sizeof(drm_radeon_private_t) );
+       dev->dev_private = (void *)dev_priv;
+       dev_priv->flags = flags;
+
+       /* request the mem regions */
+       if (!DRM(fb_loaded))
+               if ((retcode = radeon_register_regions(dev->pdev)) != 0)
+                       return retcode;
+
+       /* There are signatures in BIOS and PCI-SSID for a PCI card, but they are not very reliable.
+               Following detection method works for all cards tested so far.
+               Note, checking AGP_ENABLE bit after drmAgpEnable call can also give the correct result.
+               However, calling drmAgpEnable on a PCI card can cause some strange lockup when the server
+               restarts next time.
+       */
+       pci_read_config_dword(dev->pdev, RADEON_AGP_COMMAND_PCI_CONFIG, &save);
+       pci_write_config_dword(dev->pdev, RADEON_AGP_COMMAND_PCI_CONFIG, save | RADEON_AGP_ENABLE);
+       pci_read_config_dword(dev->pdev, RADEON_AGP_COMMAND_PCI_CONFIG, &temp);
+       if (temp & RADEON_AGP_ENABLE)
+               dev_priv->flags |= CHIP_IS_AGP;
+       DRM_DEBUG("%s card detected\n", ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI"));
+       pci_write_config_dword(dev->pdev, RADEON_AGP_COMMAND_PCI_CONFIG, save);
+
+        return 0;
+}
+
+int radeon_postinit( drm_device_t *dev, unsigned long flags )
+{
+       return 0;
+}
+
+void radeon_postcleanup( drm_device_t *dev )
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+       
+       DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER );
+
+       if (!DRM(fb_loaded))
+               radeon_release_regions(dev->pdev);
+       
+       dev->dev_private = NULL;
+}