summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_agp.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-10-03 03:26:15 (GMT)
committerDave Airlie <airlied@redhat.com>2012-10-03 03:26:15 (GMT)
commit268d28371cd326be4dfcd7eba5917bf4b9d30c8f (patch)
treefec4f9e98bde15301b5d5338038a9a31f7555456 /drivers/gpu/drm/nouveau/nouveau_agp.c
parentdf86b5765a48d5f557489577652bd6df145b0e1b (diff)
parentb9f10852fcb1f09369d931dcbfbaad89ad1da4ad (diff)
downloadlinux-268d28371cd326be4dfcd7eba5917bf4b9d30c8f.tar.xz
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
This is a major rework of the nouveau driver core, to reflect more closely how the hw is used and to make it easier to implement newer features now that the GPUs are more clearly understood than when nouveau started. It also contains a few other bits: thermal patches nv41/44 pcie gart fixes i2c unregistering fixes. * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (191 commits) drm/nv98/crypt: fix fuc build with latest envyas drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering drm/nv41/vm: fix and enable use of "real" pciegart drm/nv44/vm: fix and enable use of "real" pciegart drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie drm/nouveau: store supported dma mask in vmmgr drm/nvc0/ibus: initial implementation of subdev drm/nouveau/therm: add support for fan-control modes drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules drm/nouveau/therm: calculate the pwm divisor on nv50+ drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster drm/nouveau/therm: move thermal-related functions to the therm subdev drm/nouveau/bios: parse the pwm divisor from the perf table drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices drm/nouveau/therm: rework thermal table parsing drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table drm/nouveau: fix pm initialization order drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it drm/nouveau: log channel debug/error messages from client object rather than drm client drm/nouveau: have drm debugging macros build on top of core macros ... Conflicts: drivers/gpu/drm/nouveau/nouveau_dp.c
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_agp.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_agp.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c
new file mode 100644
index 0000000..d28430c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_agp.c
@@ -0,0 +1,152 @@
+#include <linux/module.h>
+
+#include <core/device.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_agp.h"
+#include "nouveau_reg.h"
+
+#if __OS_HAS_AGP
+MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
+static int nouveau_agpmode = -1;
+module_param_named(agpmode, nouveau_agpmode, int, 0400);
+
+static unsigned long
+get_agp_mode(struct nouveau_drm *drm, unsigned long mode)
+{
+ struct nouveau_device *device = nv_device(drm->device);
+
+ /*
+ * FW seems to be broken on nv18, it makes the card lock up
+ * randomly.
+ */
+ if (device->chipset == 0x18)
+ mode &= ~PCI_AGP_COMMAND_FW;
+
+ /*
+ * AGP mode set in the command line.
+ */
+ if (nouveau_agpmode > 0) {
+ bool agpv3 = mode & 0x8;
+ int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
+
+ mode = (mode & ~0x7) | (rate & 0x7);
+ }
+
+ return mode;
+}
+
+static bool
+nouveau_agp_enabled(struct nouveau_drm *drm)
+{
+ struct drm_device *dev = drm->dev;
+
+ if (!drm_pci_device_is_agp(dev) || !dev->agp)
+ return false;
+
+ if (drm->agp.stat == UNKNOWN) {
+ if (!nouveau_agpmode)
+ return false;
+ return true;
+ }
+
+ return (drm->agp.stat == ENABLED);
+}
+#endif
+
+void
+nouveau_agp_reset(struct nouveau_drm *drm)
+{
+#if __OS_HAS_AGP
+ struct nouveau_device *device = nv_device(drm->device);
+ struct drm_device *dev = drm->dev;
+ u32 save[2];
+ int ret;
+
+ if (!nouveau_agp_enabled(drm))
+ return;
+
+ /* 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 ((nv_rd32(device, NV04_PBUS_PCI_NV_19) |
+ dev->agp->mode) & PCI_AGP_COMMAND_FW) {
+ struct drm_agp_info info;
+ struct drm_agp_mode mode;
+
+ ret = drm_agp_info(dev, &info);
+ if (ret)
+ return;
+
+ mode.mode = get_agp_mode(drm, info.mode);
+ mode.mode &= ~PCI_AGP_COMMAND_FW;
+
+ ret = drm_agp_enable(dev, mode);
+ if (ret)
+ return;
+ }
+
+
+ /* clear busmaster bit, and disable AGP */
+ save[0] = nv_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000);
+ nv_wr32(device, NV04_PBUS_PCI_NV_19, 0);
+
+ /* reset PGRAPH, PFIFO and PTIMER */
+ save[1] = nv_mask(device, 0x000200, 0x00011100, 0x00000000);
+ nv_mask(device, 0x000200, 0x00011100, save[1]);
+
+ /* and restore bustmaster bit (gives effect of resetting AGP) */
+ nv_wr32(device, NV04_PBUS_PCI_NV_1, save[0]);
+#endif
+}
+
+void
+nouveau_agp_init(struct nouveau_drm *drm)
+{
+#if __OS_HAS_AGP
+ struct nouveau_device *device = nv_device(drm->device);
+ struct drm_device *dev = drm->dev;
+ struct drm_agp_info info;
+ struct drm_agp_mode mode;
+ int ret;
+
+ if (!nouveau_agp_enabled(drm))
+ return;
+ drm->agp.stat = DISABLE;
+
+ ret = drm_agp_acquire(dev);
+ if (ret) {
+ nv_error(device, "unable to acquire AGP: %d\n", ret);
+ return;
+ }
+
+ ret = drm_agp_info(dev, &info);
+ if (ret) {
+ nv_error(device, "unable to get AGP info: %d\n", ret);
+ return;
+ }
+
+ /* see agp.h for the AGPSTAT_* modes available */
+ mode.mode = get_agp_mode(drm, info.mode);
+
+ ret = drm_agp_enable(dev, mode);
+ if (ret) {
+ nv_error(device, "unable to enable AGP: %d\n", ret);
+ return;
+ }
+
+ drm->agp.stat = ENABLED;
+ drm->agp.base = info.aperture_base;
+ drm->agp.size = info.aperture_size;
+#endif
+}
+
+void
+nouveau_agp_fini(struct nouveau_drm *drm)
+{
+#if __OS_HAS_AGP
+ struct drm_device *dev = drm->dev;
+ if (dev->agp && dev->agp->acquired)
+ drm_agp_release(dev);
+#endif
+}