diff options
author | Alex Deucher <alex@botch2.(none)> | 2007-09-17 23:04:17 -0400 |
---|---|---|
committer | Alex Deucher <alex@botch2.(none)> | 2007-09-17 23:04:17 -0400 |
commit | 4000a710c93dd2d82891e4082bc7fa922ba9c5f4 (patch) | |
tree | 39b36b44ca858212fd08d7a91dcaff65f42705db | |
parent | 38515d402555eaa61c686d42973e59f659b07466 (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.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/i2c_vid.h | 132 | ||||
-rw-r--r-- | src/radeon.h | 6 | ||||
-rw-r--r-- | src/radeon_bios.c | 41 | ||||
-rw-r--r-- | src/radeon_display.c | 2 | ||||
-rw-r--r-- | src/radeon_driver.c | 3 | ||||
-rw-r--r-- | src/radeon_output.c | 195 | ||||
-rw-r--r-- | src/radeon_probe.h | 17 | ||||
-rw-r--r-- | src/radeon_reg.h | 2 | ||||
-rw-r--r-- | src/sil164/Makefile.am | 16 | ||||
-rw-r--r-- | src/sil164/sil164.c | 246 | ||||
-rw-r--r-- | src/sil164/sil164.h | 31 | ||||
-rw-r--r-- | src/sil164/sil164_module.c | 38 | ||||
-rw-r--r-- | src/sil164/sil164_reg.h | 74 |
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, ®9); + + 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 |