--- ./drivers/video/fbmon.c.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/fbmon.c 2008-09-23 11:54:30.000000000 +0200 @@ -40,7 +40,7 @@ * EDID parser */ -#undef DEBUG /* define this for verbose EDID parsing output */ +#define DEBUG /* define this for verbose EDID parsing output */ #ifdef DEBUG #define DPRINTK(fmt, args...) printk(fmt,## args) --- ./drivers/video/modedb.c.orig 2008-07-13 23:51:29.000000000 +0200 +++ ./drivers/video/modedb.c 2008-09-23 11:54:30.000000000 +0200 @@ -14,7 +14,7 @@ #include #include -#undef DEBUG +#define DEBUG #define name_matches(v, s, l) \ ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l)) @@ -181,7 +181,7 @@ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ - NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, + "Wide Screen", 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ @@ -523,7 +523,8 @@ int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; - u32 best, diff, tdiff; + u32 best, diff; + unsigned int dist; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { @@ -591,7 +592,6 @@ "", (margins) ? " with margins" : "", (interlace) ? " interlaced" : ""); - memset(&cvt_mode, 0, sizeof(cvt_mode)); cvt_mode.xres = xres; cvt_mode.yres = yres; cvt_mode.refresh = (refresh) ? refresh : 60; @@ -626,19 +626,21 @@ info->monspecs.vfmin && info->monspecs.vfmax && info->monspecs.hfmin && info->monspecs.hfmax && info->monspecs.dclkmax) { - refresh = 1000; + refresh = 100; } else { refresh = 60; } + DPRINTK("No refresh rate specified, using %d\n", refresh); } diff = -1; best = -1; + dist = 3; for (i = 0; i < dbsize; i++) { if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) { + if (refresh_specified && abs(db[i].refresh - refresh) < dist) { return 1; } else { if (abs(db[i].refresh - refresh) < diff) { @@ -649,32 +651,25 @@ } } if (best != -1) { + DPRINTK("Best mode is %dx%d@%d\n", db[best].xres, db[best].yres, db[best].refresh); fb_try_mode(var, info, &db[best], bpp); return (refresh_specified) ? 2 : 1; } - diff = 2 * (xres + yres); + diff = xres + yres; best = -1; DPRINTK("Trying best-fit modes\n"); for (i = 0; i < dbsize; i++) { + if (xres <= db[i].xres && yres <= db[i].yres) { DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); if (!fb_try_mode(var, info, &db[i], bpp)) { - tdiff = abs(db[i].xres - xres) + - abs(db[i].yres - yres); - - /* - * Penalize modes with resolutions smaller - * than requested. - */ - if (xres > db[i].xres || yres > db[i].yres) - tdiff += xres + yres; - - if (diff > tdiff) { - diff = tdiff; + if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { + diff = (db[i].xres - xres) + (db[i].yres - yres); best = i; } } } + } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); return 5; --- ./drivers/video/fb_ddc.c.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/fb_ddc.c 2008-09-23 11:54:30.000000000 +0200 @@ -56,12 +56,13 @@ int i, j; algo_data->setscl(algo_data->data, 1); + algo_data->setscl(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 1); + algo_data->setsda(algo_data->data, 0); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -96,15 +97,14 @@ algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); if (edid) break; } /* Release the DDC lines when done or the Apple Cinema HD display * will switch off */ - algo_data->setsda(algo_data->data, 1); - algo_data->setscl(algo_data->data, 1); + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); adapter->class |= I2C_CLASS_DDC; return edid; --- ./drivers/video/aty/radeon_accel.c.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/aty/radeon_accel.c 2008-09-23 11:54:30.000000000 +0200 @@ -211,9 +211,7 @@ host_path_cntl = INREG(HOST_PATH_CNTL); rbbm_soft_reset = INREG(RBBM_SOFT_RESET); - if (rinfo->family == CHIP_FAMILY_R300 || - rinfo->family == CHIP_FAMILY_R350 || - rinfo->family == CHIP_FAMILY_RV350) { + if (IS_R300_VARIANT(rinfo)) { u32 tmp; OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset | @@ -262,16 +260,15 @@ { unsigned long temp; - /* disable 3D engine */ - OUTREG(RB3D_CNTL, 0); - radeonfb_engine_reset(rinfo); radeon_fifo_wait (1); - if ((rinfo->family != CHIP_FAMILY_R300) && - (rinfo->family != CHIP_FAMILY_R350) && - (rinfo->family != CHIP_FAMILY_RV350)) + if (IS_R300_VARIANT(rinfo)) { + temp = INREG(RB2D_DSTCACHE_MODE); + OUTREG(RB2D_DSTCACHE_MODE, temp | (1<<17)); /* FIXME */ + } else { OUTREG(RB2D_DSTCACHE_MODE, 0); + } radeon_fifo_wait (3); /* We re-read MC_FB_LOCATION from card as it can have been --- ./drivers/video/aty/radeon_base.c.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/aty/radeon_base.c 2008-09-23 11:54:30.000000000 +0200 @@ -98,8 +98,10 @@ #define MAX_MAPPED_VRAM (2048*2048*4) #define MIN_MAPPED_VRAM (1024*768*1) +#define PCI_CLASS_MASK 0 + #define CHIP_DEF(id, family, flags) \ - { PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) } +{ PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, PCI_CLASS_MASK, (flags) | (CHIP_FAMILY_##family) } static struct pci_device_id radeonfb_pci_table[] = { /* Radeon Xpress 200m */ @@ -261,8 +263,10 @@ * globals */ +static char *monitor_mode[2] = { NULL, NULL }; static char *mode_option; static char *monitor_layout; +static char *table_layout; static int noaccel = 0; static int default_dynclk = -2; static int nomodeset = 0; @@ -271,6 +275,7 @@ static int panel_yres = 0; static int force_dfp = 0; static int force_measure_pll = 0; +static int force_pll_calc = 0; #ifdef CONFIG_MTRR static int nomtrr = 0; #endif @@ -315,7 +320,7 @@ rom = pci_map_rom(dev, &rom_size); if (!rom) { - printk(KERN_ERR "radeonfb (%s): ROM failed to map\n", + pr_err("radeonfb (%s): ROM failed to map\n", pci_name(rinfo->pdev)); return -ENOMEM; } @@ -324,7 +329,7 @@ /* Very simple test to make sure it appeared */ if (BIOS_IN16(0) != 0xaa55) { - printk(KERN_DEBUG "radeonfb (%s): Invalid ROM signature %x " + pr_err("radeonfb (%s): Invalid ROM signature %x " "should be 0xaa55\n", pci_name(rinfo->pdev), BIOS_IN16(0)); goto failed; @@ -357,23 +362,23 @@ * } pci_data_t; */ if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { - printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM" + pr_warning("radeonfb (%s): PCI DATA signature in ROM" "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr)); goto anyway; } rom_type = BIOS_IN8(dptr + 0x14); switch(rom_type) { case 0: - printk(KERN_INFO "radeonfb: Found Intel x86 BIOS ROM Image\n"); + pr_info("radeonfb: Found Intel x86 BIOS ROM Image\n"); break; case 1: - printk(KERN_INFO "radeonfb: Found Open Firmware ROM Image\n"); + pr_info("radeonfb: Found Open Firmware ROM Image\n"); goto failed; case 2: - printk(KERN_INFO "radeonfb: Found HP PA-RISC ROM Image\n"); + pr_info("radeonfb: Found HP PA-RISC ROM Image\n"); goto failed; default: - printk(KERN_INFO "radeonfb: Found unknown type %d ROM Image\n", rom_type); + pr_info("radeonfb: Found unknown type %d ROM Image\n", rom_type); goto failed; } anyway: @@ -432,7 +437,7 @@ return -ENODEV; val = of_get_property(dp, "ATY,RefCLK", NULL); if (!val || !*val) { - printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); + pr_err("radeonfb: No ATY,RefCLK property !\n"); return -EINVAL; } @@ -566,7 +571,7 @@ else if ((xtal > 29400) && (xtal < 29600)) xtal = 2950; else { - printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal); + pr_err("xtal calculation failed: %ld\n", xtal); return -1; } @@ -588,6 +593,32 @@ return 0; } +static void radeon_detect_bios_type(struct radeonfb_info *rinfo) +{ +#ifndef CONFIG_PPC_OF + int offset = rinfo->fp_bios_start + 4; + unsigned char sign[4]; + + sign[0] = BIOS_IN8(offset); + sign[1] = BIOS_IN8(offset + 1); + sign[2] = BIOS_IN8(offset + 2); + sign[3] = BIOS_IN8(offset + 3); + + if (!memcmp(sign, "ATOM", 4) || !memcmp(sign, "MOTA", 4)) { + rinfo->is_atom_bios = 1; + rinfo->atom_data_start = BIOS_IN16(rinfo->fp_bios_start + 32); + + pr_info("radeonfb: ATOM BIOS signature found\n"); + + return; + } +#endif /* NOT CONFIG_PPC_OF */ + + rinfo->is_atom_bios = 0; + + return; +} + /* * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...) */ @@ -658,17 +689,34 @@ * Retrieve PLL infos from Open Firmware first */ if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) { - printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n"); + pr_info("radeonfb: Retrieved PLL infos from Open Firmware\n"); goto found; } #endif /* CONFIG_PPC_OF || CONFIG_SPARC */ /* - * Check out if we have an X86 which gave us some PLL informations + * Check out if we have an ATOM BIOS which gave us some PLL informations * and if yes, retrieve them */ + if (!force_measure_pll && rinfo->bios_seg) { - u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); + u16 pll_info_block; + + if(rinfo->is_atom_bios) { + 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); + } else { + /* + * Check out if we have an X86 which gave us some PLL informations + * and if yes, retrieve them + */ + 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); @@ -676,8 +724,9 @@ 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); + } + pr_info("radeonfb: Retrieved PLL infos from BIOS\n"); - printk(KERN_INFO "radeonfb: Retrieved PLL infos from BIOS\n"); goto found; } @@ -686,32 +735,52 @@ * probe them */ if (radeon_probe_pll_params(rinfo) == 0) { - printk(KERN_INFO "radeonfb: Retrieved PLL infos from registers\n"); + pr_info("radeonfb: Retrieved PLL infos from registers\n"); goto found; } /* * Fall back to already-set defaults... */ - printk(KERN_INFO "radeonfb: Used default PLL infos\n"); + pr_info("radeonfb: Fall back to 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) { + pr_info("radeonfb: Set a sane default PLL divisor\n"); + rinfo->pll.ref_div = 12; + } + } + /* * Some methods fail to retrieve SCLK and MCLK values, we apply default - * settings in this case (200Mhz). If that really happne often, we could + * settings in this case (200Mhz). If that really happened often, we could * fetch from registers instead... */ - if (rinfo->pll.mclk == 0) + if (rinfo->pll.mclk == 0) { + pr_info("radeonfb: Set a sane default MCLK value\n"); rinfo->pll.mclk = 20000; - if (rinfo->pll.sclk == 0) + } + if (rinfo->pll.mclk == 0) { + pr_info("radeonfb: Set a sane default SCLK value\n"); rinfo->pll.sclk = 20000; + } - printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n", + pr_info("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n", rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100, rinfo->pll.ref_div, rinfo->pll.mclk / 100, rinfo->pll.mclk % 100, rinfo->pll.sclk / 100, rinfo->pll.sclk % 100); - printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max); + pr_info("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max); } static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info) @@ -721,7 +790,7 @@ int nom, den; unsigned int pitch; - if (radeon_match_mode(rinfo, &v, var)) + if (radeon_match_mode(rinfo, &v, var, 0)) return -EINVAL; switch (v.bits_per_pixel) { @@ -732,10 +801,7 @@ v.bits_per_pixel = 16; break; case 17 ... 24: -#if 0 /* Doesn't seem to work */ v.bits_per_pixel = 24; - break; -#endif return -EINVAL; case 25 ... 32: v.bits_per_pixel = 32; @@ -791,11 +857,14 @@ v.transp.length = 8; break; default: - printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", + pr_info("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", var->xres, var->yres, var->bits_per_pixel); return -EINVAL; } + pr_info("radeonfb: color depth valid, mode %dx%dx%d accepted\n", + v.xres, v.yres, v.bits_per_pixel); + if (v.yres_virtual < v.yres) v.yres_virtual = v.yres; if (v.xres_virtual < v.xres) @@ -931,7 +1000,7 @@ } -int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch) +int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch, int id) { u32 val; u32 tmp_pix_clks; @@ -966,7 +1035,7 @@ OUTREG(CRTC_EXT_CNTL, val); - switch (rinfo->mon1_type) { + switch (rinfo->mon[id].type) { case MT_DFP: if (unblank) OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN), @@ -993,14 +1062,14 @@ rinfo->init_state.lvds_gen_cntl |= target_val & LVDS_STATE_MASK; if (mode_switch) { - radeon_msleep(rinfo->panel_info.pwr_delay); + radeon_msleep(rinfo->mon[id].panel_info.pwr_delay); OUTREG(LVDS_GEN_CNTL, target_val); } else { rinfo->pending_lvds_gen_cntl = target_val; mod_timer(&rinfo->lvds_timer, jiffies + - msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + msecs_to_jiffies(rinfo->mon[id].panel_info.pwr_delay)); } } } else { @@ -1026,7 +1095,7 @@ rinfo->pending_lvds_gen_cntl = val; mod_timer(&rinfo->lvds_timer, jiffies + - msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + msecs_to_jiffies(rinfo->mon[id].panel_info.pwr_delay)); rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK; if (rinfo->is_mobility || rinfo->is_IGP) @@ -1045,11 +1114,17 @@ static int radeonfb_blank (int blank, struct fb_info *info) { struct radeonfb_info *rinfo = info->par; + int id; + if (rinfo->asleep) return 0; - return radeon_screen_blank(rinfo, blank, 0); + for ( id = 0; id < RADEON_MAX_MONITORS; id++) { + radeon_screen_blank(rinfo, blank, 0, id); + } + + return 0; } static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, @@ -1103,6 +1178,7 @@ (green << 8) | blue); } } + if (regno < 16) { u32 *pal = rinfo->info->pseudo_palette; switch (rinfo->depth) { @@ -1121,6 +1197,7 @@ break; } } + return 0; } @@ -1361,7 +1438,7 @@ return; if (!regs_only) - radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0); + radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0, 0); radeon_fifo_wait(31); for (i=0; i<10; i++) @@ -1404,7 +1481,7 @@ } if (!regs_only) - radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0); + radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0, 0); radeon_fifo_wait(2); OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); @@ -1552,6 +1629,7 @@ int primary_mon = PRIMARY_MONITOR(rinfo); int depth = var_to_depth(mode); int use_rmx = 0; + int id=0; newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); if (!newmode) @@ -1576,29 +1654,29 @@ v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; if (primary_mon == MT_DFP || primary_mon == MT_LCD) { - if (rinfo->panel_info.xres < mode->xres) - mode->xres = rinfo->panel_info.xres; - if (rinfo->panel_info.yres < mode->yres) - mode->yres = rinfo->panel_info.yres; + if (rinfo->mon[id].panel_info.xres < mode->xres) + mode->xres = rinfo->mon[id].panel_info.xres; + if (rinfo->mon[id].panel_info.yres < mode->yres) + mode->yres = rinfo->mon[id].panel_info.yres; - hTotal = mode->xres + rinfo->panel_info.hblank; - hSyncStart = mode->xres + rinfo->panel_info.hOver_plus; - hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width; + hTotal = mode->xres + rinfo->mon[id].panel_info.hblank; + hSyncStart = mode->xres + rinfo->mon[id].panel_info.hOver_plus; + hSyncEnd = hSyncStart + rinfo->mon[id].panel_info.hSync_width; - vTotal = mode->yres + rinfo->panel_info.vblank; - vSyncStart = mode->yres + rinfo->panel_info.vOver_plus; - vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width; + vTotal = mode->yres + rinfo->mon[id].panel_info.vblank; + vSyncStart = mode->yres + rinfo->mon[id].panel_info.vOver_plus; + vSyncEnd = vSyncStart + rinfo->mon[id].panel_info.vSync_width; - h_sync_pol = !rinfo->panel_info.hAct_high; - v_sync_pol = !rinfo->panel_info.vAct_high; + h_sync_pol = !rinfo->mon[id].panel_info.hAct_high; + v_sync_pol = !rinfo->mon[id].panel_info.vAct_high; - pixClock = 100000000 / rinfo->panel_info.clock; + pixClock = 100000000 / rinfo->mon[id].panel_info.clock; - if (rinfo->panel_info.use_bios_dividers) { + if (rinfo->mon[id].panel_info.use_bios_dividers && !force_pll_calc) { nopllcalc = 1; - newmode->ppll_div_3 = rinfo->panel_info.fbk_divider | - (rinfo->panel_info.post_divider << 16); - newmode->ppll_ref_div = rinfo->panel_info.ref_divider; + newmode->ppll_div_3 = rinfo->mon[id].panel_info.fbk_divider | + (rinfo->mon[id].panel_info.post_divider << 16); + newmode->ppll_ref_div = rinfo->mon[id].panel_info.ref_divider; } } dotClock = 1000000000 / pixClock; @@ -1738,19 +1816,19 @@ if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { unsigned int hRatio, vRatio; - if (mode->xres > rinfo->panel_info.xres) - mode->xres = rinfo->panel_info.xres; - if (mode->yres > rinfo->panel_info.yres) - mode->yres = rinfo->panel_info.yres; + if (mode->xres > rinfo->mon[0].panel_info.xres) + mode->xres = rinfo->mon[0].panel_info.xres; + if (mode->yres > rinfo->mon[0].panel_info.yres) + mode->yres = rinfo->mon[0].panel_info.yres; - newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) + newmode->fp_horz_stretch = (((rinfo->mon[0].panel_info.xres / 8) - 1) << HORZ_PANEL_SHIFT); - newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1) + newmode->fp_vert_stretch = ((rinfo->mon[0].panel_info.yres - 1) << VERT_PANEL_SHIFT); - if (mode->xres != rinfo->panel_info.xres) { + if (mode->xres != rinfo->mon[0].panel_info.xres) { hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, - rinfo->panel_info.xres); + rinfo->mon[0].panel_info.xres); newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | (newmode->fp_horz_stretch & (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | @@ -1761,9 +1839,9 @@ } newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO; - if (mode->yres != rinfo->panel_info.yres) { + if (mode->yres != rinfo->mon[0].panel_info.yres) { vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, - rinfo->panel_info.yres); + rinfo->mon[0].panel_info.yres); newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | (newmode->fp_vert_stretch & (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); @@ -1818,13 +1896,13 @@ newmode->crtc_ext_cntl &= ~CRTC_CRT_ON; } - newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) | + newmode->fp_crtc_h_total_disp = (((rinfo->mon[0].panel_info.hblank / 8) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); - newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) | + newmode->fp_crtc_v_total_disp = (rinfo->mon[0].panel_info.vblank & 0xffff) | ((mode->yres - 1) << 16); - newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) | + newmode->fp_h_sync_strt_wid = ((rinfo->mon[0].panel_info.hOver_plus & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23)); - newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) | + newmode->fp_v_sync_strt_wid = ((rinfo->mon[0].panel_info.vOver_plus & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); } @@ -1874,7 +1952,9 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) { - struct fb_info *info = rinfo->info; + struct fb_info *info; + + info = rinfo->info; info->par = rinfo; info->pseudo_palette = rinfo->pseudo_palette; @@ -1897,7 +1977,7 @@ info->fix.ywrapstep = 0; info->fix.type_aux = 0; info->fix.mmio_start = rinfo->mmio_base_phys; - info->fix.mmio_len = RADEON_REGSIZE; + info->fix.mmio_len = rinfo->mmio_len; info->fix.accel = FB_ACCEL_ATI_RADEON; fb_alloc_cmap(&info->cmap, 256, 0); @@ -1905,6 +1985,7 @@ if (noaccel) info->flags |= FBINFO_HWACCEL_DISABLED; + return 0; } @@ -2085,7 +2166,7 @@ * ToDo: identify these cases */ - pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", + pr_info("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", pci_name(rinfo->pdev), rinfo->video_ram / 1024, rinfo->vram_ddr ? "DDR" : "SDRAM", @@ -2111,7 +2192,7 @@ struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; - return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID); + return radeon_show_one_edid(buf, off, count, rinfo->mon[0].EDID); } @@ -2124,25 +2205,26 @@ struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; - return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID); + return radeon_show_one_edid(buf, off, count, rinfo->mon[1].EDID); } -static struct bin_attribute edid1_attr = { +static struct bin_attribute edid_attr[] = { + { .attr = { .name = "edid1", .mode = 0444, }, .size = EDID_LENGTH, .read = radeon_show_edid1, -}; - -static struct bin_attribute edid2_attr = { + }, + { .attr = { .name = "edid2", .mode = 0444, }, .size = EDID_LENGTH, .read = radeon_show_edid2, + } }; @@ -2154,6 +2236,7 @@ int ret; unsigned char c1, c2; int err = 0; + int id; pr_debug("radeonfb_pci_register BEGIN\n"); @@ -2190,6 +2273,8 @@ snprintf(rinfo->name, sizeof(rinfo->name), "ATI Radeon %x", ent->device & 0xffff); + pr_info("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); + rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; rinfo->chipset = pdev->device; rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; @@ -2199,26 +2284,30 @@ /* Set base addrs */ rinfo->fb_base_phys = pci_resource_start (pdev, 0); rinfo->mmio_base_phys = pci_resource_start (pdev, 2); + rinfo->mmio_len = pci_resource_len(pdev, 2); + + pr_info("radeonfb: MMIO registers at 0x%016lx: size %dKB\n", + (long unsigned int) rinfo->mmio_base_phys, rinfo->mmio_len / 1024); /* request the mem regions */ ret = pci_request_region(pdev, 0, "radeonfb framebuffer"); if (ret < 0) { - printk( KERN_ERR "radeonfb (%s): cannot request region 0.\n", + pr_err("radeonfb (%s): cannot request region 0.\n", pci_name(rinfo->pdev)); goto err_release_fb; } ret = pci_request_region(pdev, 2, "radeonfb mmio"); if (ret < 0) { - printk( KERN_ERR "radeonfb (%s): cannot request region 2.\n", + pr_err("radeonfb (%s): cannot request region 2.\n", pci_name(rinfo->pdev)); goto err_release_pci0; } /* map the regions */ - rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); + rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, rinfo->mmio_len); if (!rinfo->mmio_base) { - printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", + pr_err("radeonfb (%s): cannot map MMIO\n", pci_name(rinfo->pdev)); ret = -EIO; goto err_release_pci2; @@ -2250,7 +2339,7 @@ */ rinfo->of_node = pci_device_to_OF_node(pdev); if (rinfo->of_node == NULL) - printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n", + pr_warning("radeonfb (%s): Cannot match card to OF node !\n", pci_name(rinfo->pdev)); #endif /* CONFIG_PPC_OF || CONFIG_SPARC */ @@ -2274,13 +2363,13 @@ ((rinfo->mapped_vram /= 2) >= MIN_MAPPED_VRAM)); if (rinfo->fb_base == NULL) { - printk (KERN_ERR "radeonfb (%s): cannot map FB\n", + pr_err("radeonfb (%s): cannot map FB\n", pci_name(rinfo->pdev)); ret = -EIO; goto err_unmap_rom; } - pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), + pr_info("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), rinfo->mapped_vram/1024); /* @@ -2314,6 +2403,9 @@ 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); @@ -2326,21 +2418,51 @@ radeon_set_fbinfo (rinfo); /* Probe screen types */ - radeon_probe_screens(rinfo, monitor_layout, ignore_edid); + radeon_probe_screens(rinfo, table_layout, monitor_layout, ignore_edid); + + if (mode_option) { + char *ptr; + int cnt = 0; + ptr = mode_option; + pr_debug("radeonfb: mode_option=%s\n", ptr); + do { + switch(*ptr) { + case ',': + monitor_mode[1] = (char *) (ptr + 1); + *ptr = '\0'; + break; + case ' ': + case '\0': + break; + default: + cnt++; + + } + } while (*ptr++); + monitor_mode[0] = (cnt < 6) ? NULL: mode_option; + } /* Build mode list, check out panel native model */ - radeon_check_modes(rinfo, mode_option); + for ( id = 0; id < RADEON_MAX_MONITORS; id++) { + pr_info("radeonfb: Check mode for output %d\n", id); + radeon_check_modes(rinfo, monitor_mode[id], id); + /* we need to implement something like matrox_dh_fb_info... + * also better stop here... + */ + break; + } /* Register some sysfs stuff (should be done better) */ - if (rinfo->mon1_EDID) - err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj, - &edid1_attr); - if (rinfo->mon2_EDID) - err |= sysfs_create_bin_file(&rinfo->pdev->dev.kobj, - &edid2_attr); - if (err) - pr_warning("%s() Creating sysfs files failed, continuing\n", - __func__); + if (rinfo->mon[0].EDID) { + ret = sysfs_create_bin_file(&rinfo->pdev->dev.kobj,&edid_attr[0]); + if (ret) + goto err_unmap_fb; + } + if (rinfo->mon[1].EDID) { + ret = sysfs_create_bin_file(&rinfo->pdev->dev.kobj,&edid_attr[1]); + if (ret) + goto err_free_mon1; + } /* save current mode regs before we switch into the new one * so we can restore this upon __exit @@ -2357,16 +2479,20 @@ } else radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep); - pci_set_drvdata(pdev, info); + //pci_set_drvdata(pdev, info); /* Register with fbdev layer */ ret = register_framebuffer(info); if (ret < 0) { - printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n", + pr_err("radeonfb (%s): could not register framebuffer\n", pci_name(rinfo->pdev)); - goto err_unmap_fb; + goto err_free_mon2; } + pr_info("radeonfb%d: %s frame buffer device\n", info->node, info->fix.id); + + pci_set_drvdata(pdev, info); + #ifdef CONFIG_MTRR rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys, rinfo->video_ram, @@ -2374,22 +2500,28 @@ #endif if (backlight) - radeonfb_bl_init(rinfo); - - printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); + radeonfb_bl_init(rinfo, id); if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); + pr_debug("radeonfb_pci_register END\n"); return 0; + +err_free_mon2: + if (rinfo->mon[1].EDID) + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid_attr[1]); +err_free_mon1: + if (rinfo->mon[0].EDID) + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid_attr[0]); err_unmap_fb: iounmap(rinfo->fb_base); err_unmap_rom: - kfree(rinfo->mon1_EDID); - kfree(rinfo->mon2_EDID); - if (rinfo->mon1_modedb) - fb_destroy_modedb(rinfo->mon1_modedb); + kfree(rinfo->mon[0].EDID); + kfree(rinfo->mon[1].EDID); + if (rinfo->mon[0].modedb) + fb_destroy_modedb(rinfo->mon[0].modedb); fb_dealloc_cmap(&info->cmap); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); @@ -2420,20 +2552,10 @@ radeonfb_pm_exit(rinfo); - if (rinfo->mon1_EDID) - sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr); - if (rinfo->mon2_EDID) - sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr); - -#if 0 - /* restore original state - * - * Doesn't quite work yet, I suspect if we come from a legacy - * VGA mode (or worse, text mode), we need to do some VGA black - * magic here that I know nothing about. --BenH - */ - radeon_write_mode (rinfo, &rinfo->init_state, 1); - #endif + if (rinfo->mon[0].EDID) + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid_attr[0]); + if (rinfo->mon[1].EDID) + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid_attr[1]); del_timer_sync(&rinfo->lvds_timer); @@ -2444,7 +2566,9 @@ unregister_framebuffer(info); - radeonfb_bl_exit(rinfo); + radeonfb_bl_exit(rinfo, 0); + + radeonfb_bl_exit(rinfo, 1); iounmap(rinfo->mmio_base); iounmap(rinfo->fb_base); @@ -2452,10 +2576,12 @@ pci_release_region(pdev, 2); pci_release_region(pdev, 0); - kfree(rinfo->mon1_EDID); - kfree(rinfo->mon2_EDID); - if (rinfo->mon1_modedb) - fb_destroy_modedb(rinfo->mon1_modedb); + kfree(rinfo->mon[0].EDID); + kfree(rinfo->mon[1].EDID); + if (rinfo->mon[0].modedb) + fb_destroy_modedb(rinfo->mon[0].modedb); + if (rinfo->mon[1].modedb) + fb_destroy_modedb(rinfo->mon[1].modedb); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif @@ -2505,8 +2631,12 @@ nomodeset = 1; } else if (!strncmp(this_opt, "force_measure_pll", 17)) { force_measure_pll = 1; + } else if (!strncmp(this_opt, "force_pll_calc", 17)) { + force_pll_calc = 1; } else if (!strncmp(this_opt, "ignore_edid", 11)) { ignore_edid = 1; + } else if (!strncmp(this_opt, "table_layout:", 13)) { + table_layout = simple_strtoul((this_opt+13), NULL, 0); #if defined(CONFIG_PM) && defined(CONFIG_X86) } else if (!strncmp(this_opt, "force_sleep", 11)) { force_sleep = 1; @@ -2558,8 +2688,12 @@ MODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe"); module_param(monitor_layout, charp, 0); MODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)"); +module_param(table_layout, charp, 0); +MODULE_PARM_DESC(table_layout, "Specify table mapping (x,x,x,x,y,y,y,y)"); module_param(force_measure_pll, bool, 0); MODULE_PARM_DESC(force_measure_pll, "Force measurement of PLL (debug)"); +module_param(force_pll_calc, bool, 0400); +MODULE_PARM_DESC(force_pll_calc, "Force calculation of PLL"); #ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); @@ -2567,7 +2701,7 @@ module_param(panel_yres, int, 0); MODULE_PARM_DESC(panel_yres, "int: set panel yres"); module_param(mode_option, charp, 0); -MODULE_PARM_DESC(mode_option, "Specify resolution as \"x[-][@]\" "); +MODULE_PARM_DESC(mode_option, "Specify resolution as \"x[-][@][,...]\" "); #if defined(CONFIG_PM) && defined(CONFIG_X86) module_param(force_sleep, bool, 0); MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware"); --- ./drivers/video/aty/radeon_pm.c.orig 2008-07-13 23:51:29.000000000 +0200 +++ ./drivers/video/aty/radeon_pm.c 2008-09-23 11:54:30.000000000 +0200 @@ -101,7 +101,7 @@ (id->subsystem_device == rinfo->pdev->subsystem_device )) { /* we found a device that requires workaround */ - printk(KERN_DEBUG "radeonfb: %s detected" + pr_debug("radeonfb: %s detected" ", enabling workaround\n", id->ident); rinfo->pm_mode |= id->pm_mode_modifier; @@ -1442,7 +1442,7 @@ i = 0; j++; if (j > 10) { - printk(KERN_WARNING "radeon: PAD_CTLR_STRENGTH doesn't " + pr_warning("radeon: PAD_CTLR_STRENGTH doesn't " "stabilize !\n"); break; } @@ -2521,7 +2521,7 @@ * including PCI config registers, clocks, AGP conf, ...) */ if (suspend) { - printk(KERN_DEBUG "radeonfb (%s): switching to D2 state...\n", + pr_debug("radeonfb (%s): switching to D2 state...\n", pci_name(rinfo->pdev)); /* Disable dynamic power management of clocks for the @@ -2575,7 +2575,7 @@ mdelay(500); } } else { - printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n", + pr_debug("radeonfb (%s): switching to D0 state...\n", pci_name(rinfo->pdev)); /* Switch back PCI powermanagment to D0 */ @@ -2629,11 +2629,12 @@ struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; int i; + int id; if (mesg.event == pdev->dev.power.power_state.event) return 0; - printk(KERN_DEBUG "radeonfb (%s): suspending for event: %d...\n", + pr_debug("radeonfb (%s): suspending for event: %d...\n", pci_name(pdev), mesg.event); /* For suspend-to-disk, we cheat here. We don't suspend anything and @@ -2659,7 +2660,8 @@ } /* Blank display and LCD */ - radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1); + for ( id = 0; id < RADEON_MAX_MONITORS; id++ ) + radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1, id); /* Sleep */ rinfo->asleep = 1; @@ -2722,6 +2724,7 @@ struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; int rc = 0; + int id; if (pdev->dev.power.power_state.event == PM_EVENT_ON) return 0; @@ -2732,13 +2735,13 @@ } else acquire_console_sem(); - printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n", + pr_debug("radeonfb (%s): resuming from state: %d...\n", pci_name(pdev), pdev->dev.power.power_state.event); if (pci_enable_device(pdev)) { rc = -ENODEV; - printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n", + pr_err("radeonfb (%s): can't enable PCI device !\n", pci_name(pdev)); goto bail; } @@ -2752,7 +2755,7 @@ if (rinfo->reinit_func != NULL) rinfo->reinit_func(rinfo); else { - printk(KERN_ERR "radeonfb (%s): can't resume radeon from" + pr_err("radeonfb (%s): can't resume radeon from" " D3 cold, need softboot !", pci_name(pdev)); rc = -EIO; goto bail; @@ -2782,7 +2785,8 @@ /* Unblank */ rinfo->lock_blank = 0; - radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1); + for ( id = 0; id < RADEON_MAX_MONITORS; id++ ) + radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1, id); #ifdef CONFIG_PPC_PMAC /* On powermac, we have hooks to properly suspend/resume AGP now, @@ -2833,10 +2837,10 @@ if (rinfo->dynclk == 1) { radeon_pm_enable_dynamic_mode(rinfo); - printk("radeonfb: Dynamic Clock Power Management enabled\n"); + pr_info("radeonfb: Dynamic Clock Power Management enabled\n"); } else if (rinfo->dynclk == 0) { radeon_pm_disable_dynamic_mode(rinfo); - printk("radeonfb: Dynamic Clock Power Management disabled\n"); + pr_info("radeonfb: Dynamic Clock Power Management disabled\n"); } #if defined(CONFIG_PM) @@ -2894,14 +2898,12 @@ #endif /* defined(CONFIG_PM) */ if (ignore_devlist) - printk(KERN_DEBUG - "radeonfb: skipping test for device workarounds\n"); + pr_debug("radeonfb: skipping test for device workarounds\n"); else radeon_apply_workarounds(rinfo); if (force_sleep) { - printk(KERN_DEBUG - "radeonfb: forcefully enabling D2 sleep mode\n"); + pr_debug("radeonfb: forcefully enabling D2 sleep mode\n"); rinfo->pm_mode |= radeon_pm_d2; } } --- ./drivers/video/aty/radeonfb.h.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/aty/radeonfb.h 2008-09-23 11:54:30.000000000 +0200 @@ -3,6 +3,9 @@ #ifdef CONFIG_FB_RADEON_DEBUG #define DEBUG 1 + +#define DBG(x) pr_debug("radeonfb: %s\n", (x)); + #endif #include @@ -53,7 +56,7 @@ CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ CHIP_FAMILY_R420, /* R420/R423/M18 */ CHIP_FAMILY_RC410, - CHIP_FAMILY_RS480, + CHIP_FAMILY_RS480, /* RS480/RS482 */ CHIP_FAMILY_LAST, }; @@ -71,7 +74,6 @@ ((rinfo)->family == CHIP_FAMILY_R350) || \ ((rinfo)->family == CHIP_FAMILY_RV380) || \ ((rinfo)->family == CHIP_FAMILY_R420) || \ - ((rinfo)->family == CHIP_FAMILY_RC410) || \ ((rinfo)->family == CHIP_FAMILY_RS480)) /* @@ -116,15 +118,17 @@ ddc_dvi, ddc_vga, ddc_crt2, + ddc_lcd, + ddc_gpio, }; /* * Connector types */ enum conn_type { - conn_none, - conn_proprietary, - conn_crt, + conn_NONE, + conn_PROPRIETARY, + conn_CRT, conn_DVI_I, conn_DVI_D, }; @@ -283,6 +287,57 @@ typedef void (*reinit_function_ptr)(struct radeonfb_info *rinfo); +#define RADEON_MAX_BIOS_CONNECTORS 8 + +enum radeon_conn_type_atom { + conn_none, + conn_vga, + conn_dvi_i, + conn_dvi_d, + conn_dvi_a, + conn_stv, + conn_ctv, + conn_lvds, + conn_digital, + conn_unsupported, +}; + +#define radeon_ddc_type_atom ddc_type + +enum radeon_dac_type_atom { + dac_unknown = -1, + dac_primary = 0, + dac_tvdac = 1, + dac_none = 2, +}; + +enum radeon_tmds_type_atom { + tmds_unknown = -1, + tmds_internal = 0, + tmds_external = 1, + tmds_none = 2, +}; + +struct bios_connector { + enum radeon_conn_type_atom conn_type; + enum radeon_ddc_type_atom ddc_type; + enum radeon_dac_type_atom dac_type; + enum radeon_tmds_type_atom tmds_type; + bool valid; +}; + +#define RADEON_MAX_MONITORS 2 + +struct monitor_info { + struct panel_info panel_info; + int type; + u8 *EDID; + struct fb_videomode *modedb; + int dbsize; + bool connected; + struct bios_connector *connector; +}; + struct radeonfb_info { struct fb_info *info; @@ -292,6 +347,7 @@ char name[50]; unsigned long mmio_base_phys; + u32 mmio_len; unsigned long fb_base_phys; void __iomem *mmio_base; @@ -306,10 +362,14 @@ void __iomem *bios_seg; int fp_bios_start; + int is_atom_bios; + int atom_data_start; + + struct bios_connector bios_connector[RADEON_MAX_BIOS_CONNECTORS]; + int tvdac_use_count; u32 pseudo_palette[16]; - struct { u8 red, green, blue, pad; } - palette[256]; + struct { u8 red, green, blue, pad; } palette[256]; int chipset; u8 family; @@ -327,13 +387,7 @@ int is_IGP; int reversed_DAC; int reversed_TMDS; - struct panel_info panel_info; - int mon1_type; - u8 *mon1_EDID; - struct fb_videomode *mon1_modedb; - int mon1_dbsize; - int mon2_type; - u8 *mon2_EDID; + struct monitor_info mon[RADEON_MAX_MONITORS]; u32 dp_gui_master_cntl; @@ -365,7 +419,7 @@ }; -#define PRIMARY_MONITOR(rinfo) (rinfo->mon1_type) +#define PRIMARY_MONITOR(rinfo) (rinfo->mon[0].type) /* @@ -599,11 +653,12 @@ /* Monitor probe functions */ extern void radeon_probe_screens(struct radeonfb_info *rinfo, + const char *table_layout, const char *monitor_layout, int ignore_edid); -extern void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option); +extern void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option, int id); extern int radeon_match_mode(struct radeonfb_info *rinfo, struct fb_var_screeninfo *dest, - const struct fb_var_screeninfo *src); + const struct fb_var_screeninfo *src, int id); /* Accel functions */ extern void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region); @@ -614,17 +669,17 @@ extern void radeonfb_engine_reset(struct radeonfb_info *rinfo); /* Other functions */ -extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch); +extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch, int id); extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, int reg_only); /* Backlight functions */ #ifdef CONFIG_FB_RADEON_BACKLIGHT -extern void radeonfb_bl_init(struct radeonfb_info *rinfo); -extern void radeonfb_bl_exit(struct radeonfb_info *rinfo); +extern void radeonfb_bl_init(struct radeonfb_info *rinfo, int id); +extern void radeonfb_bl_exit(struct radeonfb_info *rinfo, int id); #else -static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {} -static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {} +static inline void radeonfb_bl_init(struct radeonfb_info *rinfo, int id) {} +static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo, int id) {} #endif #endif /* __RADEONFB_H__ */ --- ./drivers/video/aty/radeon_monitor.c.orig 2008-07-13 23:51:29.000000000 +0200 +++ ./drivers/video/aty/radeon_monitor.c 2008-09-23 11:54:30.000000000 +0200 @@ -29,7 +29,7 @@ switch (type) { case MT_NONE: - pret = "no"; + pret = "not"; break; case MT_CRT: pret = "CRT"; @@ -69,11 +69,11 @@ u8 *tmp; int i, mt = MT_NONE; - pr_debug("analyzing OF properties...\n"); + pr_info("analyzing OF properties...\n"); pmt = of_get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; - pr_debug("display-type: %s\n", pmt); + pr_info("display-type: %s\n", pmt); /* OF says "LCD" for DFP as well, we discriminate from the caller of this * function */ @@ -83,7 +83,7 @@ mt = MT_CRT; else { if (strcmp(pmt, "NONE") != 0) - printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", + pr_info("radeonfb: Unknown OF display-type: %s\n", pmt); return MT_NONE; } @@ -160,7 +160,7 @@ #endif /* CONFIG_PPC_OF || CONFIG_SPARC */ -static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) +static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo, int id) { unsigned long tmp, tmp0; char stmp[30]; @@ -170,76 +170,76 @@ return 0; if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) { - printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n"); - rinfo->panel_info.pwr_delay = 200; + pr_warning("radeonfb: Failed to detect DFP panel info using BIOS\n"); + rinfo->mon[id].panel_info.pwr_delay = 200; return 0; } for(i=0; i<24; i++) stmp[i] = BIOS_IN8(tmp+i+1); stmp[24] = 0; - printk("radeonfb: panel ID string: %s\n", stmp); - 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.pwr_delay = BIOS_IN16(tmp + 44); - pr_debug("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; + pr_info("radeonfb: panel ID string: %s\n", stmp); + rinfo->mon[id].panel_info.xres = BIOS_IN16(tmp + 25); + rinfo->mon[id].panel_info.yres = BIOS_IN16(tmp + 27); + pr_info("radeonfb: detected LVDS panel size from BIOS: %dx%d\n", + rinfo->mon[id].panel_info.xres, rinfo->mon[id].panel_info.yres); + + rinfo->mon[id].panel_info.pwr_delay = BIOS_IN16(tmp + 44); + pr_info("BIOS provided panel power delay: %d\n", rinfo->mon[id].panel_info.pwr_delay); + if (rinfo->mon[id].panel_info.pwr_delay > 2000 || rinfo->mon[id].panel_info.pwr_delay <= 0) + rinfo->mon[id].panel_info.pwr_delay = 2000; /* * Some panels only work properly with some divider combinations */ - rinfo->panel_info.ref_divider = BIOS_IN16(tmp + 46); - rinfo->panel_info.post_divider = BIOS_IN8(tmp + 48); - rinfo->panel_info.fbk_divider = BIOS_IN16(tmp + 49); - if (rinfo->panel_info.ref_divider != 0 && - rinfo->panel_info.fbk_divider > 3) { - rinfo->panel_info.use_bios_dividers = 1; - printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n"); - pr_debug("ref_divider = %x\n", rinfo->panel_info.ref_divider); - pr_debug("post_divider = %x\n", rinfo->panel_info.post_divider); - pr_debug("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); + rinfo->mon[id].panel_info.ref_divider = BIOS_IN16(tmp + 46); + rinfo->mon[id].panel_info.post_divider = BIOS_IN8(tmp + 48); + rinfo->mon[id].panel_info.fbk_divider = BIOS_IN16(tmp + 49); + if (rinfo->mon[id].panel_info.ref_divider != 0 && + rinfo->mon[id].panel_info.fbk_divider > 3) { + rinfo->mon[id].panel_info.use_bios_dividers = 1; + pr_info("radeondb: BIOS provided dividers will be used\n"); + pr_debug("ref_divider = %x\n", rinfo->mon[id].panel_info.ref_divider); + pr_debug("post_divider = %x\n", rinfo->mon[id].panel_info.post_divider); + pr_debug("fbk_divider = %x\n", rinfo->mon[id].panel_info.fbk_divider); } - pr_debug("Scanning BIOS table ...\n"); + pr_info("Scanning BIOS table ...\n"); for(i=0; i<32; i++) { tmp0 = BIOS_IN16(tmp+64+i*2); if (tmp0 == 0) break; pr_debug(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); - if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) && - (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) { - rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; - rinfo->panel_info.hOver_plus = ((BIOS_IN16(tmp0+21) - + if ((BIOS_IN16(tmp0) == rinfo->mon[id].panel_info.xres) && + (BIOS_IN16(tmp0+2) == rinfo->mon[id].panel_info.yres)) { + rinfo->mon[id].panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; + rinfo->mon[id].panel_info.hOver_plus = ((BIOS_IN16(tmp0+21) - BIOS_IN16(tmp0+19) -1) * 8) & 0x7fff; - rinfo->panel_info.hSync_width = BIOS_IN8(tmp0+23) * 8; - rinfo->panel_info.vblank = BIOS_IN16(tmp0+24) - BIOS_IN16(tmp0+26); - rinfo->panel_info.vOver_plus = (BIOS_IN16(tmp0+28) & 0x7ff) - BIOS_IN16(tmp0+26); - rinfo->panel_info.vSync_width = (BIOS_IN16(tmp0+28) & 0xf800) >> 11; - rinfo->panel_info.clock = BIOS_IN16(tmp0+9); + rinfo->mon[id].panel_info.hSync_width = BIOS_IN8(tmp0+23) * 8; + rinfo->mon[id].panel_info.vblank = BIOS_IN16(tmp0+24) - BIOS_IN16(tmp0+26); + rinfo->mon[id].panel_info.vOver_plus = (BIOS_IN16(tmp0+28) & 0x7ff) - BIOS_IN16(tmp0+26); + rinfo->mon[id].panel_info.vSync_width = (BIOS_IN16(tmp0+28) & 0xf800) >> 11; + rinfo->mon[id].panel_info.clock = BIOS_IN16(tmp0+9); /* 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; + rinfo->mon[id].panel_info.hAct_high = 1; + rinfo->mon[id].panel_info.vAct_high = 1; /* Mark panel infos valid */ - rinfo->panel_info.valid = 1; + rinfo->mon[id].panel_info.valid = 1; pr_debug("Found panel in BIOS table:\n"); - pr_debug(" hblank: %d\n", rinfo->panel_info.hblank); - pr_debug(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); - pr_debug(" hSync_width: %d\n", rinfo->panel_info.hSync_width); - pr_debug(" vblank: %d\n", rinfo->panel_info.vblank); - pr_debug(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); - pr_debug(" vSync_width: %d\n", rinfo->panel_info.vSync_width); - pr_debug(" clock: %d\n", rinfo->panel_info.clock); + pr_debug(" hblank: %d\n", rinfo->mon[id].panel_info.hblank); + pr_debug(" hOver_plus: %d\n", rinfo->mon[id].panel_info.hOver_plus); + pr_debug(" hSync_width: %d\n", rinfo->mon[id].panel_info.hSync_width); + pr_debug(" vblank: %d\n", rinfo->mon[id].panel_info.vblank); + pr_debug(" vOver_plus: %d\n", rinfo->mon[id].panel_info.vOver_plus); + pr_debug(" vSync_width: %d\n", rinfo->mon[id].panel_info.vSync_width); + pr_debug(" clock: %d\n", rinfo->mon[id].panel_info.clock); return 1; } } - pr_debug("Didn't find panel in BIOS table !\n"); + pr_warning("Didn't find panel in BIOS table !\n"); return 0; } @@ -263,7 +263,7 @@ offset = BIOS_IN16(rinfo->fp_bios_start + 0x50); if (offset == 0) { - printk(KERN_WARNING "radeonfb: No connector info table detected\n"); + pr_info("radeonfb: No connector info table detected\n"); return; } @@ -271,23 +271,212 @@ * DEBUG is enabled */ chips = BIOS_IN8(offset++) >> 4; - pr_debug("%d chips in connector info\n", chips); + pr_info("%d chips in connector info\n", chips); for (i = 0; i < chips; i++) { tmp = BIOS_IN8(offset++); connectors = tmp & 0x0f; - pr_debug(" - chip %d has %d connectors\n", tmp >> 4, connectors); + pr_info(" - chip %d has %d connectors\n", tmp >> 4, connectors); for (conn = 0; ; conn++) { tmp = BIOS_IN16(offset); if (tmp == 0) break; offset += 2; type = (tmp >> 12) & 0x0f; - pr_debug(" * connector %d of type %d (%s) : %04x\n", + pr_info(" * connector %d of type %d (%s) : %04x\n", conn, type, __conn_type_table[type], tmp); } } } +const char *MonTypeName[7] = { + "AUTO", + "NONE", + "CRT", + "LVDS", + "TMDS", + "CTV", + "STV" +}; + +const char *TMDSTypeName[4] = { + "Unknown", + "Internal", + "External", + "None" +}; + +const char *DDCTypeName[7] = { + "None", + "MONID", + "DVI_DDC", + "VGA_DDC", + "CRT2_DDC", + "LCD_DDC", + "GPIO_DDC" +}; + +const char *DACTypeName[4] = { + "Unknown", + "Primary", + "TVDAC/ExtDAC", + "None" +}; + +const char *ConnectorTypeName[8] = { + "None", + "Proprietary/LVDS", + "VGA", + "DVI-I", + "DVI-D", + "CTV", + "STV", + "Unsupported" +}; + +const char *ConnectorTypeNameATOM[10] = { + "None", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "STV", + "CTV", + "LVDS", + "Digital", + "Unsupported" +}; + +static void __devinit radeon_print_port_map(struct radeonfb_info *rinfo) +{ + struct bios_connector *conn; + int i, m; + int mon_type; + + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + conn = &(rinfo->bios_connector[i]); + if (conn->valid) { + mon_type = 0; + for ( m=0; m < RADEON_MAX_MONITORS; m++) { + if ( rinfo->mon[m].connector == conn ) { + mon_type = rinfo->mon[m].type + 1; + break; + } + } + pr_info("Port%d:\n Monitor -- %s\n Connector -- %s\n DAC Type -- %s\n TMDS Type -- %s\n DDC Type -- %s\n", + i, + MonTypeName[mon_type], + rinfo->is_atom_bios ? + ConnectorTypeNameATOM[conn->conn_type]: + ConnectorTypeName[conn->conn_type], + DACTypeName[conn->dac_type+1], + TMDSTypeName[conn->tmds_type+1], + DDCTypeName[conn->ddc_type]); + } + } + +} + +#define GPIO_LCD_MASK 0x01a0 +#define MDGPIO_EN_REG 0x01b0 + +int __devinit radeon_get_conn_info_atom(struct radeonfb_info *rinfo) +{ + int i, offset, tmp, tmp0; + u16 portinfo; + int ddc_type, crtc, gpio; + + + offset = BIOS_IN16(rinfo->atom_data_start + 22); + + if (offset) { + tmp = BIOS_IN16(offset + 4); + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if (tmp & (1 << i)) { + rinfo->bios_connector[i].valid = 1; + portinfo = BIOS_IN16(offset + 6 + i * 2); + rinfo->bios_connector[i].dac_type = (portinfo & 0xf) - 1; + rinfo->bios_connector[i].conn_type = (portinfo >> 4) & 0xf; + pr_info(" - chip (%d) has connector type %d\n", portinfo >> 4, (portinfo >> 4) & 0xf); + crtc = (portinfo >> 8) & 0xf; + ddc_type = ddc_none; + tmp0 = BIOS_IN16(rinfo->atom_data_start + 24); + gpio=BIOS_IN16(tmp0 + 4 + 27 * crtc) * 4; + switch(gpio) { + case GPIO_MONID: + rinfo->bios_connector[i].ddc_type = ddc_monid; + break; + case GPIO_DVI_DDC: + rinfo->bios_connector[i].ddc_type = ddc_dvi; + break; + case GPIO_VGA_DDC: + rinfo->bios_connector[i].ddc_type = ddc_vga; + break; + case GPIO_CRT2_DDC: + rinfo->bios_connector[i].ddc_type = ddc_crt2; + break; + case GPIO_LCD_MASK: + rinfo->bios_connector[i].ddc_type = ddc_lcd; + break; + case MDGPIO_EN_REG: + rinfo->bios_connector[i].ddc_type = ddc_gpio; + break; + default: + rinfo->bios_connector[i].ddc_type = ddc_none; + break; + } + + switch(i) { + case 3: + rinfo->bios_connector[i].tmds_type = tmds_internal; + break; + case 7: + rinfo->bios_connector[i].tmds_type = tmds_external; + break; + default: + if (rinfo->bios_connector[i].conn_type == conn_vga) + rinfo->bios_connector[i].tmds_type = tmds_none; + else + rinfo->bios_connector[i].tmds_type = tmds_unknown; + break; + } + } else { + rinfo->bios_connector[i].valid = 0; + } + } + } else { + pr_warning("No Device Info Table found!\n"); + return 0; + } + + pr_info("Bios Connector table:\n"); + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if (rinfo->bios_connector[i].valid) + pr_info("Port%d: ddc_type-%d, dac_type-%d, tmds_type-%d, conn_type-%d\n", + i, rinfo->bios_connector[i].ddc_type, rinfo->bios_connector[i].dac_type, + rinfo->bios_connector[i].tmds_type, rinfo->bios_connector[i].conn_type); + } + + /* DVI-I ports have 2 entries: one for analog, one for digital. combine them */ + if (rinfo->bios_connector[0].valid && rinfo->bios_connector[7].valid) { + rinfo->bios_connector[7].dac_type = rinfo->bios_connector[0].dac_type; + rinfo->bios_connector[0].valid = 0; + } + + if (rinfo->bios_connector[4].valid && rinfo->bios_connector[3].valid) { + rinfo->bios_connector[3].dac_type = rinfo->bios_connector[4].dac_type; + rinfo->bios_connector[4].valid = 0; + } + + pr_info("Bios Connector table (unified):\n"); + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if (rinfo->bios_connector[i].valid) + pr_info("Port%d: ddc_type-%d, dac_type-%d, tmds_type-%d, conn_type-%d\n", + i, rinfo->bios_connector[i].ddc_type, rinfo->bios_connector[i].dac_type, + rinfo->bios_connector[i].tmds_type, rinfo->bios_connector[i].conn_type); + } + + return 1; +} /* * Probe physical connection of a CRT. This code comes from XFree @@ -408,18 +597,18 @@ s2[0] = 0; } if (strcmp(s1, "CRT") == 0) - rinfo->mon1_type = MT_CRT; + rinfo->mon[0].type = MT_CRT; else if (strcmp(s1, "TMDS") == 0) - rinfo->mon1_type = MT_DFP; + rinfo->mon[0].type = MT_DFP; else if (strcmp(s1, "LVDS") == 0) - rinfo->mon1_type = MT_LCD; + rinfo->mon[0].type = MT_LCD; if (strcmp(s2, "CRT") == 0) - rinfo->mon2_type = MT_CRT; + rinfo->mon[1].type = MT_CRT; else if (strcmp(s2, "TMDS") == 0) - rinfo->mon2_type = MT_DFP; + rinfo->mon[1].type = MT_DFP; else if (strcmp(s2, "LVDS") == 0) - rinfo->mon2_type = MT_LCD; + rinfo->mon[1].type = MT_LCD; return 1; } @@ -431,99 +620,112 @@ * driver */ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, + const char *table_layout, const char *monitor_layout, int ignore_edid) { #ifdef CONFIG_FB_RADEON_I2C int ddc_crt2_used = 0; #endif int tmp, i; + int num_vga = 0; + int num_dvi = 0; - radeon_parse_connector_info(rinfo); - - if (radeon_parse_monitor_layout(rinfo, monitor_layout)) { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + rinfo->bios_connector[i].valid = 0; + rinfo->bios_connector[i].ddc_type = ddc_none; + rinfo->bios_connector[i].dac_type = dac_unknown; + rinfo->bios_connector[i].tmds_type = tmds_unknown; + rinfo->bios_connector[i].conn_type = conn_none; + } - /* - * If user specified a monitor_layout option, use it instead - * of auto-detecting. Maybe we should only use this argument - * on the first radeon card probed or provide a way to specify - * a layout for each card ? - */ + if (!rinfo->is_atom_bios) { + radeon_parse_connector_info(rinfo); + } else { + radeon_get_conn_info_atom(rinfo); + //radeon_print_port_map(rinfo); + } - pr_debug("Using specified monitor layout: %s", monitor_layout); -#ifdef CONFIG_FB_RADEON_I2C - if (!ignore_edid) { - if (rinfo->mon1_type != MT_NONE) - if (!radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID)) { - radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID); - ddc_crt2_used = 1; + if (table_layout) { + for (i = 2; i < RADEON_MAX_BIOS_CONNECTORS; i++) + rinfo->bios_connector[i].valid = 0; + + rinfo->bios_connector[0].valid = 1; + rinfo->bios_connector[1].valid = 1; + + if (sscanf(table_layout, "%u,%d,%d,%u,%u,%d,%d,%u", + &rinfo->bios_connector[0].ddc_type, + &rinfo->bios_connector[0].dac_type, + &rinfo->bios_connector[0].tmds_type, + &rinfo->bios_connector[0].conn_type, + &rinfo->bios_connector[1].ddc_type, + &rinfo->bios_connector[1].dac_type, + &rinfo->bios_connector[1].tmds_type, + &rinfo->bios_connector[1].conn_type) != 8) { + pr_err("Invalid ConnectorTable option: %s\n", table_layout); } - if (rinfo->mon2_type != MT_NONE) - if (!radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon2_EDID) && - !ddc_crt2_used) - radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon2_EDID); } -#endif /* CONFIG_FB_RADEON_I2C */ - if (rinfo->mon1_type == MT_NONE) { - if (rinfo->mon2_type != MT_NONE) { - rinfo->mon1_type = rinfo->mon2_type; - rinfo->mon1_EDID = rinfo->mon2_EDID; + + rinfo->tvdac_use_count = 0; + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if (rinfo->bios_connector[i].valid) { + if (rinfo->bios_connector[i].dac_type == dac_tvdac) + rinfo->tvdac_use_count++; + + if (rinfo->is_atom_bios) { + if ((rinfo->bios_connector[i].conn_type == conn_dvi_d) || + (rinfo->bios_connector[i].conn_type == conn_dvi_i) || + (rinfo->bios_connector[i].conn_type == conn_dvi_a)) { + num_dvi++; + } else if (rinfo->bios_connector[i].conn_type == conn_vga) { + num_vga++; + } } else { - rinfo->mon1_type = MT_CRT; - printk(KERN_INFO "radeonfb: No valid monitor, assuming CRT on first port\n"); + if ((rinfo->bios_connector[i].conn_type == conn_DVI_D) || + (rinfo->bios_connector[i].conn_type == conn_DVI_I)) { + num_dvi++; + } else if (rinfo->bios_connector[i].conn_type == conn_CRT) { + num_vga++; } - rinfo->mon2_type = MT_NONE; - rinfo->mon2_EDID = NULL; } - } else { + } + } + /* * Auto-detecting display type (well... trying to ...) */ - pr_debug("Starting monitor auto detection...\n"); + pr_info("Starting monitor auto detection...\n"); -#if defined(DEBUG) && defined(CONFIG_FB_RADEON_I2C) - { - u8 *EDIDs[4] = { NULL, NULL, NULL, NULL }; - int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE}; - int i; - - for (i = 0; i < 4; i++) - mon_types[i] = radeon_probe_i2c_connector(rinfo, - i+1, &EDIDs[i]); - } -#endif /* DEBUG */ /* * Old single head cards */ if (!rinfo->has_CRTC2) { #if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, - &rinfo->mon1_EDID); + if (rinfo->mon[0].type == MT_NONE) + rinfo->mon[0].type = radeon_probe_OF_head(rinfo, 0, + &rinfo->mon[0].EDID); #endif /* CONFIG_PPC_OF || CONFIG_SPARC */ #ifdef CONFIG_FB_RADEON_I2C - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = + if (rinfo->mon[0].type == MT_NONE) + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, ddc_dvi, - &rinfo->mon1_EDID); - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = + &rinfo->mon[0].EDID); + if (rinfo->mon[0].type == MT_NONE) + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, ddc_vga, - &rinfo->mon1_EDID); - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = + &rinfo->mon[0].EDID); + if (rinfo->mon[0].type == MT_NONE) + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, ddc_crt2, - &rinfo->mon1_EDID); + &rinfo->mon[0].EDID); #endif /* CONFIG_FB_RADEON_I2C */ - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = MT_CRT; goto bail; } /* * 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; @@ -531,77 +733,168 @@ if (!BIOS_IN8(tmp + i*2) && i > 1) break; tmp0 = BIOS_IN16(tmp + i*2); - if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) { + if ((!(tmp0 & 0x01)) && ((((tmp0 >> 8) & 0x0f) == ddc_dvi) || (((tmp0 >> 8) & 0x0f) == ddc_monid))) { rinfo->reversed_DAC = 1; - printk(KERN_INFO "radeonfb: Reversed DACs detected\n"); + pr_info("radeonfb: Reversed DACs detected\n"); } - if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) { + if ((((tmp0 >> 8) & 0x0f) == ddc_dvi || (((tmp0 >> 8) & 0x0f) == ddc_monid)) && ((tmp0 >> 4) & 0x01)) { rinfo->reversed_TMDS = 1; - printk(KERN_INFO "radeonfb: Reversed TMDS detected\n"); + pr_info("radeonfb: Reversed TMDS detected\n"); } } } - /* - * Probe primary head (DVI or laptop internal panel) - */ -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, - &rinfo->mon1_EDID); -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ -#ifdef CONFIG_FB_RADEON_I2C - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, - &rinfo->mon1_EDID); - if (rinfo->mon1_type == MT_NONE) { - rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, - &rinfo->mon1_EDID); - if (rinfo->mon1_type != MT_NONE) - ddc_crt2_used = 1; + rinfo->mon[0].type = MT_NONE; + rinfo->mon[1].type = MT_NONE; + + if (rinfo->is_atom_bios) { + if (num_vga) { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if (rinfo->bios_connector[i].conn_type == conn_vga) { + rinfo->mon[0].connector = &rinfo->bios_connector[i]; + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[0].EDID); + break; } -#endif /* CONFIG_FB_RADEON_I2C */ - if (rinfo->mon1_type == MT_NONE && rinfo->is_mobility && + } + } else { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if ((rinfo->bios_connector[i].conn_type == conn_dvi_d) || + (rinfo->bios_connector[i].conn_type == conn_dvi_i) || + (rinfo->bios_connector[i].conn_type == conn_dvi_a)) { + rinfo->mon[0].connector = &rinfo->bios_connector[i]; + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[0].EDID); + break; + } + } + } + + if (num_dvi) { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if ((rinfo->bios_connector[i].conn_type == conn_dvi_d) || + (rinfo->bios_connector[i].conn_type == conn_dvi_i) || + (rinfo->bios_connector[i].conn_type == conn_dvi_a)) { + rinfo->mon[1].connector = &rinfo->bios_connector[i]; + rinfo->mon[1].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[1].EDID); + break; + } + } + } else { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if (rinfo->bios_connector[i].conn_type == conn_vga) { + rinfo->mon[1].connector = &rinfo->bios_connector[i]; + rinfo->mon[1].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[1].EDID); + break; + } + } + } + } else { + if (num_vga) { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if (rinfo->bios_connector[i].conn_type == conn_CRT) { + rinfo->mon[0].connector = &rinfo->bios_connector[i]; + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[0].EDID); + break; + } + } + } else { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if ((rinfo->bios_connector[i].conn_type == conn_DVI_D) || + (rinfo->bios_connector[i].conn_type == conn_DVI_I)) { + rinfo->mon[0].connector = &rinfo->bios_connector[i]; + rinfo->mon[0].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[0].EDID); + break; + } + } + } + + if (num_dvi) { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if ((rinfo->bios_connector[i].conn_type == conn_DVI_D) || + (rinfo->bios_connector[i].conn_type == conn_DVI_I)) { + rinfo->mon[1].connector = &rinfo->bios_connector[i]; + rinfo->mon[1].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[1].EDID); + break; + } + } + } else { + for (i = 0; i < RADEON_MAX_BIOS_CONNECTORS; i++) { + if ( rinfo->bios_connector[i].valid == 0) + continue; + if ((rinfo->bios_connector[i].conn_type == conn_CRT)) { + rinfo->mon[1].connector = &rinfo->bios_connector[i]; + rinfo->mon[1].type = radeon_probe_i2c_connector(rinfo, rinfo->bios_connector[i].ddc_type, + &rinfo->mon[1].EDID); + break; + } + } + } + } + + if (rinfo->is_atom_bios) radeon_print_port_map(rinfo); + + if (rinfo->mon[0].type == MT_NONE && rinfo->is_mobility && ((rinfo->bios_seg && (INREG(BIOS_4_SCRATCH) & 4)) || (INREG(LVDS_GEN_CNTL) & LVDS_ON))) { - rinfo->mon1_type = MT_LCD; - printk("Non-DDC laptop panel detected\n"); + rinfo->mon[0].type = MT_LCD; + pr_info("Non-DDC laptop panel detected\n"); + } + if (rinfo->mon[0].type == MT_NONE) { + pr_info("radeonfb: Probe physical connection of a CRT\n"); + rinfo->mon[0].type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC); + if (rinfo->mon[0].type == MT_NONE) pr_info("radeonfb: No CRT found\n"); } - if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC); - - /* - * Probe secondary head (mostly VGA, can be DVI) - */ -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) - if (rinfo->mon2_type == MT_NONE) - rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, - &rinfo->mon2_EDID); -#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */ -#ifdef CONFIG_FB_RADEON_I2C - if (rinfo->mon2_type == MT_NONE) - rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga, - &rinfo->mon2_EDID); - if (rinfo->mon2_type == MT_NONE && !ddc_crt2_used) - rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, - &rinfo->mon2_EDID); -#endif /* CONFIG_FB_RADEON_I2C */ - if (rinfo->mon2_type == MT_NONE) - rinfo->mon2_type = radeon_crt_is_connected(rinfo, !rinfo->reversed_DAC); /* * If we only detected port 2, we swap them, if none detected, * assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look * at FP registers ?) */ - if (rinfo->mon1_type == MT_NONE) { - if (rinfo->mon2_type != MT_NONE) { - rinfo->mon1_type = rinfo->mon2_type; - rinfo->mon1_EDID = rinfo->mon2_EDID; - } else - rinfo->mon1_type = MT_CRT; - rinfo->mon2_type = MT_NONE; - rinfo->mon2_EDID = NULL; + if (rinfo->mon[0].type == MT_NONE) { + pr_info("radeonfb: Only port 2 detected, swap with port 1\n"); + + if (rinfo->mon[1].type != MT_NONE) { + struct monitor_info tmp = rinfo->mon[0]; + rinfo->mon[0] = rinfo->mon[1]; + rinfo->mon[1] = tmp; + + } else { + pr_info("radeonfb: none detected, assume CRT on port 1\n"); + rinfo->mon[0].type = MT_CRT; + rinfo->mon[1].type = MT_NONE; + rinfo->mon[1].EDID = NULL; + } +#if 0 + if (rinfo->mon[1].type != MT_NONE) { + rinfo->mon[0].type = rinfo->mon[1].type; + rinfo->mon[0].EDID = rinfo->mon[1].EDID; + } else { + pr_info("radeonfb: none detected, assume CRT on port 1\n"); + rinfo->mon[0].type = MT_CRT; + } + rinfo->mon[1].type = MT_NONE; + rinfo->mon[1].EDID = NULL; +#endif } /* @@ -609,68 +902,114 @@ */ if (rinfo->reversed_TMDS) { /* Always keep internal TMDS as primary head */ - if (rinfo->mon1_type == MT_DFP || rinfo->mon2_type == MT_DFP) { - int tmp_type = rinfo->mon1_type; - u8 *tmp_EDID = rinfo->mon1_EDID; - rinfo->mon1_type = rinfo->mon2_type; - rinfo->mon1_EDID = rinfo->mon2_EDID; - rinfo->mon2_type = tmp_type; - rinfo->mon2_EDID = tmp_EDID; - if (rinfo->mon1_type == MT_CRT || rinfo->mon2_type == MT_CRT) + pr_info("radeonfb: keep internal TMDS as primary head\n"); + if (rinfo->mon[0].type == MT_DFP || rinfo->mon[1].type == MT_DFP) { + int tmp_type = rinfo->mon[0].type; + u8 *tmp_EDID = rinfo->mon[0].EDID; + struct bios_connector *tmp_conn = rinfo->mon[0].connector; + rinfo->mon[0].type = rinfo->mon[1].type; + rinfo->mon[0].EDID = rinfo->mon[1].EDID; + rinfo->mon[0].connector = rinfo->mon[1].connector; + rinfo->mon[1].type = tmp_type; + rinfo->mon[1].EDID = tmp_EDID; + rinfo->mon[1].connector = tmp_conn; + if (rinfo->mon[0].type == MT_CRT || rinfo->mon[1].type == MT_CRT) rinfo->reversed_DAC ^= 1; } } + //toto: + if (radeon_parse_monitor_layout(rinfo, monitor_layout)) { + + /* + * If user specified a monitor_layout option, use it instead + * of auto-detecting. Maybe we should only use this argument + * on the first radeon card probed or provide a way to specify + * a layout for each card ? + */ + + pr_info("Using specified monitor layout: %s", monitor_layout); +#ifdef CONFIG_FB_RADEON_I2C + if (!ignore_edid) { + if (rinfo->mon[0].type != MT_NONE) + if (!radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon[0].EDID)) { + radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon[0].EDID); + ddc_crt2_used = 1; + } + if (rinfo->mon[1].type != MT_NONE) + if (!radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon[1].EDID) && + !ddc_crt2_used) + radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon[1].EDID); + } +#endif /* CONFIG_FB_RADEON_I2C */ + if (rinfo->mon[0].type == MT_NONE) { + if (rinfo->mon[1].type != MT_NONE) { + rinfo->mon[0].type = rinfo->mon[1].type; + rinfo->mon[0].EDID = rinfo->mon[1].EDID; + rinfo->mon[0].connector = rinfo->mon[1].connector; + } else { + rinfo->mon[0].type = MT_CRT; + pr_info("radeonfb: No valid monitor, assuming CRT on first port\n"); } + rinfo->mon[1].type = MT_NONE; + rinfo->mon[1].EDID = NULL; + rinfo->mon[1].connector = NULL; + } + } + if (ignore_edid) { - kfree(rinfo->mon1_EDID); - rinfo->mon1_EDID = NULL; - kfree(rinfo->mon2_EDID); - rinfo->mon2_EDID = NULL; + pr_info("radeonfb: ignore EDID flag set\n"); + kfree(rinfo->mon[0].EDID); + rinfo->mon[0].EDID = NULL; + kfree(rinfo->mon[1].EDID); + rinfo->mon[1].EDID = NULL; } bail: - printk(KERN_INFO "radeonfb: Monitor 1 type %s found\n", - radeon_get_mon_name(rinfo->mon1_type)); - if (rinfo->mon1_EDID) - printk(KERN_INFO "radeonfb: EDID probed\n"); + pr_info("radeonfb: Monitor 1 type %s found\n", + radeon_get_mon_name(rinfo->mon[0].type)); + if (rinfo->mon[0].EDID) + pr_info("radeonfb: Monitor 1, EDID probed\n"); if (!rinfo->has_CRTC2) return; - printk(KERN_INFO "radeonfb: Monitor 2 type %s found\n", - radeon_get_mon_name(rinfo->mon2_type)); - if (rinfo->mon2_EDID) - printk(KERN_INFO "radeonfb: EDID probed\n"); + pr_info("radeonfb: Monitor 2 type %s found\n", + radeon_get_mon_name(rinfo->mon[1].type)); + if (rinfo->mon[1].EDID) + pr_info("radeonfb: Monitor 2, EDID probed\n"); + else + pr_info("radeonfb: Monitor 2, no EDID to probe\n"); + } /* - * This functions applyes any arch/model/machine specific fixups + * This functions applies any arch/model/machine specific fixups * to the panel info. It may eventually alter EDID block as * well or whatever is specific to a given model and not probed * properly by the default code */ -static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) +static void radeon_fixup_panel_info(struct radeonfb_info *rinfo, int id) { #ifdef CONFIG_PPC_OF /* * LCD Flat panels should use fixed dividers, we enfore that on * PPC only for now... */ - if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD + if (!rinfo->mon[id].panel_info.use_bios_dividers && rinfo->mon[id].type == MT_LCD && rinfo->is_mobility) { int ppll_div_sel; u32 ppll_divn; ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3; radeon_pll_errata_after_index(rinfo); ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel); - rinfo->panel_info.ref_divider = rinfo->pll.ref_div; - rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff; - rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7; - rinfo->panel_info.use_bios_dividers = 1; + rinfo->mon[id].panel_info.ref_divider = rinfo->pll.ref_div; + rinfo->mon[id].panel_info.fbk_divider = ppll_divn & 0x7ff; + rinfo->mon[id].panel_info.post_divider = (ppll_divn >> 16) & 0x7; + rinfo->mon[id].panel_info.use_bios_dividers = 1; - printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x " + pr_info("radeonfb: Using Firmware dividers 0x%08x " "from PPLL %d\n", - rinfo->panel_info.fbk_divider | - (rinfo->panel_info.post_divider << 16), + rinfo->mon[id].panel_info.fbk_divider | + (rinfo->mon[id].panel_info.post_divider << 16), ppll_div_sel); } #endif /* CONFIG_PPC_OF */ @@ -681,30 +1020,30 @@ * Fill up panel infos from a mode definition, either returned by the EDID * or from the default mode when we can't do any better */ -static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var) +static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var, int id) { - rinfo->panel_info.xres = var->xres; - rinfo->panel_info.yres = var->yres; - rinfo->panel_info.clock = 100000000 / var->pixclock; - rinfo->panel_info.hOver_plus = var->right_margin; - rinfo->panel_info.hSync_width = var->hsync_len; - rinfo->panel_info.hblank = var->left_margin + + rinfo->mon[id].panel_info.xres = var->xres; + rinfo->mon[id].panel_info.yres = var->yres; + rinfo->mon[id].panel_info.clock = 100000000 / var->pixclock; + rinfo->mon[id].panel_info.hOver_plus = var->right_margin; + rinfo->mon[id].panel_info.hSync_width = var->hsync_len; + rinfo->mon[id].panel_info.hblank = var->left_margin + (var->right_margin + var->hsync_len); - rinfo->panel_info.vOver_plus = var->lower_margin; - rinfo->panel_info.vSync_width = var->vsync_len; - rinfo->panel_info.vblank = var->upper_margin + + rinfo->mon[id].panel_info.vOver_plus = var->lower_margin; + rinfo->mon[id].panel_info.vSync_width = var->vsync_len; + rinfo->mon[id].panel_info.vblank = var->upper_margin + (var->lower_margin + var->vsync_len); - rinfo->panel_info.hAct_high = + rinfo->mon[id].panel_info.hAct_high = (var->sync & FB_SYNC_HOR_HIGH_ACT) != 0; - rinfo->panel_info.vAct_high = + rinfo->mon[id].panel_info.vAct_high = (var->sync & FB_SYNC_VERT_HIGH_ACT) != 0; - rinfo->panel_info.valid = 1; + rinfo->mon[id].panel_info.valid = 1; /* We use a default of 200ms for the panel power delay, * I need to have a real schedule() instead of mdelay's in the panel code. * we might be possible to figure out a better power delay either from * MacOS OF tree or from the EDID block (proprietary extensions ?) */ - rinfo->panel_info.pwr_delay = 200; + rinfo->mon[id].panel_info.pwr_delay = 200; } static void radeon_videomode_to_var(struct fb_var_screeninfo *var, @@ -725,17 +1064,20 @@ var->vsync_len = mode->vsync_len; var->sync = mode->sync; var->vmode = mode->vmode; + + pr_info("Radeonfb: video mode: %dx%d\n", mode->xres, mode->yres); } /* * Build the modedb for head 1 (head 2 will come later), check panel infos * from either BIOS or EDID, and pick up the default mode */ -void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option) +void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option, int id) { - struct fb_info * info = rinfo->info; + struct fb_info *info; int has_default_mode = 0; + info = rinfo->info; /* * Fill default var first */ @@ -745,57 +1087,57 @@ /* * First check out what BIOS has to say */ - if (rinfo->mon1_type == MT_LCD) - radeon_get_panel_info_BIOS(rinfo); + if (rinfo->mon[id].type == MT_LCD) + radeon_get_panel_info_BIOS(rinfo, id); /* * Parse EDID detailed timings and deduce panel infos if any. Right now * we only deal with first entry returned by parse_EDID, we may do better * some day... */ - if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT - && rinfo->mon1_EDID) { + if (!rinfo->mon[id].panel_info.use_bios_dividers && rinfo->mon[id].type != MT_NONE + && rinfo->mon[id].EDID) { struct fb_var_screeninfo var; - pr_debug("Parsing EDID data for panel info\n"); - if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { - if (var.xres >= rinfo->panel_info.xres && - var.yres >= rinfo->panel_info.yres) - radeon_var_to_panel_info(rinfo, &var); + pr_info("Parsing EDID data for panel info\n"); + if (fb_parse_edid(rinfo->mon[id].EDID, &var) == 0) { + if (var.xres >= rinfo->mon[id].panel_info.xres && + var.yres >= rinfo->mon[id].panel_info.yres) + radeon_var_to_panel_info(rinfo, &var, id); } } /* * Do any additional platform/arch fixups to the panel infos */ - radeon_fixup_panel_info(rinfo); + radeon_fixup_panel_info(rinfo, id); /* * If we have some valid panel infos, we setup the default mode based on * those */ - if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { + if (rinfo->mon[id].type != MT_NONE && rinfo->mon[id].panel_info.valid) { struct fb_var_screeninfo *var = &info->var; - pr_debug("Setting up default mode based on panel info\n"); - var->xres = rinfo->panel_info.xres; - var->yres = rinfo->panel_info.yres; - var->xres_virtual = rinfo->panel_info.xres; - var->yres_virtual = rinfo->panel_info.yres; + pr_info("Setting up default mode based on panel info\n"); + var->xres = rinfo->mon[id].panel_info.xres; + var->yres = rinfo->mon[id].panel_info.yres; + var->xres_virtual = rinfo->mon[id].panel_info.xres; + var->yres_virtual = rinfo->mon[id].panel_info.yres; var->xoffset = var->yoffset = 0; var->bits_per_pixel = 8; - var->pixclock = 100000000 / rinfo->panel_info.clock; - var->left_margin = (rinfo->panel_info.hblank - rinfo->panel_info.hOver_plus - - rinfo->panel_info.hSync_width); - var->right_margin = rinfo->panel_info.hOver_plus; - var->upper_margin = (rinfo->panel_info.vblank - rinfo->panel_info.vOver_plus - - rinfo->panel_info.vSync_width); - var->lower_margin = rinfo->panel_info.vOver_plus; - var->hsync_len = rinfo->panel_info.hSync_width; - var->vsync_len = rinfo->panel_info.vSync_width; + var->pixclock = 100000000 / rinfo->mon[id].panel_info.clock; + var->left_margin = (rinfo->mon[id].panel_info.hblank - rinfo->mon[id].panel_info.hOver_plus + - rinfo->mon[id].panel_info.hSync_width); + var->right_margin = rinfo->mon[id].panel_info.hOver_plus; + var->upper_margin = (rinfo->mon[id].panel_info.vblank - rinfo->mon[id].panel_info.vOver_plus + - rinfo->mon[id].panel_info.vSync_width); + var->lower_margin = rinfo->mon[id].panel_info.vOver_plus; + var->hsync_len = rinfo->mon[id].panel_info.hSync_width; + var->vsync_len = rinfo->mon[id].panel_info.vSync_width; var->sync = 0; - if (rinfo->panel_info.hAct_high) + if (rinfo->mon[id].panel_info.hAct_high) var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (rinfo->panel_info.vAct_high) + if (rinfo->mon[id].panel_info.vAct_high) var->sync |= FB_SYNC_VERT_HIGH_ACT; var->vmode = 0; has_default_mode = 1; @@ -804,62 +1146,70 @@ /* * Now build modedb from EDID */ - if (rinfo->mon1_EDID) { - fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs); + if (rinfo->mon[id].EDID) { + fb_edid_to_monspecs(rinfo->mon[id].EDID, &info->monspecs); fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len, &info->modelist); - rinfo->mon1_modedb = info->monspecs.modedb; - rinfo->mon1_dbsize = info->monspecs.modedb_len; + rinfo->mon[id].modedb = info->monspecs.modedb; + rinfo->mon[id].dbsize = info->monspecs.modedb_len; } + if (rinfo->mon[id].panel_info.valid) { + pr_info("radeonfb: panel size for output %d: %dx%d\n", id, + rinfo->mon[id].panel_info.xres, rinfo->mon[id].panel_info.yres); + } /* * Finally, if we don't have panel infos we need to figure some (or * we try to read it from card), we try to pick a default mode * and create some panel infos. Whatever... */ - if (rinfo->mon1_type != MT_CRT && !rinfo->panel_info.valid) { + if (rinfo->mon[id].type != MT_NONE && !rinfo->mon[id].panel_info.valid) { struct fb_videomode *modedb; int dbsize; char modename[32]; - pr_debug("Guessing panel info...\n"); - if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { + pr_info("Guessing panel info...\n"); + if (rinfo->mon[id].panel_info.xres == 0 || rinfo->mon[id].panel_info.yres == 0) { u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE; - rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; + rinfo->mon[id].panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; tmp = INREG(FP_VERT_STRETCH) & VERT_PANEL_SIZE; - rinfo->panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1; + rinfo->mon[id].panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1; } - if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { - printk(KERN_WARNING "radeonfb: Can't find panel size, going back to CRT\n"); - rinfo->mon1_type = MT_CRT; + if (rinfo->mon[id].panel_info.xres == 0 || rinfo->mon[id].panel_info.yres == 0) { + pr_info("radeonfb: Can't find panel size, going back to CRT\n"); + rinfo->mon[id].type = MT_CRT; goto pickup_default; } - printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n", - rinfo->panel_info.xres, rinfo->panel_info.yres); - modedb = rinfo->mon1_modedb; - dbsize = rinfo->mon1_dbsize; - snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres); + pr_info("radeonfb: Assuming panel size %dx%d\n", + rinfo->mon[id].panel_info.xres, rinfo->mon[id].panel_info.yres); + modedb = rinfo->mon[id].modedb; + dbsize = rinfo->mon[id].dbsize; + snprintf(modename, 31, "%dx%d", rinfo->mon[id].panel_info.xres, rinfo->mon[id].panel_info.yres); if (fb_find_mode(&info->var, info, modename, modedb, dbsize, NULL, 8) == 0) { - printk(KERN_WARNING "radeonfb: Can't find mode for panel size, going back to CRT\n"); - rinfo->mon1_type = MT_CRT; + pr_info("radeonfb: Can't find mode for panel size, going back to CRT\n"); + rinfo->mon[id].type = MT_CRT; goto pickup_default; } has_default_mode = 1; - radeon_var_to_panel_info(rinfo, &info->var); + radeon_var_to_panel_info(rinfo, &info->var, id); } pickup_default: /* * Apply passed-in mode option if any */ + if (mode_option) { + pr_info("radeonfb: Apply passed-in mode option (%s)...\n", mode_option); if (fb_find_mode(&info->var, info, mode_option, info->monspecs.modedb, info->monspecs.modedb_len, NULL, 8) != 0) has_default_mode = 1; + else + pr_info("radeonfb: Can't find mode for panel size. Pick up a default from the db\n"); } /* @@ -880,6 +1230,7 @@ } } } else { + pr_info("get first mode in database...\n"); /* otherwise, get first mode in database */ modedb = &specs->modedb[0]; } @@ -935,7 +1286,7 @@ */ int radeon_match_mode(struct radeonfb_info *rinfo, struct fb_var_screeninfo *dest, - const struct fb_var_screeninfo *src) + const struct fb_var_screeninfo *src, int id) { const struct fb_videomode *db = vesa_modes; int i, dbsize = 34; @@ -947,14 +1298,18 @@ memcpy(dest, src, sizeof(struct fb_var_screeninfo)); /* Check if we have a modedb built from EDID */ - if (rinfo->mon1_modedb) { - db = rinfo->mon1_modedb; - dbsize = rinfo->mon1_dbsize; + if (rinfo->mon[id].modedb) { + db = rinfo->mon[id].modedb; + dbsize = rinfo->mon[id].dbsize; native_db = 1; + pr_info("radeonfb: using native table from EDID\n"); } /* Check if we have a scaler allowing any fancy mode */ - has_rmx = rinfo->mon1_type == MT_LCD || rinfo->mon1_type == MT_DFP; + has_rmx = rinfo->mon[id].type == MT_LCD || rinfo->mon[id].type == MT_DFP; + + if (has_rmx) + pr_info("radeonfb: we are allowed to set some fancy modes\n"); /* If we have a scaler and are passed FB_ACTIVATE_TEST or * FB_ACTIVATE_NOW, just do basic checking and return if the @@ -967,7 +1322,7 @@ * 640x480-60, but I assume userland knows what it's doing here * (though I may be proven wrong...) */ - if (has_rmx == 0 && rinfo->mon1_modedb) + if (has_rmx == 0 && rinfo->mon[id].modedb) if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info)) return -EINVAL; return 0; --- ./drivers/video/aty/radeon_i2c.c.orig 2008-09-23 11:44:23.000000000 +0200 +++ ./drivers/video/aty/radeon_i2c.c 2008-09-23 11:54:30.000000000 +0200 @@ -1,5 +1,4 @@ #include "radeonfb.h" - #include #include #include @@ -79,7 +78,7 @@ chan->algo.setscl = radeon_gpio_setscl; chan->algo.getsda = radeon_gpio_getsda; chan->algo.getscl = radeon_gpio_getscl; - chan->algo.udelay = 10; + chan->algo.udelay = 40; chan->algo.timeout = 20; chan->algo.data = chan; @@ -150,21 +149,21 @@ if (out_edid) *out_edid = edid; if (!edid) { - pr_debug("radeonfb: I2C (port %d) ... not found\n", conn); + pr_info("radeonfb: I2C bus (DDC connector %d) ... not found\n", conn); return MT_NONE; } if (edid[0x14] & 0x80) { /* Fix detection using BIOS tables */ if (rinfo->is_mobility /*&& conn == ddc_dvi*/ && (INREG(LVDS_GEN_CNTL) & LVDS_ON)) { - pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); + pr_info("radeonfb: I2C bus (DDC connector %d) ... found LVDS panel\n", conn); return MT_LCD; } else { - pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); + pr_info("radeonfb: I2C bus (DDC connector %d) ... found TMDS panel\n", conn); return MT_DFP; } } - pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn); + pr_info("radeonfb: I2C bus (DDC connector %d) ... found CRT display\n", conn); return MT_CRT; } --- ./drivers/video/aty/radeon_backlight.c.orig 2008-07-13 23:51:29.000000000 +0200 +++ ./drivers/video/aty/radeon_backlight.c 2008-09-23 11:54:30.000000000 +0200 @@ -25,7 +25,7 @@ }; static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata, - int level) + int level, int id) { int rlevel; @@ -51,9 +51,11 @@ struct radeonfb_info *rinfo = pdata->rinfo; u32 lvds_gen_cntl, tmpPixclksCntl; int level; + int id = 0; - if (rinfo->mon1_type != MT_LCD) + if (rinfo->mon[id].type != MT_LCD && rinfo->mon[id].type != MT_DFP) { return 0; + } /* We turn off the LCD completely instead of just dimming the * backlight. This provides some greater power saving and the display @@ -77,17 +79,17 @@ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= - (radeon_bl_get_level_brightness(pdata, level) << + (radeon_bl_get_level_brightness(pdata, level, id) << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= LVDS_ON; lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN); rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; mod_timer(&rinfo->lvds_timer, - jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + jiffies + msecs_to_jiffies(rinfo->mon[id].panel_info.pwr_delay)); } else { lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= - (radeon_bl_get_level_brightness(pdata, level) << + (radeon_bl_get_level_brightness(pdata, level, id) << LVDS_BL_MOD_LEVEL_SHIFT); OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); } @@ -102,7 +104,7 @@ if (rinfo->is_mobility || rinfo->is_IGP) OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN); - lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) << + lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0, id) << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= LVDS_DISPLAY_DIS; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); @@ -112,7 +114,7 @@ lvds_gen_cntl &= ~(LVDS_DIGON); rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; mod_timer(&rinfo->lvds_timer, - jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); + jiffies + msecs_to_jiffies(rinfo->mon[id].panel_info.pwr_delay)); if (rinfo->is_mobility || rinfo->is_IGP) OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl); } @@ -132,13 +134,13 @@ .update_status = radeon_bl_update_status, }; -void radeonfb_bl_init(struct radeonfb_info *rinfo) +void radeonfb_bl_init(struct radeonfb_info *rinfo, int id) { struct backlight_device *bd; struct radeon_bl_privdata *pdata; char name[12]; - if (rinfo->mon1_type != MT_LCD) + if (rinfo->mon[id].type != MT_LCD && rinfo->mon[id].type != MT_DFP) return; #ifdef CONFIG_PMAC_BACKLIGHT @@ -149,7 +151,7 @@ pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL); if (!pdata) { - printk("radeonfb: Memory allocation failed\n"); + pr_err("radeonfb: Memory allocation failed\n"); goto error; } @@ -158,7 +160,7 @@ bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data); if (IS_ERR(bd)) { rinfo->info->bl_dev = NULL; - printk("radeonfb: Backlight registration failed\n"); + pr_err("radeonfb: Backlight registration failed\n"); goto error; } @@ -190,7 +192,7 @@ bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); - printk("radeonfb: Backlight initialized (%s)\n", name); + pr_info("radeonfb: Backlight initialized (%s)\n", name); return; @@ -199,7 +201,7 @@ return; } -void radeonfb_bl_exit(struct radeonfb_info *rinfo) +void radeonfb_bl_exit(struct radeonfb_info *rinfo, int id) { struct backlight_device *bd = rinfo->info->bl_dev; @@ -211,6 +213,6 @@ kfree(pdata); rinfo->info->bl_dev = NULL; - printk("radeonfb: Backlight unloaded\n"); + pr_info("radeonfb: Backlight unloaded\n"); } }