summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain G. Ainsworth <oga@openbsd.org>2010-05-29 14:50:40 +0100
committerOwain G. Ainsworth <oga@openbsd.org>2010-06-07 21:49:21 +0100
commit1b8b09896bb8e052fb2c045a28d1488d6950a7d6 (patch)
treed9664fb1c2a1a410a6d95a646856a719994d8ec1
parent7098b4c93e80a11e2b44134c9771b4dfaeca2b34 (diff)
Initial Ironlake support
VGA works. LVDS is still screwy. panel fitting hasn't been messed with (yet). Mostly from RHEL5's 2.2.1 branch, courtesy of airlied.
-rw-r--r--src/i810_reg.h62
-rw-r--r--src/i830.h12
-rw-r--r--src/i830_crt.c86
-rw-r--r--src/i830_display.c887
-rw-r--r--src/i830_driver.c71
-rw-r--r--src/i830_hdmi.c52
-rw-r--r--src/i830_lvds.c164
7 files changed, 1262 insertions, 72 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 191ddb2a..9f78eb1d 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -2214,6 +2214,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
@@ -2350,6 +2356,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* IGDNG */
#define DISPPLANE_X_TILE (1<<10)
#define DISPPLANE_LINEAR (0<<10)
+#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14)
#define DSPABASE 0x70184
/* IGDNG */
@@ -3067,6 +3074,10 @@ typedef enum {
#define PFA_CTL_1 0x68080
#define PFB_CTL_1 0x68880
#define PF_ENABLE (1<<31)
+#define PFA_WIN_SZ 0x68074
+#define PFB_WIN_SZ 0x68874
+#define PFA_WIN_POS 0x68070
+#define PFB_WIN_POS 0x68870
#define PFA_WIN_POS 0x68070
#define PFB_WIN_POS 0x68870
@@ -3118,6 +3129,10 @@ typedef enum {
#define GTIIR 0x44018
#define GTIER 0x4401c
+
+#define DISP_ARB_CTL 0x45000
+#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
+
/* PCH */
/* south display engine interrupt */
@@ -3189,8 +3204,11 @@ typedef enum {
#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13)
#define DREF_SSC_SOURCE_DISABLE (0<<11)
#define DREF_SSC_SOURCE_ENABLE (2<<11)
+#define DREF_SSC_SOURCE_MASK (2<<11)
#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9)
+#define DREF_NONSPREAD_CK505_ENABLE (1<<9)
#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9)
+#define DREF_NONSPREAD_SOURCE_MASK (2<<9)
#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7)
#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7)
#define DREF_SSC4_DOWNSPREAD (0<<6)
@@ -3302,6 +3320,7 @@ typedef enum {
#define FDI_DP_PORT_WIDTH_X2 (1<<19)
#define FDI_DP_PORT_WIDTH_X3 (2<<19)
#define FDI_DP_PORT_WIDTH_X4 (3<<19)
+#define FDI_DP_PORT_WIDTH_MASK (7<<19)
#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
/* IGDNG: hardwired to 1 */
#define FDI_TX_PLL_ENABLE (1<<14)
@@ -3320,6 +3339,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)
@@ -3406,6 +3426,48 @@ typedef enum {
#define HDMIC 0xe1150
#define HDMID 0xe1160
#define PCH_LVDS 0xe1180
+#define LVDS_DETECTED (1 << 1)
+
+#define PCH_DP_B 0xe4100
+#define PCH_DP_C 0xe4200
+#define PCH_DP_D 0xe4200
+
+#define BLC_PWM_CPU_CTL2 0x48250
+#define PWM_ENABLE (1 << 31)
+#define PWM_PIPE_A (0 << 29)
+#define PWM_PIPE_B (1 << 29)
+#define BLC_PWM_CPU_CTL 0x48254
+
+#define BLC_PWM_PCH_CTL1 0xc8250
+#define PWM_PCH_ENABLE (1 << 31)
+#define PWM_POLARITY_ACTIVE_LOW (1 << 29)
+#define PWM_POLARITY_ACTIVE_HIGH (0 << 29)
+#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28)
+#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28)
+
+#define BLC_PWM_PCH_CTL2 0xc8254
+
+#define PCH_PP_STATUS 0xc7200
+#define PCH_PP_CONTROL 0xc7204
+#define EDP_FORCE_VDD (1 << 3)
+#define EDP_BLC_ENABLE (1 << 2)
+#define PANEL_POWER_RESET (1 << 1)
+#define PANEL_POWER_OFF (0 << 0)
+#define PANEL_POWER_ON (1 << 0)
+#define PCH_PP_ON_DELAYS 0xc7208
+#define EDP_PANEL (1 << 30)
+#define PCH_PP_OFF_DELAYS 0xc720c
+#define PCH_PP_DIVISOR 0xc7210
+
+#define DE_POWER1 0x42400
+#define WM0_PIPE_A 0x45100
+#define WM0_PIPE_B 0x45104
+#define WM1 0x45108
+#define WM2 0x4510C
+#define WM3 0x45110
+#define WM1S 0x45120
+
+
#define AUD_CONFIG 0x62000
#define AUD_DEBUG 0x62010
diff --git a/src/i830.h b/src/i830.h
index 6e4d5528..5ca4d514 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -58,6 +58,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "xf86Crtc.h"
#include "xf86RandR12.h"
+#include "xf86int10.h"
+
#include "xorg-server.h"
#include <pciaccess.h>
@@ -328,6 +330,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)
@@ -398,6 +401,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 {
@@ -405,6 +412,7 @@ enum backlight_control {
BCM_LEGACY,
BCM_COMBO,
BCM_KERNEL,
+ BCM_IRONLAKE_NULL
};
enum dri_type {
@@ -720,6 +728,10 @@ typedef struct intel_screen_private {
Bool fallback_debug;
struct sdvo_device_mapping sdvo_mappings[2];
unsigned debug_flush;
+
+ /* ironlake vt restore hack */
+ xf86Int10InfoPtr int10;
+ int int10Mode;
} intel_screen_private;
enum {
diff --git a/src/i830_crt.c b/src/i830_crt.c
index e2e3694b..26c9d412 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -29,6 +29,8 @@
#include "config.h"
#endif
+#include <unistd.h>
+
#include "xf86.h"
#include "i830.h"
#include "xf86Modes.h"
@@ -39,9 +41,14 @@ i830_crt_dpms(xf86OutputPtr output, int mode)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
- uint32_t temp;
+ uint32_t temp, reg;
+
+ if (IS_IGDNG(intel))
+ reg = PCH_ADPA;
+ else
+ reg = ADPA;
- temp = INREG(ADPA);
+ temp = INREG(reg);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
@@ -60,7 +67,7 @@ i830_crt_dpms(xf86OutputPtr output, int mode)
break;
}
- OUTREG(ADPA, temp);
+ OUTREG(reg, temp);
}
static void
@@ -68,8 +75,9 @@ i830_crt_save (xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t reg = IS_IGDNG(intel) ? PCH_ADPA : ADPA;
- intel->saveADPA = INREG(ADPA);
+ intel->saveADPA = INREG(reg);
}
static void
@@ -77,8 +85,9 @@ i830_crt_restore (xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t reg = IS_IGDNG(intel) ? PCH_ADPA : ADPA;
- OUTREG(ADPA, intel->saveADPA);
+ OUTREG(reg, intel->saveADPA);
}
static int
@@ -122,16 +131,23 @@ i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode,
I830CrtcPrivatePtr i830_crtc = crtc->driver_private;
int dpll_md_reg;
uint32_t adpa, dpll_md;
+ uint32_t adpa_reg;
if (i830_crtc->pipe == 0)
dpll_md_reg = DPLL_A_MD;
else
dpll_md_reg = DPLL_B_MD;
+
+ if (IS_IGDNG(intel))
+ adpa_reg = PCH_ADPA;
+ else
+ adpa_reg = ADPA;
+
/*
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
*/
- if (IS_I965G(intel))
+ if (IS_I965G(intel) && !IS_IGDNG(intel))
{
dpll_md = INREG(dpll_md_reg);
OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -146,15 +162,55 @@ i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode,
if (i830_crtc->pipe == 0)
{
adpa |= ADPA_PIPE_A_SELECT;
- OUTREG(BCLRPAT_A, 0);
+ if (!IS_IGDNG(intel))
+ OUTREG(BCLRPAT_A, 0);
}
else
{
adpa |= ADPA_PIPE_B_SELECT;
- OUTREG(BCLRPAT_B, 0);
+ if (!IS_IGDNG(intel))
+ OUTREG(BCLRPAT_B, 0);
}
- OUTREG(ADPA, adpa);
+ OUTREG(adpa_reg, adpa);
+}
+
+static Bool intel_igdng_crt_detect_hotplug(xf86OutputPtr output)
+{
+ ScrnInfoPtr scrn = output->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t adpa;
+ Bool ret;
+
+ adpa = INREG(PCH_ADPA);
+
+ adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+
+ adpa |= (ADPA_CRT_HOTPLUG_PERIOD_64 |
+ ADPA_CRT_HOTPLUG_WARMUP_5MS |
+ ADPA_CRT_HOTPLUG_SAMPLE_2S |
+ ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
+ ADPA_CRT_HOTPLUG_VOLREF_325MV);
+ OUTREG(PCH_ADPA, adpa);
+
+ usleep(6000); /* warmup */
+
+ adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+
+ OUTREG(PCH_ADPA, adpa);
+
+ while (INREG(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER)
+ ;
+
+ /* Check the status to see if both blue and green are on now */
+ adpa = INREG(PCH_ADPA) & ADPA_CRT_HOTPLUG_MONITOR_MASK;
+ if (adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR ||
+ adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ return ret;
}
/**
@@ -176,6 +232,9 @@ i830_crt_detect_hotplug(xf86OutputPtr output)
int tries = 1;
int try;
+ if (IS_IGDNG(intel))
+ return intel_igdng_crt_detect_hotplug(output);
+
/* On 4 series desktop, CRT detect sequence need to be done twice
* to get a reliable result. */
if (IS_G4X(intel) && !IS_GM45(intel))
@@ -459,11 +518,18 @@ i830_crt_get_crtc(xf86OutputPtr output)
static xf86MonPtr
i830_get_edid(xf86OutputPtr output, int gpio_reg, char *gpio_str)
{
+ ScrnInfoPtr scrn = output->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
I830OutputPrivatePtr intel_output = output->driver_private;
xf86MonPtr edid_mon = NULL;
+ uint32_t i2c_reg;
/* Set up the DDC bus. */
- I830I2CInit(output->scrn, &intel_output->pDDCBus, gpio_reg, gpio_str);
+ if (IS_IGDNG(intel))
+ i2c_reg = PCH_GPIOA;
+ else
+ i2c_reg = GPIOA;
+ I830I2CInit(scrn, &intel_output->pDDCBus, i2c_reg, "CRTDDC_A");
edid_mon = xf86OutputGetEDID (output, intel_output->pDDCBus);
diff --git a/src/i830_display.c b/src/i830_display.c
index 736ed043..fc7dceb6 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -42,6 +42,7 @@
#include "i830_bios.h"
#include "i830_display.h"
#include "xf86Modes.h"
+#include "i810_reg.h"
typedef struct {
/* given values */
@@ -149,6 +150,16 @@ struct intel_limit {
#define I9XX_P2_LVDS_FAST 7
#define I9XX_P2_LVDS_SLOW_LIMIT 112000
+#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
@@ -238,12 +249,75 @@ struct intel_limit {
#define G4X_P2_DUAL_LVDS_FAST 7
#define G4X_P2_DUAL_LVDS_LIMIT 0
+/* 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 Bool
intel_find_pll_i8xx_and_i9xx(const intel_limit_t *, xf86CrtcPtr,
int, int, intel_clock_t *);
static Bool
intel_find_pll_g4x(const intel_limit_t *, xf86CrtcPtr,
int, int, intel_clock_t *);
+static Bool
+intel_igdng_find_best_PLL(const intel_limit_t *, xf86CrtcPtr,
+ int, int, intel_clock_t *);
static void
i830_crtc_load_lut(xf86CrtcPtr crtc);
@@ -405,6 +479,112 @@ static const intel_limit_t intel_limits[] = {
},
};
+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 },
+ .find_pll = intel_igdng_find_best_PLL,
+};
+
+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 },
+ .find_pll = intel_igdng_find_best_PLL,
+};
+
+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 },
+ .find_pll = intel_igdng_find_best_PLL,
+};
+
+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 },
+ .find_pll = intel_igdng_find_best_PLL,
+};
+
+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 },
+ .find_pll = intel_igdng_find_best_PLL,
+};
+
+
+static const intel_limit_t *intel_igdng_limit(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ const intel_limit_t *limit;
+
+ if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) {
+ int refclk = 120;
+
+ if (intel->lvds_use_ssc && intel->lvds_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;
+}
+
+
static const intel_limit_t *intel_limit_g4x (xf86CrtcPtr crtc)
{
ScrnInfoPtr scrn = crtc->scrn;
@@ -433,7 +613,9 @@ static const intel_limit_t *intel_limit (xf86CrtcPtr crtc)
intel_screen_private *intel = intel_get_screen_private(scrn);
const intel_limit_t *limit;
- if (IS_G4X(intel)) {
+ if (IS_IGDNG(intel)) {
+ limit = intel_igdng_limit(crtc);
+ } else if (IS_G4X(intel)) {
limit = intel_limit_g4x(crtc);
} else if (IS_I9XX(intel) && !IS_IGD(intel)) {
if (i830PipeHasType (crtc, I830_OUTPUT_LVDS))
@@ -507,6 +689,61 @@ i830PrintPll(ScrnInfoPtr scrn, char *prefix, intel_clock_t *clock)
clock->p, clock->p1, clock->p2);
}
+static Bool
+i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock);
+
+static Bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, xf86CrtcPtr crtc,
+ int target, int refclk, intel_clock_t *best_clock)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ intel_clock_t clock;
+ 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)
+ clock.p2 = limit->p2.p2_fast;
+ else
+ clock.p2 = limit->p2.p2_slow;
+ } else {
+ 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));
+ 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(intel, refclk, &clock);
+ if (!i830PllIsValid(crtc, &clock))
+ continue;
+ this_err = abs(clock.dot - target) ;
+ if (this_err < err_most) {
+ *best_clock = clock;
+ err_most = this_err;
+ max_n = clock.n;
+ found = TRUE;
+ }
+ }
+ }
+ }
+ }
+ return found;
+}
+
/**
* Returns whether any output on the specified pipe is of the specified type
*/
@@ -530,7 +767,12 @@ i830PipeHasType (xf86CrtcPtr crtc, int type)
return FALSE;
}
+#if 0
+#if 1
#define i830PllInvalid(s) { /* ErrorF (s) */; return FALSE; }
+#endif
+#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.
@@ -770,6 +1012,7 @@ Bool
i830_pipe_a_require_activate (ScrnInfoPtr scrn)
{
xf86CrtcPtr crtc = i830_crtc_for_pipe (scrn, 0);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
/* VESA 640x480x72Hz mode to set on the pipe */
static DisplayModeRec mode = {
NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT,
@@ -783,6 +1026,9 @@ i830_pipe_a_require_activate (ScrnInfoPtr scrn)
FALSE, FALSE, 0, NULL, 0, 0.0, 0.0
};
+ if (IS_IGDNG(intel))
+ return FALSE;
+
if (!crtc)
return FALSE;
if (crtc->enabled)
@@ -1076,6 +1322,16 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
ScrnInfoPtr scrn = crtc->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
uint8_t sr01;
+ uint32_t vga_reg, vgacntrl;
+
+ if (IS_IGDNG(intel))
+ vga_reg = CPU_VGACNTRL;
+ else
+ vga_reg = VGACNTRL;
+
+ vgacntrl = INREG(vga_reg);
+ if (vgacntrl & VGA_DISP_DISABLE)
+ return;
/*
* Bug #17235: G4X machine needs following steps
@@ -1092,8 +1348,11 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
usleep(30);
}
- OUTREG(VGACNTRL, VGA_DISP_DISABLE);
- i830WaitForVblank(scrn);
+ while (!(INREG(vga_reg) & VGA_DISP_DISABLE)) {
+ vgacntrl |= VGA_DISP_DISABLE;
+ OUTREG(vga_reg, vgacntrl);
+ i830WaitForVblank(scrn);
+ }
/* restore SR01 */
if (IS_G4X(intel)) {
@@ -1230,6 +1489,396 @@ i830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe)
i830_disable_vga_plane (crtc);
}
+static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+ int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
+ int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
+ int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+ int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+ int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+ int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+ int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
+ int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
+ int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
+ int pf_win_pos = (pipe == 0) ? PFA_WIN_POS : PFB_WIN_POS;
+ int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+ int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+ int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+ int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+ int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+ int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+ int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
+ int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
+ int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
+ int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
+ int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
+ int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
+ uint32_t temp;
+ int tries = 5, i, j, n;
+ uint32_t 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.
+ */
+ switch (mode) {
+ case DPMSModeOn:
+ 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);
+ INREG(pch_dpll_reg);
+ 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 | 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);
+ temp |= FDI_TX_PLL_ENABLE | FDI_DP_PORT_WIDTH_X4;
+ OUTREG(fdi_tx_reg, temp);
+ usleep(100);
+ }
+
+#if 0
+ 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);
+ xf86OutputPtr output = xf86_config->output[i];
+ if (output->crtc == crtc) {
+ I830OutputPrivatePtr iout = output->driver_private;
+ 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 */
+ OUTREG(pf_win_pos, 0);
+
+ OUTREG(pf_win_size, (mode->HDisplay << 16) |
+ (mode->VDisplay));
+ break;
+ }
+ }
+ }
+#endif
+
+ ErrorF("Pipe enable\n");
+ /* Enable CPU pipe */
+ while (!((temp = INREG(pipeconf_reg)) & PIPEACONF_ENABLE)) {
+ OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ INREG(pipeconf_reg);
+ 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);
+ /* Flush the plane changes */
+ OUTREG(dspbase_reg, INREG(dspbase_reg));
+ usleep(10);
+ }
+ /* twice, like the BIOS */
+ OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+
+ /* 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;
+ temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ OUTREG(fdi_tx_reg, temp);
+ 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;
+ OUTREG(fdi_rx_reg, temp | FDI_RX_ENABLE);
+ usleep(10);
+ }
+
+ 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)) &
+ (FDI_RX_SYMBOL_LOCK|FDI_RX_BIT_LOCK)) {
+ temp &= ~(FDI_RX_SYMBOL_LOCK | FDI_RX_BIT_LOCK);
+ OUTREG(fdi_rx_imr_reg, temp);
+ 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)
+ break;
+ usleep(200);
+ }
+ if (j == tries)
+ xf86DrvMsg(scrn->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;
+ OUTREG(fdi_tx_reg, temp);
+ 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;
+ OUTREG(fdi_rx_reg, temp);
+ usleep(10);
+ }
+
+ 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)
+ break;
+ usleep(200);
+ }
+ if (j == tries)
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "train 2 failed\n");
+
+ 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));
+ OUTREG(trans_hsync_reg, INREG(cpu_hsync_reg));
+
+ OUTREG(trans_vtot_reg, INREG(cpu_vtot_reg));
+ OUTREG(trans_vblank_reg, INREG(cpu_vblank_reg));
+ OUTREG(trans_vsync_reg, INREG(cpu_vsync_reg));
+
+ /* 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 |
+ FDI_TX_ENHANCE_FRAME_ENABLE);
+ 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 |
+ FDI_RX_ENHANCE_FRAME_ENABLE);
+ usleep(10);
+ }
+
+ 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 %x enable\n", transconf_reg);
+ break;
+ }
+ }
+
+ /* 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);
+ /* Flush the plane changes */
+ OUTREG(dspbase_reg, INREG(dspbase_reg));
+ INREG(dspbase_reg);
+ usleep(10);
+ }
+ 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) {
+ OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+ INREG(pipeconf_reg);
+ n = 0;
+ /* wait for cpu pipe off, pipe state */
+ while ((INREG(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
+ n++;
+ if (n < 60) {
+ usleep(5000);
+ continue;
+ } else {
+ ErrorF("aborting pipeconf disable early\n");
+ break;
+ }
+ }
+ }
+
+ ErrorF("PFIT disable\n");
+ /* Disable PF */
+ while ((temp = INREG(pf_ctl_reg)) & PF_ENABLE) {
+ OUTREG(pf_ctl_reg, temp & ~PF_ENABLE);
+ usleep(10);
+ }
+ 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);
+ }
+
+ 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;
+ OUTREG(fdi_rx_reg, temp);
+
+ 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);
+ usleep(100);
+ }
+ }
+
+ ErrorF("Transcoder disable\n");
+ /* disable PCH transcoder */
+ temp = INREG(transconf_reg);
+ if ((temp & TRANS_STATE_ENABLE) != 0) {
+ OUTREG(transconf_reg, temp & ~TRANS_ENABLE);
+ INREG(transconf_reg);
+ n = 0;
+ /* wait for PCH transcoder off, transcoder state */
+ while ((INREG(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
+ n++;
+ if (n < 600) {
+ usleep(500);
+ continue;
+ } else {
+ ErrorF("aborting transcoder disable early, 0x%08x\n", INREG(transconf_reg));
+ break;
+ }
+ }
+ }
+
+ 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);
+ }
+
+ 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);
+
+ break;
+ }
+}
+
/**
* Sets the power management mode of the pipe and plane.
*
@@ -1237,7 +1886,7 @@ i830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe)
* on appropriately at the same time as we're turning the pipe off/on.
*/
static void
-i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+i9xx_crtc_dpms(xf86CrtcPtr crtc, int mode)
{
ScrnInfoPtr scrn = crtc->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
@@ -1261,6 +1910,19 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
intel_crtc->enabled = FALSE;
break;
}
+}
+
+static void
+i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (IS_IGDNG(intel))
+ igdng_crtc_dpms(crtc, mode);
+ else
+ i9xx_crtc_dpms(crtc, mode);
intel_crtc->dpms_mode = mode;
}
@@ -1331,6 +1993,15 @@ static Bool
i830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (IS_IGDNG(intel)) {
+ /* FDI link clock is fixed at 2.7G */
+ if (mode->Clock * 3 > 27000 * 4)
+ return MODE_CLOCK_HIGH;
+ }
+
return TRUE;
}
@@ -1479,6 +2150,48 @@ i830_update_dsparb(ScrnInfoPtr scrn)
OUTREG(DSPARB, planea_entries << DSPARB_AEND_SHIFT);
}
+struct fdi_m_n {
+ CARD32 tu;
+ CARD32 gmch_m;
+ CARD32 gmch_n;
+ CARD32 link_m;
+ CARD32 link_n;
+};
+
+static void
+fdi_reduce_ratio(CARD32 *num, CARD32 *den)
+{
+ while (*num > 0xffffff || *den > 0xffffff) {
+ *num >>= 1;
+ *den >>= 1;
+ }
+}
+
+#define DATA_N 0x800000
+#define LINK_N 0x80000
+
+static void
+igdng_compute_m_n(int bits_per_pixel, int nlanes,
+ int pixel_clock, int link_clock,
+ struct fdi_m_n *m_n)
+{
+ uint64_t temp;
+
+ m_n->tu = 64; /* default size */
+
+ temp = (uint64_t) DATA_N * pixel_clock;
+ temp = temp / link_clock;
+ m_n->gmch_m = (temp * bits_per_pixel) / nlanes;
+ m_n->gmch_m >>= 3; /* convert to bytes per pixel */
+ m_n->gmch_n = DATA_N;
+ fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+
+ temp = (uint64_t) LINK_N * pixel_clock;
+ m_n->link_m = temp / link_clock;
+ m_n->link_n = LINK_N;
+ fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
/**
* Sets up registers for the given mode/adjusted_mode pair.
*
@@ -1521,6 +2234,18 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
const intel_limit_t *limit;
+ struct fdi_m_n m_n = {0};
+ int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
+ int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
+ int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
+ int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
+ int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
+ int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+ int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+ int lvds_reg = LVDS;
+ uint32_t temp;
+ int sdvo_pixel_multiply;
+
/* Set up some convenient bools for what outputs are connected to
* our pipe, used in DPLL setup.
*/
@@ -1533,6 +2258,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
switch (intel_output->type) {
case I830_OUTPUT_LVDS:
+ ErrorF("is lvds\n");
is_lvds = TRUE;
lvds_bits = intel_output->lvds_bits;
break;
@@ -1551,6 +2277,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;
}
@@ -1568,6 +2295,8 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
"using SSC reference clock of %d MHz\n", refclk / 1000);
} else if (IS_I9XX(intel)) {
refclk = 96000;
+ if (IS_IGDNG(intel))
+ refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
}
@@ -1610,12 +2339,46 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
}
}
+ if (IS_IGDNG(intel)) {
+ int bpp = 24;
+ if (is_lvds) {
+ uint32_t lvds_reg = INREG(PCH_LVDS);
+
+ if (!((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP))
+ bpp = 18;
+ }
+
+ 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(intel)) {
+ uint32_t 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);
+ }
+
if (IS_IGD(intel))
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
else
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
- dpll = DPLL_VGA_MODE_DIS;
+ if (!IS_IGDNG(intel))
+ dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(intel)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
@@ -1624,11 +2387,12 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
if (is_sdvo)
{
dpll |= DPLL_DVO_HIGH_SPEED;
+ sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
if ((IS_I945G(intel) || IS_I945GM(intel) || IS_G33CLASS(intel)))
- {
- int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- }
+ else if (IS_IGDNG(intel))
+ dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+
}
/* compute bitmask from p1 value */
@@ -1650,7 +2414,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
- if (IS_I965G(intel) && !IS_GM45(intel))
+ if (IS_I965G(intel) && !IS_GM45(intel) && !IS_IGDNG(intel))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@@ -1680,6 +2444,10 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
+ /* this is "must be enabled" in the docs, but not set by bios */
+ if (IS_IGDNG(intel))
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
switch (scrn->bitsPerPixel) {
case 8:
dspcntr |= DISPPLANE_8BPP;
@@ -1697,10 +2465,14 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
FatalError("unknown display bpp\n");
}
- if (pipe == 0)
- dspcntr |= DISPPLANE_SEL_PIPE_A;
- else
- dspcntr |= DISPPLANE_SEL_PIPE_B;
+ /* IGDNG's plane is forced to pipe, bit 24 is to
+ enable color space conversion */
+ if (!IS_IGDNG(intel)) {
+ if (pipe == 0)
+ dspcntr |= DISPPLANE_SEL_PIPE_A;
+ else
+ dspcntr |= DISPPLANE_SEL_PIPE_B;
+ }
if (IS_I965G(intel) && i830_display_tiled(crtc))
dspcntr |= DISPLAY_PLANE_TILED;
@@ -1719,12 +2491,20 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
else
pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
}
+
+ if (IS_IGDNG(intel)) {
+ 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.
* On 855, it can lock up the chip (and the entire machine)
*/
- if (!IS_I85X (intel))
+ if (!IS_I85X (intel) && !IS_IGDNG(intel))
{
dspcntr |= DISPLAY_PLANE_ENABLE;
pipeconf |= PIPEACONF_ENABLE;
@@ -1732,7 +2512,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
}
/* Disable the panel fitter if it was on our pipe */
- if (i830_panel_fitter_pipe (intel) == pipe)
+ if (!IS_IGDNG(intel) && i830_panel_fitter_pipe (intel) == pipe)
OUTREG(PFIT_CONTROL, 0);
if (intel->debug_modes) {
@@ -1747,6 +2527,12 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
i830PrintPll(scrn, "chosen", &clock);
}
+ /* assign to IGDNG registers */
+ if (IS_IGDNG(intel)) {
+ fp_reg = pch_fp_reg;
+ dpll_reg = pch_dpll_reg;
+ }
+
if (dpll & DPLL_VCO_ENABLE)
{
OUTREG(fp_reg, fp);
@@ -1761,9 +2547,17 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
*/
if (is_lvds)
{
- uint32_t lvds = INREG(LVDS);
+ uint32_t lvds;
+
+ if (IS_IGDNG(intel))
+ lvds_reg = PCH_LVDS;
- lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
+ lvds = INREG(lvds_reg);
+ lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+ if (IS_IGDNG(intel))
+ lvds |= (pipe == 1) ? LVDS_PIPEB_SELECT : 0;
+ else
+ lvds |= LVDS_PIPEB_SELECT;
/* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not.
*/
@@ -1799,17 +2593,18 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
lvds |= lvds_bits;
- OUTREG(LVDS, lvds);
- POSTING_READ(LVDS);
+ OUTREG(lvds_reg, lvds);
+ POSTING_READ(lvds_reg);
}
OUTREG(fp_reg, fp);
+/* OUTREG(fp_reg + 4, fp); RHEL had this... wtf? */
OUTREG(dpll_reg, dpll);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
- if (IS_I965G(intel)) {
+ if (IS_I965G(intel) && !IS_IGDNG(intel)) {
int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
@@ -1832,7 +2627,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
((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) |
@@ -1840,13 +2635,37 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
/* 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);
+ if (!IS_IGDNG(intel)) {
+ OUTREG(dspsize_reg, ((mode->VDisplay - 1) << 16) | (mode->HDisplay - 1));
+ OUTREG(dsppos_reg, 0);
+ }
OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+
+ if (IS_IGDNG(intel)) {
+ OUTREG(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
+ OUTREG(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
+ OUTREG(link_m1_reg, m_n.link_m);
+ OUTREG(link_n1_reg, m_n.link_n);
+
+#if 0
+ /* enable FDI RX PLL too */
+ /* XXX this doesn't work */
+ temp = INREG(fdi_rx_reg);
+ OUTREG(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+ usleep(200);
+#endif
+ }
+
OUTREG(pipeconf_reg, pipeconf);
POSTING_READ(pipeconf_reg);
i830WaitForVblank(scrn);
+ if (IS_IGDNG(intel)) {
+ /* enable address swizzle for tiling buffer */
+ temp = INREG(DISP_ARB_CTL);
+ OUTREG(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
+ }
+
OUTREG(dspcntr_reg, dspcntr);
/* Flush the plane changes */
i830PipeSetBase(crtc, x, y);
@@ -1869,6 +2688,11 @@ i830_crtc_load_lut(xf86CrtcPtr crtc)
if (!crtc->enabled)
return;
+ /* use legacy palette for IGDNG */
+ if (IS_IGDNG(intel))
+ palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
+ LGC_PALETTE_B;
+
for (i = 0; i < 256; i++) {
OUTREG(palreg + 4 * i,
(intel_crtc->lut_r[i] << 16) |
@@ -2024,6 +2848,12 @@ i830DescribeOutputConfiguration(ScrnInfoPtr scrn)
INREG(PIPEBCONF);
Bool hw_plane_enable = (dspcntr & DISPLAY_PLANE_ENABLE) != 0;
Bool hw_pipe_enable = (pipeconf & PIPEACONF_ENABLE) != 0;
+ int pipe;
+
+ if (IS_IGDNG(intel))
+ pipe = intel_crtc->plane;
+ else
+ pipe = !!(dspcntr & DISPPLANE_SEL_PIPE_MASK);
xf86DrvMsg(scrn->scrnIndex, X_INFO,
" Pipe %c is %s\n",
@@ -2032,7 +2862,7 @@ i830DescribeOutputConfiguration(ScrnInfoPtr scrn)
" Display plane %c is now %s and connected to pipe %c.\n",
'A' + intel_crtc->plane,
hw_plane_enable ? "enabled" : "disabled",
- dspcntr & DISPPLANE_SEL_PIPE_MASK ? 'B' : 'A');
+ 'A' + pipe);
if (hw_pipe_enable != crtc->enabled) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
" Hardware claims pipe %c is %s while software "
@@ -2235,19 +3065,22 @@ i830_crtc_clock_get(ScrnInfoPtr scrn, xf86CrtcPtr crtc)
return 0;
}
- if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
+ if (IS_IGDNG(intel))
+ i9xx_clock(120000, &clock);
+ else if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
intel_clock(intel, 100000, &clock);
else
intel_clock(intel, 96000, &clock);
} else {
- Bool is_lvds = (pipe == 1) && (INREG(LVDS) & LVDS_PORT_EN);
+ CARD32 lvds = IS_IGDNG(intel) ? PCH_LVDS : LVDS;
+ Bool is_lvds = (pipe == 1) && (INREG(lvds) & LVDS_PORT_EN);
if (is_lvds) {
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
DPLL_FPA01_P1_POST_DIV_SHIFT);
/* if LVDS is dual-channel, p2 = 7 */
- if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+ if ((INREG(lvds) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
clock.p2 = 7;
else
clock.p2 = 14;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 9da62204..a7933e93 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -659,7 +659,29 @@ static void I830SetupOutputs(ScrnInfoPtr scrn)
if (IS_MOBILE(intel) && !IS_I830(intel))
i830_lvds_init(scrn);
- if (IS_I9XX(intel)) {
+ if (IS_IGDNG(intel)) {
+ int found;
+
+ if (INREG(HDMIB) & PORT_DETECTED) {
+ /* check SDVOB */
+ /* found = intel_sdvo_init(dev, HDMIB); */
+ found = 0;
+ if (!found)
+ i830_hdmi_init(scrn, HDMIB);
+ }
+
+ if (INREG(HDMIC) & PORT_DETECTED)
+ i830_hdmi_init(scrn, HDMIC);
+
+ if (INREG(HDMID) & PORT_DETECTED)
+ i830_hdmi_init(scrn, HDMID);
+
+ /* Disable DP by force */
+ OUTREG(PCH_DP_B, INREG(PCH_DP_B) & ~PORT_ENABLE);
+ OUTREG(PCH_DP_C, INREG(PCH_DP_C) & ~PORT_ENABLE);
+ OUTREG(PCH_DP_D, INREG(PCH_DP_D) & ~PORT_ENABLE);
+
+ } else if (IS_I9XX(intel)) {
Bool found = FALSE;
if ((INREG(SDVOB) & SDVO_DETECTED)) {
found = i830_sdvo_init(scrn, SDVOB);
@@ -678,7 +700,7 @@ static void I830SetupOutputs(ScrnInfoPtr scrn)
} else {
i830_dvo_init(scrn);
}
- if (IS_I9XX(intel) && IS_MOBILE(intel))
+ if (IS_I9XX(intel) && IS_MOBILE(intel) && !IS_IGDNG(intel))
i830_tv_init(scrn);
for (o = 0; o < config->num_output; o++) {
@@ -1617,6 +1639,30 @@ static Bool I830PreInit(ScrnInfoPtr scrn, int flags)
}
if (!intel->use_drm_mode) {
+ /* console hack, stolen from G80 */
+ if (IS_IGDNG(intel)) {
+ if (xf86LoadSubModule(scrn, "int10")) {
+ intel->int10 = xf86InitInt10(pEnt->index);
+ if (intel->int10) {
+ intel->int10->num = 0x10;
+ intel->int10->ax = 0x4f03;
+ intel->int10->bx =
+ intel->int10->cx =
+ intel->int10->dx = 0;
+ xf86ExecX86int10(intel->int10);
+ intel->int10Mode = intel->int10->bx & 0x3fff;
+ xf86DrvMsg(scrn->scrnIndex, X_PROBED,
+ "Console VGA mode is 0x%x\n", intel->int10Mode);
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "Failed int10 setup, VT switch won't work\n");
+ }
+ } else {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "Failed to load int10module, ironlake vt switch broken");
+ }
+ }
+
I830UnmapMMIO(scrn);
/* We won't be using the VGA access after the probe. */
@@ -1760,6 +1806,9 @@ static Bool SaveHWState(ScrnInfoPtr scrn)
vgaRegPtr vgaReg = &hwp->SavedReg;
int i;
+ if (IS_IGDNG(intel))
+ return TRUE;
+
if (intel->fb_compression) {
intel->saveFBC_CFB_BASE = INREG(FBC_CFB_BASE);
intel->saveFBC_LL_BASE = INREG(FBC_LL_BASE);
@@ -1886,6 +1935,9 @@ static Bool RestoreHWState(ScrnInfoPtr scrn)
vgaRegPtr vgaReg = &hwp->SavedReg;
int i;
+ if (IS_IGDNG(intel))
+ return TRUE;
+
DPRINTF(PFX, "RestoreHWState\n");
/* Disable outputs */
@@ -2443,7 +2495,8 @@ I830SwapPipes(ScrnInfoPtr scrn)
* alone in that case.
* Also make sure the DRM can handle the swap.
*/
- if (I830LVDSPresent(scrn) && !IS_I965GM(intel) && !IS_GM45(intel)) {
+ if (I830LVDSPresent(scrn) && !IS_I965GM(intel) && !IS_GM45(intel) &&
+ !IS_IGDNG(intel)) {
xf86DrvMsg(scrn->scrnIndex, X_INFO, "adjusting plane->pipe "
"mappings to allow for framebuffer compression\n");
for (c = 0; c < config->num_crtc; c++) {
@@ -2848,6 +2901,18 @@ static void I830LeaveVT(int scrnIndex, int flags)
i830_stop_ring(scrn, TRUE);
}
+ /* console restore hack */
+ if (IS_IGDNG(intel) && intel->int10 && intel->int10Mode) {
+ xf86Int10InfoPtr int10 = intel->int10;
+
+ /* Use int10 to restore the console mode */
+ int10->num = 0x10;
+ int10->ax = 0x4f02;
+ int10->bx = intel->int10Mode | 0x8000;
+ int10->cx = int10->dx = 0;
+ xf86ExecX86int10(int10);
+ }
+
}
intel_batch_teardown(scrn);
diff --git a/src/i830_hdmi.c b/src/i830_hdmi.c
index d2f95376..3b04b0f5 100644
--- a/src/i830_hdmi.c
+++ b/src/i830_hdmi.c
@@ -136,6 +136,22 @@ i830_hdmi_restore(xf86OutputPtr output)
OUTREG(dev_priv->output_reg, dev_priv->save_SDVO);
}
+static xf86OutputStatus
+igdng_hdmi_detect(xf86OutputPtr output)
+{
+ DisplayModePtr modes;
+ xf86OutputStatus status;
+
+ modes = i830_ddc_get_modes(output);
+
+ if (modes == NULL)
+ status = XF86OutputStatusDisconnected;
+ else
+ status = XF86OutputStatusConnected;
+
+ return status;
+}
+
/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect HDMI connection.
*
@@ -155,6 +171,9 @@ i830_hdmi_detect(xf86OutputPtr output)
dev_priv->has_hdmi_sink = FALSE;
+ if (IS_IGDNG(intel))
+ return igdng_hdmi_detect(output);
+
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 0xd.
* Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached.
@@ -332,9 +351,27 @@ i830_hdmi_init(ScrnInfoPtr scrn, int output_reg)
xf86OutputPtr output;
I830OutputPrivatePtr intel_output;
struct i830_hdmi_priv *dev_priv;
+ const char *name;
- output = xf86OutputCreate(scrn, &i830_hdmi_output_funcs,
- (output_reg == SDVOB) ? "HDMI-1" : "HDMI-2");
+ switch (output_reg) {
+ case SDVOB:
+ name = "HDMI-1";
+ break;
+ case SDVOC:
+ name = "HDMI-2";
+ break;
+ case HDMIB:
+ name = "HDMI-3";
+ break;
+ case HDMIC:
+ name = "HDMI-4";
+ break;
+ case HDMID:
+ name = "HDMI-5";
+ break;
+ }
+
+ output = xf86OutputCreate(scrn, &i830_hdmi_output_funcs, name);
if (!output)
return;
intel_output = xnfcalloc(sizeof (I830OutputPrivateRec) +
@@ -359,10 +396,15 @@ i830_hdmi_init(ScrnInfoPtr scrn, int output_reg)
/* Set up the DDC bus. */
if (output_reg == SDVOB)
I830I2CInit(scrn, &intel_output->pDDCBus, GPIOE, "HDMIDDC_B");
- else
+ else if (output_reg == SDVOC)
I830I2CInit(scrn, &intel_output->pDDCBus, GPIOD, "HDMIDDC_C");
+ else if (output_reg == HDMIB)
+ I830I2CInit(scrn, &intel_output->pDDCBus, PCH_GPIOE, "HDMIB");
+ else if (output_reg == HDMIC)
+ I830I2CInit(scrn, &intel_output->pDDCBus, PCH_GPIOD, "HDMIC");
+ else if (output_reg == HDMID)
+ I830I2CInit(scrn, &intel_output->pDDCBus, PCH_GPIOF, "HDMID");
xf86DrvMsg(scrn->scrnIndex, X_INFO,
- "HDMI output %d detected\n",
- (output_reg == SDVOB) ? 1 : 2);
+ "%s output detected\n", output->name);
}
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index b33b461d..34b3cbce 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -140,6 +140,10 @@ i830_set_lvds_backlight_method(xf86OutputPtr output)
if (i830_kernel_backlight_available(output)) {
method = BCM_KERNEL;
+#if 0
+ } else if (IS_IGDNG(intel)) {
+ method = BCM_IRONLAKE_NULL;
+#endif
} else if (IS_I965GM(intel) || IS_GM45(intel)) {
blc_pwm_ctl2 = INREG(BLC_PWM_CTL2);
if (blc_pwm_ctl2 & BLM_LEGACY_MODE2)
@@ -161,11 +165,16 @@ i830_lvds_set_backlight_native(xf86OutputPtr output, int level)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
- uint32_t blc_pwm_ctl;
+ uint32_t blc_pwm_ctl, reg;
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
+ if (IS_IGDNG(intel))
+ reg = BLC_PWM_CPU_CTL;
+ else
+ reg = BLC_PWM_CTL;
+
+ blc_pwm_ctl = INREG(reg);
blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
- OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
+ OUTREG(reg, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
}
static int
@@ -185,8 +194,15 @@ i830_lvds_get_backlight_max_native(xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
- uint32_t pwm_ctl = INREG(BLC_PWM_CTL);
- int val;
+ uint32_t pwm_ctl;
+ int val, reg;
+
+ if (IS_IGDNG(intel))
+ reg = BLC_PWM_PCH_CTL2;
+ else
+ reg = BLC_PWM_CTL;
+
+ pwm_ctl = INREG(reg);
if (IS_I965GM(intel) || IS_GM45(intel)) {
val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK2) >>
@@ -278,6 +294,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, int level)
+{
+}
+
/*
* Kernel methods
*/
@@ -482,11 +510,33 @@ i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
- uint32_t pp_status;
+ uint32_t pp_status, ctl_reg, status_reg;
+
+ if (IS_IGDNG(intel)) {
+ ctl_reg = PCH_PP_CONTROL;
+ status_reg = PCH_PP_STATUS;
+ } else {
+ ctl_reg = PP_CONTROL;
+ status_reg = PP_STATUS;
+ }
+
+ if (IS_IGDNG(intel)) {
+ CARD32 temp;
+ if (on) {
+ temp = INREG(PCH_LVDS);
+ OUTREG(PCH_LVDS, temp | PORT_ENABLE);
+ temp = INREG(PCH_LVDS);
+ } else {
+ temp = INREG(PCH_LVDS);
+ OUTREG(PCH_LVDS, temp & ~PORT_ENABLE);
+ temp = INREG(PCH_LVDS);
+ }
+ usleep(100);
+ }
if (on) {
/* if we're going from on->on, be aware to current level. */
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
+ if ((INREG(ctl_reg) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
/*
@@ -496,14 +546,14 @@ i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
* controller for example), so on them, when turning LVDS back on,
* they'll always re-maximize the brightness.
*/
- if (!(INREG(PP_CONTROL) & POWER_TARGET_ON) &&
+ if (!(INREG(ctl_reg) & POWER_TARGET_ON) &&
dev_priv->backlight_duty_cycle == 0 &&
intel->backlight_control_method < BCM_KERNEL)
dev_priv->backlight_duty_cycle = dev_priv->backlight_max;
- OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
+ OUTREG(ctl_reg, INREG(ctl_reg) | POWER_TARGET_ON);
do {
- pp_status = INREG(PP_STATUS);
+ pp_status = INREG(status_reg);
} while ((pp_status & PP_ON) == 0);
dev_priv->set_backlight(output, dev_priv->backlight_duty_cycle);
@@ -513,13 +563,13 @@ i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
* Only save the current backlight value if we're going from
* on to off.
*/
- if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
+ if ((INREG(ctl_reg) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
dev_priv->set_backlight(output, 0);
- OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
+ OUTREG(ctl_reg, INREG(ctl_reg) & ~POWER_TARGET_ON);
do {
- pp_status = INREG(PP_STATUS);
+ pp_status = INREG(status_reg);
} while (pp_status & PP_ON);
dev_priv->dpmsoff = TRUE;
@@ -544,14 +594,29 @@ i830_lvds_save (xf86OutputPtr output)
struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg, pwm_ctl_reg;
+
+ if (IS_IGDNG(intel)) {
+ pp_on_reg = PCH_PP_ON_DELAYS;
+ pp_off_reg = PCH_PP_OFF_DELAYS;
+ pp_ctl_reg = PCH_PP_CONTROL;
+ pp_div_reg = PCH_PP_DIVISOR;
+ pwm_ctl_reg = BLC_PWM_CPU_CTL;
+ } else {
+ pp_on_reg = PP_ON_DELAYS;
+ pp_off_reg = PP_OFF_DELAYS;
+ pp_ctl_reg = PP_CONTROL;
+ pp_div_reg = PP_DIVISOR;
+ pwm_ctl_reg = BLC_PWM_CTL;
+ }
if (IS_I965GM(intel) || IS_GM45(intel))
intel->saveBLC_PWM_CTL2 = INREG(BLC_PWM_CTL2);
- intel->savePP_ON = INREG(PP_ON_DELAYS);
- intel->savePP_OFF = INREG(PP_OFF_DELAYS);
- intel->savePP_CONTROL = INREG(PP_CONTROL);
- intel->savePP_DIVISOR = INREG(PP_DIVISOR);
- intel->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
+ intel->savePP_ON = INREG(pp_on_reg);
+ intel->savePP_OFF = INREG(pp_off_reg);
+ intel->savePP_CONTROL = INREG(pp_ctl_reg);
+ intel->savePP_DIVISOR = INREG(pp_div_reg);
+ intel->saveBLC_PWM_CTL = INREG(pwm_ctl_reg);
if ((INREG(PP_CONTROL) & POWER_TARGET_ON) && !dev_priv->dpmsoff)
dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
}
@@ -561,14 +626,31 @@ i830_lvds_restore(xf86OutputPtr output)
{
ScrnInfoPtr scrn = output->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ uint32_t pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+ uint32_t pwm_ctl_reg;
+
+ if (IS_IGDNG(intel)) {
+ pp_on_reg = PCH_PP_ON_DELAYS;
+ pp_off_reg = PCH_PP_OFF_DELAYS;
+ pp_ctl_reg = PCH_PP_CONTROL;
+ pp_div_reg = PCH_PP_DIVISOR;
+ pwm_ctl_reg = BLC_PWM_CPU_CTL;
+ } else {
+ pp_on_reg = PP_ON_DELAYS;
+ pp_off_reg = PP_OFF_DELAYS;
+ pp_ctl_reg = PP_CONTROL;
+ pp_div_reg = PP_DIVISOR;
+ pwm_ctl_reg = BLC_PWM_CTL;
+ }
if (IS_I965GM(intel) || IS_GM45(intel))
OUTREG(BLC_PWM_CTL2, intel->saveBLC_PWM_CTL2);
- OUTREG(BLC_PWM_CTL, intel->saveBLC_PWM_CTL);
- OUTREG(PP_ON_DELAYS, intel->savePP_ON);
- OUTREG(PP_OFF_DELAYS, intel->savePP_OFF);
- OUTREG(PP_DIVISOR, intel->savePP_DIVISOR);
- OUTREG(PP_CONTROL, intel->savePP_CONTROL);
+ OUTREG(pwm_ctl_reg, intel->saveBLC_PWM_CTL);
+ OUTREG(pp_on_reg, intel->savePP_ON);
+ OUTREG(pp_off_reg, intel->savePP_OFF);
+ OUTREG(pp_div_reg, intel->savePP_DIVISOR);
+ OUTREG(pp_ctl_reg, intel->savePP_CONTROL);
+
if (intel->savePP_CONTROL & POWER_TARGET_ON)
i830SetLVDSPanelPower(output, TRUE);
else
@@ -624,7 +706,7 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
}
}
- if (intel_crtc->pipe == 0) {
+ if (!IS_IGDNG(intel) && intel_crtc->pipe == 0) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Can't support LVDS on pipe A\n");
return FALSE;
@@ -1070,12 +1152,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];
@@ -1135,6 +1218,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
@@ -1447,6 +1535,7 @@ i830_lvds_init(ScrnInfoPtr scrn)
DisplayModePtr modes, scan;
DisplayModePtr lvds_ddc_mode = NULL;
struct i830_lvds_priv *dev_priv;
+ int gpio = GPIOC;
if (!intel->integrated_lvds) {
if (intel->debug_modes)
@@ -1458,6 +1547,12 @@ i830_lvds_init(ScrnInfoPtr scrn)
if (intel->quirk_flag & QUIRK_IGNORE_LVDS)
return;
+ if (IS_IGDNG(intel)) {
+ if ((INREG(PCH_LVDS) & LVDS_DETECTED) == 0)
+ return;
+ gpio = PCH_GPIOC;
+ }
+
output = xf86OutputCreate (scrn, &i830_lvds_output_funcs, "LVDS");
if (!output)
return;
@@ -1470,6 +1565,8 @@ i830_lvds_init(ScrnInfoPtr scrn)
}
intel_output->type = I830_OUTPUT_LVDS;
intel_output->pipe_mask = (1 << 1);
+ if (0 && IS_IGDNG(intel)) /* XXX put me back */
+ intel_output->pipe_mask |= (1 << 0);
intel_output->clone_mask = (1 << I830_OUTPUT_LVDS);
output->driver_private = intel_output;
@@ -1492,7 +1589,7 @@ i830_lvds_init(ScrnInfoPtr scrn)
/* Set up the LVDS DDC channel. Most panels won't support it, but it can
* be useful if available.
*/
- I830I2CInit(scrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C");
+ I830I2CInit(scrn, &intel_output->pDDCBus, gpio, "LVDSDDC_C");
if (intel->skip_panel_detect) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
@@ -1541,7 +1638,7 @@ i830_lvds_init(ScrnInfoPtr scrn)
* turned on. If so, assume that whatever is currently programmed is the
* correct mode.
*/
- if (!intel->lvds_fixed_mode) {
+ if (!intel->lvds_fixed_mode && !IS_IGDNG(intel)) {
uint32_t lvds = INREG(LVDS);
int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1619,6 +1716,19 @@ found_mode:
*/
dev_priv->fitting_mode = FULL_ASPECT;
+ if (IS_IGDNG(intel)) {
+ CARD32 pwm;
+ /* make sure PWM is enabled */
+ pwm = INREG(BLC_PWM_CPU_CTL2);
+ pwm |= (PWM_ENABLE | PWM_PIPE_B);
+ OUTREG(BLC_PWM_CPU_CTL2, pwm);
+
+ pwm = INREG(BLC_PWM_PCH_CTL1);
+ pwm |= PWM_PCH_ENABLE;
+ OUTREG(BLC_PWM_PCH_CTL1, pwm);
+ }
+
+
return;
disable_exit: