1038 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1038 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2004 Eric Anholt
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the name of Eric Anholt not be used in
 | |
|  * advertising or publicity pertaining to distribution of the software without
 | |
|  * specific, written prior permission.  Eric Anholt makes no
 | |
|  * representations about the suitability of this software for any purpose.  It
 | |
|  * is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | |
|  * PERFORMANCE OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include <sys/time.h>
 | |
| 
 | |
| #include "ati.h"
 | |
| #include "ati_reg.h"
 | |
| #include "ati_dma.h"
 | |
| #include "ati_draw.h"
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| #include "radeon_common.h"
 | |
| #include "r128_common.h"
 | |
| #include "ati_sarea.h"
 | |
| #endif /* USE_DRI */
 | |
| 
 | |
| #include "agp.h"
 | |
| 
 | |
| #define DEBUG_FIFO 0
 | |
| 
 | |
| extern CARD32 r128_cce_microcode[];
 | |
| extern CARD32 radeon_cp_microcode[][2];
 | |
| extern CARD32 r200_cp_microcode[][2];
 | |
| extern CARD32 r300_cp_microcode[][2];
 | |
| 
 | |
| #if DEBUG_FIFO
 | |
| static void
 | |
| ATIDebugFifo(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		ErrorF("RADEON_REG_CP_CSQ_CNTL: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL));
 | |
| 		ErrorF("RADEON_REG_CP_CSQ_STAT: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, RADEON_REG_CP_CSQ_STAT));
 | |
| 		ErrorF("RADEON_REG_RBBM_STATUS: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, RADEON_REG_RBBM_STATUS));
 | |
| 		ErrorF("RADEON_REG_RB3D_DSTCACHE_CTLSTAT: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, RADEON_REG_RB3D_DSTCACHE_CTLSTAT));
 | |
| 	} else {
 | |
| 		ErrorF("R128_REG_PM4_BUFFER_CNTL: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL));
 | |
| 		ErrorF("R128_REG_PM4_STAT: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, R128_REG_PM4_STAT));
 | |
| 		ErrorF("R128_REG_GUI_STAT: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, R128_REG_GUI_STAT));
 | |
| 		ErrorF("R128_REG_PC_NGUI_CTLSTAT: 0x%08x\n",
 | |
| 		    MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT));
 | |
| 	}
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| ATIUploadMicrocode(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	int i;
 | |
| 
 | |
| 	MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_ADDR, 0);
 | |
| 	if (atic->is_radeon && atic->is_r300) {
 | |
| 		for (i = 0; i < 256; i++) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
 | |
| 			    r300_cp_microcode[i][1]);
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
 | |
| 			    r300_cp_microcode[i][0]);
 | |
| 		}
 | |
| 	} else if (atic->is_radeon && atic->is_r200) {
 | |
| 		for (i = 0; i < 256; i++) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
 | |
| 			    r200_cp_microcode[i][1]);
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
 | |
| 			    r200_cp_microcode[i][0]);
 | |
| 		}
 | |
| 	} else if (atic->is_radeon && atic->is_r100) {
 | |
| 		for (i = 0; i < 256; i++) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
 | |
| 			    radeon_cp_microcode[i][1]);
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
 | |
| 			    radeon_cp_microcode[i][0]);
 | |
| 		}
 | |
| 	} else {
 | |
| 		for (i = 0; i < 256; i++) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
 | |
| 			    r128_cce_microcode[i * 2]);
 | |
| 			MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
 | |
| 			    r128_cce_microcode[i * 2 + 1]);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Required when reading from video memory after acceleration to make sure all
 | |
|  * data has been flushed to video memory from the pixel cache.
 | |
|  */
 | |
| static void
 | |
| ATIFlushPixelCache(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 temp;
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		temp = MMIO_IN32(mmio, RADEON_REG_RB3D_DSTCACHE_CTLSTAT);
 | |
| 		temp |= RADEON_RB3D_DC_FLUSH_ALL;
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_RB3D_DSTCACHE_CTLSTAT, temp);
 | |
| 
 | |
| 		WHILE_NOT_TIMEOUT(.2) {
 | |
| 			if ((MMIO_IN32(mmio, RADEON_REG_RB3D_DSTCACHE_CTLSTAT) &
 | |
| 			    RADEON_RB3D_DC_BUSY) == 0)
 | |
| 				break;
 | |
| 		}
 | |
| 	} else {
 | |
| 		temp = MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT);
 | |
| 		temp |= R128_PC_FLUSH_ALL;
 | |
| 		MMIO_OUT32(mmio, R128_REG_PC_NGUI_CTLSTAT, temp);
 | |
| 
 | |
| 		WHILE_NOT_TIMEOUT(.2) {
 | |
| 			if ((MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT) &
 | |
| 			    R128_PC_BUSY) != R128_PC_BUSY)
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	if (TIMEDOUT())
 | |
| 		ErrorF("Timeout flushing pixel cache.\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| ATIEngineReset(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 clockcntlindex, mclkcntl;
 | |
| 
 | |
| #if DEBUG_FIFO
 | |
| 	ErrorF("Engine Reset!\n");
 | |
| 	ATIDebugFifo(atis);
 | |
| #endif
 | |
| 
 | |
| 	ATIFlushPixelCache(atis);
 | |
| 
 | |
| 	clockcntlindex = MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX);
 | |
