aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv40_graph.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-15 07:02:47 -0500
committerBen Skeggs <bskeggs@redhat.com>2009-12-16 02:05:39 -0500
commit054b93e444550a72aef17115363cdef253b9ee7c (patch)
tree667d10b686c62d64e0b998115209c65884bcc6de /drivers/gpu/drm/nouveau/nv40_graph.c
parent15bee69ee1532a29e13124b298027ee6ef54bac8 (diff)
drm/nv40: implement ctxprog/state generation
The context programs are *very* simple compared to the ones used by the binary driver. There's notes in nv40_grctx.c explaining most of the things we don't implement. If we discover if/why any of it is required further down the track, we'll handle it then. The PGRAPH state generated for each chipset should match what NVIDIA do almost exactly (there's a couple of exceptions). If someone has a lot of time on their hands, they could figure out the mapping of object/method to PGRAPH register and demagic the initial state a little, it's not terribly important however. At time of commit, confirmed to be working at least well enough for accelerated X (and where tested, for 3D apps) on NV40, NV43, NV44, NV46, NV49, NV4A, NV4B and NV4E. A module option has been added to force the use of external firmware blobs if it becomes required. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv40_graph.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c212
1 files changed, 38 insertions, 174 deletions
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 7e8547cb5833..2b332bb55acf 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -24,36 +24,10 @@
24 * 24 *
25 */ 25 */
26 26
27#include <linux/firmware.h>
28
29#include "drmP.h" 27#include "drmP.h"
30#include "drm.h" 28#include "drm.h"
31#include "nouveau_drv.h" 29#include "nouveau_drv.h"
32 30#include "nouveau_grctx.h"
33MODULE_FIRMWARE("nouveau/nv40.ctxprog");
34MODULE_FIRMWARE("nouveau/nv40.ctxvals");
35MODULE_FIRMWARE("nouveau/nv41.ctxprog");
36MODULE_FIRMWARE("nouveau/nv41.ctxvals");
37MODULE_FIRMWARE("nouveau/nv42.ctxprog");
38MODULE_FIRMWARE("nouveau/nv42.ctxvals");
39MODULE_FIRMWARE("nouveau/nv43.ctxprog");
40MODULE_FIRMWARE("nouveau/nv43.ctxvals");
41MODULE_FIRMWARE("nouveau/nv44.ctxprog");
42MODULE_FIRMWARE("nouveau/nv44.ctxvals");
43MODULE_FIRMWARE("nouveau/nv46.ctxprog");
44MODULE_FIRMWARE("nouveau/nv46.ctxvals");
45MODULE_FIRMWARE("nouveau/nv47.ctxprog");
46MODULE_FIRMWARE("nouveau/nv47.ctxvals");
47MODULE_FIRMWARE("nouveau/nv49.ctxprog");
48MODULE_FIRMWARE("nouveau/nv49.ctxvals");
49MODULE_FIRMWARE("nouveau/nv4a.ctxprog");
50MODULE_FIRMWARE("nouveau/nv4a.ctxvals");
51MODULE_FIRMWARE("nouveau/nv4b.ctxprog");
52MODULE_FIRMWARE("nouveau/nv4b.ctxvals");
53MODULE_FIRMWARE("nouveau/nv4c.ctxprog");
54MODULE_FIRMWARE("nouveau/nv4c.ctxvals");
55MODULE_FIRMWARE("nouveau/nv4e.ctxprog");
56MODULE_FIRMWARE("nouveau/nv4e.ctxvals");
57 31
58struct nouveau_channel * 32struct nouveau_channel *
59nv40_graph_channel(struct drm_device *dev) 33nv40_graph_channel(struct drm_device *dev)
@@ -83,27 +57,30 @@ nv40_graph_create_context(struct nouveau_channel *chan)
83{ 57{
84 struct drm_device *dev = chan->dev; 58 struct drm_device *dev = chan->dev;
85 struct drm_nouveau_private *dev_priv = dev->dev_private; 59 struct drm_nouveau_private *dev_priv = dev->dev_private;
86 struct nouveau_gpuobj *ctx; 60 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
87 int ret; 61 int ret;
88 62
89 /* Allocate a 175KiB block of PRAMIN to store the context. This 63 ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
90 * is massive overkill for a lot of chipsets, but it should be safe 64 16, NVOBJ_FLAG_ZERO_ALLOC,
91 * until we're able to implement this properly (will happen at more 65 &chan->ramin_grctx);
92 * or less the same time we're able to write our own context programs.
93 */
94 ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 175*1024, 16,
95 NVOBJ_FLAG_ZERO_ALLOC,
96 &chan->ramin_grctx);
97 if (ret) 66 if (ret)
98 return ret; 67 return ret;
99 ctx = chan->ramin_grctx->gpuobj;
100 68
101 /* Initialise default context values */ 69 /* Initialise default context values */
102 dev_priv->engine.instmem.prepare_access(dev, true); 70 dev_priv->engine.instmem.prepare_access(dev, true);
103 nv40_grctx_vals_load(dev, ctx); 71 if (!pgraph->ctxprog) {
104 nv_wo32(dev, ctx, 0, ctx->im_pramin->start); 72 struct nouveau_grctx ctx = {};
105 dev_priv->engine.instmem.finish_access(dev);
106 73
74 ctx.dev = chan->dev;
75 ctx.mode = NOUVEAU_GRCTX_VALS;
76 ctx.data = chan->ramin_grctx->gpuobj;
77 nv40_grctx_init(&ctx);
78 } else {
79 nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
80 }
81 nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
82 chan->ramin_grctx->gpuobj->im_pramin->start);
83 dev_priv->engine.instmem.finish_access(dev);
107 return 0; 84 return 0;
108} 85}
109 86
@@ -204,139 +181,6 @@ nv40_graph_unload_context(struct drm_device *dev)
204 return ret; 181 return ret;
205} 182}
206 183
207struct nouveau_ctxprog {
208 uint32_t signature;
209 uint8_t version;
210 uint16_t length;
211 uint32_t data[];
212} __attribute__ ((packed));
213
214struct nouveau_ctxvals {
215 uint32_t signature;
216 uint8_t version;
217 uint32_t length;
218 struct {
219 uint32_t offset;
220 uint32_t value;
221 } data[];
222} __attribute__ ((packed));
223
224int
225nv40_grctx_init(struct drm_device *dev)
226{
227 struct drm_nouveau_private *dev_priv = dev->dev_private;
228 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
229 const int chipset = dev_priv->chipset;
230 const struct firmware *fw;
231 const struct nouveau_ctxprog *cp;
232 const struct nouveau_ctxvals *cv;
233 char name[32];
234 int ret, i;
235
236 pgraph->accel_blocked = true;
237
238 if (!pgraph->ctxprog) {
239 sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
240 ret = request_firmware(&fw, name, &dev->pdev->dev);
241 if (ret) {
242 NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
243 return ret;
244 }
245
246 pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL);
247 if (!pgraph->ctxprog) {
248 NV_ERROR(dev, "OOM copying ctxprog\n");
249 release_firmware(fw);
250 return -ENOMEM;
251 }
252 memcpy(pgraph->ctxprog, fw->data, fw->size);
253
254 cp = pgraph->ctxprog;
255 if (le32_to_cpu(cp->signature) != 0x5043564e ||
256 cp->version != 0 ||
257 le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
258 NV_ERROR(dev, "ctxprog invalid\n");
259 release_firmware(fw);
260 nv40_grctx_fini(dev);
261 return -EINVAL;
262 }
263 release_firmware(fw);
264 }
265
266 if (!pgraph->ctxvals) {
267 sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
268 ret = request_firmware(&fw, name, &dev->pdev->dev);
269 if (ret) {
270 NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
271 nv40_grctx_fini(dev);
272 return ret;
273 }
274
275 pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
276 if (!pgraph->ctxprog) {
277 NV_ERROR(dev, "OOM copying ctxprog\n");
278 release_firmware(fw);
279 nv40_grctx_fini(dev);
280 return -ENOMEM;
281 }
282 memcpy(pgraph->ctxvals, fw->data, fw->size);
283
284 cv = (void *)pgraph->ctxvals;
285 if (le32_to_cpu(cv->signature) != 0x5643564e ||
286 cv->version != 0 ||
287 le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
288 NV_ERROR(dev, "ctxvals invalid\n");
289 release_firmware(fw);
290 nv40_grctx_fini(dev);
291 return -EINVAL;
292 }
293 release_firmware(fw);
294 }
295
296 cp = pgraph->ctxprog;
297
298 nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
299 for (i = 0; i < le16_to_cpu(cp->length); i++)
300 nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
301 le32_to_cpu(cp->data[i]));
302
303 pgraph->accel_blocked = false;
304 return 0;
305}
306
307void
308nv40_grctx_fini(struct drm_device *dev)
309{
310 struct drm_nouveau_private *dev_priv = dev->dev_private;
311 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
312
313 if (pgraph->ctxprog) {
314 kfree(pgraph->ctxprog);
315 pgraph->ctxprog = NULL;
316 }
317
318 if (pgraph->ctxvals) {
319 kfree(pgraph->ctxprog);
320 pgraph->ctxvals = NULL;
321 }
322}
323
324void
325nv40_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
326{
327 struct drm_nouveau_private *dev_priv = dev->dev_private;
328 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
329 struct nouveau_ctxvals *cv = pgraph->ctxvals;
330 int i;
331
332 if (!cv)
333 return;
334
335 for (i = 0; i < le32_to_cpu(cv->length); i++)
336 nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
337 le32_to_cpu(cv->data[i].value));
338}
339
340/* 184/*
341 * G70 0x47 185 * G70 0x47
342 * G71 0x49 186 * G71 0x49
@@ -359,7 +203,26 @@ nv40_graph_init(struct drm_device *dev)
359 nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | 203 nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
360 NV_PMC_ENABLE_PGRAPH); 204 NV_PMC_ENABLE_PGRAPH);
361 205
362 nv40_grctx_init(dev); 206 if (nouveau_ctxfw) {
207 nouveau_grctx_prog_load(dev);
208 dev_priv->engine.graph.grctx_size = 175 * 1024;
209 }
210
211 if (!dev_priv->engine.graph.ctxprog) {
212 struct nouveau_grctx ctx = {};
213 uint32_t cp[256];
214
215 ctx.dev = dev;
216 ctx.mode = NOUVEAU_GRCTX_PROG;
217 ctx.data = cp;
218 ctx.ctxprog_max = 256;
219 nv40_grctx_init(&ctx);
220 dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
221
222 nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
223 for (i = 0; i < ctx.ctxprog_len; i++)
224 nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
225 }
363 226
364 /* No context present currently */ 227 /* No context present currently */
365 nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); 228 nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -539,6 +402,7 @@ nv40_graph_init(struct drm_device *dev)
539 402
540void nv40_graph_takedown(struct drm_device *dev) 403void nv40_graph_takedown(struct drm_device *dev)
541{ 404{
405 nouveau_grctx_fini(dev);
542} 406}
543 407
544struct nouveau_pgraph_object_class nv40_graph_grclass[] = { 408struct nouveau_pgraph_object_class nv40_graph_grclass[] = {