xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/vip.c (revision cc7e844c12cbb4d60c80edac08a503d5cf872929)
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