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"
// magic code for ioctls
// changed from TKRA to TKR1 for RADEON_WAITFORFIFO ioctl
#define RADEON_PRIVATE_DATA_MAGIC 'TKR1'
// changed from TKRA to TKR2 for VIP FIFO ioctls
#define RADEON_PRIVATE_DATA_MAGIC 'TKR2'
#define MAX_RADEON_DEVICE_NAME_LENGTH MAXPATHLEN
@ -40,7 +40,10 @@ enum {
RADEON_RESETENGINE,
RADEON_VIPREAD,
RADEON_VIPWRITE,
RADEON_VIPFIFOREAD,
RADEON_VIPFIFOWRITE,
RADEON_FINDVIPDEVICE,
RADEON_VIPRESET,
RADEON_WAIT_FOR_CAP_IRQ,
RADEON_DMACOPY,
@ -633,6 +636,26 @@ typedef struct {
bool lock; // true, if CP lock must be acquired
} 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
typedef struct {
uint32 magic;
@ -640,6 +663,13 @@ typedef struct {
uint channel; // channel of device (-1 if not found)
} radeon_find_vip_device;
// reset / init VIP
typedef struct {
uint32 magic;
bool lock;
} radeon_vip_reset;
// wait for capture interrupt and get status about
typedef struct {
uint32 magic;

View File

@ -8,4 +8,4 @@
*/
// 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;
} 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: {
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 );
result = B_OK;
} 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: {
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
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_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 );
void Radeon_VIPReset( device_info *di, bool lock );
// dma.c

View File

@ -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;
}
}