diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/i810_reg.h | 19 | ||||
-rw-r--r-- | src/i830.h | 13 | ||||
-rw-r--r-- | src/i830_bios.c | 48 | ||||
-rw-r--r-- | src/i830_crt.c | 20 | ||||
-rw-r--r-- | src/i830_debug.c | 264 | ||||
-rw-r--r-- | src/i830_display.c | 463 | ||||
-rw-r--r-- | src/i830_display.h | 1 | ||||
-rw-r--r-- | src/i830_driver.c | 67 | ||||
-rw-r--r-- | src/i830_dvo.c | 49 | ||||
-rw-r--r-- | src/i830_lvds.c | 127 | ||||
-rw-r--r-- | src/i830_randr.c | 3 | ||||
-rw-r--r-- | src/i830_sdvo.c | 53 | ||||
-rw-r--r-- | src/i830_tv.c | 35 | ||||
-rw-r--r-- | src/i830_xf86Crtc.h | 56 |
14 files changed, 776 insertions, 442 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h index 7312f8a4..d5250245 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -762,6 +762,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define PP_STATUS 0x61200 # define PP_ON (1 << 31) +/** + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +# define PP_READY (1 << 30) +# define PP_SEQUENCE_NONE (0 << 28) +# define PP_SEQUENCE_ON (1 << 28) +# define PP_SEQUENCE_OFF (2 << 28) +# define PP_SEQUENCE_MASK 0x30000000 #define PP_CONTROL 0x61204 # define POWER_TARGET_ON (1 << 0) @@ -796,12 +808,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define DPLL_VGA_MODE_DIS (1 << 28) # define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ # define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +# define DPLL_MODE_MASK (3 << 26) # define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ # define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ # define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ # define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ # define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ # define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 # define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ # define DPLL_FPA01_P1_POS_DIV_MASK_I830 0x001f0000 /* i830 */ # define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ @@ -809,6 +823,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ # define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ # define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +# define PLL_REF_INPUT_MASK (3 << 13) # define PLL_LOAD_PULSE_PHASE_SHIFT 9 /* * Parallel to Serial Load Pulse phase selection. @@ -818,6 +833,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ # define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) # define DISPLAY_RATE_SELECT_FPA1 (1 << 8) + /** * SDVO multiplier for 945G/GM. Not used on 965. * @@ -906,8 +922,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define FPB0 0x06048 #define FPB1 0x0604c # define FP_N_DIV_MASK 0x003f0000 +# define FP_N_DIV_SHIFT 16 # define FP_M1_DIV_MASK 0x00003f00 +# define FP_M1_DIV_SHIFT 8 # define FP_M2_DIV_MASK 0x0000003f +# define FP_M2_DIV_SHIFT 0 #define PORT_HOTPLUG_EN 0x61110 # define SDVOB_HOTPLUG_INT_EN (1 << 26) @@ -438,19 +438,8 @@ typedef struct _I830Rec { int ddc2; - /* Panel size pulled from the BIOS */ - int PanelXRes, PanelYRes; - /* The BIOS's fixed timings for the LVDS */ - int panel_fixed_clock; - int panel_fixed_hactive; - int panel_fixed_hblank; - int panel_fixed_hsyncoff; - int panel_fixed_hsyncwidth; - int panel_fixed_vactive; - int panel_fixed_vblank; - int panel_fixed_vsyncoff; - int panel_fixed_vsyncwidth; + DisplayModePtr panel_fixed_mode; int backlight_duty_cycle; /* restore backlight to this value */ diff --git a/src/i830_bios.c b/src/i830_bios.c index 0821845a..a9ef474d 100644 --- a/src/i830_bios.c +++ b/src/i830_bios.c @@ -158,6 +158,7 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn) struct lvds_bdb_2 *lvds2; struct lvds_bdb_2_fp_params *fpparam; struct lvds_bdb_2_fp_edid_dtd *fptiming; + DisplayModePtr fixed_mode; CARD8 *timing_ptr; id = INTEL_BIOS_8(start); @@ -197,32 +198,37 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn) continue; } - pI830->PanelXRes = fpparam->x_res; - pI830->PanelYRes = fpparam->y_res; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Found panel of size %dx%d in BIOS VBT tables\n", - pI830->PanelXRes, pI830->PanelYRes); + fixed_mode = xnfalloc(sizeof(DisplayModeRec)); + memset(fixed_mode, 0, sizeof(*fixed_mode)); /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing * block, pull the contents out using EDID macros. */ - pI830->panel_fixed_clock = _PIXEL_CLOCK(timing_ptr) / 1000; - pI830->panel_fixed_hactive = _H_ACTIVE(timing_ptr); - pI830->panel_fixed_hblank = _H_BLANK(timing_ptr); - pI830->panel_fixed_hsyncoff = _H_SYNC_OFF(timing_ptr); - pI830->panel_fixed_hsyncwidth = _H_SYNC_WIDTH(timing_ptr); - - pI830->panel_fixed_vactive = _V_ACTIVE(timing_ptr); - pI830->panel_fixed_vblank = _V_BLANK(timing_ptr); - pI830->panel_fixed_vsyncoff = _V_SYNC_OFF(timing_ptr); - pI830->panel_fixed_vsyncwidth = _V_SYNC_WIDTH(timing_ptr); + fixed_mode->HDisplay = _H_ACTIVE(timing_ptr); + fixed_mode->VDisplay = _V_ACTIVE(timing_ptr); + fixed_mode->HSyncStart = fixed_mode->HDisplay + + _H_SYNC_OFF(timing_ptr); + fixed_mode->HSyncEnd = fixed_mode->HSyncStart + + _H_SYNC_WIDTH(timing_ptr); + fixed_mode->HTotal = fixed_mode->HDisplay + + _H_BLANK(timing_ptr); + fixed_mode->VSyncStart = fixed_mode->VDisplay + + _V_SYNC_OFF(timing_ptr); + fixed_mode->VSyncEnd = fixed_mode->VSyncStart + + _V_SYNC_WIDTH(timing_ptr); + fixed_mode->VTotal = fixed_mode->VDisplay + + _V_BLANK(timing_ptr); + fixed_mode->Clock = _PIXEL_CLOCK(timing_ptr) / 1000; + fixed_mode->type = M_T_PREFERRED; + + xf86SetModeDefaultName(fixed_mode); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Panel mode h active %d blank %d rate %f v active %d blank %d rate %f\n", - pI830->panel_fixed_hactive, pI830->panel_fixed_hblank, - (double) pI830->panel_fixed_clock / (pI830->panel_fixed_hactive + pI830->panel_fixed_hblank), - pI830->panel_fixed_vactive, pI830->panel_fixed_vblank, - (double) pI830->panel_fixed_clock / - ((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank) * (pI830->panel_fixed_vactive + pI830->panel_fixed_vblank))); + "Found panel mode in BIOS VBT tables:\n"); + xf86PrintModeline(pScrn->scrnIndex, fixed_mode); + + pI830->panel_fixed_mode = fixed_mode; + found_panel_info = TRUE; break; } diff --git a/src/i830_crt.c b/src/i830_crt.c index bf23f9eb..d8315f07 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) @@ -370,8 +372,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_debug.c b/src/i830_debug.c index f7323891..b1902ffb 100644 --- a/src/i830_debug.c +++ b/src/i830_debug.c @@ -33,13 +33,163 @@ #include "i830.h" #include "i830_debug.h" +#define DEBUGSTRING(func) static char *func(I830Ptr pI830, int reg, CARD32 val) + +DEBUGSTRING(i830_debug_xyminus1) +{ + return XNFprintf("%d, %d", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_yxminus1) +{ + return XNFprintf("%d, %d", ((val & 0xffff0000) >> 16) + 1, + (val & 0xffff) + 1); +} + +DEBUGSTRING(i830_debug_xy) +{ + return XNFprintf("%d, %d", (val & 0xffff), + ((val & 0xffff0000) >> 16)); +} + +DEBUGSTRING(i830_debug_dspstride) +{ + return XNFprintf("%d bytes", val); +} + +DEBUGSTRING(i830_debug_dspcntr) +{ + char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled"; + char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A'; + return XNFprintf("%s, pipe %c", enabled, plane); +} + +DEBUGSTRING(i830_debug_pipeconf) +{ + char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled"; + char *wide = val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide"; + return XNFprintf("%s, %s", enabled, wide); +} + +DEBUGSTRING(i830_debug_hvtotal) +{ + return XNFprintf("%d active, %d total", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_hvsyncblank) +{ + return XNFprintf("%d start, %d end", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_vgacntrl) +{ + return XNFprintf("%s", val & VGA_DISP_DISABLE ? "disabled" : "enabled"); +} + +DEBUGSTRING(i830_debug_fp) +{ + return XNFprintf("n = %d, m1 = %d, m2 = %d", + ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT), + ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT), + ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT)); +} + +DEBUGSTRING(i830_debug_pp_status) +{ + char *status = val & PP_ON ? "on" : "off"; + char *ready = val & PP_READY ? "ready" : "not ready"; + char *seq = "unknown"; + + switch (val & PP_SEQUENCE_MASK) { + case PP_SEQUENCE_NONE: + seq = "idle"; + break; + case PP_SEQUENCE_ON: + seq = "on"; + break; + case PP_SEQUENCE_OFF: + seq = "off"; + break; + } + + return XNFprintf("%s, %s, sequencing %s", status, ready, seq); +} + +DEBUGSTRING(i830_debug_pp_control) +{ + return XNFprintf("power target: %s", + val & POWER_TARGET_ON ? "on" : "off"); +} + +DEBUGSTRING(i830_debug_dpll) +{ + char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled"; + char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo"; + char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA"; + char *mode = "unknown"; + char *clock = "unknown"; + char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : ""; + char sdvoextra[3]; + int p1, p2 = 0; + + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + switch (val & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + mode = "dac/serial"; + p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; + break; + case DPLLB_MODE_LVDS: + mode = "LVDS"; + p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; + break; + } + switch (val & PLL_REF_INPUT_MASK) { + case PLL_REF_INPUT_DREFCLK: + clock = "default"; + break; + case PLL_REF_INPUT_TVCLKINA: + clock = "TV A"; + break; + case PLL_REF_INPUT_TVCLKINBC: + clock = "TV B/C"; + break; + } + if (IS_I945G(pI830) || IS_I945GM(pI830)) { + sprintf(sdvoextra, "SDVO mult %d", + (int)(val & SDVO_MULTIPLIER_MASK) >> + SDVO_MULTIPLIER_SHIFT_HIRES); + } else { + sdvoextra[0] = '\0'; + } + + return XNFprintf("%s, %s%s, %s mode, %s clock, p1 = %d, " + "p2 = %d%s%s", + enabled, dvomode, vgamode, mode, clock, p1, p2, + fpextra, sdvoextra); +} + +DEBUGSTRING(i830_debug_lvds) +{ + char pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A'; + char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled"; + + return XNFprintf("%s, pipe %c", enable, pipe); +} + #define DEFINEREG(reg) \ - { reg, #reg, 0 } + { reg, #reg, NULL, 0 } +#define DEFINEREG2(reg, func) \ + { reg, #reg, func, 0 } static struct i830SnapshotRec { int reg; char *name; - CARD32 regval; + char *(*debug_output)(I830Ptr pI830, int reg, CARD32 val); + CARD32 val; } i830_snapshot[] = { DEFINEREG(VCLK_DIVISOR_VGA0), DEFINEREG(VCLK_DIVISOR_VGA1), @@ -61,7 +211,7 @@ static struct i830SnapshotRec { DEFINEREG(DSPFW3), DEFINEREG(ADPA), - DEFINEREG(LVDS), + DEFINEREG2(LVDS, i830_debug_lvds), DEFINEREG(DVOA), DEFINEREG(DVOB), DEFINEREG(DVOC), @@ -69,63 +219,63 @@ static struct i830SnapshotRec { DEFINEREG(DVOB_SRCDIM), DEFINEREG(DVOC_SRCDIM), - DEFINEREG(PP_CONTROL), - DEFINEREG(PP_STATUS), + DEFINEREG2(PP_CONTROL, i830_debug_pp_control), + DEFINEREG2(PP_STATUS, i830_debug_pp_status), DEFINEREG(PFIT_CONTROL), DEFINEREG(PFIT_PGM_RATIOS), DEFINEREG(PORT_HOTPLUG_EN), DEFINEREG(PORT_HOTPLUG_STAT), - DEFINEREG(DSPACNTR), - DEFINEREG(DSPASTRIDE), - DEFINEREG(DSPAPOS), - DEFINEREG(DSPASIZE), + DEFINEREG2(DSPACNTR, i830_debug_dspcntr), + DEFINEREG2(DSPASTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPAPOS, i830_debug_xy), + DEFINEREG2(DSPASIZE, i830_debug_xyminus1), DEFINEREG(DSPABASE), DEFINEREG(DSPASURF), DEFINEREG(DSPATILEOFF), - DEFINEREG(PIPEACONF), - DEFINEREG(PIPEASRC), + DEFINEREG2(PIPEACONF, i830_debug_pipeconf), + DEFINEREG2(PIPEASRC, i830_debug_yxminus1), - DEFINEREG(FPA0), - DEFINEREG(FPA1), - DEFINEREG(DPLL_A), + DEFINEREG2(FPA0, i830_debug_fp), + DEFINEREG2(FPA1, i830_debug_fp), + DEFINEREG2(DPLL_A, i830_debug_dpll), DEFINEREG(DPLL_A_MD), - DEFINEREG(HTOTAL_A), - DEFINEREG(HBLANK_A), - DEFINEREG(HSYNC_A), - DEFINEREG(VTOTAL_A), - DEFINEREG(VBLANK_A), - DEFINEREG(VSYNC_A), + DEFINEREG2(HTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank), DEFINEREG(BCLRPAT_A), DEFINEREG(VSYNCSHIFT_A), - DEFINEREG(DSPBCNTR), - DEFINEREG(DSPBSTRIDE), - DEFINEREG(DSPBPOS), - DEFINEREG(DSPBSIZE), + DEFINEREG2(DSPBCNTR, i830_debug_dspcntr), + DEFINEREG2(DSPBSTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPBPOS, i830_debug_xy), + DEFINEREG2(DSPBSIZE, i830_debug_xyminus1), DEFINEREG(DSPBBASE), DEFINEREG(DSPBSURF), DEFINEREG(DSPBTILEOFF), - DEFINEREG(PIPEBCONF), - DEFINEREG(PIPEBSRC), + DEFINEREG2(PIPEBCONF, i830_debug_pipeconf), + DEFINEREG2(PIPEBSRC, i830_debug_yxminus1), - DEFINEREG(FPB0), - DEFINEREG(FPB1), - DEFINEREG(DPLL_B), + DEFINEREG2(FPB0, i830_debug_fp), + DEFINEREG2(FPB1, i830_debug_fp), + DEFINEREG2(DPLL_B, i830_debug_dpll), DEFINEREG(DPLL_B_MD), - DEFINEREG(HTOTAL_B), - DEFINEREG(HBLANK_B), - DEFINEREG(HSYNC_B), - DEFINEREG(VTOTAL_B), - DEFINEREG(VBLANK_B), - DEFINEREG(VSYNC_B), + DEFINEREG2(HTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank), DEFINEREG(BCLRPAT_B), DEFINEREG(VSYNCSHIFT_B), DEFINEREG(VCLK_DIVISOR_VGA0), DEFINEREG(VCLK_DIVISOR_VGA1), DEFINEREG(VCLK_POST_DIV), - DEFINEREG(VGACNTRL), + DEFINEREG2(VGACNTRL, i830_debug_vgacntrl), DEFINEREG(TV_CTL), DEFINEREG(TV_DAC), @@ -171,7 +321,7 @@ void i830TakeRegSnapshot(ScrnInfoPtr pScrn) int i; for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { - i830_snapshot[i].regval = INREG(i830_snapshot[i].reg); + i830_snapshot[i].val = INREG(i830_snapshot[i].reg); } } @@ -184,11 +334,28 @@ void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn, char *where) "Comparing regs from server start up to %s\n", where); for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { CARD32 val = INREG(i830_snapshot[i].reg); - if (i830_snapshot[i].regval != val) { + if (i830_snapshot[i].val == val) + continue; + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n", + i830_snapshot[i].reg, i830_snapshot[i].name, + (int)i830_snapshot[i].val, (int)val); + + if (i830_snapshot[i].debug_output != NULL) { + char *before, *after; + + before = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + i830_snapshot[i].val); + after = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + val); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n", - i830_snapshot[i].reg, i830_snapshot[i].name, - (int)i830_snapshot[i].regval, (int)val); + "%s before: %s\n", i830_snapshot[i].name, before); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "%s after: %s\n", i830_snapshot[i].name, after); + } } } @@ -220,8 +387,19 @@ void i830DumpRegs (ScrnInfoPtr pScrn) xf86DrvMsg (pScrn->scrnIndex, X_INFO, "DumpRegsBegin\n"); for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { - xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x\n", - i830_snapshot[i].name, (unsigned int) INREG(i830_snapshot[i].reg)); + CARD32 val = INREG(i830_snapshot[i].reg); + + if (i830_snapshot[i].debug_output != NULL) { + char *debug = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + val); + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x (%s)\n", + i830_snapshot[i].name, (unsigned int)val, debug); + xfree(debug); + } else { + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x\n", + i830_snapshot[i].name, (unsigned int)val); + } } i830DumpIndexed (pScrn, "SR", 0x3c4, 0x3c5, 0, 7); msr = INREG8(0x3cc); diff --git a/src/i830_display.c b/src/i830_display.c index ac56528a..d8220837 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -478,34 +478,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; - intel_clock_t clock; - 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; @@ -516,39 +576,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; - int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT; - 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 i; + int refclk; + intel_clock_t clock; + CARD32 dpll = 0, fp = 0, dspcntr, pipeconf; + 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; @@ -568,90 +612,22 @@ 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, &clock); - if (!ok) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Couldn't find PLL settings for mode!\n"); - goto done; - } - dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS; + ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &clock); + if (!ok) + FatalError("Couldn't find PLL settings for mode!\n"); + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + + i830PrintPll("chosen", &clock); + 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; @@ -686,33 +662,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 = clock.n << 16 | clock.m1 << 8 | clock.m2; - -#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", &clock); - 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; @@ -739,55 +697,8 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode, else dspcntr |= DISPPLANE_SEL_PIPE_B; - OUTREG(VGACNTRL, VGA_DISP_DISABLE); - - /* Finally, set the mode. */ - /* First, disable display planes */ - temp = INREG(dspcntr_reg); - OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); - - /* 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); - - OUTREG(fp_reg, fp); - OUTREG(dpll_reg, dpll); - - /* - * If the panel fitter is stuck on our pipe, turn it off. - * The LVDS output will set it as necessary in post_set_mode. - */ - 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) - (*output->funcs->post_set_mode)(output, pMode); - } - - 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); - - /* Then, turn the pipe on first */ - temp = INREG(pipeconf_reg); - temp |= PIPEACONF_ENABLE; - if (!IS_I9XX(pI830) && pipe == 0) - { + pipeconf = INREG(pipeconf_reg); + if (!IS_I9XX(pI830) && pipe == 0) { /* * The docs say this is needed when the dot clock is > 90% of the * core speed. Core speeds are indicated by bits in the PCI @@ -802,16 +713,137 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode, * It doesn't seem to cause any harm, although it * does restrict some output options. */ - if (pixel_clock > 108000) - temp |= PIPEACONF_DOUBLE_WIDE; + if (adjusted_mode->Clock > 108000) + pipeconf |= PIPEACONF_DOUBLE_WIDE; else - temp &= ~PIPEACONF_DOUBLE_WIDE; + pipeconf &= ~PIPEACONF_DOUBLE_WIDE; + } + + 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); + } + + 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->VDisplay - 1) << 16) | (mode->HDisplay - 1)); + OUTREG(dsppos_reg, 0); + i830PipeSetBase(crtc, crtc->x, crtc->y); + OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1)); + OUTREG(pipeconf_reg, pipeconf); + OUTREG(dspcntr_reg, dspcntr); + + /* Disable the panel fitter if it was on our pipe */ + if (!IS_I830(pI830) && ((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe) + OUTREG(PFIT_CONTROL, 0); +} + +/** + * 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; + + /* XXX: curMode */ + + adjusted_mode = xf86DuplicateMode(pMode); + + crtc->enabled = i830PipeInUse (crtc); + + if (!crtc->enabled) + { + /* XXX disable crtc? */ + return TRUE; + } + +#ifdef XF86DRI + didLock = I830DRILock(pScrn); +#endif + + /* 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. + */ + 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) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->dpms(output, DPMSModeOff); } - OUTREG(pipeconf_reg, temp); - if (plane_enable) { - /* And then turn the plane on */ - OUTREG(dspcntr_reg, dspcntr); + crtc->funcs->dpms(crtc, DPMSModeOff); + + /* 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); + } + + /* 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); } #if 0 @@ -834,6 +866,7 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode, crtc->curMode = *pMode; + /* XXX free adjustedmode */ ret = TRUE; done: #ifdef XF86DRI @@ -1073,3 +1106,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 d140e093..8a982abc 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 73af1471..0e6fbf4a 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -718,28 +718,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) { @@ -1345,7 +1324,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) { @@ -2295,7 +2276,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); @@ -2307,12 +2294,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); @@ -2320,6 +2301,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); @@ -2336,11 +2327,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); @@ -2357,12 +2343,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); @@ -2380,6 +2362,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..97f38528 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,80 @@ 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_mode != NULL) { + adjusted_mode->HDisplay = pI830->panel_fixed_mode->HDisplay; + adjusted_mode->HSyncStart = pI830->panel_fixed_mode->HSyncStart; + adjusted_mode->HSyncEnd = pI830->panel_fixed_mode->HSyncEnd; + adjusted_mode->HTotal = pI830->panel_fixed_mode->HTotal; + adjusted_mode->VDisplay = pI830->panel_fixed_mode->VDisplay; + adjusted_mode->VSyncStart = pI830->panel_fixed_mode->VSyncStart; + adjusted_mode->VSyncEnd = pI830->panel_fixed_mode->VSyncEnd; + adjusted_mode->VTotal = pI830->panel_fixed_mode->VTotal; + adjusted_mode->Clock = pI830->panel_fixed_mode->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. + */ + + /* 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. */ - i830SetLVDSPanelPower(pScrn, FALSE); + + 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, INREG(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 +213,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); } /** @@ -194,30 +235,16 @@ i830_lvds_get_modes(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr modes, new; - char stmp[32]; + DisplayModePtr modes; modes = i830_ddc_get_modes(output); if (modes != NULL) return modes; - new = xnfcalloc(1, sizeof (DisplayModeRec)); - sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes); - new->name = xnfalloc(strlen(stmp) + 1); - strcpy(new->name, stmp); - new->HDisplay = pI830->PanelXRes; - new->VDisplay = pI830->PanelYRes; - new->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff; - new->HSyncEnd = new->HSyncStart + pI830->panel_fixed_hsyncwidth; - new->HTotal = new->HSyncEnd + 1; - new->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff; - new->VSyncEnd = new->VSyncStart + pI830->panel_fixed_vsyncwidth; - new->VTotal = new->VSyncEnd + 1; - new->Clock = pI830->panel_fixed_clock; - - new->type = M_T_PREFERRED; - - return new; + if (pI830->panel_fixed_mode != NULL) + return xf86DuplicateMode(pI830->panel_fixed_mode); + + return NULL; } static void @@ -234,8 +261,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 @@ -274,7 +301,9 @@ i830_lvds_init(ScrnInfoPtr pScrn) * display. */ - if (pI830->PanelXRes == 800 && pI830->PanelYRes == 600) { + if (pI830->panel_fixed_mode != NULL && + pI830->panel_fixed_mode->HDisplay == 800 && + pI830->panel_fixed_mode->VDisplay == 600) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Suspected Mac Mini, ignoring the LVDS\n"); return; diff --git a/src/i830_randr.c b/src/i830_randr.c index a6d71f2d..d0ced37c 100644 --- a/src/i830_randr.c +++ b/src/i830_randr.c @@ -41,6 +41,7 @@ #include "i830_xf86Crtc.h" #include "i830_randr.h" +#include "i830_debug.h" #include "i830_display.h" #include "i830.h" @@ -604,6 +605,8 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, i830PipeSetBase(crtc, x, y); } i830DisableUnusedFunctions (pScrn); + + i830DumpRegs(pScrn); } return xf86RandR12CrtcNotify (randr_crtc); } 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 21ba1fcf..10d4b726 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. |