#include "radeon.h" #include "radeon_macros.h" #include "radeon_probe.h" #include "radeon_reg.h" #include "Xv.h" #include "radeon_video.h" #include "xf86.h" #include "xf86PciInfo.h" #include "generic_bus.h" #define VIP_NAME "RADEON VIP BUS" #define VIP_TYPE "ATI VIP BUS" /* Status defines */ #define VIP_BUSY 0 #define VIP_IDLE 1 #define VIP_RESET 2 static Bool RADEONVIP_ioctl(GENERIC_BUS_Ptr b, long ioctl, long arg1, char *arg2) { long count; switch(ioctl){ case GB_IOCTL_GET_NAME: count=strlen(VIP_NAME)+1; if(count>arg1)return FALSE; memcpy(arg2,VIP_NAME,count); return TRUE; case GB_IOCTL_GET_TYPE: count=strlen(VIP_TYPE)+1; if(count>arg1)return FALSE; memcpy(arg2,VIP_TYPE,count); return TRUE; default: return FALSE; } } static CARD32 RADEONVIP_idle(GENERIC_BUS_Ptr b) { ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 timeout; RADEONWaitForIdleMMIO(pScrn); timeout = INREG(RADEON_VIPH_TIMEOUT_STAT); if(timeout & RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT) /* lockup ?? */ { RADEONWaitForFifo(pScrn, 2); OUTREG(RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK); RADEONWaitForIdleMMIO(pScrn); return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_RESET; } RADEONWaitForIdleMMIO(pScrn); return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; } /* address format: ((device & 0x3)<<14) | (fifo << 12) | (addr) */ static Bool RADEONVIP_read(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CARD8 *buffer) { ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 status,tmp; if((count!=1) && (count!=2) && (count!=4)) { xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Attempt to access VIP bus with non-stadard transaction length\n"); return FALSE; } RADEONWaitForFifo(pScrn, 2); OUTREG(RADEON_VIPH_REG_ADDR, address | 0x2000); write_mem_barrier(); while(VIP_BUSY == (status = RADEONVIP_idle(b))); if(VIP_IDLE != status) return FALSE; /* disable RADEON_VIPH_REGR_DIS to enable VIP cycle. The LSB of RADEON_VIPH_TIMEOUT_STAT are set to 0 because 1 would have acknowledged various VIP interrupts unexpectedly */ RADEONWaitForIdleMMIO(pScrn); OUTREG(RADEON_VIPH_TIMEOUT_STAT, INREG(RADEON_VIPH_TIMEOUT_STAT) & (0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS) ); write_mem_barrier(); /* the value returned here is garbage. The read merely initiates a register cycle */ RADEONWaitForIdleMMIO(pScrn); INREG(RADEON_VIPH_REG_DATA); while(VIP_BUSY == (status = RADEONVIP_idle(b))); if(VIP_IDLE != status) return FALSE; /* set RADEON_VIPH_REGR_DIS so that the read won't take too long. */ RADEONWaitForIdleMMIO(pScrn); tmp=INREG(RADEON_VIPH_TIMEOUT_STAT); OUTREG(RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); write_mem_barrier(); RADEONWaitForIdleMMIO(pScrn); switch(count){ case 1: *buffer=(CARD8)(INREG(RADEON_VIPH_REG_DATA) & 0xff); break; case 2: *(CARD16 *)buffer=(CARD16) (INREG(RADEON_VIPH_REG_DATA) & 0xffff); break; case 4: *(CARD32 *)buffer=(CARD32) ( INREG(RADEON_VIPH_REG_DATA) & 0xffffffff); break; } while(VIP_BUSY == (status = RADEONVIP_idle(b))); if(VIP_IDLE != status) return FALSE; /* so that reading RADEON_VIPH_REG_DATA would not trigger unnecessary vip cycles. */ OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); write_mem_barrier(); return TRUE; } static Bool RADEONVIP_write(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CARD8 *buffer) { ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 status; if((count!=4)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to access VIP bus with non-stadard transaction length\n"); return FALSE; } RADEONWaitForFifo(pScrn, 2); OUTREG(RADEON_VIPH_REG_ADDR, address & (~0x2000)); while(VIP_BUSY == (status = RADEONVIP_idle(b))); if(VIP_IDLE != status) return FALSE; RADEONWaitForFifo(pScrn, 2); switch(count){ case 4: OUTREG(RADEON_VIPH_REG_DATA, *(CARD32 *)buffer); break; } write_mem_barrier(); while(VIP_BUSY == (status = RADEONVIP_idle(b))); if(VIP_IDLE != status) return FALSE; return TRUE; } void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; RADEONWaitForIdleMMIO(pScrn); switch(info->ChipFamily){ case CHIP_FAMILY_RV250: OUTREG(RADEON_VIPH_CONTROL, 0x003F0009); /* slowest, timeout in 16 phases */ OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ OUTREG(RADEON_VIPH_BM_CHUNK, 0x0); OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); break; default: OUTREG(RADEON_VIPH_CONTROL, 0x003F0004); /* slowest, timeout in 16 phases */ OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ OUTREG(RADEON_VIPH_BM_CHUNK, 0x151); OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); } } void RADEONVIP_init(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) { pPriv->VIP=xcalloc(1,sizeof(GENERIC_BUS_Rec)); pPriv->VIP->scrnIndex=pScrn->scrnIndex; pPriv->VIP->DriverPrivate.ptr=pPriv; pPriv->VIP->ioctl=RADEONVIP_ioctl; pPriv->VIP->read=RADEONVIP_read; pPriv->VIP->write=RADEONVIP_write; RADEONVIP_reset(pScrn, pPriv); }