summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2006-12-05 10:01:31 -0800
committerEric Anholt <eric@anholt.net>2006-12-05 12:15:34 -0800
commite777d38ce98d7220621b049b09df1deca5a5df42 (patch)
tree441a22533d263d5e1a2778f9bc560c99bcc54568 /src
parent81dde11d419c8f9198ab3502d9813d66d0bc6d6d (diff)
WIP code to move mode set sequencing to XFree86 handlers.
It compiles. It definitely doesn't run.
Diffstat (limited to 'src')
-rw-r--r--src/i830_crt.c20
-rw-r--r--src/i830_display.c428
-rw-r--r--src/i830_display.h1
-rw-r--r--src/i830_driver.c67
-rw-r--r--src/i830_dvo.c49
-rw-r--r--src/i830_lvds.c105
-rw-r--r--src/i830_sdvo.c53
-rw-r--r--src/i830_tv.c35
-rw-r--r--src/i830_xf86Crtc.h56
9 files changed, 488 insertions, 326 deletions
diff --git a/src/i830_crt.c b/src/i830_crt.c
index 7a706d14..ebd83bc4 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -93,13 +93,16 @@ i830_crt_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
return MODE_OK;
}
-static void
-i830_crt_pre_set_mode (xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_crt_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
+ return TRUE;
}
static void
-i830_crt_post_set_mode (xf86OutputPtr output, DisplayModePtr pMode)
+i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
@@ -122,11 +125,10 @@ i830_crt_post_set_mode (xf86OutputPtr output, DisplayModePtr pMode)
OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
}
- adpa = ADPA_DAC_ENABLE;
-
- if (pMode->Flags & V_PHSYNC)
+ adpa = 0;
+ if (adjusted_mode->Flags & V_PHSYNC)
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
- if (pMode->Flags & V_PVSYNC)
+ if (adjusted_mode->Flags & V_PVSYNC)
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
if (i830_crtc->pipe == 0)
@@ -372,8 +374,8 @@ static const xf86OutputFuncsRec i830_crt_output_funcs = {
.save = i830_crt_save,
.restore = i830_crt_restore,
.mode_valid = i830_crt_mode_valid,
- .pre_set_mode = i830_crt_pre_set_mode,
- .post_set_mode = i830_crt_post_set_mode,
+ .mode_fixup = i830_crt_mode_fixup,
+ .mode_set = i830_crt_mode_set,
.detect = i830_crt_detect,
.get_modes = i830_crt_get_modes,
.destroy = i830_crt_destroy
diff --git a/src/i830_display.c b/src/i830_display.c
index 29b783bf..eab82f6e 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -408,34 +408,94 @@ i830PipeInUse (xf86CrtcPtr crtc)
return FALSE;
}
+static void
+i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ CARD32 temp;
+
+ /* XXX: When our outputs are all unaware of DPMS modes other than off and
+ * on, we should map those modes to DPMSModeOff in the CRTC.
+ */
+ switch (mode) {
+ case DPMSModeOn:
+ case DPMSModeStandby:
+ case DPMSModeSuspend:
+ /* Enable the DPLL */
+ temp = INREG(dpll_reg);
+ OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
+
+ /* Wait for the clocks to stabilize. */
+ usleep(150);
+
+ /* Enable the pipe */
+ temp = INREG(pipeconf_reg);
+ OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+
+ /* Enable the plane */
+ temp = INREG(dspcntr_reg);
+ OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+ break;
+ case DPMSModeOff:
+ /* Disable display plane */
+ temp = INREG(dspcntr_reg);
+ OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+
+ /* Disable the VGA plane that we never use */
+ OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+
+ if (!IS_I9XX(pI830)) {
+ /* Wait for vblank for the disable to take effect */
+ i830WaitForVblank(pScrn);
+ }
+
+ /* Next, disable display pipes */
+ temp = INREG(pipeconf_reg);
+ OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+
+ /* Wait for vblank for the disable to take effect. */
+ i830WaitForVblank(pScrn);
+
+ temp = INREG(dpll_reg);
+ OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+ break;
+ }
+}
+
+static Bool
+i830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
+{
+ return TRUE;
+}
+
/**
- * Sets the given video mode on the given pipe.
+ * Sets up registers for the given mode/adjusted_mode pair.
*
- * Plane A is always output to pipe A, and plane B to pipe B. The plane
- * will not be enabled if plane_enable is FALSE, which is used for
- * load detection, when something else will be output to the pipe other than
- * display data.
+ * The clocks, CRTCs and outputs attached to this CRTC must be off.
+ *
+ * This shouldn't enable any clocks, CRTCs, or outputs, but they should
+ * be easily turned on/off after this.
*/
-Bool
-i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
- Bool plane_enable)
+static void
+i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
int pipe = intel_crtc->pipe;
- int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
- CARD32 dpll = 0, fp = 0, temp;
- CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
- CARD32 pipesrc, dspsize;
- Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
- Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
- int refclk, pixel_clock;
- int i;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int fp_reg = (pipe == 0) ? FPA0 : FPB0;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+ int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
@@ -446,38 +506,23 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
- Bool ret = FALSE;
-#ifdef XF86DRI
- Bool didLock = FALSE;
-#endif
-
- if (xf86ModesEqual(&crtc->curMode, pMode))
- return TRUE;
-
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested pix clock: %d\n",
- pMode->Clock);
-
- crtc->enabled = i830PipeInUse (crtc);
-
- if (!crtc->enabled)
- {
- /* XXX disable crtc? */
- return TRUE;
- }
+ int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
+ int i;
+ int refclk;
+ CARD32 dpll = 0, fp = 0, temp, dspcntr;
+ Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
+ Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
-#ifdef XF86DRI
- didLock = I830DRILock(pScrn);
-#endif
-
- for (i = 0; i < pI830->xf86_config.num_output; i++)
- {
+ /* Set up some convenient bools for what outputs are connected to
+ * our pipe, used in DPLL setup.
+ */
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
xf86OutputPtr output = pI830->xf86_config.output[i];
- I830OutputPrivatePtr intel_output = output->driver_private;
+ I830OutputPrivatePtr intel_output = output->driver_private;
+
if (output->crtc != crtc)
continue;
- (*output->funcs->pre_set_mode)(output, pMode);
-
switch (intel_output->type) {
case I830_OUTPUT_LVDS:
is_lvds = TRUE;
@@ -497,90 +542,23 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
}
}
- if (is_lvds && (is_sdvo || is_dvo || is_tv || is_crt)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't enable LVDS and non-LVDS on the same pipe\n");
- goto done;
- }
- if (is_tv && (is_sdvo || is_dvo || is_crt || is_lvds)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't enable a TV and any other output on the same "
- "pipe\n");
- goto done;
- }
- if (pipe == 0 && is_lvds) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't support LVDS on pipe A\n");
- goto done;
- }
-
- htot = (pMode->CrtcHDisplay - 1) | ((pMode->CrtcHTotal - 1) << 16);
- hblank = (pMode->CrtcHBlankStart - 1) | ((pMode->CrtcHBlankEnd - 1) << 16);
- hsync = (pMode->CrtcHSyncStart - 1) | ((pMode->CrtcHSyncEnd - 1) << 16);
- vtot = (pMode->CrtcVDisplay - 1) | ((pMode->CrtcVTotal - 1) << 16);
- vblank = (pMode->CrtcVBlankStart - 1) | ((pMode->CrtcVBlankEnd - 1) << 16);
- vsync = (pMode->CrtcVSyncStart - 1) | ((pMode->CrtcVSyncEnd - 1) << 16);
- pipesrc = ((pMode->HDisplay - 1) << 16) | (pMode->VDisplay - 1);
- dspsize = ((pMode->VDisplay - 1) << 16) | (pMode->HDisplay - 1);
- pixel_clock = pMode->Clock;
-
- if (is_lvds && pI830->panel_fixed_hactive != 0) {
- /* To enable panel fitting, we need to set the pipe timings to that of
- * the screen at its full resolution. So, drop the timings from the
- * BIOS VBT tables here.
- */
- htot = (pI830->panel_fixed_hactive - 1) |
- ((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
- << 16);
- hblank = (pI830->panel_fixed_hactive - 1) |
- ((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
- << 16);
- hsync = (pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff - 1) |
- ((pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff +
- pI830->panel_fixed_hsyncwidth - 1) << 16);
-
- vtot = (pI830->panel_fixed_vactive - 1) |
- ((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
- << 16);
- vblank = (pI830->panel_fixed_vactive - 1) |
- ((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
- << 16);
- vsync = (pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff - 1) |
- ((pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff +
- pI830->panel_fixed_vsyncwidth - 1) << 16);
- pixel_clock = pI830->panel_fixed_clock;
-
- if (pMode->HDisplay <= pI830->panel_fixed_hactive &&
- pMode->HDisplay <= pI830->panel_fixed_vactive)
- {
- pipesrc = ((pMode->HDisplay - 1) << 16) |
- (pMode->VDisplay - 1);
- dspsize = ((pMode->VDisplay - 1) << 16) |
- (pMode->HDisplay - 1);
- }
- }
-
- /* Adjust the clock for pixel multiplication.
- * See DPLL_MD_UDI_MULTIPLIER_MASK.
- */
- if (is_sdvo) {
- pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode);
- }
-
if (IS_I9XX(pI830)) {
refclk = 96000;
} else {
refclk = 48000;
}
- ok = i830FindBestPLL(crtc, pixel_clock, refclk, &m1, &m2, &n,
+
+ ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &m1, &m2, &n,
&p1, &p2);
- if (!ok) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Couldn't find PLL settings for mode!\n");
- goto done;
- }
+ if (!ok)
+ FatalError("Couldn't find PLL settings for mode!\n");
- dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
+ fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
+
+ i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
+ ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
+
+ dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(pI830)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
@@ -615,33 +593,15 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
}
-#if 0
+#if 0
else if (is_lvds)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
#endif
- else
+ else
dpll |= PLL_REF_INPUT_DREFCLK;
- fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
-
-#if 1
- ErrorF("hact: %d htot: %d hbstart: %d hbend: %d hsyncstart: %d hsyncend: %d\n",
- (int)(htot & 0xffff) + 1, (int)(htot >> 16) + 1,
- (int)(hblank & 0xffff) + 1, (int)(hblank >> 16) + 1,
- (int)(hsync & 0xffff) + 1, (int)(hsync >> 16) + 1);
- ErrorF("vact: %d vtot: %d vbstart: %d vbend: %d vsyncstart: %d vsyncend: %d\n",
- (int)(vtot & 0xffff) + 1, (int)(vtot >> 16) + 1,
- (int)(vblank & 0xffff) + 1, (int)(vblank >> 16) + 1,
- (int)(vsync & 0xffff) + 1, (int)(vsync >> 16) + 1);
- ErrorF("pipesrc: %dx%d, dspsize: %dx%d\n",
- (int)(pipesrc >> 16) + 1, (int)(pipesrc & 0xffff) + 1,
- (int)(dspsize & 0xffff) + 1, (int)(dspsize >> 16) + 1);
-#endif
-
- i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
- ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
-
- dspcntr = DISPLAY_PLANE_ENABLE;
+ /* Set up the display plane register */
+ dspcntr = 0;
switch (pScrn->bitsPerPixel) {
case 8:
dspcntr |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
@@ -668,61 +628,139 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
- OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+ OUTREG(fp_reg, fp);
+ OUTREG(dpll_reg, dpll);
+ if (IS_I965G(pI830)) {
+ /* Set the SDVO multiplier/divider to 1x for the sake of analog output.
+ * It will be updated by the SDVO code if SDVO had fixed up the clock
+ * for a higher multiplier.
+ */
+ OUTREG(dpll_md_reg, 0);
+ }
- /* Finally, set the mode. */
- /* First, disable display planes */
- temp = INREG(dspcntr_reg);
- OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+ OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) |
+ ((adjusted_mode->CrtcHTotal - 1) << 16));
+ OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) |
+ ((adjusted_mode->CrtcHBlankEnd - 1) << 16));
+ OUTREG(hsync_reg, (adjusted_mode->CrtcHSyncStart - 1) |
+ ((adjusted_mode->CrtcHSyncEnd - 1) << 16));
+ OUTREG(vtot_reg, (adjusted_mode->CrtcVDisplay - 1) |
+ ((adjusted_mode->CrtcVTotal - 1) << 16));
+ OUTREG(vblank_reg, (adjusted_mode->CrtcVBlankStart - 1) |
+ ((adjusted_mode->CrtcVBlankEnd - 1) << 16));
+ OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) |
+ ((adjusted_mode->CrtcVSyncEnd - 1) << 16));
+ OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
+ /* pipesrc and dspsize control the size that is scaled from, which should
+ * always be the user's requested size.
+ */
+ OUTREG(dspsize_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+ OUTREG(dsppos_reg, 0);
+ i830PipeSetBase(crtc, crtc->x, crtc->y);
+ OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+ temp = INREG(pipeconf_reg);
+ OUTREG(pipeconf_reg, temp);
+ OUTREG(dspcntr_reg, dspcntr);
- /* Wait for vblank for the disable to take effect */
- i830WaitForVblank(pScrn);
+ /* Disable the panel fitter if it was on our pipe */
+ if (!IS_I830(pI830) && ((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
+ OUTREG(PFIT_CONTROL, 0);
+}
- /* Next, disable display pipes */
- temp = INREG(pipeconf_reg);
- OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+/**
+ * Sets the given video mode on the given pipe.
+ *
+ * Plane A is always output to pipe A, and plane B to pipe B. The plane
+ * will not be enabled if plane_enable is FALSE, which is used for
+ * load detection, when something else will be output to the pipe other than
+ * display data.
+ */
+Bool
+i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
+ Bool plane_enable)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ int i;
+ Bool ret = FALSE;
+#ifdef XF86DRI
+ Bool didLock = FALSE;
+#endif
+ DisplayModePtr adjusted_mode;
- OUTREG(fp_reg, fp);
- OUTREG(dpll_reg, dpll);
+ /* XXX: curMode */
+
+ adjusted_mode = xf86DuplicateMode(pMode);
+
+ crtc->enabled = i830PipeInUse (crtc);
+
+ if (!crtc->enabled)
+ {
+ /* XXX disable crtc? */
+ return TRUE;
+ }
+
+#ifdef XF86DRI
+ didLock = I830DRILock(pScrn);
+#endif
- /*
- * If the panel fitter is stuck on our pipe, turn it off.
- * The LVDS output will set it as necessary in post_set_mode.
+ /* Pass our mode to the outputs and the CRTC to give them a chance to
+ * adjust it according to limitations or output properties, and also
+ * a chance to reject the mode entirely.
*/
- if (!IS_I830(pI830)) {
- if (((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
- OUTREG(PFIT_CONTROL, 0);
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+
+ if (output->crtc != crtc)
+ continue;
+
+ if (!output->funcs->mode_fixup(output, pMode, adjusted_mode)) {
+ ret = FALSE;
+ goto done;
+ }
}
+ if (!crtc->funcs->mode_fixup(crtc, pMode, adjusted_mode)) {
+ ret = FALSE;
+ goto done;
+ }
+
+ /* Disable the outputs and CRTCs before setting the mode. */
for (i = 0; i < pI830->xf86_config.num_output; i++) {
- xf86OutputPtr output = pI830->xf86_config.output[i];
- if (output->crtc == crtc)
- (*output->funcs->post_set_mode)(output, pMode);
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+
+ if (output->crtc != crtc)
+ continue;
+
+ /* Disable the output as the first thing we do. */
+ output->funcs->dpms(output, DPMSModeOff);
}
- OUTREG(htot_reg, htot);
- OUTREG(hblank_reg, hblank);
- OUTREG(hsync_reg, hsync);
- OUTREG(vtot_reg, vtot);
- OUTREG(vblank_reg, vblank);
- OUTREG(vsync_reg, vsync);
- OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
- OUTREG(dspsize_reg, dspsize);
- OUTREG(dsppos_reg, 0);
- i830PipeSetBase(crtc, crtc->x, crtc->y);
- OUTREG(pipesrc_reg, pipesrc);
+ crtc->funcs->dpms(crtc, DPMSModeOff);
- /* Then, turn the pipe on first */
- temp = INREG(pipeconf_reg);
- OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ /* Set up the DPLL and any output state that needs to adjust or depend
+ * on the DPLL.
+ */
+ crtc->funcs->mode_set(crtc, pMode, adjusted_mode);
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+ if (output->crtc == crtc)
+ output->funcs->mode_set(output, pMode, adjusted_mode);
+ }
- if (plane_enable) {
- /* And then turn the plane on */
- OUTREG(dspcntr_reg, dspcntr);
+ /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
+ crtc->funcs->dpms(crtc, DPMSModeOn);
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+ if (output->crtc == crtc)
+ output->funcs->dpms(output, DPMSModeOn);
}
crtc->curMode = *pMode;
+ i830DumpRegs(pScrn);
+
+ /* XXX free adjustedmode */
ret = TRUE;
done:
#ifdef XF86DRI
@@ -962,3 +1000,29 @@ i830ReleaseLoadDetectPipe(xf86OutputPtr output)
i830DisableUnusedFunctions(pScrn);
}
}
+
+static const xf86CrtcFuncsRec i830_crtc_funcs = {
+ .dpms = i830_crtc_dpms,
+ .save = NULL, /* XXX */
+ .restore = NULL, /* XXX */
+ .mode_fixup = i830_crtc_mode_fixup,
+ .mode_set = i830_crtc_mode_set,
+ .destroy = NULL, /* XXX */
+};
+
+void
+i830_crtc_init(ScrnInfoPtr pScrn, int pipe)
+{
+ xf86CrtcPtr crtc;
+ I830CrtcPrivatePtr intel_crtc;
+
+ crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs);
+ if (crtc == NULL)
+ return;
+
+ intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1);
+ intel_crtc->pipe = pipe;
+
+ crtc->driver_private = intel_crtc;
+}
+
diff --git a/src/i830_display.h b/src/i830_display.h
index c80c3f72..c1725ab1 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -41,6 +41,7 @@ void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn);
xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output);
void i830ReleaseLoadDetectPipe(xf86OutputPtr output);
Bool i830PipeInUse(xf86CrtcPtr crtc);
+void i830_crtc_init(ScrnInfoPtr pScrn, int pipe);
/** @{
*/
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 3aafe3aa..8f017ab2 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -715,28 +715,7 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
* Setup the CRTCs
*/
-static const xf86CrtcFuncsRec i830_crtc_funcs = {
-};
-
-static void
-I830SetupCrtcs(ScrnInfoPtr pScrn, int num_pipe)
-{
- int p;
- for (p = 0; p < num_pipe; p++)
- {
- xf86CrtcPtr crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs);
- I830CrtcPrivatePtr intel_crtc;
-
- if (!crtc)
- break;
- intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1);
- intel_crtc->pipe = p;
-
- crtc->driver_private = intel_crtc;
- }
-}
-
static void
I830PreInitDDC(ScrnInfoPtr pScrn)
{
@@ -1340,7 +1319,9 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
I830PreInitDDC(pScrn);
I830SetupOutputs(pScrn);
- I830SetupCrtcs(pScrn, num_pipe);
+ for (i = 0; i < num_pipe; i++) {
+ i830_crtc_init(pScrn, i);
+ }
if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) {
if (num_pipe == 1) {
@@ -2286,7 +2267,13 @@ RestoreHWState(ScrnInfoPtr pScrn)
vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS);
vgaHWLock(hwp);
- /* First, disable display planes */
+ /* Disable outputs */
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+ output->funcs->dpms(output, DPMSModeOff);
+ }
+
+ /* Disable display planes */
temp = INREG(DSPACNTR);
OUTREG(DSPACNTR, temp & ~DISPLAY_PLANE_ENABLE);
temp = INREG(DSPBCNTR);
@@ -2298,12 +2285,6 @@ RestoreHWState(ScrnInfoPtr pScrn)
temp = INREG(PIPEBCONF);
OUTREG(PIPEBCONF, temp & ~PIPEBCONF_ENABLE);
- /* Disable outputs if necessary */
- for (i = 0; i < pI830->xf86_config.num_output; i++) {
- xf86OutputPtr output = pI830->xf86_config.output[i];
- (*output->funcs->pre_set_mode) (output, NULL);
- }
-
i830WaitForVblank(pScrn);
OUTREG(FPA0, pI830->saveFPA0);
@@ -2311,6 +2292,16 @@ RestoreHWState(ScrnInfoPtr pScrn)
OUTREG(DPLL_A, pI830->saveDPLL_A);
if (IS_I965G(pI830))
OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD);
+ if(pI830->xf86_config.num_crtc == 2) {
+ OUTREG(FPB0, pI830->saveFPB0);
+ OUTREG(FPB1, pI830->saveFPB1);
+ OUTREG(DPLL_B, pI830->saveDPLL_B);
+ if (IS_I965G(pI830))
+ OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD);
+ }
+ /* Wait for clocks to stabilize */
+ usleep(150);
+
OUTREG(HTOTAL_A, pI830->saveHTOTAL_A);
OUTREG(HBLANK_A, pI830->saveHBLANK_A);
OUTREG(HSYNC_A, pI830->saveHSYNC_A);
@@ -2327,11 +2318,6 @@ RestoreHWState(ScrnInfoPtr pScrn)
}
if(pI830->xf86_config.num_crtc == 2) {
- OUTREG(FPB0, pI830->saveFPB0);
- OUTREG(FPB1, pI830->saveFPB1);
- OUTREG(DPLL_B, pI830->saveDPLL_B);
- if (IS_I965G(pI830))
- OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD);
OUTREG(HTOTAL_B, pI830->saveHTOTAL_B);
OUTREG(HBLANK_B, pI830->saveHBLANK_B);
OUTREG(HSYNC_B, pI830->saveHSYNC_B);
@@ -2348,12 +2334,8 @@ RestoreHWState(ScrnInfoPtr pScrn)
}
}
- OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
-
- for (i = 0; i < pI830->xf86_config.num_output; i++) {
- xf86OutputPtr output = pI830->xf86_config.output[i];
- (*output->funcs->restore) (output);
- }
+ if (!IS_I830(pI830) && !IS_845G(pI830))
+ OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
if (IS_I965G(pI830)) {
OUTREG(DSPASURF, pI830->saveDSPASURF);
@@ -2371,6 +2353,11 @@ RestoreHWState(ScrnInfoPtr pScrn)
OUTREG(DSPACNTR, pI830->saveDSPACNTR);
OUTREG(DSPBCNTR, pI830->saveDSPBCNTR);
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr output = pI830->xf86_config.output[i];
+ (*output->funcs->restore) (output);
+ }
+
for(i = 0; i < 7; i++) {
OUTREG(SWF0 + (i << 2), pI830->saveSWF[i]);
OUTREG(SWF00 + (i << 2), pI830->saveSWF[i+7]);
diff --git a/src/i830_dvo.c b/src/i830_dvo.c
index 6fe31575..04d20387 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -59,11 +59,17 @@ struct _I830DVODriver i830_dvo_drivers[] =
static void
i830_dvo_dpms(xf86OutputPtr output, int mode)
{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
I830OutputPrivatePtr intel_output = output->driver_private;
- if (mode == DPMSModeOn)
+
+ if (mode == DPMSModeOn) {
+ OUTREG(DVOC, INREG(DVOC) | DVO_ENABLE);
(*intel_output->i2c_drv->vid_rec->Power)(intel_output->i2c_drv->dev_priv, TRUE);
- else
+ } else {
(*intel_output->i2c_drv->vid_rec->Power)(intel_output->i2c_drv->dev_priv, FALSE);
+ OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
+ }
}
static void
@@ -113,48 +119,51 @@ i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
return MODE_BAD;
}
-static void
-i830_dvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- I830OutputPrivatePtr intel_output = output->driver_private;
+ /* XXX: Hook this up to a DVO driver function */
- (*intel_output->i2c_drv->vid_rec->Mode)(intel_output->i2c_drv->dev_priv, pMode);
-
- OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
+ return TRUE;
}
static void
-i830_dvo_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_dvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
xf86CrtcPtr crtc = output->crtc;
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ I830OutputPrivatePtr intel_output = output->driver_private;
int pipe = intel_crtc->pipe;
CARD32 dvo;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ intel_output->i2c_drv->vid_rec->Mode(intel_output->i2c_drv->dev_priv,
+ mode);
+
/* Save the data order, since I don't know what it should be set to. */
dvo = INREG(DVOC) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
- dvo |= DVO_ENABLE;
dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
if (pipe == 1)
dvo |= DVO_PIPE_B_SELECT;
- if (pMode->Flags & V_PHSYNC)
+ if (adjusted_mode->Flags & V_PHSYNC)
dvo |= DVO_HSYNC_ACTIVE_HIGH;
- if (pMode->Flags & V_PVSYNC)
+ if (adjusted_mode->Flags & V_PVSYNC)
dvo |= DVO_VSYNC_ACTIVE_HIGH;
OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED);
- /*OUTREG(DVOB_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
- (pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
- OUTREG(DVOC_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
- (pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
+ /*OUTREG(DVOB_SRCDIM,
+ (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+ (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
+ OUTREG(DVOC_SRCDIM,
+ (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+ (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
/*OUTREG(DVOB, dvo);*/
OUTREG(DVOC, dvo);
}
@@ -222,8 +231,8 @@ static const xf86OutputFuncsRec i830_dvo_output_funcs = {
.save = i830_dvo_save,
.restore = i830_dvo_restore,
.mode_valid = i830_dvo_mode_valid,
- .pre_set_mode = i830_dvo_pre_set_mode,
- .post_set_mode = i830_dvo_post_set_mode,
+ .mode_fixup = i830_dvo_mode_fixup,
+ .mode_set = i830_dvo_mode_set,
.detect = i830_dvo_detect,
.get_modes = i830_ddc_get_modes,
.destroy = i830_dvo_destroy
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index cf709569..a9c0e204 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -40,7 +40,7 @@ static void
i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
{
I830Ptr pI830 = I830PTR(pScrn);
- CARD32 pp_status, pp_control;
+ CARD32 pp_status;
CARD32 blc_pwm_ctl;
int backlight_duty_cycle;
@@ -77,6 +77,8 @@ i830_lvds_dpms (xf86OutputPtr output, int mode)
i830SetLVDSPanelPower(pScrn, TRUE);
else
i830SetLVDSPanelPower(pScrn, FALSE);
+
+ /* XXX: We never power down the LVDS pair. */
}
static void
@@ -128,28 +130,86 @@ i830_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
return MODE_OK;
}
-static void
-i830_lvds_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
- ScrnInfoPtr pScrn = output->scrn;
- /* Always make sure the LVDS is off before we play with DPLLs and pipe
- * configuration. We can skip this in some cases (for example, going
- * between hi-res modes with automatic panel scaling are fine), but be
- * conservative for now.
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private;
+ int i;
+
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr other_output = pI830->xf86_config.output[i];
+
+ if (other_output != output && other_output->crtc == output->crtc) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Can't enable LVDS and another output on the same "
+ "pipe\n");
+ return FALSE;
+ }
+ }
+
+ if (intel_crtc->pipe == 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Can't support LVDS on pipe A\n");
+ return FALSE;
+ }
+
+ /* If we have timings from the BIOS for the panel, put them in
+ * to the adjusted mode. The CRTC will be set up for this mode,
+ * with the panel scaling set up to source from the H/VDisplay
+ * of the original mode.
+ */
+ if (pI830->panel_fixed_hactive != 0) {
+ adjusted_mode->HDisplay = pI830->panel_fixed_hactive;
+ adjusted_mode->HTotal = adjusted_mode->HDisplay +
+ pI830->panel_fixed_hblank;
+ adjusted_mode->HSyncStart = adjusted_mode->HDisplay +
+ pI830->panel_fixed_hsyncoff;
+ adjusted_mode->HSyncStart = adjusted_mode->HSyncStart +
+ pI830->panel_fixed_hsyncwidth;
+ adjusted_mode->VDisplay = pI830->panel_fixed_vactive;
+ adjusted_mode->VTotal = adjusted_mode->VDisplay +
+ pI830->panel_fixed_hblank;
+ adjusted_mode->VSyncStart = adjusted_mode->VDisplay +
+ pI830->panel_fixed_hsyncoff;
+ adjusted_mode->VSyncStart = adjusted_mode->VSyncStart +
+ pI830->panel_fixed_hsyncwidth;
+ adjusted_mode->Clock = pI830->panel_fixed_clock;
+ xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
+ }
+
+ /* XXX: if we don't have BIOS fixed timings (or we have
+ * a preferred mode from DDC, probably), we should use the
+ * DDC mode as the fixed timing.
*/
- i830SetLVDSPanelPower(pScrn, FALSE);
+
+ /* XXX: It would be nice to support lower refresh rates on the
+ * panels to reduce power consumption, and perhaps match the
+ * user's requested refresh rate.
+ */
+
+ return TRUE;
}
static void
-i830_lvds_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
- ScrnInfoPtr pScrn = output->scrn;
- I830Ptr pI830 = I830PTR(pScrn);
- CARD32 pfit_control;
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 pfit_control;
+
+ /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+ * This is an exception to the general rule that mode_set doesn't turn
+ * things on.
+ */
+ OUTREG(LVDS, LVDS_PORT_EN | LVDS_PIPEB_SELECT);
/* Enable automatic panel scaling so that non-native modes fill the
* screen. Should be enabled before the pipe is enabled, according to
- * register description.
+ * register description and PRM.
*/
pfit_control = (PFIT_ENABLE |
VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -159,19 +219,6 @@ i830_lvds_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
OUTREG(PFIT_CONTROL, pfit_control);
-
- /* Disable the PLL before messing with LVDS enable */
- OUTREG(FPB0, INREG(FPB0) & ~DPLL_VCO_ENABLE);
-
- /* LVDS must be powered on before PLL is enabled and before power
- * sequencing the panel.
- */
- OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
-
- /* Re-enable the PLL */
- OUTREG(FPB0, INREG(FPB0) | DPLL_VCO_ENABLE);
-
- i830SetLVDSPanelPower(pScrn, TRUE);
}
/**
@@ -234,8 +281,8 @@ static const xf86OutputFuncsRec i830_lvds_output_funcs = {
.save = i830_lvds_save,
.restore = i830_lvds_restore,
.mode_valid = i830_lvds_mode_valid,
- .pre_set_mode = i830_lvds_pre_set_mode,
- .post_set_mode = i830_lvds_post_set_mode,
+ .mode_fixup = i830_lvds_mode_fixup,
+ .mode_set = i830_lvds_mode_set,
.detect = i830_lvds_detect,
.get_modes = i830_lvds_get_modes,
.destroy = i830_lvds_destroy
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index c75800d4..7755252a 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -534,15 +534,36 @@ i830_sdvo_set_clock_rate_mult(xf86OutputPtr output, CARD8 val)
return TRUE;
}
+static Bool
+i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
+{
+ /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO
+ * device will be told of the multiplier during mode_set.
+ */
+ adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode);
+
+ return TRUE;
+}
+
static void
-i830_sdvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr mode)
+i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
- CARD16 width;
- CARD16 height;
+ xf86CrtcPtr crtc = output->crtc;
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ Bool input1, input2;
+ CARD32 dpll, sdvox;
+ int dpll_reg = (intel_crtc->pipe == 0) ? DPLL_A : DPLL_B;
+ int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+ int sdvo_pixel_multiply;
+ int i;
+ CARD8 status;
+ CARD16 width, height;
CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
CARD16 h_sync_offset, v_sync_offset;
struct i830_sdvo_dtd output_dtd;
@@ -633,26 +654,6 @@ i830_sdvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr mode)
break;
}
- OUTREG(dev_priv->output_device, INREG(dev_priv->output_device) & ~SDVO_ENABLE);
-}
-
-static void
-i830_sdvo_post_set_mode(xf86OutputPtr output, DisplayModePtr mode)
-{
- ScrnInfoPtr pScrn = output->scrn;
- I830OutputPrivatePtr intel_output = output->driver_private;
- struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
- xf86CrtcPtr crtc = output->crtc;
- I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
- I830Ptr pI830 = I830PTR(pScrn);
- Bool input1, input2;
- CARD32 dpll, sdvox;
- int dpll_reg = (intel_crtc->pipe == 0) ? DPLL_A : DPLL_B;
- int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
- int sdvo_pixel_multiply;
- int i;
- CARD8 status;
-
/* Set the SDVO control regs. */
sdvox = INREG(dev_priv->output_device);
switch (dev_priv->output_device) {
@@ -663,7 +664,7 @@ i830_sdvo_post_set_mode(xf86OutputPtr output, DisplayModePtr mode)
sdvox &= SDVOC_PRESERVE_MASK;
break;
}
- sdvox |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
+ sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
if (intel_crtc->pipe == 1)
sdvox |= SDVO_PIPE_B_SELECT;
@@ -1014,8 +1015,8 @@ static const xf86OutputFuncsRec i830_sdvo_output_funcs = {
.save = i830_sdvo_save,
.restore = i830_sdvo_restore,
.mode_valid = i830_sdvo_mode_valid,
- .pre_set_mode = i830_sdvo_pre_set_mode,
- .post_set_mode = i830_sdvo_post_set_mode,
+ .mode_fixup = i830_sdvo_mode_fixup,
+ .mode_set = i830_sdvo_mode_set,
.detect = i830_sdvo_detect,
.get_modes = i830_ddc_get_modes,
.destroy = i830_sdvo_destroy
diff --git a/src/i830_tv.c b/src/i830_tv.c
index f5716f8b..87aecda6 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -295,8 +295,33 @@ static const CARD32 v_chroma[43] = {
0x28003100, 0x28002F00, 0x00003100,
};
+static Bool
+i830_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ int i;
+
+ for (i = 0; i < pI830->xf86_config.num_output; i++) {
+ xf86OutputPtr other_output = pI830->xf86_config.output[i];
+
+ if (other_output != output && other_output->crtc == output->crtc) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Can't enable TV and another output on the same "
+ "pipe\n");
+ return FALSE;
+ }
+ }
+
+ /* XXX: fill me in */
+
+ return TRUE;
+}
+
static void
-i830_tv_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
@@ -359,7 +384,7 @@ i830_tv_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
- tv_ctl = TV_ENC_ENABLE;
+ tv_ctl = 0;
if (intel_crtc->pipe == 1)
tv_ctl |= TV_ENC_PIPEB_SELECT;
@@ -403,7 +428,7 @@ i830_tv_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
tv_filter_ctl = TV_AUTO_SCALE;
- if (pMode->HDisplay > 1024)
+ if (mode->HDisplay > 1024)
tv_ctl |= TV_V_FILTER_BYPASS;
OUTREG(TV_H_CTL_1, hctl1);
@@ -635,8 +660,8 @@ static const xf86OutputFuncsRec i830_tv_output_funcs = {
.save = i830_tv_save,
.restore = i830_tv_restore,
.mode_valid = i830_tv_mode_valid,
- .pre_set_mode = i830_tv_pre_set_mode,
- .post_set_mode = i830_tv_post_set_mode,
+ .mode_fixup = i830_tv_mode_fixup,
+ .mode_set = i830_tv_mode_set,
.detect = i830_tv_detect,
.get_modes = i830_tv_get_modes,
.destroy = i830_tv_destroy
diff --git a/src/i830_xf86Crtc.h b/src/i830_xf86Crtc.h
index 2952c8d5..b5dbe511 100644
--- a/src/i830_xf86Crtc.h
+++ b/src/i830_xf86Crtc.h
@@ -27,14 +27,15 @@
#include "i830_xf86Modes.h"
typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
+typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
typedef struct _xf86CrtcFuncs {
/**
* Turns the crtc on/off, or sets intermediate power levels if available.
*
* Unsupported intermediate modes drop to the lower power setting. If the
- * mode is DPMSModeOff, the crtc must be disabled, as the DPLL may be
- * disabled afterwards.
+ * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to
+ * be safe to call mode_set.
*/
void
(*dpms)(xf86CrtcPtr crtc,
@@ -52,6 +53,27 @@ typedef struct _xf86CrtcFuncs {
void
(*restore)(xf86CrtcPtr crtc);
+
+ /**
+ * Callback to adjust the mode to be set in the CRTC.
+ *
+ * This allows a CRTC 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)(xf86CrtcPtr crtc,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode);
+
+ /**
+ * Callback for setting up a video mode after fixups have been made.
+ */
+ void
+ (*mode_set)(xf86CrtcPtr crtc,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode);
+
/**
* Clean up driver-specific bits of the crtc
*/
@@ -127,8 +149,6 @@ struct _xf86Crtc {
#endif
};
-typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
-
typedef struct _xf86OutputFuncs {
/**
* Turns the output on/off, or sets intermediate power levels if available.
@@ -157,7 +177,7 @@ typedef struct _xf86OutputFuncs {
* 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 pipe specifically, and not represent generic CRTC limitations.
+ * on the output specifically, and not represent generic CRTC limitations.
*
* \return MODE_OK if the mode is valid, or another MODE_* otherwise.
*/
@@ -166,22 +186,28 @@ typedef struct _xf86OutputFuncs {
DisplayModePtr pMode);
/**
- * Callback for setting up a video mode before any crtc/dpll changes.
+ * Callback to adjust the mode to be set in the CRTC.
*
- * \param pMode the mode that will be set, or NULL if the mode to be set is
- * unknown (such as the restore path of VT switching).
+ * 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.
*/
- void
- (*pre_set_mode)(xf86OutputPtr output,
- DisplayModePtr pMode);
+ Bool
+ (*mode_fixup)(xf86OutputPtr output,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode);
/**
- * Callback for setting up a video mode after the DPLL update but before
- * the plane is enabled.
+ * 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
- (*post_set_mode)(xf86OutputPtr output,
- DisplayModePtr pMode);
+ (*mode_set)(xf86OutputPtr output,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode);
/**
* Probe for a connected output, and return detect_status.