summaryrefslogtreecommitdiff
AgeCommit message (Expand)Author
2004-10-30Some stabilizing work to the DMA ring-buffer code. Temporarily replaced theThomas Hellstrom
2004-10-29Switch SPIN_LOCK_UNLOCKED to spin_lock_init()Jon Smirl
2004-10-29Add include of moduleparam.hJon Smirl
2004-10-28Break poll() to make it match the Xserver's broken expectations.Jon Smirl
2004-10-28fix for 2.4 buildDave Airlie
2004-10-23Round 2 of getting rid of inter_module_get()Jon Smirl
2004-10-23Revert symbol_get() changes from drm_drvJon Smirl
2004-10-23fix inter module put/getDave Airlie
2004-10-23actually 2.6.10 introduced pfn range so it should work now..Dave Airlie
2004-10-23fix pfn vs page for older kernels (2.6.9-rc kernels many not work..)Dave Airlie
2004-10-23Apply radeon r300 microcode patch to non-coreDave Airlie
2004-10-23Prepare to eliminate inter_module_get("agp")Jon Smirl
2004-10-22Bring in patch from kernel for remap_pfn_rangeJon Smirl
2004-10-21Fix up the radeon i2c error handingJon Smirl
2004-10-20Don't release an i2c channel that has not initialized correctlyJon Smirl
2004-10-20Switch linux-core from using dev->pdev->driver->name toJon Smirl
2004-10-20Fix dd vs di version typo in drm_setversionJon Smirl
2004-10-19Add a protective check against a possible buffer overflowJon Smirl
2004-10-19Fix missing I2C busses to be non-fatal error.Jon Smirl
2004-10-19drm-core, Clean up bug error path on stealth mode exitJon Smirl
2004-10-18Update Doxygen configuration & comments.Jose Fonseca
2004-10-16Fixed off by one errors in clipping.Ville Syrjala
2004-10-16Fixed bad formatting.Ville Syrjala
2004-10-15Remove drm_init.cJon Smirl
2004-10-15Move drm_cpu_valid out of drm_init. drm_init is empty now.Jon Smirl
2004-10-15Switch linux-core over to 2.6 parameter model to enable debug useJon Smirl
2004-10-13Add a poll function that alternates between zero and normal poll return toJon Smirl
2004-10-12Via updates. Fixed unlikely but possible uint32_t overflow in ring-bufferThomas Hellstrom
2004-10-12Breakout heads into their own data structures.Jon Smirl
2004-10-10Rename fn_tbl to driver. Core driver now uses pci_driver name whichJon Smirl
2004-10-10Vladimir requested support so we can at least load r300 microcode forDave Airlie
2004-10-10Forgot to add the new MakefileJon Smirl
2004-10-10Make the test programs buildJon Smirl
2004-10-09cleanup VIA driver to look a bit like others before kernel mergeDave Airlie
2004-10-09fix up whitespacing in KconfigDave Airlie
2004-10-09Lindent the via stuff so I can include it in kernelDave Airlie
2004-10-09remove unused dma remnants that were gamma only - these could cause an oopsDave Airlie
2004-10-08Changed unsigned to uint32_t in some ioctl parameters. Introduced firstThomas Hellstrom
2004-10-08Fix refcount bug in stealth modeJon Smirl
2004-10-07Fix drm_exit to allow for DRM(global) being deleted when framebuffer isJon Smirl
2004-10-06Revert back to drm_order() instead of using kernel get_order(). TheJon Smirl
2004-10-05Patch for Kconfig for making i830/i915 not build togetherDave Airlie
2004-10-05enable the device in the right order, remove __devinit from drm_intJon Smirl
2004-10-02janitor-list_for_each-drivers-char-drm-radeon_memc.patch from mm kernelJon Smirl
2004-09-30Make the debug memory functions compile for the core model.Jon Smirl
2004-09-30Remove DRM() macros from core ffb driver. DaveA says he'll make it compileJon Smirl
2004-09-30Lindent of core build. Drivers checked for no binary diffs. A few filesJon Smirl
2004-09-30savage.h not used in core buildsJon Smirl
2004-09-30core ffb.h is not used anymoreJon Smirl
2004-09-30Remove unused drm_module.hJon Smirl
>
/*
 * Copyright (C) 2006 Ben Skeggs.
 *
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/*
 * Authors:
 *   Ben Skeggs <darktama@iinet.net.au>
 */

