+ radeonfb-atom-bios-support-new-head-code-fixes.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled
     radeonfb: ATOM BIOS support, new head code, fixes
has been added to the -mm tree.  Its filename is
     radeonfb-atom-bios-support-new-head-code-fixes.patch

See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find
out what to do about this

------------------------------------------------------
Subject: radeonfb: ATOM BIOS support, new head code, fixes
From: Solomon Peachy <pizza@xxxxxxxxxxxx>

This is a large patch, but the short summary is that it's necessary for people
with newer radeon cards to use radeonfb.  The head detection code has also
been rewritten to be considerably more robust.  

 New stuff:
  * ATOM BIOS support for newer Radeon cards.
  * Virtualize the BIOS access functions; This way all of the
    ATOM/Legacy/OpenFirmare/etc is self-contained. 
  * All new connector/head detection code that uses bios/firmware
    defaults whenever possible.  This works much better than the old 
    code with my limited test gear.
  * Card IDs for all known Radeon X300/X600/X700/X800/X850 cards; ie all 
    R400 variants; they get the same tweaks as R300 cards. R520 aka X1k 
    is NOT supported.

 Fixes:
  * Handle bogus PLL divider with sane default.
  * Default PLL clocks for R420 and its variants.
  * Cap VRAM at 128M max
  * add default_dnclk to builtin argument parsing
  * Expand default mmio size to its max of 64K
  * Some init tweaks for R300 & RS300 cards.

See bugzilla #6215 for further details, including some user feedback.

Note that the "new memmap" stuff has not been ported over yet, and I 
have no OpenFirmware hardware so I can't be sure I didn't break that.

Signed-off-by: Solomon Peachy <pizza@xxxxxxxxxxxx>
Cc: Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx>
Cc: "Antonino A. Daplas" <adaplas@xxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

 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      |  453 ++++++---
 drivers/video/aty/radeon_i2c.c       |   62 -
 drivers/video/aty/radeon_monitor.c   | 1199 ++++++++++++++++++-------
 drivers/video/aty/radeonfb.h         |  163 ++-
 7 files changed, 1419 insertions(+), 513 deletions(-)

diff -puN drivers/video/aty/ati_ids.h~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/ati_ids.h
--- a/drivers/video/aty/ati_ids.h~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/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
 
diff -puN drivers/video/aty/radeon_accel.c~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeon_accel.c
--- a/drivers/video/aty/radeon_accel.c~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/drivers/video/aty/radeon_accel.c
@@ -203,9 +203,7 @@ void radeonfb_engine_reset(struct radeon
 	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 radeon
 	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 radeon
 {
 	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 -puN drivers/video/aty/radeon_backlight.c~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeon_backlight.c
--- a/drivers/video/aty/radeon_backlight.c~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/drivers/video/aty/radeon_backlight.c
@@ -58,7 +58,7 @@ static int radeon_bl_update_status(struc
 	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
@@ -146,7 +146,7 @@ void radeonfb_bl_init(struct radeonfb_in
 	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 -puN drivers/video/aty/radeon_base.c~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeon_base.c
--- a/drivers/video/aty/radeon_base.c~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/drivers/video/aty/radeon_base.c
@@ -3,6 +3,7 @@
  *
  *	framebuffer driver for ATI Radeon chipset video boards
  *
+ *	Copyright 2006	Solomon Peachy <pizza@xxxxxxxxxxxx>
  *	Copyright 2003	Ben. Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx>
  *	Copyright 2000	Ani Joshi <ajoshi@xxxxxxxxxxxxxxxxxxx>
  *
@@ -50,7 +51,7 @@
  */
 
 
-#define RADEON_VERSION	"0.2.0"
+#define RADEON_VERSION	"0.3.0"
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -180,6 +181,7 @@ static struct pci_device_id radeonfb_pci
 	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),
@@ -190,7 +192,7 @@ static struct pci_device_id radeonfb_pci
 	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),
@@ -201,6 +203,19 @@ static struct pci_device_id radeonfb_pci
 	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),
@@ -208,7 +223,9 @@ static struct pci_device_id radeonfb_pci
 	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),
@@ -217,6 +234,24 @@ static struct pci_device_id radeonfb_pci
 	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),
@@ -259,6 +294,7 @@ 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;
@@ -269,6 +305,12 @@ static int nomtrr = 0;
 static int force_sleep;
 static int ignore_devlist;
 