| 	if (atic->is_r300)
 | |
| 		R300CGWorkaround(atis);
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		CARD32 host_path_cntl;
 | |
| 
 | |
| 		mclkcntl = INPLL(mmio, RADEON_REG_MCLK_CNTL);
 | |
| 
 | |
| 		OUTPLL(mmio, RADEON_REG_MCLK_CNTL, mclkcntl |
 | |
| 		    RADEON_FORCEON_MCLKA |
 | |
| 		    RADEON_FORCEON_MCLKB |
 | |
| 		    RADEON_FORCEON_YCLKA |
 | |
| 		    RADEON_FORCEON_YCLKB |
 | |
| 		    RADEON_FORCEON_MC |
 | |
| 		    RADEON_FORCEON_AIC);
 | |
| 
 | |
| 		host_path_cntl = MMIO_IN32(mmio, RADEON_REG_HOST_PATH_CNTL);
 | |
| 
 | |
| 		if (atic->is_r300) {
 | |
| 			MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET,
 | |
| 			    RADEON_SOFT_RESET_CP |
 | |
| 			    RADEON_SOFT_RESET_HI |
 | |
| 			    RADEON_SOFT_RESET_E2);
 | |
| 		} else {
 | |
| 			MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET,
 | |
| 			    RADEON_SOFT_RESET_CP |
 | |
| 			    RADEON_SOFT_RESET_SE |
 | |
| 			    RADEON_SOFT_RESET_RE |
 | |
| 			    RADEON_SOFT_RESET_PP |
 | |
| 			    RADEON_SOFT_RESET_E2 |
 | |
| 			    RADEON_SOFT_RESET_RB);
 | |
| 		}
 | |
| 		MMIO_IN32(mmio, RADEON_REG_RBBM_SOFT_RESET);
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET, 0);
 | |
| 
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_HOST_PATH_CNTL, host_path_cntl |
 | |
| 		    RADEON_HDP_SOFT_RESET);
 | |
| 		MMIO_IN32(mmio, RADEON_REG_HOST_PATH_CNTL);
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_HOST_PATH_CNTL, host_path_cntl);
 | |
| 
 | |
| 		MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, clockcntlindex);
 | |
| 		OUTPLL(mmio, RADEON_REG_MCLK_CNTL, mclkcntl);
 | |
| 		if (atic->is_r300)
 | |
| 			R300CGWorkaround(atis);
 | |
| 	} else {
 | |
| 		CARD32 temp;
 | |
| 
 | |
| 		mclkcntl = INPLL(mmio, R128_REG_MCLK_CNTL);
 | |
| 
 | |
| 		OUTPLL(mmio, R128_REG_MCLK_CNTL,
 | |
| 		    mclkcntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
 | |
| 
 | |
| 		temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
 | |
| 		MMIO_OUT32(mmio, R128_REG_GEN_RESET_CNTL,
 | |
| 		    temp | R128_SOFT_RESET_GUI);
 | |
| 		temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
 | |
| 		MMIO_OUT32(mmio, R128_REG_GEN_RESET_CNTL,
 | |
| 		    temp & ~R128_SOFT_RESET_GUI);
 | |
| 		temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
 | |
| 
 | |
| 		OUTPLL(mmio, R128_REG_MCLK_CNTL, mclkcntl);
 | |
| 		MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, clockcntlindex);
 | |
| 	}
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri) {
 | |
| 		ATIDRIDMAReset(atis);
 | |
| 		ATIDRIDMAStart(atis);
 | |
| 	}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void
 | |
| ATIWaitAvailMMIO(ATIScreenInfo *atis, int n)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	if (atis->mmio_avail >= n) {
 | |
| 		atis->mmio_avail -= n;
 | |
| 		return;
 | |
| 	}
 | |
