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