diff options
author | Dave Airlie <airlied@airlied-rhel5.(none)> | 2010-04-21 11:07:56 +1000 |
---|---|---|
committer | Dave Airlie <airlied@airlied-rhel5.(none)> | 2010-05-27 14:53:15 +1000 |
commit | 0fa5031c838fd11cc8462f8786d9f0e8bb8ebc7b (patch) | |
tree | 9d96058a8d1821757d9b1979fded0c945a351a02 | |
parent | 74631582089f4eaf1916008d649ba1e90319622f (diff) |
wip.patch
-rw-r--r-- | src/i810_reg.h | 7 | ||||
-rw-r--r-- | src/i830.h | 11 | ||||
-rw-r--r-- | src/i830_bios.c | 6 | ||||
-rw-r--r-- | src/i830_bios.h | 33 | ||||
-rw-r--r-- | src/i830_display.c | 343 | ||||
-rw-r--r-- | src/i830_lvds.c | 29 |
6 files changed, 351 insertions, 78 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h index 6a1339c0..25c59cb3 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -2083,6 +2083,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define SVBLANK_INT_STATUS (1 << 2) # define VBLANK_INT_STATUS (1 << 1) # define OREG_UPDATE_STATUS (1 << 0) +#define PIPE_BPC_MASK (7 << 5) /* Ironlake */ +#define PIPE_8BPC (0 << 5) +#define PIPE_10BPC (1 << 5) +#define PIPE_6BPC (2 << 5) +#define PIPE_12BPC (3 << 5) + #define DSPARB 0x70030 @@ -3138,6 +3144,7 @@ typedef enum { #define FDI_10BPC (1<<16) #define FDI_6BPC (2<<16) #define FDI_12BPC (3<<16) +#define FDI_BPC_MASK (3<<16) #define FDI_LINK_REVERSE_OVERWRITE (1<<15) #define FDI_DMI_LINK_REVERSE_MASK (1<<14) #define FDI_RX_PLL_ENABLE (1<<13) @@ -272,6 +272,7 @@ typedef struct _I830CrtcPrivateRec { uint64_t cursor_addr; unsigned long cursor_argb_addr; Bool cursor_is_argb; + int bpc; } I830CrtcPrivateRec, *I830CrtcPrivatePtr; #define I830CrtcPrivate(c) ((I830CrtcPrivatePtr) (c)->driver_private) @@ -340,6 +341,10 @@ enum last_3d { * BCM_KERNEL: use kernel methods for controlling the backlight * This is only available on some platforms, but where present this can * provide the best user experience. + * + * And, if you're in EL5, a fifth! + * BCM_IRONLAKE_NULL: just don't do anything and be quiet about it. This is + * a workaround for an RHGB interaction; you won't hit this at runtime. */ enum backlight_control { @@ -347,6 +352,7 @@ enum backlight_control { BCM_LEGACY, BCM_COMBO, BCM_KERNEL, + BCM_IRONLAKE_NULL }; typedef struct _I830Rec { @@ -640,6 +646,11 @@ typedef struct _I830Rec { /* ironlake vt restore hack */ xf86Int10InfoPtr int10; int int10Mode; + + /* spread spectrum clock frequency selection */ + CARD8 enable_ssc; + CARD8 ssc_freq; + } I830Rec; #define I830PTR(p) ((I830Ptr)((p)->driverPrivate)) diff --git a/src/i830_bios.c b/src/i830_bios.c index b7e69e12..bdfb2e4d 100644 --- a/src/i830_bios.c +++ b/src/i830_bios.c @@ -170,12 +170,18 @@ i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither) struct lvds_bdb_2 *lvds2; struct lvds_bdb_2_fp_params *fpparam; struct lvds_bdb_2_fp_edid_dtd *fptiming; + struct bdb_general_features *features; DisplayModePtr fixed_mode; CARD8 *timing_ptr; id = INTEL_BIOS_8(start); block_size = INTEL_BIOS_16(start + 1) + 3; switch (id) { + case 1: + features = (struct bdb_general_features *)(bios + start); + pI830->enable_ssc = features->enable_ssc; + pI830->ssc_freq = features->ssc_freq; + break; case 40: lvds1 = (struct lvds_bdb_1 *)(bios + start); panel_type = lvds1->panel_type; diff --git a/src/i830_bios.h b/src/i830_bios.h index 9e8356a1..71066a9b 100644 --- a/src/i830_bios.h +++ b/src/i830_bios.h @@ -130,6 +130,39 @@ struct aimdb_block { CARD16 aimdb_size; } __attribute__((packed)); +struct bdb_general_features { + CARD8 id; /* 1 */ + CARD16 size; + + /* bits 1 */ + CARD8 panel_fitting:2; + CARD8 flexaim:1; + CARD8 msg_enable:1; + CARD8 clear_screen:3; + CARD8 color_flip:1; + + /* bits 2 */ + CARD8 download_ext_vbt:1; + CARD8 enable_ssc:1; + CARD8 ssc_freq:1; + CARD8 enable_lfp_on_override:1; + CARD8 disable_ssc_ddt:1; + CARD8 rsvd8:3; /* finish byte */ + + /* bits 3 */ + CARD8 disable_smooth_vision:1; + CARD8 single_dvi:1; + CARD8 rsvd9:6; /* finish byte */ + + /* bits 4 */ + CARD8 legacy_monitor_detect; + + /* bits 5 */ + CARD8 int_crt_support:1; + CARD8 int_tv_support:1; + CARD8 rsvd11:6; /* finish byte */ +} __attribute__((packed)); + struct vch_panel_data { CARD16 fp_timing_offset; CARD8 fp_timing_size; diff --git a/src/i830_display.c b/src/i830_display.c index d6dfb4c2..287277dd 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -133,35 +133,81 @@ typedef struct { #define I9XX_P2_LVDS_FAST 7 #define I9XX_P2_LVDS_SLOW_LIMIT 112000 -#define IGDNG_DOT_MIN 25000 -#define IGDNG_DOT_MAX 350000 -#define IGDNG_VCO_MIN 1760000 -#define IGDNG_VCO_MAX 3510000 -#define IGDNG_N_MIN 1 -#define IGDNG_N_MAX 6 -#define IGDNG_M_MIN 79 -#define IGDNG_M_MAX 127 -#define IGDNG_M1_MIN 12 -#define IGDNG_M1_MAX 22 -#define IGDNG_M2_MIN 5 -#define IGDNG_M2_MAX 9 -#define IGDNG_P_SDVO_DAC_MIN 5 -#define IGDNG_P_SDVO_DAC_MAX 80 -#define IGDNG_P_LVDS_MIN 28 -#define IGDNG_P_LVDS_MAX 112 -#define IGDNG_P1_MIN 1 -#define IGDNG_P1_MAX 8 -#define IGDNG_P2_SDVO_DAC_SLOW 10 -#define IGDNG_P2_SDVO_DAC_FAST 5 -#define IGDNG_P2_LVDS_SLOW 14 /* single channel */ -#define IGDNG_P2_LVDS_FAST 7 /* double channel */ -#define IGDNG_P2_DOT_LIMIT 225000 /* 225Mhz */ +#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ +#define IRONLAKE_DOT_MIN 25000 +#define IRONLAKE_DOT_MAX 350000 +#define IRONLAKE_VCO_MIN 1760000 +#define IRONLAKE_VCO_MAX 3510000 +#define IRONLAKE_M1_MIN 12 +#define IRONLAKE_M1_MAX 22 +#define IRONLAKE_M2_MIN 5 +#define IRONLAKE_M2_MAX 9 #define INTEL_LIMIT_I8XX_DVO_DAC 0 #define INTEL_LIMIT_I8XX_LVDS 1 #define INTEL_LIMIT_I9XX_SDVO_DAC 2 #define INTEL_LIMIT_I9XX_LVDS 3 +/* DAC & HDMI Refclk 120Mhz */ +#define IRONLAKE_DAC_N_MIN 1 +#define IRONLAKE_DAC_N_MAX 5 +#define IRONLAKE_DAC_M_MIN 79 +#define IRONLAKE_DAC_M_MAX 127 +#define IRONLAKE_DAC_P_MIN 5 +#define IRONLAKE_DAC_P_MAX 80 +#define IRONLAKE_DAC_P1_MIN 1 +#define IRONLAKE_DAC_P1_MAX 8 +#define IRONLAKE_DAC_P2_SLOW 10 +#define IRONLAKE_DAC_P2_FAST 5 + +/* LVDS single-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_S_N_MIN 1 +#define IRONLAKE_LVDS_S_N_MAX 3 +#define IRONLAKE_LVDS_S_M_MIN 79 +#define IRONLAKE_LVDS_S_M_MAX 118 +#define IRONLAKE_LVDS_S_P_MIN 28 +#define IRONLAKE_LVDS_S_P_MAX 112 +#define IRONLAKE_LVDS_S_P1_MIN 2 +#define IRONLAKE_LVDS_S_P1_MAX 8 +#define IRONLAKE_LVDS_S_P2_SLOW 14 +#define IRONLAKE_LVDS_S_P2_FAST 14 + +/* LVDS dual-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_D_N_MIN 1 +#define IRONLAKE_LVDS_D_N_MAX 3 +#define IRONLAKE_LVDS_D_M_MIN 79 +#define IRONLAKE_LVDS_D_M_MAX 127 +#define IRONLAKE_LVDS_D_P_MIN 14 +#define IRONLAKE_LVDS_D_P_MAX 56 +#define IRONLAKE_LVDS_D_P1_MIN 2 +#define IRONLAKE_LVDS_D_P1_MAX 8 +#define IRONLAKE_LVDS_D_P2_SLOW 7 +#define IRONLAKE_LVDS_D_P2_FAST 7 + +/* LVDS single-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_S_SSC_N_MIN 1 +#define IRONLAKE_LVDS_S_SSC_N_MAX 2 +#define IRONLAKE_LVDS_S_SSC_M_MIN 79 +#define IRONLAKE_LVDS_S_SSC_M_MAX 126 +#define IRONLAKE_LVDS_S_SSC_P_MIN 28 +#define IRONLAKE_LVDS_S_SSC_P_MAX 112 +#define IRONLAKE_LVDS_S_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_S_SSC_P1_MAX 8 +#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14 +#define IRONLAKE_LVDS_S_SSC_P2_FAST 14 + +/* LVDS dual-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_D_SSC_N_MIN 1 +#define IRONLAKE_LVDS_D_SSC_N_MAX 3 +#define IRONLAKE_LVDS_D_SSC_M_MIN 79 +#define IRONLAKE_LVDS_D_SSC_M_MAX 126 +#define IRONLAKE_LVDS_D_SSC_P_MIN 14 +#define IRONLAKE_LVDS_D_SSC_P_MAX 42 +#define IRONLAKE_LVDS_D_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_D_SSC_P1_MAX 6 +#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7 +#define IRONLAKE_LVDS_D_SSC_P2_FAST 7 + static const intel_limit_t intel_limits[] = { { /* INTEL_LIMIT_I8XX_DVO_DAC */ .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, @@ -216,41 +262,102 @@ static const intel_limit_t intel_limits[] = { }, }; -static const intel_limit_t intel_limits_igdng_sdvo_dac = { - .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, - .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, - .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, - .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, - .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, - .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, - .p = { .min = IGDNG_P_SDVO_DAC_MIN, .max = IGDNG_P_SDVO_DAC_MAX }, - .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, - .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, - .p2_slow = IGDNG_P2_SDVO_DAC_SLOW, - .p2_fast = IGDNG_P2_SDVO_DAC_FAST }, +static const intel_limit_t intel_limits_ironlake_dac = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX }, + .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX }, + .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_DAC_P2_SLOW, + .p2_fast = IRONLAKE_DAC_P2_FAST }, +}; + +static const intel_limit_t intel_limits_ironlake_single_lvds = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_S_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_P2_FAST }, }; -static const intel_limit_t intel_limits_igdng_lvds = { - .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, - .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, - .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, - .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, - .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, - .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, - .p = { .min = IGDNG_P_LVDS_MIN, .max = IGDNG_P_LVDS_MAX }, - .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, - .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, - .p2_slow = IGDNG_P2_LVDS_SLOW, - .p2_fast = IGDNG_P2_LVDS_FAST }, +static const intel_limit_t intel_limits_ironlake_dual_lvds = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_D_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_P2_FAST }, }; +static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST }, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST }, +}; + + static const intel_limit_t *intel_igdng_limit(xf86CrtcPtr crtc) { + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); const intel_limit_t *limit; - if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) - limit = &intel_limits_igdng_lvds; - else - limit = &intel_limits_igdng_sdvo_dac; + + if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) { + int refclk = 120; + + if (pI830->enable_ssc && pI830->ssc_freq) + refclk = 100; + + if (INREG(PCH_LVDS) & LVDS_CLKB_POWER_MASK == LVDS_CLKB_POWER_UP) { + if (refclk == 100) + limit = &intel_limits_ironlake_dual_lvds_100m; + else + limit = &intel_limits_ironlake_dual_lvds; + } else { + if (refclk == 100) + limit = &intel_limits_ironlake_single_lvds_100m; + else + limit = &intel_limits_ironlake_single_lvds; + } + } else + limit = &intel_limits_ironlake_dac; return limit; } @@ -340,7 +447,10 @@ i830PipeHasType (xf86CrtcPtr crtc, int type) return FALSE; } +#if 1 #define i830PllInvalid(s) { /* ErrorF (s) */; return FALSE; } +#endif +#define i830PllInvalid(s) { ErrorF (s) ; return FALSE; } /** * Returns whether the given set of divisors are valid for a given refclk with * the given outputs. @@ -376,7 +486,7 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock) return TRUE; } - +/* HUAGLAHGLAHGLAH */ static Bool intel_igdng_find_best_PLL(const intel_limit_t *limit, xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_clock) @@ -384,8 +494,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, xf86CrtcPtr crtc, ScrnInfoPtr pScrn = crtc->scrn; I830Ptr pI830 = I830PTR(pScrn); intel_clock_t clock; - int err_most = 47; - int err_min = 10000; + int max_n; + Bool found = FALSE; + int err_most = (target >> 8) + (target >> 10); if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) { if ((INREG(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) @@ -400,34 +511,32 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, xf86CrtcPtr crtc, } memset(best_clock, 0, sizeof(*best_clock)); - for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { - /* based on hardware requriment prefer smaller n to precision */ - for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { - /* based on hardware requirment prefere larger m1,m2 */ - for (clock.m1 = limit->m1.max; - clock.m1 >= limit->m1.min; clock.m1--) { - for (clock.m2 = limit->m2.max; - clock.m2 >= limit->m2.min; clock.m2--) { + max_n = limit->n.max; + /* based on hardware requriment prefer smaller n to precision */ + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + /* based on hardware requirment prefere larger m1,m2 */ + for (clock.m1 = limit->m1.max; clock.m1 >= limit->m1.min; clock.m1--) { + for (clock.m2 = limit->m2.max; + clock.m2 >= limit->m2.min; clock.m2--) { + for (clock.p1 = limit->p1.max; + clock.p1 >= limit->p1.min; clock.p1--) { int this_err; intel_clock(pI830, refclk, &clock); if (!i830PllIsValid(crtc, &clock)) continue; - this_err = abs((10000 - (target*10000/clock.dot))); + this_err = abs(clock.dot - target) ; if (this_err < err_most) { *best_clock = clock; - /* found on first matching */ - goto out; - } else if (this_err < err_min) { - *best_clock = clock; - err_min = this_err; + err_most = this_err; + max_n = clock.n; + found = TRUE; } } } } } - out: - return TRUE; + return found; } /** @@ -873,10 +982,14 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; CARD32 temp; int tries = 5, i, j, n; + CARD32 pipe_bpc; if (intel_crtc->pipe != intel_crtc->plane) FatalError("pipe/plane mismatch, aborting\n"); + temp = INREG(pipeconf_reg); + pipe_bpc = temp & PIPE_BPC_MASK; + /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. */ @@ -885,6 +998,9 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) case DPMSModeStandby: case DPMSModeSuspend: + /* XXX no LVDS port force */ + + ErrorF("PCH DPLL enable\n"); /* enable PCH DPLL */ while (!((temp = INREG(pch_dpll_reg)) & DPLL_VCO_ENABLE)) { OUTREG(pch_dpll_reg, temp | DPLL_VCO_ENABLE); @@ -892,14 +1008,17 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(10); } + ErrorF("PCH FDI RX PLL enable\n"); /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ while (!((temp = INREG(fdi_rx_reg)) & FDI_RX_PLL_ENABLE)) { - temp &= (~FDI_DP_PORT_WIDTH_MASK); + temp &= (~FDI_DP_PORT_WIDTH_MASK | FDI_BPC_MASK); temp |= FDI_RX_PLL_ENABLE | FDI_SEL_PCDCLK | FDI_DP_PORT_WIDTH_X4; + temp |= (pipe_bpc << 11); OUTREG(fdi_rx_reg, temp); /* default 4 lanes */ usleep(200); } + ErrorF("PCH FDI TX PLL enable\n"); /* Enable CPU FDI TX PLL, always on for IGDNG */ while (!((temp = INREG(fdi_tx_reg)) & FDI_TX_PLL_ENABLE)) { temp &= (~FDI_DP_PORT_WIDTH_MASK); @@ -908,6 +1027,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(100); } + ErrorF("PFIT enable\n"); /* Enable panel fitting for LVDS */ for (i = 0; i < xf86_config->num_output; i++) { extern DisplayModePtr i830_lvds_panel_fixed_mode(xf86OutputPtr output); @@ -917,6 +1037,11 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) if (iout->type == I830_OUTPUT_LVDS) { DisplayModePtr mode = i830_lvds_panel_fixed_mode(output); temp = INREG(pf_ctl_reg); + + /* filter force */ + temp &= ~0x00c00000; + temp |= 0x00800000; + OUTREG(pf_ctl_reg, temp | PF_ENABLE); /* currently full aspect */ @@ -929,6 +1054,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } } + ErrorF("Pipe enable\n"); /* Enable CPU pipe */ while (!((temp = INREG(pipeconf_reg)) & PIPEACONF_ENABLE)) { OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE); @@ -936,6 +1062,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(100); } + ErrorF("Plane enable\n"); /* configure and enable CPU plane */ while (!((temp = INREG(dspcntr_reg)) & DISPLAY_PLANE_ENABLE)) { OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); @@ -948,6 +1075,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) /* Train FDI. */ + ErrorF("FDI TX enable\n"); /* enable CPU FDI TX and PCH FDI RX */ while (!((temp = INREG(fdi_tx_reg)) & FDI_TX_ENABLE)) { temp |= FDI_TX_ENABLE; @@ -958,6 +1086,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(10); } + ErrorF("FDI RX enable\n"); while (!((temp = INREG(fdi_rx_reg)) & FDI_RX_ENABLE)) { temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; @@ -967,6 +1096,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(150); + ErrorF("FDI link train 1 start\n"); /* unmask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ while ((temp = INREG(fdi_rx_imr_reg)) & @@ -976,6 +1106,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(150); } + ErrorF("FDI link train 1 wait\n"); for (j = 0; j < tries; j++) { temp = INREG(fdi_rx_iir_reg); if (temp & FDI_RX_BIT_LOCK) @@ -985,6 +1116,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) if (j == tries) xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "train 1 failed\n"); + ErrorF("FDI link train 2 start TX\n"); while (!((temp = INREG(fdi_tx_reg)) & FDI_LINK_TRAIN_PATTERN_2)) { temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; @@ -992,6 +1124,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(10); } + ErrorF("FDI link train 2 start TX\n"); while (!((temp = INREG(fdi_rx_reg)) & FDI_LINK_TRAIN_PATTERN_2)) { temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; @@ -1001,6 +1134,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(500); + ErrorF("FDI link train 2 wait\n"); for (j = 0; j < tries; j++) { temp = INREG(fdi_rx_iir_reg); if (temp & FDI_RX_SYMBOL_LOCK) @@ -1012,6 +1146,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(500); + ErrorF("transcoder timing\n"); /* set transcoder timing */ OUTREG(trans_htot_reg, INREG(cpu_htot_reg)); OUTREG(trans_hblank_reg, INREG(cpu_hblank_reg)); @@ -1023,6 +1158,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) /* enable normal */ + ErrorF("FDI TX link normal\n"); while (((temp = INREG(fdi_tx_reg)) & FDI_LINK_TRAIN_NONE) != FDI_LINK_TRAIN_NONE) { temp &= ~FDI_LINK_TRAIN_NONE; OUTREG(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | @@ -1030,6 +1166,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(10); } + ErrorF("FDI RX link normal\n"); while (((temp = INREG(fdi_rx_reg)) & FDI_LINK_TRAIN_NONE) != FDI_LINK_TRAIN_NONE) { temp &= ~FDI_LINK_TRAIN_NONE; OUTREG(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | @@ -1039,14 +1176,18 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(500); + ErrorF("transcoder enable\n"); /* enable transcoder */ n = 0; while (!((temp = INREG(transconf_reg)) & TRANS_STATE_ENABLE)) { + temp |= TRANS_ENABLE; + temp &= ~FDI_BPC_MASK; + temp |= pipe_bpc; OUTREG(transconf_reg, temp | TRANS_ENABLE); n++; usleep(500); if (n > 20) { - ErrorF("aborting transcoder enable\n"); + ErrorF("aborting transcoder %x enable\n", transconf_reg); break; } } @@ -1054,11 +1195,15 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) /* wait one idle pattern time */ usleep(100); + ErrorF("LUT load\n"); i830_crtc_load_lut(crtc); + ErrorF("DPMS on done\n"); + break; case DPMSModeOff: + ErrorF("Plane disable\n"); /* Disable display plane */ while ((temp = INREG(dspcntr_reg)) & DISPLAY_PLANE_ENABLE) { OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); @@ -1069,6 +1214,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } i830_disable_vga_plane (crtc); + ErrorF("Pipe disable\n"); /* disable cpu pipe, disable after all planes disabled */ temp = INREG(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { @@ -1088,6 +1234,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } } + ErrorF("PFIT disable\n"); /* Disable PF */ while ((temp = INREG(pf_ctl_reg)) & PF_ENABLE) { OUTREG(pf_ctl_reg, temp & ~PF_ENABLE); @@ -1095,12 +1242,14 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } OUTREG(pf_win_size, 0); + ErrorF("FDI TX disable\n"); /* disable CPU FDI tx and PCH FDI rx */ while ((temp = INREG(fdi_tx_reg)) & FDI_TX_ENABLE) { OUTREG(fdi_tx_reg, temp & ~FDI_TX_ENABLE); usleep(10); } + ErrorF("FDI RX disable\n"); while ((temp = INREG(fdi_rx_reg)) & FDI_RX_ENABLE) { OUTREG(fdi_rx_reg, temp & ~FDI_RX_ENABLE); usleep(10); @@ -1108,12 +1257,14 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(100); + ErrorF("FDI TX train 1 preload\n"); /* still set train pattern 1 */ temp = INREG(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; OUTREG(fdi_tx_reg, temp); + ErrorF("FDI RX train 1 preload\n"); temp = INREG(fdi_rx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; @@ -1121,6 +1272,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) usleep(100); + ErrorF("LVDS port force off\n"); if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) { while ((temp = INREG(PCH_LVDS)) & PORT_ENABLE) { OUTREG(PCH_LVDS, temp & ~PORT_ENABLE); @@ -1128,6 +1280,7 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } } + ErrorF("Transcoder disable\n"); /* disable PCH transcoder */ temp = INREG(transconf_reg); if ((temp & TRANS_STATE_ENABLE) != 0) { @@ -1147,24 +1300,34 @@ static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode) } } + ErrorF("PCH DPLL disable\n"); /* disable PCH DPLL */ while ((temp = INREG(pch_dpll_reg)) & DPLL_VCO_ENABLE) { OUTREG(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); usleep(10); } - while ((temp = INREG(fdi_rx_reg)) & FDI_RX_PLL_ENABLE) { + ErrorF("FDI RX PLL PCD disable\n"); + while ((temp = INREG(fdi_rx_reg)) & FDI_SEL_PCDCLK) { temp &= ~FDI_SEL_PCDCLK; + OUTREG(fdi_rx_reg, temp); + usleep(10); + } + + ErrorF("FDI RX PLL disable\n"); + while ((temp = INREG(fdi_rx_reg)) & FDI_RX_PLL_ENABLE) { temp &= ~FDI_RX_PLL_ENABLE; OUTREG(fdi_rx_reg, temp); usleep(10); } + ErrorF("FDI TX PLL disable\n"); while ((temp = INREG(fdi_tx_reg)) & FDI_RX_PLL_ENABLE) { OUTREG(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); usleep(10); } + ErrorF("DPMS off done\n"); /* Wait for the clocks to turn off. */ usleep(150); @@ -1620,6 +1783,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, switch (intel_output->type) { case I830_OUTPUT_LVDS: + ErrorF("is lvds\n"); is_lvds = TRUE; break; case I830_OUTPUT_SDVO: @@ -1635,6 +1799,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, is_tv = TRUE; break; case I830_OUTPUT_ANALOG: + ErrorF("is crt\n"); is_crt = TRUE; break; } @@ -1661,18 +1826,36 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, } if (IS_IGDNG(pI830)) { - int bpc = 24; + int bpp = 24; if (is_lvds) { CARD32 lvds_reg = INREG(PCH_LVDS); if (!((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)) - bpc = 18; + bpp = 18; } - igdng_compute_m_n(bpc, 4, /* lane num 4 */ + igdng_compute_m_n(bpp, 4, /* lane num 4 */ adjusted_mode->Clock, 270000, /* lane clock */ &m_n); + ErrorF("bpp %d\n", bpp / 3); + intel_crtc->bpc = bpp / 3; + } + + if (IS_IGDNG(pI830)) { + CARD32 temp; + + temp = INREG(PCH_DREF_CONTROL); + /* Always enable nonspread source */ + temp &= ~DREF_NONSPREAD_SOURCE_MASK; + temp |= DREF_NONSPREAD_SOURCE_ENABLE; + OUTREG(PCH_DREF_CONTROL, temp); + temp = INREG(PCH_DREF_CONTROL); + + temp &= ~DREF_SSC_SOURCE_MASK; + temp |= DREF_SSC_SOURCE_ENABLE; + OUTREG(PCH_DREF_CONTROL, temp); + temp = INREG(PCH_DREF_CONTROL); } fp = clock.n << 16 | clock.m1 << 8 | clock.m2; @@ -1789,6 +1972,14 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, else pipeconf &= ~PIPEACONF_DOUBLE_WIDE; } + + if (IS_IGDNG(pI830)) { + if (intel_crtc->bpc == 6) + pipeconf |= (1 << 6); /* 0 is 8bpc */ + if (intel_crtc->bpc != 8) + pipeconf |= (1 << 4); /* enable dithering */ + } + /* * This "shouldn't" be needed as the dpms on code * will be run after the mode is set. On 9xx, it helps. diff --git a/src/i830_lvds.c b/src/i830_lvds.c index 4fb83b59..4d9cb6be 100644 --- a/src/i830_lvds.c +++ b/src/i830_lvds.c @@ -122,6 +122,8 @@ i830_set_lvds_backlight_method(xf86OutputPtr output) if (i830_kernel_backlight_available(output)) { method = BCM_KERNEL; + } else if (IS_IGDNG(pI830)) { + method = BCM_IRONLAKE_NULL; } else if (IS_I965GM(pI830) || IS_GM45(pI830)) { blc_pwm_ctl2 = INREG(BLC_PWM_CTL2); if (blc_pwm_ctl2 & BLM_LEGACY_MODE2) @@ -288,6 +290,18 @@ i830_lvds_get_backlight_max_combo(xf86OutputPtr output) return i830_lvds_get_backlight_max_native(output) >> 1; } +/* null methods */ +static int +i830_lvds_get_backlight_null(xf86OutputPtr output) +{ + return 1; +} + +static void +i830_lvds_set_backlight_null(xf86OutputPtr output) +{ +} + /* * Kernel methods */ @@ -792,12 +806,13 @@ static Atom backlight_atom; * or not at all. */ #define BACKLIGHT_CONTROL_NAME "BACKLIGHT_CONTROL" -#define NUM_BACKLIGHT_CONTROL_METHODS 4 +#define NUM_BACKLIGHT_CONTROL_METHODS 5 static char *backlight_control_names[] = { "native", "legacy", "combination", "kernel", + "null", }; static Atom backlight_control_atom; static Atom backlight_control_name_atoms[NUM_BACKLIGHT_CONTROL_METHODS]; @@ -846,6 +861,11 @@ i830_lvds_set_backlight_control(xf86OutputPtr output) dev_priv->backlight_max = i830_lvds_get_backlight_max_kernel(output); break; + case BCM_IRONLAKE_NULL: + dev_priv->set_backlight = i830_lvds_set_backlight_null; + dev_priv->get_backlight = i830_lvds_get_backlight_null; + dev_priv->backlight_max = 1; + break; default: /* * Should be impossible to get here unless the caller set a bogus @@ -1050,7 +1070,7 @@ i830_lvds_init(ScrnInfoPtr pScrn) } intel_output->type = I830_OUTPUT_LVDS; intel_output->pipe_mask = (1 << 1); - if (IS_IGDNG(pI830)) + if (0 && IS_IGDNG(pI830)) /* XXX put me back */ intel_output->pipe_mask |= (1 << 0); intel_output->clone_mask = (1 << I830_OUTPUT_LVDS); @@ -1196,6 +1216,11 @@ i830_lvds_init(ScrnInfoPtr pScrn) dev_priv->get_backlight = i830_lvds_get_backlight_kernel; dev_priv->backlight_max = i830_lvds_get_backlight_max_kernel(output); break; + case BCM_IRONLAKE_NULL: + dev_priv->set_backlight = i830_lvds_set_backlight_null; + dev_priv->get_backlight = i830_lvds_get_backlight_null; + dev_priv->backlight_max = 1; + break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "bad backlight control method\n"); break; |