xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/bios.c (revision cc7e844c12cbb4d60c80edac08a503d5cf872929)
11da2dde8Sshadow303 /*
21da2dde8Sshadow303 	Copyright (c) 2002, Thomas Kurschel
31da2dde8Sshadow303 
41da2dde8Sshadow303 
51da2dde8Sshadow303 	Part of Radeon kernel driver
61da2dde8Sshadow303 
71da2dde8Sshadow303 	BIOS detection and retrieval of vital data
81da2dde8Sshadow303 
91da2dde8Sshadow303 	Most of this data should be gathered directly,
101da2dde8Sshadow303 	especially monitor detection should be done on
111da2dde8Sshadow303 	demand so not all monitors need to be connected
121da2dde8Sshadow303 	during boot
131da2dde8Sshadow303 */
141da2dde8Sshadow303 
151da2dde8Sshadow303 #include "radeon_driver.h"
165f6e3f51Sshadow303 #include "mmio.h"
175f6e3f51Sshadow303 #include "bios_regs.h"
185f6e3f51Sshadow303 #include "config_regs.h"
195f6e3f51Sshadow303 #include "memcntrl_regs.h"
208841d8bcSAxel Dörfler #include "buscntrl_regs.h"
215f6e3f51Sshadow303 #include "fp_regs.h"
225f6e3f51Sshadow303 #include "crtc_regs.h"
238841d8bcSAxel Dörfler #include "ddc_regs.h"
245f6e3f51Sshadow303 #include "radeon_bios.h"
255f6e3f51Sshadow303 #include "utils.h"
261da2dde8Sshadow303 
271da2dde8Sshadow303 #include <stdio.h>
281da2dde8Sshadow303 #include <string.h>
291da2dde8Sshadow303 
30300bef58SAxel Dörfler #define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
311da2dde8Sshadow303 
32300bef58SAxel Dörfler #define RADEON_BIOS8(v) 	 (di->rom.rom_ptr[v])
33300bef58SAxel Dörfler #define RADEON_BIOS16(v) 	((di->rom.rom_ptr[v]) | \
34300bef58SAxel Dörfler 				(di->rom.rom_ptr[(v) + 1] << 8))
35300bef58SAxel Dörfler #define RADEON_BIOS32(v) 	((di->rom.rom_ptr[v]) | \
36f9a5b215SAxel Dörfler 				(di->rom.rom_ptr[(v) + 1] << 8) | \
37f9a5b215SAxel Dörfler 				(di->rom.rom_ptr[(v) + 2] << 16) | \
38300bef58SAxel Dörfler 				(di->rom.rom_ptr[(v) + 3] << 24))
39300bef58SAxel Dörfler 
40300bef58SAxel Dörfler static const char ati_rom_sig[] = "761295520";
411da2dde8Sshadow303 
42f9a5b215SAxel Dörfler static const tmds_pll_info default_tmds_pll[14][4] =
43f9a5b215SAxel Dörfler {
44f9a5b215SAxel Dörfler     {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},			// r100
45f9a5b215SAxel Dörfler     {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},			// rv100
46f9a5b215SAxel Dörfler     {{0, 0}, {0, 0}, {0, 0}, {0, 0}},						// rs100
47f9a5b215SAxel Dörfler     {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},			// rv200
48f9a5b215SAxel Dörfler     {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},			// rs200
49f9a5b215SAxel Dörfler     {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},			// r200
50f9a5b215SAxel Dörfler     {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}},			// rv250
51f9a5b215SAxel Dörfler     {{0, 0}, {0, 0}, {0, 0}, {0, 0}},						// rs300
52f9a5b215SAxel Dörfler     {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, 	// rv280
53f9a5b215SAxel Dörfler     {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},				// r300
54f9a5b215SAxel Dörfler     {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},				// r350
55f9a5b215SAxel Dörfler     {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},			// rv350
56f9a5b215SAxel Dörfler     {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},			// rv380
57f9a5b215SAxel Dörfler     {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},				// r420
58f9a5b215SAxel Dörfler };
59f9a5b215SAxel Dörfler 
60f9a5b215SAxel Dörfler 
615f6e3f51Sshadow303 // find address of ROM;
625f6e3f51Sshadow303 // this code is really nasty as maintaining the radeon signatures
635f6e3f51Sshadow303 // is almost impossible (the signatures provided by ATI are always out-dated);
645f6e3f51Sshadow303 // further, if there is more then one card built into the computer, we
655f6e3f51Sshadow303 // may detect the wrong BIOS!
665f6e3f51Sshadow303 // we have two possible solutions:
675f6e3f51Sshadow303 // 1. use the PCI location as stored in BIOS
685f6e3f51Sshadow303 // 2. verify the IO-base address as stored in BIOS
695f6e3f51Sshadow303 // I have no clue how these values are _written_ into the BIOS, and
705f6e3f51Sshadow303 // unfortunately, every BIOS does the detection in a different way,
715f6e3f51Sshadow303 // so I'm not sure which is the _right_ way of doing it
Radeon_FindRom(rom_info * ri)721da2dde8Sshadow303 static char *Radeon_FindRom( rom_info *ri )
731da2dde8Sshadow303 {
741da2dde8Sshadow303 	uint32 segstart;
755f6e3f51Sshadow303 	uint8 *rom_base;
761da2dde8Sshadow303 	char *rom;
77300bef58SAxel Dörfler 	int i;
781da2dde8Sshadow303 
791da2dde8Sshadow303 	for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
805f6e3f51Sshadow303 		bool found = false;
811da2dde8Sshadow303 
821da2dde8Sshadow303 		// find ROM
831da2dde8Sshadow303 		rom_base = ri->bios_ptr + segstart - 0xc0000;
841da2dde8Sshadow303 
855f6e3f51Sshadow303 		if( rom_base[0] != 0x55 || rom_base[1] != 0xaa )
861da2dde8Sshadow303 			continue;
871da2dde8Sshadow303 
881da2dde8Sshadow303 		// find signature of ATI
891da2dde8Sshadow303 		rom = rom_base;
901da2dde8Sshadow303 
915f6e3f51Sshadow303 		found = false;
921da2dde8Sshadow303 
935f6e3f51Sshadow303 		for( i = 0; i < 128 - strlen( ati_rom_sig ); i++ ) {
945f6e3f51Sshadow303 			if( ati_rom_sig[0] == rom_base[i] ) {
955f6e3f51Sshadow303 				if( strncmp(ati_rom_sig, rom_base + i, strlen( ati_rom_sig )) == 0 ) {
965f6e3f51Sshadow303 					found = true;
971da2dde8Sshadow303 					break;
981da2dde8Sshadow303 				}
991da2dde8Sshadow303 			}
1001da2dde8Sshadow303 		}
1015f6e3f51Sshadow303 
1025f6e3f51Sshadow303 		if( !found )
1035f6e3f51Sshadow303 			continue;
1045f6e3f51Sshadow303 
105300bef58SAxel Dörfler 		// EK don't bother looking for signiture now, due to lack of consistancy.
1061da2dde8Sshadow303 
107*cc7e844cSMurai Takashi 		SHOW_INFO( 2, "found ROM @0x%" B_PRIx32, segstart );
1081da2dde8Sshadow303 		return rom_base;
1091da2dde8Sshadow303 	}
1101da2dde8Sshadow303 
1111da2dde8Sshadow303 	SHOW_INFO0( 2, "no ROM found" );
1121da2dde8Sshadow303 	return NULL;
1131da2dde8Sshadow303 }
1141da2dde8Sshadow303 
1151da2dde8Sshadow303 
1165f6e3f51Sshadow303 // PLL info is stored in ROM, probably it's too easy to replace it
1175f6e3f51Sshadow303 // and thus they produce cards with different timings
Radeon_GetPLLInfo(device_info * di)1181da2dde8Sshadow303 static void Radeon_GetPLLInfo( device_info *di )
1191da2dde8Sshadow303 {
1201da2dde8Sshadow303 	uint8 *bios_header;
121300bef58SAxel Dörfler 	uint8 *tmp;
1221da2dde8Sshadow303 	PLL_BLOCK pll, *pll_info;
1231da2dde8Sshadow303 
1241da2dde8Sshadow303 	bios_header = di->rom.rom_ptr + *(uint16 *)(di->rom.rom_ptr + 0x48);
1251da2dde8Sshadow303 	pll_info = (PLL_BLOCK *)(di->rom.rom_ptr + *(uint16 *)(bios_header + 0x30));
1261da2dde8Sshadow303 
127300bef58SAxel Dörfler 	// determine type of ROM
128300bef58SAxel Dörfler 
129300bef58SAxel Dörfler 	tmp = bios_header + 4;
130300bef58SAxel Dörfler 
131300bef58SAxel Dörfler     if ((	*tmp 	== 'A'
132300bef58SAxel Dörfler    		&& *(tmp+1) == 'T'
133300bef58SAxel Dörfler    		&& *(tmp+2) == 'O'
134300bef58SAxel Dörfler    		&& *(tmp+3) == 'M'
135300bef58SAxel Dörfler    		)
136300bef58SAxel Dörfler    		||
137300bef58SAxel Dörfler    		(	*tmp	== 'M'
138300bef58SAxel Dörfler    		&& *(tmp+1) == 'O'
139300bef58SAxel Dörfler    		&& *(tmp+2) == 'T'
140300bef58SAxel Dörfler    		&& *(tmp+3) == 'A'
141300bef58SAxel Dörfler    		))
142300bef58SAxel Dörfler 	{
143300bef58SAxel Dörfler 		int bios_header, master_data_start, pll_start;
144300bef58SAxel Dörfler 		di->is_atombios = true;
145300bef58SAxel Dörfler 
146300bef58SAxel Dörfler 		bios_header 	  	 = RADEON_BIOS16(0x48);
147300bef58SAxel Dörfler 		master_data_start 	 = RADEON_BIOS16(bios_header + 32);
148300bef58SAxel Dörfler 		pll_start 		  	 = RADEON_BIOS16(master_data_start + 12);
149300bef58SAxel Dörfler 
150300bef58SAxel Dörfler 		di->pll.ref_div 	 = 0;
151300bef58SAxel Dörfler 		di->pll.max_pll_freq = RADEON_BIOS16(pll_start + 32);
152300bef58SAxel Dörfler 		di->pll.xclk 		 = RADEON_BIOS16(pll_start + 72);
153300bef58SAxel Dörfler 		di->pll.min_pll_freq = RADEON_BIOS16(pll_start + 78);
154300bef58SAxel Dörfler 		di->pll.ref_freq 	 = RADEON_BIOS16(pll_start + 82);
155300bef58SAxel Dörfler 
156*cc7e844cSMurai Takashi 		SHOW_INFO( 2, "TESTING "
157*cc7e844cSMurai Takashi 			"ref_clk=%" B_PRIu32 ", ref_div=%" B_PRIu32 ", xclk=%" B_PRIu32 ", "
158*cc7e844cSMurai Takashi 			"min_freq=%" B_PRIu32 ", max_freq=%" B_PRIu32 " from ATOM Bios",
159300bef58SAxel Dörfler 			di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
160300bef58SAxel Dörfler 			di->pll.min_pll_freq, di->pll.max_pll_freq );
161300bef58SAxel Dörfler 
162300bef58SAxel Dörfler 		// Unused by beos driver so it appears...
163300bef58SAxel Dörfler 		// info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0;
164300bef58SAxel Dörfler 		// info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0;
165300bef58SAxel Dörfler 		// if (info->sclk == 0) info->sclk = 200;
166300bef58SAxel Dörfler 		// if (info->mclk == 0) info->mclk = 200;
167300bef58SAxel Dörfler 
168300bef58SAxel Dörfler 	}
169300bef58SAxel Dörfler     else
170300bef58SAxel Dörfler 	{
171300bef58SAxel Dörfler 		di->is_atombios = false;
172300bef58SAxel Dörfler 
1731da2dde8Sshadow303 		memcpy( &pll, pll_info, sizeof( pll ));
1741da2dde8Sshadow303 
1751da2dde8Sshadow303 		di->pll.xclk 		 = (uint32)pll.XCLK;
1761da2dde8Sshadow303 		di->pll.ref_freq 	 = (uint32)pll.PCLK_ref_freq;
1771da2dde8Sshadow303 		di->pll.ref_div 	 = (uint32)pll.PCLK_ref_divider;
1781da2dde8Sshadow303 		di->pll.min_pll_freq = pll.PCLK_min_freq;
1791da2dde8Sshadow303 		di->pll.max_pll_freq = pll.PCLK_max_freq;
1801da2dde8Sshadow303 
181*cc7e844cSMurai Takashi 		SHOW_INFO( 2,
182*cc7e844cSMurai Takashi 			"ref_clk=%" B_PRIu32 ", ref_div=%" B_PRIu32 ", xclk=%" B_PRIu32 ", "
183*cc7e844cSMurai Takashi 			"min_freq=%" B_PRIu32 ", max_freq=%" B_PRIu32 " from Legacy BIOS",
1841da2dde8Sshadow303 			di->pll.ref_freq, di->pll.ref_div, di->pll.xclk,
1851da2dde8Sshadow303 			di->pll.min_pll_freq, di->pll.max_pll_freq );
186300bef58SAxel Dörfler 
187300bef58SAxel Dörfler 	}
188300bef58SAxel Dörfler 
1891da2dde8Sshadow303 }
1901da2dde8Sshadow303 
1915f6e3f51Sshadow303 /*
1921da2dde8Sshadow303 const char *Mon2Str[] = {
1931da2dde8Sshadow303 	"N/C",
1941da2dde8Sshadow303 	"CRT",
1951da2dde8Sshadow303 	"CRT",
1961da2dde8Sshadow303 	"Laptop flatpanel",
1971da2dde8Sshadow303 	"DVI (flatpanel)",
1981da2dde8Sshadow303 	"secondary DVI (flatpanel) - unsupported",
1995f6e3f51Sshadow303 	"Composite TV",
2005f6e3f51Sshadow303 	"S-Video out"
2015f6e3f51Sshadow303 };*/
2021da2dde8Sshadow303 
2035f6e3f51Sshadow303 /*
2041da2dde8Sshadow303 // ask BIOS what kind of monitor is connected to each port
2051da2dde8Sshadow303 static void Radeon_GetMonType( device_info *di )
2061da2dde8Sshadow303 {
2071da2dde8Sshadow303 	unsigned int tmp;
2081da2dde8Sshadow303 
2091da2dde8Sshadow303 	SHOW_FLOW0( 3, "" );
2101da2dde8Sshadow303 
2111da2dde8Sshadow303 	di->disp_type[0] = di->disp_type[1] = dt_none;
2121da2dde8Sshadow303 
2131da2dde8Sshadow303 	if (di->has_crtc2) {
2141da2dde8Sshadow303 		tmp = INREG( di->regs, RADEON_BIOS_4_SCRATCH );
2151da2dde8Sshadow303 
2165f6e3f51Sshadow303 		// ordering of "if"s is important as multiple
2171da2dde8Sshadow303 		// devices can be concurrently connected to one port
2181da2dde8Sshadow303 		// (like both a CRT and a TV)
2191da2dde8Sshadow303 
2201da2dde8Sshadow303 		// primary port
2215f6e3f51Sshadow303 		// having flat-panel support is most important
2221da2dde8Sshadow303 		if (tmp & 0x08)
2235f6e3f51Sshadow303 			di->disp_type[0] = dt_dvi;
2241da2dde8Sshadow303 		else if (tmp & 0x4)
2251da2dde8Sshadow303 			di->disp_type[0] = dt_lvds;
2261da2dde8Sshadow303 		else if (tmp & 0x200)
2275f6e3f51Sshadow303 			di->disp_type[0] = dt_tv_crt;
2281da2dde8Sshadow303 		else if (tmp & 0x10)
2291da2dde8Sshadow303 			di->disp_type[0] = dt_ctv;
2301da2dde8Sshadow303 		else if (tmp & 0x20)
2311da2dde8Sshadow303 			di->disp_type[0] = dt_stv;
2321da2dde8Sshadow303 
2331da2dde8Sshadow303 		// secondary port
2345f6e3f51Sshadow303 		// having TV-Out support is more important then CRT support
2355f6e3f51Sshadow303 		// (CRT gets signal anyway)
2365f6e3f51Sshadow303 		if (tmp & 0x1000)
2371da2dde8Sshadow303 			di->disp_type[1] = dt_ctv;
2381da2dde8Sshadow303 		else if (tmp & 0x2000)
2391da2dde8Sshadow303 			di->disp_type[1] = dt_stv;
2405f6e3f51Sshadow303 		else if (tmp & 0x2)
2415f6e3f51Sshadow303 			di->disp_type[1] = dt_crt;
2425f6e3f51Sshadow303 		else if (tmp & 0x800)
2435f6e3f51Sshadow303 			di->disp_type[1] = dt_dvi_ext;
2445f6e3f51Sshadow303 		else if (tmp & 0x400)
2455f6e3f51Sshadow303 			// this is unlikely - I only know about one LVDS unit
2465f6e3f51Sshadow303 			di->disp_type[1] = dt_lvds;
2471da2dde8Sshadow303 	} else {
2481da2dde8Sshadow303 		// regular Radeon
2495f6e3f51Sshadow303 		// TBD: no TV-Out detection
2501da2dde8Sshadow303 		di->disp_type[0] = dt_none;
2511da2dde8Sshadow303 
2521da2dde8Sshadow303 		tmp = INREG( di->regs, RADEON_FP_GEN_CNTL);
2531da2dde8Sshadow303 
2541da2dde8Sshadow303 		if( tmp & RADEON_FP_EN_TMDS )
2555f6e3f51Sshadow303 			di->disp_type[0] = dt_dvi;
2561da2dde8Sshadow303 		else
2575f6e3f51Sshadow303 			di->disp_type[0] = dt_crt;
2581da2dde8Sshadow303 	}
2591da2dde8Sshadow303 
2601da2dde8Sshadow303 	SHOW_INFO( 1, "BIOS reports %s on primary and %s on secondary port",
2611da2dde8Sshadow303 		Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
2621da2dde8Sshadow303 
2631da2dde8Sshadow303 	// remove unsupported devices
2645f6e3f51Sshadow303 	if( di->disp_type[0] >= dt_dvi_ext )
2651da2dde8Sshadow303 		di->disp_type[0] = dt_none;
2665f6e3f51Sshadow303 	if( di->disp_type[1] >= dt_dvi_ext )
2671da2dde8Sshadow303 		di->disp_type[1] = dt_none;
2681da2dde8Sshadow303 
2691da2dde8Sshadow303 	// HACK: overlays can only be shown on first CRTC;
2701da2dde8Sshadow303 	// if there's nothing on first port, connect
2711da2dde8Sshadow303 	// second port to first CRTC (proper signal routing
2721da2dde8Sshadow303 	// is hopefully done by BIOS)
2731da2dde8Sshadow303 	if( di->has_crtc2 ) {
2745f6e3f51Sshadow303 		if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt ) {
2755f6e3f51Sshadow303 			di->disp_type[0] = dt_crt;
2761da2dde8Sshadow303 			di->disp_type[1] = dt_none;
2771da2dde8Sshadow303 		}
2781da2dde8Sshadow303 	}
2791da2dde8Sshadow303 
2801da2dde8Sshadow303 	SHOW_INFO( 1, "Effective routing: %s on primary and %s on secondary port",
2811da2dde8Sshadow303 		Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
2821da2dde8Sshadow303 }
2835f6e3f51Sshadow303 */
2841da2dde8Sshadow303 
285b8fb3d17SAxel Dörfler 
Radeon_GetConnectorInfoFromBIOS(device_info * di)286b8fb3d17SAxel Dörfler static bool Radeon_GetConnectorInfoFromBIOS ( device_info* di )
287b8fb3d17SAxel Dörfler {
288b8fb3d17SAxel Dörfler 
289b8fb3d17SAxel Dörfler 	ptr_disp_entity ptr_entity = &di->routing;
290b8fb3d17SAxel Dörfler 	int i = 0, j, tmp, tmp0=0, tmp1=0;
291b8fb3d17SAxel Dörfler 
292b8fb3d17SAxel Dörfler 	int bios_header, master_data_start;
293b8fb3d17SAxel Dörfler 
294b8fb3d17SAxel Dörfler 	bios_header = RADEON_BIOS16(0x48);
295b8fb3d17SAxel Dörfler 
296b8fb3d17SAxel Dörfler 	if (di->is_atombios)
297b8fb3d17SAxel Dörfler 	{
298b8fb3d17SAxel Dörfler 		master_data_start = RADEON_BIOS16( bios_header + 32 );
299b8fb3d17SAxel Dörfler 		tmp = RADEON_BIOS16( master_data_start + 22);
300b8fb3d17SAxel Dörfler 		if (tmp) {
301b8fb3d17SAxel Dörfler 			int crtc = 0, id[2];
302b8fb3d17SAxel Dörfler 			tmp1 = RADEON_BIOS16( tmp + 4 );
303b8fb3d17SAxel Dörfler 			for (i=0; i<8; i++) {
304b8fb3d17SAxel Dörfler 				if(tmp1 & (1<<i)) {
305b8fb3d17SAxel Dörfler 					uint16 portinfo = RADEON_BIOS16( tmp + 6 + i * 2 );
306b8fb3d17SAxel Dörfler 					if (crtc < 2) {
307b8fb3d17SAxel Dörfler 						if ((i == 2) || (i == 6)) continue; /* ignore TV here */
308b8fb3d17SAxel Dörfler 
309b8fb3d17SAxel Dörfler 						if ( crtc == 1 ) {
310b8fb3d17SAxel Dörfler 							/* sharing same port with id[0] */
311b8fb3d17SAxel Dörfler 							if ((( portinfo >> 8) & 0xf) == id[0] ) {
312b8fb3d17SAxel Dörfler 								if (i == 3)
313b8fb3d17SAxel Dörfler 									ptr_entity->port_info[0].tmds_type = tmds_int;
314b8fb3d17SAxel Dörfler 								else if (i == 7)
315b8fb3d17SAxel Dörfler 									ptr_entity->port_info[0].tmds_type = tmds_ext;
316b8fb3d17SAxel Dörfler 
317b8fb3d17SAxel Dörfler 								if (ptr_entity->port_info[0].dac_type == dac_unknown)
318b8fb3d17SAxel Dörfler 									ptr_entity->port_info[0].dac_type = (portinfo & 0xf) - 1;
319b8fb3d17SAxel Dörfler 								continue;
320b8fb3d17SAxel Dörfler 							}
321b8fb3d17SAxel Dörfler 						}
322b8fb3d17SAxel Dörfler 
323b8fb3d17SAxel Dörfler 						id[crtc] = (portinfo>>8) & 0xf;
324b8fb3d17SAxel Dörfler 						ptr_entity->port_info[crtc].dac_type = (portinfo & 0xf) - 1;
325b8fb3d17SAxel Dörfler 						ptr_entity->port_info[crtc].connector_type = (portinfo>>4) & 0xf;
326b8fb3d17SAxel Dörfler 						if (i == 3)
327b8fb3d17SAxel Dörfler 							ptr_entity->port_info[crtc].tmds_type = tmds_int;
328b8fb3d17SAxel Dörfler 						else if (i == 7)
329b8fb3d17SAxel Dörfler 							ptr_entity->port_info[crtc].tmds_type = tmds_ext;
330b8fb3d17SAxel Dörfler 
331b8fb3d17SAxel Dörfler 						tmp0 = RADEON_BIOS16( master_data_start + 24);
332b8fb3d17SAxel Dörfler 						if( tmp0 && id[crtc] ) {
333b8fb3d17SAxel Dörfler 							switch (RADEON_BIOS16(tmp0 + 4 + 27 * id[crtc]) * 4)
334b8fb3d17SAxel Dörfler 							{
335b8fb3d17SAxel Dörfler 								case RADEON_GPIO_MONID:
336b8fb3d17SAxel Dörfler 									ptr_entity->port_info[crtc].ddc_type = ddc_monid;
337b8fb3d17SAxel Dörfler 									break;
338b8fb3d17SAxel Dörfler 								case RADEON_GPIO_DVI_DDC:
339b8fb3d17SAxel Dörfler 									ptr_entity->port_info[crtc].ddc_type = ddc_dvi;
340b8fb3d17SAxel Dörfler 									break;
341b8fb3d17SAxel Dörfler 								case RADEON_GPIO_VGA_DDC:
342b8fb3d17SAxel Dörfler 									ptr_entity->port_info[crtc].ddc_type = ddc_vga;
343b8fb3d17SAxel Dörfler 									break;
344b8fb3d17SAxel Dörfler 								case RADEON_GPIO_CRT2_DDC:
345b8fb3d17SAxel Dörfler 									ptr_entity->port_info[crtc].ddc_type = ddc_crt2;
346b8fb3d17SAxel Dörfler 									break;
347b8fb3d17SAxel Dörfler 								default:
348b8fb3d17SAxel Dörfler 									ptr_entity->port_info[crtc].ddc_type = ddc_none_detected;
349b8fb3d17SAxel Dörfler 									break;
350b8fb3d17SAxel Dörfler 							}
351b8fb3d17SAxel Dörfler 
352b8fb3d17SAxel Dörfler 						} else {
353b8fb3d17SAxel Dörfler 							ptr_entity->port_info[crtc].ddc_type = ddc_none_detected;
354b8fb3d17SAxel Dörfler 						}
355b8fb3d17SAxel Dörfler 						crtc++;
356b8fb3d17SAxel Dörfler 					} else {
357b8fb3d17SAxel Dörfler 						/* we have already had two CRTCs assigned. the rest may share the same
358b8fb3d17SAxel Dörfler 						* port with the existing connector, fill in them accordingly.
359b8fb3d17SAxel Dörfler 						*/
360b8fb3d17SAxel Dörfler 						for ( j = 0; j < 2; j++ ) {
361b8fb3d17SAxel Dörfler 							if ((( portinfo >> 8 ) & 0xf ) == id[j] ) {
362b8fb3d17SAxel Dörfler 								if ( i == 3 )
363b8fb3d17SAxel Dörfler 								ptr_entity->port_info[j].tmds_type = tmds_int;
364b8fb3d17SAxel Dörfler 								else if (i == 7)
365b8fb3d17SAxel Dörfler 								ptr_entity->port_info[j].tmds_type = tmds_ext;
366b8fb3d17SAxel Dörfler 
367b8fb3d17SAxel Dörfler 								if ( ptr_entity->port_info[j].dac_type == dac_unknown )
368b8fb3d17SAxel Dörfler 									ptr_entity->port_info[j].dac_type = ( portinfo & 0xf ) - 1;
369b8fb3d17SAxel Dörfler 							}
370b8fb3d17SAxel Dörfler 						}
371b8fb3d17SAxel Dörfler 					}
372b8fb3d17SAxel Dörfler 				}
373b8fb3d17SAxel Dörfler 			}
374b8fb3d17SAxel Dörfler 
375b8fb3d17SAxel Dörfler 			for (i=0; i<2; i++) {
376b8fb3d17SAxel Dörfler 				SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
377b8fb3d17SAxel Dörfler 					i, ptr_entity->port_info[i].ddc_type, ptr_entity->port_info[i].dac_type,
378b8fb3d17SAxel Dörfler 					ptr_entity->port_info[i].tmds_type, ptr_entity->port_info[i].connector_type);
379b8fb3d17SAxel Dörfler 		    }
380b8fb3d17SAxel Dörfler 		} else {
381b8fb3d17SAxel Dörfler 			SHOW_INFO0( 4 , "No Device Info Table found!");
382b8fb3d17SAxel Dörfler 			return FALSE;
383b8fb3d17SAxel Dörfler 		}
384b8fb3d17SAxel Dörfler 	} else {
385b8fb3d17SAxel Dörfler 		/* Some laptops only have one connector (VGA) listed in the connector table,
386b8fb3d17SAxel Dörfler 		* we need to add LVDS in as a non-DDC display.
387b8fb3d17SAxel Dörfler 		* Note, we can't assume the listed VGA will be filled in PortInfo[0],
388b8fb3d17SAxel Dörfler 		* when walking through connector table. connector_found has following meaning:
389b8fb3d17SAxel Dörfler 		* 0 -- nothing found,
390b8fb3d17SAxel Dörfler 		* 1 -- only PortInfo[0] filled,
391b8fb3d17SAxel Dörfler 		* 2 -- only PortInfo[1] filled,
392b8fb3d17SAxel Dörfler 		* 3 -- both are filled.
393b8fb3d17SAxel Dörfler 		*/
394b8fb3d17SAxel Dörfler 		int connector_found = 0;
395b8fb3d17SAxel Dörfler 
396b8fb3d17SAxel Dörfler 		if ((tmp = RADEON_BIOS16( bios_header + 0x50 ))) {
397b8fb3d17SAxel Dörfler 			for ( i = 1; i < 4; i++ ) {
398b8fb3d17SAxel Dörfler 
399b8fb3d17SAxel Dörfler 				if (!(RADEON_BIOS16( tmp + i * 2 )))
400b8fb3d17SAxel Dörfler 					break; /* end of table */
401b8fb3d17SAxel Dörfler 
402b8fb3d17SAxel Dörfler 				tmp0 = RADEON_BIOS16( tmp + i * 2 );
403b8fb3d17SAxel Dörfler 				if ((( tmp0 >> 12 ) & 0x0f ) == 0 )
404b8fb3d17SAxel Dörfler 					continue;     /* no connector */
405b8fb3d17SAxel Dörfler 				if (connector_found > 0) {
406b8fb3d17SAxel Dörfler 					if (ptr_entity->port_info[tmp1].ddc_type == (( tmp0 >> 8 ) & 0x0f ))
407b8fb3d17SAxel Dörfler 						continue;	/* same connector */
408b8fb3d17SAxel Dörfler 				}
409b8fb3d17SAxel Dörfler 
410b8fb3d17SAxel Dörfler 				/* internal ddc_dvi port will get assigned to portinfo[0], or if there is no ddc_dvi (like in some igps). */
411b8fb3d17SAxel Dörfler 				tmp1 = (((( tmp0 >> 8 ) & 0xf ) == ddc_dvi ) || ( tmp1 == 1 )) ? 0 : 1; /* determine port info index */
412b8fb3d17SAxel Dörfler 
413b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].ddc_type = (tmp0 >> 8) & 0x0f;
414b8fb3d17SAxel Dörfler 				if (ptr_entity->port_info[tmp1].ddc_type > ddc_crt2)
415b8fb3d17SAxel Dörfler 					ptr_entity->port_info[tmp1].ddc_type = ddc_none_detected;
416b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].dac_type = (tmp0 & 0x01) ? dac_tvdac : dac_primary;
417b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].connector_type = (tmp0 >> 12) & 0x0f;
418b8fb3d17SAxel Dörfler 				if (ptr_entity->port_info[tmp1].connector_type > connector_unsupported)
419b8fb3d17SAxel Dörfler 					ptr_entity->port_info[tmp1].connector_type = connector_unsupported;
420b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].tmds_type = ((tmp0 >> 4) & 0x01) ? tmds_ext : tmds_int;
421b8fb3d17SAxel Dörfler 
422b8fb3d17SAxel Dörfler 				/* some sanity checks */
423b8fb3d17SAxel Dörfler 				if (((ptr_entity->port_info[tmp1].connector_type != connector_dvi_d) &&
424b8fb3d17SAxel Dörfler 				(ptr_entity->port_info[tmp1].connector_type != connector_dvi_i)) &&
425b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].tmds_type == tmds_int)
426b8fb3d17SAxel Dörfler 				ptr_entity->port_info[tmp1].tmds_type = tmds_unknown;
427b8fb3d17SAxel Dörfler 
428b8fb3d17SAxel Dörfler 				connector_found += (tmp1 + 1);
429b8fb3d17SAxel Dörfler 			}
430b8fb3d17SAxel Dörfler 		} else {
431b8fb3d17SAxel Dörfler 			SHOW_INFO0(4, "No Connector Info Table found!");
432b8fb3d17SAxel Dörfler 			return FALSE;
433b8fb3d17SAxel Dörfler 		}
434b8fb3d17SAxel Dörfler 
435b8fb3d17SAxel Dörfler 		if (di->is_mobility)
436b8fb3d17SAxel Dörfler 		{
437b8fb3d17SAxel Dörfler 			/* For the cases where only one VGA connector is found,
438b8fb3d17SAxel Dörfler 			we assume LVDS is not listed in the connector table,
439b8fb3d17SAxel Dörfler 			add it in here as the first port.
440b8fb3d17SAxel Dörfler 			*/
441b8fb3d17SAxel Dörfler 			if ((connector_found < 3) && (ptr_entity->port_info[tmp1].connector_type == connector_crt)) {
442b8fb3d17SAxel Dörfler 				if (connector_found == 1) {
443b8fb3d17SAxel Dörfler 					memcpy (&ptr_entity->port_info[1],
444b8fb3d17SAxel Dörfler 						&ptr_entity->port_info[0],
445b8fb3d17SAxel Dörfler 							sizeof (ptr_entity->port_info[0]));
446b8fb3d17SAxel Dörfler 				}
447b8fb3d17SAxel Dörfler 				ptr_entity->port_info[0].dac_type = dac_tvdac;
448b8fb3d17SAxel Dörfler 				ptr_entity->port_info[0].tmds_type = tmds_unknown;
449b8fb3d17SAxel Dörfler 				ptr_entity->port_info[0].ddc_type = ddc_none_detected;
450b8fb3d17SAxel Dörfler 				ptr_entity->port_info[0].connector_type = connector_proprietary;
451b8fb3d17SAxel Dörfler 
452b8fb3d17SAxel Dörfler 				SHOW_INFO0( 4 , "lvds port is not in connector table, added in.");
453b8fb3d17SAxel Dörfler 				if (connector_found == 0)
454b8fb3d17SAxel Dörfler 					connector_found = 1;
455b8fb3d17SAxel Dörfler 				else
456b8fb3d17SAxel Dörfler 					connector_found = 3;
457b8fb3d17SAxel Dörfler 			}
458b8fb3d17SAxel Dörfler 
459b8fb3d17SAxel Dörfler 			if ((tmp = RADEON_BIOS16( bios_header + 0x42 ))) {
460b8fb3d17SAxel Dörfler 				if ((tmp0 = RADEON_BIOS16( tmp + 0x15 ))) {
461b8fb3d17SAxel Dörfler 					if ((tmp1 = RADEON_BIOS16( tmp0 + 2 ) & 0x07)) {
462b8fb3d17SAxel Dörfler 						ptr_entity->port_info[0].ddc_type	= tmp1;
463b8fb3d17SAxel Dörfler 						if (ptr_entity->port_info[0].ddc_type > ddc_crt2) {
464b8fb3d17SAxel Dörfler 							SHOW_INFO( 4, "unknown ddctype %d found",
465b8fb3d17SAxel Dörfler 								ptr_entity->port_info[0].ddc_type);
466b8fb3d17SAxel Dörfler 							ptr_entity->port_info[0].ddc_type = ddc_none_detected;
467b8fb3d17SAxel Dörfler 						}
468b8fb3d17SAxel Dörfler 						SHOW_INFO0( 4, "lcd ddc info table found!");
469b8fb3d17SAxel Dörfler 					}
470b8fb3d17SAxel Dörfler 				}
471b8fb3d17SAxel Dörfler 			}
472b8fb3d17SAxel Dörfler 		} else if (connector_found == 2) {
473b8fb3d17SAxel Dörfler 			memcpy (&ptr_entity->port_info[0],
474b8fb3d17SAxel Dörfler 				&ptr_entity->port_info[1],
475b8fb3d17SAxel Dörfler 					sizeof (ptr_entity->port_info[0]));
476b8fb3d17SAxel Dörfler 			ptr_entity->port_info[1].dac_type = dac_unknown;
477b8fb3d17SAxel Dörfler 			ptr_entity->port_info[1].tmds_type = tmds_unknown;
478b8fb3d17SAxel Dörfler 			ptr_entity->port_info[1].ddc_type = ddc_none_detected;
479b8fb3d17SAxel Dörfler 			ptr_entity->port_info[1].connector_type = connector_none;
480b8fb3d17SAxel Dörfler 			connector_found = 1;
481b8fb3d17SAxel Dörfler 		}
482b8fb3d17SAxel Dörfler 
483b8fb3d17SAxel Dörfler 		if (connector_found == 0) {
484b8fb3d17SAxel Dörfler 			SHOW_INFO0( 4, "no connector found in connector info table.");
485b8fb3d17SAxel Dörfler 		} else {
486b8fb3d17SAxel Dörfler 			SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
487b8fb3d17SAxel Dörfler 				0, ptr_entity->port_info[0].ddc_type, ptr_entity->port_info[0].dac_type,
488b8fb3d17SAxel Dörfler 				ptr_entity->port_info[0].tmds_type, ptr_entity->port_info[0].connector_type);
489b8fb3d17SAxel Dörfler 
490b8fb3d17SAxel Dörfler 		}
491b8fb3d17SAxel Dörfler 		if (connector_found == 3) {
492b8fb3d17SAxel Dörfler 			SHOW_INFO( 2, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d",
493b8fb3d17SAxel Dörfler 				1, ptr_entity->port_info[1].ddc_type, ptr_entity->port_info[1].dac_type,
494b8fb3d17SAxel Dörfler 				ptr_entity->port_info[1].tmds_type, ptr_entity->port_info[1].connector_type);
495b8fb3d17SAxel Dörfler 		}
496b8fb3d17SAxel Dörfler 
497b8fb3d17SAxel Dörfler 	}
498b8fb3d17SAxel Dörfler 	return TRUE;
499b8fb3d17SAxel Dörfler }
500b8fb3d17SAxel Dörfler 
501b8fb3d17SAxel Dörfler 
5021da2dde8Sshadow303 // get flat panel info (does only make sense for Laptops
5031da2dde8Sshadow303 // with integrated display, but looking for it doesn't hurt,
5041da2dde8Sshadow303 // who knows which strange kind of combination is out there?)
Radeon_GetBIOSDFPInfo(device_info * di)5051da2dde8Sshadow303 static bool Radeon_GetBIOSDFPInfo( device_info *di )
5061da2dde8Sshadow303 {
507300bef58SAxel Dörfler 	uint16 bios_header;
5081da2dde8Sshadow303 	uint16 fpi_offset;
5091da2dde8Sshadow303 	FPI_BLOCK fpi;
5101da2dde8Sshadow303 	char panel_name[30];
5111da2dde8Sshadow303 	int i;
5121da2dde8Sshadow303 
513300bef58SAxel Dörfler 	uint16 tmp;
5141da2dde8Sshadow303 
515300bef58SAxel Dörfler 	bios_header = RADEON_BIOS16( 0x48 );
516300bef58SAxel Dörfler 
517300bef58SAxel Dörfler 	if (di->is_atombios)
518300bef58SAxel Dörfler 	{
519300bef58SAxel Dörfler 		int master_data_start;
520300bef58SAxel Dörfler 		master_data_start = RADEON_BIOS16( bios_header + 32 );
521300bef58SAxel Dörfler 
522300bef58SAxel Dörfler 		tmp = RADEON_BIOS16( master_data_start + 16 );
523300bef58SAxel Dörfler 		if( tmp )
524300bef58SAxel Dörfler 		{
525300bef58SAxel Dörfler 
526300bef58SAxel Dörfler 		    di->fp_info.panel_xres		= RADEON_BIOS16( tmp +  6 );
527300bef58SAxel Dörfler 		    di->fp_info.panel_yres		= RADEON_BIOS16( tmp + 10 );
528300bef58SAxel Dörfler 		    di->fp_info.dot_clock		= RADEON_BIOS16( tmp +  4 ) * 10;
529300bef58SAxel Dörfler 		    di->fp_info.h_blank			= RADEON_BIOS16( tmp +  8 );
530300bef58SAxel Dörfler 		    di->fp_info.h_over_plus		= RADEON_BIOS16( tmp + 14 );
531300bef58SAxel Dörfler 		    di->fp_info.h_sync_width	= RADEON_BIOS16( tmp + 16 );
532300bef58SAxel Dörfler 		    di->fp_info.v_blank      	= RADEON_BIOS16( tmp + 12 );
533300bef58SAxel Dörfler 			di->fp_info.v_over_plus		= RADEON_BIOS16( tmp + 18 );
534300bef58SAxel Dörfler 		    di->fp_info.h_sync_width	= RADEON_BIOS16( tmp + 20 );
535300bef58SAxel Dörfler 		    di->fp_info.panel_pwr_delay	= RADEON_BIOS16( tmp + 40 );
536300bef58SAxel Dörfler 
537300bef58SAxel Dörfler 		    SHOW_INFO( 2, "Panel Info from ATOMBIOS:\n"
538300bef58SAxel Dörfler 					"XRes: %d, YRes: %d, DotClock: %d\n"
539300bef58SAxel Dörfler 					"HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
540300bef58SAxel Dörfler 					"VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n"
541300bef58SAxel Dörfler 					"PanelPowerDelay: %d\n",
542300bef58SAxel Dörfler 					di->fp_info.panel_xres,	di->fp_info.panel_yres,	di->fp_info.dot_clock,
543300bef58SAxel Dörfler 					di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width,
544300bef58SAxel Dörfler 					di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.h_sync_width,
545300bef58SAxel Dörfler 					di->fp_info.panel_pwr_delay	);
546300bef58SAxel Dörfler 
547300bef58SAxel Dörfler 		}
548300bef58SAxel Dörfler 		else
549300bef58SAxel Dörfler 		{
550300bef58SAxel Dörfler 		    di->fp_info.panel_pwr_delay = 200;
551300bef58SAxel Dörfler 			SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
552300bef58SAxel Dörfler 			return false;
553300bef58SAxel Dörfler 		}
554300bef58SAxel Dörfler 	} // is_atombios
555300bef58SAxel Dörfler 	else
556300bef58SAxel Dörfler 	{
557300bef58SAxel Dörfler 
558300bef58SAxel Dörfler 		fpi_offset = RADEON_BIOS16(bios_header + 0x40);
5591da2dde8Sshadow303 
5601da2dde8Sshadow303 		if( !fpi_offset ) {
5611da2dde8Sshadow303 			di->fp_info.panel_pwr_delay = 200;
5621da2dde8Sshadow303 			SHOW_ERROR0( 2, "No Panel Info Table found in BIOS" );
5631da2dde8Sshadow303 			return false;
5641da2dde8Sshadow303 		}
5651da2dde8Sshadow303 
5661da2dde8Sshadow303 		memcpy( &fpi, di->rom.rom_ptr + fpi_offset, sizeof( fpi ));
5671da2dde8Sshadow303 
5681da2dde8Sshadow303 		memcpy( panel_name, &fpi.name, sizeof( fpi.name ) );
5691da2dde8Sshadow303 		panel_name[sizeof( fpi.name )] = 0;
5701da2dde8Sshadow303 
5711da2dde8Sshadow303 		SHOW_INFO( 2, "Panel ID string: %s", panel_name );
5721da2dde8Sshadow303 
5731da2dde8Sshadow303 		di->fp_info.panel_xres = fpi.panel_xres;
5741da2dde8Sshadow303 		di->fp_info.panel_yres = fpi.panel_yres;
5751da2dde8Sshadow303 
5761da2dde8Sshadow303 		SHOW_INFO( 2, "Panel Size from BIOS: %dx%d",
5771da2dde8Sshadow303 			di->fp_info.panel_xres, di->fp_info.panel_yres);
5781da2dde8Sshadow303 
5791da2dde8Sshadow303 		di->fp_info.panel_pwr_delay = fpi.panel_pwr_delay;
5801da2dde8Sshadow303 		if( di->fp_info.panel_pwr_delay > 2000 || di->fp_info.panel_pwr_delay < 0 )
5811da2dde8Sshadow303 			di->fp_info.panel_pwr_delay = 2000;
5821da2dde8Sshadow303 
583707e075aSBruno G. Albuquerque 		di->fp_info.ref_div = fpi.ref_div;
584707e075aSBruno G. Albuquerque 		di->fp_info.post_div = fpi.post_div;
585707e075aSBruno G. Albuquerque 		di->fp_info.feedback_div = fpi.feedback_div;
586707e075aSBruno G. Albuquerque 
587707e075aSBruno G. Albuquerque 		di->fp_info.fixed_dividers =
588707e075aSBruno G. Albuquerque 			di->fp_info.ref_div != 0 && di->fp_info.feedback_div > 3;
589707e075aSBruno G. Albuquerque 
590707e075aSBruno G. Albuquerque 
5911da2dde8Sshadow303 		// there might be multiple supported resolutions stored;
5921da2dde8Sshadow303 		// we are looking for native resolution
5931da2dde8Sshadow303 		for( i = 0; i < 20; ++i ) {
5941da2dde8Sshadow303 			uint16 fpi_timing_ofs;
5951da2dde8Sshadow303 			FPI_TIMING_BLOCK fpi_timing;
5961da2dde8Sshadow303 
5971da2dde8Sshadow303 			fpi_timing_ofs = fpi.fpi_timing_ofs[i];
5981da2dde8Sshadow303 
5991da2dde8Sshadow303 			if( fpi_timing_ofs == 0 )
6001da2dde8Sshadow303 				break;
6011da2dde8Sshadow303 
6021da2dde8Sshadow303 			memcpy( &fpi_timing, di->rom.rom_ptr + fpi_timing_ofs, sizeof( fpi_timing ));
6031da2dde8Sshadow303 
6041da2dde8Sshadow303 			if( fpi_timing.panel_xres != di->fp_info.panel_xres ||
6051da2dde8Sshadow303 				fpi_timing.panel_yres != di->fp_info.panel_yres )
6061da2dde8Sshadow303 				continue;
6071da2dde8Sshadow303 
6081da2dde8Sshadow303 			di->fp_info.h_blank			= (fpi_timing.h_total - fpi_timing.h_display) * 8;
6091da2dde8Sshadow303 			// TBD: seems like upper four bits of hsync_start contain garbage
6101da2dde8Sshadow303 			di->fp_info.h_over_plus 	= ((fpi_timing.h_sync_start & 0xfff) - fpi_timing.h_display - 1) * 8;
6111da2dde8Sshadow303 			di->fp_info.h_sync_width 	= fpi_timing.h_sync_width * 8;
6121da2dde8Sshadow303 			di->fp_info.v_blank			= fpi_timing.v_total - fpi_timing.v_display;
6131da2dde8Sshadow303 			di->fp_info.v_over_plus 	= (fpi_timing.v_sync & 0x7ff) - fpi_timing.v_display;
6141da2dde8Sshadow303 			di->fp_info.v_sync_width 	= (fpi_timing.v_sync & 0xf800) >> 11;
6151da2dde8Sshadow303 			di->fp_info.dot_clock 		= fpi_timing.dot_clock * 10;
6161da2dde8Sshadow303 			return true;
6171da2dde8Sshadow303 		}
618300bef58SAxel Dörfler 	} // not is_atombios
6191da2dde8Sshadow303 
6201da2dde8Sshadow303 	SHOW_ERROR0( 2, "Radeon: couldn't get Panel Timing from BIOS" );
6211da2dde8Sshadow303 	return false;
6221da2dde8Sshadow303 }
6231da2dde8Sshadow303 
6241da2dde8Sshadow303 
6251da2dde8Sshadow303 // try to reverse engineer DFP specification from
6261da2dde8Sshadow303 // timing currently set up in graphics cards registers
6271da2dde8Sshadow303 // (effectively, we hope that BIOS has set it up correctly
6281da2dde8Sshadow303 //  and noone has messed registers up yet; let's pray)
Radeon_RevEnvDFPSize(device_info * di)6291da2dde8Sshadow303 static void Radeon_RevEnvDFPSize( device_info *di )
6301da2dde8Sshadow303 {
6311da2dde8Sshadow303 	vuint8 *regs = di->regs;
6321da2dde8Sshadow303 
6331da2dde8Sshadow303 	di->fp_info.panel_yres =
6341da2dde8Sshadow303 		((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE)
6355f6e3f51Sshadow303 		>> RADEON_VERT_PANEL_SIZE_SHIFT) + 1;
6361da2dde8Sshadow303 
6371da2dde8Sshadow303 	di->fp_info.panel_xres =
6381da2dde8Sshadow303 		(((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE)
6395f6e3f51Sshadow303 		>> RADEON_HORZ_PANEL_SIZE_SHIFT) + 1) * 8;
6401da2dde8Sshadow303 
6411da2dde8Sshadow303 	SHOW_INFO( 2, "detected panel size from registers: %dx%d",
6421da2dde8Sshadow303 		di->fp_info.panel_xres, di->fp_info.panel_yres);
6431da2dde8Sshadow303 }
6441da2dde8Sshadow303 
6451da2dde8Sshadow303 
6461da2dde8Sshadow303 // once more for getting precise timing
Radeon_RevEnvDFPTiming(device_info * di)6471da2dde8Sshadow303 static void Radeon_RevEnvDFPTiming( device_info *di )
6481da2dde8Sshadow303 {
6491da2dde8Sshadow303 	vuint8 *regs = di->regs;
6501da2dde8Sshadow303 	uint32 r;
6511da2dde8Sshadow303 	uint16 a, b;
6521da2dde8Sshadow303 
6531da2dde8Sshadow303 
6541da2dde8Sshadow303 	r = INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP );
6551da2dde8Sshadow303 	// the magic "4" was found by trial and error and probably stems from fudge (see crtc.c)
6561da2dde8Sshadow303 	a = (r & RADEON_FP_CRTC_H_TOTAL_MASK)/* + 4*/;
6571da2dde8Sshadow303 	b = (r & RADEON_FP_CRTC_H_DISP_MASK) >> RADEON_FP_CRTC_H_DISP_SHIFT;
6581da2dde8Sshadow303 	di->fp_info.h_blank = (a - b) * 8;
6591da2dde8Sshadow303 
6601da2dde8Sshadow303 	SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
6611da2dde8Sshadow303 
6621da2dde8Sshadow303 	r = INREG( regs, RADEON_FP_H_SYNC_STRT_WID );
6631da2dde8Sshadow303 	di->fp_info.h_over_plus =
6641da2dde8Sshadow303 		((r & RADEON_FP_H_SYNC_STRT_CHAR_MASK)
6651da2dde8Sshadow303 			  	>> RADEON_FP_H_SYNC_STRT_CHAR_SHIFT) - b/* - 1*/;
6661da2dde8Sshadow303 	di->fp_info.h_over_plus *= 8;
6671da2dde8Sshadow303 	di->fp_info.h_sync_width =
6681da2dde8Sshadow303 		((r & RADEON_FP_H_SYNC_WID_MASK)
6691da2dde8Sshadow303 				>> RADEON_FP_H_SYNC_WID_SHIFT);
6701da2dde8Sshadow303 	// TBD: this seems to be wrong
6715f6e3f51Sshadow303 	// (my BIOS tells 112, this calculation leads to 24!)
6721da2dde8Sshadow303 	di->fp_info.h_sync_width *= 8;
6731da2dde8Sshadow303 
6741da2dde8Sshadow303 	r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP );
6751da2dde8Sshadow303 	a = (r & RADEON_FP_CRTC_V_TOTAL_MASK)/* + 1*/;
6761da2dde8Sshadow303 	b = (r & RADEON_FP_CRTC_V_DISP_MASK) >> RADEON_FP_CRTC_V_DISP_SHIFT;
6771da2dde8Sshadow303 	di->fp_info.v_blank = a - b;
6781da2dde8Sshadow303 
6791da2dde8Sshadow303 	SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
6801da2dde8Sshadow303 
6811da2dde8Sshadow303 	r = INREG( regs, RADEON_FP_V_SYNC_STRT_WID );
6821da2dde8Sshadow303 	di->fp_info.v_over_plus = (r & RADEON_FP_V_SYNC_STRT_MASK) - b;
6831da2dde8Sshadow303 	di->fp_info.v_sync_width = ((r & RADEON_FP_V_SYNC_WID_MASK)
6841da2dde8Sshadow303 		>> RADEON_FP_V_SYNC_WID_SHIFT)/* + 1*/;
6851da2dde8Sshadow303 
6861da2dde8Sshadow303 	// standard CRTC
6871da2dde8Sshadow303 	r = INREG( regs, RADEON_CRTC_H_TOTAL_DISP );
6881da2dde8Sshadow303 	a = (r & RADEON_CRTC_H_TOTAL);
6891da2dde8Sshadow303 	b = (r & RADEON_CRTC_H_DISP) >> RADEON_CRTC_H_DISP_SHIFT;
6901da2dde8Sshadow303 	di->fp_info.h_blank = (a - b) * 8;
6911da2dde8Sshadow303 
6921da2dde8Sshadow303 	SHOW_FLOW( 2, "h_total=%d, h_disp=%d", a * 8, b * 8 );
6931da2dde8Sshadow303 
6941da2dde8Sshadow303 	r = INREG( regs, RADEON_CRTC_H_SYNC_STRT_WID );
6951da2dde8Sshadow303 	di->fp_info.h_over_plus =
6961da2dde8Sshadow303 		((r & RADEON_CRTC_H_SYNC_STRT_CHAR)
6971da2dde8Sshadow303 			  	>> RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) - b;
6981da2dde8Sshadow303 	di->fp_info.h_over_plus *= 8;
6991da2dde8Sshadow303 	di->fp_info.h_sync_width =
7001da2dde8Sshadow303 		((r & RADEON_CRTC_H_SYNC_WID)
7011da2dde8Sshadow303 				>> RADEON_CRTC_H_SYNC_WID_SHIFT);
7021da2dde8Sshadow303 	di->fp_info.h_sync_width *= 8;
7031da2dde8Sshadow303 
7041da2dde8Sshadow303 	r = INREG( regs, RADEON_CRTC_V_TOTAL_DISP );
7051da2dde8Sshadow303 	a = (r & RADEON_CRTC_V_TOTAL);
7061da2dde8Sshadow303 	b = (r & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
7071da2dde8Sshadow303 	di->fp_info.v_blank = a - b;
7081da2dde8Sshadow303 
7091da2dde8Sshadow303 	SHOW_FLOW( 2, "v_total=%d, v_disp=%d", a, b );
7101da2dde8Sshadow303 
7111da2dde8Sshadow303 	r = INREG( regs, RADEON_CRTC_V_SYNC_STRT_WID );
7121da2dde8Sshadow303 	di->fp_info.v_over_plus = (r & RADEON_CRTC_V_SYNC_STRT) - b;
7131da2dde8Sshadow303 	di->fp_info.v_sync_width = ((r & RADEON_CRTC_V_SYNC_WID)
7141da2dde8Sshadow303 		>> RADEON_CRTC_V_SYNC_WID_SHIFT);
7151da2dde8Sshadow303 }
7161da2dde8Sshadow303 
717f9a5b215SAxel Dörfler //snaffled from X.org hope it works...
Radeon_GetTMDSInfoFromBios(device_info * di)718f9a5b215SAxel Dörfler static void Radeon_GetTMDSInfoFromBios( device_info *di )
719f9a5b215SAxel Dörfler {
720f9a5b215SAxel Dörfler     uint32 tmp, maxfreq;
721f9a5b215SAxel Dörfler     uint32 found = FALSE;
722f9a5b215SAxel Dörfler     int i, n;
723f9a5b215SAxel Dörfler     uint16 bios_header;
724f9a5b215SAxel Dörfler 
725f9a5b215SAxel Dörfler     bios_header = RADEON_BIOS16( 0x48 );
726f9a5b215SAxel Dörfler 
727f9a5b215SAxel Dörfler 	for (i = 0; i < 4; i++) {
728f9a5b215SAxel Dörfler         di->tmds_pll[i].value = 0;
729f9a5b215SAxel Dörfler         di->tmds_pll[i].freq = 0;
730f9a5b215SAxel Dörfler     }
731f9a5b215SAxel Dörfler 
732f9a5b215SAxel Dörfler 	if (di->is_atombios)
733f9a5b215SAxel Dörfler 	{
734f9a5b215SAxel Dörfler 		int master_data_start;
735f9a5b215SAxel Dörfler 		master_data_start = RADEON_BIOS16( bios_header + 32 );
736f9a5b215SAxel Dörfler 
737f9a5b215SAxel Dörfler 		if((tmp = RADEON_BIOS16 (master_data_start + 18))) {
738f9a5b215SAxel Dörfler 
739f9a5b215SAxel Dörfler 		    maxfreq = RADEON_BIOS16(tmp + 4);
740f9a5b215SAxel Dörfler 
741f9a5b215SAxel Dörfler 		    for (i = 0; i < 4; i++) {
742f9a5b215SAxel Dörfler 				di->tmds_pll[i].freq = RADEON_BIOS16(tmp + i * 6 + 6);
743f9a5b215SAxel Dörfler 				// This assumes each field in TMDS_PLL has 6 bit as in R300/R420
744f9a5b215SAxel Dörfler 				di->tmds_pll[i].value = ((RADEON_BIOS8(tmp + i * 6 + 8) & 0x3f) |
745f9a5b215SAxel Dörfler 				   ((RADEON_BIOS8(tmp + i * 6 + 10) & 0x3f) << 6) |
746f9a5b215SAxel Dörfler 				   ((RADEON_BIOS8(tmp + i * 6 +  9) & 0xf) << 12) |
747f9a5b215SAxel Dörfler 				   ((RADEON_BIOS8(tmp + i * 6 + 11) & 0xf) << 16));
748*cc7e844cSMurai Takashi 				SHOW_ERROR( 2, "TMDS PLL from BIOS: %" B_PRIu32 " %" B_PRIx32,
749f9a5b215SAxel Dörfler 				   di->tmds_pll[i].freq, di->tmds_pll[i].value);
750f9a5b215SAxel Dörfler 
751f9a5b215SAxel Dörfler 				if (maxfreq == di->tmds_pll[i].freq) {
752f9a5b215SAxel Dörfler 				    di->tmds_pll[i].freq = 0xffffffff;
753f9a5b215SAxel Dörfler 				    break;
754f9a5b215SAxel Dörfler 				}
755f9a5b215SAxel Dörfler 		    }
756f9a5b215SAxel Dörfler 		    found = TRUE;
757f9a5b215SAxel Dörfler 		}
758f9a5b215SAxel Dörfler     } else {
759f9a5b215SAxel Dörfler 
760f9a5b215SAxel Dörfler 		tmp = RADEON_BIOS16(bios_header + 0x34);
761f9a5b215SAxel Dörfler 		if (tmp) {
762f9a5b215SAxel Dörfler 		    SHOW_ERROR( 2, "DFP table revision: %d", RADEON_BIOS8(tmp));
763f9a5b215SAxel Dörfler 		    if (RADEON_BIOS8(tmp) == 3) {
764f9a5b215SAxel Dörfler 				n = RADEON_BIOS8(tmp + 5) + 1;
765f9a5b215SAxel Dörfler 				if (n > 4)
766f9a5b215SAxel Dörfler 					n = 4;
767f9a5b215SAxel Dörfler 				for (i = 0; i < n; i++) {
768f9a5b215SAxel Dörfler 					di->tmds_pll[i].value = RADEON_BIOS32(tmp + i * 10 + 0x08);
769f9a5b215SAxel Dörfler 					di->tmds_pll[i].freq = RADEON_BIOS16(tmp + i * 10 + 0x10);
770f9a5b215SAxel Dörfler 				}
771f9a5b215SAxel Dörfler 				found = TRUE;
772f9a5b215SAxel Dörfler 		    } else if (RADEON_BIOS8(tmp) == 4) {
773f9a5b215SAxel Dörfler 		        int stride = 0;
774f9a5b215SAxel Dörfler 				n = RADEON_BIOS8(tmp + 5) + 1;
775f9a5b215SAxel Dörfler 				if (n > 4)
776f9a5b215SAxel Dörfler 					n = 4;
777f9a5b215SAxel Dörfler 				for (i = 0; i < n; i++) {
778f9a5b215SAxel Dörfler 				    di->tmds_pll[i].value = RADEON_BIOS32(tmp + stride + 0x08);
779f9a5b215SAxel Dörfler 				    di->tmds_pll[i].freq = RADEON_BIOS16(tmp + stride + 0x10);
780f9a5b215SAxel Dörfler 				    if (i == 0)
781f9a5b215SAxel Dörfler 				    	stride += 10;
782f9a5b215SAxel Dörfler 				    else
783f9a5b215SAxel Dörfler 				    	stride += 6;
784f9a5b215SAxel Dörfler 				}
785f9a5b215SAxel Dörfler 				found = TRUE;
786f9a5b215SAxel Dörfler 		    }
787f9a5b215SAxel Dörfler 
788f9a5b215SAxel Dörfler 		    // revision 4 has some problem as it appears in RV280,
789f9a5b215SAxel Dörfler 		    // comment it off for now, use default instead
790f9a5b215SAxel Dörfler 			/*
791f9a5b215SAxel Dörfler 				else if (RADEON_BIOS8(tmp) == 4) {
792f9a5b215SAxel Dörfler 				int stride = 0;
793f9a5b215SAxel Dörfler 				n = RADEON_BIOS8(tmp + 5) + 1;
794f9a5b215SAxel Dörfler 				if (n > 4) n = 4;
795f9a5b215SAxel Dörfler 				for (i = 0; i < n; i++) {
796f9a5b215SAxel Dörfler 					di->tmds_pll[i].value = RADEON_BIOS32(tmp + stride + 0x08);
797f9a5b215SAxel Dörfler 					di->tmds_pll[i].freq = RADEON_BIOS16(tmp + stride + 0x10);
798f9a5b215SAxel Dörfler 					if (i == 0)
799f9a5b215SAxel Dörfler 						stride += 10;
800f9a5b215SAxel Dörfler 					else
801f9a5b215SAxel Dörfler 						stride += 6;
802f9a5b215SAxel Dörfler 				}
803f9a5b215SAxel Dörfler 				found = TRUE;
804f9a5b215SAxel Dörfler 			}
805f9a5b215SAxel Dörfler 			*/
806f9a5b215SAxel Dörfler 
807f9a5b215SAxel Dörfler 		}
808f9a5b215SAxel Dörfler     }
809f9a5b215SAxel Dörfler 
810f9a5b215SAxel Dörfler     if (found == FALSE) {
811f9a5b215SAxel Dörfler     	for (i = 0; i < 4; i++) {
812f9a5b215SAxel Dörfler 	        di->tmds_pll[i].value = default_tmds_pll[di->asic][i].value;
813f9a5b215SAxel Dörfler 	        di->tmds_pll[i].freq = default_tmds_pll[di->asic][i].freq;
814*cc7e844cSMurai Takashi 	        SHOW_ERROR( 2, "TMDS PLL from DEFAULTS: %" B_PRIu32 " %" B_PRIx32,
815f9a5b215SAxel Dörfler 				di->tmds_pll[i].freq, di->tmds_pll[i].value);
816f9a5b215SAxel Dörfler     	}
817f9a5b215SAxel Dörfler     }
818f9a5b215SAxel Dörfler }
8191da2dde8Sshadow303 
8205f6e3f51Sshadow303 /*
8211da2dde8Sshadow303 // get everything in terms of monitors connected to the card
8221da2dde8Sshadow303 static void Radeon_GetBIOSMon( device_info *di )
8231da2dde8Sshadow303 {
8241da2dde8Sshadow303 	Radeon_GetMonType( di );
8251da2dde8Sshadow303 
8261da2dde8Sshadow303     // reset all Flat Panel Info;
8271da2dde8Sshadow303     // it gets filled out step by step, and this way we know what's still missing
8281da2dde8Sshadow303     memset( &di->fp_info, 0, sizeof( di->fp_info ));
8291da2dde8Sshadow303 
8301da2dde8Sshadow303     // we assume that the only fp port is combined with standard port 0
8311da2dde8Sshadow303 	di->fp_info.disp_type = di->disp_type[0];
8321da2dde8Sshadow303 
8335f6e3f51Sshadow303 	if( di->is_mobility ) {
8341da2dde8Sshadow303 		// there is a flat panel - get info about it
8351da2dde8Sshadow303 		Radeon_GetBIOSDFPInfo( di );
8361da2dde8Sshadow303 
8371da2dde8Sshadow303 		// if BIOS doesn't know, ask the registers
8381da2dde8Sshadow303 		if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0)
8391da2dde8Sshadow303 			Radeon_RevEnvDFPSize( di );
8401da2dde8Sshadow303 
8411da2dde8Sshadow303 		if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0)
8421da2dde8Sshadow303 			Radeon_RevEnvDFPTiming( di );
8431da2dde8Sshadow303 
8441da2dde8Sshadow303 		SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
8451da2dde8Sshadow303 			di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width );
8461da2dde8Sshadow303 		SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
8471da2dde8Sshadow303 			di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width );
8481da2dde8Sshadow303 		SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
8491da2dde8Sshadow303 	}
8501da2dde8Sshadow303 }
8515f6e3f51Sshadow303 */
8521da2dde8Sshadow303 
8535f6e3f51Sshadow303 // get info about Laptop flat panel
Radeon_GetFPData(device_info * di)8545f6e3f51Sshadow303 static void Radeon_GetFPData( device_info *di )
8555f6e3f51Sshadow303 {
8565f6e3f51Sshadow303     // reset all Flat Panel Info;
8575f6e3f51Sshadow303     // it gets filled out step by step, and this way we know what's still missing
8585f6e3f51Sshadow303     memset( &di->fp_info, 0, sizeof( di->fp_info ));
8595f6e3f51Sshadow303 
8605f6e3f51Sshadow303 	// we only use BIOS for Laptop flat panels
8615f6e3f51Sshadow303 	if( !di->is_mobility )
8625f6e3f51Sshadow303 		return;
8635f6e3f51Sshadow303 
8645f6e3f51Sshadow303 	// ask BIOS about flat panel spec
8655f6e3f51Sshadow303 	Radeon_GetBIOSDFPInfo( di );
8665f6e3f51Sshadow303 
8675f6e3f51Sshadow303 	// if BIOS doesn't know, ask the registers
8685f6e3f51Sshadow303 	if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0)
8695f6e3f51Sshadow303 		Radeon_RevEnvDFPSize( di );
8705f6e3f51Sshadow303 
8715f6e3f51Sshadow303 	if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0)
8725f6e3f51Sshadow303 		Radeon_RevEnvDFPTiming( di );
8735f6e3f51Sshadow303 
8745f6e3f51Sshadow303 	SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
8755f6e3f51Sshadow303 		di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width );
8765f6e3f51Sshadow303 	SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
8775f6e3f51Sshadow303 		di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width );
8785f6e3f51Sshadow303 	SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
8795f6e3f51Sshadow303 }
8801da2dde8Sshadow303 
881a85694c3SAxel Dörfler 
882a85694c3SAxel Dörfler // Depending on card genertation, chipset bugs, etc... the amount of vram
883a85694c3SAxel Dörfler // accessible to the CPU can vary. This function is our best shot at figuring
884a85694c3SAxel Dörfler // it out. Returns a value in KB.
RADEON_GetAccessibleVRAM(device_info * di)885a85694c3SAxel Dörfler static uint32 RADEON_GetAccessibleVRAM( device_info *di )
886a85694c3SAxel Dörfler {
887a85694c3SAxel Dörfler 	vuint8 *regs = di->regs;
888a85694c3SAxel Dörfler 	pci_info *pcii = &(di->pcii);
889a85694c3SAxel Dörfler 
890a85694c3SAxel Dörfler     uint32 aper_size = INREG( regs, RADEON_CONFIG_APER_SIZE );
891a85694c3SAxel Dörfler 
892a85694c3SAxel Dörfler     // Set HDP_APER_CNTL only on cards that are known not to be broken,
893a85694c3SAxel Dörfler     // that is has the 2nd generation multifunction PCI interface
894a85694c3SAxel Dörfler     if (di->asic == rt_rv280 ||
895a85694c3SAxel Dörfler 		di->asic == rt_rv350 ||
896a85694c3SAxel Dörfler 		di->asic == rt_rv380 ||
897a85694c3SAxel Dörfler 		di->asic == rt_r420  ) {
898a85694c3SAxel Dörfler 			OUTREGP( regs, RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL,
899a85694c3SAxel Dörfler 		     ~RADEON_HDP_APER_CNTL);
900a85694c3SAxel Dörfler 	    SHOW_INFO0( 0, "Generation 2 PCI interface, using max accessible memory");
901a85694c3SAxel Dörfler 	    return aper_size * 2;
902a85694c3SAxel Dörfler     }
903a85694c3SAxel Dörfler 
904a85694c3SAxel Dörfler     // Older cards have all sorts of funny issues to deal with. First
905a85694c3SAxel Dörfler     // check if it's a multifunction card by reading the PCI config
906a85694c3SAxel Dörfler     // header type... Limit those to one aperture size
907a85694c3SAxel Dörfler     if (get_pci(PCI_header_type, 1) & 0x80) {
908a85694c3SAxel Dörfler 		SHOW_INFO0( 0, "Generation 1 PCI interface in multifunction mode"
909a85694c3SAxel Dörfler 				", accessible memory limited to one aperture\n");
910a85694c3SAxel Dörfler 		return aper_size;
911a85694c3SAxel Dörfler     }
912a85694c3SAxel Dörfler 
913a85694c3SAxel Dörfler     // Single function older card. We read HDP_APER_CNTL to see how the BIOS
914a85694c3SAxel Dörfler     // have set it up. We don't write this as it's broken on some ASICs but
915a85694c3SAxel Dörfler     // we expect the BIOS to have done the right thing (might be too optimistic...)
916a85694c3SAxel Dörfler     if (INREG( regs, RADEON_HOST_PATH_CNTL ) & RADEON_HDP_APER_CNTL )
917a85694c3SAxel Dörfler         return aper_size * 2;
918a85694c3SAxel Dörfler 
919a85694c3SAxel Dörfler     return aper_size;
920a85694c3SAxel Dörfler }
921a85694c3SAxel Dörfler 
922a85694c3SAxel Dörfler 
9231da2dde8Sshadow303 // detect amount of graphics memory
Radeon_DetectRAM(device_info * di)924e02e12deSAxel Dörfler static void Radeon_DetectRAM( device_info *di )
9251da2dde8Sshadow303 {
9261da2dde8Sshadow303 	vuint8 *regs = di->regs;
927a85694c3SAxel Dörfler 	uint32 accessible, bar_size, tmp = 0;
9281da2dde8Sshadow303 
929a85694c3SAxel Dörfler 	if( di->is_igp	) {
9305f6e3f51Sshadow303 		uint32 tom;
9315f6e3f51Sshadow303 
9328841d8bcSAxel Dörfler 		tom = INREG( regs, RADEON_NB_TOM );
9335f6e3f51Sshadow303 		di->local_mem_size = ((tom >> 16) + 1 - (tom & 0xffff)) << 16;
934a85694c3SAxel Dörfler 		OUTREG( regs, RADEON_CONFIG_MEMSIZE, di->local_mem_size * 1024);
935a85694c3SAxel Dörfler 	} else {
936a85694c3SAxel Dörfler 		di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
9375f6e3f51Sshadow303 	}
9381da2dde8Sshadow303 
9391da2dde8Sshadow303 	// some production boards of m6 will return 0 if it's 8 MB
940a85694c3SAxel Dörfler 	if( di->local_mem_size == 0 ) {
9411da2dde8Sshadow303 		di->local_mem_size = 8 * 1024 *1024;
942a85694c3SAxel Dörfler 		OUTREG( regs, RADEON_CONFIG_MEMSIZE, di->local_mem_size);
943a85694c3SAxel Dörfler 	}
9441da2dde8Sshadow303 
945a85694c3SAxel Dörfler 
946a85694c3SAxel Dörfler 	// Get usable Vram, after asic bugs, configuration screw ups etc
947a85694c3SAxel Dörfler 	accessible = RADEON_GetAccessibleVRAM( di );
948a85694c3SAxel Dörfler 
949a85694c3SAxel Dörfler 	// Crop it to the size of the PCI BAR
950a85694c3SAxel Dörfler 	bar_size = di->pcii.u.h0.base_register_sizes[0];
951a85694c3SAxel Dörfler 	if (bar_size == 0)
952a85694c3SAxel Dörfler 	    bar_size = 0x200000;
953a85694c3SAxel Dörfler 	if (accessible > bar_size)
954a85694c3SAxel Dörfler 	    accessible = bar_size;
955a85694c3SAxel Dörfler 
956*cc7e844cSMurai Takashi 	SHOW_INFO( 0,
957*cc7e844cSMurai Takashi 		"Detected total video RAM=%" B_PRIu32 "K, "
958*cc7e844cSMurai Takashi 		"accessible=%" B_PRIu32 "K "
959*cc7e844cSMurai Takashi 		"(PCI BAR=%" B_PRIu32 "K)",
960*cc7e844cSMurai Takashi 		di->local_mem_size / 1024,
961*cc7e844cSMurai Takashi 		accessible / 1024,
962*cc7e844cSMurai Takashi 		bar_size / 1024);
963a85694c3SAxel Dörfler 	if (di->local_mem_size > accessible)
964a85694c3SAxel Dörfler 	    di->local_mem_size = accessible;
965a85694c3SAxel Dörfler 
966a85694c3SAxel Dörfler 	// detect ram bus width only used by dynamic clocks for now.
967a85694c3SAxel Dörfler 	tmp = INREG( regs, RADEON_MEM_CNTL );
968a85694c3SAxel Dörfler 	if (IS_DI_R300_VARIANT) {
969a85694c3SAxel Dörfler 		tmp &=  R300_MEM_NUM_CHANNELS_MASK;
970a85694c3SAxel Dörfler 		switch (tmp) {
971a85694c3SAxel Dörfler 			case 0: di->ram.width = 64; break;
972a85694c3SAxel Dörfler 			case 1: di->ram.width = 128; break;
973a85694c3SAxel Dörfler 			case 2: di->ram.width = 256; break;
974a85694c3SAxel Dörfler 			default: di->ram.width = 128; break;
975a85694c3SAxel Dörfler 		}
976a85694c3SAxel Dörfler 	} else if ( (di->asic >= rt_rv100) ||
977a85694c3SAxel Dörfler 				(di->asic >= rt_rs100) ||
978a85694c3SAxel Dörfler 				(di->asic >= rt_rs200)) {
979a85694c3SAxel Dörfler 		if (tmp & RV100_HALF_MODE)
980a85694c3SAxel Dörfler 			di->ram.width = 32;
981a85694c3SAxel Dörfler 		else
982a85694c3SAxel Dörfler 			di->ram.width = 64;
983a85694c3SAxel Dörfler 	} else {
984a85694c3SAxel Dörfler 		if (tmp & RADEON_MEM_NUM_CHANNELS_MASK)
985a85694c3SAxel Dörfler 			di->ram.width = 128;
986a85694c3SAxel Dörfler 		else
987a85694c3SAxel Dörfler 			di->ram.width = 64;
988a85694c3SAxel Dörfler 	}
989a85694c3SAxel Dörfler 
990a85694c3SAxel Dörfler 	if (di->is_igp || (di->asic >= rt_r300))
991a85694c3SAxel Dörfler 	{
992a85694c3SAxel Dörfler 		uint32 mem_type = INREG( regs, RADEON_MEM_SDRAM_MODE_REG ) & RADEON_MEM_CFG_TYPE_MASK;
993a85694c3SAxel Dörfler 		if ( mem_type == RADEON_MEM_CFG_SDR) {
9941da2dde8Sshadow303 				// SDR SGRAM (2:1)
9951da2dde8Sshadow303 				strcpy(di->ram_type, "SDR SGRAM");
9961da2dde8Sshadow303 				di->ram.ml = 4;
9971da2dde8Sshadow303 				di->ram.MB = 4;
9981da2dde8Sshadow303 				di->ram.Trcd = 1;
9991da2dde8Sshadow303 				di->ram.Trp = 2;
10001da2dde8Sshadow303 				di->ram.Twr = 1;
10011da2dde8Sshadow303 				di->ram.CL = 2;
10021da2dde8Sshadow303 				di->ram.loop_latency = 16;
10031da2dde8Sshadow303 				di->ram.Rloop = 16;
10041da2dde8Sshadow303 				di->ram.Tr2w = 0;
1005a85694c3SAxel Dörfler 		} else {  // RADEON_MEM_CFG_DDR
10061da2dde8Sshadow303 				// DDR SGRAM
10071da2dde8Sshadow303 				strcpy(di->ram_type, "DDR SGRAM");
10081da2dde8Sshadow303 				di->ram.ml = 4;
10091da2dde8Sshadow303 				di->ram.MB = 4;
10101da2dde8Sshadow303 				di->ram.Trcd = 3;
10111da2dde8Sshadow303 				di->ram.Trp = 3;
10121da2dde8Sshadow303 				di->ram.Twr = 2;
10131da2dde8Sshadow303 				di->ram.CL = 3;
10141da2dde8Sshadow303 				di->ram.Tr2w = 1;
10151da2dde8Sshadow303 				di->ram.loop_latency = 16;
10161da2dde8Sshadow303 				di->ram.Rloop = 16;
1017a85694c3SAxel Dörfler 		}
10181da2dde8Sshadow303 	}
10191da2dde8Sshadow303 
1020*cc7e844cSMurai Takashi 	SHOW_INFO( 1, "%" B_PRIu32 " MB %s found on %d wide bus",
1021a85694c3SAxel Dörfler 		di->local_mem_size / 1024 / 1024, di->ram_type, di->ram.width);
10221da2dde8Sshadow303 
10235f6e3f51Sshadow303 /*	if( di->local_mem_size > 64 * 1024 * 1024 ) {
10241da2dde8Sshadow303 		di->local_mem_size = 64 * 1024 * 1024;
10251da2dde8Sshadow303 
10261da2dde8Sshadow303 		SHOW_INFO0( 1, "restricted to 64 MB" );
10275f6e3f51Sshadow303 	}*/
10281da2dde8Sshadow303 }
10291da2dde8Sshadow303 
10301da2dde8Sshadow303 
10311da2dde8Sshadow303 // map and verify card's BIOS to see whether this really is a Radeon
10321da2dde8Sshadow303 // (as we need BIOS for further info we have to make sure we use the right one)
Radeon_MapBIOS(pci_info * pcii,rom_info * ri)10331da2dde8Sshadow303 status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
10341da2dde8Sshadow303 {
10355f6e3f51Sshadow303 	char buffer[100];
10361da2dde8Sshadow303 
10371da2dde8Sshadow303 	sprintf(buffer, "%04X_%04X_%02X%02X%02X bios",
10381da2dde8Sshadow303 		pcii->vendor_id, pcii->device_id,
10391da2dde8Sshadow303 		pcii->bus, pcii->device, pcii->function);
10401da2dde8Sshadow303 
10411da2dde8Sshadow303 	// we only scan BIOS at legacy location in first MB;
10421da2dde8Sshadow303 	// using the PCI location would improve detection, especially
10431da2dde8Sshadow303 	// if multiple graphics cards are installed
10441da2dde8Sshadow303 	// BUT: BeOS uses the first graphics card it finds (sorted by
10451da2dde8Sshadow303 	// device name), thus you couldn't choose in BIOS which card
10461da2dde8Sshadow303 	// to use; checking the legacy location ensures that the card is
10471da2dde8Sshadow303 	// only detected if it's the primary card
10485f6e3f51Sshadow303 	ri->phys_address = 0xc0000;
10495f6e3f51Sshadow303 	ri->size = 0x40000;
10505f6e3f51Sshadow303 
105164d79effSIngo Weinhold 	ri->bios_area = map_physical_memory( buffer, ri->phys_address,
10525f6e3f51Sshadow303 		ri->size, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr );
10531da2dde8Sshadow303 	if( ri->bios_area < 0 )
10541da2dde8Sshadow303 		return ri->bios_area;
10551da2dde8Sshadow303 
10561da2dde8Sshadow303 	ri->rom_ptr = Radeon_FindRom( ri );
10571da2dde8Sshadow303 
10585f6e3f51Sshadow303 	// on success, adjust physical address to found ROM
10595f6e3f51Sshadow303 	if( ri->rom_ptr != NULL )
10605f6e3f51Sshadow303 		ri->phys_address += ri->rom_ptr - ri->bios_ptr;
10615f6e3f51Sshadow303 
10621da2dde8Sshadow303 	return ri->rom_ptr != NULL ? B_OK : B_ERROR;
10631da2dde8Sshadow303 }
10641da2dde8Sshadow303 
10651da2dde8Sshadow303 
10661da2dde8Sshadow303 // unmap card's BIOS
Radeon_UnmapBIOS(rom_info * ri)10671da2dde8Sshadow303 void Radeon_UnmapBIOS( rom_info *ri )
10681da2dde8Sshadow303 {
10691da2dde8Sshadow303 	delete_area( ri->bios_area );
10701da2dde8Sshadow303 
10711da2dde8Sshadow303 	ri->bios_ptr = ri->rom_ptr = NULL;
10721da2dde8Sshadow303 }
10731da2dde8Sshadow303 
10741da2dde8Sshadow303 
10751da2dde8Sshadow303 // get everything valuable from BIOS (BIOS must be mapped)
Radeon_ReadBIOSData(device_info * di)10761da2dde8Sshadow303 status_t Radeon_ReadBIOSData( device_info *di )
10771da2dde8Sshadow303 {
10781da2dde8Sshadow303 	shared_info dummy_si;
10791da2dde8Sshadow303 	status_t result = B_OK;
10801da2dde8Sshadow303 
10811da2dde8Sshadow303 	// give Radeon_MapDevice something to play with
10821da2dde8Sshadow303 	di->si = &dummy_si;
10831da2dde8Sshadow303 
10841da2dde8Sshadow303 	// don't map frame buffer - we don't know its proper size yet!
10851da2dde8Sshadow303 	result = Radeon_MapDevice( di, true );
10861da2dde8Sshadow303 	if( result < 0 )
10871da2dde8Sshadow303 		goto err1;
10881da2dde8Sshadow303 
10891da2dde8Sshadow303 	Radeon_GetPLLInfo( di );
1090b8fb3d17SAxel Dörfler 
1091b8fb3d17SAxel Dörfler 	// setup defaults
1092b8fb3d17SAxel Dörfler 	di->routing.port_info[0].mon_type = mt_unknown;
1093b8fb3d17SAxel Dörfler 	di->routing.port_info[0].ddc_type = ddc_none_detected;
1094b8fb3d17SAxel Dörfler 	di->routing.port_info[0].dac_type = dac_unknown;
1095b8fb3d17SAxel Dörfler 	di->routing.port_info[0].tmds_type = tmds_unknown;
1096b8fb3d17SAxel Dörfler 	di->routing.port_info[0].connector_type = connector_none;
1097b8fb3d17SAxel Dörfler 
1098f9a5b215SAxel Dörfler 	di->routing.port_info[1].mon_type = mt_unknown;
1099f9a5b215SAxel Dörfler 	di->routing.port_info[1].ddc_type = ddc_none_detected;
1100f9a5b215SAxel Dörfler 	di->routing.port_info[1].dac_type = dac_unknown;
1101f9a5b215SAxel Dörfler 	di->routing.port_info[1].tmds_type = tmds_unknown;
1102f9a5b215SAxel Dörfler 	di->routing.port_info[1].connector_type = connector_none;
1103f9a5b215SAxel Dörfler 
1104b8fb3d17SAxel Dörfler 	if ( !Radeon_GetConnectorInfoFromBIOS( di ) )
1105b8fb3d17SAxel Dörfler 	{
1106b8fb3d17SAxel Dörfler 		di->routing.port_info[0].mon_type = mt_unknown;
1107b8fb3d17SAxel Dörfler 		di->routing.port_info[0].ddc_type = ddc_none_detected;
1108b8fb3d17SAxel Dörfler 		di->routing.port_info[0].dac_type = dac_tvdac;
1109b8fb3d17SAxel Dörfler 		di->routing.port_info[0].tmds_type = tmds_unknown;
1110b8fb3d17SAxel Dörfler 		di->routing.port_info[0].connector_type = connector_proprietary;
1111b8fb3d17SAxel Dörfler 
1112b8fb3d17SAxel Dörfler 		di->routing.port_info[1].mon_type = mt_unknown;
1113b8fb3d17SAxel Dörfler 		di->routing.port_info[1].ddc_type = ddc_none_detected;
1114b8fb3d17SAxel Dörfler 		di->routing.port_info[1].dac_type = dac_primary;
1115b8fb3d17SAxel Dörfler 		di->routing.port_info[1].tmds_type = tmds_ext;
1116b8fb3d17SAxel Dörfler 		di->routing.port_info[1].connector_type = connector_crt;
1117b8fb3d17SAxel Dörfler 
1118b8fb3d17SAxel Dörfler 	}
11195f6e3f51Sshadow303 	Radeon_GetFPData( di );
1120f9a5b215SAxel Dörfler 	Radeon_GetTMDSInfoFromBios( di );
11211da2dde8Sshadow303 	Radeon_DetectRAM( di );
11221da2dde8Sshadow303 
11231da2dde8Sshadow303 	Radeon_UnmapDevice( di );
11241da2dde8Sshadow303 
11251da2dde8Sshadow303 err1:
11261da2dde8Sshadow303 	di->si = NULL;
11271da2dde8Sshadow303 
11281da2dde8Sshadow303 	return result;
11291da2dde8Sshadow303 }
1130