📄 radeon_vip.c
字号:
#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#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 2static 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -