summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/radeon_vip.c141
1 files changed, 139 insertions, 2 deletions
diff --git a/src/radeon_vip.c b/src/radeon_vip.c
index 815a098d..9f2ae2d4 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);
}