xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/bios.c (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 /*
2 	Copyright (c) 2002, Thomas Kurschel
3 
4 
5 	Part of Radeon kernel driver
6 
7 	BIOS detection and retrieval of vital data
8 
9 	Most of this data should be gathered directly,
10 	especially monitor detection should be done on
11 	demand so not all monitors need to be connected
12 	during boot
13 */
14 
15 #include "radeon_driver.h"
16 #include <mmio.h>
17 #include <bios_regs.h>
18 #include <config_regs.h>
19 #include <memcntrl_regs.h>
20 #include <fp_regs.h>
21 #include <crtc_regs.h>
22 #include <radeon_bios.h>
23 //#include "../common/utils.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 static const char ati_rom_sig[] = "761295520";
29 static const char *radeon_sig[] = {
30 	"RG6",			// r200
31 	"RADEON",		// r100
32 	"M6",			// mobile version of r100
33 	// probably an M6P;
34 	// anyway - this is the card I wrote this driver for!
35 	// (perhaps ATI tries to make the card incompatible to standard drivers)
36 	"P6",
37 	"RV200",		// rv200
38 	"RV100",		// rv100
39 	"M7",			// m7
40 	"RV250",		// rv250 R9100
41 	"V280",			// RV280 R9200
42 	"R300",			// R300 R9500 / R9700
43 	"R350",			// R350 R9800
44 	"R360",			// R360 R9800 XT
45 	"V350",			// RV350 R9600
46 	"V360",			// RV350 R9600 XT :guess
47 	"M9"			// guess: m9
48 };
49 
50 void Radeon_DetectRAM( device_info *di );
51 
52 
53 // find address of ROM
54 static char *Radeon_FindRom( rom_info *ri )
55 {
56 	uint32 segstart;
57 	char *rom_base;
58 	char *rom;
59 	int stage;
60 	int i,j;
61 
62 	for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
63 		stage = 1;
64 
65 		// find ROM
66 		rom_base = ri->bios_ptr + segstart - 0xc0000;
67 
68 		if( *rom_base == 0x55 && ((*(rom_base + 1)) & 0xff) == 0xaa )
69 			stage = 2;
70 
71 		if (stage != 2)
72 			continue;
73 
74 		// find signature of ATI
75 		rom = rom_base;
76 
77 		for( i = 0; i < 128 - (int)strlen( ati_rom_sig ) && stage != 3; i++ ) {
78 			if( ati_rom_sig[0] == *rom ) {
79 				if( strncmp(ati_rom_sig, rom, strlen( ati_rom_sig )) == 0 )
80 					stage = 3;
81 			}
82 			rom++;
83 		}
84 
85 		if( stage != 3 )
86 			continue;
87 
88 		// find signature of card
89 		rom = rom_base;
90 
91 		for( i = 0; (i < 512) && (stage != 4); i++ ) {
92 			for( j = 0; j < (int)sizeof( radeon_sig ) / (int)sizeof( radeon_sig[0] ); j++ ) {
93 				if( radeon_sig[j][0] == *rom ) {
94 					if( strncmp( radeon_sig[j], rom, strlen( radeon_sig[j] )) == 0 ) {
95 						SHOW_INFO( 2, "Signature: %s", radeon_sig[j] );
96 						stage = 4;
97 						break;
98 					}
99 				}
100 			}
101 			rom++;
102 		}
103 
104 		if( stage != 4 )
105 			continue;
106 
107 		SHOW_INFO( 2, "found ROM @0x%lx", segstart );
108 		return rom_base;
109 	}
110 
111 	SHOW_INFO0( 2, "no ROM found" );
112 	return NULL;
113 }
114 
115 
116 // PLL info is stored in ROM, probably to easily replace it
117 // and thus produce cards with different timings
118 static void Radeon_GetPLLInfo( device_info *di )
119 {
120 	uint8 *bios_header;
121 	PLL_BLOCK pll, *pll_info;
122 
123 	bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48);
124 	pll_info = (PLL_BLOCK *)(di->rom.rom_ptr + *(uint16 *)(bios_header + 0x30));
125 
126 	memcpy( &pll, pll_info, sizeof( pll ));
127 
128 	di->pll.xclk = (uint32)pll.XCLK;
129 	di->pll.ref_freq = (uint32)pll.PCLK_ref_freq;
130 	di->pll.ref_div = (uint32)pll.PCLK_ref_divider;
131 	di->pll.min_pll_freq = pll.PCLK_min_freq;
132 	di->pll.max_pll_freq = pll.PCLK_max_freq;
133 
134 	SHOW_INFO( 2, "ref_clk=%ld, ref_div=%ld, xclk=%ld, min_freq=%ld, max_freq=%ld from BIOS",
135 		di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
136 		di->pll.min_pll_freq, di->pll.max_pll_freq );
137 }
138 
139 const char *Mon2Str[] = {
140 	"N/C",
141 	"CRT",
142 	"CRT",
143 	"Laptop flatpanel",
144 	"DVI (flatpanel)",
145 	"secondary DVI (flatpanel) - unsupported",
146 	"Composite TV - unsupported",
147 	"S-Video out - unsupported"
148 };
149 
150 // ask BIOS what kind of monitor is connected to each port
151 static void Radeon_GetMonType( device_info *di )
152 {
153 	unsigned int tmp;
154 
155 	SHOW_FLOW0( 3, "" );
156 
157 	di->disp_type[0] = di->disp_type[1] = dt_none;
158 
159 	if (di->has_crtc2) {
160 		tmp = INREG( di->regs, RADEON_BIOS_4_SCRATCH );
161 
162 		// ordering of "if"s is important are multiple
163 		// devices can be concurrently connected to one port
164 		// (like both a CRT and a TV)
165 
166 		// primary port
167 		if (tmp & 0x08)
168 			di->disp_type[0] = dt_dvi_1;
169 		else if (tmp & 0x4)
170 			di->disp_type[0] = dt_lvds;
171 		else if (tmp & 0x200)
172 			di->disp_type[0] = dt_crt_1;
173 		else if (tmp & 0x10)
174 			di->disp_type[0] = dt_ctv;
175 		else if (tmp & 0x20)
176 			di->disp_type[0] = dt_stv;
177 
178 		// secondary port
179 		if (tmp & 0x2)
180 			di->disp_type[1] = dt_crt_2;
181 		else if (tmp & 0x800)
182 			di->disp_type[1] = dt_dvi_2;
183 		else if (tmp & 0x400)
184 			// this is unlikely - I only know about one LVDS unit
185 			di->disp_type[1] = dt_lvds;
186 		else if (tmp & 0x1000)
187 			di->disp_type[1] = dt_ctv;
188 		else if (tmp & 0x2000)
189 			di->disp_type[1] = dt_stv;
190 	} else {
191 		// regular Radeon
192 		di->disp_type[0] = dt_none;
193 
194 		tmp = INREG( di->regs, RADEON_FP_GEN_CNTL);
195 
196 		if( tmp & RADEON_FP_EN_TMDS )
197 			di->disp_type[0] = dt_dvi_1;
198 		else
199 			di->disp_type[0] = dt_crt_1;
200 	}
201 
202 	SHOW_INFO( 1, "BIOS reports %s on primary and %s on secondary port",
203 		Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
204 
205 	// remove unsupported devices
206 	if( di->disp_type[0] >= dt_dvi_2 )
207 		di->disp_type[0] = dt_none;
208 	if( di->disp_type[1] >= dt_dvi_2 )
209 		di->disp_type[1] = dt_none;
210 
211 	// HACK: overlays can only be shown on first CRTC;
212 	// if there's nothing on first port, connect
213 	// second port to first CRTC (proper signal routing
214 	// is hopefully done by BIOS)
215 	if( di->has_crtc2 ) {
216 		if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt_2 ) {
217 			di->disp_type[0] = dt_crt_1;
218 			di->disp_type[1] = dt_none;
219 		}
220 	}
221 
222 	SHOW_INFO( 1, "Effective routing: %s on primary and %s on secondary port",
223 		Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
224 }
225 
226 
227 // get flat panel info (does only make sense for Laptops
228 // with integrated display, but looking for it doesn't hurt,
229 // who knows which strange kind of combination is out there?)
230 static bool Radeon_GetBIOSDFPInfo( device_info *di )
231 {
232 	uint8 *bios_header;
233 	uint16 fpi_offset;
234 	FPI_BLOCK fpi;
235 	char panel_name[30];
236 	int i;
237 
238 	bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48);
239 
240 	fpi_offset = *(uint16 *)(bios_header + 0x40);
241 
242 	if( !fpi_offset ) {
243 		di->fp_info.panel_pwr_delay = 200;
244 		SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
245 		return false;
246 	}
247 
248 	memcpy( &fpi, di->rom.rom_ptr + fpi_offset, sizeof( fpi ));
249 
250 	memcpy( panel_name, &fpi.name, sizeof( fpi.name ) );
251 	panel_name[sizeof( fpi.name )] = 0;
252 
253 	SHOW_INFO( 2, "Panel ID string: %s", panel_name );
254 
255 	di->fp_info.panel_xres = fpi.panel_xres;
256 	di->fp_info.panel_yres = fpi.panel_yres;
257 
258 	SHOW_INFO( 2, "Panel Size from BIOS: %dx%d",
259 		di->fp_info.panel_xres, di->fp_info.panel_yres);
260 
261 	di->fp_info.panel_pwr_delay = fpi.panel_pwr_delay;
262 	if( di->fp_info.panel_pwr_delay > 2000 || di->fp_info.panel_pwr_delay < 0 )
263 		di->fp_info.panel_pwr_delay = 2000;
264 
265 	// there might be multiple supported resolutions stored;
266 	// we are looking for native resolution
267 	for( i = 0; i < 20; ++i ) {
268 		uint16 fpi_timing_ofs;
269 		FPI_TIMING_BLOCK fpi_timing;
270 
271 		fpi_timing_ofs = fpi.fpi_timing_ofs[i];
272 
273 		if( fpi_timing_ofs == 0 )
274 			break;
275 
276 		memcpy( &fpi_timing, di->rom.rom_ptr + fpi_timing_ofs, sizeof( fpi_timing ));
277 
278 		if( fpi_timing.panel_xres != di->fp_info.panel_xres ||
279 			fpi_timing.panel_yres != di->fp_info.panel_yres )
280 			continue;
281 
282 		di->fp_info.h_blank = (fpi_timing.h_total - fpi_timing.h_display) * 8;
283 		// TBD: seems like upper four bits of hsync_start contain garbage
284 		di->fp_info.h_over_plus = ((fpi_timing.h_sync_start & 0xfff) - fpi_timing.h_display - 1) * 8;
285 		di->fp_info.h_sync_width = fpi_timing.h_sync_width * 8;
286 		di->fp_info.v_blank = fpi_timing.v_total - fpi_timing.v_display;
287 		di->fp_info.v_over_plus = (fpi_timing.v_sync & 0x7ff) - fpi_timing.v_display;
288 		di->fp_info.v_sync_width = (fpi_timing.v_sync & 0xf800) >> 11;
289 		di->fp_info.dot_clock = fpi_timing.dot_clock * 10;
290 		return true;
291 	}
292 
293 	SHOW_ERROR0( 2, "Radeon: couldn't get Panel Timing from BIOS" );
294 	return false;
295 }
296 
297 
298 // try to reverse engineer DFP specification from
299 // timing currently set up in graphics cards registers
300 // (effectively, we hope that BIOS has set it up correctly
301 //  and noone has messed registers up yet; let's pray)
302 static void Radeon_RevEnvDFPSize( device_info *di )
303 {
304 	vuint8 *regs = di->regs;
305 /*	uint32 r;
306 
307 	// take a look at flat_panel.c of the accelerant how register values
308 	// are calculated - this is the inverse function
309 	r = INREG( regs, RADEON_FP_VERT_STRETCH );
310 	if( (r & RADEON_VERT_STRETCH_BLEND) == 0 ) {
311 		di->fp_info.panel_yres =
312 			((r & RADEON_VERT_PANEL_SIZE) >> RADEON_VERT_PANEL_SHIFT) + 1;
313 	} else {
314 		uint32 v_total = (INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP )
315 			>> RADEON_FP_CRTC_V_DISP_SHIFT) + 1;
316 		SHOW_INFO( 2, "stretched mode: v_total=%d", v_total );
317 		di->fp_info.panel_yres =
318 			(v_total * FIX_SCALE * RADEON_VERT_STRETCH_RATIO_MAX /
319 			 (r & RADEON_VERT_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
320 		// seems to be a BIOS bug - vertical size is 1 point too small
321 		// (checked by re-calculating stretch factor)
322 		++di->fp_info.panel_yres;
323 	}
324 
325 	r = INREG( regs, RADEON_FP_HORZ_STRETCH );
326 	if( (r & RADEON_HORZ_STRETCH_BLEND) == 0 ) {
327 		di->fp_info.panel_xres =
328 			(((r & RADEON_HORZ_PANEL_SIZE) >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
329 	} else {
330 		uint32 h_total = ((INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP )
331 			>> RADEON_FP_CRTC_H_DISP_SHIFT) + 1) * 8;
332 		SHOW_INFO( 2, "stretched mode: h_total=%d", h_total );
333 		di->fp_info.panel_xres =
334 			(h_total * FIX_SCALE * RADEON_HORZ_STRETCH_RATIO_MAX /
335 			 (r & RADEON_HORZ_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
336 	}*/
337 
338 	di->fp_info.panel_yres =
339 		((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE)
340 		>> RADEON_VERT_PANEL_SHIFT) + 1;
341 
342 	di->fp_info.panel_xres =
343 		(((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE)
344 		>> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
345 
346 	SHOW_INFO( 2, "detected panel size from registers: %dx%d",
347 		di->fp_info.panel_xres, di->fp_info.panel_yres);
348 }
349 
350 
351 // once more for getting precise timing
352 static void Radeon_RevEnvDFPTiming( device_info *di )
353 {
354 	vuint8 *regs = di->regs;
355 	uint32 r;
356 	uint16 a, b;
357 
358 
359 	r = INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP );
360 	// the magic "4" was found by trial and error and probably stems from fudge (see crtc.c)
361 	a = (r & RADEON_FP_CRTC_H_TOTAL_MASK)/* + 4*/;
362 	b = (r & RADEON_FP_CRTC_H_DISP_MASK) >> RADEON_FP_CRTC_H_DISP_SHIFT;
363 	di->fp_info.h_blank = (a - b) * 8;
364 
365 	SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
366 
367 	r = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
368 	di->fp_info.h_over_plus =
369 		((r & RADEON_FP_H_SYNC_STRT_CHAR_MASK)
370 			  	>> RADEON_FP_H_SYNC_STRT_CHAR_SHIFT) - b/* - 1*/;
371 	di->fp_info.h_over_plus *= 8;
372 	di->fp_info.h_sync_width =
373 		((r & RADEON_FP_H_SYNC_WID_MASK)
374 				>> RADEON_FP_H_SYNC_WID_SHIFT);
375 	// TBD: this seems to be wrong
376 	// (BIOS tells 112, this calculation leads to 24!)
377 	di->fp_info.h_sync_width *= 8;
378 
379 	r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP );
380 	a = (r & RADEON_FP_CRTC_V_TOTAL_MASK)/* + 1*/;
381 	b = (r & RADEON_FP_CRTC_V_DISP_MASK) >> RADEON_FP_CRTC_V_DISP_SHIFT;
382 	di->fp_info.v_blank = a - b;
383 
384 	SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
385 
386 	r = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
387 	di->fp_info.v_over_plus = (r & RADEON_FP_V_SYNC_STRT_MASK) - b;
388 	di->fp_info.v_sync_width = ((r & RADEON_FP_V_SYNC_WID_MASK)
389 		>> RADEON_FP_V_SYNC_WID_SHIFT)/* + 1*/;
390 
391 	// standard CRTC
392 
393 	r = INREG( regs, RADEON_CRTC_H_TOTAL_DISP );
394 	a = (r & RADEON_CRTC_H_TOTAL);
395 	b = (r & RADEON_CRTC_H_DISP) >> RADEON_CRTC_H_DISP_SHIFT;
396 	di->fp_info.h_blank = (a - b) * 8;
397 
398 	SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
399 
400 	r = INREG( regs, RADEON_CRTC_H_SYNC_STRT_WID );
401 	di->fp_info.h_over_plus =
402 		((r & RADEON_CRTC_H_SYNC_STRT_CHAR)
403 			  	>> RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) - b;
404 	di->fp_info.h_over_plus *= 8;
405 	di->fp_info.h_sync_width =
406 		((r & RADEON_CRTC_H_SYNC_WID)
407 				>> RADEON_CRTC_H_SYNC_WID_SHIFT);
408 	di->fp_info.h_sync_width *= 8;
409 
410 	r = INREG( regs, RADEON_CRTC_V_TOTAL_DISP );
411 	a = (r & RADEON_CRTC_V_TOTAL);
412 	b = (r & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
413 	di->fp_info.v_blank = a - b;
414 
415 	SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
416 
417 	r = INREG( regs, RADEON_CRTC_V_SYNC_STRT_WID );
418 	di->fp_info.v_over_plus = (r & RADEON_CRTC_V_SYNC_STRT) - b;
419 	di->fp_info.v_sync_width = ((r & RADEON_CRTC_V_SYNC_WID)
420 		>> RADEON_CRTC_V_SYNC_WID_SHIFT);
421 }
422 
423 
424 // get everything in terms of monitors connected to the card
425 static void Radeon_GetBIOSMon( device_info *di )
426 {
427 	Radeon_GetMonType( di );
428 
429     // reset all Flat Panel Info;
430     // it gets filled out step by step, and this way we know what's still missing
431     memset( &di->fp_info, 0, sizeof( di->fp_info ));
432 
433     // we assume that the only fp port is combined with standard port 0
434 	di->fp_info.disp_type = di->disp_type[0];
435 
436 	if( di->disp_type[0] == dt_dvi_1 || di->disp_type[0] == dt_lvds )
437 	{
438 		// there is a flat panel - get info about it
439 		Radeon_GetBIOSDFPInfo( di );
440 
441 		// if BIOS doesn't know, ask the registers
442 		if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0)
443 			Radeon_RevEnvDFPSize( di );
444 
445 		if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0)
446 			Radeon_RevEnvDFPTiming( di );
447 
448 		SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
449 			di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width );
450 		SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
451 			di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width );
452 		SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
453 	}
454 }
455 
456 
457 // detect amount of graphics memory
458 void Radeon_DetectRAM( device_info *di )
459 {
460 	vuint8 *regs = di->regs;
461 
462 	di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
463 
464 	// some production boards of m6 will return 0 if it's 8 MB
465 	if( di->local_mem_size == 0 )
466 		di->local_mem_size = 8 * 1024 *1024;
467 
468 	switch( INREG( regs, RADEON_MEM_SDRAM_MODE_REG ) & RADEON_MEM_CFG_TYPE_MASK ) {
469 		case RADEON_MEM_CFG_SDR:
470 			// SDR SGRAM (2:1)
471 			strcpy(di->ram_type, "SDR SGRAM");
472 			di->ram.ml = 4;
473 			di->ram.MB = 4;
474 			di->ram.Trcd = 1;
475 			di->ram.Trp = 2;
476 			di->ram.Twr = 1;
477 			di->ram.CL = 2;
478 			di->ram.loop_latency = 16;
479 			di->ram.Rloop = 16;
480 			di->ram.Tr2w = 0;
481 			break;
482 
483 		case RADEON_MEM_CFG_DDR:
484 			// DDR SGRAM
485 			strcpy(di->ram_type, "DDR SGRAM");
486 			di->ram.ml = 4;
487 			di->ram.MB = 4;
488 			di->ram.Trcd = 3;
489 			di->ram.Trp = 3;
490 			di->ram.Twr = 2;
491 			di->ram.CL = 3;
492 			di->ram.Tr2w = 1;
493 			di->ram.loop_latency = 16;
494 			di->ram.Rloop = 16;
495 			break;
496 
497 		// only one bit, so there's no default
498 	}
499 
500 	SHOW_INFO( 1, "%ld MB %s found", di->local_mem_size / 1024 / 1024,
501 		di->ram_type );
502 
503 	if( di->local_mem_size > 64 * 1024 * 1024 ) {
504 		di->local_mem_size = 64 * 1024 * 1024;
505 
506 		SHOW_INFO0( 1, "restricted to 64 MB" );
507 	}
508 }
509 
510 
511 // map and verify card's BIOS to see whether this really is a Radeon
512 // (as we need BIOS for further info we have to make sure we use the right one)
513 status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
514 {
515 	char buffer[B_OS_NAME_LENGTH];
516 
517 	sprintf(buffer, "%04X_%04X_%02X%02X%02X bios",
518 		pcii->vendor_id, pcii->device_id,
519 		pcii->bus, pcii->device, pcii->function);
520 
521 	// we only scan BIOS at legacy location in first MB;
522 	// using the PCI location would improve detection, especially
523 	// if multiple graphics cards are installed
524 	// BUT: BeOS uses the first graphics card it finds (sorted by
525 	// device name), thus you couldn't choose in BIOS which card
526 	// to use; checking the legacy location ensures that the card is
527 	// only detected if it's the primary card
528 	ri->bios_area = map_physical_memory( buffer, (void *)0xc0000,
529 		0x40000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr );
530 	if( ri->bios_area < 0 )
531 		return ri->bios_area;
532 
533 	ri->rom_ptr = Radeon_FindRom( ri );
534 
535 	return ri->rom_ptr != NULL ? B_OK : B_ERROR;
536 }
537 
538 
539 // unmap card's BIOS
540 void Radeon_UnmapBIOS( rom_info *ri )
541 {
542 	delete_area( ri->bios_area );
543 
544 	ri->bios_ptr = ri->rom_ptr = NULL;
545 }
546 
547 
548 // get everything valuable from BIOS (BIOS must be mapped)
549 status_t Radeon_ReadBIOSData( device_info *di )
550 {
551 	shared_info dummy_si;
552 	status_t result = B_OK;
553 
554 	// give Radeon_MapDevice something to play with
555 	di->si = &dummy_si;
556 
557 	// don't map frame buffer - we don't know its proper size yet!
558 	result = Radeon_MapDevice( di, true );
559 	if( result < 0 )
560 		goto err1;
561 
562 	Radeon_GetPLLInfo( di );
563 	Radeon_GetBIOSMon( di );
564 	Radeon_DetectRAM( di );
565 
566 	Radeon_UnmapDevice( di );
567 
568 err1:
569 	di->si = NULL;
570 
571 	return result;
572 }
573