diff options
author | Alex Deucher <alex@botch2.(none)> | 2007-09-30 13:11:20 -0400 |
---|---|---|
committer | Alex Deucher <alex@botch2.(none)> | 2007-09-30 13:13:15 -0400 |
commit | 22519fde1e002f28d6036d448fcd18452d00f1bb (patch) | |
tree | 79bcca5131140677fb758f49fe3e10f55e69e9ff | |
parent | dcc376e2d2a13329dd03f1bc4b471329757a6f5f (diff) |
RADEON: add support for ext tmds table and ext tmds chip init
This probably won't work on all chips as the various gpio lines
seem to need special magic to to actually talk to the i2c slave
chips.
-rw-r--r-- | src/radeon.h | 9 | ||||
-rw-r--r-- | src/radeon_bios.c | 133 | ||||
-rw-r--r-- | src/radeon_driver.c | 8 | ||||
-rw-r--r-- | src/radeon_output.c | 111 | ||||
-rw-r--r-- | src/radeon_probe.h | 5 |
5 files changed, 261 insertions, 5 deletions
diff --git a/src/radeon.h b/src/radeon.h index cec06e97..288fe00e 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -950,6 +950,15 @@ extern Bool RADEONInit2(ScrnInfoPtr pScrn, DisplayModePtr crtc1, DisplayModePtr crtc2, int crtc_mask, RADEONSavePtr save, RADEONMonitorType montype); +extern Bool +RADEONDVOReadByte(I2CDevPtr dvo, int addr, CARD8 *ch); +extern Bool +RADEONDVOWriteByte(I2CDevPtr dvo, int addr, CARD8 ch); +extern Bool +RADEONGetExtTMDSInfoFromBIOS (xf86OutputPtr output); +extern Bool +RADEONInitExtTMDSInfoFromBIOS (xf86OutputPtr output); + void radeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y); void diff --git a/src/radeon_bios.c b/src/radeon_bios.c index e106a168..cfa5d2bc 100644 --- a/src/radeon_bios.c +++ b/src/radeon_bios.c @@ -672,6 +672,139 @@ Bool RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output) return FALSE; } +Bool RADEONGetExtTMDSInfoFromBIOS (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int offset, table_start, max_freq, gpio_reg, flags; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + return FALSE; + } else { + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58); + if (offset) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "External TMDS Table revision: %d\n", + RADEON_BIOS8(offset)); + table_start = offset+4; + max_freq = RADEON_BIOS16(table_start); + radeon_output->dvo_i2c_slave_addr = RADEON_BIOS8(table_start+2); + gpio_reg = RADEON_BIOS8(table_start+3); + if (gpio_reg == 1) + radeon_output->dvo_i2c_reg = RADEON_GPIO_MONID; + else if (gpio_reg == 2) + radeon_output->dvo_i2c_reg = RADEON_GPIO_DVI_DDC; + else if (gpio_reg == 3) + radeon_output->dvo_i2c_reg = RADEON_GPIO_VGA_DDC; + else if (gpio_reg == 4) + radeon_output->dvo_i2c_reg = RADEON_GPIO_CRT2_DDC; + else if (gpio_reg == 5) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "unsupported MM gpio_reg\n"); + /*radeon_output->i2c_reg = RADEON_GPIO_MM;*/ + else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unknown gpio reg: %d\n", gpio_reg); + return FALSE; + } + flags = RADEON_BIOS8(table_start+5); + radeon_output->dvo_duallink = flags & 0x01; + if (radeon_output->dvo_duallink) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Duallink TMDS detected\n"); + } + return TRUE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No External TMDS Table found\n"); + + return FALSE; +} + +Bool RADEONInitExtTMDSInfoFromBIOS (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int offset, index, id; + CARD32 val, reg, andmask, ormask; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + return FALSE; + } else { + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x58); + if (offset) { + index = offset+10; + id = RADEON_BIOS16(index); + while (id != 0xffff) { + index += 2; + switch(id >> 13) { + case 0: + reg = id & 0x1fff; + val = RADEON_BIOS32(index); + index += 4; + ErrorF("WRITE INDEXED: 0x%x 0x%x\n", + reg, (unsigned)val); + /*OUTREG(reg, val);*/ + break; + case 2: + reg = id & 0x1fff; + andmask = RADEON_BIOS32(index); + index += 4; + ormask = RADEON_BIOS32(index); + index += 4; + val = INREG(reg); + val = (val & andmask) | ormask; + ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n", + reg, (unsigned)andmask, (unsigned)ormask); + /*OUTREG(reg, val);*/ + break; + case 4: + val = RADEON_BIOS16(index); + index += 2; + ErrorF("delay: %d\n", val); + usleep(val); + break; + case 5: + reg = id & 0x1fff; + andmask = RADEON_BIOS32(index); + index += 4; + ormask = RADEON_BIOS32(index); + index += 4; + ErrorF("MASK PLL: 0x%x 0x%x 0x%x\n", + reg, (unsigned)andmask, (unsigned)ormask); + /*val = INPLL(pScrn, reg); + val = (val & andmask) | ormask; + OUTPLL(pScrn, reg, val);*/ + break; + case 6: + reg = id & 0x1fff; + val = RADEON_BIOS8(index); + index += 1; + ErrorF("i2c write: 0x%x, 0x%x\n", reg, val); + RADEONDVOWriteByte(radeon_output->DVOChip, reg, val); + break; + default: + ErrorF("unknown id %d\n", id>>13); + return FALSE; + }; + id = RADEON_BIOS16(index); + } + return TRUE; + } + } + + return FALSE; +} + /* support for init from bios tables * * Based heavily on the netbsd radeonfb driver diff --git a/src/radeon_driver.c b/src/radeon_driver.c index a8a3d39e..b7e2684b 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -2755,10 +2755,10 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) } /* Free the video bios (if applicable) */ - if (info->VBIOS) { - xfree(info->VBIOS); - info->VBIOS = NULL; - } + //if (info->VBIOS) { + //xfree(info->VBIOS); + //info->VBIOS = NULL; + //} /* Free int10 info */ if (pInt10) diff --git a/src/radeon_output.c b/src/radeon_output.c index fd94266c..6d46a98e 100644 --- a/src/radeon_output.c +++ b/src/radeon_output.c @@ -154,6 +154,87 @@ static RADEONMonitorType radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color); static RADEONMonitorType radeon_detect_ext_dac(ScrnInfoPtr pScrn); static void RADEONGetTMDSInfoFromTable(xf86OutputPtr output); +Bool +RADEONDVOReadByte(I2CDevPtr dvo, int addr, CARD8 *ch) +{ + if (!xf86I2CReadByte(dvo, addr, ch)) { + xf86DrvMsg(dvo->pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s Slave %d.\n", + dvo->pI2CBus->BusName, dvo->SlaveAddr); + return FALSE; + } + return TRUE; +} + +Bool +RADEONDVOWriteByte(I2CDevPtr dvo, int addr, CARD8 ch) +{ + if (!xf86I2CWriteByte(dvo, addr, ch)) { + xf86DrvMsg(dvo->pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + dvo->pI2CBus->BusName, dvo->SlaveAddr); + return FALSE; + } + return TRUE; +} + +static I2CDevPtr +RADEONDVODeviceInit(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CDevPtr dvo; + + dvo = xcalloc(1, sizeof(I2CDevRec)); + if (dvo == NULL) + return NULL; + + dvo->DevName = "RADEON DVO Controller"; + dvo->SlaveAddr = addr; + dvo->pI2CBus = b; + dvo->StartTimeout = b->StartTimeout; + dvo->BitTimeout = b->BitTimeout; + dvo->AcknTimeout = b->AcknTimeout; + dvo->ByteTimeout = b->ByteTimeout; + + if (xf86I2CDevInit(dvo)) { + return dvo; + } + + xfree(dvo); + return NULL; +} + +void +RADEONRestoreDVOChip(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (!radeon_output->DVOChip) + return; + + OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) & + (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); + + if (!RADEONInitExtTMDSInfoFromBIOS(output)) { + /* do mac stuff here */ +#if defined(__powerpc__) + if (radeon_output->DVOChip) { + switch(info->MacModel) { + case RADEON_MAC_POWERBOOK_DL: + RADEONDVOWriteByte(radeon_output->DVOChip, 0x08, 0x30); + RADEONDVOWriteByte(radeon_output->DVOChip, 0x09, 0x00); + RADEONDVOWriteByte(radeon_output->DVOChip, 0x0a, 0x90); + RADEONDVOWriteByte(radeon_output->DVOChip, 0x0c, 0x89); + RADEONDVOWriteByte(radeon_output->DVOChip, 0x08, 0x3b); + break; + default: + } + } +#endif + } +} + void RADEONPrintPortMap(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -796,6 +877,14 @@ static void RADEONInitFP2Registers(xf86OutputPtr output, RADEONSavePtr save, RADEON_FP2_DVO_EN | RADEON_FP2_DVO_RATE_SEL_SDR); +#if 0 + /* XXX: these may be chip specific */ + save->fp2_gen_cntl |= (1 << 22) | R200_FP2_DVO_CLOCK_MODE_SINGLE; + + if (mode->Clock > 165000) + save->fp2_gen_cntl |= R200_FP2_DVO_DUAL_CHANNEL_EN; +#endif + if (IsPrimary) { if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { save->fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; @@ -1062,6 +1151,7 @@ radeon_mode_set(xf86OutputPtr output, DisplayModePtr mode, RADEONRestoreFPRegisters(pScrn, &info->ModeReg); } else { ErrorF("restore FP2\n"); + RADEONRestoreDVOChip(pScrn, output); RADEONRestoreFP2Registers(pScrn, &info->ModeReg); } break; @@ -2489,8 +2579,27 @@ void RADEONInitConnector(xf86OutputPtr output) } if (radeon_output->type == OUTPUT_DVI) { + I2CBusPtr pDVOBus; radeon_output->rmx_type = RMX_OFF; - RADEONGetTMDSInfo(output); + if (radeon_output->TMDSType == TMDS_EXT) { +#if defined(__powerpc__) + radeon_output->dvo_i2c_reg = RADEON_GPIO_MONID; + radeon_output->dvo_i2c_slave_addr = 0x70; +#else + if (!RADEONGetExtTMDSInfoFromBIOS(output)) { + radeon_output->dvo_i2c_reg = RADEON_GPIO_CRT2_DDC; + radeon_output->dvo_i2c_slave_addr = 0x70; + } +#endif + if (RADEONI2CInit(pScrn, &pDVOBus, radeon_output->dvo_i2c_reg, "DVO")) { + radeon_output->DVOChip = + RADEONDVODeviceInit(pDVOBus, + radeon_output->dvo_i2c_slave_addr); + if (!radeon_output->DVOChip) + xfree(pDVOBus); + } + } else + RADEONGetTMDSInfo(output); } if (radeon_output->type == OUTPUT_STV || diff --git a/src/radeon_probe.h b/src/radeon_probe.h index ec895e49..dbd50d74 100644 --- a/src/radeon_probe.h +++ b/src/radeon_probe.h @@ -205,6 +205,11 @@ typedef struct _RADEONOutputPrivateRec { int DotClock; RADEONTMDSPll tmds_pll[4]; RADEONRMXType rmx_type; + /* dvo */ + I2CDevPtr DVOChip; + int dvo_i2c_reg; + int dvo_i2c_slave_addr; + Bool dvo_duallink; /* TV out */ TVStd default_tvStd; TVStd tvStd; |