+#ifdef CONFIG_FB_RADEON_DEBUG
+int radeonfb_debug = 1;
+#else
+int radeonfb_debug = 0;
+#endif
+
 /*
  * prototypes
  */
@@ -324,7 +366,7 @@ static int __devinit radeon_map_ROM(stru
 	 * 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 {
@@ -410,7 +452,7 @@ static int  __devinit radeon_find_mem_vb
  * 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;
@@ -433,6 +475,7 @@ static int __devinit radeon_read_xtal_OF
 	if (val && *val)
 		rinfo->pll.mclk = (*val) / 10;
 
+	RTRACE("Retrieved PLL infos from Open Firmware\n");
        	return 0;
 }
 #endif /* CONFIG_PPC_OF */
@@ -575,10 +618,88 @@ static int __devinit radeon_probe_pll_pa
 	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)
+{
+#ifdef CONFIG_PPC_OF
+	  rinfo->is_atom_bios = 0;
+	  rinfo->get_pll_info = radeon_get_pll_info_openfirmware;
+	  rinfo->get_lvds_info = radeon_get_lvds_info_openfirmware;
+	  rinfo->radeon_get_tmds_info = NULL;
+	  rinfo->get_conn_info = radeon_get_conn_info_openfirmware;
+#else
+	  int tmp = rinfo->fp_bios_start + 4;
+
+	  if ((BIOS_IN8(tmp) == 'A' &&
+	       BIOS_IN8(tmp+1) == 'T' &&
+	       BIOS_IN8(tmp+2) == 'O' &&
+	       BIOS_IN8(tmp+3) == 'M') ||
+	      (BIOS_IN8(tmp) == 'M' &&
+	       BIOS_IN8(tmp+1) == 'O' &&
+	       BIOS_IN8(tmp+2) == 'T' &&
+	       BIOS_IN8(tmp+3) == 'A')) {
+		  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 */
+
+}
+
 /*
  * 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
@@ -630,46 +751,30 @@ static void __devinit radeon_get_pllinfo
 	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;
-
 
-#ifdef CONFIG_PPC_OF
 	/*
-	 * Retrieve PLL infos from Open Firmware first
+	 * If we have a way to retrieve the PLL information, do so.
 	 */
-       	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 */
-
-	/*
-	 * Check out if we have an X86 which gave us some PLL informations
-	 * and if yes, retrieve them
-	 */
-	if (!force_measure_pll && rinfo->bios_seg) {
-		u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
-
-		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) {
@@ -683,6 +788,22 @@ static void __devinit radeon_get_pllinfo
        	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
@@ -698,7 +819,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)
@@ -839,7 +960,7 @@ static int radeonfb_pan_display (struct 
         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;
@@ -923,6 +1044,7 @@ int radeon_screen_blank(struct radeonfb_
         u32 val;
 	u32 tmp_pix_clks;
 	int unblank = 0;
+	int i;
 
 	if (rinfo->lock_blank)
 		return 0;
@@ -952,78 +1074,80 @@ int radeon_screen_blank(struct radeonfb_
         }
 	OUTREG(CRTC_EXT_CNTL, val);
 
+	for (i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
+		if (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;
+			} else {
+				val |= LVDS_DISPLAY_DIS;
+				OUTREG(LVDS_GEN_CNTL, val);
 
-			/* 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);
+				/* 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;
 	}
 
 	/* let fbcon do a soft blank for us */
@@ -1274,10 +1398,7 @@ static void radeon_write_pll_regs(struct
 	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.
@@ -1374,6 +1495,7 @@ void radeon_write_mode (struct radeonfb_
 	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);
 
@@ -1884,7 +2006,7 @@ static int __devinit radeon_set_fbinfo (
         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);
@@ -1988,9 +2110,7 @@ static void radeon_identify_vram(struct 
 	u32 tmp;
 
 	/* framebuffer size */
-        if ((rinfo->family == CHIP_FAMILY_RS100) ||
-            (rinfo->family == CHIP_FAMILY_RS200) ||
-            (rinfo->family == CHIP_FAMILY_RS300)) {
+        if (rinfo->is_IGP) {
           u32 tom = INREG(NB_TOM);
           tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
 
@@ -2018,6 +2138,10 @@ static void radeon_identify_vram(struct 
 	/* 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
@@ -2102,7 +2226,7 @@ static ssize_t radeon_show_edid1(struct 
         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);
 }
 
 
@@ -2113,7 +2237,27 @@ static ssize_t radeon_show_edid2(struct 
         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[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->connectors[rinfo->heads[3]].edid);
 }
 
 static struct bin_attribute edid1_attr = {
@@ -2136,6 +2280,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)
@@ -2143,6 +2306,7 @@ static int __devinit radeonfb_pci_regist
 	struct fb_info *info;
 	struct radeonfb_info *rinfo;
 	int ret;
+	int i;
 
 	RTRACE("radeonfb_pci_register BEGIN\n");
 	
@@ -2199,7 +2363,8 @@ static int __devinit radeonfb_pci_regist
 	}
 
 	/* 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));
@@ -2284,6 +2449,7 @@ static int __devinit radeonfb_pci_regist
 	 * 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);
@@ -2295,14 +2461,23 @@ static int __devinit radeonfb_pci_regist
 	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);
 
@@ -2313,10 +2488,15 @@ static int __devinit radeonfb_pci_regist
 	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
@@ -2361,10 +2541,12 @@ static int __devinit radeonfb_pci_regist
 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);
@@ -2389,17 +2571,23 @@ static void __devexit radeonfb_pci_unreg
 {
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
- 
+
+	int i;
+
         if (!rinfo)
                 return;
 
 	radeonfb_bl_exit(rinfo);
 	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
@@ -2426,10 +2614,11 @@ static void __devexit radeonfb_pci_unreg
 	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        
@@ -2479,12 +2668,18 @@ static int __init radeonfb_setup (char *
 			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)) {
 			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;
 	}
@@ -2528,6 +2723,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);
@@ -2546,3 +2743,5 @@ MODULE_PARM_DESC(force_sleep, "bool: for
 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 -puN drivers/video/aty/radeon_i2c.c~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeon_i2c.c
--- a/drivers/video/aty/radeon_i2c.c~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/drivers/video/aty/radeon_i2c.c
@@ -136,29 +136,53 @@ void radeon_delete_i2c_busses(struct rad
 	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)
 {
-	u8 *edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
+	int mon_type = MT_NONE;
+	u8 *edid;
+
+	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;
+			goto done;
+	}
+
+	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[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 ((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;
 	}
-       	RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn);
-	return MT_CRT;
+
+	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->ddc_type);
+	mon_type = MT_CRT;
+
+ done:
+	conn->edid = edid;
+	conn->mon_type = mon_type;
+
+	return (mon_type == MT_NONE);
 }
 
diff -puN drivers/video/aty/radeon_monitor.c~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeon_monitor.c
--- a/drivers/video/aty/radeon_monitor.c~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/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/*0x40111*/}, {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,6 @@ static struct fb_var_screeninfo radeonfb
 	.vmode		= FB_VMODE_NONINTERLACED
 };
 
-static char *radeon_get_mon_name(int type)
-{
-	char *pret = NULL;
-
-	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";
-			break;
-	}
-
-	return pret;
-}
-
-
 #ifdef CONFIG_PPC_OF
 /*
  * Try to find monitor informations & EDID data out of the Open Firmware
@@ -59,7 +53,8 @@ static char *radeon_get_mon_name(int typ
  * 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 device_node *dp,
+					       struct radeon_connector *conn,
 					       int hdno)
 {
         static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
@@ -67,25 +62,30 @@ static int __devinit radeon_parse_montyp
 	const u8 *pedid = NULL;
 	const u8 *pmt = NULL;
 	u8 *tmp;
-        int i, mt = MT_NONE;  
+        int i;
 	
 	RTRACE("analyzing OF properties...\n");
 	pmt = 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) {
@@ -102,26 +102,41 @@ static int __devinit radeon_parse_montyp
 	if (pedid == NULL && dp->parent && (hdno == 0))
 		pedid = get_property(dp->parent, "EDID", NULL);
 	if (pedid == NULL)
-		return mt;
+		return 1;
 
 	tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL);
-	if (!tmp)
-		return mt;
-	memcpy(tmp, pedid, EDID_LENGTH);
-	*out_EDID = tmp;
-	return mt;
+	if (tmp) {
+		memcpy(tmp, pedid, EDID_LENGTH);
+	}
+
+	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 radeon_connector *conn;
         struct device_node *dp;
+	u8 *out_EDID;
 
 	RTRACE("radeon_probe_OF_head\n");
 
+	conn = rinfo->connectors[head_no];
+
         dp = rinfo->of_node;
-        while (dp == NULL)
-		return MT_NONE;
+        if (dp == NULL)
+		return 1;
 
 	if (rinfo->has_CRTC2) {
 		const char *pname;
@@ -130,49 +145,91 @@ static int __devinit radeon_probe_OF_hea
 		dp = dp->child;
 		do {
 			if (!dp)
-				return MT_NONE;
+				return 1;
+
 			pname = get_property(dp, "name", NULL);
 			if (!pname)
-				return MT_NONE;
+				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(dp, conn, 0);
+			} else if (pname[len-1] == 'B' && head_no == 1) {
+				return radeon_parse_montype_prop(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);
+		if (head_no > 0) {
+			return 1;
+		}
+		return radeon_parse_montype_prop(dp, conn, -1);
 	}
-        return MT_NONE;
+	return 1;
 }
 #endif /* CONFIG_PPC_OF */
 
 
-static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
+int __devinit radeon_get_lvds_info_atom(struct radeonfb_info *rinfo)
+{
+	unsigned long tmp;
+
+	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 0;
+		return -ENODEV;
 
 	if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) {
-		printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n");
+		RTRACE("No LVDS panel info in Legacy BIOS\n");
 		rinfo->panel_info.pwr_delay = 200;
-		return 0;
+		return -ENODEV;
 	}
 
 	for(i=0; i<24; i++)
@@ -182,7 +239,7 @@ static int __devinit radeon_get_panel_in
 	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.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);
@@ -203,6 +260,7 @@ static int __devinit radeon_get_panel_in
 		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);
@@ -235,12 +293,427 @@ static int __devinit radeon_get_panel_in
 			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;
+
+			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;
+
+	/* Get default TMDS infos for this chip */
+	for (i=0; i<4; i++) {
+		rinfo->tmds_pll[i].value =
+			default_tmds_pll[rinfo->family][i].value;
+		rinfo->tmds_pll[i].freq =
+			default_tmds_pll[rinfo->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;
+
+	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
+}
+
+/*
+ * 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)
+{
+	int i;
+
+	/* 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);
+			}
+		}
+
+		/* 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;
+			}
+		}
+	}
+
+	printk(KERN_INFO "radeonfb: No connector infos, using defaults...\n");
+
+	/* Here, we use defaults that are common enough ... we hope
+	 * For a mobility chip, we assume LVDS is on primary
+	 */
+	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;
+		}
+	}
+
+ 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;
+		}
+	}
+
+	/* Single head chips all use primary DAC */
+	if (!rinfo->has_CRTC2)
+		rinfo->connectors[0].dac_type = dac_primary;
+
+	return;
+ }
+
+#ifdef CONFIG_PPC_OF
+int __devinit radeon_get_conn_info_openfirmware(struct radeonfb_info *rinfo)
+{
+	int i;
+	int not_found = 1;
+
+	for(i = 0 ; < 2 ; i++) {  /* Only two heads for OF! */
+		if (!radeon_probe_OF_head(rinfo, i)) found = 0;
+	}
+	return found;
+}
+#endif /* CONFIG_PPC_OF */
+
+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;
+
+	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++) {
+		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;
+			/* Gotcha, just "update" values */
+			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 == dac_unknown)
+				rinfo->connectors[j].ddc_type = dac_type;
+			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))
+			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;
+
+		/* increment connector_found for primary connectors only */
+		if (idx < 2)
+			connector_found += (idx + 1);
+	}
+
+	if (connector_found == 0)
+		return -ENODEV;
+
 	return 0;
 }
 