#include "drmP.h"
#include "drm.h"
#include "nouveau_drm.h"
#include "nouveau_drv.h"
#include "nouveau_reg.h"

void nouveau_irq_preinstall(drm_device_t *dev)
{
	drm_nouveau_private_t *dev_priv = dev->dev_private;

	DRM_DEBUG("IRQ: preinst\n");

	/* Disable/Clear PFIFO interrupts */
	NV_WRITE(NV_PFIFO_INTEN, 0);
	NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF);
	/* Disable/Clear PGRAPH interrupts */
	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 */
	NV_WRITE(NV_CRTC0_INTEN, 0);
	NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
	NV_WRITE(NV_CRTC1_INTEN, 0);
	NV_WRITE(NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
#endif
	/* Master disable */
	NV_WRITE(NV_PMC_INTEN, 0);
}

void nouveau_irq_postinstall(drm_device_t *dev)
{
	drm_nouveau_private_t *dev_priv = dev->dev_private;

	DRM_DEBUG("IRQ: postinst\n");

	/* Enable PFIFO error reporting */
	NV_WRITE(NV_PFIFO_INTEN , 
			NV_PFIFO_INTR_CACHE_ERROR |
			NV_PFIFO_INTR_RUNOUT |
			NV_PFIFO_INTR_RUNOUT_OVERFLOW |
			NV_PFIFO_INTR_DMA_PUSHER |
			NV_PFIFO_INTR_DMA_PT |
			NV_PFIFO_INTR_SEMAPHORE |
			NV_PFIFO_INTR_ACQUIRE_TIMEOUT
			);
	NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF);

	/* Enable PGRAPH interrupts */
	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
				);
	NV_WRITE(NV_PGRAPH_INTSTAT, 0xFFFFFFFF);

#if 0
	/* Enable CRTC0/1 interrupts */
	NV_WRITE(NV_CRTC0_INTEN, NV_CRTC_INTR_VBLANK);
	NV_WRITE(NV_CRTC1_INTEN, NV_CRTC_INTR_VBLANK);
#endif

	/* Master enable */
	NV_WRITE(NV_PMC_INTEN, NV_PMC_INTEN_MASTER_ENABLE);
}

void nouveau_irq_uninstall(drm_device_t *dev)
{
	drm_nouveau_private_t *dev_priv = dev->dev_private;

	DRM_DEBUG("IRQ: uninst\n");

	/* Disable PFIFO interrupts */
	NV_WRITE(NV_PFIFO_INTEN, 0);
	/* Disable PGRAPH interrupts */
	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);
	NV_WRITE(NV_CRTC1_INTEN, 0);
#endif
	/* Master disable */
	NV_WRITE(NV_PMC_INTEN, 0);
}

static void nouveau_fifo_irq_handler(drm_device_t *dev)
{
	uint32_t status, chmode, chstat, channel;
	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(NV_PFIFO_DMA);
	channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1);

	DRM_DEBUG("NV: PFIFO interrupt! Channel=%d, INTSTAT=0x%08x/MODE=0x%08x/PEND=0x%08x\n", channel, status, chmode, chstat);

	if (status & NV_PFIFO_INTR_CACHE_ERROR) {
		uint32_t c1get, c1method, c1data;

		DRM_ERROR("NV: PFIFO error interrupt\n");

		c1get = NV_READ(NV_PFIFO_CACH1_GET) >> 2;
		if (dev_priv->card_type < NV_40) {
			/* Untested, so it may not work.. */
			c1method = NV_READ(NV_PFIFO_CACH1_METHOD(c1get));
			c1data   = NV_READ(NV_PFIFO_CACH1_DATA(c1get));
		} else {
			c1method = NV_READ(NV40_PFIFO_CACH1_METHOD(c1get));
			c1data   = NV_READ(NV40_PFIFO_CACH1_DATA(c1get));
		}

		DRM_ERROR("NV: Channel %d/%d - Method 0x%04x, Data 0x%08x\n",
				channel, (c1method >> 13) & 7,
				c1method & 0x1ffc, c1data
			 );

		status &= ~NV_PFIFO_INTR_CACHE_ERROR;
		NV_WRITE(NV_PFIFO_INTSTAT, NV_PFIFO_INTR_CACHE_ERROR);
	}

	if (status & NV_PFIFO_INTR_DMA_PUSHER) {
		DRM_INFO("NV: PFIFO DMA pusher interrupt\n");

		status &= ~NV_PFIFO_INTR_DMA_PUSHER;
		NV_WRITE(NV_PFIFO_INTSTAT, NV_PFIFO_INTR_DMA_PUSHER);

		NV_WRITE(NV_PFIFO_CACH1_DMAS, 0x00000000);
		if (NV_READ(NV_PFIFO_CACH1_DMAP)!=NV_READ(NV_PFIFO_CACH1_DMAG))
		{
			uint32_t getval=NV_READ(NV_PFIFO_CACH1_DMAG)+4;
			NV_WRITE(NV_PFIFO_CACH1_DMAG,getval);
		}
	}

	if (status) {
		DRM_INFO("NV: unknown PFIFO interrupt. status=0x%08x\n", status);

		NV_WRITE(NV_PFIFO_INTSTAT, status);
	}

	NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PFIFO_PENDING);
}

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_CONTROL, 0x10000100);
	NV_WRITE(NV_PGRAPH_CTX_USER, NV_READ(NV_PGRAPH_CTX_USER)|0x1F000000);
