15f6e3f51Sshadow303 /*
2e02e12deSAxel Dörfler Copyright (c) 2002-05, Thomas Kurschel
35f6e3f51Sshadow303
45f6e3f51Sshadow303
55f6e3f51Sshadow303 Part of Radeon accelerant
65f6e3f51Sshadow303
75f6e3f51Sshadow303 Access to VIP
85f6e3f51Sshadow303
95f6e3f51Sshadow303 This code must be in kernel because we need for FIFO to become empty
105f6e3f51Sshadow303 during VIP access (which in turn requires locking the card, and locking
115f6e3f51Sshadow303 is a dangerous thing in user mode as the app can suddenly die, taking
125f6e3f51Sshadow303 the lock with it)
135f6e3f51Sshadow303 */
145f6e3f51Sshadow303
155f6e3f51Sshadow303 #include "radeon_driver.h"
165f6e3f51Sshadow303 #include "mmio.h"
175f6e3f51Sshadow303 #include "vip_regs.h"
185f6e3f51Sshadow303 #include "bios_regs.h"
195f6e3f51Sshadow303 #include "theatre_regs.h"
205f6e3f51Sshadow303
215f6e3f51Sshadow303
225f6e3f51Sshadow303 // moved to bottom to avoid inlining
235f6e3f51Sshadow303 static bool Radeon_VIPWaitForIdle( device_info *di );
247ce2eaa1SAxel Dörfler static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel);
255f6e3f51Sshadow303
265f6e3f51Sshadow303
275f6e3f51Sshadow303 // read data from VIP
285f6e3f51Sshadow303 // CP lock must be hold
do_VIPRead(device_info * di,uint channel,uint address,uint32 * data)29e02e12deSAxel Dörfler static bool do_VIPRead(
30e02e12deSAxel Dörfler device_info *di, uint channel, uint address, uint32 *data )
315f6e3f51Sshadow303 {
325f6e3f51Sshadow303 vuint8 *regs = di->regs;
335f6e3f51Sshadow303
345f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
355f6e3f51Sshadow303 // the 0x2000 is the nameless "register-read" flag
365f6e3f51Sshadow303 OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x2000 );
375f6e3f51Sshadow303
385f6e3f51Sshadow303 if( !Radeon_VIPWaitForIdle( di ))
395f6e3f51Sshadow303 return false;
405f6e3f51Sshadow303
415f6e3f51Sshadow303 // enable VIP register cycle reads
425f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
435f6e3f51Sshadow303 OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, 0,
445f6e3f51Sshadow303 ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
455f6e3f51Sshadow303 //Radeon_WaitForIdle( di, false, false );
465f6e3f51Sshadow303
475f6e3f51Sshadow303 // this read starts a register cycle; the returned value has no meaning
485f6e3f51Sshadow303 INREG( regs, RADEON_VIPH_REG_DATA );
495f6e3f51Sshadow303
505f6e3f51Sshadow303 if( !Radeon_VIPWaitForIdle( di ))
515f6e3f51Sshadow303 return false;
525f6e3f51Sshadow303
535f6e3f51Sshadow303 //Radeon_WaitForIdle( di, false, false );
545f6e3f51Sshadow303
555f6e3f51Sshadow303 // register cycle is done, so disable any further cycle
565f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
575f6e3f51Sshadow303 OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
585f6e3f51Sshadow303 ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
595f6e3f51Sshadow303 //Radeon_WaitForIdle( di, false, false );
605f6e3f51Sshadow303
615f6e3f51Sshadow303 // get the data
625f6e3f51Sshadow303 *data = INREG( regs, RADEON_VIPH_REG_DATA );
635f6e3f51Sshadow303
645f6e3f51Sshadow303 //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data );
655f6e3f51Sshadow303
665f6e3f51Sshadow303 if( !Radeon_VIPWaitForIdle( di ))
675f6e3f51Sshadow303 return false;
685f6e3f51Sshadow303
695f6e3f51Sshadow303 // disable register cycle again (according to sample code)
705f6e3f51Sshadow303 // IMHO, this is not necessary as it has been done before
715f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
725f6e3f51Sshadow303 OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
735f6e3f51Sshadow303 ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
745f6e3f51Sshadow303
755f6e3f51Sshadow303 return true;
765f6e3f51Sshadow303 }
775f6e3f51Sshadow303
785f6e3f51Sshadow303 // public function: read data from VIP
Radeon_VIPRead(device_info * di,uint channel,uint address,uint32 * data,bool lock)79e02e12deSAxel Dörfler bool Radeon_VIPRead(
80e02e12deSAxel Dörfler device_info *di, uint channel, uint address, uint32 *data, bool lock )
815f6e3f51Sshadow303 {
825f6e3f51Sshadow303 bool res;
835f6e3f51Sshadow303
84e02e12deSAxel Dörfler if( lock )
855f6e3f51Sshadow303 ACQUIRE_BEN( di->si->cp.lock );
865f6e3f51Sshadow303
875f6e3f51Sshadow303 res = do_VIPRead( di, channel, address, data );
885f6e3f51Sshadow303
89e02e12deSAxel Dörfler if( lock )
905f6e3f51Sshadow303 RELEASE_BEN( di->si->cp.lock );
91e02e12deSAxel Dörfler
92e02e12deSAxel Dörfler // SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
93e02e12deSAxel Dörfler
945f6e3f51Sshadow303 return res;
955f6e3f51Sshadow303 }
965f6e3f51Sshadow303
do_VIPFifoRead(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer)977ce2eaa1SAxel Dörfler static bool do_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
985f6e3f51Sshadow303 {
995f6e3f51Sshadow303 vuint8 *regs = di->regs;
1007ce2eaa1SAxel Dörfler uint32 status, tmp;
1017ce2eaa1SAxel Dörfler
1027ce2eaa1SAxel Dörfler if(count!=1)
1037ce2eaa1SAxel Dörfler {
1047ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "Attempt to access VIP bus with non-stadard transaction length\n");
1057ce2eaa1SAxel Dörfler return false;
1067ce2eaa1SAxel Dörfler }
1077ce2eaa1SAxel Dörfler
108*cc7e844cSMurai Takashi SHOW_FLOW( 2, "address=%" B_PRIx32 ", count=%" B_PRIu32 " ",
109*cc7e844cSMurai Takashi address, count );
1107ce2eaa1SAxel Dörfler
1117ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2);
1127ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "1");
1137ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x3000);
1147ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "3");
1157ce2eaa1SAxel Dörfler while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
1167ce2eaa1SAxel Dörfler if(B_OK != status) return false;
1177ce2eaa1SAxel Dörfler
1187ce2eaa1SAxel Dörfler // disable VIPH_REGR_DIS to enable VIP cycle.
1197ce2eaa1SAxel Dörfler // The LSB of VIPH_TIMEOUT_STAT are set to 0
1207ce2eaa1SAxel Dörfler // because 1 would have acknowledged various VIP
1217ce2eaa1SAxel Dörfler // interrupts unexpectedly
1227ce2eaa1SAxel Dörfler
1237ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "4");
1247ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
1257ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "5");
1267ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
1277ce2eaa1SAxel Dörfler INREG( regs, RADEON_VIPH_TIMEOUT_STAT) &
1287ce2eaa1SAxel Dörfler (0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS) );
1297ce2eaa1SAxel Dörfler
1307ce2eaa1SAxel Dörfler // the value returned here is garbage. The read merely initiates
1317ce2eaa1SAxel Dörfler // a register cycle
1327ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "6");
1337ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
1347ce2eaa1SAxel Dörfler INREG( regs, RADEON_VIPH_REG_DATA);
1357ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "7");
1367ce2eaa1SAxel Dörfler while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
1377ce2eaa1SAxel Dörfler if(B_OK != status) return false;
1387ce2eaa1SAxel Dörfler
1397ce2eaa1SAxel Dörfler // set VIPH_REGR_DIS so that the read won't take too long.
1407ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "8");
1417ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
1427ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "9");
1437ce2eaa1SAxel Dörfler tmp = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
1447ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
1457ce2eaa1SAxel Dörfler
1467ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "10");
1477ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
1487ce2eaa1SAxel Dörfler switch(count){
1497ce2eaa1SAxel Dörfler case 1:
1507ce2eaa1SAxel Dörfler *buffer=(uint8)(INREG( regs, RADEON_VIPH_REG_DATA) & 0xff);
1517ce2eaa1SAxel Dörfler break;
1527ce2eaa1SAxel Dörfler case 2:
1537ce2eaa1SAxel Dörfler *(uint16 *)buffer=(uint16) (INREG( regs, RADEON_VIPH_REG_DATA) & 0xffff);
1547ce2eaa1SAxel Dörfler break;
1557ce2eaa1SAxel Dörfler case 4:
1567ce2eaa1SAxel Dörfler *(uint32 *)buffer=(uint32) ( INREG( regs, RADEON_VIPH_REG_DATA) & 0xffffffff);
1577ce2eaa1SAxel Dörfler break;
1587ce2eaa1SAxel Dörfler }
1597ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "11");
1607ce2eaa1SAxel Dörfler while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
1617ce2eaa1SAxel Dörfler if(B_OK != status) return false;
1627ce2eaa1SAxel Dörfler
1637ce2eaa1SAxel Dörfler // so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles.
1647ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "12");
1657ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
1667ce2eaa1SAxel Dörfler (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
1677ce2eaa1SAxel Dörfler return true;
1687ce2eaa1SAxel Dörfler
1697ce2eaa1SAxel Dörfler }
1707ce2eaa1SAxel Dörfler
Radeon_VIPFifoRead(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer,bool lock)1717ce2eaa1SAxel Dörfler bool Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
1727ce2eaa1SAxel Dörfler {
1735f6e3f51Sshadow303 bool res;
1745f6e3f51Sshadow303
1757ce2eaa1SAxel Dörfler if( lock )
1767ce2eaa1SAxel Dörfler ACQUIRE_BEN( di->si->cp.lock );
1777ce2eaa1SAxel Dörfler
1787ce2eaa1SAxel Dörfler res = do_VIPFifoRead( di, channel, address, count, buffer );
1797ce2eaa1SAxel Dörfler
1807ce2eaa1SAxel Dörfler if( lock )
1817ce2eaa1SAxel Dörfler RELEASE_BEN( di->si->cp.lock );
1827ce2eaa1SAxel Dörfler
1837ce2eaa1SAxel Dörfler //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
1847ce2eaa1SAxel Dörfler
1857ce2eaa1SAxel Dörfler return res;
1867ce2eaa1SAxel Dörfler }
1877ce2eaa1SAxel Dörfler
1887ce2eaa1SAxel Dörfler // write data to VIP
1897ce2eaa1SAxel Dörfler // CP must be hold
do_VIPWrite(device_info * di,uint8 channel,uint address,uint32 data)1907ce2eaa1SAxel Dörfler static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
1917ce2eaa1SAxel Dörfler {
1927ce2eaa1SAxel Dörfler vuint8 *regs = di->regs;
1937ce2eaa1SAxel Dörfler
1945f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
1955f6e3f51Sshadow303 OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
1965f6e3f51Sshadow303
1977ce2eaa1SAxel Dörfler if( !Radeon_VIPWaitForIdle( di )) return false;
1985f6e3f51Sshadow303
1995f6e3f51Sshadow303 //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
2005f6e3f51Sshadow303
2015f6e3f51Sshadow303 Radeon_WaitForFifo( di, 2 );
2025f6e3f51Sshadow303 OUTREG( regs, RADEON_VIPH_REG_DATA, data );
2035f6e3f51Sshadow303
2047ce2eaa1SAxel Dörfler return Radeon_VIPWaitForIdle( di );
2055f6e3f51Sshadow303
2065f6e3f51Sshadow303 }
2075f6e3f51Sshadow303
2085f6e3f51Sshadow303 // public function: write data to VIP
Radeon_VIPWrite(device_info * di,uint8 channel,uint address,uint32 data,bool lock)2097ce2eaa1SAxel Dörfler bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
2105f6e3f51Sshadow303 {
2115f6e3f51Sshadow303 bool res;
2125f6e3f51Sshadow303
213e02e12deSAxel Dörfler //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
214e02e12deSAxel Dörfler
215e02e12deSAxel Dörfler if( lock )
2165f6e3f51Sshadow303 ACQUIRE_BEN( di->si->cp.lock );
2175f6e3f51Sshadow303
2185f6e3f51Sshadow303 res = do_VIPWrite( di, channel, address, data );
2195f6e3f51Sshadow303
220e02e12deSAxel Dörfler if( lock )
2215f6e3f51Sshadow303 RELEASE_BEN( di->si->cp.lock );
222e02e12deSAxel Dörfler
2235f6e3f51Sshadow303 return res;
2245f6e3f51Sshadow303 }
2255f6e3f51Sshadow303
2265f6e3f51Sshadow303
do_VIPFifoWrite(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer)227*cc7e844cSMurai Takashi static bool do_VIPFifoWrite(device_info *di, uint8 channel, uint32 address,
228*cc7e844cSMurai Takashi uint32 count, uint8 *buffer)
2297ce2eaa1SAxel Dörfler {
2307ce2eaa1SAxel Dörfler vuint8 *regs = di->regs;
2317ce2eaa1SAxel Dörfler
2327ce2eaa1SAxel Dörfler uint32 status;
2337ce2eaa1SAxel Dörfler uint32 i;
2347ce2eaa1SAxel Dörfler
235*cc7e844cSMurai Takashi SHOW_FLOW( 2, "address=%" B_PRIx32 ", count=%" B_PRIu32 ", ",
236*cc7e844cSMurai Takashi address, count );
2377ce2eaa1SAxel Dörfler
2387ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2 );
239*cc7e844cSMurai Takashi OUTREG( regs, RADEON_VIPH_REG_ADDR,
240*cc7e844cSMurai Takashi ((channel << 14) | address | 0x1000) & ~0x2000 );
2417ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "1");
242679c7513SAdrien Destugues do {
243679c7513SAdrien Destugues status = RADEON_VIPFifoIdle(di, 0x0f);
244679c7513SAdrien Destugues } while (status == B_BUSY);
2457ce2eaa1SAxel Dörfler
2467ce2eaa1SAxel Dörfler if(B_OK != status){
247*cc7e844cSMurai Takashi SHOW_FLOW( 2 ,"cannot write %x to VIPH_REG_ADDR\n",
248*cc7e844cSMurai Takashi (unsigned int)address);
2497ce2eaa1SAxel Dörfler return false;
2507ce2eaa1SAxel Dörfler }
2517ce2eaa1SAxel Dörfler
2527ce2eaa1SAxel Dörfler SHOW_FLOW0( 2, "2");
2537ce2eaa1SAxel Dörfler for (i = 0; i < count; i+=4)
2547ce2eaa1SAxel Dörfler {
2557ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 2);
256*cc7e844cSMurai Takashi SHOW_FLOW( 2, "count %" B_PRIu32, count);
2577ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_REG_DATA, *(uint32*)(buffer + i));
258679c7513SAdrien Destugues
259679c7513SAdrien Destugues do {
260679c7513SAdrien Destugues status = RADEON_VIPFifoIdle(di, 0x0f);
261679c7513SAdrien Destugues } while (status == B_BUSY);
262679c7513SAdrien Destugues
2637ce2eaa1SAxel Dörfler if(B_OK != status)
2647ce2eaa1SAxel Dörfler {
2657ce2eaa1SAxel Dörfler SHOW_FLOW0( 2 , "cannot write to VIPH_REG_DATA\n");
2667ce2eaa1SAxel Dörfler return false;
2677ce2eaa1SAxel Dörfler }
2687ce2eaa1SAxel Dörfler }
2697ce2eaa1SAxel Dörfler
2707ce2eaa1SAxel Dörfler return true;
2717ce2eaa1SAxel Dörfler }
2727ce2eaa1SAxel Dörfler
Radeon_VIPFifoWrite(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer,bool lock)2737ce2eaa1SAxel Dörfler bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
2747ce2eaa1SAxel Dörfler {
2757ce2eaa1SAxel Dörfler bool res;
2767ce2eaa1SAxel Dörfler
2777ce2eaa1SAxel Dörfler //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
2787ce2eaa1SAxel Dörfler
2797ce2eaa1SAxel Dörfler if( lock )
2807ce2eaa1SAxel Dörfler ACQUIRE_BEN( di->si->cp.lock );
2817ce2eaa1SAxel Dörfler
2827ce2eaa1SAxel Dörfler Radeon_VIPReset( di, false);
2837ce2eaa1SAxel Dörfler res = do_VIPFifoWrite( di, channel, address, count, buffer );
2847ce2eaa1SAxel Dörfler
2857ce2eaa1SAxel Dörfler if( lock )
2867ce2eaa1SAxel Dörfler RELEASE_BEN( di->si->cp.lock );
2877ce2eaa1SAxel Dörfler
2887ce2eaa1SAxel Dörfler return res;
2897ce2eaa1SAxel Dörfler }
2907ce2eaa1SAxel Dörfler
2917ce2eaa1SAxel Dörfler
2925f6e3f51Sshadow303 // reset VIP
Radeon_VIPReset(device_info * di,bool lock)2937ce2eaa1SAxel Dörfler void Radeon_VIPReset(
294e02e12deSAxel Dörfler device_info *di, bool lock )
2955f6e3f51Sshadow303 {
2965f6e3f51Sshadow303 vuint8 *regs = di->regs;
2975f6e3f51Sshadow303
298e02e12deSAxel Dörfler if( lock )
2995f6e3f51Sshadow303 ACQUIRE_BEN( di->si->cp.lock );
3005f6e3f51Sshadow303
3017ce2eaa1SAxel Dörfler Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
3027ce2eaa1SAxel Dörfler switch(di->asic){
3037ce2eaa1SAxel Dörfler case rt_r200:
3047ce2eaa1SAxel Dörfler case rt_rs200:
3057ce2eaa1SAxel Dörfler case rt_rv200:
3067ce2eaa1SAxel Dörfler case rt_rs100:
3077ce2eaa1SAxel Dörfler case rt_rv100:
3087ce2eaa1SAxel Dörfler case rt_r100:
3097ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_CONTROL, 4 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
3107ce2eaa1SAxel Dörfler RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
3117ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
3127ce2eaa1SAxel Dörfler RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
3135f6e3f51Sshadow303 OUTREG( regs, RADEON_VIPH_DV_LAT,
3145f6e3f51Sshadow303 0xff |
3155f6e3f51Sshadow303 (4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
3165f6e3f51Sshadow303 (4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
3175f6e3f51Sshadow303 (4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
3187ce2eaa1SAxel Dörfler (4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
3197ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
3207ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
3217ce2eaa1SAxel Dörfler default:
3227ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_CONTROL, 9 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
3237ce2eaa1SAxel Dörfler RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
3247ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
3257ce2eaa1SAxel Dörfler RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
3267ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_DV_LAT,
3277ce2eaa1SAxel Dörfler 0xff |
3287ce2eaa1SAxel Dörfler (4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
3297ce2eaa1SAxel Dörfler (4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
3307ce2eaa1SAxel Dörfler (4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
3317ce2eaa1SAxel Dörfler (4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
3327ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x0);
3337ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
3347ce2eaa1SAxel Dörfler break;
3357ce2eaa1SAxel Dörfler
3367ce2eaa1SAxel Dörfler }
3375f6e3f51Sshadow303
338e02e12deSAxel Dörfler if( lock )
3395f6e3f51Sshadow303 RELEASE_BEN( di->si->cp.lock );
3405f6e3f51Sshadow303 }
3415f6e3f51Sshadow303
3425f6e3f51Sshadow303
3435f6e3f51Sshadow303 // check whether VIP host is idle
3445f6e3f51Sshadow303 // lock must be hold
Radeon_VIPIdle(device_info * di)345e02e12deSAxel Dörfler static status_t Radeon_VIPIdle(
346e02e12deSAxel Dörfler device_info *di )
3475f6e3f51Sshadow303 {
3485f6e3f51Sshadow303 vuint8 *regs = di->regs;
3495f6e3f51Sshadow303 uint32 timeout;
3505f6e3f51Sshadow303
3515f6e3f51Sshadow303 //Radeon_WaitForIdle( di, false, false );
3525f6e3f51Sshadow303
3535f6e3f51Sshadow303 // if there is a stuck transaction, acknowledge that
3545f6e3f51Sshadow303 timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
3557ce2eaa1SAxel Dörfler if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
3567ce2eaa1SAxel Dörfler {
3577ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
3587ce2eaa1SAxel Dörfler (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
3597ce2eaa1SAxel Dörfler return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
3607ce2eaa1SAxel Dörfler }
3617ce2eaa1SAxel Dörfler return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
3625f6e3f51Sshadow303 }
3635f6e3f51Sshadow303
RADEON_VIPFifoIdle(device_info * di,uint8 channel)3647ce2eaa1SAxel Dörfler static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel)
3657ce2eaa1SAxel Dörfler {
3667ce2eaa1SAxel Dörfler vuint8 *regs = di->regs;
3677ce2eaa1SAxel Dörfler uint32 timeout;
3685f6e3f51Sshadow303
3697ce2eaa1SAxel Dörfler timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
3707ce2eaa1SAxel Dörfler if((timeout & 0x0000000f) & channel) /* lockup ?? */
3717ce2eaa1SAxel Dörfler {
3727ce2eaa1SAxel Dörfler OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel);
3737ce2eaa1SAxel Dörfler return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
3747ce2eaa1SAxel Dörfler }
3757ce2eaa1SAxel Dörfler return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK ;
3765f6e3f51Sshadow303 }
3775f6e3f51Sshadow303
3785f6e3f51Sshadow303
3795f6e3f51Sshadow303 // wait until VIP host is idle
3805f6e3f51Sshadow303 // lock must be hold
Radeon_VIPWaitForIdle(device_info * di)381e02e12deSAxel Dörfler static bool Radeon_VIPWaitForIdle(
382e02e12deSAxel Dörfler device_info *di )
3835f6e3f51Sshadow303 {
3845f6e3f51Sshadow303 int i;
3855f6e3f51Sshadow303
3865f6e3f51Sshadow303 // wait 100x 1ms before giving up
3875f6e3f51Sshadow303 for( i = 0; i < 100; ++i ) {
3885f6e3f51Sshadow303 status_t res;
3895f6e3f51Sshadow303
3905f6e3f51Sshadow303 res = Radeon_VIPIdle( di );
3915f6e3f51Sshadow303 if( res != B_BUSY ) {
3925f6e3f51Sshadow303 if( res == B_OK )
3935f6e3f51Sshadow303 return true;
3945f6e3f51Sshadow303 else
3955f6e3f51Sshadow303 return false;
3965f6e3f51Sshadow303 }
3975f6e3f51Sshadow303
3985f6e3f51Sshadow303 snooze( 1000 );
3995f6e3f51Sshadow303 }
4005f6e3f51Sshadow303
4015f6e3f51Sshadow303 return false;
4025f6e3f51Sshadow303 }
403e02e12deSAxel Dörfler
404e02e12deSAxel Dörfler
405e02e12deSAxel Dörfler // find VIP channel of a device
406e02e12deSAxel Dörfler // return: >= 0 channel of device
407e02e12deSAxel Dörfler // < 0 no device found
Radeon_FindVIPDevice(device_info * di,uint32 device_id)408e02e12deSAxel Dörfler int Radeon_FindVIPDevice(
409e02e12deSAxel Dörfler device_info *di, uint32 device_id )
410e02e12deSAxel Dörfler {
411e02e12deSAxel Dörfler uint channel;
412e02e12deSAxel Dörfler uint32 cur_device_id;
413e02e12deSAxel Dörfler
414e02e12deSAxel Dörfler // if card has no VIP port, let hardware detection fail;
415e02e12deSAxel Dörfler // in this case, noone will bother us again
4167ce2eaa1SAxel Dörfler if( !di->has_vip ) {
4177ce2eaa1SAxel Dörfler SHOW_FLOW0( 3, "This Device has no VIP Bus.");
418e02e12deSAxel Dörfler return -1;
4197ce2eaa1SAxel Dörfler }
420e02e12deSAxel Dörfler
421e02e12deSAxel Dörfler ACQUIRE_BEN( di->si->cp.lock );
422e02e12deSAxel Dörfler
4237ce2eaa1SAxel Dörfler Radeon_VIPReset( di, false );
424e02e12deSAxel Dörfler
425e02e12deSAxel Dörfler // there are up to 4 devices, connected to one of 4 channels
426e02e12deSAxel Dörfler for( channel = 0; channel < 4; ++channel ) {
4277ce2eaa1SAxel Dörfler
428e02e12deSAxel Dörfler // read device id
4297ce2eaa1SAxel Dörfler if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false )) {
4307ce2eaa1SAxel Dörfler SHOW_FLOW( 3, "No device found on channel %d", channel);
431e02e12deSAxel Dörfler continue;
4327ce2eaa1SAxel Dörfler }
433e02e12deSAxel Dörfler
434e02e12deSAxel Dörfler // compare device id directly
435e02e12deSAxel Dörfler if( cur_device_id == device_id ) {
436*cc7e844cSMurai Takashi SHOW_FLOW( 3, "Device %08" B_PRIx32 " found on channel %d",
437*cc7e844cSMurai Takashi device_id, channel);
438e02e12deSAxel Dörfler RELEASE_BEN( di->si->cp.lock );
439e02e12deSAxel Dörfler return channel;
440e02e12deSAxel Dörfler }
441e02e12deSAxel Dörfler }
442e02e12deSAxel Dörfler
443e02e12deSAxel Dörfler RELEASE_BEN( di->si->cp.lock );
444e02e12deSAxel Dörfler
445e02e12deSAxel Dörfler // couldn't find device
446e02e12deSAxel Dörfler return -1;
447e02e12deSAxel Dörfler }
448