Patch by Euan Kirkhope:

* VIP FIFO functions for Rage Theater200 support


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20278 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-03-01 09:43:33 +00:00
parent 0caeca2af7
commit 7ce2eaa1e0
5 changed files with 285 additions and 53 deletions

View File

@ -20,8 +20,8 @@
#include "ddc.h" #include "ddc.h"
// magic code for ioctls // magic code for ioctls
// changed from TKRA to TKR1 for RADEON_WAITFORFIFO ioctl // changed from TKRA to TKR2 for VIP FIFO ioctls
#define RADEON_PRIVATE_DATA_MAGIC 'TKR1' #define RADEON_PRIVATE_DATA_MAGIC 'TKR2'
#define MAX_RADEON_DEVICE_NAME_LENGTH MAXPATHLEN #define MAX_RADEON_DEVICE_NAME_LENGTH MAXPATHLEN
@ -40,7 +40,10 @@ enum {
RADEON_RESETENGINE, RADEON_RESETENGINE,
RADEON_VIPREAD, RADEON_VIPREAD,
RADEON_VIPWRITE, RADEON_VIPWRITE,
RADEON_VIPFIFOREAD,
RADEON_VIPFIFOWRITE,
RADEON_FINDVIPDEVICE, RADEON_FINDVIPDEVICE,
RADEON_VIPRESET,
RADEON_WAIT_FOR_CAP_IRQ, RADEON_WAIT_FOR_CAP_IRQ,
RADEON_DMACOPY, RADEON_DMACOPY,
@ -633,6 +636,26 @@ typedef struct {
bool lock; // true, if CP lock must be acquired bool lock; // true, if CP lock must be acquired
} radeon_vip_write; } radeon_vip_write;
// read VIP fifo
typedef struct {
uint32 magic;
uint channel; // channel, i.e. device
uint address; // address
uint32 count; // size of buffer
uint8 *data; // read data
bool lock; // true, if CP lock must be acquired
} radeon_vip_fifo_read;
// write VIP fifo
typedef struct {
uint32 magic;
uint channel; // channel, i.e. device
uint address; // address
uint32 count; // size of buffer
uint8 *data; // data to write
bool lock; // true, if CP lock must be acquired
} radeon_vip_fifo_write;
// find channel of device with given ID // find channel of device with given ID
typedef struct { typedef struct {
uint32 magic; uint32 magic;
@ -640,6 +663,13 @@ typedef struct {
uint channel; // channel of device (-1 if not found) uint channel; // channel of device (-1 if not found)
} radeon_find_vip_device; } radeon_find_vip_device;
// reset / init VIP
typedef struct {
uint32 magic;
bool lock;
} radeon_vip_reset;
// wait for capture interrupt and get status about // wait for capture interrupt and get status about
typedef struct { typedef struct {
uint32 magic; uint32 magic;

View File

@ -8,4 +8,4 @@
*/ */
// current version // current version
#define RADEON_DRIVER_VERSION "Version: 5.1.4.9" #define RADEON_DRIVER_VERSION "Version: 5.1.5.0"

View File

@ -400,6 +400,26 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
vw->lock ) ? B_OK : B_ERROR; vw->lock ) ? B_OK : B_ERROR;
} break; } break;
case RADEON_VIPFIFOREAD: {
radeon_vip_fifo_read *vr = (radeon_vip_fifo_read *)buf;
if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPFifoRead( di, vr->channel, vr->address, vr->count, vr->data,
vr->lock ) ? B_OK : B_ERROR;
} break;
case RADEON_VIPFIFOWRITE: {
radeon_vip_fifo_write *vw = (radeon_vip_fifo_write *)buf;
if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPFifoWrite( di, vw->channel, vw->address, vw->count, vw->data,
vw->lock ) ? B_OK : B_ERROR;
} break;
case RADEON_FINDVIPDEVICE: { case RADEON_FINDVIPDEVICE: {
radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf; radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
@ -409,7 +429,18 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id ); fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
result = B_OK; result = B_OK;
} break; } break;
case RADEON_VIPRESET: {
radeon_vip_reset *fvd = (radeon_vip_reset *)buf;
if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
Radeon_VIPReset( di, fvd->lock );
result = B_OK;
} break;
case RADEON_WAIT_FOR_CAP_IRQ: { case RADEON_WAIT_FOR_CAP_IRQ: {
radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf; radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;

View File

@ -225,7 +225,10 @@ void Radeon_SetDynamicClock( device_info *di, int mode );
// vip.c // vip.c
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data, bool lock ); bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data, bool lock );
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 Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock);
bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock);
int Radeon_FindVIPDevice( device_info *di, uint32 device_id ); int Radeon_FindVIPDevice( device_info *di, uint32 device_id );
void Radeon_VIPReset( device_info *di, bool lock );
// dma.c // dma.c

View File