| 	if (atic->is_radeon) {
 | |
| 		WHILE_NOT_TIMEOUT(.2) {
 | |
| 			atis->mmio_avail = MMIO_IN32(mmio,
 | |
| 			    RADEON_REG_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK;
 | |
| 			if (atis->mmio_avail >= n)
 | |
| 				break;
 | |
| 		}
 | |
| 	} else {
 | |
| 		WHILE_NOT_TIMEOUT(.2) {
 | |
| 			atis->mmio_avail = MMIO_IN32(mmio, R128_REG_GUI_STAT) &
 | |
| 			    0xfff;
 | |
| 			if (atis->mmio_avail >= n)
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	if (TIMEDOUT()) {
 | |
| 		ErrorF("Timeout waiting for %d MMIO slots.\n", n);
 | |
| 		ATIEngineReset(atis);
 | |
| 		ATIDrawSetup(atis->screen->pScreen);
 | |
| 	}
 | |
| 	atis->mmio_avail -= n;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ATIGetAvailPrimary(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		int csq_stat, diff;
 | |
| 	
 | |
| 		csq_stat = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_STAT);
 | |
| 		if (atic->is_r200)
 | |
| 			diff = ((csq_stat & R200_CSQ_WPTR_PRIMARY_MASK) >> 9) - 
 | |
| 			    (csq_stat & R200_CSQ_RPTR_PRIMARY_MASK);
 | |
| 		else
 | |
| 			diff = ((csq_stat & RADEON_CSQ_WPTR_PRIMARY_MASK) >> 8) - 
 | |
| 			    (csq_stat & RADEON_CSQ_RPTR_PRIMARY_MASK);
 | |
| 	
 | |
| 		if (diff < 0)
 | |
| 			return -diff;
 | |
| 		else
 | |
| 			return atis->cce_pri_size - diff;
 | |
| 	} else {
 | |
| 		return MMIO_IN32(mmio, R128_REG_PM4_STAT) &
 | |
| 		    R128_PM4_FIFOCNT_MASK;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| ATIWaitAvailPrimary(ATIScreenInfo *atis, int n)
 | |
| {
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	if (atis->cce_pri_avail >= n) {
 | |
| 		atis->cce_pri_avail -= n;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	WHILE_NOT_TIMEOUT(.2) {
 | |
| 		if (atis->cce_pri_avail >= n)
 | |
| 			break;
 | |
| 		atis->cce_pri_avail = ATIGetAvailPrimary(atis);
 | |
| 		if (atis->cce_pri_avail >= n)
 | |
| 			break;
 | |
| 	}
 | |
| 	if (TIMEDOUT()) {
 | |
| 		ErrorF("Timeout waiting for %d CCE slots (%d avail).\n", n,
 | |
| 		    atis->cce_pri_avail);
 | |
| 		ATIEngineReset(atis);
 | |
| 		ATIDrawSetup(atis->screen->pScreen);
 | |
| 	}
 | |
| 	atis->cce_pri_avail -= n;
 | |
| }
 | |
| 
 | |
| void
 | |
| ATIWaitIdle(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	if (atis->indirectBuffer != NULL)
 | |
| 		ATIFlushIndirect(atis, 0);
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri) {
 | |
| 		int ret = 0;
 | |
| 		int cmd = (atic->is_radeon ? DRM_RADEON_CP_IDLE :
 | |
| 		    DRM_R128_CCE_IDLE);
 | |
| 		WHILE_NOT_TIMEOUT(2) {
 | |
| 			ret = drmCommandNone(atic->drmFd, cmd);
 | |
| 			if (ret != -EBUSY)
 | |
| 				break;
 | |
| 		}
 | |
| 		if (TIMEDOUT()) {
 | |
| 			ATIDebugFifo(atis);
 | |
| 			FatalError("Timed out idling CCE (card hung)\n");
 | |
| 		}
 | |
| 		if (ret != 0)
 | |
| 			ErrorF("Failed to idle DMA, returned %d\n", ret);
 | |
| 		return;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	if (!atic->is_radeon && (atis->using_pseudo || atis->using_dma)) {
 | |
| 		ATIWaitAvailPrimary(atis, atis->cce_pri_size);
 | |
| 
 | |
| 		WHILE_NOT_TIMEOUT(.2) {
 | |
| 			if ((MMIO_IN32(mmio, R128_REG_PM4_STAT) &
 | |
| 			    (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE)) == 0)
 | |
| 				break;
 | |
| 		}
 | |
| 		if (TIMEDOUT()) {
 | |
| 			ErrorF("Timeout idling CCE, resetting...\n");
 | |
| 			ATIEngineReset(atis);
 | |
| 			ATIDrawSetup(atis->screen->pScreen);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Radeon CP idle is the same as MMIO idle. */
 | |
| 	if (atis->using_pio || atic->is_radeon) {
 | |
| 		/* Empty the fifo */
 | |
| 		ATIWaitAvailMMIO(atis, 64);
 | |
| 
 | |
| 		if (atic->is_radeon) {
 | |
| 			WHILE_NOT_TIMEOUT(.2) {
 | |
| 				if ((MMIO_IN32(mmio, RADEON_REG_RBBM_STATUS) &
 | |
| 				    RADEON_RBBM_ACTIVE) == 0)
 | |
| 					break;
 | |
| 			}
 | |
| 		} else {
 | |
| 			WHILE_NOT_TIMEOUT(.2) {
 | |
| 				if ((MMIO_IN32(mmio, R128_REG_GUI_STAT) &
 | |
| 				    R128_GUI_ACTIVE) == 0)
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 		if (TIMEDOUT()) {
 | |
| 			ErrorF("Timeout idling accelerator, resetting...\n");
 | |
| 			ATIEngineReset(atis);
 | |
| 			ATIDrawSetup(atis->screen->pScreen);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ATIFlushPixelCache(atis);
 | |
| 
 | |
| #if DEBUG_FIFO
 | |
| 	ErrorF("Idle?\n");
 | |
| 	ATIDebugFifo(atis);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| dmaBuf *
 | |
| ATIGetDMABuffer(ATIScreenInfo *atis)
 | |
| {
 | |
| 	dmaBuf *buf;
 | |
| 
 | |
| 	buf = (dmaBuf *)xalloc(sizeof(dmaBuf));
 | |
| 	if (buf == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri) {
 | |
| 		buf->drmBuf = ATIDRIGetBuffer(atis);
 | |
| 		if (buf->drmBuf == NULL) {
 | |
| 			xfree(buf);
 | |
| 			return NULL;
 | |
| 		}
 | |
| 		buf->size = buf->drmBuf->total;
 | |
| 		buf->used = buf->drmBuf->used;
 | |
| 		buf->address = buf->drmBuf->address;
 | |
| 		return buf;
 | |
| 	}
 | |
| #endif /* USE_DRI */
 | |
| 
 | |
| 	if (atis->using_dma)
 | |
| 		buf->size = atis->ring_len / 2;
 | |
| 	else
 | |
| 		buf->size = 512 * 1024;
 | |
| 	buf->address = xalloc(buf->size);
 | |
| 	if (buf->address == NULL) {
 | |
| 		xfree(buf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	buf->used = 0;
 | |
| 
 | |
| 	return buf;
 | |
| }
 | |
| 
 | |
| /* Decode a type-3 packet into MMIO register writes. Only some type-3 packets
 | |
|  * supported, and only partially.
 | |
|  */
 | |
| static void
 | |
| ATIDispatchPacket3MMIO(ATIScreenInfo *atis, CARD32 header, CARD32 *addr,
 | |
|     int count)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 settings;
 | |
| 	int i = 0;
 | |
| 
 | |
| 	settings = addr[i++];
 | |
| 
 | |
| 	if ((settings & ATI_GMC_SRC_PITCH_OFFSET_CNTL) != 0)
 | |
| 		MMIO_OUT32(mmio, ATI_REG_SRC_PITCH_OFFSET, addr[i++]);
 | |
| 	if ((settings & ATI_GMC_DST_PITCH_OFFSET_CNTL) != 0)
 | |
| 		MMIO_OUT32(mmio, ATI_REG_DST_PITCH_OFFSET, addr[i++]);
 | |
| 	if ((settings & ATI_GMC_BRUSH_MASK) == ATI_GMC_BRUSH_SOLID_COLOR)
 | |
| 		MMIO_OUT32(mmio, ATI_REG_DP_BRUSH_FRGD_CLR, addr[i++]);
 | |
| 
 | |
| 	switch (header & (ATI_CCE_PACKETTYPE_MASK |
 | |
| 	    ATI_CCE_PACKET3_IT_OPCODE_MASK))
 | |
| 	{
 | |
| 	case ATI_CCE_PACKET3_PAINT_MULTI:
 | |
| 		while (i < count) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_DST_Y_X,
 | |
| 			    (addr[i] >> 16) | (addr[i] << 16));
 | |
| 			i++;
 | |
| 			MMIO_OUT32(mmio, ATI_REG_DST_HEIGHT_WIDTH,
 | |
| 			    (addr[i] >> 16) | (addr[i] << 16));
 | |
| 			i++;
 | |
| 		}
 | |
| 		break;
 | |
| 	case ATI_CCE_PACKET3_BITBLT_MULTI:
 | |
| 		while (i < count) {
 | |
| 			MMIO_OUT32(mmio, ATI_REG_SRC_Y_X,
 | |
| 			    (addr[i] >> 16) | (addr[i] << 16));
 | |
| 			i++;
 | |
| 			MMIO_OUT32(mmio, ATI_REG_DST_Y_X,
 | |
| 			    (addr[i] >> 16) | (addr[i] << 16));
 | |
| 			i++;
 | |
| 			MMIO_OUT32(mmio, ATI_REG_DST_HEIGHT_WIDTH,
 | |
| 			    (addr[i] >> 16) | (addr[i] << 16));
 | |
| 			i++;
 | |
| 		}
 | |
| 		break;
 | |
| 	default:
 | |
| 		ErrorF("Unsupported packet: 0x%x\n", header);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Dispatch packets by decoding them and writing to registers.  Doesn't support
 | |
|  * the type 3 packets.
 | |
|  */
 | |
| static void
 | |
| ATIDispatchIndirectMMIO(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	dmaBuf *buf = atis->indirectBuffer;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 *addr;
 | |
| 	CARD32 reg;
 | |
| 	int i, n, count;
 | |
| 
 | |
| 	addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
 | |
| 	count = (buf->used - atis->indirectStart) / 4;
 | |
| 
 | |
| 	for (i = 0; i < count; i++) {
 | |
| 		CARD32 header = addr[i];
 | |
| 
 | |
| 		switch (header & ATI_CCE_PACKETTYPE_MASK)
 | |
| 		{
 | |
| 		case ATI_CCE_PACKET0:
 | |
| 			n = ((header & ATI_CCE_PACKET0_COUNT_MASK) >> 16) + 1;
 | |
| 			reg = (header & ATI_CCE_PACKET0_REG_MASK) << 2;
 | |
| 			ATIWaitAvailMMIO(atis, n);
 | |
| 			while (n > 0) {
 | |
| 				i++;
 | |
| 				MMIO_OUT32(mmio, reg, addr[i]);
 | |
| 				if ((header & ATI_CCE_PACKET0_ONE_REG_WR) == 0)
 | |
| 					reg += 4;
 | |
| 				n--;
 | |
| 			}
 | |
| 			break;
 | |
| 		case ATI_CCE_PACKET1:
 | |
| 			reg = (header & ATI_CCE_PACKET1_REG_1) << 2;
 | |
| 			MMIO_OUT32(mmio, reg, addr[++i]);
 | |
| 			reg = ((header & ATI_CCE_PACKET1_REG_2) >>
 | |
| 			    ATI_CCE_PACKET1_REG_2_SHIFT) << 2;
 | |
| 			MMIO_OUT32(mmio, reg, addr[++i]);
 | |
| 			break;
 | |
| 		case ATI_CCE_PACKET2:
 | |
| 			/* PACKET2 is a no-op packet. */
 | |
| 			break;
 | |
| 		case ATI_CCE_PACKET3:
 | |
| 			n = ((header & ATI_CCE_PACKET3_COUNT_MASK) >> 16) + 1;
 | |
| 			ATIDispatchPacket3MMIO(atis, header, &addr[i], n);
 | |
| 			i += n;
 | |
| 			break;
 | |
| 		default:
 | |
| 			ErrorF("Unsupported packet: 0x%x\n", addr[i]);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Dispatch packets by sending them through the MMIO aperture. */
 | |
| static void
 | |
| R128DispatchIndirectPDMA(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	dmaBuf *buf = atis->indirectBuffer;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 *addr;
 | |
| 	int count;
 | |
| 
 | |
| 	addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
 | |
| 	count = (buf->used - atis->indirectStart) / 4;
 | |
| 
 | |
| 	while (count > 1) {
 | |
| 		ATIWaitAvailPrimary(atis, 2);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_EVEN, *addr++);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_ODD, *addr++);
 | |
| 		count -= 2;
 | |
| 	}
 | |
| 
 | |
| 	/* Submit last DWORD if necessary. */
 | |
| 	if (count != 0) {
 | |
| 		ATIWaitAvailPrimary(atis, 2);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_EVEN, *addr++);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_ODD, ATI_CCE_PACKET2);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Dispatch packets by sending them through the MMIO aperture, using the
 | |
|  * primary CCE ring. */
 | |
| static void
 | |
| RadeonDispatchIndirectPDMA(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	dmaBuf *buf = atis->indirectBuffer;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 *addr;
 | |
| 	int count, avail, reg, i;
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
 | |
| 	count = (buf->used - atis->indirectStart) / 4;
 | |
| 
 | |
| 	reg = RADEON_REG_CSQ_APER_PRIMARY;
 | |
| 	WHILE_NOT_TIMEOUT(3) {
 | |
| 		/* 3 seconds is empirical, using render_bench on an r100. */
 | |
| 		if (count <= 0)
 | |
| 			break;
 | |
| 		avail = ATIGetAvailPrimary(atis);
 | |
| 		for (i = 0; i < min(count, avail); i++) {
 | |
| 			MMIO_OUT32(mmio, reg, *addr++);
 | |
| 			if (reg == RADEON_REG_CSQ_APER_PRIMARY_END)
 | |
| 				reg = RADEON_REG_CSQ_APER_PRIMARY;
 | |
| 			else
 | |
| 				reg += 4;
 | |
| 		}
 | |
| 		count -= i;
 | |
| 	}
 | |
| 	if (TIMEDOUT()) {
 | |
| 		ErrorF("Timeout submitting packets, resetting...\n");
 | |
| 		ATIEngineReset(atis);
 | |
| 		ATIDrawSetup(atis->screen->pScreen);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Dispatch packets by writing them to the (primary) ring buffer, which happens
 | |
|  * to be in framebuffer memory.
 | |
|  */
 | |
| static void
 | |
| R128DispatchIndirectDMA(ATIScreenInfo *atis)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	dmaBuf *buf = atis->indirectBuffer;
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	CARD32 *addr;
 | |
| 	int count, ring_count;
 | |
| 	TIMEOUT_LOCALS;
 | |
| 
 | |
| 	addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
 | |
| 	count = (buf->used - atis->indirectStart) / 4;
 | |
| 	ring_count = atis->ring_len / 4;
 | |
| 
 | |
| 	WHILE_NOT_TIMEOUT(.2) {
 | |
| 		if (count <= 0)
 | |
| 			break;
 | |
| 
 | |
| 		atis->ring_addr[atis->ring_write++] = *addr++;
 | |
| 		if (atis->ring_write >= ring_count)
 | |
| 			atis->ring_write = 0;
 | |
| 		while (atis->ring_write == atis->ring_read) {
 | |
| 			atis->ring_read = MMIO_IN32(mmio, ATI_REG_CCE_RPTR);
 | |
| 		}
 | |
| 		count--;
 | |
| 	}
 | |
| 	if (TIMEDOUT()) {
 | |
| 		ErrorF("Timeout submitting packets, resetting...\n");
 | |
| 		ATIEngineReset(atis);
 | |
| 		ATIDrawSetup(atis->screen->pScreen);
 | |
| 	}
 | |
| 		
 | |
| 	/* Workaround for some early Rage 128 ASIC spins where the CCE parser
 | |
| 	 * may read up to 32 DWORDS beyond the end of the ring buffer memory
 | |
| 	 * before wrapping around, if the ring buffer was empty and a <32 DWORD
 | |
| 	 * packet that wraps around the end of the ring buffer is submitted.
 | |
| 	 * To work around that, copy the beginning of the ring buffer past the
 | |
| 	 * end if that may happen.
 | |
| 	 */
 | |
| 	if (atis->ring_write < 32)
 | |
| 		memcpy(atis->ring_addr + ring_count, atis->ring_addr, 32 * 4);
 | |
| 
 | |
| 	/* Update write pointer */
 | |
| 	MMIO_OUT32(mmio, ATI_REG_CCE_WPTR, atis->ring_write);
 | |
| }
 | |
| 
 | |
| void
 | |
| ATIFlushIndirect(ATIScreenInfo *atis, Bool discard)
 | |
| {
 | |
| 	ATICardInfo *atic = atis->atic;
 | |
| 	dmaBuf *buf = atis->indirectBuffer;
 | |
| 
 | |
| 	if ((atis->indirectStart == buf->used) && !discard)
 | |
| 		return;
 | |
| 
 | |
| #if DEBUG_FIFO
 | |
| 	ErrorF("Dispatching %d DWORDS\n", (buf->used - atis->indirectStart) /
 | |
| 	    4);
 | |
| #endif
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri) {
 | |
| 		buf->drmBuf->used = buf->used;
 | |
| 		ATIDRIDispatchIndirect(atis, discard);
 | |
| 		if (discard) {
 | |
| 			buf->drmBuf = ATIDRIGetBuffer(atis);
 | |
| 			buf->size = buf->drmBuf->total;
 | |
| 			buf->used = buf->drmBuf->used;
 | |
| 			buf->address = buf->drmBuf->address;
 | |
| 			atis->indirectStart = 0;
 | |
| 		} else {
 | |
| 			/* Start on a double word boundary */
 | |
| 			atis->indirectStart = buf->used = (buf->used + 7) & ~7;
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| #endif /* USE_DRI */
 | |
| 
 | |
| 	if (atis->using_dma && !atic->is_radeon)
 | |
| 		R128DispatchIndirectDMA(atis);
 | |
| 	else if (atis->using_pseudo) {
 | |
| 		if (atic->is_radeon)
 | |
| 			RadeonDispatchIndirectPDMA(atis);
 | |
| 		else
 | |
| 			R128DispatchIndirectPDMA(atis);
 | |
| 	} else
 | |
| 		ATIDispatchIndirectMMIO(atis);
 | |
| 
 | |
| 	buf->used = 0;
 | |
| 	atis->indirectStart = 0;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ATIInitAGP(ScreenPtr pScreen, int size)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	AgpInfoPtr agp_info;
 | |
| 	int screennum = atis->screen->mynum;
 | |
| 
 | |
| 	if (atic->is_radeon)
 | |
| 		return FALSE;
 | |
| 
 | |
| 	if (!KdAgpGARTSupported()) 
 | |
| 		return FALSE; 
 | |
| 
 | |
| 	if (!KdAcquireGART(screennum))
 | |
| 		return FALSE;
 | |
| 
 | |
| 	atis->agp_key = KdAllocateGARTMemory(screennum, size, 0, NULL);
 | |
| 	if (atis->agp_key == -1) {
 | |
| 		ErrorF("Failed to allocate %dKB GART memory\n", size/1024);
 | |
| 		KdReleaseGART(screennum);
 | |
| 		return FALSE;
 | |
| 	}
 | |
| 
 | |
| 	if (!KdBindGARTMemory(screennum, atis->agp_key, 0)) {
 | |
| 		ErrorF("Failed to bind GART memory\n");
 | |
| 		KdReleaseGART(screennum);
 | |
| 		return FALSE;
 | |
| 	}
 | |
| 
 | |
| 	agp_info = KdGetAGPInfo(screennum);
 | |
| 	if (agp_info == NULL) {
 | |
| 		KdUnbindGARTMemory(screennum, atis->agp_key);
 | |
| 		KdReleaseGART(screennum);
 | |
| 		return FALSE;
 | |
| 	}
 | |
| 
 | |
| 	atis->agp_addr = KdMapDevice(agp_info->base, agp_info->size);
 | |
| 	if (atis->agp_addr == NULL) {
 | |
| 		ErrorF("Failed to map GART memory\n");
 | |
| 		KdUnbindGARTMemory(screennum, atis->agp_key);
 | |
| 		KdReleaseGART(screennum);
 | |
| 		free(agp_info);
 | |
| 		return FALSE;
 | |
| 	}
 | |
| 	KdSetMappedMode(agp_info->base, agp_info->size,
 | |
| 	    KD_MAPPED_MODE_FRAMEBUFFER);
 | |
| 
 | |
| 	atis->agp_size = size;
 | |
| 	free(agp_info);
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ATIFiniAGP(ScreenPtr pScreen)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	int screennum = atis->screen->mynum;
 | |
| 
 | |
| 	KdUnbindGARTMemory(screennum, atis->agp_key);
 | |
| 	KdReleaseGART(screennum);
 | |
| 	atis->agp_addr = NULL;
 | |
| 	atis->agp_size = 0;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ATIPseudoDMAInit(ScreenPtr pScreen)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	char *mmio = atic->reg_base;
 | |
| 
 | |
| 	if (atic->is_r300)
 | |
| 		return FALSE;
 | |
| 
 | |
| 	ATIUploadMicrocode(atis);
 | |
| 	ATIEngineReset(atis);
 | |
| 
 | |
| 	if (atic->is_r200) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIPIO_INDDIS);
 | |
| 		atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
 | |
| 		    R200_CSQ_CNT_PRIMARY_MASK;
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
 | |
| 	} else if (atic->is_radeon) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIPIO_INDDIS);
 | |
| 		atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
 | |
| 		    RADEON_CSQ_CNT_PRIMARY_MASK;
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
 | |
| 	} else {
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL, R128_PM4_192PIO |
 | |
| 		    R128_PM4_BUFFER_CNTL_NOUPDATE);
 | |
| 		atis->cce_pri_size = 192;
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL,
 | |
| 		    R128_PM4_MICRO_FREERUN);
 | |
| 	}
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ATIPseudoDMAFini(ScreenPtr pScreen)
 | |
| {	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	char *mmio = atic->reg_base;
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, 0);
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIDIS_INDDIS);
 | |
| 	} else {
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL, 0);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
 | |
| 		    R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
 | |
| 	}
 | |
| 	atis->cce_pri_size = 0;
 | |
| 
 | |
| 	ATIEngineReset(atis);
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ATIDMAInit(ScreenPtr pScreen, Bool use_agp)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	char *mmio = atic->reg_base;
 | |
| 	int dma_offset;
 | |
| 	CARD32 tmp;
 | |
| 
 | |
| 	/* XXX: Not for radeons.  Yet? */
 | |
| 	if (atic->is_radeon)
 | |
| 		return FALSE;
 | |
| 
 | |
| 	if (use_agp) {
 | |
| 		if (1)
 | |
| 			return FALSE; /* XXX */
 | |
| 		/* Allocate a 1MB AGP space, but only use 128k + 128 for DMA.
 | |
| 		 * XXX: Should use the rest for things like scratch space.
 | |
| 		 */
 | |
| 		if (!ATIInitAGP(pScreen, 1024 * 1024))
 | |
| 			return FALSE;
 | |
| 		atis->ring_addr = atis->agp_addr;
 | |
| 		atis->ring_len = 128 * 1024;
 | |
| 		dma_offset = R128_AGP_OFFSET;
 | |
| 	} else {
 | |
| 		if (1)
 | |
| 			return FALSE; /* XXX */
 | |
| 		/* Allocate a 128K buffer, plus 32 DWORDS to give space for the
 | |
| 		 * R128 ASIC bug workaround.
 | |
| 		 */
 | |
| 		atis->dma_space = KdOffscreenAlloc(pScreen, 128 * 1024 + 128,
 | |
| 		    128, TRUE, NULL, NULL);
 | |
| 		if (atis->dma_space == NULL)
 | |
| 			return FALSE;
 | |
| 		atis->ring_addr = (CARD32 *)(atis->dma_space->offset +
 | |
| 		    pScreenPriv->screen->memory_base);
 | |
| 		atis->ring_len = 128 * 1024;
 | |
| 		dma_offset = atis->dma_space->offset;
 | |
| 	}
 | |
| 
 | |
| 	ATIUploadMicrocode(atis);
 | |
| 	ATIEngineReset(atis);
 | |
| 
 | |
| 	atis->ring_read = 0;
 | |
| 	atis->ring_write = 0;
 | |
| 
 | |
| 	tmp = MMIO_IN32(mmio, ATI_REG_BUS_CNTL);
 | |
| 	MMIO_OUT32(mmio, ATI_REG_BUS_CNTL, tmp & ~ATI_BUS_MASTER_DIS);
 | |
| 
 | |
| 	MMIO_OUT32(mmio, ATI_REG_CCE_RB_BASE, dma_offset);
 | |
| 	MMIO_OUT32(mmio, ATI_REG_CCE_WPTR, atis->ring_write);
 | |
| 	MMIO_OUT32(mmio, ATI_REG_CCE_RPTR, atis->ring_read);
 | |
| 	MMIO_OUT32(mmio, ATI_REG_CCE_RPTR_ADDR, 0 /* XXX? */);
 | |
| 
 | |
| 	if (atic->is_r200) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIBM_INDBM);
 | |
| 		atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
 | |
| 		    R200_CSQ_CNT_PRIMARY_MASK;
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
 | |
| 	} else if (atic->is_radeon) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIBM_INDBM);
 | |
| 		atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
 | |
| 		    RADEON_CSQ_CNT_PRIMARY_MASK;
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
 | |
| 	} else {
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_WM_CNTL,
 | |
| 		    ((R128_WATERMARK_L/4) << R128_WMA_SHIFT) |
 | |
| 		    ((R128_WATERMARK_M/4) << R128_WMB_SHIFT) |
 | |
| 		    ((R128_WATERMARK_N/4) << R128_WMC_SHIFT) |
 | |
| 		    ((R128_WATERMARK_K/64) << R128_WB_WM_SHIFT));
 | |
| 		/* The sample code reads from an undocumneted register
 | |
| 		 * (PM4_BUFFER_ADDR).  Perhaps it's a write posting thing?  Do
 | |
| 		 * a read in case that's it.
 | |
| 		 */
 | |
| 		MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL);
 | |
| 		if (use_agp) {
 | |
| 			/* XXX Magic num */
 | |
| 			MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 1);
 | |
| 			MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
 | |
| 			    ATILog2(atis->ring_len) |
 | |
| 			    R128_PM4_192BM |
 | |
| 			    R128_PM4_BUFFER_CNTL_NOUPDATE);
 | |
| 		} else {
 | |
| 			MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
 | |
| 			    ATILog2(atis->ring_len) |
 | |
| 			    R128_PM4_192BM |
 | |
| 			    R128_PM4_BUFFER_CNTL_NOUPDATE |
 | |
| 			    R128_PM4_IN_FRAME_BUFFER);
 | |
