lkml.org 
[lkml]   [2007]   [May]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: radeonfb and X800 cards
    Il Thu, May 17, 2007 at 11:59:23AM +1000, Benjamin Herrenschmidt ha scritto: 
    > On Wed, 2007-05-16 at 21:47 -0400, Daniel Drake wrote:
    > > Hi,
    > >
    > > Did anything happen to the patch titled "radeonfb: add support for newer
    > > cards"?
    > > http://lwn.net/Articles/215965/
    > >
    > > Jimmy at http://bugs.gentoo.org/174063 has extended upon this with some
    > > further fixes based on code the in X11 driver. The patches are on the
    > > bug report.
    > >
    > > Ben, where can the most up-to-date radeonfb code be found?
    >
    > upstream. I haven't released anything else so far. Does the patch still
    > apply ?

    This is what I'm using here, it's still the same old patch (Solomon's
    plus my stuff). I think I can coordinate with Jimmy.Jazz@gmx.net to
    create an incremental patch to fix radeonfb on his hardware (provided
    that this mega-patch is suitable as baseline that is).

    ---
    Applies to current git

    drivers/video/aty/ati_ids.h | 32
    drivers/video/aty/radeon_accel.c | 19
    drivers/video/aty/radeon_backlight.c | 4
    drivers/video/aty/radeon_base.c | 494 +++++++----
    drivers/video/aty/radeon_i2c.c | 66 -
    drivers/video/aty/radeon_monitor.c | 1339 +++++++++++++++++++++---------
    drivers/video/aty/radeonfb.h | 163 ++-
    7 files changed, 1516 insertions(+), 601 deletions(-)

    diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
    index 90e7df2..7b701cc 100644
    --- a/drivers/video/aty/ati_ids.h
    +++ b/drivers/video/aty/ati_ids.h
    @@ -31,6 +31,7 @@
    #define PCI_CHIP_RV360_AR 0x4152
    #define PCI_CHIP_RV350_AS 0x4153
    #define PCI_CHIP_RV350_AT 0x4154
    +#define PCI_CHIP_RV350_AU 0x4155
    #define PCI_CHIP_RV350_AV 0x4156
    #define PCI_CHIP_MACH32 0x4158
    #define PCI_CHIP_RS250_4237 0x4237
    @@ -71,7 +72,13 @@
    #define PCI_CHIP_R420_JL 0x4A4C
    #define PCI_CHIP_R420_JM 0x4A4D
    #define PCI_CHIP_R420_JN 0x4A4E
    +#define PCI_CHIP_R420_JO 0x4A4F
    #define PCI_CHIP_R420_JP 0x4A50
    +#define PCI_CHIP_R420_JT 0x4A54
    +#define PCI_CHIP_R480_KI 0x4B49
    +#define PCI_CHIP_R480_KJ 0x4B4A
    +#define PCI_CHIP_R480_KK 0x4B4B
    +#define PCI_CHIP_R480_KL 0x4B4C
    #define PCI_CHIP_MACH64LB 0x4C42
    #define PCI_CHIP_MACH64LD 0x4C44
    #define PCI_CHIP_RAGE128LE 0x4C45
    @@ -182,9 +189,19 @@
    #define PCI_CHIP_R423_UI 0x5549
    #define PCI_CHIP_R423_UJ 0x554A
    #define PCI_CHIP_R423_UK 0x554B
    +#define PCI_CHIP_R423_UL 0x554C
    +#define PCI_CHIP_R423_UM 0x554D
    +#define PCI_CHIP_R423_UN 0x554E
    +#define PCI_CHIP_R423_UO 0x554F
    +#define PCI_CHIP_R423_UP 0x5550
    #define PCI_CHIP_R423_UQ 0x5551
    #define PCI_CHIP_R423_UR 0x5552
    #define PCI_CHIP_R423_UT 0x5554
    +#define PCI_CHIP_RV410_VJ 0x564A
    +#define PCI_CHIP_RV410_VK 0x564B
    +#define PCI_CHIP_RV410_VO 0x564F
    +#define PCI_CHIP_RV410_VR 0x5652
    +#define PCI_CHIP_RV410_VS 0x5653
    #define PCI_CHIP_MACH64VT 0x5654
    #define PCI_CHIP_MACH64VU 0x5655
    #define PCI_CHIP_MACH64VV 0x5656
    @@ -206,7 +223,22 @@
    #define PCI_CHIP_RV280_5964 0x5964
    #define PCI_CHIP_RV280_5C61 0x5C61
    #define PCI_CHIP_RV280_5C63 0x5C63
    +#define PCI_CHIP_R423_5D48 0x5D48
    +#define PCI_CHIP_R423_5D49 0x5D49
    +#define PCI_CHIP_R423_5D4A 0x5D4A
    +#define PCI_CHIP_R480_5D4C 0x5D4C
    +#define PCI_CHIP_R480_5D4D 0x5D4D
    +#define PCI_CHIP_R480_5D4E 0x5D4E
    +#define PCI_CHIP_R480_5D4F 0x5D4F
    +#define PCI_CHIP_R480_5D50 0x5D50
    +#define PCI_CHIP_R480_5D52 0x5D52
    #define PCI_CHIP_R423_5D57 0x5D57
    +#define PCI_CHIP_RV410_5E48 0x5E48
    +#define PCI_CHIP_RV410_5E4A 0x5E4A
    +#define PCI_CHIP_RV410_5E4B 0x5E4B
    +#define PCI_CHIP_RV410_5E4C 0x5E4C
    +#define PCI_CHIP_RV410_5E4D 0x5E4D
    +#define PCI_CHIP_RV410_5E4F 0x5E4F
    #define PCI_CHIP_RS350_7834 0x7834
    #define PCI_CHIP_RS350_7835 0x7835
    #define PCI_CHIP_RS480_5955 0x5955
    diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
    index 3ca27cb..529f158 100644
    --- a/drivers/video/aty/radeon_accel.c
    +++ b/drivers/video/aty/radeon_accel.c
    @@ -203,9 +203,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
    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 |
    @@ -241,9 +239,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
    INREG(HOST_PATH_CNTL);
    OUTREG(HOST_PATH_CNTL, host_path_cntl);

    - if (rinfo->family != CHIP_FAMILY_R300 ||
    - rinfo->family != CHIP_FAMILY_R350 ||
    - rinfo->family != CHIP_FAMILY_RV350)
    + if (IS_R300_VARIANT(rinfo))
    OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);

    OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
    @@ -254,16 +250,15 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo)
    {
    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
    diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
    index 0be25fa..0c264f3 100644
    --- a/drivers/video/aty/radeon_backlight.c
    +++ b/drivers/video/aty/radeon_backlight.c
    @@ -52,7 +52,7 @@ static int radeon_bl_update_status(struct backlight_device *bd)
    u32 lvds_gen_cntl, tmpPixclksCntl;
    int level;

    - if (rinfo->mon1_type != MT_LCD)
    + if (PRIMARY_MONITOR(rinfo) != MT_LCD)
    return 0;

    /* We turn off the LCD completely instead of just dimming the
    @@ -138,7 +138,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
    struct radeon_bl_privdata *pdata;
    char name[12];

    - if (rinfo->mon1_type != MT_LCD)
    + if (PRIMARY_MONITOR(rinfo) == MT_LCD)
    return;

    #ifdef CONFIG_PMAC_BACKLIGHT
    diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
    index 2ce0501..9616303 100644
    --- a/drivers/video/aty/radeon_base.c
    +++ b/drivers/video/aty/radeon_base.c
    @@ -3,6 +3,7 @@
    *
    * framebuffer driver for ATI Radeon chipset video boards
    *
    + * Copyright 2006 Solomon Peachy <pizza@shaftnet.org>
    * Copyright 2003 Ben. Herrenschmidt <benh@kernel.crashing.org>
    * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org>
    *
    @@ -50,7 +51,7 @@
    */


    -#define RADEON_VERSION "0.2.0"
    +#define RADEON_VERSION "0.3.0"

    #include <linux/module.h>
    #include <linux/moduleparam.h>
    @@ -112,7 +113,7 @@ static struct pci_device_id radeonfb_pci_table[] = {
    /* Radeon IGP320M (U1) */
    CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
    /* Radeon IGP320 (A3) */
    - CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP),
    + CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP),
    /* IGP330M/340M/350M (U2) */
    CHIP_DEF(PCI_CHIP_RS200_4337, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
    /* IGP330/340/350 (A4) */
    @@ -182,6 +183,7 @@ static struct pci_device_id radeonfb_pci_table[] = {
    CHIP_DEF(PCI_CHIP_RV360_AR, RV350, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV350_AS, RV350, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV350_AT, RV350, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV350_AU, RV350, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV350_AV, RV350, CHIP_HAS_CRTC2),
    /* 9800/Pro/FileGL X2 */
    CHIP_DEF(PCI_CHIP_R350_AH, R350, CHIP_HAS_CRTC2),
    @@ -192,7 +194,7 @@ static struct pci_device_id radeonfb_pci_table[] = {
    CHIP_DEF(PCI_CHIP_R350_NI, R350, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R360_NJ, R350, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R350_NK, R350, CHIP_HAS_CRTC2),
    - /* Newer stuff */
    + /* X300/X600 */
    CHIP_DEF(PCI_CHIP_RV380_3E50, RV380, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV380_3E54, RV380, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV380_3150, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    @@ -203,6 +205,19 @@ static struct pci_device_id radeonfb_pci_table[] = {
    CHIP_DEF(PCI_CHIP_RV370_5B65, RV380, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_RV370_5460, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    CHIP_DEF(PCI_CHIP_RV370_5464, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + /* X700 */
    + CHIP_DEF(PCI_CHIP_RV410_VJ, RV410, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_RV410_VK, RV410, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_RV410_VO, RV410, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_RV410_VR, RV410, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_RV410_VS, RV410, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_RV410_5E48, RV410, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV410_5E4A, RV410, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV410_5E4B, RV410, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV410_5E4C, RV410, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV410_5E4D, RV410, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_RV410_5E4F, RV410, CHIP_HAS_CRTC2),
    + /* X800/X850 */
    CHIP_DEF(PCI_CHIP_R420_JH, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R420_JI, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R420_JJ, R420, CHIP_HAS_CRTC2),
    @@ -210,7 +225,9 @@ static struct pci_device_id radeonfb_pci_table[] = {
    CHIP_DEF(PCI_CHIP_R420_JL, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R420_JM, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R420_JN, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_R420_JO, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R420_JT, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R423_UJ, R420, CHIP_HAS_CRTC2),
    @@ -219,6 +236,24 @@ static struct pci_device_id radeonfb_pci_table[] = {
    CHIP_DEF(PCI_CHIP_R423_UR, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R423_UT, R420, CHIP_HAS_CRTC2),
    CHIP_DEF(PCI_CHIP_R423_5D57, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R423_UP, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R423_5D49, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_R423_5D4A, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_R423_5D48, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
    + CHIP_DEF(PCI_CHIP_R423_UO, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R423_UM, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R423_UN, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R423_UL, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D4C, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D50, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D4E, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D4F, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D52, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_5D4D, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_KJ, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_KK, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_KI, R420, CHIP_HAS_CRTC2),
    + CHIP_DEF(PCI_CHIP_R480_KL, R420, CHIP_HAS_CRTC2),
    /* Original Radeon/7200 */
    CHIP_DEF(PCI_CHIP_RADEON_QD, RADEON, 0),
    CHIP_DEF(PCI_CHIP_RADEON_QE, RADEON, 0),
    @@ -239,7 +274,7 @@ typedef struct {
    * interfere with anything
    */
    static reg_val common_regs[] = {
    - { OVR_CLR, 0 },
    + { OVR_CLR, 0 },
    { OVR_WID_LEFT_RIGHT, 0 },
    { OVR_WID_TOP_BOTTOM, 0 },
    { OV0_SCALE_CNTL, 0 },
    @@ -254,13 +289,13 @@ static reg_val common_regs[] = {
    /*
    * globals
    */
    -
    static char *mode_option;
    static char *monitor_layout;
    static int noaccel = 0;
    static int default_dynclk = -2;
    static int nomodeset = 0;
    static int ignore_edid = 0;
    +static int ignore_conntable = 0;
    static int mirror = 0;
    static int panel_yres = 0;
    static int force_dfp = 0;
    @@ -276,6 +311,12 @@ static int backlight = 1;
    static int backlight = 0;
    #endif

    +#ifdef CONFIG_FB_RADEON_DEBUG
    +int radeonfb_debug = 1;
    +#else
    +int radeonfb_debug = 0;
    +#endif
    +
    /*
    * prototypes
    */
    @@ -331,7 +372,7 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev
    * to phase out Open Firmware images.
    *
    * Currently, we only look at the first PCI data, we could iteratre and deal with
    - * them all, and we should use fb_bios_start relative to start of image and not
    + * them all, and we should use fp_bios_start relative to start of image and not
    * relative start of ROM, but so far, I never found a dual-image ATI card
    *
    * typedef struct {
    @@ -417,7 +458,7 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
    * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
    * tree. Hopefully, ATI OF driver is kind enough to fill these
    */
    -static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
    +static int __devinit radeon_get_pll_info_openfirmware (struct radeonfb_info *rinfo)
    {
    struct device_node *dp = rinfo->of_node;
    const u32 *val;
    @@ -440,7 +481,8 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
    if (val && *val)
    rinfo->pll.mclk = (*val) / 10;

    - return 0;
    + RTRACE("Retrieved PLL infos from Open Firmware\n");
    + return 0;
    }
    #endif /* CONFIG_PPC_OF || CONFIG_SPARC */

    @@ -582,10 +624,87 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
    return 0;
    }

    +static int __devinit radeon_get_pll_info_legacy(struct radeonfb_info *rinfo)
    +{
    + u16 pll_info_block;
    +
    + if (!rinfo->bios_seg)
    + return -EINVAL;
    +
    + pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
    +
    + rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08);
    + rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a);
    + rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e);
    + rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10);
    + rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12);
    + rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16);
    +
    + RTRACE("Retrieved PLL infos from Legacy BIOS\n");
    + return 0;
    +}
    +
    +
    +static int __devinit radeon_get_pll_info_atom(struct radeonfb_info *rinfo)
    +{
    + u16 pll_info_block;
    +
    + if (!rinfo->bios_seg)
    + return -EINVAL;
    +
    + pll_info_block = BIOS_IN16(rinfo->atom_data_start + 12);
    +
    + rinfo->pll.sclk = BIOS_IN32(pll_info_block + 8);
    + rinfo->pll.mclk = BIOS_IN32(pll_info_block + 12);
    + rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 82);
    + rinfo->pll.ref_div = 0; /* Have to get it elsewhere */
    + rinfo->pll.ppll_min = BIOS_IN16(pll_info_block + 78);
    + rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 32);
    +
    + RTRACE("Retrieved PLL infos from ATOM BIOS\n");
    + return 0;
    +}
    +
    +static void radeon_detect_bios_type(struct radeonfb_info *rinfo)
    +{
    +#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
    + rinfo->is_atom_bios = 0;
    + rinfo->radeon_get_pll_info = radeon_get_pll_info_openfirmware;
    + rinfo->radeon_get_lvds_info = radeon_get_lvds_info_openfirmware;
    + rinfo->radeon_get_tmds_info = NULL;
    + rinfo->radeon_get_conn_info = radeon_get_conn_info_openfirmware;
    +#else
    + int tmp = rinfo->fp_bios_start + 4;
    + unsigned char sign[4];
    +
    + sign[0] = BIOS_IN8(tmp);
    + sign[1] = BIOS_IN8(tmp + 1);
    + sign[2] = BIOS_IN8(tmp + 2);
    + sign[3] = BIOS_IN8(tmp + 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);
    + rinfo->radeon_get_pll_info = radeon_get_pll_info_atom;
    + rinfo->radeon_get_lvds_info = radeon_get_lvds_info_atom;
    + rinfo->radeon_get_conn_info = radeon_get_conn_info_atom;
    + rinfo->radeon_get_tmds_info = radeon_get_tmds_info_atom;
    + } else {
    + rinfo->is_atom_bios = 0;
    + rinfo->radeon_get_pll_info = radeon_get_pll_info_legacy;
    + rinfo->radeon_get_lvds_info = radeon_get_lvds_info_legacy;
    + rinfo->radeon_get_conn_info = radeon_get_conn_info_legacy;
    + rinfo->radeon_get_tmds_info = radeon_get_tmds_info_legacy;
    + }
    +#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */
    +
    +}
    +
    /*
    * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...)
    */
    -static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
    +static void __devinit radeon_get_pll_info(struct radeonfb_info *rinfo)
    {
    /*
    * In the case nothing works, these are defaults; they are mostly
    @@ -637,46 +756,30 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
    case PCI_DEVICE_ID_ATI_RADEON_QF:
    case PCI_DEVICE_ID_ATI_RADEON_QG:
    default:
    - rinfo->pll.ppll_max = 35000;
    - rinfo->pll.ppll_min = 12000;
    + if (rinfo->family == CHIP_FAMILY_R420) {
    + rinfo->pll.ppll_max = 50000;
    + rinfo->pll.ppll_min = 20000;
    + } else {
    + rinfo->pll.ppll_max = 35000;
    + rinfo->pll.ppll_min = 12000;
    + }
    rinfo->pll.mclk = 16600;
    rinfo->pll.sclk = 16600;
    rinfo->pll.ref_clk = 2700;
    break;
    }
    - rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
    -
    -
    -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
    - /*
    - * 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");
    - goto found;
    - }
    -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */

    /*
    - * Check out if we have an X86 which gave us some PLL informations
    - * and if yes, retrieve them
    + * If we have a way to retrieve the PLL information, do so.
    */
    - if (!force_measure_pll && rinfo->bios_seg) {
    - u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
    -
    - rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08);
    - rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a);
    - rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e);
    - rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10);
    - rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12);
    - rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16);
    -
    - printk(KERN_INFO "radeonfb: Retrieved PLL infos from BIOS\n");
    - goto found;
    + if (!force_measure_pll && rinfo->radeon_get_pll_info) {
    + if (!rinfo->radeon_get_pll_info(rinfo)) {
    + goto found;
    + }
    }

    /*
    - * We didn't get PLL parameters from either OF or BIOS, we try to
    + * If we don't get the PLL parameters handed to us, we try to
    * probe them
    */
    if (radeon_probe_pll_params(rinfo) == 0) {
    @@ -687,9 +790,25 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
    /*
    * Fall back to already-set defaults...
    */
    - printk(KERN_INFO "radeonfb: Used default PLL infos\n");
    + printk(KERN_INFO "radeonfb: Used default PLL infos\n");

    found:
    +
    + /* Check and fix-up the PLL divisor if necessary */
    + if (rinfo->pll.ref_div < 2) {
    + int tmp = INPLL(PPLL_REF_DIV);
    + if (rinfo->family == CHIP_FAMILY_RS300) {
    + rinfo->pll.ref_div = (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> R300_PPLL_REF_DIV_ACC_SHIFT;
    + } else {
    + rinfo->pll.ref_div = tmp & PPLL_REF_DIV_MASK;
    + }
    +
    + /* Sane default */
    + if (rinfo->pll.ref_div < 2) {
    + rinfo->pll.ref_div = 12;
    + }
    + }
    +
    /*
    * Some methods fail to retrieve SCLK and MCLK values, we apply default
    * settings in this case (200Mhz). If that really happne often, we could
    @@ -705,7 +824,7 @@ found:
    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);
    + RTRACE("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)
    @@ -846,7 +965,7 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
    if (rinfo->asleep)
    return 0;

    - radeon_fifo_wait(2);
    + radeon_engine_idle();
    OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
    * var->bits_per_pixel / 8) & ~7);
    return 0;
    @@ -927,9 +1046,10 @@ static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,

    int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
    {
    - u32 val;
    + u32 val;
    u32 tmp_pix_clks;
    int unblank = 0;
    + int i;

    if (rinfo->lock_blank)
    return 0;
    @@ -937,9 +1057,9 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
    radeon_engine_idle();

    val = INREG(CRTC_EXT_CNTL);
    - val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
    + val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
    CRTC_VSYNC_DIS);
    - switch (blank) {
    + switch (blank) {
    case FB_BLANK_VSYNC_SUSPEND:
    val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
    break;
    @@ -956,81 +1076,84 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
    case FB_BLANK_UNBLANK:
    default:
    unblank = 1;
    - }
    + }
    OUTREG(CRTC_EXT_CNTL, val);

    + for (i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
    + if (rinfo->heads[i] == -1)
    + continue;

    - switch (rinfo->mon1_type) {
    - case MT_DFP:
    - if (unblank)
    - OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
    - ~(FP_FPON | FP_TMDS_EN));
    - else {
    - if (mode_switch || blank == FB_BLANK_NORMAL)
    - break;
    - OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
    - }
    + switch (rinfo->connectors[rinfo->heads[i]].mon_type) {
    + case MT_DFP:
    + if (unblank)
    + OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
    + ~(FP_FPON | FP_TMDS_EN));
    + else {
    + if (mode_switch || blank == FB_BLANK_NORMAL)
    + break;
    + OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
    + }
    break;
    - case MT_LCD:
    - del_timer_sync(&rinfo->lvds_timer);
    - val = INREG(LVDS_GEN_CNTL);
    - if (unblank) {
    - u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
    - | LVDS_EN | (rinfo->init_state.lvds_gen_cntl
    - & (LVDS_DIGON | LVDS_BL_MOD_EN));
    - if ((val ^ target_val) == LVDS_DISPLAY_DIS)
    - OUTREG(LVDS_GEN_CNTL, target_val);
    - else if ((val ^ target_val) != 0) {
    - OUTREG(LVDS_GEN_CNTL, target_val
    - & ~(LVDS_ON | LVDS_BL_MOD_EN));
    - rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
    - rinfo->init_state.lvds_gen_cntl |=
    - target_val & LVDS_STATE_MASK;
    - if (mode_switch) {
    - radeon_msleep(rinfo->panel_info.pwr_delay);
    + case MT_LCD:
    + del_timer_sync(&rinfo->lvds_timer);
    + val = INREG(LVDS_GEN_CNTL);
    + if (unblank) {
    + u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
    + | LVDS_EN | (rinfo->init_state.lvds_gen_cntl
    + & (LVDS_DIGON | LVDS_BL_MOD_EN));
    + if ((val ^ target_val) == LVDS_DISPLAY_DIS)
    OUTREG(LVDS_GEN_CNTL, target_val);
    + else if ((val ^ target_val) != 0) {
    + OUTREG(LVDS_GEN_CNTL, target_val
    + & ~(LVDS_ON | LVDS_BL_MOD_EN));
    + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
    + rinfo->init_state.lvds_gen_cntl |=
    + target_val & LVDS_STATE_MASK;
    + if (mode_switch) {
    + radeon_msleep(rinfo->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));
    + }
    }
    - else {
    - rinfo->pending_lvds_gen_cntl = target_val;
    - mod_timer(&rinfo->lvds_timer,
    - jiffies +
    - msecs_to_jiffies(rinfo->panel_info.pwr_delay));
    - }
    + } else {
    + val |= LVDS_DISPLAY_DIS;
    + OUTREG(LVDS_GEN_CNTL, val);
    +
    + /* We don't do a full switch-off on a simple mode switch */
    + if (mode_switch || blank == FB_BLANK_NORMAL)
    + break;
    +
    + /* Asic bug, when turning off LVDS_ON, we have to make sure
    + * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
    + */
    + tmp_pix_clks = INPLL(PIXCLKS_CNTL);
    + if (rinfo->is_mobility || rinfo->is_IGP)
    + OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
    + val &= ~(LVDS_BL_MOD_EN);
    + OUTREG(LVDS_GEN_CNTL, val);
    + udelay(100);
    + val &= ~(LVDS_ON | LVDS_EN);
    + OUTREG(LVDS_GEN_CNTL, val);
    + val &= ~LVDS_DIGON;
    + rinfo->pending_lvds_gen_cntl = val;
    + mod_timer(&rinfo->lvds_timer,
    + jiffies +
    + msecs_to_jiffies(rinfo->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)
    + OUTPLL(PIXCLKS_CNTL, tmp_pix_clks);
    }
    - } else {
    - val |= LVDS_DISPLAY_DIS;
    - OUTREG(LVDS_GEN_CNTL, val);
    -
    - /* We don't do a full switch-off on a simple mode switch */
    - if (mode_switch || blank == FB_BLANK_NORMAL)
    - break;
    -
    - /* Asic bug, when turning off LVDS_ON, we have to make sure
    - * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
    - */
    - tmp_pix_clks = INPLL(PIXCLKS_CNTL);
    - if (rinfo->is_mobility || rinfo->is_IGP)
    - OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
    - val &= ~(LVDS_BL_MOD_EN);
    - OUTREG(LVDS_GEN_CNTL, val);
    - udelay(100);
    - val &= ~(LVDS_ON | LVDS_EN);
    - OUTREG(LVDS_GEN_CNTL, val);
    - val &= ~LVDS_DIGON;
    - rinfo->pending_lvds_gen_cntl = val;
    - mod_timer(&rinfo->lvds_timer,
    - jiffies +
    - msecs_to_jiffies(rinfo->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)
    - OUTPLL(PIXCLKS_CNTL, tmp_pix_clks);
    + break;
    + case MT_CRT:
    + // todo: powerdown DAC
    + default:
    + break;
    }
    - break;
    - case MT_CRT:
    - // todo: powerdown DAC
    - default:
    - break;
    }

    return 0;
    @@ -1260,7 +1383,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
    ~PPLL_DIV_SEL_MASK);
    radeon_pll_errata_after_index(rinfo);
    radeon_pll_errata_after_data(rinfo);
    - return;
    + return;
    }
    }

    @@ -1280,10 +1403,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
    radeon_pll_errata_after_data(rinfo);

    /* Set PPLL ref. div */
    - if (rinfo->family == CHIP_FAMILY_R300 ||
    - rinfo->family == CHIP_FAMILY_RS300 ||
    - rinfo->family == CHIP_FAMILY_R350 ||
    - rinfo->family == CHIP_FAMILY_RV350) {
    + if (IS_R300_VARIANT(rinfo) || (rinfo->family == CHIP_FAMILY_RS300)) {
    if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
    /* When restoring console mode, use saved PPLL_REF_DIV
    * setting.
    @@ -1292,7 +1412,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
    } else {
    /* R300 uses ref_div_acc field as real ref divider */
    OUTPLLP(PPLL_REF_DIV,
    - (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
    + (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
    ~R300_PPLL_REF_DIV_ACC_MASK);
    }
    } else
    @@ -1380,6 +1500,7 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
    OUTREG(CRTC_OFFSET_CNTL, 0);
    OUTREG(CRTC_PITCH, mode->crtc_pitch);
    OUTREG(SURFACE_CNTL, mode->surface_cntl);
    + OUTREG(DISP_MERGE_CNTL, 0xffff0000);

    radeon_write_pll_regs(rinfo, mode);

    @@ -1890,7 +2011,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
    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 = pci_resource_len(rinfo->pdev, 2);
    info->fix.accel = FB_ACCEL_ATI_RADEON;

    fb_alloc_cmap(&info->cmap, 256, 0);
    @@ -1994,10 +2115,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
    u32 tmp;

    /* framebuffer size */
    - if ((rinfo->family == CHIP_FAMILY_RS100) ||
    - (rinfo->family == CHIP_FAMILY_RS200) ||
    - (rinfo->family == CHIP_FAMILY_RS300) ||
    - (rinfo->family == CHIP_FAMILY_RS480) ) {
    + if (rinfo->is_IGP) {
    u32 tom = INREG(NB_TOM);
    tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);

    @@ -2025,6 +2143,10 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
    /* mem size is bits [28:0], mask off the rest */
    rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;

    + /* Limit memory to 128 megs for now */
    + if (rinfo->video_ram > MAX_VRAM)
    + rinfo->video_ram = MAX_VRAM;
    +
    /*
    * Hack to get around some busted production M6's
    * reporting no ram
    @@ -2106,10 +2228,10 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, si
    {
    struct device *dev = container_of(kobj, struct device, kobj);
    struct pci_dev *pdev = to_pci_dev(dev);
    - struct fb_info *info = pci_get_drvdata(pdev);
    - struct radeonfb_info *rinfo = info->par;
    + 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->connectors[rinfo->heads[0]].edid);
    }


    @@ -2117,10 +2239,30 @@ static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, si
    {
    struct device *dev = container_of(kobj, struct device, kobj);
    struct pci_dev *pdev = to_pci_dev(dev);
    - struct fb_info *info = pci_get_drvdata(pdev);
    - struct radeonfb_info *rinfo = info->par;
    + struct fb_info *info = pci_get_drvdata(pdev);
    + struct radeonfb_info *rinfo = info->par;
    +
    + return radeon_show_one_edid(buf, off, count, rinfo->connectors[rinfo->heads[1]].edid);
    +}
    +
    +static ssize_t radeon_show_edid3(struct kobject *kobj, char *buf, loff_t off, size_t count)
    +{
    + struct device *dev = container_of(kobj, struct device, kobj);
    + struct pci_dev *pdev = to_pci_dev(dev);
    + struct fb_info *info = pci_get_drvdata(pdev);
    + struct radeonfb_info *rinfo = info->par;
    +
    + return radeon_show_one_edid(buf, off, count, rinfo->connectors[rinfo->heads[2]].edid);
    +}
    +
    +static ssize_t radeon_show_edid4(struct kobject *kobj, char *buf, loff_t off, size_t count)
    +{
    + struct device *dev = container_of(kobj, struct device, kobj);
    + struct pci_dev *pdev = to_pci_dev(dev);
    + 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->connectors[rinfo->heads[3]].edid);
    }

    static struct bin_attribute edid1_attr = {
    @@ -2143,6 +2285,25 @@ static struct bin_attribute edid2_attr = {
    .read = radeon_show_edid2,
    };

    +static struct bin_attribute edid3_attr = {
    + .attr = {
    + .name = "edid3",
    + .owner = THIS_MODULE,
    + .mode = 0444,
    + },
    + .size = EDID_LENGTH,
    + .read = radeon_show_edid3,
    +};
    +
    +static struct bin_attribute edid4_attr = {
    + .attr = {
    + .name = "edid4",
    + .owner = THIS_MODULE,
    + .mode = 0444,
    + },
    + .size = EDID_LENGTH,
    + .read = radeon_show_edid4,
    +};

    static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    const struct pci_device_id *ent)
    @@ -2150,9 +2311,10 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    struct fb_info *info;
    struct radeonfb_info *rinfo;
    int ret;
    + int i;

    RTRACE("radeonfb_pci_register BEGIN\n");
    -
    +
    /* Enable device in PCI config */
    ret = pci_enable_device(pdev);
    if (ret < 0) {
    @@ -2169,9 +2331,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    goto err_disable;
    }
    rinfo = info->par;
    - rinfo->info = info;
    + rinfo->info = info;
    rinfo->pdev = pdev;
    -
    +
    spin_lock_init(&rinfo->reg_lock);
    init_timer(&rinfo->lvds_timer);
    rinfo->lvds_timer.function = radeon_lvds_timer_func;
    @@ -2206,7 +2368,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    }

    /* map the regions */
    - rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE);
    + rinfo->mmio_base = ioremap(rinfo->mmio_base_phys,
    + pci_resource_len(rinfo->pdev, 2));
    if (!rinfo->mmio_base) {
    printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n",
    pci_name(rinfo->pdev));
    @@ -2258,7 +2421,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram);

    do {
    - rinfo->fb_base = ioremap (rinfo->fb_base_phys,
    + rinfo->fb_base = ioremap(rinfo->fb_base_phys,
    rinfo->mapped_vram);
    } while ( rinfo->fb_base == 0 &&
    ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) );
    @@ -2293,6 +2456,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    * We probably need to make sure this is the primary display,
    * but that is difficult without some arch support.
    */
    +
    #ifdef CONFIG_X86
    if (rinfo->bios_seg == NULL)
    radeon_find_mem_vbios(rinfo);
    @@ -2304,14 +2468,23 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    if (rinfo->bios_seg == NULL && rinfo->is_mobility)
    radeon_map_ROM(rinfo, pdev);

    + /* Check BIOS Type */
    + radeon_detect_bios_type(rinfo);
    +
    /* Get informations about the board's PLL */
    - radeon_get_pllinfo(rinfo);
    + radeon_get_pll_info(rinfo);
    +
    + /* Get informations about internal TMDS controller if any */
    + radeon_get_tmds_info(rinfo);

    #ifdef CONFIG_FB_RADEON_I2C
    /* Register I2C bus */
    radeon_create_i2c_busses(rinfo);
    #endif

    + /* Get infos about connectors -- need I2C here! */
    + radeon_get_conn_info(rinfo, ignore_conntable);
    +
    /* set all the vital stuff */
    radeon_set_fbinfo (rinfo);

    @@ -2322,10 +2495,15 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    radeon_check_modes(rinfo, mode_option);

    /* Register some sysfs stuff (should be done better) */
    - if (rinfo->mon1_EDID)
    +
    + if ((rinfo->heads[0] != -1) && rinfo->connectors[rinfo->heads[0]].edid)
    sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
    - if (rinfo->mon2_EDID)
    + if ((rinfo->heads[1] != -1) && rinfo->connectors[rinfo->heads[1]].edid)
    sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
    + if ((rinfo->heads[2] != -1) && rinfo->connectors[rinfo->heads[2]].edid)
    + sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid3_attr);
    + if ((rinfo->heads[3] != -1) && rinfo->connectors[rinfo->heads[3]].edid)
    + sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid4_attr);

    /* save current mode regs before we switch into the new one
    * so we can restore this upon __exit
    @@ -2371,10 +2549,12 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
    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);
    + for (i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
    + kfree(rinfo->connectors[i].edid);
    + if (rinfo->connectors[i].modedb)
    + fb_destroy_modedb(rinfo->connectors[i].modedb);
    + }
    +
    fb_dealloc_cmap(&info->cmap);
    #ifdef CONFIG_FB_RADEON_I2C
    radeon_delete_i2c_busses(rinfo);
    @@ -2387,7 +2567,7 @@ err_release_pci2:
    err_release_pci0:
    pci_release_region(pdev, 0);
    err_release_fb:
    - framebuffer_release(info);
    + framebuffer_release(info);
    err_disable:
    err_out:
    return ret;
    @@ -2399,16 +2579,21 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
    {
    struct fb_info *info = pci_get_drvdata(pdev);
    struct radeonfb_info *rinfo = info->par;
    + int i;

    if (!rinfo)
    return;

    radeonfb_pm_exit(rinfo);

    - if (rinfo->mon1_EDID)
    + if ((rinfo->heads[0] != -1) && rinfo->connectors[rinfo->heads[0]].edid)
    sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
    - if (rinfo->mon2_EDID)
    + if ((rinfo->heads[1] != -1) && rinfo->connectors[rinfo->heads[1]].edid)
    sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
    + if ((rinfo->heads[2] != -1) && rinfo->connectors[rinfo->heads[2]].edid)
    + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid3_attr);
    + if ((rinfo->heads[3] != -1) && rinfo->connectors[rinfo->heads[3]].edid)
    + sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid4_attr);

    #if 0
    /* restore original state
    @@ -2437,13 +2622,14 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
    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);
    + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
    + kfree(rinfo->connectors[i].edid);
    + if (rinfo->connectors[i].modedb)
    + fb_destroy_modedb(rinfo->connectors[i].modedb);
    + }
    #ifdef CONFIG_FB_RADEON_I2C
    radeon_delete_i2c_busses(rinfo);
    -#endif
    +#endif
    fb_dealloc_cmap(&info->cmap);
    framebuffer_release(info);
    }
    @@ -2492,12 +2678,18 @@ static int __init radeonfb_setup (char *options)
    force_measure_pll = 1;
    } else if (!strncmp(this_opt, "ignore_edid", 11)) {
    ignore_edid = 1;
    + } else if (!strncmp(this_opt, "ignore_conntable", 16)) {
    + ignore_conntable = 1;
    + } else if (!strncmp( this_opt, "default_dynclk:", 15)) {
    + default_dynclk = simple_strtoul((this_opt+15), NULL, 10);
    #if defined(CONFIG_PM) && defined(CONFIG_X86)
    - } else if (!strncmp(this_opt, "force_sleep", 11)) {
    + } else if (!strncmp(this_opt, "force_sleep", 11)) {
    force_sleep = 1;
    } else if (!strncmp(this_opt, "ignore_devlist", 14)) {
    ignore_devlist = 1;
    #endif
    + } else if (!strncmp(this_opt, "debug", 5)) {
    + radeonfb_debug = 1;
    } else
    mode_option = this_opt;
    }
    @@ -2541,6 +2733,8 @@ module_param(force_dfp, bool, 0);
    MODULE_PARM_DESC(force_dfp, "bool: force display to dfp");
    module_param(ignore_edid, bool, 0);
    MODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe");
    +module_param(ignore_conntable, bool, 0);
    +MODULE_PARM_DESC(ignore_conntable, "bool: Ignore BIOS Connector table");
    module_param(monitor_layout, charp, 0);
    MODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)");
    module_param(force_measure_pll, bool, 0);
    @@ -2559,3 +2753,5 @@ MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware");
    module_param(ignore_devlist, bool, 0);
    MODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops");
    #endif
    +module_param(radeonfb_debug, int, 0);
    +MODULE_PARM_DESC(radeonfb_debug, "Enable full debugging text");
    diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
    index 7db9de6..e4bc267 100644
    --- a/drivers/video/aty/radeon_i2c.c
    +++ b/drivers/video/aty/radeon_i2c.c
    @@ -134,35 +134,57 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
    rinfo->i2c[3].rinfo = NULL;
    }

    -int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
    - u8 **out_edid)
    +
    +int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, struct radeon_connector *conn)
    {
    - u32 reg = rinfo->i2c[conn-1].ddc_reg;
    + int mon_type = MT_NONE;
    u8 *edid;

    - OUTREG(reg, INREG(reg) &
    - ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
    + if (!conn)
    + return 1;
    +
    + if (rinfo->is_mobility && (conn->ddc_type == ddc_none) &&
    + (INREG(LVDS_GEN_CNTL) & (LVDS_ON|LVDS_EN))) {
    + RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn->ddc_type);
    + mon_type = MT_LCD;
    + edid = NULL;
    + goto done;
    + }

    - edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
    + if (conn->ddc_type == ddc_none)
    + return 1;
    + edid = fb_ddc_read(&rinfo->i2c[conn->ddc_type].adapter);

    - if (out_edid)
    - *out_edid = edid;
    if (!edid) {
    - RTRACE("radeonfb: I2C (port %d) ... not found\n", conn);
    - return MT_NONE;
    + /* what about the special case where we are a DFP/LVDS, but have a DDC connection
    + * but no EDID? We should fall back to MT_LCD...? XXXX
    + */
    + RTRACE("radeonfb: I2C (port %d) ... not found\n", conn->ddc_type);
    + mon_type = MT_NONE;
    + goto done;
    + }
    + if ((edid[EDID_STRUCT_DISPLAY] & 0x80) && (conn->ddc_type == ddc_dvi)) {
    + RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn->ddc_type);
    + mon_type = MT_DFP;
    + goto done;
    }
    - if (edid[0x14] & 0x80) {
    - /* Fix detection using BIOS tables */
    - if (rinfo->is_mobility /*&& conn == ddc_dvi*/ &&
    - (INREG(LVDS_GEN_CNTL) & LVDS_ON)) {
    - RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
    - return MT_LCD;
    - } else {
    - RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
    - return MT_DFP;
    - }
    +
    + if (rinfo->is_mobility &&
    + (conn->conn_type == conn_lvds) &&
    + (edid[EDID_STRUCT_DISPLAY] & 0x80) && // ie EDID valid and marks us as a DFP...
    + (INREG(LVDS_GEN_CNTL) & (LVDS_ON|LVDS_EN))) {
    + RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn->ddc_type);
    + mon_type = MT_LCD;
    + goto done;
    }
    - RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn);
    - return MT_CRT;
    +
    + RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn->ddc_type);
    + mon_type = MT_CRT;
    +
    +done:
    + conn->edid = edid;
    + conn->mon_type = mon_type;
    +
    + return (mon_type == MT_NONE);
    }

    diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
    index 2030ed8..1b646d1 100644
    --- a/drivers/video/aty/radeon_monitor.c
    +++ b/drivers/video/aty/radeon_monitor.c
    @@ -1,6 +1,29 @@
    #include "radeonfb.h"
    #include "../edid.h"

    +/*
    + * TMDS PLL configuration table, taken from X.org
    + */
    +static const struct radeon_tmds_pll_info default_tmds_pll[CHIP_FAMILY_LAST][4] =
    +{
    + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/
    + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/
    + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/
    + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/
    + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/
    + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/
    + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/
    + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/
    + {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/
    + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/
    + {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x400f7}, {0, 0}}, /*CHIP_FAMILY_RV280*/
    + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/
    + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/
    + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/
    + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV380*/
    + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R420*/
    +};
    +
    static struct fb_var_screeninfo radeonfb_default_var = {
    .xres = 640,
    .yres = 480,
    @@ -23,35 +46,311 @@ static struct fb_var_screeninfo radeonfb_default_var = {
    .vmode = FB_VMODE_NONINTERLACED
    };

    -static char *radeon_get_mon_name(int type)
    +
    +int __devinit radeon_get_lvds_info_atom(struct radeonfb_info *rinfo)
    {
    - char *pret = NULL;
    + unsigned long tmp;

    - switch (type) {
    - case MT_NONE:
    - pret = "no";
    - break;
    - case MT_CRT:
    - pret = "CRT";
    - break;
    - case MT_DFP:
    - pret = "DFP";
    - break;
    - case MT_LCD:
    - pret = "LCD";
    - break;
    - case MT_CTV:
    - pret = "CTV";
    - break;
    - case MT_STV:
    - pret = "STV";
    + if (!rinfo->bios_seg)
    + return -ENODEV;
    +
    + tmp = BIOS_IN16(rinfo->atom_data_start + 16);
    + if (!tmp) {
    + RTRACE("No LVDS panel info in ATOM BIOS\n");
    + rinfo->panel_info.pwr_delay = 200;
    + return -ENODEV;
    + }
    +
    + rinfo->panel_info.xres = BIOS_IN16(tmp+6);
    + rinfo->panel_info.yres = BIOS_IN16(tmp+10);
    + printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n",
    + rinfo->panel_info.xres, rinfo->panel_info.yres);
    + rinfo->panel_info.pwr_delay = BIOS_IN16(tmp+40);
    + RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
    + if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0)
    + rinfo->panel_info.pwr_delay = 2000;
    +
    + /* No special divider combinations? */
    +
    + rinfo->panel_info.hblank = BIOS_IN16(tmp+8);
    + rinfo->panel_info.hOver_plus = BIOS_IN16(tmp+14);
    + rinfo->panel_info.hSync_width = BIOS_IN16(tmp+16);
    + rinfo->panel_info.vblank = BIOS_IN16(tmp+12);
    + rinfo->panel_info.vOver_plus = BIOS_IN16(tmp+18);
    + rinfo->panel_info.vSync_width = BIOS_IN16(tmp+20);
    + rinfo->panel_info.clock = BIOS_IN16(tmp+4);
    +
    + /* Assume high active syncs for now until ATI tells me more... maybe we
    + * can probe register values here ?
    + */
    + rinfo->panel_info.hAct_high = 1;
    + rinfo->panel_info.vAct_high = 1;
    + /* Mark panel infos valid */
    + rinfo->panel_info.valid = 1;
    +
    + return 0;
    +}
    +
    +int __devinit radeon_get_lvds_info_legacy(struct radeonfb_info *rinfo)
    +{
    + unsigned long tmp, tmp0;
    + char stmp[30];
    + int i;
    +
    + if (!rinfo->bios_seg)
    + return -ENODEV;
    +
    + if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) {
    + RTRACE("No LVDS panel info in Legacy BIOS\n");
    + rinfo->panel_info.pwr_delay = 200;
    + return -ENODEV;
    + }
    +
    + 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);
    + RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
    + if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0)
    + rinfo->panel_info.pwr_delay = 2000;
    +
    + /*
    + * Some panels only work properly with some divider combinations
    + */
    + 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");
    + RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider);
    + RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider);
    + RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider);
    + }
    +
    + RTRACE("Scanning BIOS table ...\n");
    + for(i = 0; i < 32; i++) {
    + tmp0 = BIOS_IN16(tmp + 64 + i*2);
    + if (tmp0 == 0)
    break;
    + RTRACE(" %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) -
    + 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);
    + /* Assume high active syncs for now until ATI tells me more... maybe we
    + * can probe register values here ?
    + */
    + rinfo->panel_info.hAct_high = 1;
    + rinfo->panel_info.vAct_high = 1;
    + /* Mark panel infos valid */
    + rinfo->panel_info.valid = 1;
    +
    + RTRACE("Found panel in BIOS table:\n");
    + RTRACE(" hblank: %d\n", rinfo->panel_info.hblank);
    + RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus);
    + RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width);
    + RTRACE(" vblank: %d\n", rinfo->panel_info.vblank);
    + RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus);
    + RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width);
    + RTRACE(" clock: %d\n", rinfo->panel_info.clock);
    +
    + return 0;
    + }
    + }
    +
    + RTRACE("Didn't find panel in BIOS table !\n");
    +
    + return -ENODEV;
    +}
    +
    +/*
    + * Get informations about TMDS controllers and their setup at
    + * different operating frequencies
    + */
    +void __devinit radeon_get_tmds_info(struct radeonfb_info *rinfo)
    +{
    + int i;
    + int family = rinfo->family;
    +
    + /* Get default TMDS infos for this chip */
    + for (i = 0; i < 4; i++) {
    + rinfo->tmds_pll[i].value = default_tmds_pll[family][i].value;
    + rinfo->tmds_pll[i].freq = default_tmds_pll[family][i].freq;
    + }
    +
    + /* Get whatever the firmware provides */
    + if (rinfo->radeon_get_tmds_info) {
    + rinfo->radeon_get_tmds_info(rinfo);
    + // XXX Do we care about the return value?
    + }
    +}
    +
    +int __devinit radeon_get_tmds_info_legacy(struct radeonfb_info *rinfo)
    +{
    + int offset, i, n, rev;
    +
    + offset = BIOS_IN16(rinfo->fp_bios_start + 0x34);
    + if (offset == 0)
    + return -ENODEV;
    +
    + rev = BIOS_IN8(offset);
    + RTRACE("DFP table revision: %d\n", rev);
    +
    + switch(rev) {
    + case 3:
    + n = BIOS_IN8(offset + 5) + 1;
    + if (n > 4)
    + n = 4;
    + for (i = 0; i < n; i++) {
    + /* Looks bogus ... but that's what is in X.org */
    + rinfo->tmds_pll[i].value =
    + BIOS_IN32(offset + i*10 + 0x08);
    + rinfo->tmds_pll[i].freq =
    + BIOS_IN16(offset + i*10 + 0x10);
    + }
    + return 0;
    +
    + /* revision 4 has some problem as it appears in RV280,
    + * comment it off for now, use default instead
    + */
    +#if 0
    + case 4:
    + stride = 0;
    + n = BIOS_IN8(offset 5) + 1;
    + if (n > 4)
    + n = 4;
    + for (i = 0; i < n; i++) {
    + rinfo->tmds_pll[i].value =
    + BIOS_IN32(tmp + stride + 0x08);
    + rinfo->tmds_pll[i].freq =
    + BIOS_IN16(tmp + stride + 0x10);
    + if (i == 0)
    + stride += 10;
    + else
    + stride += 6;
    + }
    + return 0;
    +#endif
    }
    + return -ENODEV;
    +}
    +
    +int __devinit radeon_get_tmds_info_atom(struct radeonfb_info *rinfo)
    +{
    + int offset, i, maxfreq;
    +
    + offset = BIOS_IN16(rinfo->atom_data_start + 18);
    + if (offset == 0)
    + return -ENODEV;

    - return pret;
    + maxfreq = BIOS_IN16(offset + 4);
    +
    + for (i = 0; i < 4; i++) {
    + rinfo->tmds_pll[i].freq = BIOS_IN16(offset + i*6 + 6);
    + /* This assumes each field in TMDS_PLL has 6 bit as
    + * in R300/R420
    + */
    + rinfo->tmds_pll[i].value =
    + ((BIOS_IN8(offset + i*6 + 8) & 0x3f) |
    + ((BIOS_IN8(offset + i*6 + 10) & 0x3f)<<6) |
    + ((BIOS_IN8(offset + i*6 + 9) & 0xf)<<12) |
    + ((BIOS_IN8(offset + i*6 + 11) & 0xf)<<16));
    + RTRACE("TMDS PLL from BIOS: %ld %x\n",
    + rinfo->tmds_pll[i].freq, rinfo->tmds_pll[i].value);
    +
    + if (maxfreq == rinfo->tmds_pll[i].freq) {
    + rinfo->tmds_pll[i].freq = 0xffffffff;
    + break;
    + }
    + }
    + return 0;
    }


    +static const char *conn_type_name[] = {
    + "NONE", "VGA", "DVI-I", "DVI-D", "DVI-A", "S-Video",
    + "Composite Video", "Internal Panel", "Digital",
    + "Unsupported", "Proprietary"
    +};
    +
    +static const char *mon_type_name[] = {
    + "None", "CRT", "LVDS Flat panel",
    + "DVI Flat panel", "Composite TV", "S-Video TV"
    +};
    +
    +static void __devinit radeon_fill_conn(struct radeon_connector *conn, int mon_type, int ddc_type, int *found_tmds, int *found_crt)
    +{
    + conn->mon_type = mon_type;
    + conn->ddc_type = ddc_type;
    +
    + // XXX what about reversed DAC/TMDS??
    +
    + switch(mon_type) {
    + case MT_CRT:
    + conn->conn_type = conn_vga;
    + conn->tmds_type = tmds_unknown;
    + conn->dac_type = (*found_crt) ? dac_tvdac: dac_primary;
    + if (ddc_type == ddc_none)
    + conn->ddc_type = (*found_crt) ? ddc_crt2 : ddc_vga;
    + *found_crt = 1;
    + break;
    + case MT_DFP:
    + conn->conn_type = conn_dvi_i;
    + conn->tmds_type = (*found_tmds) ? tmds_external: tmds_internal;
    + conn->dac_type = dac_unknown;
    + if (ddc_type == ddc_none)
    + conn->ddc_type = ddc_dvi;
    + *found_tmds = 1;
    + break;
    + case MT_LCD:
    + conn->conn_type = conn_lvds;
    + conn->tmds_type = tmds_unknown;
    + conn->dac_type = dac_unknown;
    + if (ddc_type == ddc_none)
    + conn->ddc_type = ddc_none; //heh
    + break;
    + case MT_CTV:
    + conn->conn_type = conn_ctv;
    + conn->tmds_type = tmds_unknown;
    + conn->dac_type = dac_tvdac;
    + if (ddc_type == ddc_none)
    + conn->ddc_type = ddc_vga; // XXX ddc_crt2?
    + break;
    + case MT_STV:
    + conn->conn_type = conn_stv;
    + conn->tmds_type = tmds_unknown;
    + conn->dac_type = dac_tvdac;
    + if (ddc_type == ddc_none)
    + conn->ddc_type = ddc_vga; // XXX ddc_crt2?
    + break;
    + case MT_UNKNOWN:
    + case MT_NONE:
    + conn->conn_type = conn_none;
    + conn->tmds_type = tmds_unknown;
    + conn->mon_type = MT_NONE;
    + conn->ddc_type = ddc_none;
    + conn->dac_type = dac_unknown;
    + break;
    + default:
    + break;
    + }
    + // leaves conn_digital, conn_unsupported, conn_propritetary
    +}
    +
    #if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
    /*
    * Try to find monitor informations & EDID data out of the Open Firmware
    @@ -59,33 +358,40 @@ 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,
    +static int __devinit radeon_parse_montype_prop(struct radeonfb_info *rinfo,
    + struct device_node *dp,
    + struct radeon_connector *conn,
    int hdno)
    {
    - static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
    + 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;
    -
    + int i;
    +
    RTRACE("analyzing OF properties...\n");
    pmt = of_get_property(dp, "display-type", NULL);
    if (!pmt)
    - return MT_NONE;
    + return -1;
    RTRACE("display-type: %s\n", pmt);
    - /* OF says "LCD" for DFP as well, we discriminate from the caller of this
    - * function
    - */
    - if (!strcmp(pmt, "LCD") || !strcmp(pmt, "DFP"))
    - mt = MT_DFP;
    - else if (!strcmp(pmt, "CRT"))
    - mt = MT_CRT;
    - else {
    + if (!strcmp(pmt, "LCD") || !strcmp(pmt, "DFP")) {
    + /* OF says "LCD" for DFP as well.*/
    + if (rinfo->is_mobility) {
    + conn->mon_type = MT_LCD;
    + /* Maybe check for LVDS_GEN_CNTL here ? I need to check out
    + * what OF does when booting with lid closed
    + */
    + } else{
    + conn->mon_type = MT_DFP;
    + }
    + } else if (!strcmp(pmt, "CRT")) {
    + conn->mon_type = MT_CRT;
    + } else {
    if (strcmp(pmt, "NONE") != 0)
    printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n",
    pmt);
    - return MT_NONE;
    + return -1;
    }

    for (i = 0; propnames[i] != NULL; ++i) {
    @@ -103,25 +409,36 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
    if (pedid == NULL && dp->parent && (hdno == 0))
    pedid = of_get_property(dp->parent, "EDID", NULL);
    if (pedid == NULL)
    - return mt;
    + return -1;

    tmp = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL);
    - if (!tmp)
    - return mt;
    - *out_EDID = tmp;
    - return mt;
    + conn->edid = tmp;
    +
    + {
    + int found_tmds = 0;
    + int found_crt = 0;
    + int ddc_type = ddc_none;
    + // XXX what about reversed DAC/TMDS??
    + radeon_fill_conn(conn, conn->mon_type, ddc_type, &found_crt, &found_tmds);
    + }
    +
    + return 0;
    }

    -static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no,
    - u8 **out_EDID)
    +/* return a -1 on error */
    +static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no)
    +
    {
    - struct device_node *dp;
    + struct radeon_connector *conn;
    + struct device_node *dp;

    RTRACE("radeon_probe_OF_head\n");

    - dp = rinfo->of_node;
    - while (dp == NULL)
    - return MT_NONE;
    + conn = &rinfo->connectors[head_no];
    +
    + dp = rinfo->of_node;
    + if (dp == NULL)
    + return -1;

    if (rinfo->has_CRTC2) {
    const char *pname;
    @@ -130,116 +447,284 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
    dp = dp->child;
    do {
    if (!dp)
    - return MT_NONE;
    + return -1;
    +
    pname = of_get_property(dp, "name", NULL);
    - if (!pname)
    - return MT_NONE;
    + if (!pname)
    + return -1;
    +
    len = strlen(pname);
    RTRACE("head: %s (letter: %c, head_no: %d)\n",
    pname, pname[len-1], head_no);
    if (pname[len-1] == 'A' && head_no == 0) {
    - int mt = radeon_parse_montype_prop(dp, out_EDID, 0);
    - /* Maybe check for LVDS_GEN_CNTL here ? I need to check out
    - * what OF does when booting with lid closed
    - */
    - if (mt == MT_DFP && rinfo->is_mobility)
    - mt = MT_LCD;
    - return mt;
    - } else if (pname[len-1] == 'B' && head_no == 1)
    - return radeon_parse_montype_prop(dp, out_EDID, 1);
    + return radeon_parse_montype_prop(rinfo, dp, conn, 0);
    + } else if (pname[len-1] == 'B' && head_no == 1) {
    + return radeon_parse_montype_prop(rinfo, dp, conn, 1);
    + }
    second = 1;
    dp = dp->sibling;
    } while(!second);
    } else {
    if (head_no > 0)
    - return MT_NONE;
    - return radeon_parse_montype_prop(dp, out_EDID, -1);
    + return -1;
    + return radeon_parse_montype_prop(rinfo, dp, conn, -1);
    }
    - return MT_NONE;
    + return -1;
    }
    #endif /* CONFIG_PPC_OF || CONFIG_SPARC */

    -
    -static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
    +/*
    + * Get informations about the various connectors on this card. This is
    + * the most prone to fail function as various firmwares tend to say
    + * crap or not give any info at all. The Open Firmware version is just
    + * a table of known cards for now for example. We'll probably need some
    + * additional module params to force different settings in case of
    + * misdetection here.
    + *
    + * This doesn _not_ try actual probing of whatever is plugged on those
    + * various connectors. This will be done later. We do store whatever
    + * probing info the firmware gives us though
    + */
    +void __devinit radeon_get_conn_info(struct radeonfb_info *rinfo, int ignore_conntable)
    {
    - unsigned long tmp, tmp0;
    - char stmp[30];
    int i;

    - if (!rinfo->bios_seg)
    - 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;
    - return 0;
    + /* Clear table */
    + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
    + rinfo->connectors[i].conn_type = conn_none;
    + rinfo->connectors[i].ddc_type = ddc_none;
    + rinfo->connectors[i].dac_type = dac_unknown;
    + rinfo->connectors[i].tmds_type = tmds_unknown;
    + rinfo->connectors[i].mon_type = MT_UNKNOWN;
    + rinfo->connectors[i].head = -1;
    + rinfo->heads[i] = -1;
    }
    + rinfo->num_heads = 0;
    +
    + if (ignore_conntable) {
    +#if defined(CONFIG_FB_RADEON_I2C)
    + struct radeon_connector conn;
    + int idx = 0;
    + int found_tmds = 0;
    + int found_crt = 0;
    +
    + // XXX what about reversed DAC/TMDS??
    +
    + for (i = 0; i < 4; i++) {
    + conn.ddc_type = i;
    + if (!radeon_probe_i2c_connector(rinfo, &conn)) {
    + radeon_fill_conn(&rinfo->connectors[idx++], conn.mon_type, conn.ddc_type,
    + &found_tmds, &found_crt);
    + }
    + }

    - 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);
    + /* If we failed to probe something.. */
    + if (idx)
    + goto found;
    +#endif /* CONFIG_FB_RADEON_I2C */
    + } else {
    + /* Try to obtain infos from firmware */
    + if (rinfo->radeon_get_conn_info) {
    + if (!rinfo->radeon_get_conn_info(rinfo)) {
    + goto found;
    + }
    + }
    + }

    - rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44);
    - RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
    - if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0)
    - rinfo->panel_info.pwr_delay = 2000;
    + printk(KERN_INFO "radeonfb: No connector infos, using defaults...\n");

    - /*
    - * Some panels only work properly with some divider combinations
    + /* Here, we use defaults that are common enough ... we hope
    + * For a mobility chip, we assume LVDS is on primary
    */
    - 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");
    - RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider);
    - RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider);
    - RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider);
    + if (rinfo->is_mobility) {
    + rinfo->connectors[0].conn_type = conn_lvds;
    + rinfo->connectors[0].ddc_type = ddc_dvi;
    + rinfo->connectors[0].dac_type = dac_primary;
    + rinfo->connectors[0].tmds_type = tmds_unknown;
    + rinfo->connectors[0].mon_type = MT_UNKNOWN;
    +
    + rinfo->connectors[1].conn_type = conn_dvi_d;
    + rinfo->connectors[1].ddc_type = ddc_vga;
    + rinfo->connectors[1].dac_type = dac_primary;
    + rinfo->connectors[1].tmds_type = tmds_internal;
    + rinfo->connectors[1].mon_type = MT_UNKNOWN;
    +
    + rinfo->connectors[2].conn_type = conn_stv;
    + rinfo->connectors[2].ddc_type = ddc_none;
    + rinfo->connectors[2].dac_type = dac_tvdac;
    + rinfo->connectors[2].tmds_type = tmds_unknown;
    + rinfo->connectors[2].mon_type = MT_UNKNOWN;
    + } else {
    + rinfo->connectors[0].conn_type = conn_dvi_d;
    + rinfo->connectors[0].ddc_type = ddc_dvi;
    + rinfo->connectors[0].dac_type = dac_tvdac;
    + rinfo->connectors[0].tmds_type = tmds_internal;
    + rinfo->connectors[0].mon_type = MT_UNKNOWN;
    +
    + rinfo->connectors[1].conn_type = conn_vga;
    + rinfo->connectors[1].ddc_type = ddc_vga;
    + rinfo->connectors[1].dac_type = dac_primary;
    + rinfo->connectors[1].tmds_type = tmds_unknown;
    + rinfo->connectors[1].mon_type = MT_UNKNOWN;
    +
    + if (rinfo->has_CRTC2) {
    + rinfo->connectors[1].conn_type = conn_vga;
    + rinfo->connectors[1].ddc_type = ddc_crt2;
    + rinfo->connectors[1].dac_type = dac_tvdac;
    + rinfo->connectors[1].tmds_type = tmds_unknown;
    + rinfo->connectors[1].mon_type = MT_UNKNOWN;
    + }
    }
    - RTRACE("Scanning BIOS table ...\n");
    - for(i=0; i<32; i++) {
    - tmp0 = BIOS_IN16(tmp+64+i*2);
    - if (tmp0 == 0)
    - break;
    - RTRACE(" %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) -
    - 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);
    - /* Assume high active syncs for now until ATI tells me more... maybe we
    - * can probe register values here ?
    - */
    - rinfo->panel_info.hAct_high = 1;
    - rinfo->panel_info.vAct_high = 1;
    - /* Mark panel infos valid */
    - rinfo->panel_info.valid = 1;

    - RTRACE("Found panel in BIOS table:\n");
    - RTRACE(" hblank: %d\n", rinfo->panel_info.hblank);
    - RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus);
    - RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width);
    - RTRACE(" vblank: %d\n", rinfo->panel_info.vblank);
    - RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus);
    - RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width);
    - RTRACE(" clock: %d\n", rinfo->panel_info.clock);
    -
    - return 1;
    +found:
    + /* Now, we do additional fixups */
    +
    + /* RS300 has only one DAC, force TV-DAC on VGA port */
    + if (rinfo->family == CHIP_FAMILY_RS300) {
    + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
    + if (rinfo->connectors[i].conn_type == conn_vga)
    + rinfo->connectors[i].dac_type = dac_tvdac;
    + else if (rinfo->connectors[i].dac_type != dac_unknown)
    + rinfo->connectors[i].dac_type = dac_primary;
    }
    }
    - RTRACE("Didn't find panel in BIOS table !\n");
    +
    + /* Single head chips all use primary DAC */
    + if (!rinfo->has_CRTC2)
    + rinfo->connectors[0].dac_type = dac_primary;
    +
    + return;
    +}
    +
    +#if defined CONFIG_PPC_OF || defined(CONFIG_SPARC)
    +int __devinit radeon_get_conn_info_openfirmware(struct radeonfb_info *rinfo)
    +{
    + int i;
    + int found = 0;
    +
    + /* Only two heads for OF! */
    + for(i = 0 ; i < 2 ; i++) {
    + if (!radeon_probe_OF_head(rinfo, i))
    + found = 0;
    + }
    + return found;
    +}
    +#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
    +
    +int __devinit radeon_get_conn_info_atom(struct radeonfb_info *rinfo)
    +{
    + int i, j, offset, valids;
    + int ids[RADEON_MAX_CONNECTORS];
    + u16 portinfo, tmp0;
    + int conn_index = 0;
    + int conn_add = 2;
    + int idx = 0;
    + int ddc_type, dac_type, conn_type, tmds_type, port_id;
    + int connector_found = 0;
    + int shared;
    +
    + offset = BIOS_IN16(rinfo->atom_data_start + 22);
    + if (offset == 0)
    + return -ENODEV;
    +
    + /* Again, I slightly modified X.org algorithm. I assign "primary" outputs
    + * to entries 0 and 1, and anything else goes after 2.
    + *
    + * Also, I keep an array of all port IDs matching connectors[] array,
    + * unlike X which limits itself to "crtc"'s
    + */
    + for (i = 0; i < RADEON_MAX_CONNECTORS; i++)
    + ids[i] = -1;
    +
    + valids = BIOS_IN16(offset + 4);
    + for (i = 0; i < 8; i++) {
    + shared = 0;
    + if (!(valids & (1 << i)))
    + continue;
    + portinfo = BIOS_IN16(offset + 6 + i*2);
    +
    + conn_type = (portinfo >> 4) & 0xf;
    + dac_type = (portinfo & 0xf) - 1;
    + port_id = (portinfo >> 8) & 0xf;
    + ddc_type = ddc_none;
    +
    + if ((tmp0 = BIOS_IN16(rinfo->atom_data_start + 24))) {
    + switch(BIOS_IN16(tmp0 + 4 + (27 * port_id)) * 4) {
    + case GPIO_MONID:
    + ddc_type = ddc_monid;
    + break;
    + case GPIO_DVI_DDC:
    + ddc_type = ddc_dvi;
    + break;
    + case GPIO_VGA_DDC:
    + ddc_type = ddc_vga;
    + break;
    + case GPIO_CRT2_DDC:
    + ddc_type = ddc_crt2;
    + break;
    + default:
    + ddc_type = ddc_none;
    + break;
    + }
    + }
    +
    + if (i == 3)
    + tmds_type = tmds_internal;
    + else if (i == 7)
    + tmds_type = tmds_external;
    + else
    + tmds_type = tmds_unknown;
    +
    + RTRACE("index %d port %d conn %d dac %d ddc %d tmds %d\n", i, port_id, conn_type, dac_type, ddc_type, tmds_type);
    +
    + /* Ok, now we have the port ID, look for an existing port
    + * already using this ID
    + */
    + for (j = 0; j < RADEON_MAX_CONNECTORS; j++) {
    + if (port_id != ids[j])
    + continue;
    +
    + /* This port is shared. Update the values (if needed)
    + * and probe next connector without creating a new
    + * connector entry.
    + */
    + if (tmds_type != tmds_unknown)
    + rinfo->connectors[j].tmds_type = tmds_type;
    + if (rinfo->connectors[j].dac_type == dac_unknown)
    + rinfo->connectors[j].dac_type = dac_type;
    + if (rinfo->connectors[j].ddc_type == ddc_none)
    + rinfo->connectors[j].ddc_type = ddc_type;
    +
    + shared = 1;
    + }
    + if (shared)
    + continue;
    +
    + conn_index = (ddc_type == ddc_dvi || conn_index == 1) ? 0 : 1;
    +
    + /* if the port is a TV port, or both connectors are already
    + * assigned, assign it after further in the table
    + */
    + if (conn_type == conn_ctv || conn_type == conn_stv ||
    + (rinfo->connectors[0].conn_type != conn_none &&
    + rinfo->connectors[1].conn_type != conn_none))
    + idx = conn_add++;
    + else
    + idx = conn_index;
    +
    + rinfo->connectors[idx].tmds_type = tmds_type;
    + rinfo->connectors[idx].dac_type = dac_type;
    + rinfo->connectors[idx].ddc_type = ddc_type;
    + rinfo->connectors[idx].conn_type = conn_type;
    + ids[idx] = port_id;
    +
    + /* increment connector_found for primary connectors only */
    + if (idx < 2)
    + connector_found += (idx + 1);
    + }
    +
    + if (connector_found == 0)
    + return -ENODEV;

    return 0;
    }
    @@ -248,44 +733,167 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
    * doesn't quite work yet, but it's output is still useful for
    * debugging
    */
    -static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo)
    +int __devinit radeon_get_conn_info_legacy(struct radeonfb_info *rinfo)
    {
    - int offset, chips, connectors, tmp, i, conn, type;
    -
    - static char* __conn_type_table[16] = {
    - "NONE", "Proprietary", "CRT", "DVI-I", "DVI-D", "Unknown", "Unknown",
    - "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown",
    - "Unknown", "Unknown", "Unknown"
    + int offset, i, entry, tmp;
    + int ddc_type, dac_type, conn_type, tmds_type;
    + int conn_index = 0;
    + int conn_add = 2;
    + int idx = 0;
    +
    + /* Convert legacy to real connector types */
    + const enum radeon_conn_type legacy_conn_to_type[] = {
    + conn_none,
    + conn_proprietary,
    + conn_vga,
    + conn_dvi_i,
    + conn_dvi_d,
    + conn_ctv,
    + conn_stv,
    + conn_unsupported,
    };

    - if (!rinfo->bios_seg)
    - return;
    + /* Some laptops only have one connector (VGA) listed in the connector
    + * table, we need to add LVDS in as a non-DDC display.
    + * Note, we can't assume the listed VGA will be filled in PortInfo[0],
    + * when walking through connector table. connector_found has following
    + * meaning:
    + * 0 -- nothing found,
    + * 1 -- only connectors[0] filled,
    + * 2 -- only connectors[1] filled,
    + * 3 -- both are filled.
    + *
    + * Note: I modified X.org algorithm to add additional entries if any
    + * after the second table slot. Those entries do not affect the value
    + * of connector_found. --BenH.
    + */
    + int connector_found = 0;

    offset = BIOS_IN16(rinfo->fp_bios_start + 0x50);
    - if (offset == 0) {
    - printk(KERN_WARNING "radeonfb: No connector info table detected\n");
    - return;
    + if (offset == 0)
    + return -ENODEV;
    +
    + for (i = 1; i < 4; i++) {
    + entry = offset + i*2;
    +
    + /* End of table */
    + if (!BIOS_IN8(entry) && i > 1)
    + break;
    +
    + /* Read table entry, check connector type */
    + tmp = BIOS_IN16(entry);
    + conn_type = (tmp >> 12) & 0xf;
    + if (conn_type == legacy_conn_none)
    + continue;
    + ddc_type = (tmp >> 8) & 0xf;
    + dac_type = (tmp & 0x01) ? dac_tvdac : dac_primary;
    + tmds_type = (tmp & 0x10) ? tmds_external : tmds_internal;
    +
    + /* same connector */
    + if (connector_found > 0) {
    + if (rinfo->connectors[conn_index].ddc_type == ddc_type)
    + continue;
    + }
    +
    + /* sanity checks */
    + if (ddc_type > ddc_crt2)
    + ddc_type = ddc_none;
    + if (conn_type > legacy_conn_unsupported)
    + conn_type = legacy_conn_unsupported;
    + if (conn_type != legacy_conn_dvi_d &&
    + conn_type != legacy_conn_dvi_i &&
    + tmds_type == tmds_internal)
    + tmds_type= tmds_unknown;
    +
    + /* convert connector type */
    + conn_type = legacy_conn_to_type[conn_type];
    +
    + /* internal DDC_DVI port will get assigned to connector[0], or
    + * if there is no DDC_DVI (like in some IGPs).
    + */
    + conn_index = (ddc_type == ddc_dvi || conn_index == 1) ? 0 : 1;
    +
    + /* if the port is a TV port, or both connectors are already
    + * assigned, assign it after further in the table
    + */
    + if (conn_type == conn_ctv || conn_type == conn_stv ||
    + (rinfo->connectors[0].conn_type != conn_none &&
    + rinfo->connectors[1].conn_type))
    + idx = conn_add++;
    + else
    + idx = conn_index;
    +
    + /* if table full, exit */
    + if (idx >= RADEON_MAX_CONNECTORS) {
    + printk(KERN_WARNING "radeonfb: Connector table full !\n");
    + break;
    + }
    + rinfo->connectors[idx].conn_type = conn_type;
    + rinfo->connectors[idx].ddc_type = ddc_type;
    + rinfo->connectors[idx].dac_type = dac_type;
    + rinfo->connectors[idx].tmds_type = tmds_type;
    +
    + /* increment connector_found for primary connectors only */
    + if (idx < 2)
    + connector_found += (idx + 1);
    }

    - /* Don't do much more at this point but displaying the data if
    - * DEBUG is enabled
    - */
    - chips = BIOS_IN8(offset++) >> 4;
    - RTRACE("%d chips in connector info\n", chips);
    - for (i = 0; i < chips; i++) {
    - tmp = BIOS_IN8(offset++);
    - connectors = tmp & 0x0f;
    - RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors);
    - for (conn = 0; ; conn++) {
    - tmp = BIOS_IN16(offset);
    - if (tmp == 0)
    - break;
    - offset += 2;
    - type = (tmp >> 12) & 0x0f;
    - RTRACE(" * connector %d of type %d (%s) : %04x\n",
    - conn, type, __conn_type_table[type], tmp);
    + if (rinfo->is_mobility) {
    + /* For the cases where only one VGA connector is found,
    + * we assume LVDS is not listed in the connector table,
    + * add it in here as the first port.
    + *
    + * TODO: Check what's up with laptops that have a DVI output
    + * and no LVDS entry in the table. I suspect some thinkpads
    + * may play trick with us here... We may want to check the
    + * presence of a panel via LVDS_GEN_CNTL to be sure...
    + */
    + if ((connector_found < 3) &&
    + (rinfo->connectors[idx].conn_type == conn_vga)) {
    + if (connector_found == 1) {
    + memcpy(&rinfo->connectors[1], &rinfo->connectors[0],
    + sizeof(struct radeon_connector));
    + }
    +
    + /* Fixme: TV DAC is probably elsewhere ... */
    + rinfo->connectors[0].dac_type = dac_tvdac;
    + rinfo->connectors[0].tmds_type = tmds_unknown;
    + rinfo->connectors[0].ddc_type = ddc_none;
    + rinfo->connectors[0].conn_type = conn_proprietary;
    +
    + printk(KERN_WARNING "radeonfb: LVDS port is not in connector table, added in.\n");
    + if (connector_found == 0)
    + connector_found = 1;
    + else
    + connector_found = 3;
    }
    +
    + /* Check for LCD DDC info table */
    + if ((offset = BIOS_IN16(rinfo->fp_bios_start + 0x42))) {
    + if ((tmp = BIOS_IN16(offset + 0x15))) {
    + if ((ddc_type = BIOS_IN8(tmp+2) & 0x07)) {
    + rinfo->connectors[0].ddc_type = ddc_type;
    + printk(KERN_WARNING "radeonfb: LCD DDC Info Table found, "
    + "forcing primary port to %d\n",
    + ddc_type);
    + }
    + }
    + }
    + } else if (connector_found == 2) {
    + memcpy(&rinfo->connectors[0], &rinfo->connectors[1],
    + sizeof (struct radeon_connector));
    + rinfo->connectors[1].dac_type = dac_unknown;
    + rinfo->connectors[1].tmds_type = tmds_unknown;
    + rinfo->connectors[1].ddc_type = ddc_none;
    + rinfo->connectors[1].conn_type = conn_none;
    + connector_found = 1;
    }
    +
    + if (connector_found == 0)
    + return -ENODEV;
    +
    + /* External TMDS Table, not used now */
    + return 0;
    }


    @@ -362,6 +970,51 @@ static int __devinit radeon_crt_is_connected(struct radeonfb_info *rinfo, int is
    return connected ? MT_CRT : MT_NONE;
    }

    +/* Find if the desired connector and monitor are compatible */
    +static int __devinit radeon_conn_monitor_compatible(int mon_type, int conn_type)
    +{
    + switch(mon_type) {
    + case MT_CRT:
    + return ((conn_type == conn_vga) || (conn_type == conn_dvi_a));
    + case MT_DFP:
    + return ((conn_type == conn_dvi_i) || (conn_type == conn_dvi_d));
    + case MT_LCD:
    + return (conn_type == conn_lvds);
    + case MT_CTV:
    + return (conn_type == conn_ctv);
    + case MT_STV:
    + return (conn_type == conn_stv);
    + case MT_UNKNOWN:
    + case MT_NONE:
    + default:
    + return 0;
    + }
    + // leaves conn_digital, conn_unsupported, conn_propritetary
    +}
    +
    +/* Find a suitable connector for this display type */
    +static int __devinit radeon_find_connector_for_mon(struct radeonfb_info *rinfo, int mon_type)
    +{
    + int i;
    +
    + if (mon_type <= MT_NONE)
    + return 0;
    +
    + for (i = 0; i < RADEON_MAX_CONNECTORS ; i++) {
    + if (radeon_conn_monitor_compatible(mon_type, rinfo->connectors[i].conn_type) &&
    + (rinfo->connectors[i].mon_type <= MT_NONE)) {
    + rinfo->connectors[i].mon_type = mon_type;
    + rinfo->connectors[i].head = rinfo->num_heads;
    + rinfo->heads[rinfo->num_heads] = i;
    + rinfo->num_heads++;
    + return 0;
    + }
    + }
    +
    + printk(KERN_INFO "radeonfb: couldn't find a connector for monitor %d\n", mon_type);
    + return -1;
    +}
    +
    /*
    * Parse the "monitor_layout" string if any. This code is mostly
    * copied from XFree's radeon driver
    @@ -407,19 +1060,20 @@ static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
    s1[i] = 0;
    s2[0] = 0;
    }
    +
    if (strcmp(s1, "CRT") == 0)
    - rinfo->mon1_type = MT_CRT;
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    else if (strcmp(s1, "TMDS") == 0)
    - rinfo->mon1_type = MT_DFP;
    + radeon_find_connector_for_mon(rinfo, MT_DFP);
    else if (strcmp(s1, "LVDS") == 0)
    - rinfo->mon1_type = MT_LCD;
    + radeon_find_connector_for_mon(rinfo, MT_LCD);

    if (strcmp(s2, "CRT") == 0)
    - rinfo->mon2_type = MT_CRT;
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    else if (strcmp(s2, "TMDS") == 0)
    - rinfo->mon2_type = MT_DFP;
    + radeon_find_connector_for_mon(rinfo, MT_DFP);
    else if (strcmp(s2, "LVDS") == 0)
    - rinfo->mon2_type = MT_LCD;
    + radeon_find_connector_for_mon(rinfo, MT_LCD);

    return 1;
    }
    @@ -433,12 +1087,7 @@ static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
    void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
    const char *monitor_layout, int ignore_edid)
    {
    -#ifdef CONFIG_FB_RADEON_I2C
    - int ddc_crt2_used = 0;
    -#endif
    - int tmp, i;
    -
    - radeon_parse_connector_info(rinfo);
    + int i;

    if (radeon_parse_monitor_layout(rinfo, monitor_layout)) {

    @@ -449,214 +1098,142 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
    * a layout for each card ?
    */

    - RTRACE("Using specified monitor layout: %s", monitor_layout);
    + RTRACE("Using specified monitor layout: %s\n", monitor_layout);
    #ifdef CONFIG_FB_RADEON_I2C
    if (!ignore_edid) {
    - if (rinfo->mon1_type != MT_NONE)
    - 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;
    + int mon_type;
    +
    + /* If the DDC detection fails,
    + we still want to use the user's specified layout! */
    + mon_type = PRIMARY_MONITOR(rinfo);
    +
    + if (PRIMARY_MONITOR(rinfo) > MT_NONE)
    + if (radeon_probe_i2c_connector(rinfo, &PRIMARY_HEAD(rinfo)))
    + PRIMARY_MONITOR(rinfo) = mon_type;
    + if (SECONDARY_HEAD_PRESENT(rinfo)) {
    + mon_type = SECONDARY_MONITOR(rinfo);
    + if (SECONDARY_MONITOR(rinfo) > MT_NONE) {
    + if (radeon_probe_i2c_connector(rinfo, &SECONDARY_HEAD(rinfo)))
    + rinfo->connectors[rinfo->heads[1]].mon_type = mon_type;
    }
    - 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;
    - } else {
    - rinfo->mon1_type = MT_CRT;
    - printk(KERN_INFO "radeonfb: No valid monitor, assuming CRT on first port\n");
    - }
    - rinfo->mon2_type = MT_NONE;
    - rinfo->mon2_EDID = NULL;
    +
    + /* If the user specified a bogus monitor layout... */
    + if (PRIMARY_MONITOR(rinfo) <= MT_NONE) {
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    + printk(KERN_INFO "radeonfb: No valid monitor, assuming CRT on first port\n");
    }
    } else {
    /*
    * Auto-detecting display type (well... trying to ...)
    */
    -
    - RTRACE("Starting monitor auto detection...\n");

    -#if 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;
    + RTRACE("Starting monitor auto detection...\n");

    - 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);
    -#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_vga,
    - &rinfo->mon1_EDID);
    - if (rinfo->mon1_type == MT_NONE)
    - rinfo->mon1_type =
    - radeon_probe_i2c_connector(rinfo, ddc_crt2,
    - &rinfo->mon1_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 &&
    - (tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) {
    - for (i = 1; i < 4; i++) {
    - unsigned int tmp0;
    -
    - if (!BIOS_IN8(tmp + i*2) && i > 1)
    + /* Probe each connector */
    + for(i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
    + if (PRIMARY_MONITOR(rinfo) > MT_NONE)
    + /* only one head */
    break;
    - tmp0 = BIOS_IN16(tmp + i*2);
    - if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) {
    - rinfo->reversed_DAC = 1;
    - printk(KERN_INFO "radeonfb: Reversed DACs detected\n");
    - }
    - if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) {
    - rinfo->reversed_TMDS = 1;
    - printk(KERN_INFO "radeonfb: Reversed TMDS detected\n");
    + if (!radeon_probe_i2c_connector(rinfo, &rinfo->connectors[i])) {
    + rinfo->heads[rinfo->num_heads] = i;
    + rinfo->connectors[i].head = rinfo->num_heads++;
    }
    }
    +#endif /* CONFIG_FB_RADEON_I2C */
    + if (PRIMARY_MONITOR(rinfo) <= MT_NONE) {
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    + }
    + goto bail;
    }

    - /*
    - * 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 */
    + /* Probe heads */
    #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;
    - }
    -#endif /* CONFIG_FB_RADEON_I2C */
    - if (rinfo->mon1_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");
    + /* Probe each connector in turn. */
    + for(i = 0; i < RADEON_MAX_CONNECTORS; i++) {
    + if (rinfo->connectors[i].mon_type > MT_NONE)
    + /* Don't probe "detected" stuff again */
    + continue;
    + if (!radeon_probe_i2c_connector(rinfo, &rinfo->connectors[i])) {
    + rinfo->heads[rinfo->num_heads] = i;
    + rinfo->connectors[i].head = rinfo->num_heads++;
    + }
    }
    - 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;
    + /* Mobility chips usually have LCDs... */
    + if ((PRIMARY_MONITOR(rinfo) <= MT_NONE) &&
    + rinfo->is_mobility &&
    + ((rinfo->bios_seg && (INREG(BIOS_4_SCRATCH) & 4)) ||
    + (INREG(LVDS_GEN_CNTL) & (LVDS_EN|LVDS_ON)))) {
    + printk(KERN_INFO "radeonfb: Non-DDC laptop panel detected\n");
    + radeon_find_connector_for_mon(rinfo, MT_LCD);
    + if (rinfo->radeon_get_lvds_info) {
    + rinfo->radeon_get_lvds_info(rinfo);
    + }
    }

    - /*
    - * Deal with reversed TMDS
    - */
    - 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)
    - rinfo->reversed_DAC ^= 1;
    - }
    + /* Probe for monitors on the primary and secondary crtc heads */
    + if (PRIMARY_MONITOR(rinfo) <= MT_NONE)
    + radeon_find_connector_for_mon(rinfo, radeon_crt_is_connected(rinfo, 1));
    +
    + /* If we still haven't found anything, just force it to be on the CRT.. */
    + if (PRIMARY_MONITOR(rinfo) <= MT_NONE)
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    +
    + /* Always keep internal TMDS as primary head */
    + if (SECONDARY_HEAD_PRESENT(rinfo) &&
    + (SECONDARY_HEAD(rinfo).tmds_type == tmds_internal) &&
    + (SECONDARY_MONITOR(rinfo) == MT_DFP)) {
    + int head = rinfo->heads[0];
    + rinfo->heads[0] = rinfo->heads[1];
    + rinfo->heads[1] = head;
    }
    }
    - if (ignore_edid) {
    - kfree(rinfo->mon1_EDID);
    - rinfo->mon1_EDID = NULL;
    - kfree(rinfo->mon2_EDID);
    - rinfo->mon2_EDID = NULL;
    +bail:
    +
    + /* Dump out the heads we've found so far */
    + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
    + if (rinfo->connectors[i].conn_type == conn_none)
    + continue;
    + printk(KERN_INFO " * Connector %d is %s. Head %d, Monitor: %s ", i + 1,
    + conn_type_name[rinfo->connectors[i].conn_type],
    + rinfo->connectors[i].head,
    + rinfo->connectors[i].mon_type == MT_UNKNOWN ?
    + "Not Probed Yet" :
    + mon_type_name[rinfo->connectors[i].mon_type]);
    +
    + if (rinfo->connectors[i].edid)
    + printk("(EDID probed)\n");
    + else
    + printk("\n");
    +
    + printk(KERN_INFO " ddc port: %d, dac: %d, tmds: %d\n",
    + rinfo->connectors[i].ddc_type,
    + rinfo->connectors[i].dac_type,
    + rinfo->connectors[i].tmds_type);
    }
    -
    - 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");
    - 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");
    }


    -/*
    - * This functions applyes 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)
    -{
    #ifdef CONFIG_PPC_OF
    +int __devinit radeon_get_lvds_info_openfirmware(struct radeonfb_info *rinfo)
    +{
    +
    /*
    * 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
    - && rinfo->is_mobility) {
    + if (!rinfo->panel_info.use_bios_dividers && (PRIMARY_MONITOR(rinfo) == MT_LCD) &&
    + rinfo->is_mobility) {
    int ppll_div_sel;
    u32 ppll_divn;
    ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
    @@ -667,15 +1244,16 @@ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo)
    rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7;
    rinfo->panel_info.use_bios_dividers = 1;

    - printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x "
    + printk(KERN_INFO "Using Firmware dividers 0x%08x "
    "from PPLL %d\n",
    rinfo->panel_info.fbk_divider |
    (rinfo->panel_info.post_divider << 16),
    ppll_div_sel);
    + return 0;
    }
    -#endif /* CONFIG_PPC_OF */
    + return -ENODEV;
    }
    -
    +#endif /* CONFIG_PPC_OF */

    /*
    * Fill up panel infos from a mode definition, either returned by the EDID
    @@ -688,18 +1266,18 @@ static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_
    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->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->panel_info.vblank = var->upper_margin +
    (var->lower_margin + var->vsync_len);
    rinfo->panel_info.hAct_high =
    (var->sync & FB_SYNC_HOR_HIGH_ACT) != 0;
    rinfo->panel_info.vAct_high =
    (var->sync & FB_SYNC_VERT_HIGH_ACT) != 0;
    rinfo->panel_info.valid = 1;
    - /* We use a default of 200ms for the panel power delay,
    + /* 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 ?)
    @@ -742,22 +1320,34 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
    info->var = radeonfb_default_var;
    INIT_LIST_HEAD(&info->modelist);

    - /*
    - * First check out what BIOS has to say
    - */
    - if (rinfo->mon1_type == MT_LCD)
    - radeon_get_panel_info_BIOS(rinfo);
    + /* If we're an LCD and don't have a valid setup... */
    + if ((PRIMARY_MONITOR(rinfo) == MT_LCD) &&
    + !rinfo->panel_info.valid &&
    + rinfo->radeon_get_lvds_info) {
    + rinfo->radeon_get_lvds_info(rinfo);
    + }
    +
    +#if 0
    + /* If we're a mobility and still haven't detected a screen..? */
    + if ((PRIMARY_MONITOR(rinfo) <= MT_NONE) &&
    + rinfo->is_mobility &&
    + rinfo->radeon_get_lvds_info) {
    + if (!rinfo->radeon_get_lvds_info(rinfo))
    + radeon_find_connector_for_mon(rinfo, MT_LCD);
    + }
    +#endif

    /*
    * 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->panel_info.use_bios_dividers &&
    + (PRIMARY_MONITOR(rinfo) != MT_CRT) &&
    + PRIMARY_HEAD(rinfo).edid) {
    struct fb_var_screeninfo var;
    RTRACE("Parsing EDID data for panel info\n");
    - if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {
    + if (fb_parse_edid(PRIMARY_HEAD(rinfo).edid, &var) == 0) {
    if (var.xres >= rinfo->panel_info.xres &&
    var.yres >= rinfo->panel_info.yres)
    radeon_var_to_panel_info(rinfo, &var);
    @@ -765,15 +1355,10 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
    }

    /*
    - * Do any additional platform/arch fixups to the panel infos
    - */
    - radeon_fixup_panel_info(rinfo);
    -
    - /*
    * 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 ((PRIMARY_MONITOR(rinfo) != MT_CRT) && rinfo->panel_info.valid) {
    struct fb_var_screeninfo *var = &info->var;

    RTRACE("Setting up default mode based on panel info\n");
    @@ -804,22 +1389,21 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
    /*
    * Now build modedb from EDID
    */
    - if (rinfo->mon1_EDID) {
    - fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs);
    + if (PRIMARY_HEAD(rinfo).edid) {
    + fb_edid_to_monspecs(PRIMARY_HEAD(rinfo).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;
    + PRIMARY_HEAD(rinfo).modedb = info->monspecs.modedb;
    + PRIMARY_HEAD(rinfo).modedb_size = info->monspecs.modedb_len;
    }

    -
    /*
    * 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 ((PRIMARY_MONITOR(rinfo) != MT_CRT) && !rinfo->panel_info.valid) {
    struct fb_videomode *modedb;
    int dbsize;
    char modename[32];
    @@ -833,25 +1417,26 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
    }
    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;
    + radeon_find_connector_for_mon(rinfo, 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;
    + modedb = PRIMARY_HEAD(rinfo).modedb;
    + dbsize = PRIMARY_HEAD(rinfo).modedb_size;
    snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->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;
    + radeon_find_connector_for_mon(rinfo, MT_CRT);
    goto pickup_default;
    }
    has_default_mode = 1;
    + radeon_find_connector_for_mon(rinfo, MT_LCD);
    radeon_var_to_panel_info(rinfo, &info->var);
    }

    - pickup_default:
    +pickup_default:
    /*
    * Apply passed-in mode option if any
    */
    @@ -860,7 +1445,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
    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
    @@ -947,14 +1532,14 @@ int radeon_match_mode(struct radeonfb_info *rinfo,
    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 (PRIMARY_HEAD(rinfo).modedb) {
    + db = PRIMARY_HEAD(rinfo).modedb;
    + dbsize = PRIMARY_HEAD(rinfo).modedb_size;
    native_db = 1;
    }

    /* Check if we have a scaler allowing any fancy mode */
    - has_rmx = rinfo->mon1_type == MT_LCD || rinfo->mon1_type == MT_DFP;
    + has_rmx = (PRIMARY_MONITOR(rinfo) == MT_LCD) || (PRIMARY_MONITOR(rinfo) == MT_DFP);

    /* 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 +1552,7 @@ int radeon_match_mode(struct radeonfb_info *rinfo,
    * 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 && PRIMARY_HEAD(rinfo).modedb)
    if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info))
    return -EINVAL;
    return 0;
    @@ -979,7 +1564,7 @@ int radeon_match_mode(struct radeonfb_info *rinfo,
    int d;

    if (db[i].yres < src->yres)
    - continue;
    + continue;
    if (db[i].xres < src->xres)
    continue;
    d = radeon_compare_modes(src, &db[i]);
    diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
    index 7ebffcd..9d0b161 100644
    --- a/drivers/video/aty/radeonfb.h
    +++ b/drivers/video/aty/radeonfb.h
    @@ -26,6 +26,8 @@
    * Most of the definitions here are adapted right from XFree86 *
    ***************************************************************/

    +/* Sorry, we have to limit video ram to 128M */
    +#define MAX_VRAM (128*1024*1024)

    /*
    * Chip families. Must fit in the low 16 bits of a long word
    @@ -47,7 +49,8 @@ enum radeon_family {
    CHIP_FAMILY_R350,
    CHIP_FAMILY_RV350,
    CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */
    - CHIP_FAMILY_R420, /* R420/R423/M18 */
    + CHIP_FAMILY_RV410, /* RV410/M26 */
    + CHIP_FAMILY_R420, /* R420/R423/R480/M18 */
    CHIP_FAMILY_RS480,
    CHIP_FAMILY_LAST,
    };
    @@ -65,6 +68,7 @@ enum radeon_family {
    ((rinfo)->family == CHIP_FAMILY_RV350) || \
    ((rinfo)->family == CHIP_FAMILY_R350) || \
    ((rinfo)->family == CHIP_FAMILY_RV380) || \
    + ((rinfo)->family == CHIP_FAMILY_RV410) || \
    ((rinfo)->family == CHIP_FAMILY_R420) || \
    ((rinfo)->family == CHIP_FAMILY_RS480) )

    @@ -88,11 +92,50 @@ enum radeon_errata {
    CHIP_ERRATA_PLL_DELAY = 0x00000004,
    };

    +/*
    + * DDC i2c ports
    + */
    +enum radeon_ddc_type {
    + ddc_none = -1,
    + ddc_monid = 0,
    + ddc_dvi,
    + ddc_vga,
    + ddc_crt2,
    +};
    +
    +/*
    + * Connector types
    + */
    +enum radeon_legacy_conn_type {
    + legacy_conn_none = 0,
    + legacy_conn_proprietary,
    + legacy_conn_crt,
    + legacy_conn_dvi_i,
    + legacy_conn_dvi_d,
    + legacy_conn_ctv,
    + legacy_conn_stv,
    + legacy_conn_unsupported,
    +};
    +
    +enum radeon_conn_type {
    + conn_none = 0,
    + conn_vga,
    + conn_dvi_i,
    + conn_dvi_d,
    + conn_dvi_a,
    + conn_stv,
    + conn_ctv,
    + conn_lvds,
    + conn_digital,
    + conn_unsupported,
    + conn_proprietary,
    +};

    /*
    * Monitor types
    */
    -enum radeon_montype {
    +enum radeon_mon_type {
    + MT_UNKNOWN = -1,
    MT_NONE = 0,
    MT_CRT, /* CRT */
    MT_LCD, /* LCD */
    @@ -102,27 +145,45 @@ enum radeon_montype {
    };

    /*
    - * DDC i2c ports
    + * DAC types
    */
    -enum ddc_type {
    - ddc_none,
    - ddc_monid,
    - ddc_dvi,
    - ddc_vga,
    - ddc_crt2,
    +enum radeon_dac_type {
    + dac_unknown = -1,
    + dac_primary = 0,
    + dac_tvdac = 1,
    };

    /*
    - * Connector types
    + * TMDS types
    */
    -enum conn_type {
    - conn_none,
    - conn_proprietary,
    - conn_crt,
    - conn_DVI_I,
    - conn_DVI_D,
    +enum radeon_tmds_type {
    + tmds_unknown = -1,
    + tmds_internal = 0,
    + tmds_external = 1,
    };

    +/*
    + * Each connector gets this structure associated with it,
    + * containing infos about the connector wiring and about
    + * whatever has been detected on it
    + */
    +struct radeon_connector {
    + enum radeon_conn_type conn_type;
    + enum radeon_ddc_type ddc_type;
    + enum radeon_dac_type dac_type;
    + enum radeon_tmds_type tmds_type;
    + enum radeon_mon_type mon_type;
    + u8 *edid;
    + struct fb_videomode *modedb;
    + unsigned int modedb_size;
    +
    + int head;
    +};
    +
    +/*
    + * Currently, the driver deals with at most 4 connectors
    + */
    +#define RADEON_MAX_CONNECTORS 4

    /*
    * PLL infos
    @@ -130,11 +191,19 @@ enum conn_type {
    struct pll_info {
    int ppll_max;
    int ppll_min;
    - int sclk, mclk;
    + int sclk;
    + int mclk;
    int ref_div;
    int ref_clk;
    };

    +/*
    + * TMDS PLL infos
    + */
    +struct radeon_tmds_pll_info {
    + long freq;
    + u32 value;
    +};

    /*
    * This structure contains the various registers manipulated by this
    @@ -301,6 +370,20 @@ struct radeonfb_info {
    void __iomem *bios_seg;
    int fp_bios_start;

    + int is_atom_bios;
    + int atom_data_start;
    +
    + /* BIOS Functions */
    + int (*radeon_get_pll_info)(struct radeonfb_info *rinfo);
    + int (*radeon_get_lvds_info)(struct radeonfb_info *rinfo);
    + int (*radeon_get_conn_info)(struct radeonfb_info *rinfo);
    + int (*radeon_get_tmds_info)(struct radeonfb_info *rinfo);
    +
    + /* Connector infos */
    + struct radeon_connector connectors[RADEON_MAX_CONNECTORS];
    + int heads[RADEON_MAX_CONNECTORS]; // index into connectors.
    + int num_heads; // number of heads.
    +
    u32 pseudo_palette[17];
    struct { u8 red, green, blue, pad; }
    palette[256];
    @@ -319,15 +402,8 @@ struct radeonfb_info {
    int has_CRTC2;
    int is_mobility;
    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 radeon_tmds_pll_info tmds_pll[4];

    u32 dp_gui_master_cntl;

    @@ -359,24 +435,19 @@ struct radeonfb_info {
    };


    -#define PRIMARY_MONITOR(rinfo) (rinfo->mon1_type)
    +#define PRIMARY_HEAD(rinfo) (rinfo->connectors[rinfo->heads[0]])
    +#define SECONDARY_HEAD(rinfo) (rinfo->connectors[rinfo->heads[1]])
    +
    +#define SECONDARY_HEAD_PRESENT(rinfo) (rinfo->heads[1] != -1)

    +#define PRIMARY_MONITOR(rinfo) (rinfo->connectors[rinfo->heads[0]].mon_type)
    +#define SECONDARY_MONITOR(rinfo) ((SECONDARY_HEAD_PRESENT(rinfo) ? (rinfo->connectors[rinfo->heads[1]].mon_type) : MT_NONE))

    /*
    * Debugging stuffs
    */
    -#ifdef CONFIG_FB_RADEON_DEBUG
    -#define DEBUG 1
    -#else
    -#define DEBUG 0
    -#endif
    -
    -#if DEBUG
    -#define RTRACE printk
    -#else
    -#define RTRACE if(0) printk
    -#endif
    -
    +extern int radeonfb_debug;
    +#define RTRACE if(radeonfb_debug) printk

    /*
    * IO macros
    @@ -599,7 +670,7 @@ static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
    /* I2C Functions */
    extern void radeon_create_i2c_busses(struct radeonfb_info *rinfo);
    extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo);
    -extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);
    +extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, struct radeon_connector *conn);

    /* PM Functions */
    extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
    @@ -637,4 +708,18 @@ static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
    static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
    #endif

    +/* Bios functions. Fix this. */
    +extern void __devinit radeon_get_conn_info(struct radeonfb_info *rinfo, int ignore_conntable);
    +extern void __devinit radeon_get_tmds_info(struct radeonfb_info *rinfo);
    +
    +extern int __devinit radeon_get_lvds_info_atom(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_lvds_info_legacy(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_conn_info_atom(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_conn_info_legacy(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_tmds_info_legacy(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_tmds_info_atom(struct radeonfb_info *rinfo);
    +#ifdef CONFIG_PPC_OF
    +extern int __devinit radeon_get_lvds_info_openfirmware(struct radeonfb_info *rinfo);
    +extern int __devinit radeon_get_conn_info_openfirmware(struct radeonfb_info *rinfo);
    +#endif
    #endif /* __RADEONFB_H__ */


    Luca
    --
    "New processes are created by other processes, just like new
    humans. New humans are created by other humans, of course,
    not by processes." -- Unix System Administration Handbook
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-05-17 22:03    [W:0.209 / U:90.840 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site