diff options
Diffstat (limited to 'shared-core/nouveau_fifo.c')
| -rw-r--r-- | shared-core/nouveau_fifo.c | 280 | 
1 files changed, 184 insertions, 96 deletions
| diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index cf389647..c662165b 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -53,63 +53,111 @@ int nouveau_fifo_number(drm_device_t* dev)   * voir nv_driver.c : NVPreInit    */ -static void nouveau_fifo_init(drm_device_t* dev) +static int nouveau_fifo_instmem_configure(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.. -	 */ +	int i; -	if (dev->irq_enabled) -		nouveau_irq_postinstall(dev); +	/* Clear RAMIN */ +	for (i=0x00710000; i<0x00800000; i++) +		NV_WRITE(i, 0x00000000); -	if (dev_priv->card_type >= NV_40) -		NV_WRITE(NV_PGRAPH_NV40_UNK220, dev_priv->fb_obj->instance >> 4); +	/* FIFO hash table (RAMHT) +	 *   use 4k hash table at RAMIN+0x10000 +	 *   TODO: extend the hash table +	 */ +	dev_priv->ramht_offset = 0x10000; +	dev_priv->ramht_bits   = 9; +	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits); +	NV_WRITE(NV_PFIFO_RAMHT, +			(0x03 << 24) /* search 128 */ |  +			((dev_priv->ramht_bits - 9) << 16) | +			(dev_priv->ramht_offset >> 8) +			); +	DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", +			dev_priv->ramht_offset, +			dev_priv->ramht_size); + +	/* FIFO runout table (RAMRO) - 512k at 0x11200 */ +	dev_priv->ramro_offset = 0x11200; +	dev_priv->ramro_size   = 512; +	NV_WRITE(NV_PFIFO_RAMRO, dev_priv->ramro_offset>>8); +	DRM_DEBUG("RAMRO offset=0x%x, size=%d\n", +			dev_priv->ramro_offset, +			dev_priv->ramro_size); + +	/* FIFO context table (RAMFC) +	 *   NV40  : Not sure exactly how to position RAMFC on some cards, +	 *           0x30002 seems to position it at RAMIN+0x20000 on these +	 *           cards.  RAMFC is 4kb (32 fifos, 128byte entries). +	 *   Others: Position RAMFC at RAMIN+0x11400 +	 */ +	if (dev_priv->card_type >= NV_40) { +		dev_priv->ramfc_offset = 0x20000; +		dev_priv->ramfc_size   = nouveau_fifo_number(dev) * 128; +		NV_WRITE(NV40_PFIFO_RAMFC, 0x30002); +	} else if (dev_priv->card_type >= NV_10) { +		dev_priv->ramfc_offset = 0x11400; +		dev_priv->ramfc_size   = nouveau_fifo_number(dev) * 64; +		NV_WRITE(NV_PFIFO_RAMFC, dev_priv->ramfc_offset>>8); +	} else { +		dev_priv->ramfc_offset = 0x11400; +		dev_priv->ramfc_size   = nouveau_fifo_number(dev) * 32; +		NV_WRITE(NV_PFIFO_RAMFC, dev_priv->ramfc_offset>>8); +	} +	DRM_DEBUG("RAMFC offset=0x%x, size=%d\n", +			dev_priv->ramfc_offset, +			dev_priv->ramfc_size); + +	return 0; +} -	DRM_DEBUG("%s: setting FIFO %d active\n", __func__, dev_priv->cur_fifo); +int nouveau_fifo_init(drm_device_t *dev) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	int ret; -	// FIXME remove all the stuff that's done in nouveau_fifo_alloc  	NV_WRITE(NV_PFIFO_CACHES, 0x00000000); + +	ret = nouveau_fifo_instmem_configure(dev); +	if (ret) { +		DRM_ERROR("Failed to configure instance memory\n"); +		return ret; +	} + +	/* FIXME remove all the stuff that's done in nouveau_fifo_alloc */ + +	DRM_DEBUG("Setting defaults for remaining PFIFO regs\n"); + +	/* All channels into PIO mode */  	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); +	/* Channel 0 active, PIO mode */ +	NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000000); +	/* PUT and GET to 0 */ +	NV_WRITE(NV_PFIFO_CACH1_DMAP, 0x00000000); +	NV_WRITE(NV_PFIFO_CACH1_DMAP, 0x00000000); +	/* No cmdbuf object */ +	NV_WRITE(NV_PFIFO_CACH1_DMAI, 0x00000000);  	NV_WRITE(NV_PFIFO_CACH0_PSH0, 0x00000000);  	NV_WRITE(NV_PFIFO_CACH0_PUL0, 0x00000000); -	NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF); +	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) -			); -	/* RAMFC needs to be at RAMIN+0x20000 on NV40, I currently don't know -	 * how to move it.. -	 */ -	dev_priv->ramfc_offset=0x20000; -	if (dev_priv->card_type < NV_40) -		NV_WRITE(NV_PFIFO_RAMFC, dev_priv->ramfc_offset>>8); /* RAMIN+0x11000 0.5k */ -	else -		NV_WRITE(0x2220, 0x30002); -	dev_priv->ramro_offset=0x11200; -	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); +	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); +	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); @@ -126,11 +174,7 @@ static void nouveau_fifo_init(drm_device_t* dev)  	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__); +	return 0;  }  static int nouveau_dma_init(struct drm_device *dev) @@ -140,14 +184,6 @@ static int nouveau_dma_init(struct drm_device *dev)  	struct mem_block *cb;  	int cb_min_size = nouveau_fifo_number(dev) * max(NV03_FIFO_SIZE,PAGE_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; @@ -168,17 +204,9 @@ static int nouveau_dma_init(struct drm_device *dev)  		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"); @@ -191,23 +219,11 @@ static void nouveau_context_init(drm_device_t *dev,  				 drm_nouveau_fifo_alloc_t *init)  {  	drm_nouveau_private_t *dev_priv = dev->dev_private; -	uint32_t ctx_addr,ctx_size; +	struct nouveau_object *cb_obj; +	uint32_t ctx_addr, ctx_size = 32;  	int i; -	switch(dev_priv->card_type) -	{ -		case NV_03: -		case NV_04: -		case NV_05: -			ctx_size=32; -			break; -		case NV_10: -		case NV_20: -		case NV_30: -		default: -			ctx_size=64; -			break; -	} +	cb_obj = dev_priv->fifos[init->channel].cmdbuf_obj;  	ctx_addr=NV_RAMIN+dev_priv->ramfc_offset+init->channel*ctx_size;  	// clear the fifo context @@ -216,36 +232,83 @@ static void nouveau_context_init(drm_device_t *dev,  	NV_WRITE(ctx_addr,init->put_base);  	NV_WRITE(ctx_addr+4,init->put_base); -	if (dev_priv->card_type <= NV_05) -	{ -		// that's what is done in nvosdk, but that part of the code is buggy so... -		NV_WRITE(ctx_addr+8,dev_priv->cmdbuf_obj->instance >> 4); +	// that's what is done in nvosdk, but that part of the code is buggy so... +	NV_WRITE(ctx_addr+8, cb_obj->instance >> 4);  #ifdef __BIG_ENDIAN -		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|NV_PFIFO_CACH1_BIG_ENDIAN); +	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|NV_PFIFO_CACH1_BIG_ENDIAN);  #else -		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); +	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);  #endif -	} -	else -	{ -		NV_WRITE(ctx_addr+12,dev_priv->cmdbuf_obj->instance >> 4/*DMA INST/DMA COUNT*/); +} + +#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV10_RAMFC_##offset, (val)) +static void nouveau_nv10_context_init(drm_device_t *dev, +				      drm_nouveau_fifo_alloc_t *init) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_object *cb_obj; +	uint32_t fifoctx; +	int i; + +	cb_obj  = dev_priv->fifos[init->channel].cmdbuf_obj; +	fifoctx = NV_RAMIN + dev_priv->ramfc_offset + init->channel*64; +	for (i=0;i<64;i+=4) +		NV_WRITE(fifoctx + i, 0); + +	/* Fill entries that are seen filled in dumps of nvidia driver just +	 * after channel's is put into DMA mode +	 */ +	RAMFC_WR(DMA_PUT       , init->put_base); +	RAMFC_WR(DMA_GET       , init->put_base); +	RAMFC_WR(DMA_INSTANCE  , cb_obj->instance >> 4);  #ifdef __BIG_ENDIAN -		NV_WRITE(ctx_addr+20,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); +		RAMFC_WR(DMA_FETCH, 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(ctx_addr+20,NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4); +		RAMFC_WR(DMA_FETCH, NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES |  +				    NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES | +				    NV_PFIFO_CACH1_DMAF_MAX_REQS_4);  #endif -	} +	RAMFC_WR(DMA_SUBROUTINE, init->put_base); +} +static void nouveau_nv10_context_save(drm_device_t *dev) +{ +	drm_nouveau_private_t *dev_priv = dev->dev_private; +	uint32_t fifoctx; +	int channel; + +	channel = NV_READ(NV_PFIFO_CACH1_PSH1) & (nouveau_fifo_number(dev)-1); +	fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + +	RAMFC_WR(DMA_PUT          , NV_READ(NV_PFIFO_CACH1_DMAP)); +	RAMFC_WR(DMA_GET          , NV_READ(NV_PFIFO_CACH1_DMAG)); +	RAMFC_WR(REF_CNT          , NV_READ(NV_PFIFO_CACH1_REF_CNT)); +	RAMFC_WR(DMA_INSTANCE     , NV_READ(NV_PFIFO_CACH1_DMAI)); +	RAMFC_WR(DMA_STATE        , NV_READ(NV_PFIFO_CACH1_DMAS)); +	RAMFC_WR(DMA_FETCH        , NV_READ(NV_PFIFO_CACH1_DMAF)); +	RAMFC_WR(ENGINE           , NV_READ(NV_PFIFO_CACH1_ENG)); +	RAMFC_WR(PULL1_ENGINE     , NV_READ(NV_PFIFO_CACH1_PUL1)); +	RAMFC_WR(ACQUIRE_VALUE    , NV_READ(NV_PFIFO_CACH1_ACQUIRE_VALUE)); +	RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV_PFIFO_CACH1_ACQUIRE_TIMESTAMP)); +	RAMFC_WR(ACQUIRE_TIMEOUT  , NV_READ(NV_PFIFO_CACH1_ACQUIRE_TIMEOUT)); +	RAMFC_WR(SEMAPHORE        , NV_READ(NV_PFIFO_CACH1_SEMAPHORE)); +	RAMFC_WR(DMA_SUBROUTINE   , NV_READ(NV_PFIFO_CACH1_DMAG));  } +#undef RAMFC_WR  #define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val))  static void nouveau_nv40_context_init(drm_device_t *dev,  				      drm_nouveau_fifo_alloc_t *init)  {  	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_object *cb_obj;  	uint32_t fifoctx;  	int i; +	cb_obj  = dev_priv->fifos[init->channel].cmdbuf_obj;  	fifoctx = NV_RAMIN + dev_priv->ramfc_offset + init->channel*128;  	for (i=0;i<128;i+=4)  		NV_WRITE(fifoctx + i, 0); @@ -255,7 +318,7 @@ static void nouveau_nv40_context_init(drm_device_t *dev,  	 */  	RAMFC_WR(DMA_PUT       , init->put_base);  	RAMFC_WR(DMA_GET       , init->put_base); -	RAMFC_WR(DMA_INSTANCE  , dev_priv->cmdbuf_obj->instance >> 4); +	RAMFC_WR(DMA_INSTANCE  , cb_obj->instance >> 4);  	RAMFC_WR(DMA_FETCH     , 0x30086078);  	RAMFC_WR(DMA_SUBROUTINE, init->put_base);  	RAMFC_WR(GRCTX_INSTANCE, 0); /* XXX */ @@ -297,6 +360,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init,  	int i;  	int ret;  	drm_nouveau_private_t *dev_priv = dev->dev_private; +	struct nouveau_object *cb_obj;  	/* Init cmdbuf on first FIFO init, this is delayed until now to  	 * give the ddx a chance to configure the cmdbuf with SETPARAM @@ -324,6 +388,23 @@ static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init,  	if (i==nouveau_fifo_number(dev))  		return DRM_ERR(EINVAL); +	/* allocate a dma object for the command buffer */ +	if (dev_priv->cmdbuf_alloc->flags & NOUVEAU_MEM_AGP) { +		cb_obj = nouveau_dma_object_create(dev, +				dev_priv->cmdbuf_alloc->start, +				dev_priv->cmdbuf_alloc->size, +				NV_DMA_ACCESS_RO, +				NV_DMA_TARGET_AGP); +	} else { +		cb_obj = nouveau_dma_object_create(dev, +				dev_priv->cmdbuf_alloc->start - +					drm_get_resource_start(dev, 1), +				dev_priv->cmdbuf_alloc->size, +				NV_DMA_ACCESS_RO, +				NV_DMA_TARGET_VIDMEM); +	} +	dev_priv->fifos[i].cmdbuf_obj = cb_obj; +  	/* that fifo is used */  	dev_priv->fifos[i].used=1;  	dev_priv->fifos[i].filp=filp; @@ -340,16 +421,20 @@ static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init,  	NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000000);  	NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000000); -	if (dev_priv->card_type < NV_40) +	/* Save current channel's state to it's RAMFC entry. +	 * +	 * Then, construct inital RAMFC for new channel, I'm not entirely +	 * sure this is needed if we activate the channel immediately. +	 * My understanding is that the GPU will fill RAMFC itself when +	 * it switches away from the channel +	 */ +	if (dev_priv->card_type < NV_10) {  		nouveau_context_init(dev, init); -	else { -		/* Save current channel's state to it's RAMFC entry */ +	} else if (dev_priv->card_type < NV_40) { +		nouveau_nv10_context_save(dev); +		nouveau_nv10_context_init(dev, init); +	} else {  		nouveau_nv40_context_save(dev); -		/* Construct inital RAMFC for new channel, I'm not entirely -		 * sure this is needed if we activate the channel immediately. -		 * My understanding is that the GPU will fill RAMFC itself -		 * when it switches away from the channel -		 */  		nouveau_nv40_context_init(dev, init);  	} @@ -368,7 +453,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init,  	NV_WRITE(NV_PFIFO_CACH1_DMAP, init->put_base);  	NV_WRITE(NV_PFIFO_CACH1_DMAG, init->put_base); -	NV_WRITE(NV_PFIFO_CACH1_DMAI, dev_priv->cmdbuf_obj->instance >> 4); +	NV_WRITE(NV_PFIFO_CACH1_DMAI, cb_obj->instance >> 4);  	NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF);  	NV_WRITE(NV_PFIFO_CACH1_HASH, 0x0000FFFF); @@ -409,6 +494,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init,  	/* FIFO has no objects yet */  	dev_priv->fifos[init->channel].objs = NULL; +	dev_priv->fifo_alloc_count++;  	DRM_INFO("%s: initialised FIFO %d\n", __func__, init->channel);  	return 0; @@ -438,6 +524,8 @@ void nouveau_fifo_free(drm_device_t* dev,int n)  	/* reenable the fifo caches */  	NV_WRITE(NV_PFIFO_CACHES, 0x00000001); + +	dev_priv->fifo_alloc_count--;  }  /* cleanups all the fifos from filp */ | 