| 		}
 | |
| 		atis->cce_pri_size = 192;
 | |
| 		MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL,
 | |
| 		    R128_PM4_MICRO_FREERUN);
 | |
| 	}
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| ATIDMAFini(ScreenPtr pScreen)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	char *mmio = atic->reg_base;
 | |
| 
 | |
| 	if (atic->is_radeon) {
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, 0);
 | |
| 		MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
 | |
| 		    RADEON_CSQ_PRIDIS_INDDIS);
 | |
| 	} else {
 | |
| 		MMIO_OUT32(mmio, ATI_REG_CCE_WPTR,
 | |
| 		    atis->ring_write | R128_PM4_BUFFER_DL_DONE);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL, 0);
 | |
| 		MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
 | |
| 		    R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
 | |
| 	}
 | |
| 	atis->cce_pri_size = 0;
 | |
| 
 | |
| 	ATIEngineReset(atis);
 | |
| 
 | |
| 	if (atis->using_agp)
 | |
| 		ATIFiniAGP(pScreen);
 | |
| 	else
 | |
| 		KdOffscreenFree(pScreen, atis->dma_space);
 | |
| 
 | |
| 	return TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| ATIDMASetup(ScreenPtr pScreen)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATICardInfo(pScreenPriv);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri)
 | |