@ -21,6 +21,7 @@
// moved to bottom to avoid inlining // moved to bottom to avoid inlining
static bool Radeon_VIPWaitForIdle( device_info *di ); static bool Radeon_VIPWaitForIdle( device_info *di );
static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel);
// read data from VIP // read data from VIP
@ -84,6 +85,96 @@ bool Radeon_VIPRead(
ACQUIRE_BEN( di->si->cp.lock ); ACQUIRE_BEN( di->si->cp.lock );
res = do_VIPRead( di, channel, address, data ); 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 ) if( lock )
RELEASE_BEN( di->si->cp.lock ); RELEASE_BEN( di->si->cp.lock );
@ -95,31 +186,26 @@ bool Radeon_VIPRead(
// write data to VIP // write data to VIP
// CP must be hold // CP must be hold
static bool do_VIPWrite( static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
device_info *di, uint8 channel, uint address, uint32 data )
{ {
vuint8 *regs = di->regs; vuint8 *regs = di->regs;
bool res;
Radeon_WaitForFifo( di, 2 ); Radeon_WaitForFifo( di, 2 );
OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) ); OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
if( !Radeon_VIPWaitForIdle( di )) if( !Radeon_VIPWaitForIdle( di )) return false;
return false;
//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data ); //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
Radeon_WaitForFifo( di, 2 ); Radeon_WaitForFifo( di, 2 );
OUTREG( regs, RADEON_VIPH_REG_DATA, data ); OUTREG( regs, RADEON_VIPH_REG_DATA, data );
res = Radeon_VIPWaitForIdle( di ); return Radeon_VIPWaitForIdle( di );
return res;
} }
// public function: write data to VIP // public function: write data to VIP
bool Radeon_VIPWrite( bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
device_info *di, uint8 channel, uint address, uint32 data, bool lock )
{ {
bool res; 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 // reset VIP
static void VIPReset( void Radeon_VIPReset(
device_info *di, bool lock ) device_info *di, bool lock )
{ {
vuint8 *regs = di->regs; vuint8 *regs = di->regs;
@ -146,27 +288,43 @@ static void VIPReset(
if( lock ) if( lock )
ACQUIRE_BEN( di->si->cp.lock ); ACQUIRE_BEN( di->si->cp.lock );
Radeon_WaitForFifo( di, 5 ); Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
OUTREG( regs, RADEON_VIPH_CONTROL, switch(di->asic){
4 | case rt_r200:
(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) | case rt_rs200:
RADEON_VIPH_CONTROL_VIPH_DMA_MODE | case rt_rv200:
RADEON_VIPH_CONTROL_VIPH_EN ); case rt_rs100:
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS, case rt_rv100:
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS); case rt_r100:
OUTREG( regs, RADEON_VIPH_DV_LAT, OUTREG( regs, RADEON_VIPH_CONTROL, 4 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
0xff | RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) | OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) | OUTREG( regs, RADEON_VIPH_DV_LAT,
(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); 0xff |
OUTREG( regs, RADEON_VIPH_DMA_CHUNK, (4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
1 | (4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH1_CHUNK_SHIFT) | (4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH2_CHUNK_SHIFT) | (4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH3_CHUNK_SHIFT)); OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
OUTREGP( regs, RADEON_TEST_DEBUG_CNTL, 0, ~RADEON_TEST_DEBUG_CNTL_OUT_EN ); 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 ) if( lock )
RELEASE_BEN( di->si->cp.lock ); RELEASE_BEN( di->si->cp.lock );
} }
@ -184,25 +342,30 @@ static status_t Radeon_VIPIdle(
// if there is a stuck transaction, acknowledge that // if there is a stuck transaction, acknowledge that
timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT ); timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 ) { if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, {
RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK, OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
~RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK & ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK ); (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 ) return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
return B_BUSY;
else
return B_ERROR;
} }
return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
//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;
} }
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 // wait until VIP host is idle
// lock must be hold // lock must be hold
static bool Radeon_VIPWaitForIdle( static bool Radeon_VIPWaitForIdle(
@ -240,23 +403,28 @@ int Radeon_FindVIPDevice(
// if card has no VIP port, let hardware detection fail; // if card has no VIP port, let hardware detection fail;
// in this case, noone will bother us again // 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; return -1;
}
ACQUIRE_BEN( di->si->cp.lock ); 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 // there are up to 4 devices, connected to one of 4 channels
for( channel = 0; channel < 4; ++channel ) { for( channel = 0; channel < 4; ++channel ) {
// read device id // 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; continue;
}
// compare device id directly // compare device id directly
if( cur_device_id == device_id ) { if( cur_device_id == device_id ) {
SHOW_FLOW( 3, "Device %08lx found on channel %d", device_id, channel);
RELEASE_BEN( di->si->cp.lock ); RELEASE_BEN( di->si->cp.lock );
return channel; return channel;
} }
} }