summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@airlied-rhel5.(none)>2010-04-21 11:07:14 +1000
committerDave Airlie <airlied@airlied-rhel5.(none)>2010-04-21 11:07:14 +1000
commitc97eddba9d98c71933a62f957b80d9478ee6edb2 (patch)
tree2701c8c3a4c9421c44309c947c1121e775e86714
parenta9e5421915c8fac06d685e04de57898c6153cf3d (diff)
intel-2.2.1-ironlake-modesetting.patch
-rw-r--r--src/i810_driver.c2
-rw-r--r--src/i810_reg.h81
-rw-r--r--src/i830_crt.c89
-rw-r--r--src/i830_display.c633
-rw-r--r--src/i830_driver.c21
-rw-r--r--src/i830_lvds.c120
6 files changed, 863 insertions, 83 deletions
diff --git a/src/i810_driver.c b/src/i810_driver.c
index 43ad259b..f288ca36 100644
--- a/src/i810_driver.c
+++ b/src/i810_driver.c
@@ -822,6 +822,8 @@ I810Probe(DriverPtr drv, int flags)
case PCI_CHIP_G45_G:
case PCI_CHIP_Q45_G:
case PCI_CHIP_G41_G:
+ case PCI_CHIP_IGDNG_D_G:
+ case PCI_CHIP_IGDNG_M_G:
xf86SetEntitySharable(usedChips[i]);
/* Allocate an entity private if necessary */
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 0953359b..92321ab1 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -2173,6 +2173,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 */
@@ -2873,6 +2874,15 @@ typedef enum {
#define PFA_CTRL_1 0x68080
#define PFB_CTRL_1 0x68880
+/* CPU panel fitter */
+#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
+
/* legacy palette */
#define LGC_PALETTE_A 0x4a000
#define LGC_PALETTE_B 0x4a800
@@ -2918,6 +2928,9 @@ 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 */
@@ -2982,23 +2995,27 @@ typedef enum {
#define PCH_DPLL_TEST 0xc606c
-#define PCH_DREF_CONTROL 0xC6200
-#define DREF_CONTROL_MASK 0x7fc3
-#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13)
-#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13)
-#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13)
-#define DREF_SSC_SOURCE_DISABLE (0<<11)
-#define DREF_SSC_SOURCE_ENABLE (2<<11)
-#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9)
-#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9)
-#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7)
-#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7)
-#define DREF_SSC4_DOWNSPREAD (0<<6)
-#define DREF_SSC4_CENTERSPREAD (1<<6)
-#define DREF_SSC1_DISABLE (0<<1)
-#define DREF_SSC1_ENABLE (1<<1)
-#define DREF_SSC4_DISABLE (0)
-#define DREF_SSC4_ENABLE (1)
+#define PCH_DREF_CONTROL 0xC6200
+#define DREF_CONTROL_MASK 0x7fc3
+#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13)
+#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13)
+#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13)
+#define DREF_CPU_SOURCE_OUTPUT_MASK (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)
+#define DREF_SSC4_CENTERSPREAD (1<<6)
+#define DREF_SSC1_DISABLE (0<<1)
+#define DREF_SSC1_ENABLE (1<<1)
+#define DREF_SSC4_DISABLE (0)
+#define DREF_SSC4_ENABLE (1)
#define PCH_RAWCLK_FREQ 0xc6204
#define FDL_TP1_TIMER_SHIFT 12
@@ -3206,4 +3223,34 @@ typedef enum {
#define HDMIC 0xe1150
#define HDMID 0xe1160
+#define PCH_LVDS 0xe1180
+#define LVDS_DETECTED (1 << 1)
+
+#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
+
#endif /* _I810_REG_H */
diff --git a/src/i830_crt.c b/src/i830_crt.c
index 42067d4d..9368ea07 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 pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
- CARD32 temp;
+ CARD32 temp, reg;
+
+ if (IS_IGDNG(pI830))
+ 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
@@ -110,16 +117,23 @@ i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode,
I830CrtcPrivatePtr i830_crtc = crtc->driver_private;
int dpll_md_reg;
CARD32 adpa, dpll_md;
+ CARD32 adpa_reg;
if (i830_crtc->pipe == 0)
dpll_md_reg = DPLL_A_MD;
else
dpll_md_reg = DPLL_B_MD;
+
+ if (IS_IGDNG(pI830))
+ 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(pI830))
+ if (IS_I965G(pI830) && !IS_IGDNG(pI830))
{
dpll_md = INREG(dpll_md_reg);
OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -134,15 +148,53 @@ 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(pI830))
+ OUTREG(BCLRPAT_A, 0);
}
else
{
adpa |= ADPA_PIPE_B_SELECT;
- OUTREG(BCLRPAT_B, 0);
+ if (!IS_IGDNG(pI830))
+ OUTREG(BCLRPAT_B, 0);
}
- OUTREG(ADPA, adpa);
+ OUTREG(adpa_reg, adpa);
+}
+
+static Bool intel_igdng_crt_detect_hotplug(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 adpa;
+ Bool ret;
+
+ adpa = INREG(PCH_ADPA);
+
+ adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+
+ adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
+ ADPA_CRT_HOTPLUG_WARMUP_10MS |
+ ADPA_CRT_HOTPLUG_SAMPLE_4S |
+ ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
+ ADPA_CRT_HOTPLUG_VOLREF_325MV |
+ ADPA_CRT_HOTPLUG_ENABLE |
+ ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
+
+ OUTREG(PCH_ADPA, adpa);
+
+ while (adpa = INREG(PCH_ADPA),
+ (adpa & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0)
+ ;
+
+ /* 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;
}
/**
@@ -163,6 +215,9 @@ i830_crt_detect_hotplug(xf86OutputPtr output)
int starttime, curtime;
int tries = 1;
+ if (IS_IGDNG(pI830))
+ 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(pI830) && !IS_GM45(pI830))
@@ -362,10 +417,8 @@ i830_crt_detect(xf86OutputPtr output)
xf86OutputStatus status;
Bool connected;
- crtc = i830GetLoadDetectPipe (output, NULL, &dpms_mode);
-
- if (crtc && (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830) ||
- IS_G33CLASS(pI830))) {
+ if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830) ||
+ IS_G33CLASS(pI830)) {
if (i830_crt_detect_hotplug(output))
status = XF86OutputStatusConnected;
else
@@ -379,6 +432,8 @@ i830_crt_detect(xf86OutputPtr output)
goto out;
}
+ crtc = i830GetLoadDetectPipe (output, NULL, &dpms_mode);
+
if (!crtc)
return XF86OutputStatusUnknown;
@@ -389,10 +444,9 @@ i830_crt_detect(xf86OutputPtr output)
else
status = XF86OutputStatusDisconnected;
-out:
- if (crtc)
- i830ReleaseLoadDetectPipe (output, dpms_mode);
+ i830ReleaseLoadDetectPipe (output, dpms_mode);
+ out:
return status;
}
@@ -423,6 +477,7 @@ i830_crt_init(ScrnInfoPtr pScrn)
xf86OutputPtr output;
I830OutputPrivatePtr i830_output;
I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 i2c_reg;
output = xf86OutputCreate (pScrn, &i830_crt_output_funcs, "VGA");
if (!output)
@@ -447,5 +502,9 @@ i830_crt_init(ScrnInfoPtr pScrn)
output->doubleScanAllowed = FALSE;
/* Set up the DDC bus. */
- I830I2CInit(pScrn, &i830_output->pDDCBus, GPIOA, "CRTDDC_A");
+ if (IS_IGDNG(pI830))
+ i2c_reg = PCH_GPIOA;
+ else
+ i2c_reg = GPIOA;
+ I830I2CInit(pScrn, &i830_output->pDDCBus, i2c_reg, "CRTDDC_A");
}
diff --git a/src/i830_display.c b/src/i830_display.c
index 28680c7b..978e7fc3 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -42,6 +42,7 @@
#include "i830_display.h"
#include "i830_debug.h"
#include "xf86Modes.h"
+#include "i810_reg.h"
typedef struct {
/* given values */
@@ -132,6 +133,30 @@ 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 5
+#define IGDNG_M_MIN 79
+#define IGDNG_M_MAX 118
+#define IGDNG_M1_MIN 12
+#define IGDNG_M1_MAX 23
+#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 INTEL_LIMIT_I8XX_DVO_DAC 0
#define INTEL_LIMIT_I8XX_LVDS 1
#define INTEL_LIMIT_I9XX_SDVO_DAC 2
@@ -191,13 +216,55 @@ 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_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_igdng_limit(xf86CrtcPtr crtc)
+{
+ const intel_limit_t *limit;
+ if (i830PipeHasType(crtc, I830_OUTPUT_LVDS))
+ limit = &intel_limits_igdng_lvds;
+ else
+ limit = &intel_limits_igdng_sdvo_dac;
+
+ return limit;
+}
+
+
static const intel_limit_t *intel_limit (xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
const intel_limit_t *limit;
- if (IS_I9XX(pI830)) {
+ if (IS_IGDNG(pI830))
+ limit = intel_igdng_limit(crtc);
+ else if (IS_I9XX(pI830)) {
if (i830PipeHasType (crtc, I830_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
else
@@ -309,6 +376,60 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock)
return TRUE;
}
+
+static Bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, xf86CrtcPtr crtc,
+ int target, int refclk, intel_clock_t *best_clock)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ intel_clock_t clock;
+ int err_most = 47;
+ int err_min = 10000;
+
+ 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));
+ 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--) {
+ int this_err;
+
+ intel_clock(pI830, refclk, &clock);
+ if (!i830PllIsValid(crtc, &clock))
+ continue;
+ this_err = abs((10000 - (target*10000/clock.dot)));
+ 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;
+ }
+ }
+ }
+ }
+ }
+ out:
+ return TRUE;
+}
+
/**
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
@@ -323,6 +444,10 @@ i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_cl
const intel_limit_t *limit = intel_limit (crtc);
int err = target;
+ if (IS_IGDNG(pI830))
+ return intel_igdng_find_best_PLL(limit, crtc,
+ target, refclk, best_clock);
+
if (i830PipeHasType(crtc, I830_OUTPUT_LVDS))
{
/* For LVDS, if the panel is on, just rely on its current settings for
@@ -670,6 +795,16 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
uint8_t sr01;
+ uint32_t vga_reg, vgacntrl;
+
+ if (IS_IGDNG(pI830))
+ 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
@@ -686,7 +821,8 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
usleep(30);
}
- OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+ vgacntrl |= VGA_DISP_DISABLE;
+ OUTREG(vga_reg, vgacntrl);
i830WaitForVblank(pScrn);
/* restore SR01 */
@@ -696,6 +832,323 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
}
}
+static void igdng_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ int 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;
+ CARD32 temp;
+ int tries = 5, j, n;
+
+ /* 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:
+
+ /* enable PCH DPLL */
+ temp = INREG(pch_dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) == 0) {
+ OUTREG(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+ INREG(pch_dpll_reg);
+ }
+
+ /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+ temp = INREG(fdi_rx_reg);
+ OUTREG(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
+ FDI_SEL_PCDCLK |
+ FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+ INREG(fdi_rx_reg);
+ usleep(200);
+
+ /* Enable CPU FDI TX PLL, always on for IGDNG */
+ temp = INREG(fdi_tx_reg);
+ if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+ OUTREG(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+ INREG(fdi_tx_reg);
+ usleep(100);
+ }
+
+ /* Enable panel fitting for LVDS */
+ if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) {
+ temp = INREG(pf_ctl_reg);
+ OUTREG(pf_ctl_reg, temp | PF_ENABLE);
+
+ /* currently full aspect */
+ OUTREG(pf_win_pos, 0);
+
+ OUTREG(pf_win_size,
+ (1680 << 16) |
+ (1050));
+ }
+
+
+ /* Enable CPU pipe */
+ temp = INREG(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) == 0) {
+ OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ INREG(pipeconf_reg);
+ usleep(100);
+ }
+
+ /* configure and enable CPU plane */
+ temp = INREG(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+ OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ OUTREG(dspbase_reg, INREG(dspbase_reg));
+ }
+
+ /* enable CPU FDI TX and PCH FDI RX */
+ temp = INREG(fdi_tx_reg);
+ 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);
+ INREG(fdi_tx_reg);
+
+ temp = INREG(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ OUTREG(fdi_rx_reg, temp | FDI_RX_ENABLE);
+ INREG(fdi_rx_reg);
+
+ usleep(150);
+
+ /* Train FDI. */
+ /* umask FDI RX Interrupt symbol_lock and bit_lock bit
+ for train result */
+ temp = INREG(fdi_rx_imr_reg);
+ temp &= ~FDI_RX_SYMBOL_LOCK;
+ temp &= ~FDI_RX_BIT_LOCK;
+ OUTREG(fdi_rx_imr_reg, temp);
+ INREG(fdi_rx_imr_reg);
+ usleep(150);
+
+ temp = INREG(fdi_rx_iir_reg);
+
+ if ((temp & FDI_RX_BIT_LOCK) == 0) {
+ for (j = 0; j < tries; j++) {
+ temp = INREG(fdi_rx_iir_reg);
+ if (temp & FDI_RX_BIT_LOCK)
+ break;
+ usleep(200);
+ }
+ if (j != tries)
+ OUTREG(fdi_rx_iir_reg, temp | FDI_RX_BIT_LOCK);
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "train 1 failed\n");
+ } else {
+ OUTREG(fdi_rx_iir_reg, temp | FDI_RX_BIT_LOCK);
+ }
+ temp = INREG(fdi_tx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_2;
+ OUTREG(fdi_tx_reg, temp);
+
+ temp = INREG(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_2;
+ OUTREG(fdi_rx_reg, temp);
+
+ usleep(150);
+
+ temp = INREG(fdi_rx_iir_reg);
+
+ if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
+ for (j = 0; j < tries; j++) {
+ temp = INREG(fdi_rx_iir_reg);
+ if (temp & FDI_RX_SYMBOL_LOCK)
+ break;
+ usleep(200);
+ }
+ if (j != tries)
+ OUTREG(fdi_rx_iir_reg,
+ temp | FDI_RX_SYMBOL_LOCK);
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "train 2 failed\n");
+
+ } else {
+ OUTREG(fdi_rx_iir_reg,
+ temp | FDI_RX_SYMBOL_LOCK);
+ }
+
+ /* 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 PCH transcoder */
+ temp = INREG(transconf_reg);
+ OUTREG(transconf_reg, temp | TRANS_ENABLE);
+ INREG(transconf_reg);
+
+ while ((INREG(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+ usleep(500);
+
+ /* enable normal */
+
+ temp = INREG(fdi_tx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ OUTREG(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+ FDI_TX_ENHANCE_FRAME_ENABLE);
+ INREG(fdi_tx_reg);
+
+ temp = INREG(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ OUTREG(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
+ FDI_RX_ENHANCE_FRAME_ENABLE);
+ INREG(fdi_rx_reg);
+
+ /* wait one idle pattern time */
+ usleep(100);
+
+ i830_crtc_load_lut(crtc);
+
+ break;
+ case DPMSModeOff:
+
+ /* Disable display plane */
+ temp = INREG(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+ OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ OUTREG(dspbase_reg, INREG(dspbase_reg));
+ INREG(dspbase_reg);
+ }
+
+ /* 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 {
+ break;
+ }
+ }
+ }
+
+ /* disable CPU FDI tx and PCH FDI rx */
+ temp = INREG(fdi_tx_reg);
+ OUTREG(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
+ INREG(fdi_tx_reg);
+
+ temp = INREG(fdi_rx_reg);
+ OUTREG(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
+ INREG(fdi_rx_reg);
+
+ usleep(100);
+
+ /* 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);
+
+ temp = INREG(fdi_rx_reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ OUTREG(fdi_rx_reg, temp);
+
+ usleep(100);
+
+ /* 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 < 60) {
+ usleep(500);
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* disable PCH DPLL */
+ temp = INREG(pch_dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) != 0) {
+ OUTREG(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
+ INREG(pch_dpll_reg);
+ }
+
+ temp = INREG(fdi_rx_reg);
+ if ((temp & FDI_RX_PLL_ENABLE) != 0) {
+ temp &= ~FDI_SEL_PCDCLK;
+ temp &= ~FDI_RX_PLL_ENABLE;
+ OUTREG(fdi_rx_reg, temp);
+ INREG(fdi_rx_reg);
+ }
+
+ temp = INREG(fdi_tx_reg);
+ if ((temp & FDI_TX_PLL_ENABLE) != 0) {
+ OUTREG(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
+ INREG(fdi_tx_reg);
+ usleep(100);
+ }
+
+ /* Disable PF */
+ temp = INREG(pf_ctl_reg);
+ if ((temp & PF_ENABLE) != 0) {
+ OUTREG(pf_ctl_reg, temp & ~PF_ENABLE);
+ INREG(pf_ctl_reg);
+ }
+ OUTREG(pf_win_size, 0);
+
+ /* Wait for the clocks to turn off. */
+ usleep(150);
+
+ i830_disable_vga_plane (crtc);
+
+ break;
+ }
+}
+
/**
* Sets the power management mode of the pipe and plane.
*
@@ -703,7 +1156,7 @@ i830_disable_vga_plane (xf86CrtcPtr crtc)
* 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 pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
@@ -822,6 +1275,19 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
break;
}
+}
+
+static void
+i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (IS_IGDNG(pI830))
+ igdng_crtc_dpms(crtc, mode);
+ else
+ i9xx_crtc_dpms(crtc, mode);
intel_crtc->dpms_mode = mode;
@@ -835,7 +1301,7 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
if (!sPriv)
return;
- switch (plane) {
+ switch (intel_crtc->pipe) {
case 0:
sPriv->planeA_w = enabled ? crtc->mode.HDisplay : 0;
sPriv->planeA_h = enabled ? crtc->mode.VDisplay : 0;
@@ -846,7 +1312,7 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Can't update pipe %d in SAREA\n", pipe);
+ "Can't update pipe %d in SAREA\n", intel_crtc->pipe);
break;
}
}
@@ -921,6 +1387,15 @@ static Bool
i830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ if (IS_IGDNG(pI830)) {
+ /* FDI link clock is fixed at 2.7G */
+ if (mode->Clock * 3 > 27000 * 4)
+ return MODE_CLOCK_HIGH;
+ }
+
return TRUE;
}
@@ -1015,6 +1490,47 @@ i830_panel_fitter_pipe(I830Ptr pI830)
return 1;
}
+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 bytes_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 * bytes_per_pixel) / nlanes;
+ 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.
*
@@ -1056,6 +1572,18 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
+ 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.
*/
@@ -1090,6 +1618,8 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
if (IS_I9XX(pI830)) {
refclk = 96000;
+ if (IS_IGDNG(pI830))
+ refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
}
@@ -1106,9 +1636,16 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
(float)adjusted_mode->Clock / 1000);
}
+ if (IS_IGDNG(pI830))
+ igdng_compute_m_n(3, 4, /* lane num 4 */
+ adjusted_mode->Clock,
+ 270000, /* lane clock */
+ &m_n);
+
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
- dpll = DPLL_VGA_MODE_DIS;
+ if (!IS_IGDNG(pI830))
+ dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(pI830)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
@@ -1117,15 +1654,19 @@ 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(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830))
- {
- int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- }
+ else if (IS_IGDNG(pI830))
+ dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+
}
/* compute bitmask from p1 value */
dpll |= (1 << (clock.p1 - 1)) << 16;
+ /* also FPA1 */
+ if (IS_IGDNG(pI830))
+ dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
switch (clock.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -1140,7 +1681,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
- if (IS_I965G(pI830) && !IS_GM45(pI830))
+ if (IS_I965G(pI830) && !IS_GM45(pI830) && !IS_IGDNG(pI830))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@@ -1161,15 +1702,16 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
}
-#if 0
else if (is_lvds)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-#endif
else
dpll |= PLL_REF_INPUT_DREFCLK;
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
+ if (IS_IGDNG(pI830))
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
switch (pScrn->bitsPerPixel) {
case 8:
dspcntr |= DISPPLANE_8BPP;
@@ -1187,10 +1729,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(pI830)) {
+ if (pipe == 0)
+ dspcntr |= DISPPLANE_SEL_PIPE_A;
+ else
+ dspcntr |= DISPPLANE_SEL_PIPE_B;
+ }
if (IS_I965G(pI830) && i830_display_tiled(crtc))
dspcntr |= DISPLAY_PLANE_TILED;
@@ -1222,7 +1768,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
}
/* Disable the panel fitter if it was on our pipe */
- if (i830_panel_fitter_pipe (pI830) == pipe)
+ if (!IS_IGDNG(pI830) && i830_panel_fitter_pipe (pI830) == pipe)
OUTREG(PFIT_CONTROL, 0);
if (pI830->debug_modes) {
@@ -1237,6 +1783,12 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
i830PrintPll("chosen", &clock);
}
+ /* assign to IGDNG registers */
+ if (IS_IGDNG(pI830)) {
+ fp_reg = pch_fp_reg;
+ dpll_reg = pch_dpll_reg;
+ }
+
if (dpll & DPLL_VCO_ENABLE)
{
OUTREG(fp_reg, fp);
@@ -1251,8 +1803,12 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
*/
if (is_lvds)
{
- CARD32 lvds = INREG(LVDS);
+ CARD32 lvds;
+
+ if (IS_IGDNG(pI830))
+ lvds_reg = PCH_LVDS;
+ lvds = INREG(LVDS);
lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | 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.
@@ -1276,17 +1832,18 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
lvds |= LVDS_DITHER_ENABLE;
}
- OUTREG(LVDS, lvds);
- POSTING_READ(LVDS);
+ OUTREG(lvds_reg, lvds);
+ POSTING_READ(lvds_reg);
}
OUTREG(fp_reg, fp);
+ OUTREG(fp_reg + 4, fp);
OUTREG(dpll_reg, dpll);
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
- if (IS_I965G(pI830)) {
+ if (IS_I965G(pI830) && !IS_IGDNG(pI830)) {
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));
@@ -1297,7 +1854,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
POSTING_READ(dpll_reg);
/* Wait for the clocks to stabilize. */
usleep(150);
-
+
OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) |
((adjusted_mode->CrtcHTotal - 1) << 16));
OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) |
@@ -1306,7 +1863,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) |
@@ -1315,13 +1872,34 @@ 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(pI830)) {
+ 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(pI830)) {
+ 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);
+
+ /* enable FDI RX PLL too */
+ temp = INREG(fdi_rx_reg);
+ OUTREG(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+ usleep(200);
+ }
+
OUTREG(pipeconf_reg, pipeconf);
POSTING_READ(pipeconf_reg);
i830WaitForVblank(pScrn);
+ if (IS_IGDNG(pI830)) {
+ /* 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);
@@ -1347,6 +1925,11 @@ i830_crtc_load_lut(xf86CrtcPtr crtc)
if (!crtc->enabled)
return;
+ /* use legacy palette for IGDNG */
+ if (IS_IGDNG(pI830))
+ 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) |
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 69704e6e..a0092ec8 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -919,7 +919,24 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
if (IS_MOBILE(pI830) && !IS_I830(pI830))
i830_lvds_init(pScrn);
- if (IS_I9XX(pI830)) {
+ if (IS_IGDNG(pI830)) {
+ int found;
+
+ if (INREG(HDMIB) & PORT_DETECTED) {
+ /* check SDVOB */
+ /* found = intel_sdvo_init(dev, HDMIB); */
+ found = 0;
+ if (!found)
+ i830_hdmi_init(pScrn, HDMIB);
+ }
+
+ if (INREG(HDMIC) & PORT_DETECTED)
+ i830_hdmi_init(pScrn, HDMIC);
+
+ if (INREG(HDMID) & PORT_DETECTED)
+ i830_hdmi_init(pScrn, HDMID);
+
+ } else if (IS_I9XX(pI830)) {
if (INREG(SDVOB) & SDVO_DETECTED) {
Bool found = i830_sdvo_init(pScrn, SDVOB);
@@ -936,7 +953,7 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
} else {
i830_dvo_init(pScrn);
}
- if (IS_I9XX(pI830) && IS_MOBILE(pI830))
+ if (IS_I9XX(pI830) && IS_MOBILE(pI830) && !IS_IGDNG(pI830))
i830_tv_init(pScrn);
for (o = 0; o < config->num_output; o++)
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index e8469616..ae75ab35 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -135,11 +135,16 @@ i830_lvds_set_backlight_native(xf86OutputPtr output, int level)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
- CARD32 blc_pwm_ctl;
+ CARD32 blc_pwm_ctl, reg;
- blc_pwm_ctl = INREG(BLC_PWM_CTL);
+ if (IS_IGDNG(pI830))
+ 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
@@ -159,8 +164,15 @@ i830_lvds_get_backlight_max_native(xf86OutputPtr output)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
- CARD32 pwm_ctl = INREG(BLC_PWM_CTL);
- int val;
+ CARD32 pwm_ctl;
+ int val, reg;
+
+ if (IS_IGDNG(pI830))
+ reg = BLC_PWM_PCH_CTL2;
+ else
+ reg = BLC_PWM_CTL;
+
+ val = INREG(BLC_PWM_CTL);
if (IS_I965GM(pI830) || IS_GM45(pI830)) {
val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK2) >>
@@ -370,7 +382,15 @@ i830SetLVDSPanelPower(xf86OutputPtr output, Bool on)
struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
- CARD32 pp_status;
+ CARD32 pp_status, ctl_reg, status_reg;
+
+ if (IS_IGDNG(pI830)) {
+ ctl_reg = PCH_PP_CONTROL;
+ status_reg = PCH_PP_STATUS;
+ } else {
+ ctl_reg = PP_CONTROL;
+ status_reg = PP_STATUS;
+ }
if (on) {
/*
@@ -380,13 +400,13 @@ 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)
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);
@@ -395,13 +415,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)
+ if (INREG(ctl_reg) & POWER_TARGET_ON)
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);
}
}
@@ -424,14 +444,30 @@ i830_lvds_save (xf86OutputPtr output)
struct i830_lvds_priv *dev_priv = intel_output->dev_priv;
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+ CARD32 pwm_ctl_reg;
+
+ if (IS_IGDNG(pI830)) {
+ 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 = LVDSPP_ON;
+ pp_off_reg = LVDSPP_OFF;
+ pp_ctl_reg = PP_CONTROL;
+ pp_div_reg = PP_CYCLE;
+ pwm_ctl_reg = BLC_PWM_CTL;
+ }
if (IS_I965GM(pI830) || IS_GM45(pI830))
pI830->saveBLC_PWM_CTL2 = INREG(BLC_PWM_CTL2);
- pI830->savePP_ON = INREG(LVDSPP_ON);
- pI830->savePP_OFF = INREG(LVDSPP_OFF);
- pI830->savePP_CONTROL = INREG(PP_CONTROL);
- pI830->savePP_CYCLE = INREG(PP_CYCLE);
- pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
+ pI830->savePP_ON = INREG(pp_on_reg);
+ pI830->savePP_OFF = INREG(pp_off_reg);
+ pI830->savePP_CONTROL = INREG(pp_ctl_reg);
+ pI830->savePP_CYCLE = INREG(pp_div_reg);
+ pI830->saveBLC_PWM_CTL = INREG(pwm_ctl_reg);
dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
}
@@ -440,14 +476,30 @@ i830_lvds_restore(xf86OutputPtr output)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
+ CARD32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+ CARD32 pwm_ctl_reg;
+
+ if (IS_IGDNG(pI830)) {
+ 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 = LVDSPP_ON;
+ pp_off_reg = LVDSPP_OFF;
+ pp_ctl_reg = PP_CONTROL;
+ pp_div_reg = PP_CYCLE;
+ pwm_ctl_reg = BLC_PWM_CTL;
+ }
if (IS_I965GM(pI830) || IS_GM45(pI830))
OUTREG(BLC_PWM_CTL2, pI830->saveBLC_PWM_CTL2);
- OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
- OUTREG(LVDSPP_ON, pI830->savePP_ON);
- OUTREG(LVDSPP_OFF, pI830->savePP_OFF);
- OUTREG(PP_CYCLE, pI830->savePP_CYCLE);
- OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
+ OUTREG(pwm_ctl_reg, pI830->saveBLC_PWM_CTL);
+ OUTREG(pp_on_reg, pI830->savePP_ON);
+ OUTREG(pp_off_reg, pI830->savePP_OFF);
+ OUTREG(pp_div_reg, pI830->savePP_CYCLE);
+ OUTREG(pp_ctl_reg, pI830->savePP_CONTROL);
if (pI830->savePP_CONTROL & POWER_TARGET_ON)
i830SetLVDSPanelPower(output, TRUE);
else
@@ -951,10 +1003,17 @@ i830_lvds_init(ScrnInfoPtr pScrn)
I830OutputPrivatePtr intel_output;
DisplayModePtr modes, scan, bios_mode;
struct i830_lvds_priv *dev_priv;
+ int gpio = GPIOC;
if (pI830->quirk_flag & QUIRK_IGNORE_LVDS)
return;
+ if (IS_IGDNG(pI830)) {
+ if ((INREG(PCH_LVDS) & LVDS_DETECTED) == 0)
+ return;
+ gpio = PCH_GPIOC;
+ }
+
output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS");
if (!output)
return;
@@ -980,7 +1039,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
/* Set up the LVDS DDC channel. Most panels won't support it, but it can
* be useful if available.
*/
- I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C");
+ I830I2CInit(pScrn, &intel_output->pDDCBus, gpio, "LVDSDDC_C");
/* Attempt to get the fixed panel mode from DDC. Assume that the preferred
* mode is the right one.
@@ -1007,7 +1066,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
/* If we didn't get EDID, try checking if the panel is already turned on.
* If so, assume that whatever is currently programmed is the correct mode.
*/
- if (dev_priv->panel_fixed_mode == NULL) {
+ if (dev_priv->panel_fixed_mode == NULL && !IS_IGDNG(pI830)) {
CARD32 lvds = INREG(LVDS);
int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
@@ -1118,6 +1177,19 @@ i830_lvds_init(ScrnInfoPtr pScrn)
dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
+ if (IS_IGDNG(pI830)) {
+ 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: