drm/nouveau: port remainder of drm code, and rip out compat layer

v2: Ben Skeggs <bskeggs@redhat.com>
- fill in nouveau_pm.dev to prevent oops
- fix ppc issues (build + OF shadow)

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
new file mode 100644
index 0000000..9d45544
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -0,0 +1,98 @@
+#include <linux/vgaarb.h>
+#include <linux/vga_switcheroo.h>
+
+#include "drmP.h"
+#include "drm_crtc_helper.h"
+
+#include "nouveau_drm.h"
+#include "nouveau_acpi.h"
+#include "nouveau_fbcon.h"
+
+static unsigned int
+nouveau_vga_set_decode(void *priv, bool state)
+{
+	struct nouveau_device *device = nouveau_dev(priv);
+
+	if (device->chipset >= 0x40)
+		nv_wr32(device, 0x088054, state);
+	else
+		nv_wr32(device, 0x001854, state);
+
+	if (state)
+		return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+		       VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+	else
+		return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
+
+static void
+nouveau_switcheroo_set_state(struct pci_dev *pdev,
+			     enum vga_switcheroo_state state)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
+
+	if (state == VGA_SWITCHEROO_ON) {
+		printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
+		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+		nouveau_drm_resume(pdev);
+		drm_kms_helper_poll_enable(dev);
+		dev->switch_power_state = DRM_SWITCH_POWER_ON;
+	} else {
+		printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+		drm_kms_helper_poll_disable(dev);
+		nouveau_switcheroo_optimus_dsm();
+		nouveau_drm_suspend(pdev, pmm);
+		dev->switch_power_state = DRM_SWITCH_POWER_OFF;
+	}
+}
+
+static void
+nouveau_switcheroo_reprobe(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	nouveau_fbcon_output_poll_changed(dev);
+}
+
+static bool
+nouveau_switcheroo_can_switch(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	bool can_switch;
+
+	spin_lock(&dev->count_lock);
+	can_switch = (dev->open_count == 0);
+	spin_unlock(&dev->count_lock);
+	return can_switch;
+}
+
+static const struct vga_switcheroo_client_ops
+nouveau_switcheroo_ops = {
+	.set_gpu_state = nouveau_switcheroo_set_state,
+	.reprobe = nouveau_switcheroo_reprobe,
+	.can_switch = nouveau_switcheroo_can_switch,
+};
+
+void
+nouveau_vga_init(struct nouveau_drm *drm)
+{
+	struct drm_device *dev = drm->dev;
+	vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
+	vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops);
+}
+
+void
+nouveau_vga_fini(struct nouveau_drm *drm)
+{
+	struct drm_device *dev = drm->dev;
+	vga_switcheroo_unregister_client(dev->pdev);
+	vga_client_register(dev->pdev, NULL, NULL, NULL);
+}
+
+
+void
+nouveau_vga_lastclose(struct drm_device *dev)
+{
+	vga_switcheroo_process_delayed_switch();
+}