2007-05-17 01:48:54

by Daniel Drake

[permalink] [raw]
Subject: radeonfb and X800 cards

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?

Thanks,
Daniel


2007-05-17 01:59:40

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

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 ?

Ben.


2007-05-17 12:43:53

by Luca Tettamanti

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

On 5/17/07, Benjamin Herrenschmidt <[email protected]> wrote:
> 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 ?

Nope, but I still rebase against current kernel for my own use. I can
send an up to date patch when I get home this evening.

Luca

2007-05-17 20:00:31

by Luca Tettamanti

[permalink] [raw]
Subject: Re: 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 [email protected] 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 <[email protected]>
* Copyright 2003 Ben. Herrenschmidt <[email protected]>
* Copyright 2000 Ani Joshi <[email protected]>
*
@@ -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

2007-05-17 20:30:11

by Fabio Comolli

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

Hi.

On 5/17/07, Luca Tettamanti <[email protected]> wrote:
> 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 [email protected] to
> create an incremental patch to fix radeonfb on his hardware (provided
> that this mega-patch is suitable as baseline that is).
>

[long patch snipped]

Is there a reason why this patch can't go upstream?

Regards,
Fabio

> 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 [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ...
>
> [Message clipped]

2007-05-18 01:19:20

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: radeonfb and X800 cards


> 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 [email protected] to
> create an incremental patch to fix radeonfb on his hardware (provided
> that this mega-patch is suitable as baseline that is).

Yes, I would very much appreciate if you guys managed to turn that into
some incremental patch serie. That would make it much easier for me to
review properly and track down possible regressions in fact.

Ben.


2007-05-18 01:27:17

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

On Thu, 2007-05-17 at 22:29 +0200, Fabio Comolli wrote:

> Is there a reason why this patch can't go upstream?

Yes. A change of that magnitude will most certainly introduce
regressions. So we can either:

- Have it in -mm for monthes trying to iron out all of them (and we'll
miss some). And struggle also since it's hard to track subtle
regressions with very big patches.

- Have it split in smaller bits, which make it possible to bisect in
case of problem, and thus find/correct problems much faster.

That's my main issue with it at this point. But I'm ok going for route
#1 provided that you guys are willing to help with tracking regressions
down. That also mean I need to do some serious testing on powermacs
since those rely very heavily on a working radeonfb.

Ben.


2007-05-19 20:34:14

by Fabio Comolli

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

Hi.
This patch does not work for me.
Relevant part of the dmesg output is:

< ACPI: PCI Interrupt 0000:01:00.0[A] -> GSI 16 (level, low) -> IRQ 16
< radeonfb: Reference=27.00 MHz (RefDiv=7) Memory=330.00 Mhz, System=358.00 MHz
< Device driver i2c-0 lacks bus and class support for being resumed.
< Device driver i2c-1 lacks bus and class support for being resumed.
< Device driver i2c-2 lacks bus and class support for being resumed.
< Device driver i2c-3 lacks bus and class support for being resumed.
< i2c-adapter i2c-2: unable to read EDID block.
< i2c-adapter i2c-2: unable to read EDID block.
< i2c-adapter i2c-2: unable to read EDID block.
< * Connector 1 is Internal Panel. Head 0, Monitor: LVDS Flat panel
(EDID probed)
< ddc port: 0, dac: -1, tmds: -1
< * Connector 2 is VGA. Head -1, Monitor: None
< ddc port: 2, dac: 0, tmds: -1
< radeonfb: detected LVDS panel size from BIOS: 1280x800
< radeonfb: Dynamic Clock Power Management enabled
< radeonfb (0000:01:00.0): ATI Radeon VS

My card is:

01:00.0 VGA compatible controller: ATI Technologies Inc Radeon
Mobility X700 (PCIE) (prog-if 00 [VGA])
Subsystem: Hewlett-Packard Company Unknown device 309e
Flags: bus master, fast devsel, latency 0, IRQ 16
Memory at d0000000 (32-bit, prefetchable) [size=128M]
I/O ports at 3000 [size=256]
Memory at c8100000 (32-bit, non-prefetchable) [size=64K]
[virtual] Expansion ROM at c8120000 [disabled] [size=128K]
Capabilities: [50] Power Management version 2
Capabilities: [58] Express Endpoint IRQ 0
Capabilities: [80] Message Signalled Interrupts: 64bit+
Queue=0/0 Enable-
Capabilities: [100] Advanced Error Reporting

Please let me know if you need more details.
Regards,
Fabio




On 5/18/07, Benjamin Herrenschmidt <[email protected]> wrote:
> On Thu, 2007-05-17 at 22:29 +0200, Fabio Comolli wrote:
>
> > Is there a reason why this patch can't go upstream?
>
> Yes. A change of that magnitude will most certainly introduce
> regressions. So we can either:
>
> - Have it in -mm for monthes trying to iron out all of them (and we'll
> miss some). And struggle also since it's hard to track subtle
> regressions with very big patches.
>
> - Have it split in smaller bits, which make it possible to bisect in
> case of problem, and thus find/correct problems much faster.
>
> That's my main issue with it at this point. But I'm ok going for route
> #1 provided that you guys are willing to help with tracking regressions
> down. That also mean I need to do some serious testing on powermacs
> since those rely very heavily on a working radeonfb.
>
> Ben.
>
>
>

2007-05-19 21:16:40

by Fabio Comolli

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

Oh, never mind. Of course it works.
I forgot to enable the framebuffer console, I thought that selecting a
fb driver would have automagically enabled it.

It breaks suspend-to-ram, but this is expected.

Thanks and sorry for the noise.
Fabio



On 5/19/07, Fabio Comolli <[email protected]> wrote:
> Hi.
> This patch does not work for me.
> Relevant part of the dmesg output is:
>
[snipped the rest of the email]

2007-05-20 12:54:32

by Jimmy Jazz

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

--- radeon_accel.c.ori 2007-05-09 17:09:00.000000000 +0200
+++ radeon_accel.c 2007-05-09 18:59:25.000000000 +0200
@@ -203,9 +203,7 @@
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 @@
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 @@
{
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
--- radeon_base.c.ori 2007-05-09 17:09:00.000000000 +0200
+++ radeon_base.c 2007-05-09 19:07:19.000000000 +0200
@@ -582,6 +582,32 @@
return 0;
}

+static void radeon_detect_bios_type(struct radeonfb_info *rinfo)
+{
+#ifndef CONFIG_PPC_OF
+ int offset = rinfo->fp_bios_start + 4;
+ unsigned char sign[4];
+
+ sign[0] = BIOS_IN8(offset);
+ sign[1] = BIOS_IN8(offset + 1);
+ sign[2] = BIOS_IN8(offset + 2);
+ sign[3] = BIOS_IN8(offset + 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);
+
+ printk(KERN_INFO "radeonfb: ATOM BIOS signature found\n");
+
+ return;
+ }
+#endif /* NOT CONFIG_PPC_OF */
+
+ rinfo->is_atom_bios = 0;
+
+ return;
+}
+
/*
* Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...)
*/
@@ -658,20 +684,38 @@
#endif /* CONFIG_PPC_OF || CONFIG_SPARC */

