X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fvideo%2Faty%2Fradeon_monitor.c;h=38c7dbf8c151a72747602eae0b38027445b8e89c;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=e93e94c5c45ea3efa043980073541a88ce384b56;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index e93e94c5c..38c7dbf8c 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -1,16 +1,26 @@ #include "radeonfb.h" #include "../edid.h" -#ifdef CONFIG_PPC_OF -#include -#include -#endif /* CONFIG_PPC_OF */ - static struct fb_var_screeninfo radeonfb_default_var = { - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2, - 0, FB_VMODE_NONINTERLACED + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 8, + .red = { .length = 8 }, + .green = { .length = 8 }, + .blue = { .length = 8 }, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED }; static char *radeon_get_mon_name(int type) @@ -49,16 +59,18 @@ static char *radeon_get_mon_name(int type) * models with broken OF probing by hard-coding known EDIDs for some Mac * laptops internal LVDS panel. (XXX: not done yet) */ -static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID, int hdno) +static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID, + int hdno) { - static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID2", NULL }; - u8 *pedid = NULL; - u8 *pmt = NULL; + static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", + "EDID1", "EDID2", NULL }; + const u8 *pedid = NULL; + const u8 *pmt = NULL; u8 *tmp; - int i, mt; + int i, mt = MT_NONE; RTRACE("analyzing OF properties...\n"); - pmt = (u8 *)get_property(dp, "display-type", NULL); + pmt = get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; RTRACE("display-type: %s\n", pmt); @@ -69,12 +81,15 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ mt = MT_DFP; else if (!strcmp(pmt, "CRT")) mt = MT_CRT; - else if (strcmp(pmt, "NONE")) { - printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", pmt); + else { + if (strcmp(pmt, "NONE") != 0) + printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n", + pmt); return MT_NONE; } + for (i = 0; propnames[i] != NULL; ++i) { - pedid = (u8 *)get_property(dp, propnames[i], NULL); + pedid = get_property(dp, propnames[i], NULL); if (pedid != NULL) break; } @@ -89,10 +104,9 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ if (pedid == NULL) return mt; - tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL); + tmp = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL); if (!tmp) return mt; - memcpy(tmp, pedid, EDID_LENGTH); *out_EDID = tmp; return mt; } @@ -104,19 +118,19 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ RTRACE("radeon_probe_OF_head\n"); - dp = pci_device_to_OF_node(rinfo->pdev); + dp = rinfo->of_node; while (dp == NULL) return MT_NONE; if (rinfo->has_CRTC2) { - char *pname; + const char *pname; int len, second = 0; dp = dp->child; do { if (!dp) return MT_NONE; - pname = (char *)get_property(dp, "name", NULL); + pname = get_property(dp, "name", NULL); if (!pname) return MT_NONE; len = strlen(pname); @@ -381,6 +395,10 @@ static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo, s1[i] = *s; i++; } + + if (i > 4) + i = 4; + } while (*s++); if (second) s2[i] = 0; @@ -408,7 +426,7 @@ static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo, /* * Probe display on both primary and secondary card's connector (if any) * by various available techniques (i2c, OF device tree, BIOS, ...) and - * try to retreive EDID. The algorithm here comes from XFree's radeon + * try to retrieve EDID. The algorithm here comes from XFree's radeon * driver */ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, @@ -484,8 +502,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, #endif /* CONFIG_PPC_OF */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, - &rinfo->mon1_EDID); + 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_vga, @@ -527,7 +546,8 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, */ #ifdef CONFIG_PPC_OF if (rinfo->mon1_type == MT_NONE) - rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID); + rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, + &rinfo->mon1_EDID); #endif /* CONFIG_PPC_OF */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) @@ -554,7 +574,8 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, */ #ifdef CONFIG_PPC_OF if (rinfo->mon2_type == MT_NONE) - rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, &rinfo->mon2_EDID); + rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, + &rinfo->mon2_EDID); #endif /* CONFIG_PPC_OF */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon2_type == MT_NONE) @@ -600,11 +621,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, } } if (ignore_edid) { - if (rinfo->mon1_EDID) - kfree(rinfo->mon1_EDID); + kfree(rinfo->mon1_EDID); rinfo->mon1_EDID = NULL; - if (rinfo->mon2_EDID) - kfree(rinfo->mon2_EDID); + kfree(rinfo->mon2_EDID); rinfo->mon2_EDID = NULL; } @@ -630,34 +649,28 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, */ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) { +#ifdef CONFIG_PPC_OF /* - * A few iBook laptop panels seem to need a fixed PLL setting - * - * We should probably do this differently based on the panel - * type/model or eventually some other device-tree informations, - * but these tweaks below work enough for now. --BenH + * LCD Flat panels should use fixed dividers, we enfore that on + * PPC only for now... */ -#ifdef CONFIG_PPC_OF - /* iBook2's */ - if (machine_is_compatible("PowerBook4,3")) { - rinfo->panel_info.ref_divider = rinfo->pll.ref_div; - rinfo->panel_info.post_divider = 0x6; - rinfo->panel_info.fbk_divider = 0xad; - rinfo->panel_info.use_bios_dividers = 1; - } - /* Aluminium PowerBook 17" */ - if (machine_is_compatible("PowerBook5,3")) { - rinfo->panel_info.ref_divider = rinfo->pll.ref_div; - rinfo->panel_info.post_divider = 0x4; - rinfo->panel_info.fbk_divider = 0x80; - rinfo->panel_info.use_bios_dividers = 1; - } - /* iBook G4 */ - if (machine_is_compatible("PowerBook6,3")) { + if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_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.post_divider = 0x6; - rinfo->panel_info.fbk_divider = 0xad; + rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff; + 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 " + "from PPLL %d\n", + rinfo->panel_info.fbk_divider | + (rinfo->panel_info.post_divider << 16), + ppll_div_sel); } #endif /* CONFIG_PPC_OF */ } @@ -693,40 +706,24 @@ static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_ rinfo->panel_info.pwr_delay = 200; } -static void radeon_var_to_videomode(struct fb_videomode *mode, - const struct fb_var_screeninfo *var) -{ - mode->xres = var->xres; - mode->yres = var->yres; - mode->pixclock = var->pixclock; - mode->left_margin = var->left_margin; - mode->right_margin = var->right_margin; - mode->upper_margin = var->upper_margin; - mode->lower_margin = var->lower_margin; - mode->hsync_len = var->hsync_len; - mode->vsync_len = var->vsync_len; - mode->sync = var->sync; - mode->vmode = var->vmode; -} - static void radeon_videomode_to_var(struct fb_var_screeninfo *var, const struct fb_videomode *mode) { - var->xres = mode->xres; - var->yres = mode->yres; - var->xres_virtual = mode->xres; - var->yres_virtual = mode->yres; - var->xoffset = 0; - var->yoffset = 0; - var->pixclock = mode->pixclock; - var->left_margin = mode->left_margin; - var->right_margin = mode->right_margin; - var->upper_margin = mode->upper_margin; - var->lower_margin = mode->lower_margin; - var->hsync_len = mode->hsync_len; - var->vsync_len = mode->vsync_len; - var->sync = mode->sync; - var->vmode = mode->vmode; + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = mode->xres; + var->yres_virtual = mode->yres; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = mode->vmode; } /* @@ -735,12 +732,14 @@ static void radeon_videomode_to_var(struct fb_var_screeninfo *var, */ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option) { + struct fb_info * info = rinfo->info; int has_default_mode = 0; /* * Fill default var first */ - rinfo->info->var = radeonfb_default_var; + info->var = radeonfb_default_var; + INIT_LIST_HEAD(&info->modelist); /* * First check out what BIOS has to say @@ -774,7 +773,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ * those */ if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { - struct fb_var_screeninfo *var = &rinfo->info->var; + struct fb_var_screeninfo *var = &info->var; RTRACE("Setting up default mode based on panel info\n"); var->xres = rinfo->panel_info.xres; @@ -805,9 +804,12 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ * Now build modedb from EDID */ if (rinfo->mon1_EDID) { - rinfo->mon1_modedb = fb_create_modedb(rinfo->mon1_EDID, - &rinfo->mon1_dbsize); - fb_get_monitor_limits(rinfo->mon1_EDID, &rinfo->info->monspecs); + fb_edid_to_monspecs(rinfo->mon1_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; } @@ -838,31 +840,62 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ modedb = rinfo->mon1_modedb; dbsize = rinfo->mon1_dbsize; snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres); - if (fb_find_mode(&rinfo->info->var, rinfo->info, modename, + 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; goto pickup_default; } has_default_mode = 1; - radeon_var_to_panel_info(rinfo, &rinfo->info->var); + radeon_var_to_panel_info(rinfo, &info->var); } pickup_default: /* - * Pick up a random default mode + * Apply passed-in mode option if any */ - if (!has_default_mode || mode_option) { - struct fb_videomode default_mode; - if (has_default_mode) - radeon_var_to_videomode(&default_mode, &rinfo->info->var); - else - radeon_var_to_videomode(&default_mode, &radeonfb_default_var); - if (fb_find_mode(&rinfo->info->var, rinfo->info, mode_option, - rinfo->mon1_modedb, rinfo->mon1_dbsize, &default_mode, 8) == 0) - rinfo->info->var = radeonfb_default_var; - } + if (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; + } + + /* + * Still no mode, let's pick up a default from the db + */ + if (!has_default_mode && info->monspecs.modedb != NULL) { + struct fb_monspecs *specs = &info->monspecs; + struct fb_videomode *modedb = NULL; + + /* get preferred timing */ + if (specs->misc & FB_MISC_1ST_DETAIL) { + int i; + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + modedb = &specs->modedb[i]; + break; + } + } + } else { + /* otherwise, get first mode in database */ + modedb = &specs->modedb[0]; + } + if (modedb != NULL) { + info->var.bits_per_pixel = 8; + radeon_videomode_to_var(&info->var, modedb); + has_default_mode = 1; + } + } + if (1) { + struct fb_videomode mode; + /* Make sure that whatever mode got selected is actually in the + * modelist or the kernel may die + */ + fb_var_to_videomode(&mode, &info->var); + fb_add_videomode(&mode, &info->modelist); + } } /* @@ -871,7 +904,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ */ /* - * This is used when looking for modes. We assign a "goodness" value + * This is used when looking for modes. We assign a "distance" value * to a mode in the modedb depending how "close" it is from what we * are looking for. * Currently, we don't compare that much, we could do better but @@ -880,13 +913,11 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ static int radeon_compare_modes(const struct fb_var_screeninfo *var, const struct fb_videomode *mode) { - int goodness = 0; + int distance = 0; - if (var->yres == mode->yres) - goodness += 10; - if (var->xres == mode->xres) - goodness += 9; - return goodness; + distance = mode->yres - var->yres; + distance += (mode->xres - var->xres)/2; + return distance; } /* @@ -908,7 +939,7 @@ int radeon_match_mode(struct radeonfb_info *rinfo, const struct fb_videomode *db = vesa_modes; int i, dbsize = 34; int has_rmx, native_db = 0; - int goodness = 0; + int distance = INT_MAX; const struct fb_videomode *candidate = NULL; /* Start with a copy of the requested mode */ @@ -944,19 +975,19 @@ int radeon_match_mode(struct radeonfb_info *rinfo, /* Now look for a mode in the database */ while (db) { for (i = 0; i < dbsize; i++) { - int g; + int d; if (db[i].yres < src->yres) continue; if (db[i].xres < src->xres) continue; - g = radeon_compare_modes(src, &db[i]); + d = radeon_compare_modes(src, &db[i]); /* If the new mode is at least as good as the previous one, * then it's our new candidate */ - if (g >= goodness) { + if (d < distance) { candidate = &db[i]; - goodness = g; + distance = d; } } db = NULL;