diff -aur aty-2.6.15/ati_ids.h aty/ati_ids.h --- aty-2.6.15/ati_ids.h 2006-02-22 23:28:14.000000000 -0500 +++ aty/ati_ids.h 2006-02-23 15:32:21.000000000 -0500 @@ -185,6 +185,10 @@ #define PCI_CHIP_R423_UQ 0x5551 #define PCI_CHIP_R423_UR 0x5552 #define PCI_CHIP_R423_UT 0x5554 +#define PCI_CHIP_RV410_564B 0x564A +#define PCI_CHIP_RV410_564A 0x564B +#define PCI_CHIP_RV410_5652 0x5652 +#define PCI_CHIP_RV410_VS 0x5653 #define PCI_CHIP_MACH64VT 0x5654 #define PCI_CHIP_MACH64VU 0x5655 #define PCI_CHIP_MACH64VV 0x5656 Only in aty-2.6.15: radeon-atom-bios2.diff Only in aty-2.6.15: radeon_atom_bios.diff diff -aur aty-2.6.15/radeon_base.c aty/radeon_base.c --- aty-2.6.15/radeon_base.c 2006-02-22 23:28:14.000000000 -0500 +++ aty/radeon_base.c 2006-02-23 15:41:35.000000000 -0500 @@ -214,6 +214,10 @@ CHIP_DEF(PCI_CHIP_R420_JL, R420, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_R420_JM, R420, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_R420_JN, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV410_564A, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV410_564B, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV410_5652, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), + CHIP_DEF(PCI_CHIP_RV410_VS, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2), @@ -342,7 +346,7 @@ * to phase out Open Firmware images. * * Currently, we only look at the first PCI data, we could iteratre and deal with - * them all, and we should use fb_bios_start relative to start of image and not + * them all, and we should use fp_bios_start relative to start of image and not * relative start of ROM, but so far, I never found a dual-image ATI card * * typedef struct { @@ -428,7 +432,7 @@ * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device * tree. Hopefully, ATI OF driver is kind enough to fill these */ -static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) +static int __devinit radeon_get_pll_info_openfirmware (struct radeonfb_info *rinfo) { struct device_node *dp = rinfo->of_node; u32 *val; @@ -451,6 +455,7 @@ if (val && *val) rinfo->pll.mclk = (*val) / 10; + printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n"); return 0; } #endif /* CONFIG_PPC_OF */ @@ -593,10 +598,90 @@ return 0; } +static int __devinit radeon_get_pll_info_legacy(struct radeonfb_info *rinfo) +{ + u16 pll_info_block; + + if (!rinfo->bios_seg) + return -EINVAL; + + pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); + + rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08); + rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a); + rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e); + rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10); + rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12); + rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16); + + printk(KERN_INFO "radeonfb: Retreived PLL infos from Legacy BIOS\n"); + return 0; +} + + +static int __devinit radeon_get_pll_info_atom(struct radeonfb_info *rinfo) +{ + u16 pll_info_block; + + if (!rinfo->bios_seg) + return -EINVAL; + + pll_info_block = BIOS_IN16(rinfo->atom_data_start + 12); + + rinfo->pll.sclk = BIOS_IN32(pll_info_block + 8); + rinfo->pll.mclk = BIOS_IN32(pll_info_block + 12); + rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 82); + rinfo->pll.ref_div = 0; /* Have to get it elsewhere */ + rinfo->pll.ppll_min = BIOS_IN16(pll_info_block + 78); + rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 32); + + printk(KERN_INFO "radeonfb: Retreived PLL infos from ATOM BIOS\n"); + return 0; +} + +static void radeon_detect_bios_type(struct radeonfb_info *rinfo) +{ +#ifdef CONFIG_PPC_OF + rinfo->is_atom_bios = 0; + rinfo->get_pll_info = radeon_get_pll_info_openfirmware; + rinfo->get_lvds_info = NULL; + rinfo->get_conn_info = NULL; + printk("radeonfb: Using OpenFirmware tables\n"); +#else + int tmp = rinfo->fp_bios_start + 4; + + if ((BIOS_IN8(tmp) == 'A' && + BIOS_IN8(tmp+1) == 'T' && + BIOS_IN8(tmp+2) == 'O' && + BIOS_IN8(tmp+3) == 'M') || + (BIOS_IN8(tmp) == 'M' && + BIOS_IN8(tmp+1) == 'O' && + BIOS_IN8(tmp+2) == 'T' && + BIOS_IN8(tmp+3) == 'A')) { + rinfo->is_atom_bios = 1; + + rinfo->atom_data_start = BIOS_IN16(rinfo->fp_bios_start + 32); + rinfo->radeon_get_pll_info = radeon_get_pll_info_atom; + rinfo->radeon_get_lvds_info = radeon_get_lvds_info_atom; + rinfo->radeon_get_conn_info = radeon_get_conn_info_atom; + rinfo->radeon_get_tmds_info = radeon_get_tmds_info_atom; + printk("radeonfb: Using ATOM BIOS tables\n"); + } else { + rinfo->is_atom_bios = 0; + rinfo->radeon_get_pll_info = radeon_get_pll_info_legacy; + rinfo->radeon_get_lvds_info = radeon_get_lvds_info_legacy; + rinfo->radeon_get_conn_info = radeon_get_conn_info_legacy; + rinfo->radeon_get_tmds_info = radeon_get_tmds_info_legacy; + printk("radeonfb: Using Legacy BIOS tables\n"); + } +#endif /* CONFIG_PPC_OF */ + +} + /* * Retreive PLL infos by different means (BIOS, Open Firmware, register probing...) */ -static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo) +static void __devinit radeon_get_pll_info(struct radeonfb_info *rinfo) { /* * In the case nothing works, these are defaults; they are mostly @@ -648,46 +733,30 @@ case PCI_DEVICE_ID_ATI_RADEON_QF: case PCI_DEVICE_ID_ATI_RADEON_QG: default: - rinfo->pll.ppll_max = 35000; - rinfo->pll.ppll_min = 12000; + if (rinfo->family == CHIP_FAMILY_R420) { + rinfo->pll.ppll_max = 50000; + rinfo->pll.ppll_min = 20000; + } else { + rinfo->pll.ppll_max = 35000; + rinfo->pll.ppll_min = 12000; + } rinfo->pll.mclk = 16600; rinfo->pll.sclk = 16600; rinfo->pll.ref_clk = 2700; break; } - rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; - - -#ifdef CONFIG_PPC_OF - /* - * Retreive PLL infos from Open Firmware first - */ - if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) { - printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n"); - goto found; - } -#endif /* CONFIG_PPC_OF */ /* - * Check out if we have an X86 which gave us some PLL informations - * and if yes, retreive them + * If we have a way to retrieve the PLL information, do so. */ - if (!force_measure_pll && rinfo->bios_seg) { - u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); - - rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08); - rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a); - rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e); - rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10); - rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12); - rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16); - - printk(KERN_INFO "radeonfb: Retreived PLL infos from BIOS\n"); - goto found; + if (!force_measure_pll && rinfo->radeon_get_pll_info) { + if (!rinfo->radeon_get_pll_info(rinfo)) { + goto found; + } } /* - * We didn't get PLL parameters from either OF or BIOS, we try to + * If we don't get the PLL parameters handed to us, we try to * probe them */ if (radeon_probe_pll_params(rinfo) == 0) { @@ -701,6 +770,22 @@ printk(KERN_INFO "radeonfb: Used default PLL infos\n"); found: + + /* Check and fix-up the PLL divisor if necessary */ + if (rinfo->pll.ref_div < 2) { + int tmp = INPLL(PPLL_REF_DIV); + if (rinfo->family == CHIP_FAMILY_RS300) { + rinfo->pll.ref_div = (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> R300_PPLL_REF_DIV_ACC_SHIFT; + } else { + rinfo->pll.ref_div = tmp & PPLL_REF_DIV_MASK; + } + + /* Sane default */ + if (rinfo->pll.ref_div < 2) { + rinfo->pll.ref_div = 12; + } + } + /* * Some methods fail to retreive SCLK and MCLK values, we apply default * settings in this case (200Mhz). If that really happne often, we could @@ -2412,6 +2497,7 @@ * We probably need to make sure this is the primary display, * but that is difficult without some arch support. */ + #ifdef CONFIG_X86 if (rinfo->bios_seg == NULL) radeon_find_mem_vbios(rinfo); @@ -2423,8 +2509,17 @@ if (rinfo->bios_seg == NULL && rinfo->is_mobility) radeon_map_ROM(rinfo, pdev); + /* Check BIOS Type */ + radeon_detect_bios_type(rinfo); + /* Get informations about the board's PLL */ - radeon_get_pllinfo(rinfo); + radeon_get_pll_info(rinfo); + + /* Get informations about internal TMDS controller if any */ + radeon_get_tmds_info(rinfo); + + /* Get infos about connectors */ + radeon_get_conn_info(rinfo); #ifdef CONFIG_FB_RADEON_I2C /* Register I2C bus */ diff -aur aty-2.6.15/radeon_monitor.c aty/radeon_monitor.c --- aty-2.6.15/radeon_monitor.c 2006-02-22 23:28:14.000000000 -0500 +++ aty/radeon_monitor.c 2006-02-23 15:06:41.000000000 -0500 @@ -1,6 +1,29 @@ #include "radeonfb.h" #include "../edid.h" +/* + * TMDS PLL configuration table, taken from X.org + */ +static const struct radeon_tmds_pll_info default_tmds_pll[CHIP_FAMILY_LAST][4] = +{ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/ + {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/ + {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x400f7/*0x40111*/}, {0, 0}}, /*CHIP_FAMILY_RV280*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV380*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R420*/ +}; + static struct fb_var_screeninfo radeonfb_default_var = { .xres = 640, .yres = 480, @@ -160,21 +183,65 @@ #endif /* CONFIG_PPC_OF */ -static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) +int __devinit radeon_get_lvds_info_atom(struct radeonfb_info *rinfo) +{ + unsigned long tmp; + + if (!rinfo->bios_seg) + return -ENODEV; + + tmp = BIOS_IN16(rinfo->atom_data_start + 16); + if (!tmp) { + printk(KERN_ERR "radeonfb: No LVDS panel info in BIOS\n"); + rinfo->panel_info.pwr_delay = 200; + return -ENODEV; + } + + rinfo->panel_info.xres = BIOS_IN16(tmp+6); + rinfo->panel_info.yres = BIOS_IN16(tmp+10); + printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n", + rinfo->panel_info.xres, rinfo->panel_info.yres); + rinfo->panel_info.pwr_delay = BIOS_IN16(tmp+40); + RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); + if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) + rinfo->panel_info.pwr_delay = 2000; + + /* No special divider combinations? */ + + rinfo->panel_info.hblank = BIOS_IN16(tmp+8); + rinfo->panel_info.hOver_plus = BIOS_IN16(tmp+14); + rinfo->panel_info.hSync_width = BIOS_IN16(tmp+16); + rinfo->panel_info.vblank = BIOS_IN16(tmp+12); + rinfo->panel_info.vOver_plus = BIOS_IN16(tmp+18); + rinfo->panel_info.vSync_width = BIOS_IN16(tmp+20); + rinfo->panel_info.clock = BIOS_IN16(tmp+4); + + /* Assume high active syncs for now until ATI tells me more... maybe we + * can probe register values here ? + */ + rinfo->panel_info.hAct_high = 1; + rinfo->panel_info.vAct_high = 1; + /* Mark panel infos valid */ + rinfo->panel_info.valid = 1; + + return 0; +} + +int __devinit radeon_get_lvds_info_legacy(struct radeonfb_info *rinfo) { unsigned long tmp, tmp0; char stmp[30]; int i; if (!rinfo->bios_seg) - return 0; + return -ENODEV; if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) { - printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n"); + printk(KERN_ERR "radeonfb: No LVDS panel info in BIOS\n"); rinfo->panel_info.pwr_delay = 200; - return 0; + return -ENODEV; } - + for(i=0; i<24; i++) stmp[i] = BIOS_IN8(tmp+i+1); stmp[24] = 0; @@ -182,13 +249,13 @@ rinfo->panel_info.xres = BIOS_IN16(tmp + 25); rinfo->panel_info.yres = BIOS_IN16(tmp + 27); printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n", - rinfo->panel_info.xres, rinfo->panel_info.yres); - + rinfo->panel_info.xres, rinfo->panel_info.yres); + rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44); RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) rinfo->panel_info.pwr_delay = 2000; - + /* * Some panels only work properly with some divider combinations */ @@ -203,6 +270,7 @@ RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider); RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); } + RTRACE("Scanning BIOS table ...\n"); for(i=0; i<32; i++) { tmp0 = BIOS_IN16(tmp+64+i*2); @@ -226,7 +294,7 @@ rinfo->panel_info.vAct_high = 1; /* Mark panel infos valid */ rinfo->panel_info.valid = 1; - + RTRACE("Found panel in BIOS table:\n"); RTRACE(" hblank: %d\n", rinfo->panel_info.hblank); RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); @@ -235,57 +303,507 @@ RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width); RTRACE(" clock: %d\n", rinfo->panel_info.clock); - - return 1; + + return 0; } } + RTRACE("Didn't find panel in BIOS table !\n"); + return -ENODEV; +} + +/* + * Get informations about TMDS controllers and their setup at + * different operating frequencies + */ +void __devinit radeon_get_tmds_info(struct radeonfb_info *rinfo) +{ + int i; + + /* Get default TMDS infos for this chip */ + for (i=0; i<4; i++) { + rinfo->tmds_pll[i].value = + default_tmds_pll[rinfo->family][i].value; + rinfo->tmds_pll[i].freq = + default_tmds_pll[rinfo->family][i].freq; + } + + /* Get whatever the firmware provides */ + if (rinfo->radeon_get_tmds_info) { + rinfo->radeon_get_tmds_info(rinfo); + // XXX Do we care about the return value? + } +} + +int __devinit radeon_get_tmds_info_legacy(struct radeonfb_info *rinfo) +{ + int offset, i, n, rev; + + offset = BIOS_IN16(rinfo->fp_bios_start + 0x34); + if (offset == 0) + return -ENODEV; + + rev = BIOS_IN8(offset); + printk(KERN_INFO "DFP table revision: %d\n", rev); + + switch(rev) { + case 3: + n = BIOS_IN8(offset + 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + /* Looks bogus ... but that's what is in X.org */ + rinfo->tmds_pll[i].value = + BIOS_IN32(offset+i*10+0x08); + rinfo->tmds_pll[i].freq = + BIOS_IN16(offset+i*10+0x10); + } + return 0; + + /* revision 4 has some problem as it appears in RV280, + * comment it off for now, use default instead + */ +#if 0 + case 4: + stride = 0; + n = BIOS_IN8(offset 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + rinfo->tmds_pll[i].value = + BIOS_IN32(tmp+stride+0x08); + rinfo->tmds_pll[i].freq = + BIOS_IN16(tmp+stride+0x10); + if (i == 0) + stride += 10; + else + stride += 6; + } + return 0; +#endif + } + return -ENODEV; +} + +int __devinit radeon_get_tmds_info_atom(struct radeonfb_info *rinfo) +{ + int offset, i, maxfreq; + + offset = BIOS_IN16(rinfo->atom_data_start + 18); + if (offset == 0) + return -ENODEV; + + maxfreq = BIOS_IN16(offset + 4); + + for (i = 0; i < 4; i++) { + rinfo->tmds_pll[i].freq = BIOS_IN16(offset+i*6+6); + /* This assumes each field in TMDS_PLL has 6 bit as + * in R300/R420 + */ + rinfo->tmds_pll[i].value = + ((BIOS_IN8(offset+i*6+8) & 0x3f) | + ((BIOS_IN8(offset+i*6+10) & 0x3f)<<6) | + ((BIOS_IN8(offset+i*6+9) & 0xf)<<12) | + ((BIOS_IN8(offset+i*6+11) & 0xf)<<16)); + printk(KERN_INFO "TMDS PLL from BIOS: %ld %x\n", + rinfo->tmds_pll[i].freq, rinfo->tmds_pll[i].value); + + if (maxfreq == rinfo->tmds_pll[i].freq) { + rinfo->tmds_pll[i].freq = 0xffffffff; + break; + } + } return 0; } -/* Try to extract the connector informations from the BIOS. This - * doesn't quite work yet, but it's output is still useful for - * debugging + +/* + * Get informations about the various connectors on this card. This is + * the most prone to fail function as various firmwares tend to say + * crap or not give any info at all. The Open Firmware version is just + * a table of known cards for now for example. We'll probably need some + * additional module params to force different settings in case of + * misdetection here. + * + * This doesn _not_ try actual probing of whatever is plugged on those + * various connectors. This will be done later. We do store whatever + * probing info the firmware gives us though */ -static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo) +void __devinit radeon_get_conn_info(struct radeonfb_info *rinfo) { - int offset, chips, connectors, tmp, i, conn, type; + int i; - static char* __conn_type_table[16] = { - "NONE", "Proprietary", "CRT", "DVI-I", "DVI-D", "Unknown", "Unknown", - "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", - "Unknown", "Unknown", "Unknown" + const char *conn_type_name[] = { + "NONE", "VGA", "DVI-I", "DVI-D", "DVI-A", "S-Video", + "Composite Video", "Internal Panel", "Digital", + "Unsupported", "Proprietary" + }; + const char *mon_type_name[] = { + "None", "CRT", "LVDS Flat panel", + "DVI Flat panel", "Composite TV", "S-Video TV" }; - if (!rinfo->bios_seg) - return; + /* Clear table */ + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + rinfo->connectors[i].conn_type = conn_none; + rinfo->connectors[i].ddc_type = ddc_none; + rinfo->connectors[i].dac_type = dac_unknown; + rinfo->connectors[i].tmds_type = tmds_unknown; + rinfo->connectors[i].mon_type = MT_UNKNOWN; + } - offset = BIOS_IN16(rinfo->fp_bios_start + 0x50); - if (offset == 0) { - printk(KERN_WARNING "radeonfb: No connector info table detected\n"); - return; + /* Try to obtain infos from firmware */ + if (rinfo->radeon_get_conn_info) { + if (!rinfo->radeon_get_conn_info(rinfo)) { + goto found; + } + } + + printk(KERN_INFO "radeonfb: No connector infos, using defaults...\n"); + + /* Here, we use defaults that are common enough ... we hope + * For a mobility chip, we assume LVDS is on primary + */ + if (rinfo->is_mobility) { + rinfo->connectors[0].conn_type = conn_lvds; + rinfo->connectors[0].ddc_type = ddc_dvi; + rinfo->connectors[0].dac_type = dac_primary; + rinfo->connectors[0].tmds_type = tmds_unknown; + rinfo->connectors[0].mon_type = MT_UNKNOWN; + + rinfo->connectors[1].conn_type = conn_dvi_d; + rinfo->connectors[1].ddc_type = ddc_vga; + rinfo->connectors[1].dac_type = dac_primary; + rinfo->connectors[1].tmds_type = tmds_internal; + rinfo->connectors[1].mon_type = MT_UNKNOWN; + + rinfo->connectors[2].conn_type = conn_stv; + rinfo->connectors[2].ddc_type = ddc_none; + rinfo->connectors[2].dac_type = dac_tvdac; + rinfo->connectors[2].tmds_type = tmds_unknown; + rinfo->connectors[2].mon_type = MT_UNKNOWN; + } else { + rinfo->connectors[0].conn_type = conn_dvi_d; + rinfo->connectors[0].ddc_type = ddc_dvi; + rinfo->connectors[0].dac_type = dac_tvdac; + rinfo->connectors[0].tmds_type = tmds_internal; + rinfo->connectors[0].mon_type = MT_UNKNOWN; + + rinfo->connectors[1].conn_type = conn_vga; + rinfo->connectors[1].ddc_type = ddc_vga; + rinfo->connectors[1].dac_type = dac_primary; + rinfo->connectors[1].tmds_type = tmds_external; + rinfo->connectors[1].mon_type = MT_UNKNOWN; + } + + found: + /* Now, we do additional fixups */ + + /* RS300 has only one DAC, force TV-DAC on VGA port */ + if (rinfo->family == CHIP_FAMILY_RS300) { + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (rinfo->connectors[i].conn_type == conn_vga) + rinfo->connectors[i].dac_type = dac_tvdac; + else if (rinfo->connectors[i].dac_type != dac_unknown) + rinfo->connectors[i].dac_type = dac_primary; + } } - /* Don't do much more at this point but displaying the data if - * DEBUG is enabled + /* Single head chips all use primary DAC */ + if (!rinfo->has_CRTC2) + rinfo->connectors[0].dac_type = dac_primary; + + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (rinfo->connectors[i].conn_type == conn_none) + continue; + printk(KERN_INFO " * Connector %d is %s. Monitor: %s\n", i, + conn_type_name[rinfo->connectors[i].conn_type], + rinfo->connectors[i].mon_type == MT_UNKNOWN ? + "Not Probed" : + mon_type_name[rinfo->connectors[i].mon_type]); + printk(KERN_INFO " ddc port: %d, dac: %d, tmds: %d\n", + rinfo->connectors[i].ddc_type, + rinfo->connectors[i].dac_type, + rinfo->connectors[i].tmds_type); + } + return; + } + + +int __devinit radeon_get_conn_info_atom(struct radeonfb_info *rinfo) +{ + int i, j, offset, valids; + int ids[RADEON_MAX_CONNECTORS]; + u16 portinfo, tmp0; + int conn_index = 0; + int conn_add = 2; + int idx = 0; + int ddc_type, dac_type, conn_type, tmds_type, port_id; + int connector_found = 0; + + offset = BIOS_IN16(rinfo->atom_data_start + 22); + if (offset == 0) + return -ENODEV; + + /* Again, I slightly modified X.org algorithm. I assign "primary" outputs + * to entries 0 and 1, and anything else goes after 2. + * + * Also, I keep an array of all port IDs matching connectors[] array, + * unlike X which limits itself to "crtc"'s */ - chips = BIOS_IN8(offset++) >> 4; - RTRACE("%d chips in connector info\n", chips); - for (i = 0; i < chips; i++) { - tmp = BIOS_IN8(offset++); - connectors = tmp & 0x0f; - RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors); - for (conn = 0; ; conn++) { - tmp = BIOS_IN16(offset); - if (tmp == 0) + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) + ids[i] = -1; + + valids = BIOS_IN16(offset + 4); + for (i = 0; i < 8; i++) { + if (!(valids & (1 << i))) + continue; + portinfo = BIOS_IN16(offset + 6 + i*2); + + conn_type = (portinfo >> 4) & 0xf; + dac_type = (portinfo & 0xf) - 1; + port_id = (portinfo >> 8) & 0xf; + ddc_type = ddc_none; + + if ((tmp0 = BIOS_IN16(rinfo->atom_data_start + 24))) { + switch(BIOS_IN16(tmp0 + 4 + (27 * port_id)) * 4) { + case GPIO_MONID: + ddc_type = ddc_monid; + break; + case GPIO_DVI_DDC: + ddc_type = ddc_dvi; + break; + case GPIO_VGA_DDC: + ddc_type = ddc_vga; break; - offset += 2; - type = (tmp >> 12) & 0x0f; - RTRACE(" * connector %d of type %d (%s) : %04x\n", - conn, type, __conn_type_table[type], tmp); + case GPIO_CRT2_DDC: + ddc_type = ddc_crt2; + break; + default: + ddc_type = ddc_none; + break; + } + } + + if (i == 3) + tmds_type = tmds_internal; + else if (i == 7) + tmds_type = tmds_external; + else + tmds_type = tmds_unknown; + + RTRACE("index %d port %d conn %d dac %d ddc %d tmds %d\n", i, port_id, conn_type, dac_type, ddc_type, tmds_type); + + /* Ok, now we have the port ID, look for an existing port + * already using this ID + */ + for (j = 0; j < RADEON_MAX_CONNECTORS; j++) { + if (port_id != ids[j]) + continue; + /* Gotcha, just "update" values */ + if (tmds_type != tmds_unknown) + rinfo->connectors[j].tmds_type = tmds_type; + if (rinfo->connectors[j].dac_type == dac_unknown) + rinfo->connectors[j].dac_type = dac_type; + if (rinfo->connectors[j].ddc_type == dac_unknown) + rinfo->connectors[j].ddc_type = dac_type; + continue; + } + + conn_index = (ddc_type == ddc_dvi || conn_index == 1) ? 0 : 1; + + /* if the port is a TV port, or both connectors are already + * assigned, assign it after further in the table + */ + if (conn_type == conn_ctv || conn_type == conn_stv || + (rinfo->connectors[0].conn_type != conn_none && + rinfo->connectors[1].conn_type)) + idx = conn_add++; + else + idx = conn_index; + + rinfo->connectors[idx].tmds_type = tmds_type; + rinfo->connectors[idx].dac_type = dac_type; + rinfo->connectors[idx].ddc_type = ddc_type; + rinfo->connectors[idx].conn_type = conn_type; + + /* increment connector_found for primary connectors only */ + if (idx < 2) + connector_found += (idx + 1); + } + + if (connector_found == 0) + return -ENODEV; + + return 0; +} + +/* Try to extract the connector informations from the BIOS. This + * doesn't quite work yet, but it's output is still useful for + * debugging + */ +int __devinit radeon_get_conn_info_legacy(struct radeonfb_info *rinfo) +{ + int offset, i, entry, tmp; + int ddc_type, dac_type, conn_type, tmds_type; + int conn_index = 0; + int conn_add = 2; + int idx = 0; + + /* Convert legacy to real connector types */ + const enum radeon_conn_type legacy_conn_to_type[] = { + conn_none, + conn_proprietary, + conn_vga, + conn_dvi_i, + conn_dvi_d, + conn_ctv, + conn_stv, + conn_unsupported, + }; + + /* Some laptops only have one connector (VGA) listed in the connector + * table, we need to add LVDS in as a non-DDC display. + * Note, we can't assume the listed VGA will be filled in PortInfo[0], + * when walking through connector table. connector_found has following + * meaning: + * 0 -- nothing found, + * 1 -- only connectors[0] filled, + * 2 -- only connectors[1] filled, + * 3 -- both are filled. + * + * Note: I modified X.org algorithm to add additional entries if any + * after the second table slot. Those entries do not affect the value + * of connector_found. --BenH. + */ + int connector_found = 0; + + offset = BIOS_IN16(rinfo->fp_bios_start + 0x50); + if (offset == 0) + return -ENODEV; + + for (i = 1; i < 4; i++) { + entry = offset + i*2; + + /* End of table */ + if (!BIOS_IN8(entry) && i > 1) + break; + + /* Read table entry, check connector type */ + tmp = BIOS_IN16(entry); + conn_type = (tmp >> 12) & 0xf; + if (conn_type == legacy_conn_none) + continue; + ddc_type = (tmp >> 8) & 0xf; + dac_type = (tmp & 0x01) ? dac_tvdac : dac_primary; + tmds_type = (tmp & 0x10) ? tmds_external : tmds_internal; + + /* same connector */ + if (connector_found > 0) { + if (rinfo->connectors[conn_index].ddc_type == ddc_type) + continue; + } + + /* sanity checks */ + if (ddc_type > ddc_crt2) + ddc_type = ddc_none; + if (conn_type > legacy_conn_unsupported) + conn_type = legacy_conn_unsupported; + if (conn_type != legacy_conn_dvi_d && + conn_type != legacy_conn_dvi_i && + tmds_type == tmds_internal) + tmds_type= tmds_unknown; + + /* convert connector type */ + conn_type = legacy_conn_to_type[conn_type]; + + /* internal DDC_DVI port will get assigned to connector[0], or + * if there is no DDC_DVI (like in some IGPs). + */ + conn_index = (ddc_type == ddc_dvi || conn_index == 1) ? 0 : 1; + + /* if the port is a TV port, or both connectors are already + * assigned, assign it after further in the table + */ + if (conn_type == conn_ctv || conn_type == conn_stv || + (rinfo->connectors[0].conn_type != conn_none && + rinfo->connectors[1].conn_type)) + idx = conn_add++; + else + idx = conn_index; + + /* if table full, exit */ + if (idx >= RADEON_MAX_CONNECTORS) { + printk(KERN_WARNING "radeonfb: Connector table full !\n"); + break; } + rinfo->connectors[idx].conn_type = conn_type; + rinfo->connectors[idx].ddc_type = ddc_type; + rinfo->connectors[idx].dac_type = dac_type; + rinfo->connectors[idx].tmds_type = tmds_type; + + /* increment connector_found for primary connectors only */ + if (idx < 2) + connector_found += (idx + 1); + } + + if (rinfo->is_mobility) { + /* For the cases where only one VGA connector is found, + * we assume LVDS is not listed in the connector table, + * add it in here as the first port. + * + * TODO: Check what's up with laptops that have a DVI output + * and no LVDS entry in the table. I suspect some thinkpads + * may play trick with us here... We may want to check the + * presence of a panel via LVDS_GEN_CNTL to be sure... + */ + if ((connector_found < 3) && + (rinfo->connectors[idx].conn_type == conn_vga)) { + if (connector_found == 1) { + memcpy(&rinfo->connectors[1], + &rinfo->connectors[0], + sizeof(struct radeon_connector)); + } + /* Fixme: TV DAC is probably elsewhere ... */ + rinfo->connectors[0].dac_type = dac_tvdac; + rinfo->connectors[0].tmds_type = tmds_unknown; + rinfo->connectors[0].ddc_type = ddc_none; + rinfo->connectors[0].conn_type = conn_proprietary; + + printk(KERN_WARNING "radeonfb: LVDS port is not in connector table, added in.\n"); + if (connector_found == 0) + connector_found = 1; + else + connector_found = 3; + } + + /* Check for LCD DDC info table */ + if ((offset = BIOS_IN16(rinfo->fp_bios_start + 0x42))) { + if ((tmp = BIOS_IN16(offset + 0x15))) { + if ((ddc_type = BIOS_IN8(tmp+2) & 0x07)) { + rinfo->connectors[0].ddc_type = ddc_type; + printk(KERN_WARNING "radeonfb: LCD DDC Info Table found, " + "forcing primary port to %d\n", + ddc_type); + } + } + } + } else if (connector_found == 2) { + memcpy(&rinfo->connectors[0], &rinfo->connectors[1], + sizeof (struct radeon_connector)); + rinfo->connectors[1].dac_type = dac_unknown; + rinfo->connectors[1].tmds_type = tmds_unknown; + rinfo->connectors[1].ddc_type = ddc_none; + rinfo->connectors[1].conn_type = conn_none; + connector_found = 1; } + + if (connector_found == 0) + return -ENODEV; + + /* External TMDS Table, not used now */ + return 0; } @@ -434,8 +952,6 @@ #endif int tmp, i; - radeon_parse_connector_info(rinfo); - if (radeon_parse_monitor_layout(rinfo, monitor_layout)) { /* @@ -445,7 +961,7 @@ * a layout for each card ? */ - RTRACE("Using specified monitor layout: %s", monitor_layout); + RTRACE("Using specified monitor layout: %s\n", monitor_layout); #ifdef CONFIG_FB_RADEON_I2C if (!ignore_edid) { if (rinfo->mon1_type != MT_NONE) @@ -519,7 +1035,8 @@ /* * Check for cards with reversed DACs or TMDS controllers using BIOS */ - if (rinfo->bios_seg && + + if (rinfo->bios_seg && !rinfo->is_atom_bios && (tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) { for (i = 1; i < 4; i++) { unsigned int tmp0; @@ -663,7 +1180,7 @@ rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7; rinfo->panel_info.use_bios_dividers = 1; - printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x " + printk(KERN_INFO "Using Firmware dividers 0x%08x " "from PPLL %d\n", rinfo->panel_info.fbk_divider | (rinfo->panel_info.post_divider << 16), @@ -741,8 +1258,12 @@ /* * First check out what BIOS has to say */ - if (rinfo->mon1_type == MT_LCD) - radeon_get_panel_info_BIOS(rinfo); + if (rinfo->mon1_type == MT_LCD) { + if (rinfo->radeon_get_lvds_info) { + rinfo->radeon_get_lvds_info(rinfo); + // XXX Do we care about the return value? + } + } /* * Parse EDID detailed timings and deduce panel infos if any. Right now diff -aur aty-2.6.15/radeonfb.h aty/radeonfb.h --- aty-2.6.15/radeonfb.h 2006-02-22 23:28:14.000000000 -0500 +++ aty/radeonfb.h 2006-02-23 15:00:24.000000000 -0500 @@ -91,7 +91,8 @@ /* * Monitor types */ -enum radeon_montype { +enum radeon_mon_type { + MT_UNKNOWN = -1, MT_NONE = 0, MT_CRT, /* CRT */ MT_LCD, /* LCD */ @@ -103,8 +104,8 @@ /* * DDC i2c ports */ -enum ddc_type { - ddc_none, +enum radeon_ddc_type { + ddc_none = 0, ddc_monid, ddc_dvi, ddc_vga, @@ -114,14 +115,69 @@ /* * Connector types */ -enum conn_type { - conn_none, - conn_proprietary, - conn_crt, - conn_DVI_I, - conn_DVI_D, +enum radeon_legacy_conn_type { + legacy_conn_none = 0, + legacy_conn_proprietary, + legacy_conn_crt, + legacy_conn_dvi_i, + legacy_conn_dvi_d, + legacy_conn_ctv, + legacy_conn_stv, + legacy_conn_unsupported, }; +enum radeon_conn_type { + conn_none = 0, + conn_vga, + conn_dvi_i, + conn_dvi_d, + conn_dvi_a, + conn_stv, + conn_ctv, + conn_lvds, + conn_digital, + conn_unsupported, + conn_proprietary +}; + +/* + * DAC types + */ +enum radeon_dac_type { + dac_unknown = -1, + dac_primary = 0, + dac_tvdac = 1, +}; + +/* + * TMDS types + */ +enum radeon_tmds_type { + tmds_unknown = -1, + tmds_internal = 0, + tmds_external = 1, +}; + +/* + * Each connector gets this structure associated with it, + * containing infos about the connector wiring and about + * whatever has been detected on it + */ +struct radeon_connector { + enum radeon_conn_type conn_type; + enum radeon_ddc_type ddc_type; + enum radeon_dac_type dac_type; + enum radeon_tmds_type tmds_type; + enum radeon_mon_type mon_type; + u8 *edid; + struct fb_videomode *modedb; + unsigned int modedb_size; +}; + +/* + * Currently, the driver deals with at most 4 connectors + */ +#define RADEON_MAX_CONNECTORS 4 /* * PLL infos @@ -129,11 +185,19 @@ struct pll_info { int ppll_max; int ppll_min; - int sclk, mclk; + int sclk; + int mclk; int ref_div; int ref_clk; }; +/* + * TMDS PLL infos + */ +struct radeon_tmds_pll_info { + long freq; + u32 value; +}; /* * This structure contains the various registers manipulated by this @@ -298,6 +362,18 @@ void __iomem *bios_seg; int fp_bios_start; + int is_atom_bios; + int atom_data_start; + + /* BIOS Functions */ + int (*radeon_get_pll_info)(struct radeonfb_info *rinfo); + int (*radeon_get_lvds_info)(struct radeonfb_info *rinfo); + int (*radeon_get_conn_info)(struct radeonfb_info *rinfo); + int (*radeon_get_tmds_info)(struct radeonfb_info *rinfo); + + /* Connector infos */ + struct radeon_connector connectors[RADEON_MAX_CONNECTORS]; + u32 pseudo_palette[17]; struct { u8 red, green, blue, pad; } palette[256]; @@ -319,6 +395,8 @@ int reversed_DAC; int reversed_TMDS; struct panel_info panel_info; + struct radeon_tmds_pll_info tmds_pll[4]; + int mon1_type; u8 *mon1_EDID; struct fb_videomode *mon1_modedb; @@ -625,4 +703,14 @@ extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, int reg_only); +/* Bios functions. Fix this. */ +extern void __devinit radeon_get_conn_info(struct radeonfb_info *rinfo); +extern void __devinit radeon_get_tmds_info(struct radeonfb_info *rinfo); + +extern int __devinit radeon_get_lvds_info_atom(struct radeonfb_info *rinfo); +extern int __devinit radeon_get_lvds_info_legacy(struct radeonfb_info *rinfo); +extern int __devinit radeon_get_conn_info_atom(struct radeonfb_info *rinfo); +extern int __devinit radeon_get_conn_info_legacy(struct radeonfb_info *rinfo); +extern int __devinit radeon_get_tmds_info_legacy(struct radeonfb_info *rinfo); +extern int __devinit radeon_get_tmds_info_atom(struct radeonfb_info *rinfo); #endif /* __RADEONFB_H__ */ Only in aty-2.6.15: radeonfb.ko