| 		ATIDRIDMAStart(atis);
 | |
| #endif /* USE_DRI */
 | |
| 
 | |
| 	if (!atis->using_dri) {
 | |
| 		atis->using_agp = FALSE;
 | |
| 		if (atic->is_agp && ATIDMAInit(pScreen, TRUE)) {
 | |
| 			atis->using_agp = TRUE;
 | |
| 			atis->using_dma = TRUE;
 | |
| 		} else if (ATIDMAInit(pScreen, FALSE)) {
 | |
| 			atis->using_agp = FALSE;
 | |
| 			atis->using_dma = TRUE;
 | |
| 		} else if (ATIPseudoDMAInit(pScreen))
 | |
| 			atis->using_pseudo = TRUE;
 | |
| 		else
 | |
| 			atis->using_pio = TRUE;
 | |
| 	}
 | |
| 
 | |
| 	atis->indirectBuffer = ATIGetDMABuffer(atis);
 | |
| 	if (atis->indirectBuffer == FALSE)
 | |
| 		FatalError("Failed to allocate DMA buffer.\n");
 | |
| 
 | |
| 	if (atis->using_dri)
 | |
| 		ErrorF("Initialized %s DRI DMA\n",
 | |
| 		    atis->using_agp ? "AGP" : "PCI");
 | |
