usb_ecm: Use the current configuration instead of a fixed one.
[haiku.git] / src / add-ons / kernel / drivers / graphics / radeon / vip.c
blob9c5c2b7e271afba3eb708f308a55b1c09df7cf15
1 /*
2 Copyright (c) 2002-05, Thomas Kurschel
5 Part of Radeon accelerant
7 Access to VIP
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)
15 #include "radeon_driver.h"
16 #include "mmio.h"
17 #include "vip_regs.h"
18 #include "bios_regs.h"
19 #include "theatre_regs.h"
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);
27 // read data from VIP
28 // CP lock must be hold
29 static bool do_VIPRead(
30 device_info *di, uint channel, uint address, uint32 *data )
32 vuint8 *regs = di->regs;
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 );
38 if( !Radeon_VIPWaitForIdle( di ))
39 return false;
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 );
47 // this read starts a register cycle; the returned value has no meaning
48 INREG( regs, RADEON_VIPH_REG_DATA );
50 if( !Radeon_VIPWaitForIdle( di ))
51 return false;
53 //Radeon_WaitForIdle( di, false, false );
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 );
61 // get the data
62 *data = INREG( regs, RADEON_VIPH_REG_DATA );
64 //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data );
66 if( !Radeon_VIPWaitForIdle( di ))
67 return false;
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 );
75 return true;
78 // public function: read data from VIP
79 bool Radeon_VIPRead(
80 device_info *di, uint channel, uint address, uint32 *data, bool lock )
82 bool res;
84 if( lock )
85 ACQUIRE_BEN( di->si->cp.lock );
87 res = do_VIPRead( di, channel, address, data );
89 if( lock )
90 RELEASE_BEN( di->si->cp.lock );
92 // SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
94 return res;
97 static bool do_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
99 vuint8 *regs = di->regs;
100 uint32 status, tmp;
102 if(count!=1)
104 SHOW_FLOW0( 2, "Attempt to access VIP bus with non-stadard transaction length\n");
105 return false;
108 SHOW_FLOW( 2, "address=%lx, count=%ld ", address, count );
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;
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
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) );
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;
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);
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;
158 SHOW_FLOW0( 2, "11");
159 while(B_BUSY == (status = RADEON_VIPFifoIdle( di , 0xff)));
160 if(B_OK != status) return false;
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;
170 bool Radeon_VIPFifoRead(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
172 bool res;
174 if( lock )
175 ACQUIRE_BEN( di->si->cp.lock );
177 res = do_VIPFifoRead( di, channel, address, count, buffer );
179 if( lock )
180 RELEASE_BEN( di->si->cp.lock );
182 //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, *data, lock );
184 return res;
187 // write data to VIP
188 // CP must be hold
189 static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
191 vuint8 *regs = di->regs;
193 Radeon_WaitForFifo( di, 2 );
194 OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
196 if( !Radeon_VIPWaitForIdle( di )) return false;
198 //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
200 Radeon_WaitForFifo( di, 2 );
201 OUTREG( regs, RADEON_VIPH_REG_DATA, data );
203 return Radeon_VIPWaitForIdle( di );
207 // public function: write data to VIP
208 bool Radeon_VIPWrite(device_info *di, uint8 channel, uint address, uint32 data, bool lock )
210 bool res;
212 //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
214 if( lock )
215 ACQUIRE_BEN( di->si->cp.lock );
217 res = do_VIPWrite( di, channel, address, data );
219 if( lock )
220 RELEASE_BEN( di->si->cp.lock );
222 return res;
226 static bool do_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer)
228 vuint8 *regs = di->regs;
230 uint32 status;
231 uint32 i;
233 SHOW_FLOW( 2, "address=%lx, count=%ld, ", address, count );
235 Radeon_WaitForFifo( di, 2 );
236 OUTREG( regs, RADEON_VIPH_REG_ADDR, ((channel << 14) | address | 0x1000) & ~0x2000 );
237 SHOW_FLOW0( 2, "1");
238 while(B_BUSY == (status = RADEON_VIPFifoIdle( di, 0x0f)));
241 if(B_OK != status){
242 SHOW_FLOW( 2 ,"cannot write %x to VIPH_REG_ADDR\n", (unsigned int)address);
243 return false;
246 SHOW_FLOW0( 2, "2");
247 for (i = 0; i < count; i+=4)
249 Radeon_WaitForFifo( di, 2);
250 SHOW_FLOW( 2, "count %ld", count);
251 OUTREG( regs, RADEON_VIPH_REG_DATA, *(uint32*)(buffer + i));
252 while(B_BUSY == (status = RADEON_VIPFifoIdle( di, 0x0f)));
253 if(B_OK != status)
255 SHOW_FLOW0( 2 , "cannot write to VIPH_REG_DATA\n");
256 return false;
260 return true;
263 bool Radeon_VIPFifoWrite(device_info *di, uint8 channel, uint32 address, uint32 count, uint8 *buffer, bool lock)
265 bool res;
267 //SHOW_FLOW( 2, "address=%x, data=%lx, lock=%d", address, data, lock );
269 if( lock )
270 ACQUIRE_BEN( di->si->cp.lock );
272 Radeon_VIPReset( di, false);
273 res = do_VIPFifoWrite( di, channel, address, count, buffer );
275 if( lock )
276 RELEASE_BEN( di->si->cp.lock );
278 return res;
282 // reset VIP
283 void Radeon_VIPReset(
284 device_info *di, bool lock )
286 vuint8 *regs = di->regs;
288 if( lock )
289 ACQUIRE_BEN( di->si->cp.lock );
291 Radeon_WaitForFifo( di, 5 ); // Radeon_WaitForIdle( di, false, false );
292 switch(di->asic){
293 case rt_r200:
294 case rt_rs200:
295 case rt_rv200:
296 case rt_rs100:
297 case rt_rv100:
298 case rt_r100:
299 OUTREG( regs, RADEON_VIPH_CONTROL, 4 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
300 RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
301 OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
302 RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
303 OUTREG( regs, RADEON_VIPH_DV_LAT,
304 0xff |
305 (4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
306 (4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
307 (4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
308 (4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
309 OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x151);
310 OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
311 default:
312 OUTREG( regs, RADEON_VIPH_CONTROL, 9 | (15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
313 RADEON_VIPH_CONTROL_VIPH_DMA_MODE | RADEON_VIPH_CONTROL_VIPH_EN ); // slowest, timeout in 16 phases
314 OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (INREG( regs, RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) |
315 RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
316 OUTREG( regs, RADEON_VIPH_DV_LAT,
317 0xff |
318 (4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
319 (4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
320 (4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
321 (4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT)); // set timeslice
322 OUTREG( regs, RADEON_VIPH_DMA_CHUNK, 0x0);
323 OUTREG( regs, RADEON_TEST_DEBUG_CNTL, INREG( regs, RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL_OUT_EN));
324 break;
328 if( lock )
329 RELEASE_BEN( di->si->cp.lock );
333 // check whether VIP host is idle
334 // lock must be hold
335 static status_t Radeon_VIPIdle(
336 device_info *di )
338 vuint8 *regs = di->regs;
339 uint32 timeout;
341 //Radeon_WaitForIdle( di, false, false );
343 // if there is a stuck transaction, acknowledge that
344 timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
345 if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 )
347 OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT,
348 (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK);
349 return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
351 return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK;
354 static status_t RADEON_VIPFifoIdle(device_info *di, uint8 channel)
356 vuint8 *regs = di->regs;
357 uint32 timeout;
359 timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT);
360 if((timeout & 0x0000000f) & channel) /* lockup ?? */
362 OUTREG( regs, RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xfffffff0) | channel);
363 return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_ERROR;
365 return (INREG( regs, RADEON_VIPH_CONTROL) & 0x2000) ? B_BUSY : B_OK ;
369 // wait until VIP host is idle
370 // lock must be hold
371 static bool Radeon_VIPWaitForIdle(
372 device_info *di )
374 int i;
376 // wait 100x 1ms before giving up
377 for( i = 0; i < 100; ++i ) {
378 status_t res;
380 res = Radeon_VIPIdle( di );
381 if( res != B_BUSY ) {
382 if( res == B_OK )
383 return true;
384 else
385 return false;
388 snooze( 1000 );
391 return false;
395 // find VIP channel of a device
396 // return: >= 0 channel of device
397 // < 0 no device found
398 int Radeon_FindVIPDevice(
399 device_info *di, uint32 device_id )
401 uint channel;
402 uint32 cur_device_id;
404 // if card has no VIP port, let hardware detection fail;
405 // in this case, noone will bother us again
406 if( !di->has_vip ) {
407 SHOW_FLOW0( 3, "This Device has no VIP Bus.");
408 return -1;
411 ACQUIRE_BEN( di->si->cp.lock );
413 Radeon_VIPReset( di, false );
415 // there are up to 4 devices, connected to one of 4 channels
416 for( channel = 0; channel < 4; ++channel ) {
418 // read device id
419 if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id, false )) {
420 SHOW_FLOW( 3, "No device found on channel %d", channel);
421 continue;
424 // compare device id directly
425 if( cur_device_id == device_id ) {
426 SHOW_FLOW( 3, "Device %08lx found on channel %d", device_id, channel);
427 RELEASE_BEN( di->si->cp.lock );
428 return channel;
432 RELEASE_BEN( di->si->cp.lock );
434 // couldn't find device
435 return -1;