summaryrefslogtreecommitdiff
path: root/src/radeon_vip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_vip.c')
-rw-r--r--src/radeon_vip.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/radeon_vip.c b/src/radeon_vip.c
new file mode 100644
index 0000000..b61adfe
--- /dev/null
+++ b/src/radeon_vip.c
@@ -0,0 +1,353 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "radeon.h"
+#include "radeon_reg.h"
+#include "radeon_macros.h"
+#include "radeon_probe.h"
+#include <X11/extensions/Xv.h>
+#include "radeon_video.h"
+
+#include "xf86.h"
+#include "atipciids.h"
+
+#include "generic_bus.h"
+#include "theatre_reg.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 ;
+}
+
+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)
+*/
+
+#define VIP_WAIT_FOR_IDLE() { \
+ int i2ctries = 0; \
+ while (i2ctries < 10) { \
+ status = RADEONVIP_idle(b); \
+ if (status==VIP_BUSY) \
+ { \
+ usleep(1000); \
+ i2ctries++; \
+ } else break; \
+ } \
+ }
+
+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();
+ VIP_WAIT_FOR_IDLE();
+ 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);
+
+ VIP_WAIT_FOR_IDLE();
+ 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;
+ }
+ VIP_WAIT_FOR_IDLE();
+ 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_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];
+ 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;
+}
+
+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);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+
+ RADEONWaitForIdleMMIO(pScrn);
+ switch(info->ChipFamily){
+ 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 */
+ 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;
+ pPriv->VIP->fifo_read=RADEONVIP_fifo_read;
+ pPriv->VIP->fifo_write=RADEONVIP_fifo_write;
+
+ RADEONVIP_reset(pScrn, pPriv);
+}