diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_agp.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_agp.c | 152 |
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 000000000000..d28430cd2ba6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c | |||
@@ -0,0 +1,152 @@ | |||
1 | #include <linux/module.h> | ||
2 | |||
3 | #include <core/device.h> | ||
4 | |||
5 | #include "nouveau_drm.h" | ||
6 | #include "nouveau_agp.h" | ||
7 | #include "nouveau_reg.h" | ||
8 | |||
9 | #if __OS_HAS_AGP | ||
10 | MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); | ||
11 | static int nouveau_agpmode = -1; | ||
12 | module_param_named(agpmode, nouveau_agpmode, int, 0400); | ||
13 | |||
14 | static unsigned long | ||
15 | get_agp_mode(struct nouveau_drm *drm, unsigned long mode) | ||
16 | { | ||
17 | struct nouveau_device *device = nv_device(drm->device); | ||
18 | |||
19 | /* | ||
20 | * FW seems to be broken on nv18, it makes the card lock up | ||
21 | * randomly. | ||
22 | */ | ||
23 | if (device->chipset == 0x18) | ||
24 | mode &= ~PCI_AGP_COMMAND_FW; | ||
25 | |||
26 | /* | ||
27 | * AGP mode set in the command line. | ||
28 | */ | ||
29 | if (nouveau_agpmode > 0) { | ||
30 | bool agpv3 = mode & 0x8; | ||
31 | int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; | ||
32 | |||
33 | mode = (mode & ~0x7) | (rate & 0x7); | ||
34 | } | ||
35 | |||
36 | return mode; | ||
37 | } | ||
38 | |||
39 | static bool | ||
40 | nouveau_agp_enabled(struct nouveau_drm *drm) | ||
41 | { | ||
42 | struct drm_device *dev = drm->dev; | ||
43 | |||
44 | if (!drm_pci_device_is_agp(dev) || !dev->agp) | ||
45 | return false; | ||
46 | |||
47 | if (drm->agp.stat == UNKNOWN) { | ||
48 | if (!nouveau_agpmode) | ||
49 | return false; | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | return (drm->agp.stat == ENABLED); | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | void | ||
58 | nouveau_agp_reset(struct nouveau_drm *drm) | ||
59 | { | ||
60 | #if __OS_HAS_AGP | ||
61 | struct nouveau_device *device = nv_device(drm->device); | ||
62 | struct drm_device *dev = drm->dev; | ||
63 | u32 save[2]; | ||
64 | int ret; | ||
65 | |||
66 | if (!nouveau_agp_enabled(drm)) | ||
67 | return; | ||
68 | |||
69 | /* First of all, disable fast writes, otherwise if it's | ||
70 | * already enabled in the AGP bridge and we disable the card's | ||
71 | * AGP controller we might be locking ourselves out of it. */ | ||
72 | if ((nv_rd32(device, NV04_PBUS_PCI_NV_19) | | ||
73 | dev->agp->mode) & PCI_AGP_COMMAND_FW) { | ||
74 | struct drm_agp_info info; | ||
75 | struct drm_agp_mode mode; | ||
76 | |||
77 | ret = drm_agp_info(dev, &info); | ||
78 | if (ret) | ||
79 | return; | ||
80 | |||
81 | mode.mode = get_agp_mode(drm, info.mode); | ||
82 | mode.mode &= ~PCI_AGP_COMMAND_FW; | ||
83 | |||
84 | ret = drm_agp_enable(dev, mode); | ||
85 | if (ret) | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | |||
90 | /* clear busmaster bit, and disable AGP */ | ||
91 | save[0] = nv_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); | ||
92 | nv_wr32(device, NV04_PBUS_PCI_NV_19, 0); | ||
93 | |||
94 | /* reset PGRAPH, PFIFO and PTIMER */ | ||
95 | save[1] = nv_mask(device, 0x000200, 0x00011100, 0x00000000); | ||
96 | nv_mask(device, 0x000200, 0x00011100, save[1]); | ||
97 | |||
98 | /* and restore bustmaster bit (gives effect of resetting AGP) */ | ||
99 | nv_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); | ||
100 | #endif | ||
101 | } | ||
102 | |||
103 | void | ||
104 | nouveau_agp_init(struct nouveau_drm *drm) | ||
105 | { | ||
106 | #if __OS_HAS_AGP | ||
107 | struct nouveau_device *device = nv_device(drm->device); | ||
108 | struct drm_device *dev = drm->dev; | ||
109 | struct drm_agp_info info; | ||
110 | struct drm_agp_mode mode; | ||
111 | int ret; | ||
112 | |||
113 | if (!nouveau_agp_enabled(drm)) | ||
114 | return; | ||
115 | drm->agp.stat = DISABLE; | ||
116 | |||
117 | ret = drm_agp_acquire(dev); | ||
118 | if (ret) { | ||
119 | nv_error(device, "unable to acquire AGP: %d\n", ret); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | ret = drm_agp_info(dev, &info); | ||
124 | if (ret) { | ||
125 | nv_error(device, "unable to get AGP info: %d\n", ret); | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | /* see agp.h for the AGPSTAT_* modes available */ | ||
130 | mode.mode = get_agp_mode(drm, info.mode); | ||
131 | |||
132 | ret = drm_agp_enable(dev, mode); | ||
133 | if (ret) { | ||
134 | nv_error(device, "unable to enable AGP: %d\n", ret); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | drm->agp.stat = ENABLED; | ||
139 | drm->agp.base = info.aperture_base; | ||
140 | drm->agp.size = info.aperture_size; | ||
141 | #endif | ||
142 | } | ||
143 | |||
144 | void | ||
145 | nouveau_agp_fini(struct nouveau_drm *drm) | ||
146 | { | ||
147 | #if __OS_HAS_AGP | ||
148 | struct drm_device *dev = drm->dev; | ||
149 | if (dev->agp && dev->agp->acquired) | ||
150 | drm_agp_release(dev); | ||
151 | #endif | ||
152 | } | ||