diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2008-10-03 15:24:12 -0400 |
---|---|---|
committer | Alex Deucher <alexdeucher@gmail.com> | 2008-10-03 15:24:12 -0400 |
commit | f9826a5694b7adb6920eb5bdf45d840d8fb14d53 (patch) | |
tree | 3ec6d555fd1f8eb6d8f5a2a0bf515d46d8ef8579 /src | |
parent | 23c17c0121d43c2fd11bb5cfbaa4b02abac2b16d (diff) |
Add support for DDC via atom commands for RV410
The atom calls use the hw i2c engine for DDC. For some
reason, sw i2c doesn't seem to work on the VGA GPIO on
RV410 chips, so we use atom in that case.
This fixes the longstanding VGA DDC problems on RV410/M26
chips.
Diffstat (limited to 'src')
-rw-r--r-- | src/radeon_atombios.c | 58 | ||||
-rw-r--r-- | src/radeon_atombios.h | 3 | ||||
-rw-r--r-- | src/radeon_driver.c | 2 | ||||
-rw-r--r-- | src/radeon_output.c | 19 | ||||
-rw-r--r-- | src/radeon_probe.h | 2 |
5 files changed, 80 insertions, 4 deletions
diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c index b81d2cbd..12aeecae 100644 --- a/src/radeon_atombios.c +++ b/src/radeon_atombios.c @@ -1386,6 +1386,58 @@ const int object_connector_convert[] = CONNECTOR_DISPLAY_PORT, }; +xf86MonPtr radeon_atom_get_edid(xf86OutputPtr output) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_data; + AtomBiosArgRec data; + unsigned char *space; + int i2c_clock = 50; + int engine_clk = info->sclk * 100; + int prescale; + unsigned char *edid; + xf86MonPtr mon = NULL; + + if (!radeon_output->ddc_i2c.hw_capable) + return mon; + + if (info->atomBIOS->fbBase) + edid = (unsigned char *)info->FB + info->atomBIOS->fbBase; + else if (info->atomBIOS->scratchBase) + edid = (unsigned char *)info->atomBIOS->scratchBase; + else + return mon; + + memset(edid, 0, ATOM_EDID_RAW_DATASIZE); + + if (info->ChipFamily == CHIP_FAMILY_R520) + prescale = (127 << 8) + (engine_clk * 10) / (4 * 127 * i2c_clock); + else if (info->ChipFamily < CHIP_FAMILY_R600) + prescale = (((engine_clk * 10)/(4 * 128 * 100) + 1) << 8) + 128; + else + prescale = (info->pll.reference_freq * 10) / i2c_clock; + + edid_data.usPrescale = prescale; + edid_data.usVRAMAddress = 0; + edid_data.ucSlaveAddr = 0xa0; + edid_data.ucLineNumber = radeon_output->ddc_i2c.hw_line; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &edid_data; + + if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) + ErrorF("Atom Get EDID success\n"); + else + ErrorF("Atom Get EDID failed\n"); + + if (edid[1] == 0xff) + mon = xf86InterpretEDID(output->scrn->scrnIndex, edid); + + return mon; + +} static RADEONI2CBusRec RADEONLookupGPIOLineForDDC(ScrnInfoPtr pScrn, uint8_t id) @@ -1425,9 +1477,15 @@ RADEONLookupGPIOLineForDDC(ScrnInfoPtr pScrn, uint8_t id) i2c.get_data_mask = (1 << gpio.ucDataY_Shift); i2c.a_clk_mask = (1 << gpio.ucClkA_Shift); i2c.a_data_mask = (1 << gpio.ucDataA_Shift); + i2c.hw_line = gpio.sucI2cId.sbfAccess.bfI2C_LineMux; + i2c.hw_capable = gpio.sucI2cId.sbfAccess.bfHW_Capable; i2c.valid = TRUE; #if 0 + ErrorF("id: %d\n", id); + ErrorF("hw capable: %d\n", gpio.sucI2cId.sbfAccess.bfHW_Capable); + ErrorF("hw engine id: %d\n", gpio.sucI2cId.sbfAccess.bfHW_EngineID); + ErrorF("line mux %d\n", gpio.sucI2cId.sbfAccess.bfI2C_LineMux); ErrorF("mask_clk_reg: 0x%x\n", gpio.usClkMaskRegisterIndex * 4); ErrorF("mask_data_reg: 0x%x\n", gpio.usDataMaskRegisterIndex * 4); ErrorF("put_clk_reg: 0x%x\n", gpio.usClkEnRegisterIndex * 4); diff --git a/src/radeon_atombios.h b/src/radeon_atombios.h index fe7044d0..1ec0e2d7 100644 --- a/src/radeon_atombios.h +++ b/src/radeon_atombios.h @@ -131,6 +131,9 @@ atombios_external_tmds_setup(xf86OutputPtr output, DisplayModePtr mode); extern void atombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor); +extern xf86MonPtr +radeon_atom_get_edid(xf86OutputPtr output); + Bool rhdAtomASICInit(atomBiosHandlePtr handle); diff --git a/src/radeon_driver.c b/src/radeon_driver.c index eac07d0e..c759bd6a 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -498,7 +498,7 @@ static Bool RADEONUnmapMem(ScrnInfoPtr pScrn) void RADEONPllErrataAfterIndex(RADEONInfoPtr info) { unsigned char *RADEONMMIO = info->MMIO; - + if (!(info->ChipErrata & CHIP_ERRATA_PLL_DUMMYREADS)) return; diff --git a/src/radeon_output.c b/src/radeon_output.c index 2cc38a5a..4947478f 100644 --- a/src/radeon_output.c +++ b/src/radeon_output.c @@ -222,9 +222,18 @@ radeon_ddc_connected(xf86OutputPtr output) RADEONOutputPrivatePtr radeon_output = output->driver_private; if (radeon_output->pI2CBus) { - RADEONI2CDoLock(output, TRUE); - MonInfo = xf86OutputGetEDID(output, radeon_output->pI2CBus); - RADEONI2CDoLock(output, FALSE); + /* RV410 RADEON_GPIO_VGA_DDC seems to only work via hw i2c + * We may want to extend this to other cases if the need arises... + */ + if ((info->ChipFamily == CHIP_FAMILY_RV410) && + (radeon_output->ddc_i2c.mask_clk_reg == RADEON_GPIO_VGA_DDC) && + info->IsAtomBios) + MonInfo = radeon_atom_get_edid(output); + else { + RADEONI2CDoLock(output, TRUE); + MonInfo = xf86OutputGetEDID(output, radeon_output->pI2CBus); + RADEONI2CDoLock(output, FALSE); + } } if (MonInfo) { if (!xf86ReturnOptValBool(info->Options, OPTION_IGNORE_EDID, FALSE)) @@ -1732,6 +1741,8 @@ legacy_setup_i2c_bus(int ddc_line) { RADEONI2CBusRec i2c; + i2c.hw_line = 0; + i2c.hw_capable = FALSE; i2c.mask_clk_mask = RADEON_GPIO_EN_1; i2c.mask_data_mask = RADEON_GPIO_EN_0; i2c.a_clk_mask = RADEON_GPIO_A_1; @@ -1774,6 +1785,8 @@ atom_setup_i2c_bus(int ddc_line) { RADEONI2CBusRec i2c; + i2c.hw_line = 0; + i2c.hw_capable = FALSE; if (ddc_line == AVIVO_GPIO_0) { i2c.put_clk_mask = (1 << 19); i2c.put_data_mask = (1 << 18); diff --git a/src/radeon_probe.h b/src/radeon_probe.h index ce4ba931..83b34284 100644 --- a/src/radeon_probe.h +++ b/src/radeon_probe.h @@ -180,6 +180,8 @@ typedef struct uint32_t get_data_mask; uint32_t a_clk_mask; uint32_t a_data_mask; + int hw_line; + Bool hw_capable; } RADEONI2CBusRec, *RADEONI2CBusPtr; typedef struct _RADEONCrtcPrivateRec { |