aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv40_fifo.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-11 04:24:15 -0500
committerDave Airlie <airlied@redhat.com>2009-12-11 06:29:34 -0500
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nv40_fifo.c
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv40_fifo.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
new file mode 100644
index 000000000000..b4f19ccb8b41
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -0,0 +1,314 @@
1/*
2 * Copyright (C) 2007 Ben Skeggs.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include "drmP.h"
28#include "nouveau_drv.h"
29#include "nouveau_drm.h"
30
31#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE))
32#define NV40_RAMFC__SIZE 128
33
34int
35nv40_fifo_create_context(struct nouveau_channel *chan)
36{
37 struct drm_device *dev = chan->dev;
38 struct drm_nouveau_private *dev_priv = dev->dev_private;
39 uint32_t fc = NV40_RAMFC(chan->id);
40 int ret;
41
42 ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
43 NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
44 NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
45 if (ret)
46 return ret;
47
48 dev_priv->engine.instmem.prepare_access(dev, true);
49 nv_wi32(dev, fc + 0, chan->pushbuf_base);
50 nv_wi32(dev, fc + 4, chan->pushbuf_base);
51 nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
52 nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
53 NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
54 NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
55#ifdef __BIG_ENDIAN
56 NV_PFIFO_CACHE1_BIG_ENDIAN |
57#endif
58 0x30000000 /* no idea.. */);
59 nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
60 nv_wi32(dev, fc + 60, 0x0001FFFF);
61 dev_priv->engine.instmem.finish_access(dev);
62
63 /* enable the fifo dma operation */
64 nv_wr32(dev, NV04_PFIFO_MODE,
65 nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
66 return 0;
67}
68
69void
70nv40_fifo_destroy_context(struct nouveau_channel *chan)
71{
72 struct drm_device *dev = chan->dev;
73
74 nv_wr32(dev, NV04_PFIFO_MODE,
75 nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
76
77 if (chan->ramfc)
78 nouveau_gpuobj_ref_del(dev, &chan->ramfc);
79}
80
81static void
82nv40_fifo_do_load_context(struct drm_device *dev, int chid)
83{
84 struct drm_nouveau_private *dev_priv = dev->dev_private;
85 uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
86
87 dev_priv->engine.instmem.prepare_access(dev, false);
88
89 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
90 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
91 nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
92 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE, nv_ri32(dev, fc + 12));
93 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT, nv_ri32(dev, fc + 16));
94 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, nv_ri32(dev, fc + 20));
95
96 /* No idea what 0x2058 is.. */
97 tmp = nv_ri32(dev, fc + 24);
98 tmp2 = nv_rd32(dev, 0x2058) & 0xFFF;
99 tmp2 |= (tmp & 0x30000000);
100 nv_wr32(dev, 0x2058, tmp2);
101 tmp &= ~0x30000000;
102 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_FETCH, tmp);
103
104 nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 28));
105 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 32));
106 nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE, nv_ri32(dev, fc + 36));
107 tmp = nv_ri32(dev, fc + 40);
108 nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, tmp);
109 nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT, nv_ri32(dev, fc + 44));
110 nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, nv_ri32(dev, fc + 48));
111 nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 52));
112 nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, nv_ri32(dev, fc + 56));
113
114 /* Don't clobber the TIMEOUT_ENABLED flag when restoring from RAMFC */
115 tmp = nv_rd32(dev, NV04_PFIFO_DMA_TIMESLICE) & ~0x1FFFF;
116 tmp |= nv_ri32(dev, fc + 60) & 0x1FFFF;
117 nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, tmp);
118
119 nv_wr32(dev, 0x32e4, nv_ri32(dev, fc + 64));
120 /* NVIDIA does this next line twice... */
121 nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
122 nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
123 nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
124
125 dev_priv->engine.instmem.finish_access(dev);
126
127 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
128 nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
129}
130
131int
132nv40_fifo_load_context(struct nouveau_channel *chan)
133{
134 struct drm_device *dev = chan->dev;
135 uint32_t tmp;
136
137 nv40_fifo_do_load_context(dev, chan->id);
138
139 /* Set channel active, and in DMA mode */
140 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
141 NV40_PFIFO_CACHE1_PUSH1_DMA | chan->id);
142 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 1);
143
144 /* Reset DMA_CTL_AT_INFO to INVALID */
145 tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_CTL) & ~(1 << 31);
146 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_CTL, tmp);
147
148 return 0;
149}
150
151int
152nv40_fifo_unload_context(struct drm_device *dev)
153{
154 struct drm_nouveau_private *dev_priv = dev->dev_private;
155 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
156 uint32_t fc, tmp;
157 int chid;
158
159 chid = pfifo->channel_id(dev);
160 if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
161 return 0;
162 fc = NV40_RAMFC(chid);
163
164 dev_priv->engine.instmem.prepare_access(dev, true);
165 nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
166 nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
167 nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
168 nv_wi32(dev, fc + 12, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE));
169 nv_wi32(dev, fc + 16, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT));
170 nv_wi32(dev, fc + 20, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_STATE));
171 tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH);
172 tmp |= nv_rd32(dev, 0x2058) & 0x30000000;
173 nv_wi32(dev, fc + 24, tmp);
174 nv_wi32(dev, fc + 28, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
175 nv_wi32(dev, fc + 32, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
176 nv_wi32(dev, fc + 36, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
177 tmp = nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP);
178 nv_wi32(dev, fc + 40, tmp);
179 nv_wi32(dev, fc + 44, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
180 nv_wi32(dev, fc + 48, nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE));
181 /* NVIDIA read 0x3228 first, then write DMA_GET here.. maybe something
182 * more involved depending on the value of 0x3228?
183 */
184 nv_wi32(dev, fc + 52, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
185 nv_wi32(dev, fc + 56, nv_rd32(dev, NV40_PFIFO_GRCTX_INSTANCE));
186 nv_wi32(dev, fc + 60, nv_rd32(dev, NV04_PFIFO_DMA_TIMESLICE) & 0x1ffff);
187 /* No idea what the below is for exactly, ripped from a mmio-trace */
188 nv_wi32(dev, fc + 64, nv_rd32(dev, NV40_PFIFO_UNK32E4));
189 /* NVIDIA do this next line twice.. bug? */
190 nv_wi32(dev, fc + 68, nv_rd32(dev, 0x32e8));
191 nv_wi32(dev, fc + 76, nv_rd32(dev, 0x2088));
192 nv_wi32(dev, fc + 80, nv_rd32(dev, 0x3300));
193#if 0 /* no real idea which is PUT/GET in UNK_48.. */
194 tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_GET);
195 tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
196 nv_wi32(dev, fc + 72, tmp);
197#endif
198 dev_priv->engine.instmem.finish_access(dev);
199
200 nv40_fifo_do_load_context(dev, pfifo->channels - 1);
201 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
202 NV40_PFIFO_CACHE1_PUSH1_DMA | (pfifo->channels - 1));
203 return 0;
204}
205
206static void
207nv40_fifo_init_reset(struct drm_device *dev)
208{
209 int i;
210
211 nv_wr32(dev, NV03_PMC_ENABLE,
212 nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PFIFO);
213 nv_wr32(dev, NV03_PMC_ENABLE,
214 nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO);
215
216 nv_wr32(dev, 0x003224, 0x000f0078);
217 nv_wr32(dev, 0x003210, 0x00000000);
218 nv_wr32(dev, 0x003270, 0x00000000);
219 nv_wr32(dev, 0x003240, 0x00000000);
220 nv_wr32(dev, 0x003244, 0x00000000);
221 nv_wr32(dev, 0x003258, 0x00000000);
222 nv_wr32(dev, 0x002504, 0x00000000);
223 for (i = 0; i < 16; i++)
224 nv_wr32(dev, 0x002510 + (i * 4), 0x00000000);
225 nv_wr32(dev, 0x00250c, 0x0000ffff);
226 nv_wr32(dev, 0x002048, 0x00000000);
227 nv_wr32(dev, 0x003228, 0x00000000);
228 nv_wr32(dev, 0x0032e8, 0x00000000);
229 nv_wr32(dev, 0x002410, 0x00000000);
230 nv_wr32(dev, 0x002420, 0x00000000);
231 nv_wr32(dev, 0x002058, 0x00000001);
232 nv_wr32(dev, 0x00221c, 0x00000000);
233 /* something with 0x2084, read/modify/write, no change */
234 nv_wr32(dev, 0x002040, 0x000000ff);
235 nv_wr32(dev, 0x002500, 0x00000000);
236 nv_wr32(dev, 0x003200, 0x00000000);
237
238 nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x2101ffff);
239}
240
241static void
242nv40_fifo_init_ramxx(struct drm_device *dev)
243{
244 struct drm_nouveau_private *dev_priv = dev->dev_private;
245
246 nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
247 ((dev_priv->ramht_bits - 9) << 16) |
248 (dev_priv->ramht_offset >> 8));
249 nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
250
251 switch (dev_priv->chipset) {
252 case 0x47:
253 case 0x49:
254 case 0x4b:
255 nv_wr32(dev, 0x2230, 1);
256 break;
257 default:
258 break;
259 }
260
261 switch (dev_priv->chipset) {
262 case 0x40:
263 case 0x41:
264 case 0x42:
265 case 0x43:
266 case 0x45:
267 case 0x47:
268 case 0x48:
269 case 0x49:
270 case 0x4b:
271 nv_wr32(dev, NV40_PFIFO_RAMFC, 0x30002);
272 break;
273 default:
274 nv_wr32(dev, 0x2230, 0);
275 nv_wr32(dev, NV40_PFIFO_RAMFC,
276 ((nouveau_mem_fb_amount(dev) - 512 * 1024 +
277 dev_priv->ramfc_offset) >> 16) | (3 << 16));
278 break;
279 }
280}
281
282static void
283nv40_fifo_init_intr(struct drm_device *dev)
284{
285 nv_wr32(dev, 0x002100, 0xffffffff);
286 nv_wr32(dev, 0x002140, 0xffffffff);
287}
288
289int
290nv40_fifo_init(struct drm_device *dev)
291{
292 struct drm_nouveau_private *dev_priv = dev->dev_private;
293 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
294 int i;
295
296 nv40_fifo_init_reset(dev);
297 nv40_fifo_init_ramxx(dev);
298
299 nv40_fifo_do_load_context(dev, pfifo->channels - 1);
300 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
301
302 nv40_fifo_init_intr(dev);
303 pfifo->enable(dev);
304 pfifo->reassign(dev, true);
305
306 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
307 if (dev_priv->fifos[i]) {
308 uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
309 nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
310 }
311 }
312
313 return 0;
314}