//	NV_WRITE(NV_PGRAPH_FFINTFC_ST2, NV_READ(NV_PGRAPH_FFINTFC_ST2)&0xCFFFFFFF);
	/* touch PGRAPH_CTX_SWITCH* here ? */
	NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x10000100);
}

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)
		return;

	if (status & NV_PGRAPH_INTR_NOTIFY) {
		uint32_t nsource, nstatus, instance, notify;
		DRM_DEBUG("NV: PGRAPH notify interrupt\n");

		nstatus = NV_READ(0x00400104);
		nsource = NV_READ(0x00400108);
		DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);

		instance = NV_READ(0x00400158);
		notify   = NV_READ(0x00400150) >> 16;
		DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", nsource, nstatus);

		status &= ~NV_PGRAPH_INTR_NOTIFY;
		NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_NOTIFY);
	}

	if (status & NV_PGRAPH_INTR_BUFFER_NOTIFY) {
		uint32_t nsource, nstatus, instance, notify;
		DRM_DEBUG("NV: PGRAPH buffer notify interrupt\n");

		nstatus = NV_READ(0x00400104);
		nsource = NV_READ(0x00400108);
		DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);

		instance = NV_READ(0x00400158);
		notify   = NV_READ(0x00400150) >> 16;
		DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", instance, notify);

		status &= ~NV_PGRAPH_INTR_BUFFER_NOTIFY;
		NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_BUFFER_NOTIFY);
	}

	if (status & NV_PGRAPH_INTR_MISSING_HW) {
		DRM_ERROR("NV: PGRAPH missing hw interrupt\n");

		status &= ~NV_PGRAPH_INTR_MISSING_HW;
		NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_MISSING_HW);
	}

	if (status & NV_PGRAPH_INTR_ERROR) {
		DRM_ERROR("NV: PGRAPH error interrupt\n");

		status &= ~NV_PGRAPH_INTR_ERROR;
		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:
			case NV_05:
				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);
	}

	NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PGRAPH_PENDING);
}

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);
	}

	if (crtc&2) {
		NV_WRITE(NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
	}
}

irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS)
{
	drm_device_t          *dev = (drm_device_t*)arg;
	drm_nouveau_private_t *dev_priv = dev->dev_private;
	uint32_t status;

	status = NV_READ(NV_PMC_INTSTAT);

	DRM_DEBUG("PMC INTSTAT: 0x%08x\n", status);

	if (status & NV_PMC_INTSTAT_PFIFO_PENDING) {
		nouveau_fifo_irq_handler(dev);
		status &= ~NV_PMC_INTSTAT_PFIFO_PENDING;
	}
	if (status & NV_PMC_INTSTAT_PGRAPH_PENDING) {
		nouveau_pgraph_irq_handler(dev);
		status &= ~NV_PMC_INTSTAT_PGRAPH_PENDING;
	}
	if (status & NV_PMC_INTSTAT_CRTCn_PENDING) {
		nouveau_crtc_irq_handler(dev, (status>>24)&3);
		status &= ~NV_PMC_INTSTAT_CRTCn_PENDING;
	}

	if (status)
		DRM_ERROR("Unhandled PMC INTR status bits 0x%08x\n", status);

	return IRQ_HANDLED;
}