drm/nouveau: Reset AGP before running the init scripts.
authorFrancisco Jerez <currojerez@riseup.net>
Fri, 23 Jul 2010 18:29:13 +0000 (20:29 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 26 Jul 2010 01:43:25 +0000 (11:43 +1000)
BIOS scripts usually make an attempt to reset the AGP controller,
however on some nv4x cards doing it properly involves switching FW off
and on: if we do that without updating the AGP bridge settings
accordingly (e.g. with the corresponding calls to agp_enable()) we
will be locking ourselves out of the card MMIO space. Do it from
nouveau_mem_reset_agp() before the init scripts are executed.

Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c

index e93fbcc..eeaf1f1 100644 (file)
@@ -259,6 +259,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
                return -1;
        pci_set_master(dev->pdev);
 
+       /* Make sure the AGP controller is in a consistent state */
+       if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
+               nouveau_mem_reset_agp(dev);
+
        NV_INFO(dev, "POSTing device...\n");
        ret = nouveau_run_vbios_init(dev);
        if (ret)
index 9f4b8f2..8590032 100644 (file)
@@ -688,6 +688,7 @@ extern int  nouveau_card_init(struct drm_device *);
 extern int  nouveau_mem_detect(struct drm_device *dev);
 extern int  nouveau_mem_init(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
+extern int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
 extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
                                                    uint32_t addr,
index 568bcc2..a9f36ab 100644 (file)
@@ -341,18 +341,36 @@ nouveau_mem_detect(struct drm_device *dev)
        return -ENOMEM;
 }
 
-#if __OS_HAS_AGP
-static void nouveau_mem_reset_agp(struct drm_device *dev)
+int
+nouveau_mem_reset_agp(struct drm_device *dev)
 {
-       uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
+#if __OS_HAS_AGP
+       uint32_t saved_pci_nv_1, pmc_enable;
+       int ret;
+
+       /* First of all, disable fast writes, otherwise if it's
+        * already enabled in the AGP bridge and we disable the card's
+        * AGP controller we might be locking ourselves out of it. */
+       if (dev->agp->acquired) {
+               struct drm_agp_info info;
+               struct drm_agp_mode mode;
+
+               ret = drm_agp_info(dev, &info);
+               if (ret)
+                       return ret;
+
+               mode.mode = info.mode & ~0x10;
+               ret = drm_agp_enable(dev, mode);
+               if (ret)
+                       return ret;
+       }
 
        saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1);
-       saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19);
 
        /* clear busmaster bit */
        nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4);
-       /* clear SBA and AGP bits */
-       nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff);
+       /* disable AGP */
+       nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0);
 
        /* power cycle pgraph, if enabled */
        pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
@@ -364,11 +382,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
        }
 
        /* and restore (gives effect of resetting AGP) */
-       nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
        nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
-}
 #endif
 
+       return 0;
+}
+
 int
 nouveau_mem_init_agp(struct drm_device *dev)
 {
@@ -378,11 +397,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
        struct drm_agp_mode mode;
        int ret;
 
-       if (nouveau_noagp)
-               return 0;
-
-       nouveau_mem_reset_agp(dev);
-
        if (!dev->agp->acquired) {
                ret = drm_agp_acquire(dev);
                if (ret) {
@@ -479,7 +493,8 @@ nouveau_mem_init(struct drm_device *dev)
 
        /* GART */
 #if !defined(__powerpc__) && !defined(__ia64__)
-       if (drm_device_is_agp(dev) && dev->agp) {
+       if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+               nouveau_mem_reset_agp(dev);
                ret = nouveau_mem_init_agp(dev);
                if (ret)
                        NV_ERROR(dev, "Error initialising AGP: %d\n", ret);