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) diff --git a/src/i830.h b/src/i830.h index 0c8f3883..014d16e1 100644 --- a/src/i830.h +++ b/src/i830.h @@ -192,12 +192,6 @@ struct _I830DVODriver { extern const char *i830_output_type_names[]; -enum detect_status { - OUTPUT_STATUS_CONNECTED, - OUTPUT_STATUS_DISCONNECTED, - OUTPUT_STATUS_UNKNOWN -}; - typedef struct _I830CrtcPrivateRec { int pipe; Bool gammaEnabled; @@ -439,19 +433,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 */ @@ -607,6 +590,9 @@ extern Bool I830FixOffset(ScrnInfoPtr pScrn, I830MemRange *mem); extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name); +/* return a mask of output indices matching outputs against type_mask */ +int i830_output_clones (ScrnInfoPtr pScrn, int type_mask); + /* i830_display.c */ Bool i830PipeHasType (xf86CrtcPtr crtc, int type); @@ -628,10 +614,6 @@ Bool I830BindAGPMemory(ScrnInfoPtr pScrn); Bool I830UnbindAGPMemory(ScrnInfoPtr pScrn); /* i830_modes.c */ -int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time); -void i830_reprobe_output_modes(ScrnInfoPtr pScrn); -void i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn); -void i830_set_default_screen_size(ScrnInfoPtr pScrn); DisplayModePtr i830_ddc_get_modes(xf86OutputPtr output); /* i830_tv.c */ 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); + 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); - 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); 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 7a706d14..3be10ecc 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) @@ -221,9 +223,7 @@ i830_crt_detect_load (xf86CrtcPtr crtc, adpa |= ADPA_VSYNC_CNTL_ENABLE | ADPA_HSYNC_CNTL_ENABLE; OUTREG(ADPA, adpa); - /* Set the border color to purple. Maybe we should save/restore this - * reg. - */ + /* Set the border color to purple. */ bclrpat = INREG(bclrpat_reg); OUTREG(bclrpat_reg, 0x00500050); @@ -274,7 +274,7 @@ i830_crt_detect_ddc(xf86OutputPtr output) * @param allow_disturb enables detection methods that may cause flickering * on active displays. */ -static enum detect_status +static xf86OutputStatus i830_crt_detect(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; @@ -283,13 +283,13 @@ i830_crt_detect(xf86OutputPtr output) if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830)) { if (i830_crt_detect_hotplug(output)) - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; else - return OUTPUT_STATUS_DISCONNECTED; + return XF86OutputStatusDisconnected; } if (i830_crt_detect_ddc(output)) - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; /* Use the load-detect method if we have no other way of telling. */ crtc = i830GetLoadDetectPipe (output); @@ -320,12 +320,12 @@ i830_crt_detect(xf86OutputPtr output) i830ReleaseLoadDetectPipe (output); if (connected) - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; else - return OUTPUT_STATUS_DISCONNECTED; + return XF86OutputStatusDisconnected; } - return OUTPUT_STATUS_UNKNOWN; + return XF86OutputStatusUnknown; } static DisplayModePtr @@ -339,7 +339,7 @@ i830_crt_get_modes(xf86OutputPtr output) if (modes != NULL) return modes; - if ((*output->funcs->detect)(output) == OUTPUT_STATUS_DISCONNECTED) + if ((*output->funcs->detect)(output) == XF86OutputStatusDisconnected) return NULL; /* We've got a potentially-connected monitor that we can't DDC. Return a @@ -372,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 @@ -395,6 +395,7 @@ i830_crt_init(ScrnInfoPtr pScrn) return; } i830_output->type = I830_OUTPUT_ANALOG; + output->driver_private = i830_output; /* Set up the DDC bus. */ diff --git a/src/i830_debug.c b/src/i830_debug.c index d74d0920..8c8b95ee 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[20]; + 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,24 +321,41 @@ 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); } } -void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn) +void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn, char *where) { I830Ptr pI830 = I830PTR(pScrn); int i; xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Comparing regs before/after X's VT usage\n"); + "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_debug.h b/src/i830_debug.h index a8e38398..a365085c 100644 --- a/src/i830_debug.h +++ b/src/i830_debug.h @@ -26,5 +26,5 @@ */ void i830TakeRegSnapshot(ScrnInfoPtr pScrn); -void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn); +void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn, char *where); void i830DumpRegs (ScrnInfoPtr pScrn); diff --git a/src/i830_display.c b/src/i830_display.c index 29b783bf..0e5a09ac 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -43,21 +43,179 @@ #include "i830_debug.h" #include "i830_xf86Modes.h" -/** Returns the pixel clock for the given refclk and divisors. */ -static int i830_clock(int refclk, int m1, int m2, int n, int p1, int p2) +typedef struct { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +} intel_clock_t; + +typedef struct { + int min, max; +} intel_range_t; + +typedef struct { + int dot_limit; + int p2_slow, p2_fast; +} intel_p2_t; + +#define INTEL_P2_NUM 2 + +typedef struct { + intel_range_t dot, vco, n, m, m1, m2, p, p1; + intel_p2_t p2; +} intel_limit_t; + +#define I8XX_DOT_MIN 25000 +#define I8XX_DOT_MAX 350000 +#define I8XX_VCO_MIN 930000 +#define I8XX_VCO_MAX 1400000 +#define I8XX_N_MIN 3 +#define I8XX_N_MAX 16 +#define I8XX_M_MIN 96 +#define I8XX_M_MAX 140 +#define I8XX_M1_MIN 18 +#define I8XX_M1_MAX 26 +#define I8XX_M2_MIN 6 +#define I8XX_M2_MAX 16 +#define I8XX_P_MIN 4 +#define I8XX_P_MAX 128 +#define I8XX_P1_MIN 0 +#define I8XX_P1_MAX 30 +#define I8XX_P2_SLOW 1 +#define I8XX_P2_FAST 0 +#define I8XX_P2_SLOW_LIMIT 165000 + +#define I9XX_DOT_MIN 20000 +#define I9XX_DOT_MAX 400000 +#define I9XX_VCO_MIN 1400000 +#define I9XX_VCO_MAX 2800000 +#define I9XX_N_MIN 3 +#define I9XX_N_MAX 8 +#define I9XX_M_MIN 70 +#define I9XX_M_MAX 120 +#define I9XX_M1_MIN 10 +#define I9XX_M1_MAX 20 +#define I9XX_M2_MIN 5 +#define I9XX_M2_MAX 9 +#define I9XX_P_SDVO_DAC_MIN 5 +#define I9XX_P_SDVO_DAC_MAX 80 +#define I9XX_P_LVDS_MIN 7 +#define I9XX_P_LVDS_MAX 98 +#define I9XX_P1_MIN 1 +#define I9XX_P1_MAX 8 +#define I9XX_P2_SDVO_DAC_SLOW 10 +#define I9XX_P2_SDVO_DAC_FAST 5 +#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 +#define I9XX_P2_LVDS_SLOW 14 +#define I9XX_P2_LVDS_FAST 7 +#define I9XX_P2_LVDS_SLOW_LIMIT 112000 + +#define INTEL_LIMIT_I8XX 0 +#define INTEL_LIMIT_I9XX_SDVO_DAC 1 +#define INTEL_LIMIT_I9XX_LVDS 2 + +static const intel_limit_t intel_limits[] = { + { + .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, + .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, + .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, + .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, + .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, + .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, + .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, + .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, + .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, + .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, + }, + { + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, + .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, + }, + { + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + /* The single-channel range is 25-112Mhz, and dual-channel + * is 80-224Mhz. Prefer single channel as much as possible. + */ + .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, + .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, + }, +}; + +static const intel_limit_t *intel_limit (xf86CrtcPtr crtc) { - return refclk * (5 * m1 + m2) / n / (p1 * p2); + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + const intel_limit_t *limit; + + if (IS_I9XX(pI830)) + { + if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; + } + else + limit = &intel_limits[INTEL_LIMIT_I8XX]; + return limit; +} + +/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ + +static void i8xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = (clock->p1 + 2) << (clock->p2 + 1); + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ + +static void i9xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +static void intel_clock(I830Ptr pI830, int refclk, intel_clock_t *clock) +{ + if (IS_I9XX(pI830)) + return i9xx_clock (refclk, clock); + else + return i8xx_clock (refclk, clock); } static void -i830PrintPll(char *prefix, int refclk, int m1, int m2, int n, int p1, int p2) +i830PrintPll(char *prefix, intel_clock_t *clock) { - int dotclock; - - dotclock = i830_clock(refclk, m1, m2, n, p1, p2); - - ErrorF("%s: dotclock %d ((%d, %d), %d, (%d, %d))\n", prefix, dotclock, - m1, m2, n, p1, p2); + ErrorF("%s: dotclock %d vco %d ((m %d, m1 %d, m2 %d), n %d, (p %d, p1 %d, p2 %d))\n", + prefix, clock->dot, clock->vco, + clock->m, clock->m1, clock->m2, + clock->n, + clock->p, clock->p1, clock->p2); } /** @@ -83,90 +241,38 @@ i830PipeHasType (xf86CrtcPtr crtc, int type) return FALSE; } +#define i830PllInvalid(s) { /* ErrorF (s) */; return FALSE; } /** * Returns whether the given set of divisors are valid for a given refclk with * the given outputs. - * - * The equation for these divisors would be: - * clk = refclk * (5 * m1 + m2) / n / (p1 * p2) */ + static Bool -i830PllIsValid(xf86CrtcPtr crtc, int refclk, int m1, int m2, - int n, int p1, int p2) +i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock) { - ScrnInfoPtr pScrn = crtc->scrn; - I830Ptr pI830 = I830PTR(pScrn); - int p, m, vco, dotclock; - int min_m1, max_m1, min_m2, max_m2, min_m, max_m, min_n, max_n; - int min_p1, max_p1, min_p, max_p, min_vco, max_vco, min_dot, max_dot; + const intel_limit_t *limit = intel_limit (crtc); - if (IS_I9XX(pI830)) { - min_m1 = 10; - max_m1 = 20; - min_m2 = 5; - max_m2 = 9; - min_m = 70; - max_m = 120; - min_n = 3; - max_n = 8; - min_p1 = 1; - max_p1 = 8; - if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) { - min_p = 7; - max_p = 98; - } else { - min_p = 5; - max_p = 80; - } - min_vco = 1400000; - max_vco = 2800000; - min_dot = 20000; - max_dot = 400000; - } else { - min_m1 = 18; - max_m1 = 26; - min_m2 = 6; - max_m2 = 16; - min_m = 96; - max_m = 140; - min_n = 3; - max_n = 16; - min_p1 = 2; - max_p1 = 18; - min_vco = 930000; - max_vco = 1400000; - min_dot = 20000; - max_dot = 350000; - min_p = 4; - max_p = 128; - } - - p = p1 * p2; - m = 5 * m1 + m2; - vco = refclk * m / n; - dotclock = i830_clock(refclk, m1, m2, n, p1, p2); - - if (p1 < min_p1 || p1 > max_p1) - return FALSE; - if (p < min_p || p > max_p) - return FALSE; - if (m2 < min_m2 || m2 > max_m2) - return FALSE; - if (m1 < min_m1 || m1 > max_m1) - return FALSE; - if (m1 <= m2) - return FALSE; - if (m < min_m || m > max_m) - return FALSE; - if (n < min_n || n > max_n) - return FALSE; - if (vco < min_vco || vco > max_vco) - return FALSE; + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + i830PllInvalid ("p1 out of range\n"); + if (clock->p < limit->p.min || limit->p.max < clock->p) + i830PllInvalid ("p out of range\n"); + if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) + i830PllInvalid ("m2 out of range\n"); + if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) + i830PllInvalid ("m1 out of range\n"); + if (clock->m1 <= clock->m2) + i830PllInvalid ("m1 <= m2\n"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + i830PllInvalid ("m out of range\n"); + if (clock->n < limit->n.min || limit->n.max < clock->n) + i830PllInvalid ("n out of range\n"); + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + i830PllInvalid ("vco out of range\n"); /* XXX: We may need to be checking "Dot clock" depending on the multiplier, * output, etc., rather than just a single range. */ - if (dotclock < min_dot || dotclock > max_dot) - return FALSE; + if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) + i830PllInvalid ("dot out of range\n"); return TRUE; } @@ -174,83 +280,47 @@ i830PllIsValid(xf86CrtcPtr crtc, int refclk, int m1, int m2, /** * Returns a set of divisors for the desired target clock with the given refclk, * or FALSE. Divisor values are the actual divisors for - * clk = refclk * (5 * m1 + m2) / n / (p1 * p2) */ static Bool -i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, - int *outm1, int *outm2, int *outn, int *outp1, int *outp2) +i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_clock) { ScrnInfoPtr pScrn = crtc->scrn; I830Ptr pI830 = I830PTR(pScrn); - int m1, m2, n, p1, p2; + intel_clock_t clock; + const intel_limit_t *limit = intel_limit (crtc); int err = target; - int min_m1, max_m1, min_m2, max_m2, min_n, max_n, min_p1, max_p1; - if (IS_I9XX(pI830)) { - min_m1 = 10; - max_m1 = 20; - min_m2 = 5; - max_m2 = 9; - min_n = 3; - max_n = 8; - min_p1 = 1; - max_p1 = 8; - if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) { - /* The single-channel range is 25-112Mhz, and dual-channel - * is 80-224Mhz. Prefer single channel as much as possible. - */ - if (target < 112000) - p2 = 14; - else - p2 = 7; - } else { - if (target < 200000) - p2 = 10; - else - p2 = 5; - } - } else { - min_m1 = 18; - max_m1 = 26; - min_m2 = 6; - max_m2 = 16; - min_n = 3; - max_n = 16; - min_p1 = 2; - max_p1 = 18; - if (target < 165000) - p2 = 4; - else - p2 = 2; - } + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + memset (best_clock, 0, sizeof (*best_clock)); - for (m1 = min_m1; m1 <= max_m1; m1++) { - for (m2 = min_m2; m2 < max_m2; m2++) { - for (n = min_n; n <= max_n; n++) { - for (p1 = min_p1; p1 <= max_p1; p1++) { - int clock, this_err; + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) + { + for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && clock.m2 < limit->m2.max; clock.m2++) + { + for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) + { + for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++) + { + int this_err; - if (!i830PllIsValid(crtc, refclk, m1, m2, n, - p1, p2)) { + intel_clock (pI830, refclk, &clock); + + if (!i830PllIsValid(crtc, &clock)) continue; - } - clock = i830_clock(refclk, m1, m2, n, p1, p2); - this_err = abs(clock - target); + this_err = abs(clock.dot - target); if (this_err < err) { - *outm1 = m1; - *outm2 = m2; - *outn = n; - *outp1 = p1; - *outp2 = p2; + *best_clock = clock; err = this_err; } } } } } - return (err != target); } @@ -408,34 +478,94 @@ i830PipeInUse (xf86CrtcPtr crtc) return FALSE; } -/** - * 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) +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 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 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 up registers for the given mode/adjusted_mode pair. + * + * 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. + */ +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 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 +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; - Bool ret = FALSE; -#ifdef XF86DRI - Bool didLock = FALSE; -#endif + 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; - 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; - } - -#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,97 +612,37 @@ 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, - &p1, &p2); - 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; + + dpll = DPLL_VGA_MODE_DIS; if (IS_I9XX(pI830)) { if (is_lvds) dpll |= DPLLB_MODE_LVDS; else dpll |= DPLLB_MODE_DAC_SERIAL; - dpll |= (1 << (p1 - 1)) << 16; - switch (p2) { + if (is_sdvo) + { + dpll |= DPLL_DVO_HIGH_SPEED; + if (IS_I945G(pI830) || IS_I945GM(pI830)) + { + int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock; + dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } + } + + /* compute bitmask from p1 value */ + dpll |= (1 << (clock.p1 - 1)) << 16; + switch (clock.p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; break; @@ -604,9 +659,8 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode, if (IS_I965G(pI830)) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { - dpll |= (p1 - 2) << 16; - if (p2 == 4) - dpll |= PLL_P2_DIVIDE_BY_4; + dpll |= clock.p1 << 16; + dpll |= clock.p2 << 23; } if (is_tv) @@ -615,33 +669,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 +704,179 @@ i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode, else dspcntr |= DISPPLANE_SEL_PIPE_B; - OUTREG(VGACNTRL, VGA_DISP_DISABLE); + 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 + * config space and don't seem to ever be less than 200MHz, + * which is a bit confusing. + * + * However, For one little 855/852 card I have, 135000 requires + * double wide mode, but 108000 does not. That makes no sense + * but we're used to that. It may be affected by pixel size, + * but the BIOS mode setting code doesn't appear to use that. + * + * It doesn't seem to cause any harm, although it + * does restrict some output options. + */ + if (adjusted_mode->Clock > 108000) + pipeconf |= PIPEACONF_DOUBLE_WIDE; + else + pipeconf &= ~PIPEACONF_DOUBLE_WIDE; + } - /* 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); + i830PrintPll("chosen", &clock); + ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp); 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); + 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); } - 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(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); - OUTREG(dspsize_reg, dspsize); + /* 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, pipesrc); + OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1)); + OUTREG(pipeconf_reg, pipeconf); + OUTREG(dspcntr_reg, dspcntr); - /* Then, turn the pipe on first */ - temp = INREG(pipeconf_reg); - OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE); + /* Disable the panel fitter if it was on our pipe */ + if (!IS_I830(pI830) && ((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe) + OUTREG(PFIT_CONTROL, 0); +} - if (plane_enable) { - /* And then turn the plane on */ - OUTREG(dspcntr_reg, dspcntr); +/** + * 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); + } + + 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 + /* + * If the display isn't solid, it may be running out + * of memory bandwidth. This code will dump out the + * pipe status, if bit 31 is on, the fifo underran + */ + for (i = 0; i < 4; i++) { + i830WaitForVblank(pScrn); + + OUTREG(pipestat_reg, INREG(pipestat_reg) | 0x80000000); + + i830WaitForVblank(pScrn); + + temp = INREG(pipestat_reg); + ErrorF ("pipe status 0x%x\n", temp); + } +#endif + crtc->curMode = *pMode; + /* XXX free adjustedmode */ ret = TRUE; done: #ifdef XF86DRI @@ -801,15 +955,15 @@ i830DisableUnusedFunctions(ScrnInfoPtr pScrn) Bool i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) { + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); I830Ptr pI830 = I830PTR(pScrn); Bool ok = TRUE; - int i; + xf86CrtcPtr crtc = config->output[config->compat_output]->crtc; DPRINTF(PFX, "i830SetMode\n"); - for (i = 0; i < pI830->xf86_config.num_crtc; i++) + if (crtc && crtc->enabled) { - xf86CrtcPtr crtc = pI830->xf86_config.crtc[i]; ok = i830PipeSetMode(crtc, i830PipeFindClosestMode(crtc, pMode), TRUE); @@ -962,3 +1116,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..8a982abc 100644 --- a/src/i830_display.h +++ b/src/i830_display.h @@ -41,14 +41,15 @@ void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn); xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output); void i830ReleaseLoadDetectPipe(xf86OutputPtr output); Bool i830PipeInUse(xf86CrtcPtr crtc); +void i830_crtc_init(ScrnInfoPtr pScrn, int pipe); /** @{ */ -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) DisplayModePtr i830_xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC); DisplayModePtr i830_xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, Bool Interlaced); #define xf86DDCGetModes i830_xf86DDCGetModes #define xf86CVTMode i830_xf86CVTMode -#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2) */ +#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2) */ /** @} */ diff --git a/src/i830_driver.c b/src/i830_driver.c index 267dbf1d..47e81c70 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -327,6 +327,9 @@ static Bool I830CloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool I830SaveScreen(ScreenPtr pScreen, int unblack); static Bool I830EnterVT(int scrnIndex, int flags); static CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg); +static Bool SaveHWState(ScrnInfoPtr pScrn); +static Bool RestoreHWState(ScrnInfoPtr pScrn); + extern int I830EntityIndex; @@ -685,6 +688,23 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, pI830->CursorInfoRec->ShowCursor(pScrn); } +int +i830_output_clones (ScrnInfoPtr pScrn, int type_mask) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn); + int o; + int index_mask = 0; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + I830OutputPrivatePtr intel_output = output->driver_private; + if (type_mask & (1 << intel_output->type)) + index_mask |= (1 << o); + } + return index_mask; +} + /** * Set up the outputs according to what type of chip we are. * @@ -694,7 +714,9 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, static void I830SetupOutputs(ScrnInfoPtr pScrn) { - I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn); + I830Ptr pI830 = I830PTR(pScrn); + int o; /* everyone has at least a single analog output */ i830_crt_init(pScrn); @@ -711,34 +733,51 @@ I830SetupOutputs(ScrnInfoPtr pScrn) } if (IS_I9XX(pI830) && !IS_I915G(pI830)) i830_tv_init(pScrn); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + I830OutputPrivatePtr intel_output = output->driver_private; + int crtc_mask = 0, clone_mask = 0; + + /* + * Valid crtcs + */ + switch (intel_output->type) { + case I830_OUTPUT_DVO: + case I830_OUTPUT_SDVO: + crtc_mask = ((1 << 0)| + (1 << 1)); + clone_mask = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO) | + (1 << I830_OUTPUT_SDVO)); + break; + case I830_OUTPUT_ANALOG: + crtc_mask = ((1 << 0)); + clone_mask = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO) | + (1 << I830_OUTPUT_SDVO)); + break; + case I830_OUTPUT_LVDS: + crtc_mask = (1 << 1); + clone_mask = (1 << I830_OUTPUT_LVDS); + break; + case I830_OUTPUT_TVOUT: + crtc_mask = ((1 << 0) | + (1 << 1)); + clone_mask = (1 << I830_OUTPUT_TVOUT); + break; + } + output->possible_crtcs = crtc_mask; + output->possible_clones = i830_output_clones (pScrn, clone_mask); + } } /** * 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) { @@ -882,7 +921,6 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) #ifdef XF86DRI unsigned long savedMMSize; #endif - enum detect_status output_status[MAX_OUTPUTS]; if (pScrn->numEntities != 1) return FALSE; @@ -1151,6 +1189,11 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) /* Some of the probing needs MMIO access, so map it here. */ I830MapMMIO(pScrn); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardware state on X startup:\n"); + i830DumpRegs (pScrn); + + i830TakeRegSnapshot(pScrn); + #if 1 pI830->saveSWF0 = INREG(SWF0); pI830->saveSWF4 = INREG(SWF4); @@ -1341,7 +1384,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) { @@ -1360,71 +1405,29 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) pI830->Clone = TRUE; } - - /* Perform the pipe assignment of outputs. This is a kludge until - * we have better configuration support in the generic RandR code + SaveHWState(pScrn); + /* Do an initial detection of the outputs while none are configured on yet. + * This will give us some likely legitimate response for later if both + * pipes are already allocated and we're asked to do a detect. */ for (i = 0; i < pI830->xf86_config.num_output; i++) { xf86OutputPtr output = pI830->xf86_config.output[i]; - I830OutputPrivatePtr intel_output = output->driver_private; - xf86CrtcPtr crtc; - int p; - output_status[i] = (*output->funcs->detect) (output); + output->status = (*output->funcs->detect) (output); } - - for (i = 0; i < pI830->xf86_config.num_output; i++) + + if (!xf86InitialConfiguration (pScrn)) { - xf86OutputPtr output = pI830->xf86_config.output[i]; - I830OutputPrivatePtr intel_output = output->driver_private; - xf86CrtcPtr crtc; - int p; - - output->crtc = NULL; - - if (output_status[i] == OUTPUT_STATUS_DISCONNECTED) - continue; - - switch (intel_output->type) { - case I830_OUTPUT_LVDS: - /* LVDS must live on pipe B for two-pipe devices */ - crtc = pI830->xf86_config.crtc[pI830->xf86_config.num_crtc - 1]; - if (!i830PipeInUse (crtc)) - output->crtc = crtc; - break; - case I830_OUTPUT_ANALOG: - case I830_OUTPUT_DVO: - case I830_OUTPUT_SDVO: - for (p = 0; p < pI830->xf86_config.num_crtc; p++) - { - crtc = pI830->xf86_config.crtc[p]; - if (!i830PipeInUse(crtc)) - { - output->crtc = crtc; - break; - } - } - break; - case I830_OUTPUT_TVOUT: - crtc = pI830->xf86_config.crtc[0]; - if (!i830PipeInUse(crtc)) - { - output->crtc = crtc; - } - break; - default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unhandled output type\n"); - break; - } + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + RestoreHWState(pScrn); + PreInitCleanup(pScrn); + return FALSE; } + RestoreHWState(pScrn); - for (i = 0; i < pI830->xf86_config.num_crtc; i++) - { - xf86CrtcPtr crtc = pI830->xf86_config.crtc[i]; - crtc->enabled = i830PipeInUse(crtc); - } - + pScrn->displayWidth = (pScrn->virtualX + 63) & ~63; + pI830->rotation = RR_Rotate_0; if ((s = xf86GetOptValString(pI830->Options, OPTION_ROTATE))) { pI830->InitialRotation = 0; @@ -1669,7 +1672,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) if (!xf86RandR12PreInit (pScrn)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n"); PreInitCleanup(pScrn); return FALSE; } @@ -1912,6 +1915,8 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) xf86LoaderReqSymLists(I810ramdacSymbols, NULL); } + i830CompareRegsToSnapshot(pScrn, "After PreInit"); + I830UnmapMMIO(pScrn); /* We won't be using the VGA access after the probe. */ @@ -2173,23 +2178,8 @@ SaveHWState(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); vgaRegPtr vgaReg = &hwp->SavedReg; - CARD32 temp; int i; - /* - * Print out the PIPEACONF and PIPEBCONF registers. - */ - temp = INREG(PIPEACONF); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08lx\n", - (unsigned long) temp); - if (pI830->xf86_config.num_crtc == 2) { - temp = INREG(PIPEBCONF); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", - (unsigned long) temp); - } - - i830TakeRegSnapshot(pScrn); - /* Save video mode information for native mode-setting. */ pI830->saveDSPACNTR = INREG(DSPACNTR); pI830->savePIPEACONF = INREG(PIPEACONF); @@ -2287,7 +2277,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); @@ -2299,12 +2295,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); @@ -2312,6 +2302,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); @@ -2328,11 +2328,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); @@ -2349,12 +2344,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); @@ -2372,6 +2363,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]); @@ -2381,8 +2377,6 @@ RestoreHWState(ScrnInfoPtr pScrn) OUTREG(SWF31, pI830->saveSWF[15]); OUTREG(SWF32, pI830->saveSWF[16]); - i830CompareRegsToSnapshot(pScrn); - return TRUE; } @@ -2496,195 +2490,6 @@ I965PrintErrorState(ScrnInfoPtr pScrn) } -#ifdef I830DEBUG -static void -dump_DSPACNTR(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - unsigned int tmp; - - /* Display A Control */ - tmp = INREG(0x70180); - ErrorF("Display A Plane Control Register (0x%.8x)\n", tmp); - - if (tmp & BIT(31)) - ErrorF(" Display Plane A (Primary) Enable\n"); - else - ErrorF(" Display Plane A (Primary) Disabled\n"); - - if (tmp & BIT(30)) - ErrorF(" Display A pixel data is gamma corrected\n"); - else - ErrorF(" Display A pixel data bypasses gamma correction logic (default)\n"); - - switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ - case 0x00: - case 0x01: - case 0x03: - ErrorF(" Reserved\n"); - break; - case 0x02: - ErrorF(" 8-bpp Indexed\n"); - break; - case 0x04: - ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); - break; - case 0x05: - ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); - break; - case 0x06: - ErrorF(" 32-bit format (X:8:8:8)\n"); - break; - case 0x07: - ErrorF(" 32-bit format (8:8:8:8)\n"); - break; - default: - ErrorF(" Unknown - Invalid register value maybe?\n"); - } - - if (tmp & BIT(25)) - ErrorF(" Stereo Enable\n"); - else - ErrorF(" Stereo Disable\n"); - - if (tmp & BIT(24)) - ErrorF(" Display A, Pipe B Select\n"); - else - ErrorF(" Display A, Pipe A Select\n"); - - if (tmp & BIT(22)) - ErrorF(" Source key is enabled\n"); - else - ErrorF(" Source key is disabled\n"); - - switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ - case 0x00: - ErrorF(" No line duplication\n"); - break; - case 0x01: - ErrorF(" Line/pixel Doubling\n"); - break; - case 0x02: - case 0x03: - ErrorF(" Reserved\n"); - break; - } - - if (tmp & BIT(18)) - ErrorF(" Stereo output is high during second image\n"); - else - ErrorF(" Stereo output is high during first image\n"); -} - -static void -dump_DSPBCNTR(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - unsigned int tmp; - - /* Display B/Sprite Control */ - tmp = INREG(0x71180); - ErrorF("Display B/Sprite Plane Control Register (0x%.8x)\n", tmp); - - if (tmp & BIT(31)) - ErrorF(" Display B/Sprite Enable\n"); - else - ErrorF(" Display B/Sprite Disable\n"); - - if (tmp & BIT(30)) - ErrorF(" Display B pixel data is gamma corrected\n"); - else - ErrorF(" Display B pixel data bypasses gamma correction logic (default)\n"); - - switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ - case 0x00: - case 0x01: - case 0x03: - ErrorF(" Reserved\n"); - break; - case 0x02: - ErrorF(" 8-bpp Indexed\n"); - break; - case 0x04: - ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); - break; - case 0x05: - ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); - break; - case 0x06: - ErrorF(" 32-bit format (X:8:8:8)\n"); - break; - case 0x07: - ErrorF(" 32-bit format (8:8:8:8)\n"); - break; - default: - ErrorF(" Unknown - Invalid register value maybe?\n"); - } - - if (tmp & BIT(25)) - ErrorF(" Stereo is enabled and both start addresses are used in a two frame sequence\n"); - else - ErrorF(" Stereo disable and only a single start address is used\n"); - - if (tmp & BIT(24)) - ErrorF(" Display B/Sprite, Pipe B Select\n"); - else - ErrorF(" Display B/Sprite, Pipe A Select\n"); - - if (tmp & BIT(22)) - ErrorF(" Sprite source key is enabled\n"); - else - ErrorF(" Sprite source key is disabled (default)\n"); - - switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ - case 0x00: - ErrorF(" No line duplication\n"); - break; - case 0x01: - ErrorF(" Line/pixel Doubling\n"); - break; - case 0x02: - case 0x03: - ErrorF(" Reserved\n"); - break; - } - - if (tmp & BIT(18)) - ErrorF(" Stereo output is high during second image\n"); - else - ErrorF(" Stereo output is high during first image\n"); - - if (tmp & BIT(15)) - ErrorF(" Alpha transfer mode enabled\n"); - else - ErrorF(" Alpha transfer mode disabled\n"); - - if (tmp & BIT(0)) - ErrorF(" Sprite is above overlay\n"); - else - ErrorF(" Sprite is above display A (default)\n"); -} - -void -I830_dump_registers(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - unsigned int i; - - ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); - - dump_DSPACNTR(pScrn); - dump_DSPBCNTR(pScrn); - - ErrorF("0x71400 == 0x%.8x\n", INREG(0x71400)); - ErrorF("0x70008 == 0x%.8x\n", INREG(0x70008)); - for (i = 0x71410; i <= 0x71428; i += 4) - ErrorF("0x%x == 0x%.8x\n", i, INREG(i)); - - ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); -} -#endif - static void I830PointerMoved(int index, int x, int y) { @@ -3300,10 +3105,6 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); -#ifdef I830DEBUG - I830_dump_registers(pScrn); -#endif - if (IS_I965G(pI830)) { /* turn off clock gating */ #if 0 @@ -3393,23 +3194,21 @@ static void i830AdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); I830Ptr pI830 = I830PTR(pScrn); - int i; + xf86CrtcPtr crtc = config->output[config->compat_output]->crtc; DPRINTF(PFX, "i830AdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", x, pI830->xoffset, y, pI830->yoffset); - /* Sync the engine before adjust frame */ - if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { - (*pI830->AccelInfoRec->Sync)(pScrn); - pI830->AccelInfoRec->NeedToSync = FALSE; - } - - for (i = 0; i < pI830->xf86_config.num_crtc; i++) + if (crtc && crtc->enabled) { - xf86CrtcPtr crtc = pI830->xf86_config.crtc[i]; - if (crtc->enabled) - i830PipeSetBase(crtc, x, y); + /* Sync the engine before adjust frame */ + if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { + (*pI830->AccelInfoRec->Sync)(pScrn); + pI830->AccelInfoRec->NeedToSync = FALSE; + } + i830PipeSetBase(crtc, x, y); } } @@ -3477,6 +3276,10 @@ I830LeaveVT(int scrnIndex, int flags) ResetState(pScrn, TRUE); RestoreHWState(pScrn); + + i830CompareRegsToSnapshot(pScrn, "After LeaveVT"); + i830DumpRegs (pScrn); + if (I830IsPrimary(pScrn)) I830UnbindAGPMemory(pScrn); if (pI830->AccelInfoRec) @@ -4010,7 +3813,9 @@ I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg) * implements a sensible policy using RandR-1.2. For now, all we get * is this. */ - I830ValidateXF86ModeList(pScrn, FALSE); + + xf86ProbeOutputModes (pScrn); + xf86SetScrnInfoModes (pScrn); xf86SwitchMode(pScrn->pScreen, pScrn->currentMode); /* Clear the BIOS's hotkey press flags */ diff --git a/src/i830_dvo.c b/src/i830_dvo.c index 6fe31575..25ced639 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); } @@ -164,10 +173,10 @@ i830_dvo_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode) * * Unimplemented. */ -static enum detect_status +static xf86OutputStatus i830_dvo_detect(xf86OutputPtr output) { - return OUTPUT_STATUS_UNKNOWN; + return XF86OutputStatusUnknown; } static Bool @@ -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 @@ -248,6 +257,7 @@ i830_dvo_init(ScrnInfoPtr pScrn) } intel_output->type = I830_OUTPUT_DVO; output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; /* Set up the I2C and DDC buses */ ret = I830I2CInit(pScrn, &intel_output->pI2CBus, GPIOE, "DVOI2C_E"); diff --git a/src/i830_edid_modes.c b/src/i830_edid_modes.c index fcb71d23..3becbb50 100644 --- a/src/i830_edid_modes.c +++ b/src/i830_edid_modes.c @@ -38,7 +38,7 @@ #include "i830.h" #include "i830_display.h" -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) /* * TODO: @@ -208,4 +208,4 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) return Modes; } -#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) */ +#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) */ diff --git a/src/i830_lvds.c b/src/i830_lvds.c index bfb4e148..90f785e9 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; @@ -50,12 +50,10 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on) pI830->backlight_duty_cycle = backlight_duty_cycle; if (on) { - OUTREG(PP_STATUS, INREG(PP_STATUS) | PP_ON); OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON); do { pp_status = INREG(PP_STATUS); - pp_control = INREG(PP_CONTROL); - } while (!(pp_status & PP_ON) && !(pp_control & POWER_TARGET_ON)); + } while ((pp_status & PP_ON) == 0); OUTREG(BLC_PWM_CTL, (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) | pI830->backlight_duty_cycle); @@ -63,12 +61,10 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on) OUTREG(BLC_PWM_CTL, (blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK)); - OUTREG(PP_STATUS, INREG(PP_STATUS) & ~PP_ON); OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON); do { pp_status = INREG(PP_STATUS); - pp_control = INREG(PP_CONTROL); - } while ((pp_status & PP_ON) || (pp_control & POWER_TARGET_ON)); + } while (pp_status & PP_ON); } } @@ -81,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 @@ -132,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. */ - i830SetLVDSPanelPower(pScrn, FALSE); + 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. + */ + + 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 | @@ -163,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); } /** @@ -184,10 +221,10 @@ i830_lvds_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode) * This always returns OUTPUT_STATUS_CONNECTED. This output should only have * been set up if the LVDS was actually connected anyway. */ -static enum detect_status +static xf86OutputStatus i830_lvds_detect(xf86OutputPtr output) { - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; } /** @@ -198,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; + if (pI830->panel_fixed_mode != NULL) + return xf86DuplicateMode(pI830->panel_fixed_mode); - new->type = M_T_PREFERRED; - - return new; + return NULL; } static void @@ -238,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 @@ -278,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; @@ -297,6 +322,7 @@ i830_lvds_init(ScrnInfoPtr pScrn) } intel_output->type = I830_OUTPUT_LVDS; output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; /* Set up the LVDS DDC channel. Most panels won't support it, but it can * be useful if available. diff --git a/src/i830_modes.c b/src/i830_modes.c index a0d79db9..34f6cd52 100644 --- a/src/i830_modes.c +++ b/src/i830_modes.c @@ -57,245 +57,6 @@ #define DEBUG_REPROBE 1 -static DisplayModePtr -i830GetModeListTail(DisplayModePtr pModeList) -{ - DisplayModePtr last; - - if (pModeList == NULL) - return NULL; - - for (last = pModeList; last->next != NULL; last = last->next) - ; - - return last; -} - -/** - * This function removes a mode from a list of modes. It should probably be - * moved to xf86Mode.c. - * - * There are different types of mode lists: - * - * - singly linked linear lists, ending in NULL - * - doubly linked linear lists, starting and ending in NULL - * - doubly linked circular lists - * - */ - -static void -I830xf86DeleteModeFromList(DisplayModePtr *modeList, DisplayModePtr mode) -{ - /* Catch the easy/insane cases */ - if (modeList == NULL || *modeList == NULL || mode == NULL) - return; - - /* If the mode is at the start of the list, move the start of the list */ - if (*modeList == mode) - *modeList = mode->next; - - /* If mode is the only one on the list, set the list to NULL */ - if ((mode == mode->prev) && (mode == mode->next)) { - *modeList = NULL; - } else { - if ((mode->prev != NULL) && (mode->prev->next == mode)) - mode->prev->next = mode->next; - if ((mode->next != NULL) && (mode->next->prev == mode)) - mode->next->prev = mode->prev; - } -} - -void -i830_reprobe_output_modes(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - Bool properties_set = FALSE; - int i; - - /* Re-probe the list of modes for each output. */ - for (i = 0; i < pI830->xf86_config.num_output; i++) - { - xf86OutputPtr output = pI830->xf86_config.output[i]; - DisplayModePtr mode; - - while (output->probed_modes != NULL) - xf86DeleteMode(&output->probed_modes, output->probed_modes); - - output->probed_modes = (*output->funcs->get_modes) (output); - - /* Set the DDC properties to whatever first output has DDC information. - */ - if (output->MonInfo != NULL && !properties_set) { - xf86SetDDCproperties(pScrn, output->MonInfo); - properties_set = TRUE; - } - - if (output->probed_modes != NULL) - { - /* silently prune modes down to ones matching the user's - * configuration. - */ - i830xf86ValidateModesUserConfig(pScrn, output->probed_modes); - i830xf86PruneInvalidModes(pScrn, &output->probed_modes, FALSE); - } - -#ifdef DEBUG_REPROBE - if (output->probed_modes != NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Printing probed modes for output %s\n", - output->name); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No remaining probed modes for output %s\n", - output->name); - } -#endif - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - { - /* The code to choose the best mode per pipe later on will require - * VRefresh to be set. - */ - mode->VRefresh = xf86ModeVRefresh(mode); - xf86SetModeCrtc(mode, INTERLACE_HALVE_V); - -#ifdef DEBUG_REPROBE - xf86PrintModeline(pScrn->scrnIndex, mode); -#endif - } - } -} - -/** - * Constructs pScrn->modes from the output mode lists. - * - * Currently it only takes one output's mode list and stuffs it into the - * XFree86 DDX mode list while trimming it for root window size. - * - * This should be obsoleted by RandR 1.2 hopefully. - */ -void -i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - DisplayModePtr saved_mode, last; - int originalVirtualX, originalVirtualY; - int i; - - /* Remove the current mode from the modelist if we're re-validating, so we - * can find a new mode to map ourselves to afterwards. - */ - saved_mode = pI830->currentMode; - if (saved_mode != NULL) { - I830xf86DeleteModeFromList(&pScrn->modes, saved_mode); - } - - /* Clear any existing modes from pScrn->modes */ - while (pScrn->modes != NULL) - xf86DeleteMode(&pScrn->modes, pScrn->modes); - - /* Set pScrn->modes to the mode list for an arbitrary output. - * pScrn->modes should only be used for XF86VidMode now, which we don't - * care about enough to make some sort of unioned list. - */ - for (i = 0; i < pI830->xf86_config.num_output; i++) { - xf86OutputPtr output = pI830->xf86_config.output[i]; - if (output->probed_modes != NULL) { - pScrn->modes = xf86DuplicateModes(pScrn, output->probed_modes); - break; - } - } - - xf86RandR12GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); - - /* Disable modes in the XFree86 DDX list that are larger than the current - * virtual size. - */ - i830xf86ValidateModesSize(pScrn, pScrn->modes, - originalVirtualX, originalVirtualY, - pScrn->displayWidth); - - /* Strip out anything that we threw out for virtualX/Y. */ - i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); - - if (pScrn->modes == NULL) { - FatalError("No modes left for XFree86 DDX\n"); - } - - /* For some reason, pScrn->modes is circular, unlike the other mode lists. - * How great is that? - */ - last = i830GetModeListTail(pScrn->modes); - last->next = pScrn->modes; - pScrn->modes->prev = last; - - /* Save a pointer to the previous current mode. We can't reset - * pScrn->currentmode, because we rely on xf86SwitchMode's shortcut not - * happening so we can hot-enable devices at SwitchMode. We'll notice this - * case at SwitchMode and free the saved mode. - */ - pI830->savedCurrentMode = saved_mode; -} - -/** - * Takes the output mode lists and decides the default root window size - * and framebuffer pitch. - */ -void -i830_set_default_screen_size(ScrnInfoPtr pScrn) -{ - I830Ptr pI830 = I830PTR(pScrn); - int maxX = -1, maxY = -1; - int i; - - /* Set up a virtual size that will cover any clone mode we'd want to - * set for the currently-connected outputs. - */ - for (i = 0; i < pI830->xf86_config.num_output; i++) { - xf86OutputPtr output = pI830->xf86_config.output[i]; - DisplayModePtr mode; - - for (mode = output->probed_modes; mode != NULL; mode = mode->next) - { - if (mode->HDisplay > maxX) - maxX = mode->HDisplay; - if (mode->VDisplay > maxY) - maxY = mode->VDisplay; - } - } - /* let the user specify a bigger virtual size if they like */ - if (pScrn->display->virtualX > maxX) - maxX = pScrn->display->virtualX; - if (pScrn->display->virtualY > maxY) - maxY = pScrn->display->virtualY; - pScrn->virtualX = maxX; - pScrn->virtualY = maxY; - pScrn->displayWidth = (maxX + 63) & ~63; -} - -/** - * Probes for video modes on attached otuputs, and assembles a list to insert - * into pScrn. - * - * \param first_time indicates that the memory layout has already been set up, - * so displayWidth, virtualX, and virtualY shouldn't be touched. - * - * A SetMode must follow this call in order for operatingDevices to match the - * hardware's state, in case we detect a new output device. - */ -int -I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) -{ - i830_reprobe_output_modes(pScrn); - - if (first_time) { - i830_set_default_screen_size(pScrn); - } - - i830_set_xf86_modes_from_outputs(pScrn); - - return 1; /* XXX */ -} - #ifdef RANDR_12_INTERFACE #define EDID_ATOM_NAME "EDID_DATA" diff --git a/src/i830_randr.c b/src/i830_randr.c index 373403f8..2d986df2 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" @@ -94,7 +95,8 @@ xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) } /* Re-probe the outputs for new monitors or modes */ - I830ValidateXF86ModeList(scrp, FALSE); + xf86ProbeOutputModes (scrp); + xf86SetScrnInfoModes (scrp); for (mode = scrp->modes; ; mode = mode->next) { @@ -246,13 +248,13 @@ xf86RandR12SetConfig (ScreenPtr pScreen, int rate, RRScreenSizePtr pSize) { - ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - DisplayModePtr mode; - int px, py; - Bool useVirtual = FALSE; - int maxX = 0, maxY = 0; - Rotation oldRotation = randrp->rotation; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = randrp->rotation; randrp->rotation = rotation; @@ -487,15 +489,15 @@ xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) { ScreenPtr pScreen = randr_crtc->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); RRModePtr randr_mode = NULL; int x; int y; Rotation rotation; int numOutputs; - RROutputPtr randr_outputs[MAX_OUTPUTS]; + RROutputPtr randr_outputs[XF86_MAX_OUTPUT]; RROutputPtr randr_output; - xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86CrtcPtr crtc = randr_crtc->devPrivate; xf86OutputPtr output; int i, j; DisplayModePtr curMode = &crtc->curMode; @@ -505,9 +507,9 @@ xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) rotation = RR_Rotate_0; numOutputs = 0; randr_mode = NULL; - for (i = 0; i < pI830->xf86_config.num_output; i++) + for (i = 0; i < config->num_output; i++) { - output = pI830->xf86_config.output[i]; + output = config->output[i]; if (output->crtc == crtc) { randr_output = output->randr_output; @@ -542,12 +544,13 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, RROutputPtr *randr_outputs) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); - xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = randr_crtc->devPrivate; DisplayModePtr mode = randr_mode ? randr_mode->devPrivate : NULL; Bool changed = FALSE; + Bool pos_changed; int o, ro; - xf86CrtcPtr save_crtcs[MAX_OUTPUTS]; + xf86CrtcPtr save_crtcs[XF86_MAX_OUTPUT]; Bool save_enabled = crtc->enabled; if ((mode != NULL) != crtc->enabled) @@ -555,9 +558,12 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, else if (mode && !xf86ModesEqual (&crtc->curMode, mode)) changed = TRUE; - for (o = 0; o < pI830->xf86_config.num_output; o++) + pos_changed = changed; + if (x != crtc->x || y != crtc->y) + pos_changed = TRUE; + for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = pI830->xf86_config.output[o]; + xf86OutputPtr output = config->output[o]; xf86CrtcPtr new_crtc; save_crtcs[o] = output->crtc; @@ -578,10 +584,12 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, output->crtc = new_crtc; } } + /* XXX need device-independent mode setting code through an API */ if (changed) { + I830Ptr pI830 = I830PTR(pScrn); crtc->enabled = mode != NULL; - + /* Sync the engine before adjust mode */ if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { (*pI830->AccelInfoRec->Sync)(pScrn); @@ -593,18 +601,21 @@ xf86RandR12CrtcSet (ScreenPtr pScreen, if (!i830PipeSetMode (crtc, mode, TRUE)) { crtc->enabled = save_enabled; - for (o = 0; o < pI830->xf86_config.num_output; o++) + for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = pI830->xf86_config.output[o]; + xf86OutputPtr output = config->output[o]; output->crtc = save_crtcs[o]; } return FALSE; } crtc->desiredMode = *mode; - i830PipeSetBase(crtc, x, y); } i830DisableUnusedFunctions (pScrn); + + i830DumpRegs(pScrn); } + if (pos_changed && mode) + i830PipeSetBase(crtc, x, y); return xf86RandR12CrtcNotify (randr_crtc); } @@ -620,7 +631,7 @@ xf86RandR12CrtcSetGamma (ScreenPtr pScreen, * RandR modes and assign them to the output */ static Bool -I830xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) { DisplayModePtr mode; RRModePtr *rrmodes = NULL; @@ -660,8 +671,8 @@ I830xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) modeInfo.modeFlags = mode->Flags; rrmode = RRModeGet (&modeInfo, mode->name); - rrmode->devPrivate = mode; if (rrmode) { + rrmode->devPrivate = mode; rrmodes[nmode++] = rrmode; npreferred += pref; } @@ -679,64 +690,25 @@ I830xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) * Mirror the current mode configuration to RandR */ static Bool -xf86RandR12SetInfo12 (ScrnInfoPtr pScrn) +xf86RandR12SetInfo12 (ScreenPtr pScreen) { - I830Ptr pI830 = I830PTR(pScrn); - RROutputPtr clones[MAX_OUTPUTS]; - RRCrtcPtr crtcs[MAX_DISPLAY_PIPES]; - int ncrtc; - int o, c, p; - int clone_types; - int crtc_types; - int subpixel; - RRCrtcPtr randr_crtc; - int nclone; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RROutputPtr clones[XF86_MAX_OUTPUT]; + RRCrtcPtr crtcs[XF86_MAX_CRTC]; + int ncrtc; + int o, c, l; + RRCrtcPtr randr_crtc; + int nclone; - for (o = 0; o < pI830->xf86_config.num_output; o++) + for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = pI830->xf86_config.output[o]; - I830OutputPrivatePtr intel_output = output->driver_private; - /* - * Valid crtcs - */ - switch (intel_output->type) { - case I830_OUTPUT_DVO: - case I830_OUTPUT_SDVO: - crtc_types = ((1 << 0)| - (1 << 1)); - clone_types = ((1 << I830_OUTPUT_ANALOG) | - (1 << I830_OUTPUT_DVO) | - (1 << I830_OUTPUT_SDVO)); - subpixel = SubPixelHorizontalRGB; - break; - case I830_OUTPUT_ANALOG: - crtc_types = ((1 << 0) | (1 << 1)); - clone_types = ((1 << I830_OUTPUT_ANALOG) | - (1 << I830_OUTPUT_DVO) | - (1 << I830_OUTPUT_SDVO)); - subpixel = SubPixelNone; - break; - case I830_OUTPUT_LVDS: - crtc_types = (1 << 1); - clone_types = (1 << I830_OUTPUT_LVDS); - subpixel = SubPixelHorizontalRGB; - break; - case I830_OUTPUT_TVOUT: - crtc_types = ((1 << 0) | - (1 << 1)); - clone_types = (1 << I830_OUTPUT_TVOUT); - subpixel = SubPixelNone; - break; - default: - crtc_types = 0; - clone_types = 0; - subpixel = SubPixelUnknown; - break; - } + xf86OutputPtr output = config->output[o]; + ncrtc = 0; - for (p = 0; p < pI830->xf86_config.num_crtc; p++) - if (crtc_types & (1 << p)) - crtcs[ncrtc++] = pI830->xf86_config.crtc[p]->randr_crtc; + for (c = 0; c < config->num_crtc; c++) + if (output->possible_crtcs & (1 << c)) + crtcs[ncrtc++] = config->crtc[c]->randr_crtc; if (output->crtc) randr_crtc = output->crtc->randr_crtc; @@ -750,32 +722,31 @@ xf86RandR12SetInfo12 (ScrnInfoPtr pScrn) RROutputSetPhysicalSize(output->randr_output, output->mm_width, output->mm_height); - I830xf86RROutputSetModes (output->randr_output, output->probed_modes); + xf86RROutputSetModes (output->randr_output, output->probed_modes); - switch ((*output->funcs->detect)(output)) { - case OUTPUT_STATUS_CONNECTED: + switch (output->status = (*output->funcs->detect)(output)) { + case XF86OutputStatusConnected: RROutputSetConnection (output->randr_output, RR_Connected); break; - case OUTPUT_STATUS_DISCONNECTED: + case XF86OutputStatusDisconnected: RROutputSetConnection (output->randr_output, RR_Disconnected); break; - case OUTPUT_STATUS_UNKNOWN: + case XF86OutputStatusUnknown: RROutputSetConnection (output->randr_output, RR_UnknownConnection); break; } - RROutputSetSubpixelOrder (output->randr_output, subpixel); + RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); /* * Valid clones */ nclone = 0; - for (c = 0; c < pI830->xf86_config.num_output; c++) + for (l = 0; l < config->num_output; l++) { - xf86OutputPtr clone = pI830->xf86_config.output[c]; - I830OutputPrivatePtr intel_clone = clone->driver_private; + xf86OutputPtr clone = config->output[l]; - if (o != c && ((1 << intel_clone->type) & clone_types)) + if (l != o && (output->possible_clones & (1 << l))) clones[nclone++] = clone->randr_output; } if (!RROutputSetClones (output->randr_output, clones, nclone)) @@ -793,15 +764,18 @@ xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - i830_reprobe_output_modes(pScrn); - return xf86RandR12SetInfo12 (pScrn); + xf86ProbeOutputModes (pScrn); + xf86SetScrnInfoModes (pScrn); + return xf86RandR12SetInfo12 (pScreen); } static Bool -xf86RandR12CreateObjects12 (ScrnInfoPtr pScrn) +xf86RandR12CreateObjects12 (ScreenPtr pScreen) { - I830Ptr pI830 = I830PTR(pScrn); - int p; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + int o; if (!RRInit ()) return FALSE; @@ -809,45 +783,47 @@ xf86RandR12CreateObjects12 (ScrnInfoPtr pScrn) /* * Configure crtcs */ - for (p = 0; p < pI830->xf86_config.num_crtc; p++) + for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = pI830->xf86_config.crtc[p]; + xf86CrtcPtr crtc = config->crtc[c]; + crtc->randr_crtc = RRCrtcCreate (crtc); + RRCrtcAttachScreen (crtc->randr_crtc, pScreen); RRCrtcGammaSetSize (crtc->randr_crtc, 256); } + /* + * Configure outputs + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + output->randr_output = RROutputCreate (output->name, + strlen (output->name), + output); + RROutputAttachScreen (output->randr_output, pScreen); + } return TRUE; } static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) { - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); - int p, o; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; int width, height; - /* - * Attach RandR objects to screen - */ - for (p = 0; p < pI830->xf86_config.num_crtc; p++) - if (!RRCrtcAttachScreen (pI830->xf86_config.crtc[p]->randr_crtc, pScreen)) - return FALSE; - - for (o = 0; o < pI830->xf86_config.num_output; o++) - if (!RROutputAttachScreen (pI830->xf86_config.output[o]->randr_output, pScreen)) - return FALSE; - /* * Compute width of screen */ width = 0; height = 0; - for (p = 0; p < pI830->xf86_config.num_crtc; p++) + for (c = 0; c < config->num_crtc; c++) { - xf86CrtcPtr crtc = pI830->xf86_config.crtc[p]; - int crtc_width = crtc->x + crtc->curMode.HDisplay; - int crtc_height = crtc->y + crtc->curMode.VDisplay; + xf86CrtcPtr crtc = config->crtc[c]; + int crtc_width = crtc->x + crtc->curMode.HDisplay; + int crtc_height = crtc->y + crtc->curMode.VDisplay; if (crtc->enabled && crtc_width > width) width = crtc_width; @@ -869,14 +845,14 @@ xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) "Setting screen physical size to %d x %d\n", mmWidth, mmHeight); xf86RandR12ScreenSetSize (pScreen, - width, - height, - mmWidth, - mmHeight); + width, + height, + mmWidth, + mmHeight); } - for (p = 0; p < pI830->xf86_config.num_crtc; p++) - xf86RandR12CrtcNotify (pI830->xf86_config.crtc[p]->randr_crtc); + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); if (randrp->virtualX == -1 || randrp->virtualY == -1) { @@ -906,347 +882,21 @@ xf86RandR12Init12 (ScreenPtr pScreen) rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; rp->rrSetConfig = NULL; pScrn->PointerMoved = xf86RandR12PointerMoved; - return TRUE; -} - -static RRModePtr -I830RRDefaultMode (RROutputPtr output) -{ - RRModePtr target_mode = NULL; - int target_diff = 0; - int mmHeight; - int num_modes; - int m; - - num_modes = output->numPreferred ? output->numPreferred : output->numModes; - mmHeight = output->mmHeight; - if (!mmHeight) - mmHeight = 203; /* 768 pixels at 96dpi */ - /* - * Pick a mode closest to 96dpi - */ - for (m = 0; m < num_modes; m++) - { - RRModePtr mode = output->modes[m]; - int dpi; - int diff; - - dpi = (mode->mode.height * 254) / (mmHeight * 10); - diff = dpi - 96; - diff = diff < 0 ? -diff : diff; - if (target_mode == NULL || diff < target_diff) - { - target_mode = mode; - target_diff = diff; - } - } - return target_mode; -} - -static RRModePtr -I830ClosestMode (RROutputPtr output, RRModePtr match) -{ - RRModePtr target_mode = NULL; - int target_diff = 0; - int m; - - /* - * Pick a mode closest to the specified mode - */ - for (m = 0; m < output->numModes; m++) - { - RRModePtr mode = output->modes[m]; - int dx, dy; - int diff; - - /* exact matches are preferred */ - if (mode == match) - return mode; - - dx = match->mode.width - mode->mode.width; - dy = match->mode.height - mode->mode.height; - diff = dx * dx + dy * dy; - if (target_mode == NULL || diff < target_diff) - { - target_mode = mode; - target_diff = diff; - } - } - return target_mode; -} - -static int -I830RRPickCrtcs (RROutputPtr *outputs, - RRCrtcPtr *best_crtcs, - RRModePtr *modes, - int num_output, - int n) -{ - int c, o, l; - RROutputPtr output; - RRCrtcPtr crtc; - RRCrtcPtr *crtcs; - RRCrtcPtr best_crtc; - int best_score; - int score; - int my_score; - - if (n == num_output) - return 0; - output = outputs[n]; - - /* - * Compute score with this output disabled - */ - best_crtcs[n] = NULL; - best_crtc = NULL; - best_score = I830RRPickCrtcs (outputs, best_crtcs, modes, num_output, n+1); - if (modes[n] == NULL) - return best_score; - - crtcs = xalloc (num_output * sizeof (RRCrtcPtr)); - if (!crtcs) - return best_score; - - my_score = 1; - /* Score outputs that are known to be connected higher */ - if (output->connection == RR_Connected) - my_score++; - /* Score outputs with preferred modes higher */ - if (output->numPreferred) - my_score++; - /* - * Select a crtc for this output and - * then attempt to configure the remaining - * outputs - */ - for (c = 0; c < output->numCrtcs; c++) - { - crtc = output->crtcs[c]; - /* - * Check to see if some other output is - * using this crtc - */ - for (o = 0; o < n; o++) - if (best_crtcs[o] == crtc) - break; - if (o < n) - { - /* - * If the two outputs desire the same mode, - * see if they can be cloned - */ - if (modes[o] == modes[n]) - { - for (l = 0; l < output->numClones; l++) - if (output->clones[l] == outputs[o]) - break; - if (l == output->numClones) - continue; /* nope, try next CRTC */ - } - else - continue; /* different modes, can't clone */ - } - crtcs[n] = crtc; - memcpy (crtcs, best_crtcs, n * sizeof (RRCrtcPtr)); - score = my_score + I830RRPickCrtcs (outputs, crtcs, modes, - num_output, n+1); - if (score >= best_score) - { - best_crtc = crtc; - best_score = score; - memcpy (best_crtcs, crtcs, num_output * sizeof (RRCrtcPtr)); - } - } - xfree (crtcs); - return best_score; -} - -static Bool -I830RRInitialConfiguration (RROutputPtr *outputs, - RRCrtcPtr *crtcs, - RRModePtr *modes, - int num_output) -{ - int o; - RRModePtr target_mode = NULL; - - for (o = 0; o < num_output; o++) - modes[o] = NULL; - - /* - * Let outputs with preferred modes drive screen size - */ - for (o = 0; o < num_output; o++) - { - RROutputPtr output = outputs[o]; - - if (output->connection != RR_Disconnected && output->numPreferred) - { - target_mode = I830RRDefaultMode (output); - if (target_mode) - { - modes[o] = target_mode; - break; - } - } - } - if (!target_mode) - { - for (o = 0; o < num_output; o++) - { - RROutputPtr output = outputs[o]; - if (output->connection != RR_Disconnected) - { - target_mode = I830RRDefaultMode (output); - if (target_mode) - { - modes[o] = target_mode; - break; - } - } - } - } - for (o = 0; o < num_output; o++) - { - RROutputPtr output = outputs[o]; - - if (output->connection != RR_Disconnected && !modes[o]) - modes[o] = I830ClosestMode (output, target_mode); - } - - if (!I830RRPickCrtcs (outputs, crtcs, modes, num_output, 0)) + if (!xf86RandR12CreateObjects12 (pScreen)) + return FALSE; + + /* + * Configure output modes + */ + if (!xf86RandR12SetInfo12 (pScreen)) return FALSE; - return TRUE; } -/* - * Compute the virtual size necessary to place all of the available - * crtcs in a panorama configuration - */ - -static void -I830RRDefaultScreenLimits (RROutputPtr *outputs, int num_output, - RRCrtcPtr *crtcs, int num_crtc, - int *widthp, int *heightp) -{ - int width = 0, height = 0; - int o; - int c; - int m; - int s; - - for (c = 0; c < num_crtc; c++) - { - RRCrtcPtr crtc = crtcs[c]; - int crtc_width = 1600, crtc_height = 1200; - - for (o = 0; o < num_output; o++) - { - RROutputPtr output = outputs[o]; - - for (s = 0; s < output->numCrtcs; s++) - if (output->crtcs[s] == crtc) - { - for (m = 0; m < output->numModes; m++) - { - RRModePtr mode = output->modes[m]; - if (mode->mode.width > crtc_width) - crtc_width = mode->mode.width; - if (mode->mode.height > crtc_width) - crtc_height = mode->mode.height; - } - } - } - if (crtc_width > width) - width = crtc_width; - if (crtc_height > height) - height = crtc_height; - } - *widthp = width; - *heightp = height; -} - #endif Bool xf86RandR12PreInit (ScrnInfoPtr pScrn) { - I830Ptr pI830 = I830PTR(pScrn); -#if RANDR_12_INTERFACE - RROutputPtr outputs[MAX_OUTPUTS]; - RRCrtcPtr output_crtcs[MAX_OUTPUTS]; - RRModePtr output_modes[MAX_OUTPUTS]; - RRCrtcPtr crtcs[MAX_DISPLAY_PIPES]; - int width, height; - int o; - int c; -#endif - - if (pI830->xf86_config.num_output <= 0) - return FALSE; - - i830_reprobe_output_modes(pScrn); - -#if RANDR_12_INTERFACE - if (!xf86RandR12CreateObjects12 (pScrn)) - return FALSE; - - /* - * Configure output modes - */ - if (!xf86RandR12SetInfo12 (pScrn)) - return FALSE; - /* - * With RandR info set up, let RandR choose - * the initial configuration - */ - for (o = 0; o < pI830->xf86_config.num_output; o++) - outputs[o] = pI830->xf86_config.output[o]->randr_output; - for (c = 0; c < pI830->xf86_config.num_crtc; c++) - crtcs[c] = pI830->xf86_config.crtc[c]->randr_crtc; - - if (!I830RRInitialConfiguration (outputs, output_crtcs, output_modes, - pI830->xf86_config.num_output)) - return FALSE; - - I830RRDefaultScreenLimits (outputs, pI830->xf86_config.num_output, - crtcs, pI830->xf86_config.num_crtc, - &width, &height); - - if (width > pScrn->virtualX) - pScrn->virtualX = width; - if (width > pScrn->display->virtualX) - pScrn->display->virtualX = width; - if (height > pScrn->virtualY) - pScrn->virtualY = height; - if (height > pScrn->display->virtualY) - pScrn->display->virtualY = height; - - /* XXX override xf86 common frame computation code */ - pScrn->display->frameX0 = 0; - pScrn->display->frameY0 = 0; - for (o = 0; o < pI830->xf86_config.num_output; o++) - { - xf86OutputPtr output = pI830->xf86_config.output[o]; - RRModePtr randr_mode = output_modes[o]; - RRCrtcPtr randr_crtc = output_crtcs[o]; - DisplayModePtr mode; - - if (randr_mode && randr_crtc) - { - xf86CrtcPtr crtc = randr_crtc->devPrivate; - - mode = (DisplayModePtr) randr_mode->devPrivate; - crtc->desiredMode = *mode; - output->crtc = crtc; - } - } -#endif - i830_set_xf86_modes_from_outputs (pScrn); - - i830_set_default_screen_size(pScrn); - return TRUE; } diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index aa061828..87dc9d9e 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -534,15 +534,35 @@ 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 sdvox; + 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; @@ -593,9 +613,6 @@ i830_sdvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr mode) output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; output_dtd.part2.reserved = 0; - /* Turn off the screens before adjusting timings */ - i830_sdvo_set_active_outputs(output, 0); - /* Set the output timing to the screen */ i830_sdvo_set_target_output(output, dev_priv->active_outputs); i830_sdvo_set_output_timing(output, &output_dtd); @@ -633,26 +650,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,24 +660,20 @@ 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; - dpll = INREG(dpll_reg); - sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode); if (IS_I965G(pI830)) { OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); } else if (IS_I945G(pI830) || IS_I945GM(pI830)) { - dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + /* done in crtc_mode_set as it lives inside the dpll register */ } else { sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - OUTREG(dpll_reg, dpll | DPLL_DVO_HIGH_SPEED); - OUTREG(dev_priv->output_device, sdvox); for (i = 0; i < 2; i++) @@ -694,9 +687,6 @@ i830_sdvo_post_set_mode(xf86OutputPtr output, DisplayModePtr mode) "First %s output reported failure to sync\n", SDVO_NAME(dev_priv)); } - - i830_sdvo_set_active_outputs(output, dev_priv->active_outputs); - i830_sdvo_set_target_input(output, TRUE, FALSE); } static void @@ -823,7 +813,7 @@ i830_sdvo_get_capabilities(xf86OutputPtr output, struct i830_sdvo_caps *caps) static Bool i830_sdvo_ddc_i2c_get_byte(I2CDevPtr d, I2CByte *data, Bool last) { - xf86OutputPtr output = d->DriverPrivate.ptr; + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; I830OutputPrivatePtr intel_output = output->driver_private; I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; Bool ret; @@ -840,7 +830,7 @@ i830_sdvo_ddc_i2c_get_byte(I2CDevPtr d, I2CByte *data, Bool last) static Bool i830_sdvo_ddc_i2c_put_byte(I2CDevPtr d, I2CByte c) { - xf86OutputPtr output = d->DriverPrivate.ptr; + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; I830OutputPrivatePtr intel_output = output->driver_private; I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; Bool ret; @@ -875,7 +865,7 @@ i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout) static void i830_sdvo_ddc_i2c_stop(I2CDevPtr d) { - xf86OutputPtr output = d->DriverPrivate.ptr; + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; I830OutputPrivatePtr intel_output = output->driver_private; I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; @@ -975,7 +965,7 @@ i830_sdvo_dump(ScrnInfoPtr pScrn) * * Takes 14ms on average on my i945G. */ -static enum detect_status +static xf86OutputStatus i830_sdvo_detect(xf86OutputPtr output) { CARD8 response[2]; @@ -985,12 +975,12 @@ i830_sdvo_detect(xf86OutputPtr output) status = i830_sdvo_read_response(output, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) - return OUTPUT_STATUS_UNKNOWN; + return XF86OutputStatusUnknown; if (response[0] != 0 || response[1] != 0) - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; else - return OUTPUT_STATUS_DISCONNECTED; + return XF86OutputStatusDisconnected; } static void @@ -1014,8 +1004,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 @@ -1132,9 +1122,15 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs)); if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) + { dev_priv->active_outputs = SDVO_OUTPUT_TMDS0; + output->subpixel_order = SubPixelHorizontalRGB; + } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) + { dev_priv->active_outputs = SDVO_OUTPUT_TMDS1; + output->subpixel_order = SubPixelHorizontalRGB; + } else { unsigned char bytes[2]; diff --git a/src/i830_tv.c b/src/i830_tv.c index f5716f8b..b6cc2c9b 100644 --- a/src/i830_tv.c +++ b/src/i830_tv.c @@ -59,6 +59,26 @@ struct i830_tv_priv { CARD32 save_TV_V_CTL_6; CARD32 save_TV_V_CTL_7; CARD32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; + + CARD32 save_TV_CSC_Y; + CARD32 save_TV_CSC_Y2; + CARD32 save_TV_CSC_U; + CARD32 save_TV_CSC_U2; + CARD32 save_TV_CSC_V; + CARD32 save_TV_CSC_V2; + CARD32 save_TV_CLR_KNOBS; + CARD32 save_TV_CLR_LEVEL; + CARD32 save_TV_WIN_POS; + CARD32 save_TV_WIN_SIZE; + CARD32 save_TV_FILTER_CTL_1; + CARD32 save_TV_FILTER_CTL_2; + CARD32 save_TV_FILTER_CTL_3; + + CARD32 save_TV_H_LUMA[60]; + CARD32 save_TV_H_CHROMA[60]; + CARD32 save_TV_V_LUMA[43]; + CARD32 save_TV_V_CHROMA[43]; + CARD32 save_TV_DAC; CARD32 save_TV_CTL; }; @@ -168,6 +188,7 @@ i830_tv_save(xf86OutputPtr output) I830Ptr pI830 = I830PTR(pScrn); I830OutputPrivatePtr intel_output = output->driver_private; struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int i; dev_priv->save_TV_H_CTL_1 = INREG(TV_H_CTL_1); dev_priv->save_TV_H_CTL_2 = INREG(TV_H_CTL_2); @@ -183,6 +204,29 @@ i830_tv_save(xf86OutputPtr output) dev_priv->save_TV_SC_CTL_2 = INREG(TV_SC_CTL_2); dev_priv->save_TV_SC_CTL_3 = INREG(TV_SC_CTL_3); + dev_priv->save_TV_CSC_Y = INREG(TV_CSC_Y); + dev_priv->save_TV_CSC_Y2 = INREG(TV_CSC_Y2); + dev_priv->save_TV_CSC_U = INREG(TV_CSC_U); + dev_priv->save_TV_CSC_U2 = INREG(TV_CSC_U2); + dev_priv->save_TV_CSC_V = INREG(TV_CSC_V); + dev_priv->save_TV_CSC_V2 = INREG(TV_CSC_V2); + dev_priv->save_TV_CLR_KNOBS = INREG(TV_CLR_KNOBS); + dev_priv->save_TV_CLR_LEVEL = INREG(TV_CLR_LEVEL); + dev_priv->save_TV_WIN_POS = INREG(TV_WIN_POS); + dev_priv->save_TV_WIN_SIZE = INREG(TV_WIN_SIZE); + dev_priv->save_TV_FILTER_CTL_1 = INREG(TV_FILTER_CTL_1); + dev_priv->save_TV_FILTER_CTL_2 = INREG(TV_FILTER_CTL_2); + dev_priv->save_TV_FILTER_CTL_3 = INREG(TV_FILTER_CTL_3); + + for (i = 0; i < 60; i++) + dev_priv->save_TV_H_LUMA[i] = INREG(TV_H_LUMA_0 + (i <<2)); + for (i = 0; i < 60; i++) + dev_priv->save_TV_H_CHROMA[i] = INREG(TV_H_CHROMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + dev_priv->save_TV_V_LUMA[i] = INREG(TV_V_LUMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + dev_priv->save_TV_V_CHROMA[i] = INREG(TV_V_CHROMA_0 + (i <<2)); + dev_priv->save_TV_DAC = INREG(TV_DAC); dev_priv->save_TV_CTL = INREG(TV_CTL); } @@ -194,6 +238,7 @@ i830_tv_restore(xf86OutputPtr output) I830Ptr pI830 = I830PTR(pScrn); I830OutputPrivatePtr intel_output = output->driver_private; struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int i; OUTREG(TV_H_CTL_1, dev_priv->save_TV_H_CTL_1); OUTREG(TV_H_CTL_2, dev_priv->save_TV_H_CTL_2); @@ -209,6 +254,29 @@ i830_tv_restore(xf86OutputPtr output) OUTREG(TV_SC_CTL_2, dev_priv->save_TV_SC_CTL_2); OUTREG(TV_SC_CTL_3, dev_priv->save_TV_SC_CTL_3); + OUTREG(TV_CSC_Y, dev_priv->save_TV_CSC_Y); + OUTREG(TV_CSC_Y2, dev_priv->save_TV_CSC_Y2); + OUTREG(TV_CSC_U, dev_priv->save_TV_CSC_U); + OUTREG(TV_CSC_U2, dev_priv->save_TV_CSC_U2); + OUTREG(TV_CSC_V, dev_priv->save_TV_CSC_V); + OUTREG(TV_CSC_V2, dev_priv->save_TV_CSC_V2); + OUTREG(TV_CLR_KNOBS, dev_priv->save_TV_CLR_KNOBS); + OUTREG(TV_CLR_LEVEL, dev_priv->save_TV_CLR_LEVEL); + OUTREG(TV_WIN_POS, dev_priv->save_TV_WIN_POS); + OUTREG(TV_WIN_SIZE, dev_priv->save_TV_WIN_SIZE); + OUTREG(TV_FILTER_CTL_1, dev_priv->save_TV_FILTER_CTL_1); + OUTREG(TV_FILTER_CTL_2, dev_priv->save_TV_FILTER_CTL_2); + OUTREG(TV_FILTER_CTL_3, dev_priv->save_TV_FILTER_CTL_3); + + for (i = 0; i < 60; i++) + OUTREG(TV_H_LUMA_0 + (i <<2), dev_priv->save_TV_H_LUMA[i]); + for (i = 0; i < 60; i++) + OUTREG(TV_H_CHROMA_0 + (i <<2), dev_priv->save_TV_H_CHROMA[i]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_LUMA_0 + (i <<2), dev_priv->save_TV_V_LUMA[i]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_CHROMA_0 + (i <<2), dev_priv->save_TV_V_CHROMA[i]); + OUTREG(TV_DAC, dev_priv->save_TV_DAC); OUTREG(TV_CTL, dev_priv->save_TV_CTL); } @@ -219,18 +287,6 @@ i830_tv_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) return MODE_OK; } -static void -i830_tv_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode) -{ - ScrnInfoPtr pScrn = output->scrn; - I830Ptr pI830 = I830PTR(pScrn); - - /* Disable the encoder while we set up the pipe. */ - OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE); - /* XXX match BIOS for now */ - OUTREG(ADPA, 0x40008C18); -} - static const CARD32 h_luma[60] = { 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, @@ -295,8 +351,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 +440,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 +484,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); @@ -544,7 +625,7 @@ i830_tv_detect_type (xf86CrtcPtr crtc, * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure * we have a pipe programmed in order to probe the TV. */ -static enum detect_status +static xf86OutputStatus i830_tv_detect(xf86OutputPtr output) { xf86CrtcPtr crtc; @@ -567,11 +648,11 @@ i830_tv_detect(xf86OutputPtr output) switch (dev_priv->type) { case TV_TYPE_NONE: - return OUTPUT_STATUS_DISCONNECTED; + return XF86OutputStatusDisconnected; case TV_TYPE_UNKNOWN: - return OUTPUT_STATUS_UNKNOWN; + return XF86OutputStatusUnknown; default: - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; } } @@ -635,8 +716,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.c b/src/i830_xf86Crtc.c index 2eb775bf..5378b34f 100644 --- a/src/i830_xf86Crtc.c +++ b/src/i830_xf86Crtc.c @@ -31,6 +31,7 @@ #include #include "xf86.h" +#include "xf86DDC.h" #include "i830_xf86Crtc.h" /* @@ -49,12 +50,7 @@ xf86CrtcCreate (ScrnInfoPtr scrn, crtc->scrn = scrn; crtc->funcs = funcs; #ifdef RANDR_12_INTERFACE - crtc->randr_crtc = RRCrtcCreate (crtc); - if (!crtc->randr_crtc) - { - xfree (crtc); - return NULL; - } + crtc->randr_crtc = NULL; #endif xf86_config->crtc[xf86_config->num_crtc++] = crtc; return crtc; @@ -67,9 +63,6 @@ xf86CrtcDestroy (xf86CrtcPtr crtc) int c; (*crtc->funcs->destroy) (crtc); -#ifdef RANDR_12_INTERFACE - RRCrtcDestroy (crtc->randr_crtc); -#endif for (c = 0; c < xf86_config->num_crtc; c++) if (xf86_config->crtc[c] == crtc) { @@ -100,14 +93,10 @@ xf86OutputCreate (ScrnInfoPtr scrn, output->scrn = scrn; output->funcs = funcs; output->name = (char *) (output + 1); + output->subpixel_order = SubPixelUnknown; strcpy (output->name, name); #ifdef RANDR_12_INTERFACE - output->randr_output = RROutputCreate (name, strlen (name), output); - if (!output->randr_output) - { - xfree (output); - return NULL; - } + output->randr_output = NULL; #endif xf86_config->output[xf86_config->num_output++] = output; return output; @@ -121,9 +110,6 @@ xf86OutputDestroy (xf86OutputPtr output) int o; (*output->funcs->destroy) (output); -#ifdef RANDR_12_INTERFACE - RROutputDestroy (output->randr_output); -#endif while (output->probed_modes) xf86DeleteMode (&output->probed_modes, output->probed_modes); for (o = 0; o < xf86_config->num_output; o++) @@ -138,3 +124,467 @@ xf86OutputDestroy (xf86OutputPtr output) xfree (output); } +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = 203; /* 768 pixels at 96dpi */ + /* + * Pick a mode closest to 96dpi + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + int preferred = (mode->type & M_T_PREFERRED) != 0; + int diff; + + dpi = (mode->HDisplay * 254) / (mm_height * 10); + diff = dpi - 96; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, DisplayModePtr match) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + /* exact matches are preferred */ + if (xf86ModesEqual (mode, match)) + return mode; + + dx = match->HDisplay - mode->HDisplay; + dy = match->VDisplay - mode->VDisplay; + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static Bool +xf86OutputHasPreferredMode (xf86OutputPtr output) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + if (mode->type & M_T_PREFERRED) + return TRUE; + return FALSE; +} + +static int +xf86PickCrtcs (ScrnInfoPtr pScrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c, o, l; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (pScrn, best_crtcs, modes, n+1); + if (modes[n] == NULL) + return best_score; + + crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n])) + { + for (l = 0; l < config->num_output; l++) + if (output->possible_clones & (1 << l)) + break; + if (l == config->num_output) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (pScrn, crtcs, modes, n+1); + if (score >= best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + xfree (crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in a panorama configuration + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 1600, crtc_height = 1200; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_height = mode->VDisplay; + } + } + } + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + } + *widthp = width; + *heightp = height; +} + +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool properties_set = FALSE; + int o; + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + output->probed_modes = (*output->funcs->get_modes) (output); + + /* Set the DDC properties to whatever first output has DDC information. + */ + if (output->MonInfo != NULL && !properties_set) { + xf86SetDDCproperties(pScrn, output->MonInfo); + properties_set = TRUE; + } + +#ifdef DEBUG_REPROBE + if (output->probed_modes != NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } +#endif + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + +#ifdef DEBUG_REPROBE + xf86PrintModeline(pScrn->scrnIndex, mode); +#endif + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode; + int originalVirtualX, originalVirtualY; + + output = config->output[config->compat_output]; + if (!output->crtc) + { + int o; + + output = NULL; + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc) + { + config->compat_output = o; + output = config->output[o]; + break; + } + /* no outputs are active, punt and leave things as they are */ + if (!output) + return; + } + crtc = output->crtc; + + /* Clear any existing modes from pScrn->modes */ + while (pScrn->modes != NULL) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + + /* Set pScrn->modes to the mode list for the 'compat' output */ + pScrn->modes = xf86DuplicateModes(pScrn, output->probed_modes); + + xf86RandR12GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); + + /* Disable modes in the XFree86 DDX list that are larger than the current + * virtual size. + */ + i830xf86ValidateModesSize(pScrn, pScrn->modes, + originalVirtualX, originalVirtualY, + pScrn->displayWidth); + + /* Strip out anything that we threw out for virtualX/Y. */ + i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); + + for (mode = pScrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + + /* For some reason, pScrn->modes is circular, unlike the other mode lists. + * How great is that? + */ + for (last = pScrn->modes; last && last->next; last = last->next); + last->next = pScrn->modes; + pScrn->modes->prev = last; + if (mode) + while (pScrn->modes != mode) + pScrn->modes = pScrn->modes->next; + pScrn->currentMode = pScrn->modes; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + */ + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + DisplayModePtr target_mode = NULL; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + int width, height; + + xf86ProbeOutputModes (pScrn); + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + + for (o = 0; o < config->num_output; o++) + modes[o] = NULL; + + /* + * Let outputs with preferred modes drive screen size + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->status != XF86OutputStatusDisconnected && + xf86OutputHasPreferredMode (output)) + { + target_mode = xf86DefaultMode (output); + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + if (!target_mode) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->status != XF86OutputStatusDisconnected) + { + target_mode = xf86DefaultMode (output); + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + } + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->status != XF86OutputStatusDisconnected && !modes[o]) + modes[o] = xf86ClosestMode (output, target_mode); + } + + if (!xf86PickCrtcs (pScrn, crtcs, modes, 0)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + xf86DefaultScreenLimits (pScrn, &width, &height); + + /* + * Expand virtual size to cover potential mode switches + */ + if (width > pScrn->virtualX) + pScrn->virtualX = width; + if (width > pScrn->display->virtualX) + pScrn->display->virtualX = width; + if (height > pScrn->virtualY) + pScrn->virtualY = height; + if (height > pScrn->display->virtualY) + pScrn->display->virtualY = height; + + /* XXX override xf86 common frame computation code */ + + pScrn->display->frameX0 = 0; + pScrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + } + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->enabled = TRUE; + crtc->x = 0; + crtc->y = 0; + output->crtc = crtc; + /* XXX set position; for now, we clone */ + } + } + + /* Mirror output modes to pScrn mode list */ + xf86SetScrnInfoModes (pScrn); + + xfree (crtcs); + xfree (modes); + return TRUE; +} diff --git a/src/i830_xf86Crtc.h b/src/i830_xf86Crtc.h index 2952c8d5..21fc244e 100644 --- a/src/i830_xf86Crtc.h +++ b/src/i830_xf86Crtc.h @@ -27,14 +27,21 @@ #include "i830_xf86Modes.h" typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr; +typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr; + +typedef enum _xf86OutputStatus { + XF86OutputStatusConnected, + XF86OutputStatusDisconnected, + XF86OutputStatusUnknown, +} xf86OutputStatus; 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 +59,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 +155,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 +183,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,27 +192,33 @@ 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. */ - enum detect_status + xf86OutputStatus (*detect)(xf86OutputPtr output); /** @@ -211,12 +243,23 @@ struct _xf86Output { * Associated ScrnInfo */ ScrnInfoPtr scrn; + /** * Currently connected crtc (if any) * * If this output is not in use, this field will be NULL. */ xf86CrtcPtr crtc; + + /** + * Possible CRTCs for this output as a mask of crtc indices + */ + CARD32 possible_crtcs; + + /** + * Possible outputs to share the same CRTC as a mask of output indices + */ + CARD32 possible_clones; /** * List of available modes on this output. * @@ -225,9 +268,20 @@ struct _xf86Output { */ DisplayModePtr probed_modes; + /** + * Current connection status + * + * This indicates whether a monitor is known to be connected + * to this output or not, or whether there is no way to tell + */ + xf86OutputStatus status; + /** EDID monitor information */ xf86MonPtr MonInfo; + /** subpixel order */ + int subpixel_order; + /** Physical size of the currently attached output device. */ int mm_width, mm_height; @@ -253,12 +307,20 @@ struct _xf86Output { #endif }; +/* XXX yes, static allocation is a kludge */ #define XF86_MAX_CRTC 4 #define XF86_MAX_OUTPUT 16 typedef struct _xf86CrtcConfig { int num_output; xf86OutputPtr output[XF86_MAX_OUTPUT]; + /** + * compat_output is used whenever we deal + * with legacy code that only understands a single + * output. pScrn->modes will be loaded from this output, + * adjust frame will whack this output, etc. + */ + int compat_output; int num_crtc; xf86CrtcPtr crtc[XF86_MAX_CRTC]; @@ -307,4 +369,13 @@ xf86OutputCreate (ScrnInfoPtr scrn, void xf86OutputDestroy (xf86OutputPtr output); +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn); + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn); + #endif /* _XF86CRTC_H_ */ diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c index c091aef7..1afda951 100644 --- a/src/i830_xf86Modes.c +++ b/src/i830_xf86Modes.c @@ -45,7 +45,7 @@ * there but we still want to use. We need to come up with better API here. */ -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) /** * Calculates the horizontal sync rate of a mode. * @@ -321,7 +321,7 @@ xf86PrintModeline(int scrnIndex,DisplayModePtr mode) mode->VTotal, flags, xf86ModeHSync(mode)); xfree(flags); } -#endif /* XORG_VERSION_CURRENT <= 7.1.99.2 */ +#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ /** * Marks as bad any modes with unsupported flags. diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h index 3bd8557d..98300039 100644 --- a/src/i830_xf86Modes.h +++ b/src/i830_xf86Modes.h @@ -29,7 +29,7 @@ #define _I830_XF86MODES_H_ #include "xorgVersion.h" -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) double i830_xf86ModeHSync(DisplayModePtr mode); double i830_xf86ModeVRefresh(DisplayModePtr mode); DisplayModePtr i830_xf86DuplicateMode(DisplayModePtr pMode); @@ -50,7 +50,7 @@ DisplayModePtr i830_xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new); #define xf86ModesEqual i830_xf86ModesEqual #define xf86PrintModeline i830_xf86PrintModeline #define xf86ModesAdd i830_xf86ModesAdd -#endif /* XORG_VERSION_CURRENT <= 7.1.99.2 */ +#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ void i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, diff --git a/src/i830_xf86cvt.c b/src/i830_xf86cvt.c index 00140561..dba57c82 100644 --- a/src/i830_xf86cvt.c +++ b/src/i830_xf86cvt.c @@ -40,7 +40,7 @@ #include "i830.h" #include "i830_display.h" -#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) /* * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. * @@ -303,4 +303,4 @@ xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, return Mode; } -#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,1,99,2,0) */ +#endif /* XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) */ diff --git a/src/i915_exa_render.c b/src/i915_exa_render.c index eae8171e..daffa0c6 100644 --- a/src/i915_exa_render.c +++ b/src/i915_exa_render.c @@ -116,6 +116,8 @@ static struct formatinfo I915TexFormats[] = { {PICT_r5g6b5, MAPSURF_16BIT | MT_16BIT_RGB565 }, {PICT_a1r5g5b5, MAPSURF_16BIT | MT_16BIT_ARGB1555 }, {PICT_x1r5g5b5, MAPSURF_16BIT | MT_16BIT_ARGB1555 }, + {PICT_a4r4g4b4, MAPSURF_16BIT | MT_16BIT_ARGB4444 }, + {PICT_x4r4g4b4, MAPSURF_16BIT | MT_16BIT_ARGB4444 }, {PICT_a8, MAPSURF_8BIT | MT_8BIT_A8 }, };