summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2008-10-03 15:24:12 -0400
committerAlex Deucher <alexdeucher@gmail.com>2008-10-03 15:24:12 -0400
commitf9826a5694b7adb6920eb5bdf45d840d8fb14d53 (patch)
tree3ec6d555fd1f8eb6d8f5a2a0bf515d46d8ef8579
parent23c17c0121d43c2fd11bb5cfbaa4b02abac2b16d (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.
-rw-r--r--src/radeon_atombios.c58
-rw-r--r--src/radeon_atombios.h3
-rw-r--r--src/radeon_driver.c2
-rw-r--r--src/radeon_output.c19
-rw-r--r--src/radeon_probe.h2
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 {