summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/nouveau_drm.h19
-rw-r--r--shared-core/nouveau_drv.h5
-rw-r--r--shared-core/nouveau_fifo.c308
-rw-r--r--shared-core/nouveau_irq.c122
-rw-r--r--shared-core/nouveau_reg.h83
-rw-r--r--shared-core/nouveau_state.c59
6 files changed, 412 insertions, 184 deletions
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 1180a135..ed87f5c4 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -25,7 +25,7 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
-typedef struct drm_nouveau_fifo_init {
+typedef struct drm_nouveau_fifo_alloc {
int channel;
uint32_t put_base;
/* FIFO control regs */
@@ -35,7 +35,7 @@ typedef struct drm_nouveau_fifo_init {
drm_handle_t cmdbuf;
int cmdbuf_size;
}
-drm_nouveau_fifo_init_t;
+drm_nouveau_fifo_alloc_t;
typedef struct drm_nouveau_object_init {
uint32_t handle;
@@ -122,14 +122,13 @@ typedef struct drm_nouveau_sarea {
}
drm_nouveau_sarea_t;
-#define DRM_NOUVEAU_FIFO_INIT 0x00
-#define DRM_NOUVEAU_PFIFO_REINIT 0x01
-#define DRM_NOUVEAU_OBJECT_INIT 0x02
-#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x03 // We don't want this eventually..
-#define DRM_NOUVEAU_MEM_ALLOC 0x04
-#define DRM_NOUVEAU_MEM_FREE 0x05
-#define DRM_NOUVEAU_GETPARAM 0x06
-#define DRM_NOUVEAU_SETPARAM 0x07
+#define DRM_NOUVEAU_FIFO_ALLOC 0x00
+#define DRM_NOUVEAU_OBJECT_INIT 0x01
+#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02 // We don't want this eventually..
+#define DRM_NOUVEAU_MEM_ALLOC 0x03
+#define DRM_NOUVEAU_MEM_FREE 0x04
+#define DRM_NOUVEAU_GETPARAM 0x05
+#define DRM_NOUVEAU_SETPARAM 0x06
#endif /* __NOUVEAU_DRM_H__ */
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index 7af9c618..007bdd6a 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -123,6 +123,9 @@ typedef struct drm_nouveau_private {
struct nouveau_fifo fifos[NV_MAX_FIFO_NUMBER];
struct nouveau_object_store objs;
+ /* RAMFC and RAMRO offsets */
+ uint32_t ramfc_offset;
+ uint32_t ramro_offset;
struct mem_block *agp_heap;
struct mem_block *fb_heap;
@@ -139,7 +142,7 @@ extern int nouveau_firstopen(struct drm_device *dev);
extern int nouveau_unload(struct drm_device *dev);
extern int nouveau_ioctl_getparam(DRM_IOCTL_ARGS);
extern int nouveau_ioctl_setparam(DRM_IOCTL_ARGS);
-extern int nouveau_dma_init(struct drm_device *dev);
+extern void nouveau_wait_for_idle(struct drm_device *dev);
/* nouveau_mem.c */
extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev);
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index ca7ddef6..de23f96d 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -44,23 +44,6 @@ int nouveau_fifo_number(drm_device_t* dev)
}
}
-/* setup the fifo enable register */
-static void nouveau_fifo_enable(drm_device_t* dev)
-{
- int i;
- unsigned enable_val=0;
- drm_nouveau_private_t *dev_priv = dev->dev_private;
-
- for(i=31;i>=0;i--)
- {
- enable_val<<=1;
- if (dev_priv->fifos[i].used)
- enable_val|=1;
- }
- DRM_DEBUG("enable_val=0x%08x\n", enable_val);
- NV_WRITE(NV03_FIFO_ENABLE,enable_val);
-}
-
/***********************************
* functions doing the actual work
***********************************/
@@ -70,12 +53,141 @@ static void nouveau_fifo_enable(drm_device_t* dev)
* voir nv_driver.c : NVPreInit
*/
-/* initializes a fifo */
-static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DRMFILE filp)
+static void nouveau_fifo_init(drm_device_t* dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ /* Init PFIFO - This is an exact copy of what's done in the Xorg ddx so far.
+ * We should be able to figure out what's happening from the
+ * resources available..
+ */
+
+ if (dev->irq_enabled)
+ nouveau_irq_postinstall(dev);
+
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PGRAPH_NV40_UNK220, dev_priv->fb_obj->instance >> 4);
+
+ DRM_DEBUG("%s: setting FIFO %d active\n", __func__, dev_priv->cur_fifo);
+
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+ NV_WRITE(NV_PFIFO_MODE, 0x00000000);
+
+ NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000000);
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
+ else
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
+ NV_WRITE(NV_PFIFO_CACH1_DMAP, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
+ NV_WRITE(NV_PFIFO_CACH1_DMAG, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
+ NV_WRITE(NV_PFIFO_CACH1_DMAI, dev_priv->cmdbuf_obj->instance >> 4);
+ NV_WRITE(NV_PFIFO_CACH0_PSH0, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH0_PUL0, 0x00000000);
+ NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF);
+ NV_WRITE(NV_PFIFO_CACH1_HASH, 0x0000FFFF);
+ NV_WRITE(NV_PFIFO_RAMHT,
+ (0x03 << 24) /* search 128 */ |
+ ((dev_priv->objs.ht_bits - 9) << 16) |
+ (dev_priv->objs.ht_base >> 8)
+ );
+ dev_priv->ramfc_offset=0x11000;
+ dev_priv->ramro_offset=0x11200;
+ NV_WRITE(NV_PFIFO_RAMFC, dev_priv->ramfc_offset>>8); /* RAMIN+0x11000 0.5k */
+ NV_WRITE(NV_PFIFO_RAMRO, dev_priv->ramro_offset>>8); /* RAMIN+0x11200 0.5k */
+ NV_WRITE(NV_PFIFO_CACH0_PUL1, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_DMAC, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_DMAS, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_ENG, 0x00000000);
+#ifdef __BIG_ENDIAN
+ NV_WRITE(NV_PFIFO_CACH1_DMAF, NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4|NV_PFIFO_CACH1_BIG_ENDIAN);
+#else
+ NV_WRITE(NV_PFIFO_CACH1_DMAF, NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4);
+#endif
+ NV_WRITE(NV_PFIFO_CACH1_DMAPSH, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000001);
+
+ NV_WRITE(NV_PGRAPH_CTX_USER, 0x0);
+ NV_WRITE(NV_PGRAPH_CTX_SWITCH1, 0x19);
+ NV_WRITE(NV_PFIFO_DELAY_0, 0xff /* retrycount*/ );
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x00002001);
+ else
+ NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x10110000);
+
+ NV_WRITE(NV_PFIFO_DMA_TIMESLICE, 0x001fffff);
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+
+ DRM_DEBUG("%s: CACHE1 GET/PUT readback %d/%d\n", __func__,
+ NV_READ(NV_PFIFO_CACH1_DMAG),
+ NV_READ(NV_PFIFO_CACH1_DMAP));
+
+ DRM_INFO("%s: OK\n", __func__);
+}
+
+static int nouveau_dma_init(struct drm_device *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_config *config = &dev_priv->config;
+ struct mem_block *cb;
+ int cb_min_size = nouveau_fifo_number(dev) * NV03_FIFO_SIZE;
+
+ /* XXX this should be done earlier on init */
+ nouveau_hash_table_init(dev);
+
+ if (dev_priv->card_type >= NV_40)
+ dev_priv->fb_obj = nouveau_dma_object_create(dev,
+ 0, nouveau_mem_fb_amount(dev),
+ NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM);
+
+ /* Defaults for unconfigured values */
+ if (!config->cmdbuf.location)
+ config->cmdbuf.location = NOUVEAU_MEM_FB;
+ if (!config->cmdbuf.size || config->cmdbuf.size < cb_min_size)
+ config->cmdbuf.size = cb_min_size;
+
+ cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
+ config->cmdbuf.location, (DRMFILE)-2);
+ /* Try defaults if that didn't succeed */
+ if (!cb) {
+ config->cmdbuf.location = NOUVEAU_MEM_FB;
+ config->cmdbuf.size = cb_min_size;
+ cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
+ config->cmdbuf.location, (DRMFILE)-2);
+ }
+ if (!cb) {
+ DRM_ERROR("Couldn't allocate DMA command buffer.\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ if (config->cmdbuf.location == NOUVEAU_MEM_AGP)
+ dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
+ cb->start, cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP);
+ else
+ dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
+ cb->start - drm_get_resource_start(dev, 1),
+ cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
+ dev_priv->cmdbuf_ch_size = (uint32_t)cb->size / nouveau_fifo_number(dev);
+ dev_priv->cmdbuf_alloc = cb;
+
+ nouveau_fifo_init(dev);
+ DRM_INFO("DMA command buffer is %dKiB at 0x%08x(%s)\n",
+ (uint32_t)cb->size>>10, (uint32_t)cb->start,
+ config->cmdbuf.location == NOUVEAU_MEM_FB ? "VRAM" : "AGP");
+ DRM_INFO("FIFO size is %dKiB\n", dev_priv->cmdbuf_ch_size>>10);
+
+ return 0;
+}
+
+/* allocates and initializes a fifo for user space consumption */
+static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init, DRMFILE filp)
{
int i;
int ret;
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t ctx_addr;
/* Init cmdbuf on first FIFO init, this is delayed until now to
* give the ddx a chance to configure the cmdbuf with SETPARAM
@@ -90,18 +202,15 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
* Alright, here is the full story
* Nvidia cards have multiple hw fifo contexts (praise them for that,
* no complicated crash-prone context switches)
- * X always uses context 0 (0x00800000)
* We allocate a new context for each app and let it write to it directly
* (woo, full userspace command submission !)
* When there are no more contexts, you lost
*/
for(i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].used==0)
- {
- dev_priv->fifos[i].used=1;
break;
- }
+ DRM_INFO("Allocating FIFO number %d\n", i);
/* no more fifos. you lost. */
if (i==nouveau_fifo_number(dev))
return DRM_ERR(EINVAL);
@@ -110,16 +219,49 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
dev_priv->fifos[i].used=1;
dev_priv->fifos[i].filp=filp;
- /* enable the fifo */
- nouveau_fifo_enable(dev);
+ nouveau_wait_for_idle(dev);
+
+ /* disable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+
+ // FIXME i*32 is true on nv04, what is it on >=nv10 ?
+ ctx_addr=NV_RAMIN+dev_priv->ramfc_offset+i*32;
+
+ // clear the first 2 RAMFC entries
+ // FIXME try to fill GET/PUT and see what that changes
+ NV_WRITE(ctx_addr,0x0);
+ NV_WRITE(ctx_addr+4,0x0);
+
+ // FIXME that's what is done in nvosdk, but that part of the code is buggy so...
+ // RAMFC + 8 = instoffset
+ NV_WRITE(ctx_addr+8,dev_priv->cmdbuf_obj->instance >> 4);
+
+ // RAMFC + 16 = defaultFetch
+ NV_WRITE(ctx_addr+16,NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4);
+
+ /* enable the fifo dma operation */
+ NV_WRITE(NV_PFIFO_MODE,NV_READ(NV_PFIFO_MODE)|(1<<i));
+
+ // FIXME check if we need to refill the time quota with something like NV_WRITE(0x204C, 0x0003FFFF);
+
+ dev_priv->cur_fifo=i;
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
+ else
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
- /* make the fifo available to user space */
init->channel = i;
init->put_base = i*dev_priv->cmdbuf_ch_size;
NV_WRITE(NV03_FIFO_REGS_DMAPUT(i), init->put_base);
NV_WRITE(NV03_FIFO_REGS_DMAGET(i), init->put_base);
+ NV_WRITE(NV_PFIFO_CACH1_DMAP, init->put_base);
+ NV_WRITE(NV_PFIFO_CACH1_DMAG, init->put_base);
+ /* reenable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+
+ /* make the fifo available to user space */
/* first, the fifo control regs */
init->ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(i);
init->ctrl_size = NV03_FIFO_REGS_SIZE;
@@ -140,14 +282,29 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
/* FIFO has no objects yet */
dev_priv->fifos[i].objs = NULL;
- DRM_DEBUG("%s: initialised FIFO %d\n", __func__, i);
- dev_priv->cur_fifo = i;
+ DRM_INFO("%s: initialised FIFO %d\n", __func__, i);
return 0;
}
-static void nouveau_pfifo_init(drm_device_t* dev);
+
+/* stops a fifo */
+void nouveau_fifo_free(drm_device_t* dev,int n)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ dev_priv->fifos[n].used=0;
+ DRM_DEBUG("%s: freeing fifo %d\n", __func__, n);
+
+ /* disable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+
+ NV_WRITE(NV_PFIFO_MODE,NV_READ(NV_PFIFO_MODE)&~(1<<n));
+ // FIXME XXX needs more code
+
+ /* reenable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+}
/* cleanups all the fifos from filp */
-void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
+void nouveau_fifo_cleanup(drm_device_t* dev, DRMFILE filp)
{
int i;
drm_nouveau_private_t *dev_priv = dev->dev_private;
@@ -155,9 +312,10 @@ void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
DRM_DEBUG("clearing FIFO enables from filp\n");
for(i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].filp==filp)
- dev_priv->fifos[i].used=0;
+ nouveau_fifo_free(dev,i);
- if (dev_priv->cur_fifo == i) {
+ /* check we still point at an active channel */
+ if (dev_priv->fifos[dev_priv->cur_fifo].used == 0) {
DRM_DEBUG("%s: cur_fifo is no longer owned.\n", __func__);
for (i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].used) break;
@@ -167,9 +325,8 @@ void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
dev_priv->cur_fifo = i;
}
- if (dev_priv->cmdbuf_alloc)
- nouveau_pfifo_init(dev);
-// nouveau_fifo_enable(dev);
+/* if (dev_priv->cmdbuf_alloc)
+ nouveau_fifo_init(dev);*/
}
int nouveau_fifo_id_get(drm_device_t* dev, DRMFILE filp)
@@ -183,99 +340,30 @@ int nouveau_fifo_id_get(drm_device_t* dev, DRMFILE filp)
return -1;
}
-static void nouveau_pfifo_init(drm_device_t* dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
-
- /* Init PFIFO - This is an exact copy of what's done in the Xorg ddx so far.
- * We should be able to figure out what's happening from the
- * resources available..
- */
-
- if (dev->irq_enabled)
- nouveau_irq_postinstall(dev);
-
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV_PGRAPH_NV40_UNK220, dev_priv->fb_obj->instance >> 4);
-
- DRM_DEBUG("%s: setting FIFO %d active\n", __func__, dev_priv->cur_fifo);
-
- NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
- nouveau_fifo_enable(dev);
-
- NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000000);
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
- else
- NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
- NV_WRITE(NV_PFIFO_CACH1_DMAP, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
- NV_WRITE(NV_PFIFO_CACH1_DMAG, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
- NV_WRITE(NV_PFIFO_CACH1_DMAI, dev_priv->cmdbuf_obj->instance >> 4);
- NV_WRITE(NV_PFIFO_CACH0_PSH0, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH0_PUL0, 0x00000000);
- NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF);
- NV_WRITE(NV_PFIFO_CACH1_HASH, 0x0000FFFF);
- NV_WRITE(NV_PFIFO_RAMHT,
- (0x03 << 24) /* search 128 */ |
- ((dev_priv->objs.ht_bits - 9) << 16) |
- (dev_priv->objs.ht_base >> 8)
- );
- NV_WRITE(NV_PFIFO_RAMFC, 0x00000110); /* RAMIN+0x11000 0.5k */
- NV_WRITE(NV_PFIFO_RAMRO, 0x00000112); /* RAMIN+0x11200 0.5k */
- NV_WRITE(NV_PFIFO_CACH0_PUL1, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_DMAC, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH1_ENG, 0x00000000);
-#ifdef __BIG_ENDIAN
- NV_WRITE(NV_PFIFO_CACH1_DMAF, 0x800F0078);
-#else
- NV_WRITE(NV_PFIFO_CACH1_DMAF, 0x000F0078);
-#endif
- NV_WRITE(NV_PFIFO_CACH1_DMAS, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000001);
-
- NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
-
- DRM_DEBUG("%s: CACHE1 GET/PUT readback %d/%d\n", __func__,
- NV_READ(NV_PFIFO_CACH1_DMAG),
- NV_READ(NV_PFIFO_CACH1_DMAP));
-}
-
/***********************************
* ioctls wrapping the functions
***********************************/
-static int nouveau_ioctl_fifo_init(DRM_IOCTL_ARGS)
+static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_nouveau_fifo_init_t init;
+ drm_nouveau_fifo_alloc_t init;
int res;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_init_t __user *) data, sizeof(init));
+ DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, sizeof(init));
- res=nouveau_fifo_init(dev,&init,filp);
+ res=nouveau_fifo_alloc(dev,&init,filp);
if (!res)
- DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_init_t __user *)data, init, sizeof(init));
+ DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, init, sizeof(init));
return res;
}
-static int nouveau_ioctl_fifo_reinit(DRM_IOCTL_ARGS)
-{
- DRM_DEVICE;
-
- nouveau_pfifo_init(dev);
- return 0;
-}
-
/***********************************
* finally, the ioctl table
***********************************/
drm_ioctl_desc_t nouveau_ioctls[] = {
- [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_INIT)] = {nouveau_ioctl_fifo_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_NOUVEAU_PFIFO_REINIT)] = {nouveau_ioctl_fifo_reinit, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH},
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c
index 5088edac..9cd2c77f 100644
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@ -46,7 +46,10 @@ void nouveau_irq_preinstall(drm_device_t *dev)
NV_WRITE(NV_PFIFO_INTEN, 0);
NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF);
/* Disable/Clear PGRAPH interrupts */
- NV_WRITE(NV_PGRAPH_INTEN, 0);
+ if (dev_priv->card_type<NV_40)
+ NV_WRITE(NV04_PGRAPH_INTEN, 0);
+ else
+ NV_WRITE(NV40_PGRAPH_INTEN, 0);
NV_WRITE(NV_PGRAPH_INTSTAT, 0xFFFFFFFF);
#if 0
/* Disable/Clear CRTC0/1 interrupts */
@@ -70,9 +73,19 @@ void nouveau_irq_postinstall(drm_device_t *dev)
NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF);
/* Enable PGRAPH interrupts */
- NV_WRITE(NV_PGRAPH_INTEN,
+ if (dev_priv->card_type<NV_40)
+ NV_WRITE(NV04_PGRAPH_INTEN,
NV_PGRAPH_INTR_NOTIFY |
NV_PGRAPH_INTR_MISSING_HW |
+ NV_PGRAPH_INTR_CONTEXT_SWITCH |
+ NV_PGRAPH_INTR_BUFFER_NOTIFY |
+ NV_PGRAPH_INTR_ERROR
+ );
+ else
+ NV_WRITE(NV40_PGRAPH_INTEN,
+ NV_PGRAPH_INTR_NOTIFY |
+ NV_PGRAPH_INTR_MISSING_HW |
+ NV_PGRAPH_INTR_CONTEXT_SWITCH |
NV_PGRAPH_INTR_BUFFER_NOTIFY |
NV_PGRAPH_INTR_ERROR
);
@@ -97,7 +110,10 @@ void nouveau_irq_uninstall(drm_device_t *dev)
/* Disable PFIFO interrupts */
NV_WRITE(NV_PFIFO_INTEN, 0);
/* Disable PGRAPH interrupts */
- NV_WRITE(NV_PGRAPH_INTEN, 0);
+ if (dev_priv->card_type<NV_40)
+ NV_WRITE(NV04_PGRAPH_INTEN, 0);
+ else
+ NV_WRITE(NV40_PGRAPH_INTEN, 0);
#if 0
/* Disable CRTC0/1 interrupts */
NV_WRITE(NV_CRTC0_INTEN, 0);
@@ -107,15 +123,16 @@ void nouveau_irq_uninstall(drm_device_t *dev)
NV_WRITE(NV_PMC_INTEN, 0);
}
-void nouveau_fifo_irq_handler(drm_nouveau_private_t *dev_priv)
+static void nouveau_fifo_irq_handler(drm_device_t *dev)
{
uint32_t status, chmode, chstat;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
status = NV_READ(NV_PFIFO_INTSTAT);
if (!status)
return;
chmode = NV_READ(NV_PFIFO_MODE);
- chstat = NV_READ(0x2508);
+ chstat = NV_READ(NV_PFIFO_DMA);
DRM_DEBUG("NV: PFIFO interrupt! INTSTAT=0x%08x/MODE=0x%08x/PEND=0x%08x\n",
status, chmode, chstat);
@@ -136,9 +153,73 @@ void nouveau_fifo_irq_handler(drm_nouveau_private_t *dev_priv)
NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PFIFO_PENDING);
}
-void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv)
+static void nouveau_nv04_context_switch(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t channel,i;
+ uint32_t max=0;
+ NV_WRITE(NV_PGRAPH_FIFO,0x0);
+ channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1);
+ //DRM_INFO("raw PFIFO_CACH1_PHS1 reg is %x\n",NV_READ(NV_PFIFO_CACH1_PSH1));
+ //DRM_INFO("currently on channel %d\n",channel);
+ for (i=0;i<nouveau_fifo_number(dev);i++)
+ if ((dev_priv->fifos[i].used)&&(i!=channel)) {
+ uint32_t put,get,pending;
+ //put=NV_READ(dev_priv->ramfc_offset+i*32);
+ //get=NV_READ(dev_priv->ramfc_offset+4+i*32);
+ put=NV_READ(NV03_FIFO_REGS_DMAPUT(i));
+ get=NV_READ(NV03_FIFO_REGS_DMAGET(i));
+ pending=NV_READ(NV_PFIFO_DMA);
+ //DRM_INFO("Channel %d (put/get %x/%x)\n",i,put,get);
+ /* mark all pending channels as such */
+ if ((put!=get)&!(pending&(1<<i)))
+ {
+ pending|=(1<<i);
+ NV_WRITE(NV_PFIFO_DMA,pending);
+ }
+ max++;
+ }
+ nouveau_wait_for_idle(dev);
+
+#if 1
+ /* 2-channel commute */
+ // NV_WRITE(NV_PFIFO_CACH1_PSH1,channel|0x100);
+ if (channel==0)
+ channel=1;
+ else
+ channel=0;
+ // dev_priv->cur_fifo=channel;
+ NV_WRITE(0x2050,channel|0x100);
+#endif
+ //NV_WRITE(NV_PFIFO_CACH1_PSH1,max|0x100);
+ //NV_WRITE(0x2050,max|0x100);
+
+ NV_WRITE(NV_PGRAPH_FIFO,0x1);
+
+}
+
+static void nouveau_nv10_context_switch(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int channel;
+
+ channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1);
+ /* 2-channel commute */
+ if (channel==0)
+ channel=1;
+ else
+ channel=0;
+ dev_priv->cur_fifo=channel;
+
+ NV_WRITE(NV_PGRAPH_CTX_USER, (NV_READ(NV_PGRAPH_CTX_USER)&0xE0FFFFFF)|(dev_priv->cur_fifo<<24));
+ NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x10010100);
+ NV_WRITE(NV_PGRAPH_FFINTFC_ST2, NV_READ(NV_PGRAPH_FFINTFC_ST2)&0xCFFFFFFF);
+}
+
+static void nouveau_pgraph_irq_handler(drm_device_t *dev)
{
uint32_t status;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
status = NV_READ(NV_PGRAPH_INTSTAT);
if (!status)
@@ -190,6 +271,26 @@ void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv)
NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_ERROR);
}
+ if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ uint32_t channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1);
+ DRM_INFO("NV: PGRAPH context switch interrupt channel %x\n",channel);
+ switch(dev_priv->card_type)
+ {
+ case NV_04:
+ nouveau_nv04_context_switch(dev);
+ break;
+ case NV_10:
+ nouveau_nv10_context_switch(dev);
+ break;
+ default:
+ DRM_INFO("NV: Context switch not implemented\n");
+ break;
+ }
+
+ status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ }
+
if (status) {
DRM_INFO("NV: Unknown PGRAPH interrupt! STAT=0x%08x\n", status);
NV_WRITE(NV_PGRAPH_INTSTAT, status);
@@ -198,8 +299,9 @@ void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv)
NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PGRAPH_PENDING);
}
-void nouveau_crtc_irq_handler(drm_nouveau_private_t *dev_priv, int crtc)
+static void nouveau_crtc_irq_handler(drm_device_t *dev, int crtc)
{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
if (crtc&1) {
NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
}
@@ -220,15 +322,15 @@ irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS)
DRM_DEBUG("PMC INTSTAT: 0x%08x\n", status);
if (status & NV_PMC_INTSTAT_PFIFO_PENDING) {
- nouveau_fifo_irq_handler(dev_priv);
+ nouveau_fifo_irq_handler(dev);
status &= ~NV_PMC_INTSTAT_PFIFO_PENDING;
}
if (status & NV_PMC_INTSTAT_PGRAPH_PENDING) {
- nouveau_pgraph_irq_handler(dev_priv);
+ nouveau_pgraph_irq_handler(dev);
status &= ~NV_PMC_INTSTAT_PGRAPH_PENDING;
}
if (status & NV_PMC_INTSTAT_CRTCn_PENDING) {
- nouveau_crtc_irq_handler(dev_priv, (status>>24)&3);
+ nouveau_crtc_irq_handler(dev, (status>>24)&3);
status &= ~NV_PMC_INTSTAT_CRTCn_PENDING;
}
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index 42c5b851..2b723c76 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -15,8 +15,8 @@
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
-#define NV03_STATUS 0x004006b0
-#define NV04_STATUS 0x00400700
+#define NV03_PGRAPH_STATUS 0x004006b0
+#define NV04_PGRAPH_STATUS 0x00400700
#define NV_RAMIN 0x00700000
@@ -55,16 +55,24 @@
# define NV_PMC_INTEN_MASTER_ENABLE (1<< 0)
#define NV_PGRAPH_INTSTAT 0x00400100
-#define NV_PGRAPH_INTEN 0x00400140
+#define NV04_PGRAPH_INTEN 0x00400140
+#define NV40_PGRAPH_INTEN 0x0040013C
# define NV_PGRAPH_INTR_NOTIFY (1<< 0)
# define NV_PGRAPH_INTR_MISSING_HW (1<< 4)
+# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12)
# define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16)
# define NV_PGRAPH_INTR_ERROR (1<<20)
+#define NV_PGRAPH_CTX_CONTROL 0x00400144
#define NV_PGRAPH_NV40_UNK220 0x00400220
# define NV_PGRAPH_NV40_UNK220_FB_INSTANCE
+#define NV_PGRAPH_CTX_USER 0x00400148
+#define NV_PGRAPH_CTX_SWITCH1 0x0040014C
+#define NV_PGRAPH_FIFO 0x00400720
+#define NV_PGRAPH_FFINTFC_ST2 0x00400764
/* It's a guess that this works on NV03. Confirmed on NV04, though */
-#define NV03_FIFO_ENABLE 0x00002504
+#define NV_PFIFO_DELAY_0 0x00002040
+#define NV_PFIFO_DMA_TIMESLICE 0x00002044
#define NV_PFIFO_INTSTAT 0x00002100
#define NV_PFIFO_INTEN 0x00002140
# define NV_PFIFO_INTR_ERROR (1<<0)
@@ -73,14 +81,78 @@
#define NV_PFIFO_RAMRO 0x00002218
#define NV_PFIFO_CACHES 0x00002500
#define NV_PFIFO_MODE 0x00002504
+#define NV_PFIFO_DMA 0x00002508
#define NV_PFIFO_SIZE 0x0000250c
#define NV_PFIFO_CACH0_PSH0 0x00003000
#define NV_PFIFO_CACH0_PUL0 0x00003050
#define NV_PFIFO_CACH0_PUL1 0x00003054
#define NV_PFIFO_CACH1_PSH0 0x00003200
#define NV_PFIFO_CACH1_PSH1 0x00003204
-#define NV_PFIFO_CACH1_DMAS 0x00003220
+#define NV_PFIFO_CACH1_DMAPSH 0x00003220
#define NV_PFIFO_CACH1_DMAF 0x00003224
+# define NV_PFIFO_CACH1_DMAF_TRIG_8_BYTES 0x00000000
+# define NV_PFIFO_CACH1_DMAF_TRIG_8_BYTES 0x00000000
+# define NV_PFIFO_CACH1_DMAF_TRIG_16_BYTES 0x00000008
+# define NV_PFIFO_CACH1_DMAF_TRIG_24_BYTES 0x00000010
+# define NV_PFIFO_CACH1_DMAF_TRIG_32_BYTES 0x00000018
+# define NV_PFIFO_CACH1_DMAF_TRIG_40_BYTES 0x00000020
+# define NV_PFIFO_CACH1_DMAF_TRIG_48_BYTES 0x00000028
+# define NV_PFIFO_CACH1_DMAF_TRIG_56_BYTES 0x00000030
+# define NV_PFIFO_CACH1_DMAF_TRIG_64_BYTES 0x00000038
+# define NV_PFIFO_CACH1_DMAF_TRIG_72_BYTES 0x00000040
+# define NV_PFIFO_CACH1_DMAF_TRIG_80_BYTES 0x00000048
+# define NV_PFIFO_CACH1_DMAF_TRIG_88_BYTES 0x00000050
+# define NV_PFIFO_CACH1_DMAF_TRIG_96_BYTES 0x00000058
+# define NV_PFIFO_CACH1_DMAF_TRIG_104_BYTES 0x00000060
+# define NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES 0x00000068
+# define NV_PFIFO_CACH1_DMAF_TRIG_120_BYTES 0x00000070
+# define NV_PFIFO_CACH1_DMAF_TRIG_128_BYTES 0x00000078
+# define NV_PFIFO_CACH1_DMAF_TRIG_136_BYTES 0x00000080
+# define NV_PFIFO_CACH1_DMAF_TRIG_144_BYTES 0x00000088
+# define NV_PFIFO_CACH1_DMAF_TRIG_152_BYTES 0x00000090
+# define NV_PFIFO_CACH1_DMAF_TRIG_160_BYTES 0x00000098
+# define NV_PFIFO_CACH1_DMAF_TRIG_168_BYTES 0x000000A0
+# define NV_PFIFO_CACH1_DMAF_TRIG_176_BYTES 0x000000A8
+# define NV_PFIFO_CACH1_DMAF_TRIG_184_BYTES 0x000000B0
+# define NV_PFIFO_CACH1_DMAF_TRIG_192_BYTES 0x000000B8
+# define NV_PFIFO_CACH1_DMAF_TRIG_200_BYTES 0x000000C0
+# define NV_PFIFO_CACH1_DMAF_TRIG_208_BYTES 0x000000C8
+# define NV_PFIFO_CACH1_DMAF_TRIG_216_BYTES 0x000000D0
+# define NV_PFIFO_CACH1_DMAF_TRIG_224_BYTES 0x000000D8
+# define NV_PFIFO_CACH1_DMAF_TRIG_232_BYTES 0x000000E0
+# define NV_PFIFO_CACH1_DMAF_TRIG_240_BYTES 0x000000E8
+# define NV_PFIFO_CACH1_DMAF_TRIG_248_BYTES 0x000000F0
+# define NV_PFIFO_CACH1_DMAF_TRIG_256_BYTES 0x000000F8
+# define NV_PFIFO_CACH1_DMAF_SIZE 0x0000E000
+# define NV_PFIFO_CACH1_DMAF_SIZE_32_BYTES 0x00000000
+# define NV_PFIFO_CACH1_DMAF_SIZE_64_BYTES 0x00002000
+# define NV_PFIFO_CACH1_DMAF_SIZE_96_BYTES 0x00004000
+# define NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES 0x00006000
+# define NV_PFIFO_CACH1_DMAF_SIZE_160_BYTES 0x00008000
+# define NV_PFIFO_CACH1_DMAF_SIZE_192_BYTES 0x0000A000
+# define NV_PFIFO_CACH1_DMAF_SIZE_224_BYTES 0x0000C000
+# define NV_PFIFO_CACH1_DMAF_SIZE_256_BYTES 0x0000E000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS 0x001F0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_0 0x00000000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_1 0x00010000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_2 0x00020000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_3 0x00030000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_4 0x00040000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_5 0x00050000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_6 0x00060000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_7 0x00070000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_8 0x00080000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_9 0x00090000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_10 0x000A0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_11 0x000B0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_12 0x000C0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_13 0x000D0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_14 0x000E0000
+# define NV_PFIFO_CACH1_DMAF_MAX_REQS_15 0x000F0000
+# define NV_PFIFO_CACH1_ENDIAN 0x80000000
+# define NV_PFIFO_CACH1_LITTLE_ENDIAN 0x7FFFFFFF
+# define NV_PFIFO_CACH1_BIG_ENDIAN 0x80000000
+#define NV_PFIFO_CACH1_DMAS 0x00003228
#define NV_PFIFO_CACH1_DMAI 0x0000322c
#define NV_PFIFO_CACH1_DMAC 0x00003230
#define NV_PFIFO_CACH1_DMAP 0x00003240
@@ -101,3 +173,4 @@
#define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc
#define NV03_FIFO_CMD_REWIND (NV03_FIFO_CMD_JUMP | (0 & NV03_FIFO_CMD_JUMP_OFFSET_MASK))
+
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index 6c5cc153..a015a0fe 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -150,55 +150,18 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
return 0;
}
-int nouveau_dma_init(struct drm_device *dev)
+/* waits for idle */
+void nouveau_wait_for_idle(struct drm_device *dev)
{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_config *config = &dev_priv->config;
- struct mem_block *cb;
- int cb_min_size = nouveau_fifo_number(dev) * NV03_FIFO_SIZE;
-
- nouveau_hash_table_init(dev);
-
- if (dev_priv->card_type >= NV_40)
- dev_priv->fb_obj = nouveau_dma_object_create(dev,
- 0, nouveau_mem_fb_amount(dev),
- NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM);
-
- /* Defaults for unconfigured values */
- if (!config->cmdbuf.location)
- config->cmdbuf.location = NOUVEAU_MEM_FB;
- if (!config->cmdbuf.size || config->cmdbuf.size < cb_min_size)
- config->cmdbuf.size = cb_min_size;
-
- cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
- config->cmdbuf.location, (DRMFILE)-2);
- /* Try defaults if that didn't succeed */
- if (!cb) {
- config->cmdbuf.location = NOUVEAU_MEM_FB;
- config->cmdbuf.size = cb_min_size;
- cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
- config->cmdbuf.location, (DRMFILE)-2);
- }
- if (!cb) {
- DRM_ERROR("Couldn't allocate DMA command buffer.\n");
- return DRM_ERR(ENOMEM);
+ drm_nouveau_private_t *dev_priv=dev->dev_private;
+ switch(dev_priv->card_type)
+ {
+ case NV_03:
+ while(NV_READ(NV03_PGRAPH_STATUS));
+ break;
+ default:
+ while(NV_READ(NV04_PGRAPH_STATUS));
+ break;
}
-
- if (config->cmdbuf.location == NOUVEAU_MEM_AGP)
- dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
- cb->start, cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP);
- else
- dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
- cb->start - drm_get_resource_start(dev, 1),
- cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
- dev_priv->cmdbuf_ch_size = (uint32_t)cb->size / nouveau_fifo_number(dev);
- dev_priv->cmdbuf_alloc = cb;
-
- DRM_INFO("DMA command buffer is %dKiB at 0x%08x(%s)\n",
- (uint32_t)cb->size>>10, (uint32_t)cb->start,
- config->cmdbuf.location == NOUVEAU_MEM_FB ? "VRAM" : "AGP");
- DRM_INFO("FIFO size is %dKiB\n", dev_priv->cmdbuf_ch_size>>10);
-
- return 0;
}