|
|
|
@@ -21,6 +21,7 @@
|
|
|
|
|
|
|
|
|
|
// moved to bottom to avoid inlining
|
|
|
|
|
static bool Radeon_VIPWaitForIdle( device_info *di );
|
|
|
|
|
static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read data from VIP
|
|
|
|
@@ -84,6 +85,96 @@ bool Radeon_VIPRead(
|
|
|
|
|
ACQUIRE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
res = do_VIPRead( di, channel, address, data );
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
RELEASE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
// SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool do_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
|
|
|
|
|
{
|
|
|
|
|
vuint8 *regs = di->regs;
|
|
|
|
|
uint32 status, tmp;
|
|
|
|
|
|
|
|
|
|
if(count!=1)
|
|
|
|
|
{
|
|
|
|
|
SHOW_FLOW0( 2, "Attempt to access VIP bus with non-stadard transaction length\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SHOW_FLOW( 2, "address=%lx, count=%ld ", address, count );
|
|
|
|
|
|
|
|
|
|
Radeon_WaitForFifo( di, 2);
|
|
|
|
|
SHOW_FLOW0( 2, "1");
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x3000);
|
|
|
|
|
SHOW_FLOW0( 2, "3");
|
|
|
|
|
while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
|
|
|
|
|
if(B_OK != 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
|
|
|
|
|
|
|
|
|
|
SHOW_FLOW0( 2, "4");
|
|
|
|
|
Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
SHOW_FLOW0( 2, "5");
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
|
|
|
|
|
INREG( regs, RADEON_VIPH_TIMEOUT_STAT) &
|
|
|
|
|
(0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS) );
|
|
|
|
|
|
|
|
|
|
// the value returned here is garbage. The read merely initiates
|
|
|
|
|
// a register cycle
|
|
|
|
|
SHOW_FLOW0( 2, "6");
|
|
|
|
|
Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
INREG( regs, RADEON_VIPH_REG_DATA);
|
|
|
|
|
SHOW_FLOW0( 2, "7");
|
|
|
|
|
while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
|
|
|
|
|
if(B_OK != status) return false;
|
|
|
|
|
|
|
|
|
|
// set VIPH_REGR_DIS so that the read won't take too long.
|
|
|
|
|
SHOW_FLOW0( 2, "8");
|
|
|
|
|
Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
SHOW_FLOW0( 2, "9");
|
|
|
|
|
tmp = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
|
|
|
|
|
|
|
|
|
|
SHOW_FLOW0( 2, "10");
|
|
|
|
|
Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
switch(count){
|
|
|
|
|
case 1:
|
|
|
|
|
*buffer=(uint8)(INREG( regs, RADEON_VIPH_REG_DATA) & 0xff);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
*(uint16 *)buffer=(uint16) (INREG( regs, RADEON_VIPH_REG_DATA) & 0xffff);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
*(uint32 *)buffer=(uint32) ( INREG( regs, RADEON_VIPH_REG_DATA) & 0xffffffff);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
SHOW_FLOW0( 2, "11");
|
|
|
|
|
while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
|
|
|
|
|
if(B_OK != status) return false;
|
|
|
|
|
|
|
|
|
|
// so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles.
|
|
|
|
|
SHOW_FLOW0( 2, "12");
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
|
|
|
|
|
(INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
|
|
|
|
|
{
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
ACQUIRE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
res = do_VIPFifoRead( di, channel, address, count, buffer );
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
RELEASE_BEN( di->si->cp.lock );
|
|
|
|
@@ -95,31 +186,26 @@ bool Radeon_VIPRead(
|
|
|
|
|
|
|
|
|
|
// write data to VIP
|
|
|
|
|
// CP must be hold
|
|
|
|
|
static bool do_VIPWrite(
|
|
|
|
|
device_info *di, uint8 channel, uint address, uint32 data )
|
|
|
|
|
static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
|
|
|
|
|
{
|
|
|
|
|
vuint8 *regs = di->regs;
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
|
Radeon_WaitForFifo( di, 2 );
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
|
|
|
|
|
|
|
|
|
|
if( !Radeon_VIPWaitForIdle( di ))
|
|
|
|
|
return false;
|
|
|
|
|
if( !Radeon_VIPWaitForIdle( di )) return false;
|
|
|
|
|
|
|
|
|
|
//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
|
|
|
|
|
|
|
|
|
|
Radeon_WaitForFifo( di, 2 );
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_REG_DATA, data );
|
|
|
|
|
|
|
|
|
|
res = Radeon_VIPWaitForIdle( di );
|
|
|
|
|
return Radeon_VIPWaitForIdle( di );
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// public function: write data to VIP
|
|
|
|
|
bool Radeon_VIPWrite(
|
|
|
|
|
device_info *di, uint8 channel, uint address, uint32 data, bool lock )
|
|
|
|
|
bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
|
|
|
|
|
{
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
@@ -137,8 +223,64 @@ bool Radeon_VIPWrite(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool do_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
|
|
|
|
|
{
|
|
|
|
|
vuint8 *regs = di->regs;
|
|
|
|
|
|
|
|
|
|
uint32 status;
|
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
|
|
SHOW_FLOW( 2, "address=%lx, count=%ld, ", address, count );
|
|
|
|
|
|
|
|
|
|
Radeon_WaitForFifo( di, 2 );
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_REG_ADDR, ((channel << 14) | address | 0x1000) & ~0x2000 );
|
|
|
|
|
SHOW_FLOW0( 2, "1");
|
|
|
|
|
while(B_BUSY == (status = RADEON_VIPFifoIdle( di, 0x0f)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(B_OK != status){
|
|
|
|
|
SHOW_FLOW( 2 ,"cannot write %x to VIPH_REG_ADDR\n", (unsigned int)address);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SHOW_FLOW0( 2, "2");
|
|
|
|
|
for (i = 0; i < count; i+=4)
|
|
|
|
|
{
|
|
|
|
|
Radeon_WaitForFifo( di, 2);
|
|
|
|
|
SHOW_FLOW( 2, "count %ld", count);
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_REG_DATA, *(uint32*)(buffer + i));
|
|
|
|
|
while(B_BUSY == (status = RADEON_VIPFifoIdle( di, 0x0f)));
|
|
|
|
|
if(B_OK != status)
|
|
|
|
|
{
|
|
|
|
|
SHOW_FLOW0( 2 , "cannot write to VIPH_REG_DATA\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
|
|
|
|
|
{
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
|
//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
ACQUIRE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
Radeon_VIPReset( di, false);
|
|
|
|
|
res = do_VIPFifoWrite( di, channel, address, count, buffer );
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
RELEASE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// reset VIP
|
|
|
|
|
static void VIPReset(
|
|
|
|
|
void Radeon_VIPReset(
|
|
|
|
|
device_info *di, bool lock )
|
|
|
|
|
{
|
|
|
|
|
vuint8 *regs = di->regs;
|
|
|
|
@@ -146,27 +288,43 @@ static void VIPReset(
|
|
|
|
|
if( lock )
|
|
|
|
|
ACQUIRE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
Radeon_WaitForFifo( di, 5 );
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_CONTROL,
|
|
|
|
|
4 |
|
|
|
|
|
(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
|
|
|
|
|
RADEON_VIPH_CONTROL_VIPH_DMA_MODE |
|
|
|
|
|
RADEON_VIPH_CONTROL_VIPH_EN );
|
|
|
|
|
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
|
|
|
|
|
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DV_LAT,
|
|
|
|
|
0xff |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT));
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DMA_CHUNK,
|
|
|
|
|
1 |
|
|
|
|
|
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH1_CHUNK_SHIFT) |
|
|
|
|
|
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH2_CHUNK_SHIFT) |
|
|
|
|
|
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH3_CHUNK_SHIFT));
|
|
|
|
|
OUTREGP( regs, RADEON_TEST_DEBUG_CNTL, 0, ~RADEON_TEST_DEBUG_CNTL_OUT_EN );
|
|
|
|
|
Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
switch(di->asic){
|
|
|
|
|
case rt_r200:
|
|
|
|
|
case rt_rs200:
|
|
|
|
|
case rt_rv200:
|
|
|
|
|
case rt_rs100:
|
|
|
|
|
case rt_rv100:
|
|
|
|
|
case rt_r100:
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_CONTROL, 4 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
|
|
|
|
|
RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
|
|
|
|
|
RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DV_LAT,
|
|
|
|
|
0xff |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
|
|
|
|
|
OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
|
|
|
|
|
default:
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_CONTROL, 9 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
|
|
|
|
|
RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
|
|
|
|
|
RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DV_LAT,
|
|
|
|
|
0xff |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
|
|
|
|
|
(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x0);
|
|
|
|
|
OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( lock )
|
|
|
|
|
RELEASE_BEN( di->si->cp.lock );
|
|
|
|
|
}
|
|
|
|
@@ -184,25 +342,30 @@ static status_t Radeon_VIPIdle(
|
|
|
|
|
|
|
|
|
|
// if there is a stuck transaction, acknowledge that
|
|
|
|
|
timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
|
|
|
|
|
if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 ) {
|
|
|
|
|
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT,
|
|
|
|
|
RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK,
|
|
|
|
|
~RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK & ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK );
|
|
|
|
|
if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
|
|
|
|
|
return B_BUSY;
|
|
|
|
|
else
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
|
|
|
|
|
{
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
|
|
|
|
|
(timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
|
|
|
|
|
return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Radeon_WaitForIdle( di, false, false );
|
|
|
|
|
|
|
|
|
|
if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
|
|
|
|
|
return B_BUSY;
|
|
|
|
|
else
|
|
|
|
|
return B_OK;
|
|
|
|
|
return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel)
|
|
|
|
|
{
|
|
|
|
|
vuint8 *regs = di->regs;
|
|
|
|
|
uint32 timeout;
|
|
|
|
|
|
|
|
|
|
timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
|
|
|
|
|
if((timeout & 0x0000000f) & channel) /* lockup ?? */
|
|
|
|
|
{
|
|
|
|
|
OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel);
|
|
|
|
|
return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// wait until VIP host is idle
|
|
|
|
|
// lock must be hold
|
|
|
|
|
static bool Radeon_VIPWaitForIdle(
|
|
|
|
@@ -240,23 +403,28 @@ int Radeon_FindVIPDevice(
|
|
|
|
|
|
|
|
|
|
// if card has no VIP port, let hardware detection fail;
|
|
|
|
|
// in this case, noone will bother us again
|
|
|
|
|
if( !di->has_vip )
|
|
|
|
|
if( !di->has_vip ) {
|
|
|
|
|
SHOW_FLOW0( 3, "This Device has no VIP Bus.");
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ACQUIRE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
VIPReset( di, false );
|
|
|
|
|
Radeon_VIPReset( di, false );
|
|
|
|
|
|
|
|
|
|
// there are up to 4 devices, connected to one of 4 channels
|
|
|
|
|
for( channel = 0; channel < 4; ++channel ) {
|
|
|
|
|
|
|
|
|
|
// read device id
|
|
|
|
|
if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false ))
|
|
|
|
|
if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false )) {
|
|
|
|
|
SHOW_FLOW( 3, "No device found on channel %d", channel);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// compare device id directly
|
|
|
|
|
if( cur_device_id == device_id ) {
|
|
|
|
|
SHOW_FLOW( 3, "Device %08lx found on channel %d", device_id, channel);
|
|
|
|
|
RELEASE_BEN( di->si->cp.lock );
|
|
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|