@@ -248,44 +721,167 @@ static int __devinit radeon_get_panel_in
  * 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;
-	}
-
-	/* 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 (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);
+	}
+
+	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 +958,50 @@ static int __devinit radeon_crt_is_conne
     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 +1047,20 @@ static int __devinit radeon_parse_monito
 		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 +1074,7 @@ static int __devinit radeon_parse_monito
 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,30 +1085,33 @@ void __devinit radeon_probe_screens(stru
 		 * 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 {
 		/*
@@ -481,182 +1120,104 @@ void __devinit radeon_probe_screens(stru
 		
 		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;
-
-			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) {
-#ifdef CONFIG_PPC_OF
-			if (rinfo->mon1_type == MT_NONE)
-				rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
-									&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
 #ifdef CONFIG_FB_RADEON_I2C
-			if (rinfo->mon1_type == MT_NONE)
-				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);	
+			/* Probe each connector */
+			for(i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
+				if (PRIMARY_MONITOR(rinfo) > MT_NONE) break;  /* only one head */
+				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 (rinfo->mon1_type == MT_NONE)
-				rinfo->mon1_type = MT_CRT;
+			if (PRIMARY_MONITOR(rinfo) <= MT_NONE) {
+				radeon_find_connector_for_mon(rinfo, 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)
-					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");
-				}
+		/* Probe heads */
+#ifdef CONFIG_FB_RADEON_I2C
+		/* Probe each connector in turn. */
+		for(i = 0 ; i < RADEON_MAX_CONNECTORS ; i++) {
+			if (rinfo->connectors[i].mon_type > MT_NONE) continue; /* Don't probe "detected" stuff again */
+			if (!radeon_probe_i2c_connector(rinfo, &rinfo->connectors[i])) {
+				rinfo->heads[rinfo->num_heads] = i;
+				rinfo->connectors[i].head = rinfo->num_heads++;
 			}
 		}
 
-		/*
-		 * Probe primary head (DVI or laptop internal panel)
-		 */
-#ifdef CONFIG_PPC_OF
-		if (rinfo->mon1_type == MT_NONE)
-			rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
-								&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
-#ifdef CONFIG_FB_RADEON_I2C
-		if (rinfo->mon1_type == MT_NONE)
-			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");
+
+		/* 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);
+			}
 		}
-		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)
-		 */
-#ifdef CONFIG_PPC_OF
-		if (rinfo->mon2_type == MT_NONE)
-			rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
-								&rinfo->mon2_EDID);
-#endif /* CONFIG_PPC_OF */
-#ifdef CONFIG_FB_RADEON_I2C
-		if (rinfo->mon2_type == MT_NONE)
-			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);
+		/* 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 only detected port 2, we swap them, if none detected,
-		 * assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look
-		 * at FP registers ?)
-		 */
-		if (rinfo->mon1_type == MT_NONE) {
-			if (rinfo->mon2_type != MT_NONE) {
-				rinfo->mon1_type = rinfo->mon2_type;
-				rinfo->mon1_EDID = rinfo->mon2_EDID;
-			} else
-				rinfo->mon1_type = MT_CRT;
-			rinfo->mon2_type = MT_NONE;
-			rinfo->mon2_EDID = NULL;
+		/* If 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);
 		}
 
-		/*
-		 * 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;
-			}
+		/* 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:
-	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");
+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);
+	}
 }
 
 
-/*
- * 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 +1228,16 @@ static void radeon_fixup_panel_info(stru
 		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 1;
 }
-
+#endif /* CONFIG_PPC_OF */
 
 /*
  * Fill up panel infos from a mode definition, either returned by the EDID
@@ -742,22 +1304,35 @@ void __devinit radeon_check_modes(struct
 	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 +1340,10 @@ void __devinit radeon_check_modes(struct
 	}
 
 	/*
-	 * 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,13 +1374,13 @@ void __devinit radeon_check_modes(struct
 	/*
 	 * 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;
 	}
 
 	
@@ -819,7 +1389,7 @@ void __devinit radeon_check_modes(struct
 	 * 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,21 +1403,22 @@ void __devinit radeon_check_modes(struct
 		}
 		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);
 	}
 
@@ -947,14 +1518,14 @@ int  radeon_match_mode(struct radeonfb_i
 	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 +1538,7 @@ int  radeon_match_mode(struct radeonfb_i
 		 * 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;
diff -puN drivers/video/aty/radeonfb.h~radeonfb-atom-bios-support-new-head-code-fixes drivers/video/aty/radeonfb.h
--- a/drivers/video/aty/radeonfb.h~radeonfb-atom-bios-support-new-head-code-fixes
+++ a/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_LAST,
 };
 
@@ -64,6 +67,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))
 
 /*
@@ -86,11 +90,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 */
@@ -100,27 +143,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
@@ -128,11 +189,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
@@ -299,6 +368,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];
@@ -317,15 +400,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;
 
@@ -357,24 +433,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
@@ -597,7 +668,7 @@ static inline void _radeon_engine_idle(s
 /* 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);
@@ -635,4 +706,18 @@ static inline void radeonfb_bl_init(stru
 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__ */
_

Patches currently in -mm which might be from pizza@xxxxxxxxxxxx are

radeonfb-atom-bios-support-new-head-code-fixes.patch

-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux