diff options
Diffstat (limited to 'src/i830_tv.c')
-rw-r--r-- | src/i830_tv.c | 238 |
1 files changed, 149 insertions, 89 deletions
diff --git a/src/i830_tv.c b/src/i830_tv.c index ec78337a..c2192500 100644 --- a/src/i830_tv.c +++ b/src/i830_tv.c @@ -38,6 +38,7 @@ #include "i830_display.h" enum tv_type { + TV_TYPE_NONE, TV_TYPE_UNKNOWN, TV_TYPE_COMPOSITE, TV_TYPE_SVIDEO, @@ -46,6 +47,7 @@ enum tv_type { /** Private structure for the integrated TV support */ struct i830_tv_priv { + int type; CARD32 save_TV_H_CTL_1; CARD32 save_TV_H_CTL_2; CARD32 save_TV_H_CTL_3; @@ -141,69 +143,8 @@ const struct tv_mode { } }; - -static int -i830_tv_detect_type(I830_xf86OutputPtr output) -{ - ScrnInfoPtr pScrn = output->scrn; - I830Ptr pI830 = I830PTR(pScrn); - I830_xf86CrtcPtr crtc = output->crtc; - I830CrtcPrivatePtr intel_crtc = crtc->driver_private; - CARD32 save_tv_ctl, save_tv_dac; - CARD32 tv_ctl, tv_dac; - - save_tv_ctl = INREG(TV_CTL); - save_tv_dac = INREG(TV_DAC); - - /* First, we have to disable the encoder but source from the right pipe, - * which is already enabled. - */ - tv_ctl = INREG(TV_CTL) & ~(TV_ENC_ENABLE | TV_ENC_PIPEB_SELECT); - if (intel_crtc->pipe == 1) - tv_ctl |= TV_ENC_PIPEB_SELECT; - OUTREG(TV_CTL, tv_ctl); - - /* Then set the voltage overrides. */ - tv_dac = DAC_CTL_OVERRIDE | DAC_A_0_7_V | DAC_B_0_7_V | DAC_C_0_7_V; - OUTREG(TV_DAC, tv_dac); - - /* Enable sensing of the load. */ - tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; - OUTREG(TV_CTL, tv_ctl); - - tv_dac |= TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL | - TVDAC_C_SENSE_CTL; - OUTREG(TV_DAC, tv_dac); - - /* Wait for things to take effect. */ - i830WaitForVblank(pScrn); - - tv_dac = INREG(TV_DAC); - - OUTREG(TV_DAC, save_tv_dac); - OUTREG(TV_CTL, save_tv_ctl); - - if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected Composite TV connection\n"); - return TV_TYPE_COMPOSITE; - } else if ((tv_dac & TVDAC_SENSE_MASK) == TVDAC_A_SENSE) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected S-Video TV connection\n"); - return TV_TYPE_SVIDEO; - } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Detected Component TV connection\n"); - return TV_TYPE_COMPONENT; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Couldn't detect TV connection\n"); - return TV_TYPE_UNKNOWN; - } -} - static void -i830_tv_dpms(I830_xf86OutputPtr output, int mode) +i830_tv_dpms(xf86OutputPtr output, int mode) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); @@ -221,7 +162,7 @@ i830_tv_dpms(I830_xf86OutputPtr output, int mode) } static void -i830_tv_save(I830_xf86OutputPtr output) +i830_tv_save(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); @@ -247,7 +188,7 @@ i830_tv_save(I830_xf86OutputPtr output) } static void -i830_tv_restore(I830_xf86OutputPtr output) +i830_tv_restore(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); @@ -273,13 +214,13 @@ i830_tv_restore(I830_xf86OutputPtr output) } static int -i830_tv_mode_valid(I830_xf86OutputPtr output, DisplayModePtr pMode) +i830_tv_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) { return MODE_OK; } static void -i830_tv_pre_set_mode(I830_xf86OutputPtr output, DisplayModePtr pMode) +i830_tv_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); @@ -355,20 +296,22 @@ static const CARD32 v_chroma[43] = { }; static void -i830_tv_post_set_mode(I830_xf86OutputPtr output, DisplayModePtr pMode) +i830_tv_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode) { - ScrnInfoPtr pScrn = output->scrn; - I830Ptr pI830 = I830PTR(pScrn); - I830_xf86CrtcPtr crtc = output->crtc; - I830CrtcPrivatePtr intel_crtc = crtc->driver_private; - enum tv_type type; - const struct tv_mode *tv_mode; + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = output->crtc; + I830OutputPrivatePtr intel_output = output->driver_private; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + enum tv_type type; + const struct tv_mode *tv_mode; const struct tv_sc_mode *sc_mode; - CARD32 tv_ctl, tv_filter_ctl; - CARD32 hctl1, hctl2, hctl3; - CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; - CARD32 scctl1, scctl2, scctl3; - int i; + CARD32 tv_ctl, tv_filter_ctl; + CARD32 hctl1, hctl2, hctl3; + CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; + CARD32 scctl1, scctl2, scctl3; + int i; /* Need to actually choose or construct the appropriate * mode. For now, just set the first one in the list, with @@ -377,7 +320,7 @@ i830_tv_post_set_mode(I830_xf86OutputPtr output, DisplayModePtr pMode) tv_mode = &tv_modes[0]; sc_mode = &tv_sc_modes[TV_SC_NTSC_MJ]; - type = i830_tv_detect_type(output); + type = dev_priv->type; hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | (tv_mode->htotal << TV_HTOTAL_SHIFT); @@ -503,6 +446,99 @@ i830_tv_post_set_mode(I830_xf86OutputPtr output, DisplayModePtr pMode) OUTREG(TV_CTL, tv_ctl); } +static const DisplayModeRec tvModes[] = { + { + .name = "NTSC 480i", + .Clock = 108000, + + .HDisplay = 1024, + .HSyncStart = 1048, + .HSyncEnd = 1184, + .HTotal = 1344, + + .VDisplay = 768, + .VSyncStart = 771, + .VSyncEnd = 777, + .VTotal = 806, + + .type = M_T_DEFAULT + } +}; + +/** + * Detects TV presence by checking for load. + * + * Requires that the current pipe's DPLL is active. + + * \return TRUE if TV is connected. + * \return FALSE if TV is disconnected. + */ +static int +i830_tv_detect_type (xf86CrtcPtr crtc, + xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + CARD32 tv_ctl, save_tv_ctl; + CARD32 tv_dac, save_tv_dac; + int type = TV_TYPE_UNKNOWN; + + tv_dac = INREG(TV_DAC); + /* + * Detect TV by polling) + */ + if (intel_output->load_detect_temp) + { + /* TV not currently running, prod it with destructive detect */ + save_tv_dac = tv_dac; + tv_ctl = INREG(TV_CTL); + save_tv_ctl = tv_ctl; + tv_ctl &= ~TV_ENC_ENABLE; + tv_ctl &= ~TV_TEST_MODE_MASK; + tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; + tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac |= (TVDAC_STATE_CHG_EN | + TVDAC_A_SENSE_CTL | + TVDAC_B_SENSE_CTL | + TVDAC_C_SENSE_CTL); + tv_dac = DAC_CTL_OVERRIDE | DAC_A_0_7_V | DAC_B_0_7_V | DAC_C_0_7_V; + OUTREG(TV_CTL, tv_ctl); + OUTREG(TV_DAC, tv_dac); + i830WaitForVblank(pScrn); + tv_dac = INREG(TV_DAC); + OUTREG(TV_DAC, save_tv_dac); + OUTREG(TV_CTL, save_tv_ctl); + } + /* + * A B C + * 0 1 1 Composite + * 1 0 X svideo + * 0 0 0 Component + */ + if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Composite TV connection\n"); + type = TV_TYPE_COMPOSITE; + } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected S-Video TV connection\n"); + type = TV_TYPE_SVIDEO; + } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Component TV connection\n"); + type = TV_TYPE_COMPONENT; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Couldn't detect TV connection\n"); + type = TV_TYPE_NONE; + } + + dev_priv->type = type; + return type; +} + /** * Detect the TV connection. * @@ -510,10 +546,34 @@ i830_tv_post_set_mode(I830_xf86OutputPtr output, DisplayModePtr pMode) * we have a pipe programmed in order to probe the TV. */ static enum detect_status -i830_tv_detect(I830_xf86OutputPtr output) +i830_tv_detect(xf86OutputPtr output) { - /* XXX need to load-detect */ - return OUTPUT_STATUS_CONNECTED; + xf86CrtcPtr crtc; + DisplayModeRec mode; + I830OutputPrivatePtr intel_output = output->driver_private; + int type; + + crtc = i830GetLoadDetectPipe (output); + if (!crtc) + return OUTPUT_STATUS_UNKNOWN; + + if (intel_output->load_detect_temp) + { + mode = tvModes[0]; + I830xf86SetModeCrtc (&mode, INTERLACE_HALVE_V); + i830PipeSetMode (crtc, &mode, FALSE); + } + type = i830_tv_detect_type (crtc, output); + i830ReleaseLoadDetectPipe (output); + + switch (type) { + case TV_TYPE_NONE: + return OUTPUT_STATUS_DISCONNECTED; + case TV_TYPE_UNKNOWN: + return OUTPUT_STATUS_UNKNOWN; + default: + return OUTPUT_STATUS_CONNECTED; + } } /** @@ -523,7 +583,7 @@ i830_tv_detect(I830_xf86OutputPtr output) * how to probe modes off of TV connections. */ static DisplayModePtr -i830_tv_get_modes(I830_xf86OutputPtr output) +i830_tv_get_modes(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); @@ -565,13 +625,13 @@ i830_tv_get_modes(I830_xf86OutputPtr output) } static void -i830_tv_destroy (I830_xf86OutputPtr output) +i830_tv_destroy (xf86OutputPtr output) { if (output->driver_private) xfree (output->driver_private); } -static const I830_xf86OutputFuncsRec i830_tv_output_funcs = { +static const xf86OutputFuncsRec i830_tv_output_funcs = { .dpms = i830_tv_dpms, .save = i830_tv_save, .restore = i830_tv_restore, @@ -587,15 +647,14 @@ void i830_tv_init(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - I830_xf86OutputPtr output; + xf86OutputPtr output; I830OutputPrivatePtr intel_output; struct i830_tv_priv *dev_priv; if ((INREG(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) return; - output = i830xf86OutputCreate (pScrn, &i830_tv_output_funcs, - "TV"); + output = xf86OutputCreate (pScrn, &i830_tv_output_funcs, "TV"); if (!output) return; @@ -604,12 +663,13 @@ i830_tv_init(ScrnInfoPtr pScrn) sizeof (struct i830_tv_priv), 1); if (!intel_output) { - i830xf86OutputDestroy (output); + xf86OutputDestroy (output); return; } dev_priv = (struct i830_tv_priv *) (intel_output + 1); intel_output->type = I830_OUTPUT_SDVO; intel_output->dev_priv = dev_priv; + dev_priv->type = TV_TYPE_UNKNOWN; output->driver_private = intel_output; } |