Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | #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;
#ifdef __powerpc__
/* Disable AGP by default on all PowerPC machines for
* now -- At least some UniNorth-2 AGP bridges are
* known to be broken: DMA from the host to the card
* works just fine, but writeback from the card to the
* host goes straight to memory untranslated bypassing
* the GATT somehow, making them quite painful to deal
* with...
*/
if (nouveau_agpmode == -1)
return false;
#endif
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
}
|