/*
- * Check out if we have an X86 which gave us some PLL informations
+ * Check out if we have an ATOM BIOS 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);
+ u16 pll_info_block;

- 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);
+ if(rinfo->is_atom_bios) {
+ 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);
+ } else {
+ /*
+ * Check out if we have an X86 which gave us some PLL informations
+ * and if yes, retrieve them
+ */
+ 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;
}

@@ -687,18 +731,38 @@
/*
* Fall back to already-set defaults...
*/
- printk(KERN_INFO "radeonfb: Used default PLL infos\n");
+ printk(KERN_INFO "radeonfb: Fall back to 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) {
+ printk(KERN_INFO "radeonfb: Set a sane default PLL divisor\n");
+ 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
+ * settings in this case (200Mhz). If that really happen often, we could
* fetch from registers instead...
*/
- if (rinfo->pll.mclk == 0)
+ if (rinfo->pll.mclk == 0) {
+ printk(KERN_INFO "radeonfb: Set a sane default MCLK value\n");
rinfo->pll.mclk = 20000;
- if (rinfo->pll.sclk == 0)
+ }
+ if (rinfo->pll.mclk == 0) {
+ printk(KERN_INFO "radeonfb: Set a sane default SCLK value\n");
rinfo->pll.sclk = 20000;
+ }

printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n",
rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100,
@@ -2302,6 +2366,9 @@
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);

@@ -2429,6 +2496,8 @@

radeonfb_bl_exit(rinfo);

+ radeonfb_bl_exit(rinfo);
+
iounmap(rinfo->mmio_base);
iounmap(rinfo->fb_base);

