/* * Based on nv40_graph.c * Someday this will all go away... */ #include "drmP.h" #include "drm.h" #include "nouveau_drv.h" #include "nouveau_drm.h" /* * This is obviously not the correct size. */ #define NV30_GRCTX_SIZE (23840) /*TODO: deciper what each offset in the context represents. The below * contexts are taken from dumps just after the 3D object is * created. */ static void nv30_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) { struct drm_nouveau_private *dev_priv = dev->dev_private; int i; INSTANCE_WR(ctx, 0x28/4, 0x10000000); INSTANCE_WR(ctx, 0x40c/4, 0x00000101); INSTANCE_WR(ctx, 0x420/4, 0x00000111); INSTANCE_WR(ctx, 0x424/4, 0x00000060); INSTANCE_WR(ctx, 0x440/4, 0x00000080); INSTANCE_WR(ctx, 0x444/4, 0xffff0000); INSTANCE_WR(ctx, 0x448/4, 0x00000001); INSTANCE_WR(ctx, 0x45c/4, 0x44400000); INSTANCE_WR(ctx, 0x448/4, 0xffff0000); INSTANCE_WR(ctx, 0x4dc/4, 0xfff00000); INSTANCE_WR(ctx, 0x4e0/4, 0xfff00000); INSTANCE_WR(ctx, 0x4e8/4, 0x00011100); for (i = 0x504; i <= 0x540; i += 4) INSTANCE_WR(ctx, i/4, 0x7ff00000); INSTANCE_WR(ctx, 0x54c/4, 0x4b7fffff); INSTANCE_WR(ctx, 0x588/4, 0x00000080); INSTANCE_WR(ctx, 0x58c/4, 0x30201000); INSTANCE_WR(ctx, 0x590/4, 0x70605040); INSTANCE_WR(ctx, 0x594/4, 0xb8a89888); INSTANCE_WR(ctx, 0x598/4, 0xf8e8d8c8); INSTANCE_WR(ctx, 0x5ac/4, 0xb0000000); for (i = 0x604; i <= 0x640; i += 4) INSTANCE_WR(ctx, i/4, 0x00010588); for (i = 0x644; i <= 0x680; i += 4) INSTANCE_WR(ctx, i/4, 0x00030303); for (i = 0x6c4; i <= 0x700; i += 4) INSTANCE_WR(ctx, i/4, 0x0008aae4); for (i = 0x704; i <= 0x740; i += 4) INSTANCE_WR(ctx, i/4, 0x1012000); for (i = 0x744; i <= 0x780; i += 4) INSTANCE_WR(ctx, i/4, 0x0080008); INSTANCE_WR(ctx, 0x860/4, 0x00040000); INSTANCE_WR(ctx, 0x864/4, 0x00010000); INSTANCE_WR(ctx, 0x868/4, 0x00040000); INSTANCE_WR(ctx, 0x86c/4, 0x00040000); INSTANCE_WR(ctx, 0x870/4, 0x00040000); INSTANCE_WR(ctx, 0x874/4, 0x00040000); for (i = 0x00; i <= 0x1170; i += 0x10) { INSTANCE_WR(ctx, (0x1f24 + i)/4, 0x000c001b); INSTANCE_WR(ctx, (0x1f20 + i)/4, 0x0436086c); INSTANCE_WR(ctx, (0x1f1c + i)/4, 0x10700ff9); } INSTANCE_WR(ctx, 0x30bc/4, 0x0000ffff); INSTANCE_WR(ctx, 0x30c0/4, 0x0000ffff); INSTANCE_WR(ctx, 0x30c4/4, 0x0000ffff); INSTANCE_WR(ctx, 0x30c8/4, 0x0000ffff); INSTANCE_WR(ctx, 0x380c/4, 0x3f800000); INSTANCE_WR(ctx, 0x3450/4, 0x3f800000); INSTANCE_WR(ctx, 0x3820/4, 0x3f800000); INSTANCE_WR(ctx, 0x3854/4, 0x3f800000); INSTANCE_WR(ctx, 0x3850/4, 0x3f000000); INSTANCE_WR(ctx, 0x384c/4, 0x40000000); INSTANCE_WR(ctx, 0x3868/4, 0xbf800000); INSTANCE_WR(ctx, 0x3860/4, 0x3f800000); INSTANCE_WR(ctx, 0x386c/4, 0x40000000); INSTANCE_WR(ctx, 0x3870/4, 0xbf800000); for (i = 0x4e0; i <= 0x4e1c; i += 4) INSTANCE_WR(ctx, i/4, 0x001c527d); INSTANCE_WR(ctx, 0x4e40, 0x001c527c); INSTANCE_WR(ctx, 0x5680/4, 0x000a0000); INSTANCE_WR(ctx, 0x87c/4, 0x10000000); INSTANCE_WR(ctx, 0x28/4, 0x10000011); } int nv30_graph_create_context(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); unsigned int ctx_size; int ret; switch (dev_priv->chipset) { default: ctx_size = NV30_GRCTX_SIZE; ctx_init = nv30_graph_context_init; break; } if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx))) return ret; /* Initialise default context values */ ctx_init(dev, chan->ramin_grctx->gpuobj); INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */ INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, chan->ramin_grctx->instance >> 4); return 0; } void nv30_graph_destroy_context(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0); } static int nouveau_graph_wait_idle(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; int tv = 1000; while (tv--) { if (NV_READ(0x400700) == 0) break; } if (NV_READ(0x400700)) { DRM_ERROR("timeout!\n"); return DRM_ERR(EBUSY); } return 0; } int nv30_graph_load_context(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) return DRM_ERR(EINVAL); inst = chan->ramin_grctx->instance >> 4; NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD); return nouveau_graph_wait_idle(dev); } int nv30_graph_save_context(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) return DRM_ERR(EINVAL); inst = chan->ramin_grctx->instance >> 4; NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE); return nouveau_graph_wait_idle(dev); } int nv30_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; uint32_t vramsz, tmp; int ret, i; NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); /* Create Context Pointer Table */ dev_priv->ctx_table_size = 32 * 4; if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, dev_priv->ctx_table_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ctx_table))) return ret; NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, dev_priv->ctx_table->instance >> 4); NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0x00000000); NV_WRITE(NV04_PGRAPH_DEBUG_1, 0x401287c0); NV_WRITE(0x400890, 0x00140000); NV_WRITE(NV04_PGRAPH_DEBUG_3, 0xf0de0475); NV_WRITE(NV10_PGRAPH_DEBUG_4, 0x10008000); NV_WRITE(NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04b1f36); NV_WRITE(0x400B80, 0x1003d888); NV_WRITE(0x400B84, 0x0c000000); NV_WRITE(0x400B88, 0x62ff0f7f); NV_WRITE(0x400098, 0x000000c0); NV_WRITE(0x40009C, 0x0005dc00); NV_WRITE(NV04_PGRAPH_DEBUG_2, 0x62ff0f7f); NV_WRITE(0x4000a0, 0x00000000); NV_WRITE(0x4000a4, 0x00000008); /* copy tile info from PFB */ for (i=0; i