diff options
author | Eric Anholt <eric@anholt.net> | 2008-03-06 16:05:17 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2008-06-19 15:01:34 -0700 |
commit | beba1dd3561e38573ed9f507328caf7f8fb9f84a (patch) | |
tree | e9261412dce1c306b4f9c827de8fa6b5cb051d29 | |
parent | da58dc3b02999f3244d0eaf77180b828d85bd609 (diff) |
Initial HDMI work. Not currently hooked up at startup.
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/i810_reg.h | 10 | ||||
-rw-r--r-- | src/i830.h | 4 | ||||
-rw-r--r-- | src/i830_display.c | 1 | ||||
-rw-r--r-- | src/i830_driver.c | 5 | ||||
-rw-r--r-- | src/i830_hdmi.c | 222 |
6 files changed, 243 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0784c064..9dd9b378 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,7 @@ intel_drv_la_SOURCES = \ i830_driver.c \ i830_dvo.c \ i830.h \ + i830_hdmi.c \ i830_i2c.c \ i830_io.c \ i830_lvds.c \ diff --git a/src/i810_reg.h b/src/i810_reg.h index dcf14bf2..ecc26867 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -1216,6 +1216,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define FP_M2_DIV_SHIFT 0 #define PORT_HOTPLUG_EN 0x61110 +# define HDMIB_HOTPLUG_INT_EN (1 << 29) +# define HDMIC_HOTPLUG_INT_EN (1 << 28) +# define HDMID_HOTPLUG_INT_EN (1 << 27) # define SDVOB_HOTPLUG_INT_EN (1 << 26) # define SDVOC_HOTPLUG_INT_EN (1 << 25) # define TV_HOTPLUG_INT_EN (1 << 18) @@ -1223,6 +1226,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define CRT_HOTPLUG_FORCE_DETECT (1 << 3) #define PORT_HOTPLUG_STAT 0x61114 +# define HDMIB_HOTPLUG_INT_STATUS (1 << 29) +# define HDMIC_HOTPLUG_INT_STATUS (1 << 28) +# define HDMID_HOTPLUG_INT_STATUS (1 << 27) # define CRT_HOTPLUG_INT_STATUS (1 << 11) # define TV_HOTPLUG_INT_STATUS (1 << 10) # define CRT_HOTPLUG_MONITOR_MASK (3 << 8) @@ -1251,6 +1257,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SDVO_PHASE_SELECT_DEFAULT (6 << 19) #define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) #define SDVOC_GANG_MODE (1 << 16) +#define SDVO_ENCODING_SDVO (0x0 << 10) +#define SDVO_ENCODING_HDMI (0x2 << 10) +/** Requird for HDMI operation */ +#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) #define SDVO_BORDER_ENABLE (1 << 7) /** new with 965, default is to be set */ #define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) @@ -238,6 +238,7 @@ typedef struct { #define I830_OUTPUT_SDVO 5 #define I830_OUTPUT_LVDS 6 #define I830_OUTPUT_TVOUT 7 +#define I830_OUTPUT_HDMI 8 struct _I830DVODriver { int type; @@ -802,6 +803,9 @@ void i830_crt_init(ScrnInfoPtr pScrn); /* i830_dvo.c */ void i830_dvo_init(ScrnInfoPtr pScrn); +/* i830_hdmi.c */ +void i830_hdmi_init(ScrnInfoPtr pScrn, int output_reg); + /* i830_lvds.c */ void i830_lvds_init(ScrnInfoPtr pScrn); diff --git a/src/i830_display.c b/src/i830_display.c index 56a718de..7697d4f0 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -1103,6 +1103,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, lvds_bits = intel_output->lvds_bits; break; case I830_OUTPUT_SDVO: + case I830_OUTPUT_HDMI: is_sdvo = TRUE; if (intel_output->needs_tv_clock) is_tv = TRUE; diff --git a/src/i830_driver.c b/src/i830_driver.c index 604665e3..5782d487 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -924,8 +924,13 @@ I830SetupOutputs(ScrnInfoPtr pScrn) i830_lvds_init(pScrn); if (IS_I9XX(pI830)) { +#if 1 i830_sdvo_init(pScrn, SDVOB); i830_sdvo_init(pScrn, SDVOC); +#else + i830_hdmi_init(pScrn, SDVOB); + i830_hdmi_init(pScrn, SDVOC); +#endif } else { i830_dvo_init(pScrn); } diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c new file mode 100644 index 00000000..103443f6 --- /dev/null +++ b/src/i830_hdmi.c @@ -0,0 +1,222 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "xf86Modes.h" +#include "i830_display.h" + +struct i830_hdmi_priv { + uint32_t output_reg; + + uint32_t save_SDVO; +}; + +static int +i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode) +{ + return MODE_OK; +} + +static Bool +i830_hdmi_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_hdmi_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + uint32_t sdvox; + + sdvox = SDVO_ENCODING_HDMI | + SDVO_BORDER_ENABLE | + SDVO_NULL_PACKETS_DURING_VSYNC; + if (intel_crtc->pipe == 1) + sdvox |= SDVO_PIPE_B_SELECT; + + OUTREG(dev_priv->output_reg, sdvox); +} + +static void +i830_hdmi_dpms(xf86OutputPtr output, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_hdmi_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + uint32_t temp; + + if (mode == DPMSModeOff) { + temp = INREG(dev_priv->output_reg); + OUTREG(dev_priv->output_reg, temp & ~SDVO_ENABLE); + } else { + temp = INREG(dev_priv->output_reg); + OUTREG(dev_priv->output_reg, temp | SDVO_ENABLE); + } +} + +static void +i830_hdmi_save(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_hdmi_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + + dev_priv->save_SDVO = INREG(dev_priv->output_reg); +} + +static void +i830_hdmi_restore(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_hdmi_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + + OUTREG(dev_priv->output_reg, dev_priv->save_SDVO); +} + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect HDMI connection. + * + * \return TRUE if HDMI port is connected. + * \return FALSE if HDMI port is disconnected. + */ +static xf86OutputStatus +i830_hdmi_detect(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_hdmi_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + uint32_t temp, bit; + + temp = INREG(PORT_HOTPLUG_EN); + + OUTREG(PORT_HOTPLUG_EN, + temp | + HDMIB_HOTPLUG_INT_EN | + HDMIC_HOTPLUG_INT_EN | + HDMID_HOTPLUG_INT_EN); + + POSTING_READ(PORT_HOTPLUG_EN); + + switch (dev_priv->output_reg) { + case SDVOB: + bit = HDMIB_HOTPLUG_INT_STATUS; + break; + case SDVOC: + bit = HDMIC_HOTPLUG_INT_STATUS; + break; + default: + return XF86OutputStatusUnknown; + } + + if ((INREG(PORT_HOTPLUG_STAT) & bit) != 0) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; +} + +static void +i830_hdmi_destroy (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + + if (intel_output != NULL) { + xf86DestroyI2CBusRec(intel_output->pDDCBus, FALSE, FALSE); + xfree(intel_output); + } +} + +static const xf86OutputFuncsRec i830_hdmi_output_funcs = { + .dpms = i830_hdmi_dpms, + .save = i830_hdmi_save, + .restore = i830_hdmi_restore, + .mode_valid = i830_hdmi_mode_valid, + .mode_fixup = i830_hdmi_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_hdmi_mode_set, + .commit = i830_output_commit, + .detect = i830_hdmi_detect, + .get_modes = i830_ddc_get_modes, + .destroy = i830_hdmi_destroy +}; + +void +i830_hdmi_init(ScrnInfoPtr pScrn, int output_reg) +{ + xf86OutputPtr output; + I830OutputPrivatePtr intel_output; + struct i830_hdmi_priv *dev_priv; + + output = xf86OutputCreate(pScrn, &i830_hdmi_output_funcs, + (output_reg == SDVOB) ? "HDMI-1" : "HDMI-2"); + if (!output) + return; + intel_output = xnfcalloc(sizeof (I830OutputPrivateRec) + + sizeof (struct i830_hdmi_priv), 1); + if (intel_output == NULL) { + xf86OutputDestroy(output); + return; + } + output->driver_private = intel_output; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + dev_priv = (struct i830_hdmi_priv *)(intel_output + 1); + dev_priv->output_reg = output_reg; + + intel_output->dev_priv = dev_priv; + intel_output->type = I830_OUTPUT_HDMI; + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = (1 << I830_OUTPUT_HDMI); + + /* Set up the DDC bus. */ + if (output_reg == SDVOB) + I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOE, "HDMIDDC_B"); + else + I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOE, "HDMIDDC_C"); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "HDMI output %d detected\n", + 1 + (output_reg - SDVOB)); +} |