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