#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 = {
- 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)
* 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 };
+ static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
+ "EDID1", "EDID2", NULL };
u8 *pedid = NULL;
u8 *pmt = NULL;
u8 *tmp;
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);
- return MT_NONE;
- } else
+ 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);
RTRACE("radeon_probe_OF_head\n");
- dp = pci_device_to_OF_node(rinfo->pdev);
+ dp = rinfo->of_node;
while (dp == NULL)
return MT_NONE;
#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)
*/
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 15" */
- if (machine_is_compatible("PowerBook5,4")) {
- rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
- rinfo->panel_info.post_divider = 0x2;
- rinfo->panel_info.fbk_divider = 0x8e;
- rinfo->panel_info.use_bios_dividers = 1;
- }
- /* Aluminium PowerBook 17" */
- if (machine_is_compatible("PowerBook5,3") ||
- machine_is_compatible("PowerBook5,5")) {
- 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") ||
- machine_is_compatible("PowerBook6,5")) {
+ 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);
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 */
}
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);
+ }
}
/*