| 	else if (atis->using_dma && atis->using_agp)
 | |
| 		ErrorF("Initialized AGP DMA\n");
 | |
| 	else if (atis->using_dma)
 | |
| 		ErrorF("Initialized framebuffer pseudo-DMA\n");
 | |
| 	else if (atis->using_pseudo)
 | |
| 		ErrorF("Initialized pseudo-DMA\n");
 | |
| 	else if (atis->using_pio)
 | |
| 		ErrorF("Initialized PIO\n");
 | |
| }
 | |
| 
 | |
| void
 | |
| ATIDMATeardown(ScreenPtr pScreen)
 | |
| {
 | |
| 	KdScreenPriv(pScreen);
 | |
| 	ATIScreenInfo(pScreenPriv);
 | |
| 
 | |
| 	ATIWaitIdle(atis);
 | |
| 
 | |
| #ifdef USE_DRI
 | |
| 	if (atis->using_dri)
 | |
| 		ATIDRIDMAStop(atis);
 | |
| #endif /* USE_DRI */
 | |
| 
 | |
| 	if (atis->using_dma)
 | |
| 		ATIDMAFini(pScreen);
 | |
| 
 | |
| 	if (atis->using_pseudo)
 | |
| 		ATIPseudoDMAFini(pScreen);
 | |
| 
 | |
| 	if (atis->using_pio || atis->using_pseudo || atis->using_dma) {
 | |
| 		xfree(atis->indirectBuffer->address);
 | |
| 		xfree(atis->indirectBuffer);
 | |
| 	}
 | |
| 	atis->indirectBuffer = NULL;
 | |
| 
 | |
| 	atis->using_pio = FALSE;
 | |
| 	atis->using_pseudo = FALSE;
 | |
| 	atis->using_dma = FALSE;
 | |
| 	atis->using_agp = FALSE;
 | |
| }
 | |
| 
 |