#include "radeonfb.h"
#include "../edid.h"
-#ifdef CONFIG_PPC_OF
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif /* CONFIG_PPC_OF */
-
static struct fb_var_screeninfo radeonfb_default_var = {
.xres = 640,
.yres = 480,
* 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 = 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);
}
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;
}
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;
}
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);
s1[i] = *s;
i++;
}
+
+ if (i > 4)
+ i = 4;
+
} while (*s++);
if (second)
s2[i] = 0;
/*
* 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,
#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,
*/
#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)
*/
#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)
}
}
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;
}
*/
static void radeon_fixup_panel_info(struct radeonfb_info *rinfo)
{
- #ifdef CONFIG_PPC_OF
+#ifdef CONFIG_PPC_OF
/*
* LCD Flat panels should use fixed dividers, we enfore that on
- * PowerMac only for now...
+ * PPC only for now...
*/
if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD
&& rinfo->is_mobility) {
- int ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
- u32 ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel);
+ 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.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;
}
/*
*/
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
* 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;
* 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;
}
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);
+ }
}
/*
*/
/*
- * 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
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;
}
/*
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 */
/* 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;