From: Stuffed Crust <pizza@shaftnet.org>
To: Benjamin Herrenschmidt <benh@kernel.crashing.org>,
linux-fbdev-devel@lists.sourceforge.net
Subject: Re: [patch] [radeonfb] Radeon Mobility X700 (M26) and ATOM bios support
Date: Thu, 23 Feb 2006 01:09:39 -0500 [thread overview]
Message-ID: <20060223060939.GA27224@shaftnet.org> (raw)
In-Reply-To: <20060222221916.GB17359@shaftnet.org>
[-- Attachment #1.1: Type: text/plain, Size: 1922 bytes --]
On Wed, Feb 22, 2006 at 05:19:16PM -0500, Stuffed Crust wrote:
> On Wed, Feb 15, 2006 at 08:28:49AM +1100, Benjamin Herrenschmidt wrote:
> > What's the status of this patch ? Do you have a new version ? People are
> > heving enough problems with recent cards to justify getting something in
> > soon...
>
> Sorry about the delay, but as you mentioned earlier, you know how those
> higher-priority things are.
>
> I've attached my current WIP. It has no additional functionality over
> the original patch, but it's rearranged to be quite a bit cleaner, using
> function pointers for the atom/legacy bits.
>
> I haven't tested this particular patch out, but it does compile.
>
> The reversed DAC/TDMS detection and connector parsing stuff is still
> unwritten for ATOM BIOSes. I plan on digging into the X.Org sources
> later tonight.
And to follow up to myself, here is a third patch. I've started
incorporating bits and pieces from the "oooold" non-working rewrite
that you sent me for inspiration. Changes from last patch:
* Naming cleanups
* Merge the OpenFirmware PLL detection into the function pointer mess.
* Merge the oooold patch's legacy bios connector parsing code, As the
original stuff didn't really do anything anyway, I don't see the harm.
* Merge the ooold patch's atom bios connector parsing code, but it still
doesn't work yet. It's late and my eyes hurt.
The good news is that I'm typing this using this patch on my Radeon
M26 (mmm.. 1680x1050!), but the bad news is that I don't know if the
legacy BIOS code works, especially the connector parsing stuff.
Let me know if I'm going down the right path. The RadeonFB driver is
pretty complicated, so I'm trying to take baby steps as I figure more
of it out.
- Solomon
--
Solomon Peachy ICQ: 1318344
Melbourne, FL
Quidquid latine dictum sit, altum viditur.
[-- Attachment #1.2: radeon-atom-3.diff --]
[-- Type: text/plain, Size: 26727 bytes --]
diff -aur aty-2.6.15/ati_ids.h aty/ati_ids.h
--- aty-2.6.15/ati_ids.h 2006-02-22 23:28:14.000000000 -0500
+++ aty/ati_ids.h 2006-02-22 23:28:38.000000000 -0500
@@ -185,6 +185,8 @@
#define PCI_CHIP_R423_UQ 0x5551
#define PCI_CHIP_R423_UR 0x5552
#define PCI_CHIP_R423_UT 0x5554
+#define PCI_CHIP_RV410_5652 0x5652
+#define PCI_CHIP_RV410_VS 0x5653
#define PCI_CHIP_MACH64VT 0x5654
#define PCI_CHIP_MACH64VU 0x5655
#define PCI_CHIP_MACH64VV 0x5656
Only in aty-2.6.15: radeon-atom-bios2.diff
Only in aty-2.6.15: radeon_atom_bios.diff
diff -aur aty-2.6.15/radeon_base.c aty/radeon_base.c
--- aty-2.6.15/radeon_base.c 2006-02-22 23:28:14.000000000 -0500
+++ aty/radeon_base.c 2006-02-23 00:22:42.000000000 -0500
@@ -214,6 +214,8 @@
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_RV410_5652, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RV410_VS, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2),
@@ -342,7 +344,7 @@
* 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 {
@@ -428,7 +430,7 @@
* 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;
u32 *val;
@@ -451,6 +453,7 @@
if (val && *val)
rinfo->pll.mclk = (*val) / 10;
+ printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n");
return 0;
}
#endif /* CONFIG_PPC_OF */
@@ -593,10 +596,87 @@
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);
+
+ printk(KERN_INFO "radeonfb: Retreived 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);
+
+ printk(KERN_INFO "radeonfb: Retreived PLL infos from ATOM BIOS\n");
+ return 0;
+}
+
+static void radeon_detect_bios_type(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PPC_OF
+ rinfo->is_atom_bios = 0;
+ rinfo->get_pll_info = radeon_get_pll_info_openfirmware;
+ rinfo->get_panel_info = NULL;
+ rinfo->parse_connector_info = NULL;
+#else
+ int tmp = rinfo->fp_bios_start + 4;
+
+ if ((BIOS_IN8(tmp) == 'A' &&
+ BIOS_IN8(tmp+1) == 'T' &&
+ BIOS_IN8(tmp+2) == 'O' &&
+ BIOS_IN8(tmp+3) == 'M') ||
+ (BIOS_IN8(tmp) == 'M' &&
+ BIOS_IN8(tmp+1) == 'O' &&
+ BIOS_IN8(tmp+2) == 'T' &&
+ BIOS_IN8(tmp+3) == 'A')) {
+ rinfo->is_atom_bios = 1;
+
+ rinfo->atom_data_start = BIOS_IN16(rinfo->fp_bios_start + 32);
+ rinfo->radeon_get_pll_info = radeon_get_pll_info_atom;
+ rinfo->radeon_get_panel_info = radeon_get_panel_info_atom;
+ rinfo->radeon_parse_connector_info = radeon_parse_connector_info_atom;
+ printk("ATOM BIOS detected\n");
+ } else {
+ rinfo->is_atom_bios = 0;
+ rinfo->radeon_get_pll_info = radeon_get_pll_info_legacy;
+ rinfo->radeon_get_panel_info = radeon_get_panel_info_legacy;
+ rinfo->radeon_parse_connector_info = radeon_parse_connector_info_legacy;
+ printk("Legacy BIOS detected\n");
+ }
+#endif /* CONFIG_PPC_OF */
+
+}
+
/*
* Retreive 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
@@ -655,39 +735,18 @@
rinfo->pll.ref_clk = 2700;
break;
}
- rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-
-
-#ifdef CONFIG_PPC_OF
- /*
- * Retreive PLL infos from Open Firmware first
- */
- if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) {
- printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n");
- goto found;
- }
-#endif /* CONFIG_PPC_OF */
/*
- * Check out if we have an X86 which gave us some PLL informations
- * and if yes, retreive 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: Retreived 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) {
@@ -701,6 +760,22 @@
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 retreive SCLK and MCLK values, we apply default
* settings in this case (200Mhz). If that really happne often, we could
@@ -2412,6 +2487,7 @@
* 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);
@@ -2423,8 +2499,11 @@
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);
#ifdef CONFIG_FB_RADEON_I2C
/* Register I2C bus */
diff -aur aty-2.6.15/radeon_monitor.c aty/radeon_monitor.c
--- aty-2.6.15/radeon_monitor.c 2006-02-22 23:28:14.000000000 -0500
+++ aty/radeon_monitor.c 2006-02-23 00:43:15.000000000 -0500
@@ -160,7 +160,51 @@
#endif /* CONFIG_PPC_OF */
-static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
+int __devinit radeon_get_panel_info_atom(struct radeonfb_info *rinfo)
+{
+ unsigned long tmp;
+
+ if (!rinfo->bios_seg)
+ return 0;
+
+ tmp = BIOS_IN16(rinfo->atom_data_start + 16);
+ if (!tmp) {
+ printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n");
+ rinfo->panel_info.pwr_delay = 200;
+ return 0;
+ }
+
+ 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 1;
+}
+
+int __devinit radeon_get_panel_info_legacy(struct radeonfb_info *rinfo)
{
unsigned long tmp, tmp0;
char stmp[30];
@@ -174,7 +218,7 @@
rinfo->panel_info.pwr_delay = 200;
return 0;
}
-
+
for(i=0; i<24; i++)
stmp[i] = BIOS_IN8(tmp+i+1);
stmp[24] = 0;
@@ -182,13 +226,13 @@
rinfo->panel_info.xres = BIOS_IN16(tmp + 25);
rinfo->panel_info.yres = BIOS_IN16(tmp + 27);
printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n",
- rinfo->panel_info.xres, rinfo->panel_info.yres);
-
+ rinfo->panel_info.xres, rinfo->panel_info.yres);
+
rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44);
RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
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
*/
@@ -203,6 +247,7 @@
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);
@@ -226,7 +271,7 @@
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);
@@ -235,57 +280,314 @@
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;
}
}
+
RTRACE("Didn't find panel in BIOS table !\n");
return 0;
}
+int __devinit radeon_parse_connector_info_atom(struct radeonfb_info *rinfo)
+{
+#if 0
+ int i, j, offset, valids;
+ int crtc = 0, ids[RADEON_MAX_CONNECTORS];
+ u16 portinfo;
+ int additional = 2;
+ int ddc_type, dac_type, conn_type, tmds_type, port_id;
+
+ offset = BIOS_IN16(rinfo->atom_data_start + 22);
+ if (offset == 0)
+ return -ENODEV;
+
+ /* Again, I slightly modified X.org algorithm. I assign "primary" outputs
+ * to entries 0 and 1, and anything else goes after 2.
+ *
+ * Also, I keep an array of all port IDs matching connectors[] array,
+ * unlike X which limits itself to "crtc"'s
+ */
+ for (i = 0; i < RADEON_MAX_CONNECTORS; i++)
+ ids[i] = -1;
+
+ valids = BIOS_IN16(offset + 4);
+ for (i = 0; i < 8; i++) {
+ if (!(valids & (1 << i)))
+ continue;
+ portinfo = BIOS_IN16(offset + 6 + i*2);
+
+ conn_type = (portinfo >> 4) & 0xf;
+ dac_type = (portinfo & 0xf) - 1;
+ // XXX ddc_type =
+ if (i == 3)
+ tmds_type = tmds_internal;
+ else if (i == 7)
+ tmds_type = tmds_external;
+ else
+ tmds_type = tmds_unknown;
+ port_id = (portinfo >> 8) & 0xf;
+
+ /* Ok, now we have the port ID, look for an existing port
+ * already using this ID
+ */
+ for (j = 0; j < RADEON_MAX_CONNECTORS; j++) {
+ if (port_id != ids[j])
+ continue;
+ /* Gotcha, just "update" values */
+ if (tmds_type != tmds_unknown)
+ rinfo->connectors[j].tmds_type = tmds_type;
+ if (rinfo->connectors[j].dac_type == dac_unknown)
+ rinfo->connectors[j].dac_type = dac_type;
+ goto next;
+ }
+
+ if (crtc < 2) {
+ /* FIXME: ignore TV here */
+ if ((i==2) || (i==6)) continue;
+
+ if (crtc == 1) {
+ /* sharing same port with id[0] */
+ if (((portinfo>>8) & 0xf) == ids[0]) {
+ if (i == 3)
+ pRADEONEnt->PortInfo[0].TMDSType = TMDS_INT;
+ else if (i == 7)
+ pRADEONEnt->PortInfo[0].TMDSType = TMDS_EXT;
+
+ if (pRADEONEnt->PortInfo[0].DACType == DAC_UNKNOWN)
+ pRADEONEnt->PortInfo[0].DACType = (portinfo & 0xf) - 1;
+ continue;
+ }
+ }
+
+ id[crtc] = (portinfo>>8) & 0xf;
+ pRADEONEnt->PortInfo[crtc].DACType = (portinfo & 0xf) - 1;
+ pRADEONEnt->PortInfo[crtc].ConnectorType = (portinfo>>4) & 0xf;
+ if (i == 3)
+ pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_INT;
+ else if (i == 7)
+ pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_EXT;
+
+ if((tmp0 = RADEON_BIOS16 (info->MasterDataStart + 24)) && id[crtc]) {
+ switch (RADEON_BIOS16 (tmp0 + 4 + 27 * id[crtc]) * 4)
+ {
+ case RADEON_GPIO_MONID:
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_MONID;
+ break;
+ case RADEON_GPIO_DVI_DDC:
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_DVI;
+ break;
+ case RADEON_GPIO_VGA_DDC:
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_VGA;
+ break;
+ case RADEON_GPIO_CRT2_DDC:
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_CRT2;
+ break;
+ default:
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE;
+ break;
+ }
+
+ } else {
+ pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE;
+ }
+ crtc++;
+ } else {
+ /* we have already had two CRTCs assigned. the rest may share the same
+ * port with the existing connector, fill in them accordingly.
+ */
+ for (j=0; j<2; j++) {
+ if (((portinfo>>8) & 0xf) == id[j]) {
+ if (i == 3)
+ pRADEONEnt->PortInfo[j].TMDSType = TMDS_INT;
+ else if (i == 7)
+ pRADEONEnt->PortInfo[j].TMDSType = TMDS_EXT;
+
+ if (pRADEONEnt->PortInfo[j].DACType == DAC_UNKNOWN)
+ pRADEONEnt->PortInfo[j].DACType = (portinfo & 0xf) - 1;
+ }
+ }
+ }
+ }
+
+
+ for (i=0; i<2; i++) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
+ i, pRADEONEnt->PortInfo[i].DDCType, pRADEONEnt->PortInfo[i].DACType,
+ pRADEONEnt->PortInfo[i].TMDSType, pRADEONEnt->PortInfo[i].ConnectorType);
+ }
+
+#else
+ return -1;
+#endif
+}
+
/* Try to extract the connector informations from the BIOS. This
* 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_parse_connector_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;
- /* 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);
+ for (i = 1; i < 4; i++) {
+ entry = offset + i*2;
+
+ /* End of table */
+ if (!BIOS_IN8(entry) && i > 1)
+ break;
+
+ /* Read table entry, check connector type */
+ tmp = BIOS_IN16(entry);
+ conn_type = (tmp >> 12) & 0xf;
+ if (conn_type == legacy_conn_none)
+ continue;
+ ddc_type = (tmp >> 8) & 0xf;
+ dac_type = (tmp & 0x01) ? dac_tvdac : dac_primary;
+ tmds_type = (tmp & 0x10) ? tmds_external : tmds_internal;
+
+ /* same connector */
+ if (connector_found > 0) {
+ if (rinfo->connectors[conn_index].ddc_type == ddc_type)
+ continue;
}
+
+ /* sanity checks */
+ if (ddc_type > ddc_crt2)
+ ddc_type = ddc_none;
+ if (conn_type > legacy_conn_unsupported)
+ conn_type = legacy_conn_unsupported;
+ if (conn_type != legacy_conn_dvi_d &&
+ conn_type != legacy_conn_dvi_i &&
+ tmds_type == tmds_internal)
+ tmds_type= tmds_unknown;
+
+ /* convert connector type */
+ conn_type = legacy_conn_to_type[conn_type];
+
+ /* internal DDC_DVI port will get assigned to connector[0], or
+ * if there is no DDC_DVI (like in some IGPs).
+ */
+ conn_index = (ddc_type == ddc_dvi || conn_index == 1) ? 0 : 1;
+
+ /* if the port is a TV port, or both connectors are already
+ * assigned, assign it after further in the table
+ */
+ if (conn_type == conn_ctv || conn_type == conn_stv ||
+ (rinfo->connectors[0].conn_type != conn_none &&
+ rinfo->connectors[1].conn_type))
+ idx = conn_add++;
+ else
+ idx = conn_index;
+
+ /* if table full, exit */
+ if (idx >= RADEON_MAX_CONNECTORS) {
+ printk(KERN_WARNING "radeonfb: Connector table full !\n");
+ break;
+ }
+ rinfo->connectors[idx].conn_type = conn_type;
+ rinfo->connectors[idx].ddc_type = ddc_type;
+ rinfo->connectors[idx].dac_type = dac_type;
+ rinfo->connectors[idx].tmds_type = tmds_type;
+
+ /* increment connector_found for primary connectors only */
+ if (idx < 2)
+ connector_found += (idx + 1);
+ }
+
+ if (rinfo->is_mobility) {
+ /* For the cases where only one VGA connector is found,
+ * we assume LVDS is not listed in the connector table,
+ * add it in here as the first port.
+ *
+ * TODO: Check what's up with laptops that have a DVI output
+ * and no LVDS entry in the table. I suspect some thinkpads
+ * may play trick with us here... We may want to check the
+ * presence of a panel via LVDS_GEN_CNTL to be sure...
+ */
+ if ((connector_found < 3) &&
+ (rinfo->connectors[idx].conn_type == conn_vga)) {
+ if (connector_found == 1) {
+ memcpy(&rinfo->connectors[1],
+ &rinfo->connectors[0],
+ sizeof(struct radeon_connector));
+ }
+ /* Fixme: TV DAC is probably elsewhere ... */
+ rinfo->connectors[0].dac_type = dac_tvdac;
+ rinfo->connectors[0].tmds_type = tmds_unknown;
+ rinfo->connectors[0].ddc_type = ddc_none;
+ rinfo->connectors[0].conn_type = conn_proprietary;
+
+ printk(KERN_WARNING "radeonfb: LVDS port is not in connector table, added in.\n");
+ if (connector_found == 0)
+ connector_found = 1;
+ else
+ connector_found = 3;
+ }
+
+ /* Check for LCD DDC info table */
+ if ((offset = BIOS_IN16(rinfo->fp_bios_start + 0x42))) {
+ if ((tmp = BIOS_IN16(offset + 0x15))) {
+ if ((ddc_type = BIOS_IN8(tmp+2) & 0x07)) {
+ rinfo->connectors[0].ddc_type = ddc_type;
+ printk(KERN_WARNING "radeonfb: LCD DDC Info Table found, "
+ "forcing primary port to %d\n",
+ ddc_type);
+ }
+ }
+ }
+ } else if (connector_found == 2) {
+ memcpy(&rinfo->connectors[0], &rinfo->connectors[1],
+ sizeof (struct radeon_connector));
+ rinfo->connectors[1].dac_type = dac_unknown;
+ rinfo->connectors[1].tmds_type = tmds_unknown;
+ rinfo->connectors[1].ddc_type = ddc_none;
+ rinfo->connectors[1].conn_type = conn_none;
+ connector_found = 1;
}
+
+ if (connector_found == 0)
+ return -ENODEV;
+
+ /* External TMDS Table, not used now */
+ return 0;
}
@@ -434,7 +736,9 @@
#endif
int tmp, i;
- radeon_parse_connector_info(rinfo);
+ if (rinfo->radeon_parse_connector_info) {
+ rinfo->radeon_parse_connector_info(rinfo);
+ }
if (radeon_parse_monitor_layout(rinfo, monitor_layout)) {
@@ -519,7 +823,8 @@
/*
* Check for cards with reversed DACs or TMDS controllers using BIOS
*/
- if (rinfo->bios_seg &&
+
+ if (rinfo->bios_seg && !rinfo->is_atom_bios &&
(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) {
for (i = 1; i < 4; i++) {
unsigned int tmp0;
@@ -741,8 +1046,12 @@
/*
* First check out what BIOS has to say
*/
- if (rinfo->mon1_type == MT_LCD)
- radeon_get_panel_info_BIOS(rinfo);
+ if (rinfo->mon1_type == MT_LCD) {
+ if (rinfo->radeon_get_panel_info) {
+ rinfo->radeon_get_panel_info(rinfo);
+ // XXX Do we care about the return value?
+ }
+ }
/*
* Parse EDID detailed timings and deduce panel infos if any. Right now
diff -aur aty-2.6.15/radeonfb.h aty/radeonfb.h
--- aty-2.6.15/radeonfb.h 2006-02-22 23:28:14.000000000 -0500
+++ aty/radeonfb.h 2006-02-23 00:42:59.000000000 -0500
@@ -91,7 +91,7 @@
/*
* Monitor types
*/
-enum radeon_montype {
+enum radeon_mon_type {
MT_NONE = 0,
MT_CRT, /* CRT */
MT_LCD, /* LCD */
@@ -103,7 +103,7 @@
/*
* DDC i2c ports
*/
-enum ddc_type {
+enum radeon_ddc_type {
ddc_none,
ddc_monid,
ddc_dvi,
@@ -114,14 +114,69 @@
/*
* Connector types
*/
-enum conn_type {
- conn_none,
- conn_proprietary,
- conn_crt,
- conn_DVI_I,
- conn_DVI_D,
+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
+};
+
+/*
+ * DAC types
+ */
+enum radeon_dac_type {
+ dac_unknown = -1,
+ dac_primary = 0,
+ dac_tvdac = 1,
+};
+
+/*
+ * TMDS types
+ */
+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;
+};
+
+/*
+ * Currently, the driver deals with at most 4 connectors
+ */
+#define RADEON_MAX_CONNECTORS 4
/*
* PLL infos
@@ -129,11 +184,19 @@
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
@@ -298,6 +361,18 @@
void __iomem *bios_seg;
int fp_bios_start;
+ int is_atom_bios;
+ int atom_data_start;
+
+ int (*radeon_get_pll_info)(struct radeonfb_info *rinfo);
+ int (*radeon_get_panel_info)(struct radeonfb_info *rinfo);
+ int (*radeon_parse_connector_info)(struct radeonfb_info *rinfo);
+
+
+ /* Connector infos */
+ int conn_count;
+ struct radeon_connector connectors[RADEON_MAX_CONNECTORS];
+
u32 pseudo_palette[17];
struct { u8 red, green, blue, pad; }
palette[256];
@@ -625,4 +700,11 @@
extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
int reg_only);
+/* Bios functions. Fix this. */
+extern int __devinit radeon_get_panel_info_atom(struct radeonfb_info *rinfo);
+extern int __devinit radeon_get_panel_info_legacy(struct radeonfb_info *rinfo);
+int __devinit radeon_parse_connector_info_legacy(struct radeonfb_info *rinfo);
+int __devinit radeon_parse_connector_info_atom(struct radeonfb_info *rinfo);
+
+
#endif /* __RADEONFB_H__ */
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
next prev parent reply other threads:[~2006-02-23 6:10 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-01-03 20:44 [patch] [radeonfb] Radeon Mobility X700 (M26) and ATOM bios support Stuffed Crust
2006-01-03 23:29 ` Petr Vandrovec
2006-01-05 9:59 ` Benjamin Herrenschmidt
2006-01-05 20:13 ` Stuffed Crust
2006-02-14 21:28 ` Benjamin Herrenschmidt
2006-02-22 22:19 ` Stuffed Crust
2006-02-23 6:09 ` Stuffed Crust [this message]
2006-02-23 6:50 ` Benjamin Herrenschmidt
2006-02-23 22:36 ` [patch] [radeonfb] Radeon M26 and ATOM bios support (take 4) Stuffed Crust
2006-02-23 23:15 ` Benjamin Herrenschmidt
2006-03-01 3:33 ` Stuffed Crust
2006-03-01 3:46 ` Benjamin Herrenschmidt
2006-03-01 16:56 ` Gabor Gombas
2006-03-01 20:36 ` Stuffed Crust
2006-03-01 21:34 ` [patch] [radeonfb] Radeon M26 and ATOM bios support (take 5) Stuffed Crust
2006-03-01 21:47 ` Benjamin Herrenschmidt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060223060939.GA27224@shaftnet.org \
--to=pizza@shaftnet.org \
--cc=benh@kernel.crashing.org \
--cc=linux-fbdev-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).