xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/vip.c (revision cc7e844c12cbb4d60c80edac08a503d5cf872929)
1 /*
2 	Copyright (c) 2002-05, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Access to VIP
8 
9 	This code must be in kernel because we need for FIFO to become empty
10 	during VIP access (which in turn requires locking the card, and locking
11 	is a dangerous thing in user mode as the app can suddenly die, taking
12 	the lock with it)
13 */
14 
15 #include "radeon_driver.h"
16 #include "mmio.h"
17 #include "vip_regs.h"
18 #include "bios_regs.h"
19 #include "theatre_regs.h"
20 
21 
22 // moved to bottom to avoid inlining
23 static bool Radeon_VIPWaitForIdle( device_info *di );
24 static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel);
25 
26 
27 // read data from VIP
28 // CP lock must be hold
do_VIPRead(device_info * di,uint channel,uint address,uint32 * data)29 static bool do_VIPRead(
30 	device_info *di, uint channel, uint address, uint32 *data )
31 {
32 	vuint8 *regs = di->regs;
33 
34 	Radeon_WaitForFifo( di, 2 );
35 	// the 0x2000 is the nameless "register-read" flag
36 	OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x2000 );
37 
38 	if( !Radeon_VIPWaitForIdle( di ))
39 		return false;
40 
41 	// enable VIP register cycle reads
42 	Radeon_WaitForFifo( di, 2 );
43 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, 0,
44 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
45 	//Radeon_WaitForIdle( di, false, false );
46 
47 	// this read starts a register cycle; the returned value has no meaning
48 	INREG( regs, RADEON_VIPH_REG_DATA );
49 
50 	if( !Radeon_VIPWaitForIdle( di ))
51 		return false;
52 
53 	//Radeon_WaitForIdle( di, false, false );
54 
55 	// register cycle is done, so disable any further cycle
56 	Radeon_WaitForFifo( di, 2 );
57 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
58 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
59 	//Radeon_WaitForIdle( di, false, false );
60 
61 	// get the data
62 	*data = INREG( regs, RADEON_VIPH_REG_DATA );
63 
64 	//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data );
65 
66 	if( !Radeon_VIPWaitForIdle( di ))
67 		return false;
68 
69 	// disable register cycle again (according to sample code)
70 	// IMHO, this is not necessary as it has been done before
71 	Radeon_WaitForFifo( di, 2 );
72 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
73 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
74 
75 	return true;
76 }
77 
78 // public function: read data from VIP
Radeon_VIPRead(device_info * di,uint channel,uint address,uint32 * data,bool lock)79 bool Radeon_VIPRead(
80 	device_info *di, uint channel, uint address, uint32 *data, bool lock )
81 {
82 	bool res;
83 
84 	if( lock )
85 		ACQUIRE_BEN( di->si->cp.lock );
86 
87 	res = do_VIPRead( di, channel, address, data );
88 
89 	if( lock )
90 		RELEASE_BEN( di->si->cp.lock );
91 
92 //	SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
93 
94 	return res;
95 }
96 
do_VIPFifoRead(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer)97 static bool do_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
98 {
99    	vuint8 *regs = di->regs;
100 	uint32 status, tmp;
101 
102 	if(count!=1)
103 	{
104 		SHOW_FLOW0( 2, "Attempt to access VIP bus with non-stadard transaction length\n");
105 		return false;
106 	}
107 
108 	SHOW_FLOW( 2, "address=%" B_PRIx32 ", count=%" B_PRIu32 " ",
109 		address, count );
110 
111 	Radeon_WaitForFifo( di, 2);
112 	SHOW_FLOW0( 2, "1");
113 	OUTREG( regs, RADEON_VIPH_REG_ADDR,  (channel << 14) | address | 0x3000);
114 	SHOW_FLOW0( 2, "3");
115 	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
116 	if(B_OK != status) return false;
117 
118 	//	disable VIPH_REGR_DIS to enable VIP cycle.
119 	//	The LSB of VIPH_TIMEOUT_STAT are set to 0
120 	//	because 1 would have acknowledged various VIP
121 	//	interrupts unexpectedly
122 
123 	SHOW_FLOW0( 2, "4");
124 	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
125 	SHOW_FLOW0( 2, "5");
126 	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
127 		INREG( regs, RADEON_VIPH_TIMEOUT_STAT) &
128 			(0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS) );
129 
130 	//	the value returned here is garbage.  The read merely initiates
131 	//	a register cycle
132 	SHOW_FLOW0( 2, "6");
133 	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
134 	INREG( regs, RADEON_VIPH_REG_DATA);
135 	SHOW_FLOW0( 2, "7");
136 	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
137 	if(B_OK != status)  return false;
138 
139 	//	set VIPH_REGR_DIS so that the read won't take too long.
140 	SHOW_FLOW0( 2, "8");
141 	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
142 	SHOW_FLOW0( 2, "9");
143 	tmp = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
144 	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
145 
146 	SHOW_FLOW0( 2, "10");
147 	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
148 	switch(count){
149 	   case 1:
150 	        *buffer=(uint8)(INREG( regs, RADEON_VIPH_REG_DATA) & 0xff);
151 	        break;
152 	   case 2:
153 	        *(uint16 *)buffer=(uint16) (INREG( regs, RADEON_VIPH_REG_DATA) & 0xffff);
154 	        break;
155 	   case 4:
156 	        *(uint32 *)buffer=(uint32) ( INREG( regs, RADEON_VIPH_REG_DATA) & 0xffffffff);
157 	        break;
158 	   }
159 	SHOW_FLOW0( 2, "11");
160 	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
161 	if(B_OK != status) return false;
162 
163 	// so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles.
164 	SHOW_FLOW0( 2, "12");
165 	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
166 		(INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
167 	return true;
168 
169 }
170 
Radeon_VIPFifoRead(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer,bool lock)171 bool Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
172 {
173 	bool res;
174 
175 	if( lock )
176 		ACQUIRE_BEN( di->si->cp.lock );
177 
178 	res = do_VIPFifoRead( di, channel, address, count, buffer );
179 
180 	if( lock )
181 		RELEASE_BEN( di->si->cp.lock );
182 
183 	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
184 
185 	return res;
186 }
187 
188 // write data to VIP
189 // CP must be hold
do_VIPWrite(device_info * di,uint8 channel,uint address,uint32 data)190 static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
191 {
192 	vuint8 *regs = di->regs;
193 
194 	Radeon_WaitForFifo( di, 2 );
195 	OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
196 
197 	if( !Radeon_VIPWaitForIdle( di )) return false;
198 
199 	//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
200 
201 	Radeon_WaitForFifo( di, 2 );
202 	OUTREG( regs, RADEON_VIPH_REG_DATA, data );
203 
204 	return Radeon_VIPWaitForIdle( di );
205 
206 }
207 
208 // public function: write data to VIP
Radeon_VIPWrite(device_info * di,uint8 channel,uint address,uint32 data,bool lock)209 bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
210 {
211 	bool res;
212 
213 	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
214 
215 	if( lock )
216 		ACQUIRE_BEN( di->si->cp.lock );
217 
218 	res = do_VIPWrite( di, channel, address, data );
219 
220 	if( lock )
221 		RELEASE_BEN( di->si->cp.lock );
222 
223 	return res;
224 }
225 
226 
do_VIPFifoWrite(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer)227 static bool do_VIPFifoWrite(device_info *di, uint8 channel, uint32 address,
228 	uint32 count, uint8 *buffer)
229 {
230 	vuint8 *regs = di->regs;
231 
232 	uint32 status;
233 	uint32 i;
234 
235 	SHOW_FLOW( 2, "address=%" B_PRIx32 ", count=%" B_PRIu32 ", ",
236 		address, count );
237 
238 	Radeon_WaitForFifo( di, 2 );
239 	OUTREG( regs, RADEON_VIPH_REG_ADDR,
240 		((channel << 14) | address | 0x1000) & ~0x2000 );
241 	SHOW_FLOW0( 2, "1");
242 	do {
243 		status = RADEON_VIPFifoIdle(di, 0x0f);
244 	} while (status == B_BUSY);
245 
246 	if(B_OK != status){
247 		SHOW_FLOW( 2 ,"cannot write %x to VIPH_REG_ADDR\n",
248 			(unsigned int)address);
249 		return false;
250 	}
251 
252 	SHOW_FLOW0( 2, "2");
253 	for (i = 0; i < count; i+=4)
254 	{
255 		Radeon_WaitForFifo( di, 2);
256 		SHOW_FLOW( 2, "count %" B_PRIu32, count);
257 		OUTREG( regs, RADEON_VIPH_REG_DATA, *(uint32*)(buffer + i));
258 
259 		do {
260 			status = RADEON_VIPFifoIdle(di, 0x0f);
261 		} while (status == B_BUSY);
262 
263     	if(B_OK != status)
264 		{
265     		SHOW_FLOW0( 2 , "cannot write to VIPH_REG_DATA\n");
266 			return false;
267 		}
268 	}
269 
270 	return true;
271 }
272 
Radeon_VIPFifoWrite(device_info * di,uint8 channel,uint32 address,uint32 count,uint8 * buffer,bool lock)273 bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
274 {
275     bool res;
276 
277 	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
278 
279 	if( lock )
280 		ACQUIRE_BEN( di->si->cp.lock );
281 
282 	Radeon_VIPReset( di, false);
283 	res = do_VIPFifoWrite( di, channel, address, count, buffer );
284 
285 	if( lock )
286 		RELEASE_BEN( di->si->cp.lock );
287 
288 	return res;
289 }
290 
291 
292 // reset VIP
Radeon_VIPReset(device_info * di,bool lock)293 void Radeon_VIPReset(
294 	device_info *di, bool lock )
295 {
296 	vuint8 *regs = di->regs;
297 
298 	if( lock )
299 		ACQUIRE_BEN( di->si->cp.lock );
300 
301 	Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
302 	switch(di->asic){
303 	    case rt_r200:
304 	    case rt_rs200:
305 	    case rt_rv200:
306 	    case rt_rs100:
307 		case rt_rv100:
308 		case rt_r100:
309 	    OUTREG( regs, RADEON_VIPH_CONTROL, 4 | 	(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
310 			RADEON_VIPH_CONTROL_VIPH_DMA_MODE |	RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
311 	    OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
312 	    	RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
313 	    OUTREG( regs, RADEON_VIPH_DV_LAT,
314 	    		0xff |
315 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
316 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
317 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
318 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
319 	    OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
320 	    OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
321 	default:
322 		    OUTREG( regs, RADEON_VIPH_CONTROL, 9 | 	(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
323 				RADEON_VIPH_CONTROL_VIPH_DMA_MODE |	RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
324 	    OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
325 		    	RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
326 	    OUTREG( regs, RADEON_VIPH_DV_LAT,
327 			    0xff |
328 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
329 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
330 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
331 				(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
332 	    OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x0);
333 	    OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
334 	    break;
335 
336 	}
337 
338 	if( lock )
339 		RELEASE_BEN( di->si->cp.lock );
340 }
341 
342 
343 // check whether VIP host is idle
344 // lock must be hold
Radeon_VIPIdle(device_info * di)345 static status_t Radeon_VIPIdle(
346 	device_info *di )
347 {
348 	vuint8 *regs = di->regs;
349 	uint32 timeout;
350 
351 	//Radeon_WaitForIdle( di, false, false );
352 
353 	// if there is a stuck transaction, acknowledge that
354 	timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
355 	if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
356 	{
357 		OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
358 			(timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
359 		return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
360 	}
361 	return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
362 }
363 
RADEON_VIPFifoIdle(device_info * di,uint8 channel)364 static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel)
365 {
366 	vuint8 *regs = di->regs;
367 	uint32 timeout;
368 
369 	timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
370 	if((timeout & 0x0000000f) & channel) /* lockup ?? */
371 	{
372 		OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel);
373 		return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
374 	}
375 	return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK ;
376 }
377 
378 
379 // wait until VIP host is idle
380 // lock must be hold
Radeon_VIPWaitForIdle(device_info * di)381 static bool Radeon_VIPWaitForIdle(
382 	device_info *di )
383 {
384 	int i;
385 
386 	// wait 100x 1ms before giving up
387 	for( i = 0; i < 100; ++i ) {
388 		status_t res;
389 
390 		res = Radeon_VIPIdle( di );
391 		if( res != B_BUSY ) {
392 			if( res == B_OK )
393 				return true;
394 			else
395 				return false;
396 		}
397 
398 		snooze( 1000 );
399 	}
400 
401 	return false;
402 }
403 
404 
405 // find VIP channel of a device
406 // return:	>= 0 channel of device
407 //			< 0 no device found
Radeon_FindVIPDevice(device_info * di,uint32 device_id)408 int Radeon_FindVIPDevice(
409 	device_info *di, uint32 device_id )
410 {
411 	uint channel;
412 	uint32 cur_device_id;
413 
414 	// if card has no VIP port, let hardware detection fail;
415 	// in this case, noone will bother us again
416 	if( !di->has_vip ) {
417 		SHOW_FLOW0( 3, "This Device has no VIP Bus.");
418 		return -1;
419 	}
420 
421 	ACQUIRE_BEN( di->si->cp.lock );
422 
423 	Radeon_VIPReset( di, false );
424 
425 	// there are up to 4 devices, connected to one of 4 channels
426 	for( channel = 0; channel < 4; ++channel ) {
427 
428 		// read device id
429 		if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false ))	{
430 			SHOW_FLOW( 3, "No device found on channel %d", channel);
431 			continue;
432 		}
433 
434 		// compare device id directly
435 		if( cur_device_id == device_id ) {
436 			SHOW_FLOW( 3, "Device %08" B_PRIx32 " found on channel %d",
437 				device_id, channel);
438 			RELEASE_BEN( di->si->cp.lock );
439 			return channel;
440 		}
441 	}
442 
443 	RELEASE_BEN( di->si->cp.lock );
444 
445 	// couldn't find device
446 	return -1;
447 }
448