From 7ce2eaa1e008ea2f4dbb0a88fef86c99602d2953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 1 Mar 2007 09:43:33 +0000 Subject: [PATCH] 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 --- .../graphics/radeon/radeon_interface.h | 34 ++- headers/private/graphics/radeon/version.h | 2 +- .../kernel/drivers/graphics/radeon/driver.c | 31 ++ .../drivers/graphics/radeon/radeon_driver.h | 3 + .../kernel/drivers/graphics/radeon/vip.c | 268 ++++++++++++++---- 5 files changed, 285 insertions(+), 53 deletions(-) diff --git a/headers/private/graphics/radeon/radeon_interface.h b/headers/private/graphics/radeon/radeon_interface.h index 0d895a3bad..bd8f1861cb 100644 --- a/headers/private/graphics/radeon/radeon_interface.h +++ b/headers/private/graphics/radeon/radeon_interface.h @@ -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; diff --git a/headers/private/graphics/radeon/version.h b/headers/private/graphics/radeon/version.h index 323d46c652..8a29cc3e1d 100644 --- a/headers/private/graphics/radeon/version.h +++ b/headers/private/graphics/radeon/version.h @@ -8,4 +8,4 @@ */ // current version -#define RADEON_DRIVER_VERSION "Version: 5.1.4.9" +#define RADEON_DRIVER_VERSION "Version: 5.1.5.0" diff --git a/src/add-ons/kernel/drivers/graphics/radeon/driver.c b/src/add-ons/kernel/drivers/graphics/radeon/driver.c index 6950436683..bb1ab475ae 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/driver.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/driver.c @@ -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; diff --git a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h index 205ba4744e..1da27a7813 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h +++ b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h @@ -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 diff --git a/src/add-ons/kernel/drivers/graphics/radeon/vip.c b/src/add-ons/kernel/drivers/graphics/radeon/vip.c index 96ff84d977..9c5c2b7e27 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/vip.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/vip.c @@ -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; } }