drm/nouveau: implement devinit subdev, and new init table parser
[pandora-kernel.git] / drivers / gpu / drm / nouveau / nouveau_drm.c
index c72d426..3b4e65d 100644 (file)
@@ -32,6 +32,7 @@
 #include <subdev/device.h>
 
 #include "nouveau_drm.h"
+#include "nouveau_agp.h"
 
 int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *);
 void nouveau_pci_remove(struct pci_dev *);
@@ -123,6 +124,30 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        INIT_LIST_HEAD(&drm->clients);
        drm->dev = dev;
 
+       /* make sure AGP controller is in a consistent state before we
+        * (possibly) execute vbios init tables (see nouveau_agp.h)
+        */
+       if (drm_pci_device_is_agp(dev) && dev->agp) {
+               /* dummy device object, doesn't init anything, but allows
+                * agp code access to registers
+                */
+               ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT,
+                                        NVDRM_DEVICE, 0x0080,
+                                        &(struct nv_device_class) {
+                                               .device = ~0,
+                                               .disable =
+                                                ~(NV_DEVICE_DISABLE_MMIO |
+                                                  NV_DEVICE_DISABLE_IDENTIFY),
+                                               .debug0 = ~0,
+                                        }, sizeof(struct nv_device_class),
+                                        &drm->device);
+               if (ret)
+                       return ret;
+
+               nouveau_agp_reset(drm);
+               nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE);
+       }
+
        ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE,
                                 0x0080, &(struct nv_device_class) {
                                        .device = ~0,
@@ -133,6 +158,9 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto fail_device;
 
+       /* initialise AGP */
+       nouveau_agp_init(drm);
+
        ret = nouveau_load(dev, flags);
        if (ret)
                goto fail_device;
@@ -155,6 +183,8 @@ nouveau_drm_unload(struct drm_device *dev)
        if (ret)
                return ret;
 
+       nouveau_agp_fini(drm);
+
        pci_set_drvdata(pdev, drm->client.base.device);
        nouveau_cli_destroy(&drm->client);
        return 0;
@@ -195,6 +225,8 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        if (ret)
                goto fail_client;
 
+       nouveau_agp_fini(drm);
+
        pci_save_state(pdev);
        if (pm_state.event == PM_EVENT_SUSPEND) {
                pci_disable_device(pdev);
@@ -230,12 +262,16 @@ nouveau_drm_resume(struct pci_dev *pdev)
                return ret;
        pci_set_master(pdev);
 
+       nouveau_agp_reset(drm);
+
        nouveau_client_init(&drm->client.base);
 
        list_for_each_entry(cli, &drm->clients, head) {
                nouveau_client_init(&cli->base);
        }
 
+       nouveau_agp_init(drm);
+
        return nouveau_pci_resume(pdev);
 }