summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@airlied-rhel5.(none)>2010-04-21 11:07:56 +1000
committerDave Airlie <airlied@airlied-rhel5.(none)>2010-05-27 14:53:15 +1000
commit0fa5031c838fd11cc8462f8786d9f0e8bb8ebc7b (patch)
tree9d96058a8d1821757d9b1979fded0c945a351a02
parent74631582089f4eaf1916008d649ba1e90319622f (diff)
wip.patch
-rw-r--r--src/i810_reg.h7
-rw-r--r--src/i830.h11
-rw-r--r--src/i830_bios.c6
-rw-r--r--src/i830_bios.h33
-rw-r--r--src/i830_display.c343
-rw-r--r--src/i830_lvds.c29
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)
diff --git a/src/i830.h b/src/i830.h
index 4ec02ab1..2f8a44c1 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -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;