summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-03-06 16:05:17 -0800
committerEric Anholt <eric@anholt.net>2008-06-19 15:01:34 -0700
commitbeba1dd3561e38573ed9f507328caf7f8fb9f84a (patch)
treee9261412dce1c306b4f9c827de8fa6b5cb051d29
parentda58dc3b02999f3244d0eaf77180b828d85bd609 (diff)
Initial HDMI work. Not currently hooked up at startup.
-rw-r--r--src/Makefile.am1
-rw-r--r--src/i810_reg.h10
-rw-r--r--src/i830.h4
-rw-r--r--src/i830_display.c1
-rw-r--r--src/i830_driver.c5
-rw-r--r--src/i830_hdmi.c222
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)
diff --git a/src/i830.h b/src/i830.h
index 2a804abb..00a5059d 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -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));
+}