--- radeonfb.h.ori 2007-05-09 17:09:00.000000000 +0200
+++ radeonfb.h 2007-05-09 19:17:11.000000000 +0200
@@ -301,6 +301,9 @@
void __iomem *bios_seg;
int fp_bios_start;

+ int is_atom_bios;
+ int atom_data_start;
+
u32 pseudo_palette[17];
struct { u8 red, green, blue, pad; }
palette[256];
--- radeon_monitor.c.ori 2007-05-09 18:56:37.000000000 +0200
+++ radeon_monitor.c 2007-05-09 19:18:14.000000000 +0200
@@ -481,17 +481,6 @@

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
*/
@@ -531,11 +520,11 @@
if (!BIOS_IN8(tmp + i*2) && i > 1)
break;
tmp0 = BIOS_IN16(tmp + i*2);
- if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) {
+ if ((!(tmp0 & 0x01)) && ((((tmp0 >> 8) & 0x0f) == ddc_dvi) || (((tmp0 >> 8) & 0x0f) == ddc_monid))) {
rinfo->reversed_DAC = 1;
printk(KERN_INFO "radeonfb: Reversed DACs detected\n");
}
- if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) {
+ if ((((tmp0 >> 8) & 0x0f) == ddc_dvi || (((tmp0 >> 8) & 0x0f) == ddc_monid)) && ((tmp0 >> 4) & 0x01)) {
rinfo->reversed_TMDS = 1;
printk(KERN_INFO "radeonfb: Reversed TMDS detected\n");
}
@@ -552,6 +541,9 @@
#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_monid,
+ &rinfo->mon1_EDID);
+ 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) {
@@ -643,7 +635,7 @@


/*
- * This functions applyes any arch/model/machine specific fixups
+ * This functions applies 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


Attachments:
aty-2.6.22.diff (8.36 kB)

2007-05-22 19:31:52

by Luca Tettamanti

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

Il Sun, May 20, 2007 at 02:54:20PM +0200, Jimmy Jazz ha scritto:
> @Luca, if i remember well you have a X850, could you please try the
> patch for me ?

It does work - sort of; BIOS parsing code is correct. It lacks the
proper connector detection though (esp. port sharing). ATOM BIOS has a
different data layout, so this should be added (now radeonfb thinks that
I've 2 monitors).

I'll be away this weekend, so I'll try to come up with a patch as soon
as I return home.

Luca
--
"L'abilita` politica e` l'abilita` di prevedere quello che
accadra` domani, la prossima settimana, il prossimo mese e
l'anno prossimo. E di essere cosi` abili, piu` tardi,
da spiegare perche' non e` accaduto."

2007-05-24 21:56:10

by Jimmy Jazz

[permalink] [raw]
Subject: Re: radeonfb and X800 cards

Luca Tettamanti a ?crit :
> Il Sun, May 20, 2007 at 02:54:20PM +0200, Jimmy Jazz ha scritto:
>> @Luca, if i remember well you have a X850, could you please try the
>> patch for me ?
>
> It does work - sort of; BIOS parsing code is correct. It lacks the
> proper connector detection though (esp. port sharing). ATOM BIOS has a
> different data layout, so this should be added (now radeonfb thinks that
> I've 2 monitors).
>
> I'll be away this weekend, so I'll try to come up with a patch as soon
> as I return home.
>
> Luca

Hello,

The fact that you see two monitors doesn't really surprise me :) .
Also, i'm convinced to move to the mega patch even if i'm not quite sure
all that code is also needed and I know it will unnecessarily increase
the size of the kernel. However, better have much then less. Sure, if
there were any more information on the web about video card
connector/port logic, my knowledge would have been undoubtedly improved.
Anyway, adding (conn->ddc_type == ddc_monid) in the if condition in
radeon_i2c.c works for me as well.

--- /usr/src/model_with-radeon-r400/aty/radeon_i2c.c 2007-04-13
13:35:49.000000000 +0200
+++ radeon_i2c.c 2007-04-13 22:07:16.000000000 +0200
@@ -163,7 +163,7 @@
mon_type = MT_NONE;
goto done;
}
- if ((edid[EDID_STRUCT_DISPLAY] & 0x80) && (conn->ddc_type == ddc_dvi)) {
+ if ((edid[EDID_STRUCT_DISPLAY] & 0x80) && ((conn->ddc_type == ddc_dvi)
|| (conn->ddc_type == ddc_monid))) {
RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn->ddc_type);
mon_type = MT_DFP;
goto done;

Thank you for testing the patch.

Jj