diff options
-rw-r--r-- | src/radeon_vip.c | 141 |
1 files changed, 139 insertions, 2 deletions
diff --git a/src/radeon_vip.c b/src/radeon_vip.c index 815a098..9f2ae2d 100644 --- a/src/radeon_vip.c +++ b/src/radeon_vip.c @@ -9,6 +9,7 @@ #include "xf86PciInfo.h" #include "generic_bus.h" +#include "theatre_reg.h" #define VIP_NAME "RADEON VIP BUS" #define VIP_TYPE "ATI VIP BUS" @@ -60,6 +61,28 @@ static CARD32 RADEONVIP_idle(GENERIC_BUS_Ptr b) return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; } +static CARD32 RADEONVIP_fifo_idle(GENERIC_BUS_Ptr b, CARD8 channel) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + CARD32 timeout; + + RADEONWaitForIdleMMIO(pScrn); + timeout = INREG(VIPH_TIMEOUT_STAT); + if((timeout & 0x0000000f) & channel) /* lockup ?? */ + { + xf86DrvMsg(b->scrnIndex, X_INFO, "RADEON_fifo_idle\n"); + RADEONWaitForFifo(pScrn, 2); + OUTREG(VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel); + RADEONWaitForIdleMMIO(pScrn); + return (INREG(VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_RESET; + } + RADEONWaitForIdleMMIO(pScrn); + return (INREG(VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; +} + /* address format: ((device & 0x3)<<14) | (fifo << 12) | (addr) */ @@ -130,6 +153,80 @@ static Bool RADEONVIP_read(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CARD return TRUE; } +static Bool RADEONVIP_fifo_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) + { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Attempt to access VIP bus with non-stadard transaction length\n"); + return FALSE; + } + + RADEONWaitForFifo(pScrn, 2); + OUTREG(VIPH_REG_ADDR, address | 0x3000); + write_mem_barrier(); + while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); + if(VIP_IDLE != status) return FALSE; + +/* + disable VIPH_REGR_DIS to enable VIP cycle. + The LSB of VIPH_TIMEOUT_STAT are set to 0 + because 1 would have acknowledged various VIP + interrupts unexpectedly +*/ + + RADEONWaitForIdleMMIO(pScrn); + OUTREG(VIPH_TIMEOUT_STAT, INREG(VIPH_TIMEOUT_STAT) & (0xffffff00 & ~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(VIPH_REG_DATA); + + while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); + if(VIP_IDLE != status) return FALSE; + +/* + set VIPH_REGR_DIS so that the read won't take too long. +*/ + RADEONWaitForIdleMMIO(pScrn); + tmp=INREG(VIPH_TIMEOUT_STAT); + OUTREG(VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); + write_mem_barrier(); + + RADEONWaitForIdleMMIO(pScrn); + switch(count){ + case 1: + *buffer=(CARD8)(INREG(VIPH_REG_DATA) & 0xff); + break; + case 2: + *(CARD16 *)buffer=(CARD16) (INREG(VIPH_REG_DATA) & 0xffff); + break; + case 4: + *(CARD32 *)buffer=(CARD32) ( INREG(VIPH_REG_DATA) & 0xffffffff); + break; + } + while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); + if(VIP_IDLE != status) return FALSE; + + /* + so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles. +*/ + OUTREG(VIPH_TIMEOUT_STAT, (INREG(VIPH_TIMEOUT_STAT) & 0xffffff00) | 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]; @@ -163,6 +260,41 @@ static Bool RADEONVIP_write(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CAR return TRUE; } +static Bool RADEONVIP_fifo_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; + CARD32 i; + + RADEONWaitForFifo(pScrn, 2); + OUTREG(VIPH_REG_ADDR, (address & (~0x2000)) | 0x1000); + while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0x0f))); + + + if(VIP_IDLE != status){ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "cannot write %x to VIPH_REG_ADDR\n", (unsigned int)address); + return FALSE; + } + + RADEONWaitForFifo(pScrn, 2); + for (i = 0; i < count; i+=4) + { + OUTREG(VIPH_REG_DATA, *(CARD32*)(buffer + i)); + write_mem_barrier(); + while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0x0f))); + if(VIP_IDLE != status) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "cannot write to VIPH_REG_DATA\n"); + return FALSE; + } + } + + return TRUE; +} + void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -171,7 +303,10 @@ void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) RADEONWaitForIdleMMIO(pScrn); switch(info->ChipFamily){ - case CHIP_FAMILY_RV250: + case CHIP_FAMILY_RV250: + case CHIP_FAMILY_RV350: + case CHIP_FAMILY_R350: + case CHIP_FAMILY_R300: 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 */ @@ -195,6 +330,8 @@ void RADEONVIP_init(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) pPriv->VIP->ioctl=RADEONVIP_ioctl; pPriv->VIP->read=RADEONVIP_read; pPriv->VIP->write=RADEONVIP_write; - + pPriv->VIP->fifo_read=RADEONVIP_fifo_read; + pPriv->VIP->fifo_write=RADEONVIP_fifo_write; + RADEONVIP_reset(pScrn, pPriv); } |