xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/vip.c (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
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 
25 
26 // read data from VIP
27 // CP lock must be hold
28 static bool do_VIPRead(
29 	device_info *di, uint channel, uint address, uint32 *data )
30 {
31 	vuint8 *regs = di->regs;
32 
33 	Radeon_WaitForFifo( di, 2 );
34 	// the 0x2000 is the nameless "register-read" flag
35 	OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x2000 );
36 
37 	if( !Radeon_VIPWaitForIdle( di ))
38 		return false;
39 
40 	// enable VIP register cycle reads
41 	Radeon_WaitForFifo( di, 2 );
42 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, 0,
43 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
44 	//Radeon_WaitForIdle( di, false, false );
45 
46 	// this read starts a register cycle; the returned value has no meaning
47 	INREG( regs, RADEON_VIPH_REG_DATA );
48 
49 	if( !Radeon_VIPWaitForIdle( di ))
50 		return false;
51 
52 	//Radeon_WaitForIdle( di, false, false );
53 
54 	// register cycle is done, so disable any further cycle
55 	Radeon_WaitForFifo( di, 2 );
56 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
57 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
58 	//Radeon_WaitForIdle( di, false, false );
59 
60 	// get the data
61 	*data = INREG( regs, RADEON_VIPH_REG_DATA );
62 
63 	//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data );
64 
65 	if( !Radeon_VIPWaitForIdle( di ))
66 		return false;
67 
68 	// disable register cycle again (according to sample code)
69 	// IMHO, this is not necessary as it has been done before
70 	Radeon_WaitForFifo( di, 2 );
71 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
72 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
73 
74 	return true;
75 }
76 
77 // public function: read data from VIP
78 bool Radeon_VIPRead(
79 	device_info *di, uint channel, uint address, uint32 *data, bool lock )
80 {
81 	bool res;
82 
83 	if( lock )
84 		ACQUIRE_BEN( di->si->cp.lock );
85 
86 	res = do_VIPRead( di, channel, address, data );
87 
88 	if( lock )
89 		RELEASE_BEN( di->si->cp.lock );
90 
91 	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
92 
93 	return res;
94 }
95 
96 // write data to VIP
97 // CP must be hold
98 static bool do_VIPWrite(
99 	device_info *di, uint8 channel, uint address, uint32 data )
100 {
101 	vuint8 *regs = di->regs;
102 	bool res;
103 
104 	Radeon_WaitForFifo( di, 2 );
105 	OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
106 
107 	if( !Radeon_VIPWaitForIdle( di ))
108 		return false;
109 
110 	//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
111 
112 	Radeon_WaitForFifo( di, 2 );
113 	OUTREG( regs, RADEON_VIPH_REG_DATA, data );
114 
115 	res = Radeon_VIPWaitForIdle( di );
116 
117 	return res;
118 }
119 
120 // public function: write data to VIP
121 bool Radeon_VIPWrite(
122 	device_info *di, uint8 channel, uint address, uint32 data, bool lock )
123 {
124 	bool res;
125 
126 	//SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
127 
128 	if( lock )
129 		ACQUIRE_BEN( di->si->cp.lock );
130 
131 	res = do_VIPWrite( di, channel, address, data );
132 
133 	if( lock )
134 		RELEASE_BEN( di->si->cp.lock );
135 
136 	return res;
137 }
138 
139 
140 // reset VIP
141 static void VIPReset(
142 	device_info *di, bool lock )
143 {
144 	vuint8 *regs = di->regs;
145 
146 	if( lock )
147 		ACQUIRE_BEN( di->si->cp.lock );
148 
149 	Radeon_WaitForFifo( di, 5 );
150 	OUTREG( regs, RADEON_VIPH_CONTROL,
151 		4 |
152 		(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
153 		RADEON_VIPH_CONTROL_VIPH_DMA_MODE |
154 		RADEON_VIPH_CONTROL_VIPH_EN );
155 	OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
156 		~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
157 	OUTREG( regs, RADEON_VIPH_DV_LAT,
158 		0xff |
159 		(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
160 		(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
161 		(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
162 		(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT));
163 	OUTREG( regs, RADEON_VIPH_DMA_CHUNK,
164 		1 |
165 		(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH1_CHUNK_SHIFT) |
166 		(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH2_CHUNK_SHIFT) |
167 		(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH3_CHUNK_SHIFT));
168 	OUTREGP( regs, RADEON_TEST_DEBUG_CNTL, 0, ~RADEON_TEST_DEBUG_CNTL_OUT_EN );
169 
170 	if( lock )
171 		RELEASE_BEN( di->si->cp.lock );
172 }
173 
174 
175 // check whether VIP host is idle
176 // lock must be hold
177 static status_t Radeon_VIPIdle(
178 	device_info *di )
179 {
180 	vuint8 *regs = di->regs;
181 	uint32 timeout;
182 
183 	//Radeon_WaitForIdle( di, false, false );
184 
185 	// if there is a stuck transaction, acknowledge that
186 	timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
187 	if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 ) {
188 		OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT,
189 			RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK,
190 			~RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK & ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK );
191 		if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
192 			return B_BUSY;
193 		else
194 			return B_ERROR;
195 	}
196 
197 	//Radeon_WaitForIdle( di, false, false );
198 
199 	if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
200 		return B_BUSY;
201 	else
202 		return B_OK;
203 }
204 
205 
206 // wait until VIP host is idle
207 // lock must be hold
208 static bool Radeon_VIPWaitForIdle(
209 	device_info *di )
210 {
211 	int i;
212 
213 	// wait 100x 1ms before giving up
214 	for( i = 0; i < 100; ++i ) {
215 		status_t res;
216 
217 		res = Radeon_VIPIdle( di );
218 		if( res != B_BUSY ) {
219 			if( res == B_OK )
220 				return true;
221 			else
222 				return false;
223 		}
224 
225 		snooze( 1000 );
226 	}
227 
228 	return false;
229 }
230 
231 
232 // find VIP channel of a device
233 // return:	>= 0 channel of device
234 //			< 0 no device found
235 int Radeon_FindVIPDevice(
236 	device_info *di, uint32 device_id )
237 {
238 	uint channel;
239 	uint32 cur_device_id;
240 
241 	// if card has no VIP port, let hardware detection fail;
242 	// in this case, noone will bother us again
243 	if( !di->has_vip )
244 		return -1;
245 
246 	ACQUIRE_BEN( di->si->cp.lock );
247 
248 	VIPReset( di, false );
249 
250 	// there are up to 4 devices, connected to one of 4 channels
251 	for( channel = 0; channel < 4; ++channel ) {
252 		// read device id
253 		if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false ))
254 			continue;
255 
256 		// compare device id directly
257 		if( cur_device_id == device_id ) {
258 			RELEASE_BEN( di->si->cp.lock );
259 
260 			return channel;
261 		}
262 	}
263 
264 	RELEASE_BEN( di->si->cp.lock );
265 
266 	// couldn't find device
267 	return -1;
268 }
269