summaryrefslogtreecommitdiff
path: root/src/i830_crt.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2006-10-31 14:32:00 -0800
committerEric Anholt <eric@anholt.net>2006-10-31 14:32:00 -0800
commit68cef9f4e028755bbf3e1862da2ef47d46ddaa6a (patch)
tree1f5018a6e0492efff7130b97b18864d00df1d4ad /src/i830_crt.c
parent9fd719fce27f916ab5120f6e1234affa14eaed9d (diff)
Move output connection detection to a per-output method.
This will be used by RandR, and should let us clean up some of the initial display configuration, hopefully. Also, analog hotplug-based detection is now enabled on G965.
Diffstat (limited to 'src/i830_crt.c')
-rw-r--r--src/i830_crt.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/i830_crt.c b/src/i830_crt.c
index 7721a0c2..d271eedb 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -112,6 +112,167 @@ i830_crt_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
OUTREG(ADPA, adpa);
}
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
+ *
+ * Only for I945G/GM.
+ *
+ * \return TRUE if CRT is connected.
+ * \return FALSE if CRT is disconnected.
+ */
+static Bool
+i830_crt_detect_hotplug(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 temp;
+ const int timeout_ms = 1000;
+ int starttime, curtime;
+
+ temp = INREG(PORT_HOTPLUG_EN);
+
+ OUTREG(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
+
+ for (curtime = starttime = GetTimeInMillis();
+ (curtime - starttime) < timeout_ms; curtime = GetTimeInMillis())
+ {
+ if ((INREG(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0)
+ break;
+ }
+
+ if ((INREG(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
+ CRT_HOTPLUG_MONITOR_COLOR)
+ {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ * Detects CRT presence by checking for load.
+ *
+ * Requires that the current pipe's DPLL is active. This will cause flicker
+ * on the CRT, so it should not be used while the display is being used. Only
+ * color (not monochrome) displays are detected.
+ *
+ * \return TRUE if CRT is connected.
+ * \return FALSE if CRT is disconnected.
+ */
+static Bool
+i830_crt_detect_load(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 adpa, pipeconf;
+ CARD8 st00;
+ int pipeconf_reg, bclrpat_reg, dpll_reg;
+ int pipe;
+
+ pipe = pI830->pipe;
+ if (pipe == 0) {
+ bclrpat_reg = BCLRPAT_A;
+ pipeconf_reg = PIPEACONF;
+ dpll_reg = DPLL_A;
+ } else {
+ bclrpat_reg = BCLRPAT_B;
+ pipeconf_reg = PIPEBCONF;
+ dpll_reg = DPLL_B;
+ }
+
+ /* Don't try this if the DPLL isn't running. */
+ if (!(INREG(dpll_reg) & DPLL_VCO_ENABLE))
+ return FALSE;
+
+ adpa = INREG(ADPA);
+
+ /* Enable CRT output if disabled. */
+ if (!(adpa & ADPA_DAC_ENABLE)) {
+ OUTREG(ADPA, adpa | ADPA_DAC_ENABLE |
+ ((pipe == 1) ? ADPA_PIPE_B_SELECT : 0));
+ }
+
+ /* Set the border color to red, green. Maybe we should save/restore this
+ * reg.
+ */
+ OUTREG(bclrpat_reg, 0x00500050);
+
+ /* Force the border color through the active region */
+ pipeconf = INREG(pipeconf_reg);
+ OUTREG(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+
+ /* Read the ST00 VGA status register */
+ st00 = pI830->readStandard(pI830, 0x3c2);
+
+ /* Restore previous settings */
+ OUTREG(pipeconf_reg, pipeconf);
+ OUTREG(ADPA, adpa);
+
+ if (st00 & (1 << 4))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/**
+ * Detects CRT presence by probing for a response on the DDC address.
+ *
+ * This takes approximately 5ms in testing on an i915GM, with CRT connected or
+ * not.
+ *
+ * \return TRUE if the CRT is connected and responded to DDC.
+ * \return FALSE if no DDC response was detected.
+ */
+static Bool
+i830_crt_detect_ddc(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ struct _I830OutputRec *output;
+
+ output = &pI830->output[0];
+ /* CRT should always be at 0, but check anyway */
+ if (output->type != I830_OUTPUT_ANALOG)
+ return FALSE;
+
+ return xf86I2CProbeAddress(output->pDDCBus, 0x00A0);
+}
+
+/**
+ * Attempts to detect CRT presence through any method available.
+ *
+ * @param allow_disturb enables detection methods that may cause flickering
+ * on active displays.
+ */
+static enum detect_status
+i830_crt_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830)) {
+ if (i830_crt_detect_hotplug(pScrn))
+ return OUTPUT_STATUS_CONNECTED;
+ else
+ return OUTPUT_STATUS_DISCONNECTED;
+ }
+
+ if (i830_crt_detect_ddc(pScrn))
+ return OUTPUT_STATUS_CONNECTED;
+
+ /* Use the load-detect method if we're not currently outputting to the CRT,
+ * or we don't care.
+ *
+ * Actually, the method is unreliable currently. We need to not share a
+ * pipe, as it seems having other outputs on that pipe will result in a
+ * false positive.
+ */
+ if (0) {
+ if (i830_crt_detect_load(pScrn))
+ return OUTPUT_STATUS_CONNECTED;
+ else
+ return OUTPUT_STATUS_DISCONNECTED;
+ }
+
+ return OUTPUT_STATUS_UNKNOWN;
+}
+
void
i830_crt_init(ScrnInfoPtr pScrn)
{
@@ -124,6 +285,7 @@ i830_crt_init(ScrnInfoPtr pScrn)
pI830->output[pI830->num_outputs].mode_valid = i830_crt_mode_valid;
pI830->output[pI830->num_outputs].pre_set_mode = i830_crt_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_crt_post_set_mode;
+ pI830->output[pI830->num_outputs].detect = i830_crt_detect;
/* Set up the DDC bus. */
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,