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
23static bool Radeon_VIPWaitForIdle( device_info *di );
24static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel);
25
26
27// read data from VIP
28// CP lock must be hold
29static 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
79bool 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
97static 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=%lx, count=%ld ", address, count );
109
110	Radeon_WaitForFifo( di, 2);
111	SHOW_FLOW0( 2, "1");
112	OUTREG( regs, RADEON_VIPH_REG_ADDR,  (channel << 14) | address | 0x3000);
113	SHOW_FLOW0( 2, "3");
114	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
115	if(B_OK != status) return false;
116
117	//	disable VIPH_REGR_DIS to enable VIP cycle.
118	//	The LSB of VIPH_TIMEOUT_STAT are set to 0
119	//	because 1 would have acknowledged various VIP
120	//	interrupts unexpectedly
121
122	SHOW_FLOW0( 2, "4");
123	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
124	SHOW_FLOW0( 2, "5");
125	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
126		INREG( regs, RADEON_VIPH_TIMEOUT_STAT) &
127			(0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS) );
128
129	//	the value returned here is garbage.  The read merely initiates
130	//	a register cycle
131	SHOW_FLOW0( 2, "6");
132	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
133	INREG( regs, RADEON_VIPH_REG_DATA);
134	SHOW_FLOW0( 2, "7");
135	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
136	if(B_OK != status)  return false;
137
138	//	set VIPH_REGR_DIS so that the read won't take too long.
139	SHOW_FLOW0( 2, "8");
140	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
141	SHOW_FLOW0( 2, "9");
142	tmp = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
143	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
144
145	SHOW_FLOW0( 2, "10");
146	Radeon_WaitForFifo( di, 2 ); // Radeon_WaitForIdle( di, false, false );
147	switch(count){
148	   case 1:
149	        *buffer=(uint8)(INREG( regs, RADEON_VIPH_REG_DATA) & 0xff);
150	        break;
151	   case 2:
152	        *(uint16 *)buffer=(uint16) (INREG( regs, RADEON_VIPH_REG_DATA) & 0xffff);
153	        break;
154	   case 4:
155	        *(uint32 *)buffer=(uint32) ( INREG( regs, RADEON_VIPH_REG_DATA) & 0xffffffff);
156	        break;
157	   }
158	SHOW_FLOW0( 2, "11");
159	while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
160	if(B_OK != status) return false;
161
162	// so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles.
163	SHOW_FLOW0( 2, "12");
164	OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
165		(INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
166	return true;
167
168}
169
170bool Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
171{
172	bool res;
173
174	if( lock )
175		ACQUIRE_BEN( di->si->cp.lock );
176
177	res = do_VIPFifoRead( di, channel, address, count, buffer );
178
179	if( lock )
180		RELEASE_BEN( di->si->cp.lock );
181
182	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
183
184	return res;
185}
186
187// write data to VIP
188// CP must be hold
189static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
190{
191	vuint8 *regs = di->regs;
192
193	Radeon_WaitForFifo( di, 2 );
194	OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
195
196	if( !Radeon_VIPWaitForIdle( di )) return false;
197
198	//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
199
200	Radeon_WaitForFifo( di, 2 );
201	OUTREG( regs, RADEON_VIPH_REG_DATA, data );
202
203	return Radeon_VIPWaitForIdle( di );
204
205}
206
207// public function: write data to VIP
208bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
209{
210	bool res;
211
212	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
213
214	if( lock )
215		ACQUIRE_BEN( di->si->cp.lock );
216
217	res = do_VIPWrite( di, channel, address, data );
218
219	if( lock )
220		RELEASE_BEN( di->si->cp.lock );
221
222	return res;
223}
224
225
226static bool do_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
227{
228	vuint8 *regs = di->regs;
229
230	uint32 status;
231	uint32 i;
232
233	SHOW_FLOW( 2, "address=%lx, count=%ld, ", address, count );
234
235	Radeon_WaitForFifo( di, 2 );
236	OUTREG( regs, RADEON_VIPH_REG_ADDR, ((channel << 14) | address | 0x1000) & ~0x2000 );
237	SHOW_FLOW0( 2, "1");
238	do {
239		status = RADEON_VIPFifoIdle(di, 0x0f);
240	} while (status == B_BUSY);
241
242	if(B_OK != status){
243		SHOW_FLOW( 2 ,"cannot write %x to VIPH_REG_ADDR\n", (unsigned int)address);
244		return false;
245	}
246
247	SHOW_FLOW0( 2, "2");
248	for (i = 0; i < count; i+=4)
249	{
250		Radeon_WaitForFifo( di, 2);
251		SHOW_FLOW( 2, "count %ld", count);
252		OUTREG( regs, RADEON_VIPH_REG_DATA, *(uint32*)(buffer + i));
253
254		do {
255			status = RADEON_VIPFifoIdle(di, 0x0f);
256		} while (status == B_BUSY);
257
258    	if(B_OK != status)
259		{
260    		SHOW_FLOW0( 2 , "cannot write to VIPH_REG_DATA\n");
261			return false;
262		}
263	}
264
265	return true;
266}
267
268bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
269{
270    bool res;
271
272	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
273
274	if( lock )
275		ACQUIRE_BEN( di->si->cp.lock );
276
277	Radeon_VIPReset( di, false);
278	res = do_VIPFifoWrite( di, channel, address, count, buffer );
279
280	if( lock )
281		RELEASE_BEN( di->si->cp.lock );
282
283	return res;
284}
285
286
287// reset VIP
288void Radeon_VIPReset(
289	device_info *di, bool lock )
290{
291	vuint8 *regs = di->regs;
292
293	if( lock )
294		ACQUIRE_BEN( di->si->cp.lock );
295
296	Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
297	switch(di->asic){
298	    case rt_r200:
299	    case rt_rs200:
300	    case rt_rv200:
301	    case rt_rs100:
302		case rt_rv100:
303		case rt_r100:
304	    OUTREG( regs, RADEON_VIPH_CONTROL, 4 | 	(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
305			RADEON_VIPH_CONTROL_VIPH_DMA_MODE |	RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
306	    OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
307	    	RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
308	    OUTREG( regs, RADEON_VIPH_DV_LAT,
309	    		0xff |
310				(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
311				(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
312				(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
313				(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
314	    OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
315	    OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
316	default:
317		    OUTREG( regs, RADEON_VIPH_CONTROL, 9 | 	(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
318				RADEON_VIPH_CONTROL_VIPH_DMA_MODE |	RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
319	    OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
320		    	RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
321	    OUTREG( regs, RADEON_VIPH_DV_LAT,
322			    0xff |
323				(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
324				(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
325				(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
326				(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
327	    OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x0);
328	    OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
329	    break;
330
331	}
332
333	if( lock )
334		RELEASE_BEN( di->si->cp.lock );
335}
336
337
338// check whether VIP host is idle
339// lock must be hold
340static status_t Radeon_VIPIdle(
341	device_info *di )
342{
343	vuint8 *regs = di->regs;
344	uint32 timeout;
345
346	//Radeon_WaitForIdle( di, false, false );
347
348	// if there is a stuck transaction, acknowledge that
349	timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
350	if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
351	{
352		OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
353			(timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
354		return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
355	}
356	return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
357}
358
359static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel)
360{
361	vuint8 *regs = di->regs;
362	uint32 timeout;
363
364	timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
365	if((timeout & 0x0000000f) & channel) /* lockup ?? */
366	{
367		OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel);
368		return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
369	}
370	return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK ;
371}
372
373
374// wait until VIP host is idle
375// lock must be hold
376static bool Radeon_VIPWaitForIdle(
377	device_info *di )
378{
379	int i;
380
381	// wait 100x 1ms before giving up
382	for( i = 0; i < 100; ++i ) {
383		status_t res;
384
385		res = Radeon_VIPIdle( di );
386		if( res != B_BUSY ) {
387			if( res == B_OK )
388				return true;
389			else
390				return false;
391		}
392
393		snooze( 1000 );
394	}
395
396	return false;
397}
398
399
400// find VIP channel of a device
401// return:	>= 0 channel of device
402//			< 0 no device found
403int Radeon_FindVIPDevice(
404	device_info *di, uint32 device_id )
405{
406	uint channel;
407	uint32 cur_device_id;
408
409	// if card has no VIP port, let hardware detection fail;
410	// in this case, noone will bother us again
411	if( !di->has_vip ) {
412		SHOW_FLOW0( 3, "This Device has no VIP Bus.");
413		return -1;
414	}
415
416	ACQUIRE_BEN( di->si->cp.lock );
417
418	Radeon_VIPReset( di, false );
419
420	// there are up to 4 devices, connected to one of 4 channels
421	for( channel = 0; channel < 4; ++channel ) {
422
423		// read device id
424		if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false ))	{
425			SHOW_FLOW( 3, "No device found on channel %d", channel);
426			continue;
427		}
428
429		// compare device id directly
430		if( cur_device_id == device_id ) {
431			SHOW_FLOW( 3, "Device %08lx found on channel %d", device_id, channel);
432			RELEASE_BEN( di->si->cp.lock );
433			return channel;
434		}
435	}
436
437	RELEASE_BEN( di->si->cp.lock );
438
439	// couldn't find device
440	return -1;
441}
442