aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv04_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/nv04_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/nv04_fifo.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
new file mode 100644
index 000000000000..0c3cd53c7313
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -0,0 +1,271 @@
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 "drm.h"
29#include "nouveau_drv.h"
30
31#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
32#define NV04_RAMFC__SIZE 32
33#define NV04_RAMFC_DMA_PUT 0x00
34#define NV04_RAMFC_DMA_GET 0x04
35#define NV04_RAMFC_DMA_INSTANCE 0x08
36#define NV04_RAMFC_DMA_STATE 0x0C
37#define NV04_RAMFC_DMA_FETCH 0x10
38#define NV04_RAMFC_ENGINE 0x14
39#define NV04_RAMFC_PULL1_ENGINE 0x18
40
41#define RAMFC_WR(offset, val) nv_wo32(dev, chan->ramfc->gpuobj, \
42 NV04_RAMFC_##offset/4, (val))
43#define RAMFC_RD(offset) nv_ro32(dev, chan->ramfc->gpuobj, \
44 NV04_RAMFC_##offset/4)
45
46void
47nv04_fifo_disable(struct drm_device *dev)
48{
49 uint32_t tmp;
50
51 tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH);
52 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, tmp & ~1);
53 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
54 tmp = nv_rd32(dev, NV03_PFIFO_CACHE1_PULL1);
55 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, tmp & ~1);
56}
57
58void
59nv04_fifo_enable(struct drm_device *dev)
60{
61 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
62 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
63}
64
65bool
66nv04_fifo_reassign(struct drm_device *dev, bool enable)
67{
68 uint32_t reassign = nv_rd32(dev, NV03_PFIFO_CACHES);
69
70 nv_wr32(dev, NV03_PFIFO_CACHES, enable ? 1 : 0);
71 return (reassign == 1);
72}
73
74int
75nv04_fifo_channel_id(struct drm_device *dev)
76{
77 return nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
78 NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
79}
80
81int
82nv04_fifo_create_context(struct nouveau_channel *chan)
83{
84 struct drm_device *dev = chan->dev;
85 struct drm_nouveau_private *dev_priv = dev->dev_private;
86 int ret;
87
88 ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0,
89 NV04_RAMFC__SIZE,
90 NVOBJ_FLAG_ZERO_ALLOC |
91 NVOBJ_FLAG_ZERO_FREE,
92 NULL, &chan->ramfc);
93 if (ret)
94 return ret;
95
96 /* Setup initial state */
97 dev_priv->engine.instmem.prepare_access(dev, true);
98 RAMFC_WR(DMA_PUT, chan->pushbuf_base);
99 RAMFC_WR(DMA_GET, chan->pushbuf_base);
100 RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
101 RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
102 NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
103 NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
104#ifdef __BIG_ENDIAN
105 NV_PFIFO_CACHE1_BIG_ENDIAN |
106#endif
107 0));
108 dev_priv->engine.instmem.finish_access(dev);
109
110 /* enable the fifo dma operation */
111 nv_wr32(dev, NV04_PFIFO_MODE,
112 nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
113 return 0;
114}
115
116void
117nv04_fifo_destroy_context(struct nouveau_channel *chan)
118{
119 struct drm_device *dev = chan->dev;
120
121 nv_wr32(dev, NV04_PFIFO_MODE,
122 nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
123
124 nouveau_gpuobj_ref_del(dev, &chan->ramfc);
125}
126
127static void
128nv04_fifo_do_load_context(struct drm_device *dev, int chid)
129{
130 struct drm_nouveau_private *dev_priv = dev->dev_private;
131 uint32_t fc = NV04_RAMFC(chid), tmp;
132
133 dev_priv->engine.instmem.prepare_access(dev, false);
134
135 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
136 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
137 tmp = nv_ri32(dev, fc + 8);
138 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF);
139 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT, tmp >> 16);
140 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, nv_ri32(dev, fc + 12));
141 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_FETCH, nv_ri32(dev, fc + 16));
142 nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
143 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
144
145 dev_priv->engine.instmem.finish_access(dev);
146
147 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
148 nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
149}
150
151int
152nv04_fifo_load_context(struct nouveau_channel *chan)
153{
154 uint32_t tmp;
155
156 nv_wr32(chan->dev, NV03_PFIFO_CACHE1_PUSH1,
157 NV03_PFIFO_CACHE1_PUSH1_DMA | chan->id);
158 nv04_fifo_do_load_context(chan->dev, chan->id);
159 nv_wr32(chan->dev, NV04_PFIFO_CACHE1_DMA_PUSH, 1);
160
161 /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */
162 tmp = nv_rd32(chan->dev, NV04_PFIFO_CACHE1_DMA_CTL) & ~(1 << 31);
163 nv_wr32(chan->dev, NV04_PFIFO_CACHE1_DMA_CTL, tmp);
164
165 return 0;
166}
167
168int
169nv04_fifo_unload_context(struct drm_device *dev)
170{
171 struct drm_nouveau_private *dev_priv = dev->dev_private;
172 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
173 struct nouveau_channel *chan = NULL;
174 uint32_t tmp;
175 int chid;
176
177 chid = pfifo->channel_id(dev);
178 if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
179 return 0;
180
181 chan = dev_priv->fifos[chid];
182 if (!chan) {
183 NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid);
184 return -EINVAL;
185 }
186
187 dev_priv->engine.instmem.prepare_access(dev, true);
188 RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
189 RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
190 tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
191 tmp |= nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE);
192 RAMFC_WR(DMA_INSTANCE, tmp);
193 RAMFC_WR(DMA_STATE, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_STATE));
194 RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
195 RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
196 RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
197 dev_priv->engine.instmem.finish_access(dev);
198
199 nv04_fifo_do_load_context(dev, pfifo->channels - 1);
200 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
201 return 0;
202}
203
204static void
205nv04_fifo_init_reset(struct drm_device *dev)
206{
207 nv_wr32(dev, NV03_PMC_ENABLE,
208 nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PFIFO);
209 nv_wr32(dev, NV03_PMC_ENABLE,
210 nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO);
211
212 nv_wr32(dev, 0x003224, 0x000f0078);
213 nv_wr32(dev, 0x002044, 0x0101ffff);
214 nv_wr32(dev, 0x002040, 0x000000ff);
215 nv_wr32(dev, 0x002500, 0x00000000);
216 nv_wr32(dev, 0x003000, 0x00000000);
217 nv_wr32(dev, 0x003050, 0x00000000);
218 nv_wr32(dev, 0x003200, 0x00000000);
219 nv_wr32(dev, 0x003250, 0x00000000);
220 nv_wr32(dev, 0x003220, 0x00000000);
221
222 nv_wr32(dev, 0x003250, 0x00000000);
223 nv_wr32(dev, 0x003270, 0x00000000);
224 nv_wr32(dev, 0x003210, 0x00000000);
225}
226
227static void
228nv04_fifo_init_ramxx(struct drm_device *dev)
229{
230 struct drm_nouveau_private *dev_priv = dev->dev_private;
231
232 nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
233 ((dev_priv->ramht_bits - 9) << 16) |
234 (dev_priv->ramht_offset >> 8));
235 nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
236 nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
237}
238
239static void
240nv04_fifo_init_intr(struct drm_device *dev)
241{
242 nv_wr32(dev, 0x002100, 0xffffffff);
243 nv_wr32(dev, 0x002140, 0xffffffff);
244}
245
246int
247nv04_fifo_init(struct drm_device *dev)
248{
249 struct drm_nouveau_private *dev_priv = dev->dev_private;
250 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
251 int i;
252
253 nv04_fifo_init_reset(dev);
254 nv04_fifo_init_ramxx(dev);
255
256 nv04_fifo_do_load_context(dev, pfifo->channels - 1);
257 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
258
259 nv04_fifo_init_intr(dev);
260 pfifo->enable(dev);
261
262 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
263 if (dev_priv->fifos[i]) {
264 uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
265 nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
266 }
267 }
268
269 return 0;
270}
271