radeon_vip.c revision 68105dcb
1#ifdef HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <string.h> 6 7#include "radeon.h" 8#include "radeon_reg.h" 9#include "radeon_macros.h" 10#include "radeon_probe.h" 11#include <X11/extensions/Xv.h> 12#include "radeon_video.h" 13 14#include "xf86.h" 15#include "atipciids.h" 16 17#include "generic_bus.h" 18#include "theatre_reg.h" 19 20#define VIP_NAME "RADEON VIP BUS" 21#define VIP_TYPE "ATI VIP BUS" 22 23/* Status defines */ 24#define VIP_BUSY 0 25#define VIP_IDLE 1 26#define VIP_RESET 2 27 28static Bool RADEONVIP_ioctl(GENERIC_BUS_Ptr b, long ioctl, long arg1, char *arg2) 29{ 30 long count; 31 switch(ioctl){ 32 case GB_IOCTL_GET_NAME: 33 count=strlen(VIP_NAME)+1; 34 if(count>arg1)return FALSE; 35 memcpy(arg2,VIP_NAME,count); 36 return TRUE; 37 38 case GB_IOCTL_GET_TYPE: 39 count=strlen(VIP_TYPE)+1; 40 if(count>arg1)return FALSE; 41 memcpy(arg2,VIP_TYPE,count); 42 return TRUE; 43 44 default: 45 return FALSE; 46 } 47} 48 49static uint32_t RADEONVIP_idle(GENERIC_BUS_Ptr b) 50{ 51 ScrnInfoPtr pScrn = b->pScrn; 52 RADEONInfoPtr info = RADEONPTR(pScrn); 53 unsigned char *RADEONMMIO = info->MMIO; 54 55 uint32_t timeout; 56 57 RADEONWaitForIdleMMIO(pScrn); 58 timeout = INREG(RADEON_VIPH_TIMEOUT_STAT); 59 if(timeout & RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT) /* lockup ?? */ 60 { 61 RADEONWaitForFifo(pScrn, 2); 62 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK); 63 RADEONWaitForIdleMMIO(pScrn); 64 return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_RESET; 65 } 66 RADEONWaitForIdleMMIO(pScrn); 67 return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; 68} 69 70static uint32_t RADEONVIP_fifo_idle(GENERIC_BUS_Ptr b, uint8_t channel) 71{ 72 ScrnInfoPtr pScrn = b->pScrn; 73 RADEONInfoPtr info = RADEONPTR(pScrn); 74 unsigned char *RADEONMMIO = info->MMIO; 75 76 uint32_t timeout; 77 78 RADEONWaitForIdleMMIO(pScrn); 79 timeout = INREG(VIPH_TIMEOUT_STAT); 80 if((timeout & 0x0000000f) & channel) /* lockup ?? */ 81 { 82 xf86DrvMsg(b->pScrn->scrnIndex, X_INFO, "RADEON_fifo_idle\n"); 83 RADEONWaitForFifo(pScrn, 2); 84 OUTREG(VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel); 85 RADEONWaitForIdleMMIO(pScrn); 86 return (INREG(VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_RESET; 87 } 88 RADEONWaitForIdleMMIO(pScrn); 89 return (INREG(VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; 90} 91 92/* address format: 93 ((device & 0x3)<<14) | (fifo << 12) | (addr) 94*/ 95 96#define VIP_WAIT_FOR_IDLE() { \ 97 int i2ctries = 0; \ 98 while (i2ctries < 10) { \ 99 status = RADEONVIP_idle(b); \ 100 if (status==VIP_BUSY) \ 101 { \ 102 usleep(1000); \ 103 i2ctries++; \ 104 } else break; \ 105 } \ 106 } 107 108static Bool RADEONVIP_read(GENERIC_BUS_Ptr b, uint32_t address, uint32_t count, uint8_t *buffer) 109{ 110 ScrnInfoPtr pScrn = b->pScrn; 111 RADEONInfoPtr info = RADEONPTR(pScrn); 112 unsigned char *RADEONMMIO = info->MMIO; 113 uint32_t status,tmp; 114 115 if((count!=1) && (count!=2) && (count!=4)) 116 { 117 xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Attempt to access VIP bus with non-stadard transaction length\n"); 118 return FALSE; 119 } 120 121 RADEONWaitForFifo(pScrn, 2); 122 OUTREG(RADEON_VIPH_REG_ADDR, address | 0x2000); 123 write_mem_barrier(); 124 VIP_WAIT_FOR_IDLE(); 125 if(VIP_IDLE != status) return FALSE; 126 127/* 128 disable RADEON_VIPH_REGR_DIS to enable VIP cycle. 129 The LSB of RADEON_VIPH_TIMEOUT_STAT are set to 0 130 because 1 would have acknowledged various VIP 131 interrupts unexpectedly 132*/ 133 RADEONWaitForIdleMMIO(pScrn); 134 OUTREG(RADEON_VIPH_TIMEOUT_STAT, INREG(RADEON_VIPH_TIMEOUT_STAT) & (0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS) ); 135 write_mem_barrier(); 136/* 137 the value returned here is garbage. The read merely initiates 138 a register cycle 139*/ 140 RADEONWaitForIdleMMIO(pScrn); 141 INREG(RADEON_VIPH_REG_DATA); 142 143 VIP_WAIT_FOR_IDLE(); 144 if(VIP_IDLE != status) return FALSE; 145/* 146 set RADEON_VIPH_REGR_DIS so that the read won't take too long. 147*/ 148 RADEONWaitForIdleMMIO(pScrn); 149 tmp=INREG(RADEON_VIPH_TIMEOUT_STAT); 150 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 151 write_mem_barrier(); 152 RADEONWaitForIdleMMIO(pScrn); 153 switch(count){ 154 case 1: 155 *buffer=(uint8_t)(INREG(RADEON_VIPH_REG_DATA) & 0xff); 156 break; 157 case 2: 158 *(uint16_t *)buffer=(uint16_t) (INREG(RADEON_VIPH_REG_DATA) & 0xffff); 159 break; 160 case 4: 161 *(uint32_t *)buffer=(uint32_t) ( INREG(RADEON_VIPH_REG_DATA) & 0xffffffff); 162 break; 163 } 164 VIP_WAIT_FOR_IDLE(); 165 if(VIP_IDLE != status) return FALSE; 166 /* 167 so that reading RADEON_VIPH_REG_DATA would not trigger unnecessary vip cycles. 168*/ 169 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 170 write_mem_barrier(); 171 return TRUE; 172} 173 174static Bool RADEONVIP_fifo_read(GENERIC_BUS_Ptr b, uint32_t address, uint32_t count, uint8_t *buffer) 175{ 176 ScrnInfoPtr pScrn = b->pScrn; 177 RADEONInfoPtr info = RADEONPTR(pScrn); 178 unsigned char *RADEONMMIO = info->MMIO; 179 uint32_t status,tmp; 180 181 if(count!=1) 182 { 183 xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Attempt to access VIP bus with non-stadard transaction length\n"); 184 return FALSE; 185 } 186 187 RADEONWaitForFifo(pScrn, 2); 188 OUTREG(VIPH_REG_ADDR, address | 0x3000); 189 write_mem_barrier(); 190 while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); 191 if(VIP_IDLE != status) return FALSE; 192 193/* 194 disable VIPH_REGR_DIS to enable VIP cycle. 195 The LSB of VIPH_TIMEOUT_STAT are set to 0 196 because 1 would have acknowledged various VIP 197 interrupts unexpectedly 198*/ 199 200 RADEONWaitForIdleMMIO(pScrn); 201 OUTREG(VIPH_TIMEOUT_STAT, INREG(VIPH_TIMEOUT_STAT) & (0xffffff00 & ~VIPH_TIMEOUT_STAT__VIPH_REGR_DIS) ); 202 write_mem_barrier(); 203 204/* 205 the value returned here is garbage. The read merely initiates 206 a register cycle 207*/ 208 RADEONWaitForIdleMMIO(pScrn); 209 INREG(VIPH_REG_DATA); 210 211 while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); 212 if(VIP_IDLE != status) return FALSE; 213 214/* 215 set VIPH_REGR_DIS so that the read won't take too long. 216*/ 217 RADEONWaitForIdleMMIO(pScrn); 218 tmp=INREG(VIPH_TIMEOUT_STAT); 219 OUTREG(VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 220 write_mem_barrier(); 221 222 RADEONWaitForIdleMMIO(pScrn); 223 switch(count){ 224 case 1: 225 *buffer=(uint8_t)(INREG(VIPH_REG_DATA) & 0xff); 226 break; 227 case 2: 228 *(uint16_t *)buffer=(uint16_t) (INREG(VIPH_REG_DATA) & 0xffff); 229 break; 230 case 4: 231 *(uint32_t *)buffer=(uint32_t) ( INREG(VIPH_REG_DATA) & 0xffffffff); 232 break; 233 } 234 while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0xff))); 235 if(VIP_IDLE != status) return FALSE; 236 237 /* 238 so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles. 239*/ 240 OUTREG(VIPH_TIMEOUT_STAT, (INREG(VIPH_TIMEOUT_STAT) & 0xffffff00) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 241 write_mem_barrier(); 242 return TRUE; 243 244 245} 246 247 248static Bool RADEONVIP_write(GENERIC_BUS_Ptr b, uint32_t address, uint32_t count, uint8_t *buffer) 249{ 250 ScrnInfoPtr pScrn = b->pScrn; 251 RADEONInfoPtr info = RADEONPTR(pScrn); 252 unsigned char *RADEONMMIO = info->MMIO; 253 254 uint32_t status; 255 256 257 if((count!=4)) 258 { 259 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to access VIP bus with non-stadard transaction length\n"); 260 return FALSE; 261 } 262 263 RADEONWaitForFifo(pScrn, 2); 264 OUTREG(RADEON_VIPH_REG_ADDR, address & (~0x2000)); 265 while(VIP_BUSY == (status = RADEONVIP_idle(b))); 266 267 if(VIP_IDLE != status) return FALSE; 268 269 RADEONWaitForFifo(pScrn, 2); 270 switch(count){ 271 case 4: 272 OUTREG(RADEON_VIPH_REG_DATA, *(uint32_t *)buffer); 273 break; 274 } 275 write_mem_barrier(); 276 while(VIP_BUSY == (status = RADEONVIP_idle(b))); 277 if(VIP_IDLE != status) return FALSE; 278 return TRUE; 279} 280 281static Bool RADEONVIP_fifo_write(GENERIC_BUS_Ptr b, uint32_t address, uint32_t count, uint8_t *buffer) 282{ 283 ScrnInfoPtr pScrn = b->pScrn; 284 RADEONInfoPtr info = RADEONPTR(pScrn); 285 unsigned char *RADEONMMIO = info->MMIO; 286 287 uint32_t status; 288 uint32_t i; 289 290 RADEONWaitForFifo(pScrn, 2); 291 OUTREG(VIPH_REG_ADDR, (address & (~0x2000)) | 0x1000); 292 while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0x0f))); 293 294 295 if(VIP_IDLE != status){ 296 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "cannot write %x to VIPH_REG_ADDR\n", (unsigned int)address); 297 return FALSE; 298 } 299 300 RADEONWaitForFifo(pScrn, 2); 301 for (i = 0; i < count; i+=4) 302 { 303 OUTREG(VIPH_REG_DATA, *(uint32_t*)(buffer + i)); 304 write_mem_barrier(); 305 while(VIP_BUSY == (status = RADEONVIP_fifo_idle(b, 0x0f))); 306 if(VIP_IDLE != status) 307 { 308 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "cannot write to VIPH_REG_DATA\n"); 309 return FALSE; 310 } 311 } 312 313 return TRUE; 314} 315 316void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) 317{ 318 RADEONInfoPtr info = RADEONPTR(pScrn); 319 unsigned char *RADEONMMIO = info->MMIO; 320 321 322 RADEONWaitForIdleMMIO(pScrn); 323 switch(info->ChipFamily){ 324 case CHIP_FAMILY_RV250: 325 case CHIP_FAMILY_RV350: 326 case CHIP_FAMILY_R350: 327 case CHIP_FAMILY_R300: 328 OUTREG(RADEON_VIPH_CONTROL, 0x003F0009); /* slowest, timeout in 16 phases */ 329 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 330 OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ 331 OUTREG(RADEON_VIPH_BM_CHUNK, 0x0); 332 OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); 333 break; 334 case CHIP_FAMILY_RV380: 335 OUTREG(RADEON_VIPH_CONTROL, 0x003F000D); /* slowest, timeout in 16 phases */ 336 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 337 OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ 338 OUTREG(RADEON_VIPH_BM_CHUNK, 0x0); 339 OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); 340 break; 341 default: 342 OUTREG(RADEON_VIPH_CONTROL, 0x003F0004); /* slowest, timeout in 16 phases */ 343 OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); 344 OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ 345 OUTREG(RADEON_VIPH_BM_CHUNK, 0x151); 346 OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); 347 } 348} 349 350void RADEONVIP_init(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) 351{ 352 pPriv->VIP=calloc(1,sizeof(GENERIC_BUS_Rec)); 353 pPriv->VIP->pScrn=pScrn; 354 pPriv->VIP->DriverPrivate.ptr=pPriv; 355 pPriv->VIP->ioctl=RADEONVIP_ioctl; 356 pPriv->VIP->read=RADEONVIP_read; 357 pPriv->VIP->write=RADEONVIP_write; 358 pPriv->VIP->fifo_read=RADEONVIP_fifo_read; 359 pPriv->VIP->fifo_write=RADEONVIP_fifo_write; 360 361 RADEONVIP_reset(pScrn, pPriv); 362} 363