summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alex@botch2.(none)>2007-09-17 23:04:17 -0400
committerAlex Deucher <alex@botch2.(none)>2007-09-17 23:04:17 -0400
commit4000a710c93dd2d82891e4082bc7fa922ba9c5f4 (patch)
tree39b36b44ca858212fd08d7a91dcaff65f42705db
parent38515d402555eaa61c686d42973e59f659b07466 (diff)
RADEON: initial pass at external TMDS support
- Based on Dave Airlie's initial work and the dvo support in the intel driver. - Only sil164 is supported at the moment. - Once we get some testing and such, we ought to move the dvo drivers out of the drivers so they can be shared among all drivers - Doesn't seem to work on my card (r4xx ATOM) card ATM - Legacy bios table programming sequence not implemented yet
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/i2c_vid.h132
-rw-r--r--src/radeon.h6
-rw-r--r--src/radeon_bios.c41
-rw-r--r--src/radeon_display.c2
-rw-r--r--src/radeon_driver.c3
-rw-r--r--src/radeon_output.c195
-rw-r--r--src/radeon_probe.h17
-rw-r--r--src/radeon_reg.h2
-rw-r--r--src/sil164/Makefile.am16
-rw-r--r--src/sil164/sil164.c246
-rw-r--r--src/sil164/sil164.h31
-rw-r--r--src/sil164/sil164_module.c38
-rw-r--r--src/sil164/sil164_reg.h74
15 files changed, 802 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 0c413c80..50c382b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -222,5 +222,6 @@ XORG_CHECK_LINUXDOC
AC_OUTPUT([
Makefile
src/Makefile
+ src/sil164/Makefile
man/Makefile
])
diff --git a/src/Makefile.am b/src/Makefile.am
index 709b98c2..309caf6f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,7 +19,7 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+SUBDIRS = sil164
# this is obnoxious:
# -module lets us name the module exactly how we want
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
diff --git a/src/i2c_vid.h b/src/i2c_vid.h
new file mode 100644
index 00000000..2ba88298
--- /dev/null
+++ b/src/i2c_vid.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2006 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef I2C_VID_H
+#define I2C_VID_H
+#include <randrstr.h>
+#include "xf86Crtc.h"
+
+typedef struct _XF86I2CVidOutputRec {
+ /**
+ * Initialize the device at startup time.
+ * Returns NULL if the device does not exist.
+ */
+ void *(*init)(I2CBusPtr b, I2CSlaveAddr addr);
+
+ /**
+ * Called to allow the output a chance to create properties after the
+ * RandR objects have been created.
+ */
+ void
+ (*create_resources)(I2CDevPtr d);
+
+ /**
+ * Turns the output on/off, or sets intermediate power levels if available.
+ *
+ * Unsupported intermediate modes drop to the lower power setting. If the
+ * mode is DPMSModeOff, the output must be disabled, as the DPLL may be
+ * disabled afterwards.
+ */
+ void (*dpms)(I2CDevPtr d, int mode);
+
+ /**
+ * Saves the output's state for restoration on VT switch.
+ */
+ void (*save)(I2CDevPtr d);
+
+ /**
+ * Restore's the output's state at VT switch.
+ */
+ void (*restore)(I2CDevPtr d);
+
+ /**
+ * Callback for testing a video mode for a given output.
+ *
+ * This function should only check for cases where a mode can't be supported
+ * on the output specifically, and not represent generic CRTC limitations.
+ *
+ * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
+ */
+ int (*mode_valid)(I2CDevPtr d, DisplayModePtr mode);
+
+ /**
+ * Callback to adjust the mode to be set in the CRTC.
+ *
+ * This allows an output to adjust the clock or even the entire set of
+ * timings, which is used for panels with fixed timings or for
+ * buses with clock limitations.
+ */
+ Bool (*mode_fixup)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode);
+
+ /**
+ * Callback for preparing mode changes on an output
+ */
+ void (*prepare)(I2CDevPtr d);
+
+ /**
+ * Callback for committing mode changes on an output
+ */
+ void (*commit)(I2CDevPtr d);
+
+ /**
+ * Callback for setting up a video mode after fixups have been made.
+ *
+ * This is only called while the output is disabled. The dpms callback
+ * must be all that's necessary for the output, to turn the output on
+ * after this function is called.
+ */
+ void (*mode_set)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode);
+
+ /**
+ * Probe for a connected output, and return detect_status.
+ */
+ xf86OutputStatus (*detect)(I2CDevPtr d);
+
+ /**
+ * Query the device for the modes it provides.
+ *
+ * This function may also update MonInfo, mm_width, and mm_height.
+ *
+ * \return singly-linked list of modes or NULL if no modes found.
+ */
+ DisplayModePtr
+ (*get_modes)(I2CDevPtr d);
+
+ /**
+ * Callback when an output's property has changed.
+ */
+ Bool
+ (*set_property)(I2CDevPtr d, Atom property, RRPropertyValuePtr value);
+
+ /**
+ * Clean up driver-specific bits of the output
+ */
+ void (*destroy) (I2CDevPtr d);
+
+ /**
+ * Debugging hook to dump device registers to log file
+ */
+ void (*dump_regs)(I2CDevPtr d);
+} XF86I2CVidOutputRec, *XF86I2CVidOutputPtr;
+
+
+#endif
diff --git a/src/radeon.h b/src/radeon.h
index 4c995111..a1e73955 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -144,7 +144,6 @@ typedef enum {
#endif
OPTION_SHOWCACHE,
OPTION_DYNAMIC_CLOCKS,
- OPTION_BIOS_HOTKEYS,
OPTION_VGA_ACCESS,
OPTION_REVERSE_DDC,
OPTION_LVDS_PROBE_PLL,
@@ -896,6 +895,8 @@ extern Bool RADEONGetLVDSInfoFromBIOS (xf86OutputPtr output);
extern Bool RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output);
extern Bool RADEONGetTVInfoFromBIOS (xf86OutputPtr output);
extern Bool RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output);
+extern Bool RADEONGetExtTMDSInfoFromBIOS (xf86OutputPtr output);
+
extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
RADEONSavePtr restore);
@@ -946,6 +947,9 @@ extern int RADEONValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName,
extern int RADEONValidateFPModes(xf86OutputPtr output, char **ppModeName, DisplayModePtr *modeList);
extern void RADEONSetPitch (ScrnInfoPtr pScrn);
extern void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode);
+extern void RADEONSaveExtChipRegisters(ScrnInfoPtr pScrn);
+extern void RADEONRestoreExtChipRegisters(ScrnInfoPtr pScrn);
+extern void RADEONDVOPowerSet(ScrnInfoPtr pScrn, xf86OutputPtr output, int mode);
DisplayModePtr
RADEONProbeOutputModes(xf86OutputPtr output);
diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index b24c4817..af98cf73 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -884,6 +884,47 @@ 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) {
+ table_start = offset + 4;
+ max_freq = RADEON_BIOS16(table_start);
+ radeon_output->dvo_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)
+ radeon_output->dvo_i2c_reg = RADEON_GPIO_MM;*/
+ else {
+ ErrorF("unknown gpio reg: %d\n", gpio_reg);
+ return FALSE;
+ }
+ flags = RADEON_BIOS8(table_start+5);
+ /* XXX: init command list */
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
/* support for init from bios tables
*
* Based heavily on the netbsd radeonfb driver
diff --git a/src/radeon_display.c b/src/radeon_display.c
index fa80e104..ff19717f 100644
--- a/src/radeon_display.c
+++ b/src/radeon_display.c
@@ -358,6 +358,7 @@ void RADEONEnableDisplay(xf86OutputPtr output, BOOL bEnable)
tmp |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
OUTREG(RADEON_FP2_GEN_CNTL, tmp);
save->fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+ RADEONDVOPowerSet(pScrn, output, DPMSModeOn);
}
} else if (radeon_output->MonType == MT_LCD) {
tmp = INREG(RADEON_LVDS_GEN_CNTL);
@@ -409,6 +410,7 @@ void RADEONEnableDisplay(xf86OutputPtr output, BOOL bEnable)
tmp &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
OUTREG(RADEON_FP2_GEN_CNTL, tmp);
save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+ RADEONDVOPowerSet(pScrn, output, DPMSModeOff);
}
} else if (radeon_output->MonType == MT_LCD) {
unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 3f9a8fb5..d66400d8 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -5271,6 +5271,7 @@ static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save)
if (info->InternalTVOut)
RADEONSaveTVRegisters(pScrn, save);
/*RADEONSavePalette(pScrn, save);*/
+ RADEONSaveExtChipRegisters(pScrn);
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
"RADEONSaveMode returns %p\n", save);
@@ -5368,6 +5369,8 @@ void RADEONRestore(ScrnInfoPtr pScrn)
if (info->InternalTVOut)
RADEONRestoreTVRegisters(pScrn, restore);
+ RADEONRestoreExtChipRegisters(pScrn);
+
RADEONRestoreSurfaces(pScrn, restore);
#if 1
diff --git a/src/radeon_output.c b/src/radeon_output.c
index 40d88731..7d838edf 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -47,6 +47,8 @@
#include "radeon_version.h"
#include "radeon_tv.h"
+#include "i2c_vid.h"
+#include "sil164/sil164.h"
const char *MonTypeName[7] = {
"AUTO",
@@ -146,6 +148,17 @@ static const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] =
{{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS400*/ /* FIXME: just values from rv380 used... */
};
+static const char *SIL164Symbols[] = {
+ "Sil164VidOutput",
+ NULL
+};
+
+RADEONDVORec radeon_dvo_drivers[] =
+ { { 0, "sil164", "SIL164VidOutput", SIL164Symbols, NULL, NULL, NULL} };
+
+#define RADEON_NUM_DVO_DRIVERS (sizeof(radeon_dvo_drivers)/sizeof(RADEONDVORec))
+
+
static RADEONMonitorType RADEONPortCheckNonDDC(ScrnInfoPtr pScrn, xf86OutputPtr output);
static void RADEONUpdatePanelSize(xf86OutputPtr output);
static RADEONMonitorType radeon_detect_tv(ScrnInfoPtr pScrn);
@@ -154,6 +167,159 @@ static RADEONMonitorType radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color);
static RADEONMonitorType radeon_detect_ext_dac(ScrnInfoPtr pScrn);
static void RADEONGetTMDSInfoFromTable(xf86OutputPtr output);
+Bool RADEONFindDVOController(ScrnInfoPtr pScrn, xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ RADEONDVOPtr drv;
+ void *ret_ptr;
+ int i;
+
+ for (i = 0; i < RADEON_NUM_DVO_DRIVERS; i++) {
+ drv = &radeon_dvo_drivers[i];
+ drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename);
+
+ if (!drv->modhandle)
+ continue;
+
+ xf86LoaderReqSymLists(drv->symbols, NULL);
+
+ radeon_output->ExtChip = NULL;
+ ret_ptr = NULL;
+ drv->vid_rec = LoaderSymbol(drv->fntablename);
+
+ ErrorF("dvo i2c reg: 0x%02x\n", radeon_output->dvo_i2c_reg);
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+
+ if (drv->vid_rec)
+ ret_ptr = drv->vid_rec->init(radeon_output->pDVOBus, radeon_output->dvo_slave_addr);
+
+ if (ret_ptr) {
+ drv->devpriv = ret_ptr;
+ radeon_output->ExtChip = drv;
+ return TRUE;
+ }
+ xf86UnloadSubModule(drv->modhandle);
+ }
+
+ ErrorF("dvo chip detect failed\n");
+ return FALSE;
+}
+
+void RADEONDVOPowerSet(ScrnInfoPtr pScrn, xf86OutputPtr output, int mode)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->ExtChip)
+ return;
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+ radeon_output->ExtChip->vid_rec->dump_regs(radeon_output->ExtChip->devpriv);
+ radeon_output->ExtChip->vid_rec->dpms(radeon_output->ExtChip->devpriv, mode);
+
+}
+
+static void RADEONDVOSaveRegisters(ScrnInfoPtr pScrn, xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->ExtChip)
+ return;
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+ radeon_output->ExtChip->vid_rec->dump_regs(radeon_output->ExtChip->devpriv);
+ radeon_output->ExtChip->vid_rec->save(radeon_output->ExtChip->devpriv);
+
+}
+
+static void RADEONDVOProgramRegisters(ScrnInfoPtr pScrn, xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->ExtChip)
+ return;
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+ radeon_output->ExtChip->vid_rec->dump_regs(radeon_output->ExtChip->devpriv);
+ radeon_output->ExtChip->vid_rec->mode_set(radeon_output->ExtChip->devpriv, mode, adjusted_mode);
+
+}
+
+static void RADEONDVORestoreRegisters(ScrnInfoPtr pScrn, xf86OutputPtr output)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->ExtChip)
+ return;
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+ radeon_output->ExtChip->vid_rec->dump_regs(radeon_output->ExtChip->devpriv);
+ radeon_output->ExtChip->vid_rec->restore(radeon_output->ExtChip->devpriv);
+
+}
+
+static ModeStatus RADEONDVOModeValid(ScrnInfoPtr pScrn, xf86OutputPtr output, DisplayModePtr mode)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ if (!radeon_output->ExtChip)
+ return MODE_OK;
+
+ OUTREG(radeon_output->dvo_i2c_reg, INREG(radeon_output->dvo_i2c_reg) &
+ (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
+ radeon_output->ExtChip->vid_rec->dump_regs(radeon_output->ExtChip->devpriv);
+ return radeon_output->ExtChip->vid_rec->mode_valid(radeon_output->ExtChip->devpriv, mode);
+
+}
+
+void RADEONSaveExtChipRegisters(ScrnInfoPtr pScrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ RADEONOutputPrivatePtr radeon_output;
+ xf86OutputPtr output;
+ int o;
+
+ for (o = 0; o < xf86_config->num_output; o++) {
+ output = xf86_config->output[o];
+ radeon_output = output->driver_private;
+ if (radeon_output->TMDSType == TMDS_EXT)
+ RADEONDVOSaveRegisters(pScrn, output);
+ }
+}
+
+void RADEONRestoreExtChipRegisters(ScrnInfoPtr pScrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ RADEONOutputPrivatePtr radeon_output;
+ xf86OutputPtr output;
+ int o;
+
+ for (o = 0; o < xf86_config->num_output; o++) {
+ output = xf86_config->output[o];
+ radeon_output = output->driver_private;
+ if (radeon_output->TMDSType == TMDS_EXT)
+ RADEONDVORestoreRegisters(pScrn, output);
+ }
+
+}
+
void RADEONPrintPortMap(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
@@ -637,6 +803,7 @@ static int
radeon_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
{
RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ ScrnInfoPtr pScrn = output->scrn;
if (radeon_output->type == OUTPUT_STV ||
radeon_output->type == OUTPUT_CTV) {
@@ -647,6 +814,10 @@ radeon_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
return MODE_CLOCK_RANGE;
}
+ if (radeon_output->MonType == MT_DFP &&
+ radeon_output->TMDSType == TMDS_EXT)
+ return RADEONDVOModeValid(pScrn, output, pMode);
+
if (radeon_output->type != OUTPUT_LVDS)
return MODE_OK;
@@ -777,6 +948,12 @@ static void RADEONInitFP2Registers(xf86OutputPtr output, RADEONSavePtr save,
save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+ /* 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;
+
if (IsPrimary) {
if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) {
save->fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
@@ -1034,6 +1211,7 @@ radeon_mode_set(xf86OutputPtr output, DisplayModePtr mode,
RADEONRestoreFPRegisters(pScrn, &info->ModeReg);
} else {
ErrorF("restore FP2\n");
+ RADEONDVOProgramRegisters(pScrn, output, mode, adjusted_mode);
RADEONRestoreFP2Registers(pScrn, &info->ModeReg);
}
break;
@@ -2458,7 +2636,21 @@ void RADEONInitConnector(xf86OutputPtr output)
}
if (radeon_output->type == OUTPUT_DVI) {
- RADEONGetTMDSInfo(output);
+ if (radeon_output->TMDSType == TMDS_EXT) {
+#if defined(__powerpc__)
+ radeon_output->dvo_i2c_reg = RADEON_GPIO_MONID;
+ radeon_output->dvo_slave_addr = 0x70;
+#else
+ if (!RADEONGetExtTMDSInfoFromBIOS(output)) {
+ radeon_output->dvo_i2c_reg = RADEON_GPIO_CRT2_DDC;
+ radeon_output->dvo_slave_addr = 0x70;
+ }
+#endif
+ RADEONI2CInit(pScrn, &radeon_output->pDVOBus, radeon_output->dvo_i2c_reg, "DVO");
+ /* probe dvo chips */
+ RADEONFindDVOController(pScrn, output);
+ } else
+ RADEONGetTMDSInfo(output);
}
if (radeon_output->type == OUTPUT_STV ||
@@ -2478,7 +2670,6 @@ static Bool RADEONSetupAppleConnectors(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
-
switch (info->MacModel) {
case RADEON_MAC_IBOOK:
info->BiosConnector[0].DDCType = DDC_DVI;
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index bc6f0b9e..257e1963 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -40,6 +40,7 @@
#include "xf86DDC.h"
#include "randrstr.h"
+#include "i2c_vid.h"
#define _XF86MISC_SERVER_
#include <X11/extensions/xf86misc.h>
@@ -148,6 +149,17 @@ typedef enum
TV_STD_SCART_PAL = 32,
} TVStd;
+typedef struct
+{
+ int type;
+ char *modulename;
+ char *fntablename;
+ const char **symbols;
+ XF86I2CVidOutputPtr vid_rec;
+ void *devpriv;
+ pointer modhandle;
+} RADEONDVORec, *RADEONDVOPtr;
+
typedef struct _RADEONCrtcPrivateRec {
#ifdef USE_XAA
FBLinearPtr rotate_mem_xaa;
@@ -196,6 +208,11 @@ typedef struct _RADEONOutputPrivateRec {
int PanelPwrDly;
int DotClock;
RADEONTMDSPll tmds_pll[4];
+ /* DVO */
+ RADEONDVOPtr ExtChip;
+ int dvo_i2c_reg;
+ int dvo_slave_addr;
+ I2CBusPtr pDVOBus;
/* TV out */
TVStd default_tvStd;
TVStd tvStd;
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index af62a692..a39898a6 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -796,6 +796,8 @@
# define RADEON_FP2_DVO_EN (1 << 25)
# define RADEON_FP2_DVO_RATE_SEL_SDR (1 << 26)
# define R200_FP2_DVO_RATE_SEL_SDR (1 << 27)
+# define R200_FP2_DVO_CLOCK_MODE_SINGLE (1 << 28)
+# define R200_FP2_DVO_DUAL_CHANNEL_EN (1 << 29)
#define RADEON_FP_H_SYNC_STRT_WID 0x02c4
#define RADEON_FP_H2_SYNC_STRT_WID 0x03c4
#define RADEON_FP_HORZ_STRETCH 0x028c
diff --git a/src/sil164/Makefile.am b/src/sil164/Makefile.am
new file mode 100644
index 00000000..bb84d036
--- /dev/null
+++ b/src/sil164/Makefile.am
@@ -0,0 +1,16 @@
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@
+
+sil164_la_LTLIBRARIES = sil164.la
+sil164_la_LDFLAGS = -module -avoid-version
+sil164_ladir = @moduledir@/drivers
+
+sil164_la_SOURCES = \
+ sil164.c \
+ sil164_module.c \
+ sil164.h \
+ sil164_reg.h
diff --git a/src/sil164/sil164.c b/src/sil164/sil164.c
new file mode 100644
index 00000000..d15b964f
--- /dev/null
+++ b/src/sil164/sil164.c
@@ -0,0 +1,246 @@
+/* -*- c-basic-offset: 4 -*- */
+/**************************************************************************
+
+Copyright © 2006 Dave Airlie
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Resources.h"
+#include "compiler.h"
+#include "miscstruct.h"
+#include "xf86i2c.h"
+#include "xf86Crtc.h"
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "../i2c_vid.h"
+#include "sil164.h"
+#include "sil164_reg.h"
+
+static Bool
+sil164ReadByte(SIL164Ptr sil, int addr, CARD8 *ch)
+{
+ if (!xf86I2CReadByte(&(sil->d), addr, ch)) {
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to read from %s Slave %d.\n",
+ sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static Bool
+sil164WriteByte(SIL164Ptr sil, int addr, CARD8 ch)
+{
+ if (!xf86I2CWriteByte(&(sil->d), addr, ch)) {
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
+ "Unable to write to %s Slave %d.\n",
+ sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Silicon Image 164 driver for chip on i2c bus */
+static void *
+sil164_init(I2CBusPtr b, I2CSlaveAddr addr)
+{
+ /* this will detect the SIL164 chip on the specified i2c bus */
+ SIL164Ptr sil;
+ unsigned char ch;
+
+ xf86DrvMsg(b->scrnIndex, X_ERROR, "detecting sil164\n");
+
+ sil = xcalloc(1, sizeof(SIL164Rec));
+ if (sil == NULL)
+ return NULL;
+
+ sil->d.DevName = "SIL164 TMDS Controller";
+ sil->d.SlaveAddr = addr;
+ sil->d.pI2CBus = b;
+ sil->d.StartTimeout = b->StartTimeout;
+ sil->d.BitTimeout = b->BitTimeout;
+ sil->d.AcknTimeout = b->AcknTimeout;
+ sil->d.ByteTimeout = b->ByteTimeout;
+ sil->d.DriverPrivate.ptr = sil;
+
+ if (!sil164ReadByte(sil, SIL164_VID_LO, &ch))
+ goto out;
+
+ if (ch!=(SIL164_VID & 0xFF)) {
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
+ "sil164 not detected got %d: from %s Slave %d.\n",
+ ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
+ goto out;
+ }
+
+ if (!sil164ReadByte(sil, SIL164_DID_LO, &ch))
+ goto out;
+
+ if (ch!=(SIL164_DID & 0xFF)) {
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR,
+ "sil164 not detected got %d: from %s Slave %d.\n",
+ ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr);
+ goto out;
+ }
+
+ if (!xf86I2CDevInit(&(sil->d))) {
+ goto out;
+ }
+
+ return sil;
+
+out:
+ xfree(sil);
+ return NULL;
+}
+
+static xf86OutputStatus
+sil164_detect(I2CDevPtr d)
+{
+ SIL164Ptr sil = SILPTR(d);
+ CARD8 reg9;
+
+ sil164ReadByte(sil, SIL164_REG9, &reg9);
+
+ if (reg9 & SIL164_9_HTPLG)
+ return XF86OutputStatusConnected;
+ else
+ return XF86OutputStatusDisconnected;
+}
+
+static ModeStatus
+sil164_mode_valid(I2CDevPtr d, DisplayModePtr mode)
+{
+ return MODE_OK;
+}
+
+static void
+sil164_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
+{
+ SIL164Ptr sil = SILPTR(d);
+ /* As long as the basics are set up, since we don't have clock dependencies
+ * in the mode setup, we can just leave the registers alone and everything
+ * will work fine.
+ */
+ /* recommended programming sequence from doc */
+ sil164WriteByte(sil, 0x08, 0x30);
+ sil164WriteByte(sil, 0x09, 0x00);
+ sil164WriteByte(sil, 0x0a, 0x90);
+ sil164WriteByte(sil, 0x0c, 0x89);
+ sil164WriteByte(sil, 0x08, 0x3b /*0x31*/);
+ /* don't do much */
+ return;
+}
+
+/* set the SIL164 power state */
+static void
+sil164_dpms(I2CDevPtr d, int mode)
+{
+ SIL164Ptr sil = SILPTR(d);
+ int ret;
+ unsigned char ch;
+
+ ret = sil164ReadByte(sil, SIL164_REG8, &ch);
+ if (ret == FALSE)
+ return;
+
+ if (mode == DPMSModeOn)
+ ch |= SIL164_8_PD;
+ else
+ ch &= ~SIL164_8_PD;
+
+ sil164WriteByte(sil, SIL164_REG8, ch);
+
+ return;
+}
+
+static void
+sil164_dump_regs(I2CDevPtr d)
+{
+ SIL164Ptr sil = SILPTR(d);
+ CARD8 val;
+
+ sil164ReadByte(sil, SIL164_FREQ_LO, &val);
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_LO: 0x%02x\n",
+ val);
+ sil164ReadByte(sil, SIL164_FREQ_HI, &val);
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_HI: 0x%02x\n",
+ val);
+ sil164ReadByte(sil, SIL164_REG8, &val);
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG8: 0x%02x\n", val);
+ sil164ReadByte(sil, SIL164_REG9, &val);
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG9: 0x%02x\n", val);
+ sil164ReadByte(sil, SIL164_REGC, &val);
+ xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REGC: 0x%02x\n", val);
+}
+
+static void
+sil164_save(I2CDevPtr d)
+{
+ SIL164Ptr sil = SILPTR(d);
+
+ if (!sil164ReadByte(sil, SIL164_REG8, &sil->SavedReg.reg8))
+ return;
+
+ if (!sil164ReadByte(sil, SIL164_REG9, &sil->SavedReg.reg9))
+ return;
+
+ if (!sil164ReadByte(sil, SIL164_REGC, &sil->SavedReg.regc))
+ return;
+
+ return;
+}
+
+static void
+sil164_restore(I2CDevPtr d)
+{
+ SIL164Ptr sil = SILPTR(d);
+
+ /* Restore it powered down initially */
+ sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8 & ~0x1);
+
+ sil164WriteByte(sil, SIL164_REG9, sil->SavedReg.reg9);
+ sil164WriteByte(sil, SIL164_REGC, sil->SavedReg.regc);
+ sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8);
+}
+
+
+XF86I2CVidOutputRec SIL164VidOutput = {
+ .init = sil164_init,
+ .detect = sil164_detect,
+ .mode_valid = sil164_mode_valid,
+ .mode_set = sil164_mode_set,
+ .dpms = sil164_dpms,
+ .dump_regs = sil164_dump_regs,
+ .save = sil164_save,
+ .restore = sil164_restore,
+};
diff --git a/src/sil164/sil164.h b/src/sil164/sil164.h
new file mode 100644
index 00000000..9f823d6b
--- /dev/null
+++ b/src/sil164/sil164.h
@@ -0,0 +1,31 @@
+/**************************************************************************
+
+ Copyright 2006 Dave Airlie <airlied@linux.ie>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifndef SIL164_H
+#define SIL164_H
+
+#define SIL164_ADDR_1 0x38
+
+#endif
diff --git a/src/sil164/sil164_module.c b/src/sil164/sil164_module.c
new file mode 100644
index 00000000..d3bda819
--- /dev/null
+++ b/src/sil164/sil164_module.c
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 4 -*- */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86Module.h"
+
+static MODULESETUPPROTO(sil164Setup);
+
+static XF86ModuleVersionInfo sil164VersRec = {
+ "sil164",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ { 0,0,0,0 }
+};
+
+_X_EXPORT XF86ModuleData sil164ModuleData = {
+ &sil164VersRec,
+ sil164Setup,
+ NULL
+};
+
+static pointer
+sil164Setup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+ return (pointer)1;
+}
diff --git a/src/sil164/sil164_reg.h b/src/sil164/sil164_reg.h
new file mode 100644
index 00000000..ebfcb8c7
--- /dev/null
+++ b/src/sil164/sil164_reg.h
@@ -0,0 +1,74 @@
+/* -*- c-basic-offset: 4 -*- */
+/**************************************************************************
+
+ Copyright 2006 Dave Airlie <airlied@linux.ie>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifndef SIL164_REG_H
+#define SIL164_REG_H
+
+#define SIL164_VID 0x0001
+#define SIL164_DID 0x0006
+
+#define SIL164_VID_LO 0x00
+#define SIL164_VID_HI 0x01
+#define SIL164_DID_LO 0x02
+#define SIL164_DID_HI 0x03
+#define SIL164_REV 0x04
+#define SIL164_RSVD 0x05
+#define SIL164_FREQ_LO 0x06
+#define SIL164_FREQ_HI 0x07
+
+#define SIL164_REG8 0x08
+#define SIL164_8_VEN (1<<5)
+#define SIL164_8_HEN (1<<4)
+#define SIL164_8_DSEL (1<<3)
+#define SIL164_8_BSEL (1<<2)
+#define SIL164_8_EDGE (1<<1)
+#define SIL164_8_PD (1<<0)
+
+#define SIL164_REG9 0x09
+#define SIL164_9_VLOW (1<<7)
+#define SIL164_9_MSEL_MASK (0x7<<4)
+#define SIL164_9_TSEL (1<<3)
+#define SIL164_9_RSEN (1<<2)
+#define SIL164_9_HTPLG (1<<1)
+#define SIL164_9_MDI (1<<0)
+
+#define SIL164_REGC 0x0c
+
+typedef struct _Sil164SaveRec {
+ CARD8 reg8;
+ CARD8 reg9;
+ CARD8 regc;
+} SIL164SaveRec;
+
+typedef struct {
+ I2CDevRec d;
+ SIL164SaveRec SavedReg;
+ SIL164SaveRec ModeReg;
+} SIL164Rec, *SIL164Ptr;
+
+#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
+
+#endif