summaryrefslogtreecommitdiff
path: root/driver/xf86-video-intel/src/i830_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xf86-video-intel/src/i830_display.c')
-rw-r--r--driver/xf86-video-intel/src/i830_display.c765
1 files changed, 611 insertions, 154 deletions
diff --git a/driver/xf86-video-intel/src/i830_display.c b/driver/xf86-video-intel/src/i830_display.c
index 66990c2a5..dd1310fad 100644
--- a/driver/xf86-video-intel/src/i830_display.c
+++ b/driver/xf86-video-intel/src/i830_display.c
@@ -67,10 +67,13 @@ typedef struct {
#define INTEL_P2_NUM 2
-typedef struct {
+typedef struct intel_limit intel_limit_t;
+struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
-} intel_limit_t;
+ Bool (* find_pll)(const intel_limit_t *, xf86CrtcPtr,
+ int, int, intel_clock_t *);
+};
#define I8XX_DOT_MIN 25000
#define I8XX_DOT_MAX 350000
@@ -100,6 +103,8 @@ typedef struct {
#define I9XX_DOT_MAX 400000
#define I9XX_VCO_MIN 1400000
#define I9XX_VCO_MAX 2800000
+#define IGD_VCO_MIN 1700000
+#define IGD_VCO_MAX 3500000
/* Haven't found any reason to go this fast, but newer chips support it */
#define I96X_VCO_MAX 3200000
@@ -111,19 +116,31 @@ typedef struct {
*/
#define I9XX_N_MIN 1
#define I9XX_N_MAX 6
+/* IGD's Ncounter is a ring counter */
+#define IGD_N_MIN 3
+#define IGD_N_MAX 6
#define I9XX_M_MIN 70
#define I9XX_M_MAX 120
+#define IGD_M_MIN 2
+#define IGD_M_MAX 256
/* these two come from the calm1 macro */
#define I9XX_M1_MIN 10
#define I9XX_M1_MAX 22
#define I9XX_M2_MIN 5
#define I9XX_M2_MAX 9
+/* IGD M1 is reserved, and must be 0 */
+#define IGD_M1_MIN 0
+#define IGD_M1_MAX 0
+#define IGD_M2_MIN 0
+#define IGD_M2_MAX 254
#define I9XX_P_SDVO_DAC_MIN 5
#define I9XX_P_SDVO_DAC_MAX 80
#define I9XX_P_LVDS_MIN 7
#define I9XX_P_LVDS_MAX 98
+#define IGD_P_LVDS_MIN 7
+#define IGD_P_LVDS_MAX 112
#define I9XX_P1_MIN 1
#define I9XX_P1_MAX 8
#define I9XX_P2_SDVO_DAC_SLOW 10
@@ -137,6 +154,97 @@ typedef struct {
#define INTEL_LIMIT_I8XX_LVDS 1
#define INTEL_LIMIT_I9XX_SDVO_DAC 2
#define INTEL_LIMIT_I9XX_LVDS 3
+#define INTEL_LIMIT_IGD_SDVO_DAC 4
+#define INTEL_LIMIT_IGD_LVDS 5
+#define INTEL_LIMIT_G4X_SDVO 6
+#define INTEL_LIMIT_G4X_HDMI_DAC 7
+#define INTEL_LIMIT_G4X_SINGLE_LVDS 8
+#define INTEL_LIMIT_G4X_DUAL_LVDS 9
+
+/*The parameter is for SDVO on G4x platform*/
+#define G4X_VCO_MIN 1750000
+#define G4X_VCO_MAX 3500000
+#define G4X_DOT_SDVO_MIN 25000
+#define G4X_DOT_SDVO_MAX 270000
+#define G4X_N_SDVO_MIN 1
+#define G4X_N_SDVO_MAX 4
+#define G4X_M_SDVO_MIN 104
+#define G4X_M_SDVO_MAX 138
+#define G4X_M1_SDVO_MIN 17
+#define G4X_M1_SDVO_MAX 23
+#define G4X_M2_SDVO_MIN 5
+#define G4X_M2_SDVO_MAX 11
+#define G4X_P_SDVO_MIN 10
+#define G4X_P_SDVO_MAX 30
+#define G4X_P1_SDVO_MIN 1
+#define G4X_P1_SDVO_MAX 3
+#define G4X_P2_SDVO_SLOW 10
+#define G4X_P2_SDVO_FAST 10
+#define G4X_P2_SDVO_LIMIT 270000
+
+/*The parameter is for HDMI_DAC on G4x platform*/
+#define G4X_DOT_HDMI_DAC_MIN 22000
+#define G4X_DOT_HDMI_DAC_MAX 400000
+#define G4X_N_HDMI_DAC_MIN 1
+#define G4X_N_HDMI_DAC_MAX 4
+#define G4X_M_HDMI_DAC_MIN 104
+#define G4X_M_HDMI_DAC_MAX 138
+#define G4X_M1_HDMI_DAC_MIN 16
+#define G4X_M1_HDMI_DAC_MAX 23
+#define G4X_M2_HDMI_DAC_MIN 5
+#define G4X_M2_HDMI_DAC_MAX 11
+#define G4X_P_HDMI_DAC_MIN 5
+#define G4X_P_HDMI_DAC_MAX 80
+#define G4X_P1_HDMI_DAC_MIN 1
+#define G4X_P1_HDMI_DAC_MAX 8
+#define G4X_P2_HDMI_DAC_SLOW 10
+#define G4X_P2_HDMI_DAC_FAST 5
+#define G4X_P2_HDMI_DAC_LIMIT 165000
+
+/*The parameter is for SINGLE_LVDS on G4x platform*/
+#define G4X_DOT_SINGLE_LVDS_MIN 20000
+#define G4X_DOT_SINGLE_LVDS_MAX 115000
+#define G4X_N_SINGLE_LVDS_MIN 1
+#define G4X_N_SINGLE_LVDS_MAX 3
+#define G4X_M_SINGLE_LVDS_MIN 104
+#define G4X_M_SINGLE_LVDS_MAX 138
+#define G4X_M1_SINGLE_LVDS_MIN 17
+#define G4X_M1_SINGLE_LVDS_MAX 23
+#define G4X_M2_SINGLE_LVDS_MIN 5
+#define G4X_M2_SINGLE_LVDS_MAX 11
+#define G4X_P_SINGLE_LVDS_MIN 28
+#define G4X_P_SINGLE_LVDS_MAX 112
+#define G4X_P1_SINGLE_LVDS_MIN 2
+#define G4X_P1_SINGLE_LVDS_MAX 8
+#define G4X_P2_SINGLE_LVDS_SLOW 14
+#define G4X_P2_SINGLE_LVDS_FAST 14
+#define G4X_P2_SINGLE_LVDS_LIMIT 0
+
+/*The parameter is for DUAL_LVDS on G4x platform*/
+#define G4X_DOT_DUAL_LVDS_MIN 80000
+#define G4X_DOT_DUAL_LVDS_MAX 224000
+#define G4X_N_DUAL_LVDS_MIN 1
+#define G4X_N_DUAL_LVDS_MAX 3
+#define G4X_M_DUAL_LVDS_MIN 104
+#define G4X_M_DUAL_LVDS_MAX 138
+#define G4X_M1_DUAL_LVDS_MIN 17
+#define G4X_M1_DUAL_LVDS_MAX 23
+#define G4X_M2_DUAL_LVDS_MIN 5
+#define G4X_M2_DUAL_LVDS_MAX 11
+#define G4X_P_DUAL_LVDS_MIN 14
+#define G4X_P_DUAL_LVDS_MAX 42
+#define G4X_P1_DUAL_LVDS_MIN 2
+#define G4X_P1_DUAL_LVDS_MAX 6
+#define G4X_P2_DUAL_LVDS_SLOW 7
+#define G4X_P2_DUAL_LVDS_FAST 7
+#define G4X_P2_DUAL_LVDS_LIMIT 0
+
+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 const intel_limit_t intel_limits[] = {
{ /* INTEL_LIMIT_I8XX_DVO_DAC */
@@ -150,6 +258,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX },
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
},
{ /* INTEL_LIMIT_I8XX_LVDS */
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
@@ -162,6 +271,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX },
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
},
{ /* INTEL_LIMIT_I9XX_SDVO_DAC */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
@@ -174,6 +284,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
},
{ /* INTEL_LIMIT_I9XX_LVDS */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
@@ -189,20 +300,150 @@ static const intel_limit_t intel_limits[] = {
*/
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
+ },
+ { /* INTEL_LIMIT_IGD_SDVO */
+ .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
+ .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
+ .n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
+ .m = { .min = IGD_M_MIN, .max = IGD_M_MAX },
+ .m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX },
+ .m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX },
+ .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX },
+ .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
+ .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
+ .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
+ },
+ { /* INTEL_LIMIT_IGD_LVDS */
+ .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
+ .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
+ .n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
+ .m = { .min = IGD_M_MIN, .max = IGD_M_MAX },
+ .m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX },
+ .m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX },
+ .p = { .min = IGD_P_LVDS_MIN, .max = IGD_P_LVDS_MAX },
+ .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
+ /* IGD only supports single-channel mode. */
+ .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
+ .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
+ .find_pll = intel_find_pll_i8xx_and_i9xx,
+ },
+ /* below parameter and function is for G4X Chipset Family*/
+ { /* INTEL_LIMIT_G4X_SDVO */
+ .dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX },
+ .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
+ .n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX },
+ .m = { .min = G4X_M_SDVO_MIN, .max = G4X_M_SDVO_MAX },
+ .m1 = { .min = G4X_M1_SDVO_MIN, .max = G4X_M1_SDVO_MAX },
+ .m2 = { .min = G4X_M2_SDVO_MIN, .max = G4X_M2_SDVO_MAX },
+ .p = { .min = G4X_P_SDVO_MIN, .max = G4X_P_SDVO_MAX },
+ .p1 = { .min = G4X_P1_SDVO_MIN, .max = G4X_P1_SDVO_MAX},
+ .p2 = { .dot_limit = G4X_P2_SDVO_LIMIT,
+ .p2_slow = G4X_P2_SDVO_SLOW,
+ .p2_fast = G4X_P2_SDVO_FAST },
+ .find_pll = intel_find_pll_g4x,
+ },
+ { /* INTEL_LIMIT_G4X_HDMI_DAC */
+ .dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX },
+ .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
+ .n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX },
+ .m = { .min = G4X_M_HDMI_DAC_MIN, .max = G4X_M_HDMI_DAC_MAX },
+ .m1 = { .min = G4X_M1_HDMI_DAC_MIN, .max = G4X_M1_HDMI_DAC_MAX },
+ .m2 = { .min = G4X_M2_HDMI_DAC_MIN, .max = G4X_M2_HDMI_DAC_MAX },
+ .p = { .min = G4X_P_HDMI_DAC_MIN, .max = G4X_P_HDMI_DAC_MAX },
+ .p1 = { .min = G4X_P1_HDMI_DAC_MIN, .max = G4X_P1_HDMI_DAC_MAX},
+ .p2 = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT,
+ .p2_slow = G4X_P2_HDMI_DAC_SLOW,
+ .p2_fast = G4X_P2_HDMI_DAC_FAST },
+ .find_pll = intel_find_pll_g4x,
+ },
+ { /* INTEL_LIMIT_G4X_SINGLE_LVDS */
+ .dot = { .min = G4X_DOT_SINGLE_LVDS_MIN,
+ .max = G4X_DOT_SINGLE_LVDS_MAX },
+ .vco = { .min = G4X_VCO_MIN,
+ .max = G4X_VCO_MAX },
+ .n = { .min = G4X_N_SINGLE_LVDS_MIN,
+ .max = G4X_N_SINGLE_LVDS_MAX },
+ .m = { .min = G4X_M_SINGLE_LVDS_MIN,
+ .max = G4X_M_SINGLE_LVDS_MAX },
+ .m1 = { .min = G4X_M1_SINGLE_LVDS_MIN,
+ .max = G4X_M1_SINGLE_LVDS_MAX },
+ .m2 = { .min = G4X_M2_SINGLE_LVDS_MIN,
+ .max = G4X_M2_SINGLE_LVDS_MAX },
+ .p = { .min = G4X_P_SINGLE_LVDS_MIN,
+ .max = G4X_P_SINGLE_LVDS_MAX },
+ .p1 = { .min = G4X_P1_SINGLE_LVDS_MIN,
+ .max = G4X_P1_SINGLE_LVDS_MAX },
+ .p2 = { .dot_limit = G4X_P2_SINGLE_LVDS_LIMIT,
+ .p2_slow = G4X_P2_SINGLE_LVDS_SLOW,
+ .p2_fast = G4X_P2_SINGLE_LVDS_FAST },
+ .find_pll = intel_find_pll_g4x,
+ },
+ { /* INTEL_LIMIT_G4X_DUAL_LVDS */
+ .dot = { .min = G4X_DOT_DUAL_LVDS_MIN,
+ .max = G4X_DOT_DUAL_LVDS_MAX },
+ .vco = { .min = G4X_VCO_MIN,
+ .max = G4X_VCO_MAX},
+ .n = { .min = G4X_N_DUAL_LVDS_MIN,
+ .max = G4X_N_DUAL_LVDS_MAX },
+ .m = { .min = G4X_M_DUAL_LVDS_MIN,
+ .max = G4X_M_DUAL_LVDS_MAX },
+ .m1 = { .min = G4X_M1_DUAL_LVDS_MIN,
+ .max = G4X_M1_DUAL_LVDS_MAX },
+ .m2 = { .min = G4X_M2_DUAL_LVDS_MIN,
+ .max = G4X_M2_DUAL_LVDS_MAX },
+ .p = { .min = G4X_P_DUAL_LVDS_MIN,
+ .max = G4X_P_DUAL_LVDS_MAX },
+ .p1 = { .min = G4X_P1_DUAL_LVDS_MIN,
+ .max = G4X_P1_DUAL_LVDS_MAX},
+ .p2 = { .dot_limit = G4X_P2_DUAL_LVDS_LIMIT,
+ .p2_slow = G4X_P2_DUAL_LVDS_SLOW,
+ .p2_fast = G4X_P2_DUAL_LVDS_FAST },
+ .find_pll = intel_find_pll_g4x,
},
};
+static const intel_limit_t *intel_limit_g4x (xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ const intel_limit_t *limit;
+
+ if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) {
+ if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) {
+ /* LVDS with dual channel */
+ limit = &intel_limits[INTEL_LIMIT_G4X_DUAL_LVDS];
+ } else /* LVDS with single channel */
+ limit = &intel_limits[INTEL_LIMIT_G4X_SINGLE_LVDS];
+ } else if (i830PipeHasType (crtc, I830_OUTPUT_HDMI) ||
+ i830PipeHasType (crtc, I830_OUTPUT_ANALOG)) {
+ limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
+ } else if (i830PipeHasType (crtc, I830_OUTPUT_SDVO)) {
+ limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
+ } else /* The option is for other outputs */
+ limit = &intel_limits[INTEL_LIMIT_I9XX_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_G4X(pI830)) {
+ limit = intel_limit_g4x(crtc);
+ } else if (IS_I9XX(pI830) && !IS_IGD(pI830)) {
if (i830PipeHasType (crtc, I830_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
else
limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+ } else if (IS_IGD(pI830)) {
+ if (i830PipeHasType (crtc, I830_OUTPUT_LVDS))
+ limit = &intel_limits[INTEL_LIMIT_IGD_LVDS];
+ else
+ limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC];
} else {
if (i830PipeHasType (crtc, I830_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
@@ -233,11 +474,23 @@ static void i9xx_clock(int refclk, intel_clock_t *clock)
clock->dot = clock->vco / clock->p;
}
+/* m1 is reserved as 0 in IGD, n is a ring counter */
+static void igd_clock(int refclk, intel_clock_t *clock)
+{
+ clock->m = clock->m2 + 2;
+ clock->p = clock->p1 * clock->p2;
+ clock->vco = refclk * clock->m / clock->n;
+ clock->dot = clock->vco / clock->p;
+}
+
static void intel_clock(I830Ptr pI830, int refclk, intel_clock_t *clock)
{
- if (IS_I9XX(pI830))
- i9xx_clock (refclk, clock);
- else
+ if (IS_I9XX(pI830)) {
+ if (IS_IGD(pI830))
+ igd_clock(refclk, clock);
+ else
+ i9xx_clock (refclk, clock);
+ } else
i8xx_clock (refclk, clock);
}
@@ -286,6 +539,8 @@ static Bool
i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock)
{
const intel_limit_t *limit = intel_limit (crtc);
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
i830PllInvalid ("p1 out of range\n");
@@ -295,7 +550,7 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock)
i830PllInvalid ("m2 out of range\n");
if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
i830PllInvalid ("m1 out of range\n");
- if (clock->m1 <= clock->m2)
+ if (clock->m1 <= clock->m2 && !IS_IGD(pI830))
i830PllInvalid ("m1 <= m2\n");
if (clock->m < limit->m.min || limit->m.max < clock->m)
i830PllInvalid ("m out of range\n");
@@ -312,18 +567,13 @@ i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock)
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:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- */
static Bool
-i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_clock)
+intel_find_pll_i8xx_and_i9xx(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;
- const intel_limit_t *limit = intel_limit (crtc);
+ intel_clock_t clock;
int err = target;
if (i830PipeHasType(crtc, I830_OUTPUT_LVDS))
@@ -347,8 +597,11 @@ i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_cl
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++)
{
- for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; clock.m2++)
+ for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++)
{
+ /* m1 is always 0 in IGD */
+ if (clock.m2 >= clock.m1 && !IS_IGD(pI830))
+ break;
for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++)
{
for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++)
@@ -372,6 +625,64 @@ i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_cl
return (err != target);
}
+static Bool
+intel_find_pll_g4x(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 max_n;
+ Bool found = FALSE;
+ int err_most = target * 0.0048;
+
+ if (i830PipeHasType(crtc, I830_OUTPUT_LVDS))
+ {
+ /* For LVDS, if the panel is on, just rely on its current settings for
+ * dual-channel. We haven't figured out how to reliably set up
+ * different single/dual channel state, if we even can.
+ */
+ if ((INREG(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;
+ }
+
+ max_n = limit->n.max;
+ /* based on hardware requirement prefer smaller n to precision */
+ for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+ /* based on hardware requirement prefere larger m1,m2, p1*/
+ for (clock.m1 = limit->m1.max;
+ clock.m1 >= limit->m1.min; clock.m1--) {
+ for (clock.m2 = limit->m2.max;
+ clock.m2 >= limit->m2.min; clock.m2--) {
+ for (clock.p1 = limit->p1.max;
+ clock.p1 >= limit->p1.min; clock.p1--) {
+ int this_err;
+
+ intel_clock (pI830, refclk, &clock);
+ if (!i830PllIsValid(crtc, &clock))
+ continue;
+ this_err = abs(clock.dot - target) ;
+ if (this_err < err_most) {
+ memcpy(best_clock, &clock, sizeof(intel_clock_t));
+ err_most = this_err;
+ /* prefer smaller n to precision */
+ max_n = clock.n;
+ found = TRUE;
+ }
+ }
+ }
+ }
+ }
+ return found;
+}
+
void
i830WaitForVblank(ScrnInfoPtr pScreen)
{
@@ -387,12 +698,14 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- unsigned long Start, Offset;
+ unsigned long Start, Offset, Stride;
int dspbase = (plane == 0 ? DSPABASE : DSPBBASE);
int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
+ int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
Offset = ((y * pScrn->displayWidth + x) * pI830->cpp);
+ Stride = pScrn->displayWidth * pI830->cpp;
if (pI830->front_buffer == NULL) {
/* During startup we may be called as part of monitor detection while
* there is no memory allocation done, so just supply a dummy base
@@ -403,13 +716,15 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
/* offset is done by shadow painting code, not here */
Start = (char *)crtc->rotatedData - (char *)pI830->FbBase;
Offset = 0;
- } else if (I830IsPrimary(pScrn)) {
- Start = pI830->front_buffer->offset;
+ Stride = intel_crtc->rotate_mem->pitch;
} else {
- I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
- Start = pI8301->front_buffer_2->offset;
+ Start = pI830->front_buffer->offset;
}
+ crtc->x = x;
+ crtc->y = y;
+
+ OUTREG(dspstride, Stride);
if (IS_I965G(pI830)) {
OUTREG(dspbase, Offset);
POSTING_READ(dspbase);
@@ -422,20 +737,20 @@ i830PipeSetBase(xf86CrtcPtr crtc, int x, int y)
}
#ifdef XF86DRI
- if (pI830->directRenderingEnabled) {
+ if (pI830->directRenderingType == DRI_XF86DRI) {
drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen);
if (!sPriv)
return;
- switch (plane) {
+ switch (pipe) {
case 0:
- sPriv->planeA_x = x;
- sPriv->planeA_y = y;
+ sPriv->pipeA_x = x;
+ sPriv->pipeA_y = y;
break;
case 1:
- sPriv->planeB_x = x;
- sPriv->planeB_y = y;
+ sPriv->pipeB_x = x;
+ sPriv->pipeB_y = y;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
@@ -745,7 +1060,7 @@ i830_use_fb_compression(xf86CrtcPtr crtc)
return TRUE;
}
-#if defined(DRM_IOCTL_MODESET_CTL) && defined(XF86DRI)
+#if defined(DRM_IOCTL_MODESET_CTL) && (defined(XF86DRI) || defined(DRI2))
static void i830_modeset_ctl(xf86CrtcPtr crtc, int pre)
{
ScrnInfoPtr pScrn = crtc->scrn;
@@ -753,10 +1068,10 @@ static void i830_modeset_ctl(xf86CrtcPtr crtc, int pre)
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
struct drm_modeset_ctl modeset;
- if (!pI830->directRenderingEnabled)
- return;
+ if (pI830->directRenderingType <= DRI_NONE)
+ return;
- modeset.crtc = intel_crtc->plane;
+ modeset.crtc = intel_crtc->pipe;
/*
* DPMS will be called many times (especially off), but we only
@@ -777,16 +1092,40 @@ static void i830_modeset_ctl(xf86CrtcPtr crtc, int dpms_state)
{
return;
}
-#endif /* DRM_IOCTL_MODESET_CTL && XF86DRI */
+#endif /* DRM_IOCTL_MODESET_CTL && (XF86DRI || DRI2) */
-/**
- * Sets the power management mode of the pipe and plane.
- *
- * This code should probably grow support for turning the cursor off and back
- * on appropriately at the same time as we're turning the pipe off/on.
- */
static void
-i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+i830_disable_vga_plane (xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ uint32_t vgacntrl = INREG(VGACNTRL);
+ uint8_t sr01;
+
+ if (vgacntrl & VGA_DISP_DISABLE)
+ return;
+
+ /*
+ Set bit 5 of SR01;
+ Wait 30us;
+ */
+ OUTREG8(SRX, 1);
+ sr01 = INREG8(SRX + 1);
+ OUTREG8(SRX + 1, sr01 | (1 << 5));
+ usleep(30);
+ /* disable center mode on 965GM and G4X platform */
+ if (IS_I965GM(pI830) || IS_G4X(pI830))
+ vgacntrl &= ~(3 << 24);
+
+ vgacntrl |= VGA_DISP_DISABLE;
+
+ OUTREG(VGACNTRL, vgacntrl);
+ i830WaitForVblank(pScrn);
+
+}
+
+void
+i830_crtc_enable(xf86CrtcPtr crtc)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830Ptr pI830 = I830PTR(pScrn);
@@ -799,110 +1138,155 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
uint32_t temp;
- /* XXX: When our outputs are all unaware of DPMS modes other than off and
- * on, we should map those modes to DPMSModeOff in the CRTC.
- */
- switch (mode) {
- case DPMSModeOn:
- case DPMSModeStandby:
- case DPMSModeSuspend:
- /* Enable the DPLL */
- temp = INREG(dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) == 0)
- {
- OUTREG(dpll_reg, temp);
- POSTING_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- usleep(150);
- OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
- POSTING_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- usleep(150);
- OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
- POSTING_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- usleep(150);
- }
+ /* Enable the DPLL */
+ temp = INREG(dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) == 0)
+ {
+ OUTREG(dpll_reg, temp);
+ POSTING_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ usleep(150);
+ OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
+ POSTING_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ usleep(150);
+ OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
+ POSTING_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ usleep(150);
+ }
- /* Enable the pipe */
- temp = INREG(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) == 0)
- OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ /* Enable the pipe */
+ temp = INREG(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) == 0)
+ OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
- /* Enable the 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 the 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));
+ }
- i830_crtc_load_lut(crtc);
+ i830_crtc_load_lut(crtc);
- /* Give the overlay scaler a chance to enable if it's on this pipe */
- i830_crtc_dpms_video(crtc, TRUE);
+ /* Give the overlay scaler a chance to enable if it's on this pipe */
+ i830_crtc_dpms_video(crtc, TRUE);
- /* Reenable compression if needed */
- if (i830_use_fb_compression(crtc))
- i830_enable_fb_compression(crtc);
- i830_modeset_ctl(crtc, 0);
- break;
- case DPMSModeOff:
- i830_modeset_ctl(crtc, 1);
- /* Shut off compression if in use */
- if (i830_use_fb_compression(crtc))
- i830_disable_fb_compression(crtc);
+ /* Reenable compression if needed */
+ if (i830_use_fb_compression(crtc))
+ i830_enable_fb_compression(crtc);
+ i830_modeset_ctl(crtc, 0);
+}
- /* Give the overlay scaler a chance to disable if it's on this pipe */
- i830_crtc_dpms_video(crtc, FALSE);
+void
+i830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe)
+{
+ 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 dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
+ int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE;
+ uint32_t temp;
- /* Disable the VGA plane that we never use */
- OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+ i830_modeset_ctl(crtc, 1);
+ /* Shut off compression if in use */
+ if (i830_use_fb_compression(crtc))
+ i830_disable_fb_compression(crtc);
- /* May need to leave pipe A on */
- if ((pipe != 0) || !(pI830->quirk_flag & QUIRK_PIPEA_FORCE))
- {
- /* 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));
- POSTING_READ(dspbase_reg);
- }
+ /* Give the overlay scaler a chance to disable if it's on this pipe */
+ i830_crtc_dpms_video(crtc, FALSE);
- if (!IS_I9XX(pI830)) {
- /* Wait for vblank for the disable to take effect */
- i830WaitForVblank(pScrn);
- }
+ /*
+ * The documentation says :
+ * - Disable planes (VGA or hires)
+ * - Disable pipe
+ * - Disable VGA display
+ */
- /* Next, disable display pipes */
- temp = INREG(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- POSTING_READ(pipeconf_reg);
- }
+ /* 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));
+ POSTING_READ(dspbase_reg);
+ }
- /* Wait for vblank for the disable to take effect. */
- i830WaitForVblank(pScrn);
+ if (!IS_I9XX(pI830)) {
+ /* Wait for vblank for the disable to take effect */
+ i830WaitForVblank(pScrn);
+ }
- temp = INREG(dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) != 0) {
- OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- POSTING_READ(dpll_reg);
- }
+ /* May need to leave pipe A on */
+ if (disable_pipe)
+ {
+ /* Next, disable display pipes */
+ temp = INREG(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) != 0) {
+ OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+ POSTING_READ(pipeconf_reg);
}
+
+ /* Wait for vblank for the disable to take effect. */
+ i830WaitForVblank(pScrn);
+
+ temp = INREG(dpll_reg);
+ if ((temp & DPLL_VCO_ENABLE) != 0) {
+ OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+ POSTING_READ(dpll_reg);
+ }
+
/* Wait for the clocks to turn off. */
usleep(150);
+ }
+
+ /* Disable the VGA plane that we never use. */
+ i830_disable_vga_plane (crtc);
+}
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void
+i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ int pipe = intel_crtc->pipe;
+ Bool disable_pipe = TRUE;
+
+ /* XXX: When our outputs are all unaware of DPMS modes other than off and
+ * on, we should map those modes to DPMSModeOff in the CRTC.
+ */
+ switch (mode) {
+ case DPMSModeOn:
+ case DPMSModeStandby:
+ case DPMSModeSuspend:
+ i830_crtc_enable(crtc);
+ break;
+ case DPMSModeOff:
+ if ((pipe == 0) && (pI830->quirk_flag & QUIRK_PIPEA_FORCE))
+ disable_pipe = FALSE;
+ i830_crtc_disable(crtc, disable_pipe);
break;
}
intel_crtc->dpms_mode = mode;
#ifdef XF86DRI
- if (pI830->directRenderingEnabled) {
+ if (pI830->directRenderingType == DRI_XF86DRI) {
drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen);
Bool enabled = crtc->enabled && mode != DPMSModeOff;
@@ -911,14 +1295,14 @@ i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
if (!sPriv)
return;
- switch (plane) {
+ switch (pipe) {
case 0:
- sPriv->planeA_w = enabled ? crtc->mode.HDisplay : 0;
- sPriv->planeA_h = enabled ? crtc->mode.VDisplay : 0;
+ sPriv->pipeA_w = enabled ? crtc->mode.HDisplay : 0;
+ sPriv->pipeA_h = enabled ? crtc->mode.VDisplay : 0;
break;
case 1:
- sPriv->planeB_w = enabled ? crtc->mode.HDisplay : 0;
- sPriv->planeB_h = enabled ? crtc->mode.VDisplay : 0;
+ sPriv->pipeB_w = enabled ? crtc->mode.HDisplay : 0;
+ sPriv->pipeB_h = enabled ? crtc->mode.VDisplay : 0;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
@@ -982,6 +1366,11 @@ i830_crtc_commit (xf86CrtcPtr crtc)
/* Reenable FB compression if possible */
if (i830_use_fb_compression(crtc))
i830_enable_fb_compression(crtc);
+
+#ifdef XF86DRI
+ /* Tell DRI1 the news about new output config */
+ i830_update_dri_buffers(crtc->scrn);
+#endif
}
void
@@ -1012,11 +1401,11 @@ i830_get_core_clock_speed(ScrnInfoPtr pScrn)
/* Core clock values taken from the published datasheets.
* The 830 may go up to 166 Mhz, which we should check.
*/
- if (IS_I945G(pI830) || IS_G33CLASS(pI830))
+ if (IS_I945G(pI830) || (IS_G33CLASS(pI830) && !IS_IGDGM(pI830)))
return 400000;
else if (IS_I915G(pI830))
return 333000;
- else if (IS_I945GM(pI830) || IS_845G(pI830))
+ else if (IS_I945GM(pI830) || IS_845G(pI830) || IS_IGDGM(pI830))
return 200000;
else if (IS_I915GM(pI830)) {
uint16_t gcfgc;
@@ -1116,7 +1505,7 @@ i830_update_dsparb(ScrnInfoPtr pScrn)
/*
* FIFO entries will be split based on programmed modes
*/
- if (IS_I965GM(pI830) || IS_GM45(pI830))
+ if (IS_I965GM(pI830))
fifo_entries = 127;
else if (IS_I9XX(pI830))
fifo_entries = 95;
@@ -1189,16 +1578,15 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
- int dspstride_reg = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
- int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT;
int i, num_outputs = 0;
int refclk;
intel_clock_t clock;
uint32_t dpll = 0, fp = 0, dspcntr, pipeconf, lvds_bits = 0;
Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
+ const intel_limit_t *limit;
/* Set up some convenient bools for what outputs are connected to
* our pipe, used in DPLL setup.
@@ -1251,7 +1639,13 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
refclk = 48000;
}
- ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &clock);
+ /*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE. The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+ limit = intel_limit (crtc);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->Clock, refclk, &clock);
if (!ok)
FatalError("Couldn't find PLL settings for mode!\n");
@@ -1263,7 +1657,30 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
(float)adjusted_mode->Clock / 1000);
}
- fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+ /* SDVO TV has fixed PLL values depends on its clock range,
+ this mirrors vbios setting. */
+ if (is_sdvo && is_tv) {
+ if (adjusted_mode->Clock >= 100000 &&
+ adjusted_mode->Clock < 140500) {
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.n = 3;
+ clock.m1 = 16;
+ clock.m2 = 8;
+ } else if (adjusted_mode->Clock >= 140500 &&
+ adjusted_mode->Clock <= 200000) {
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.n = 6;
+ clock.m1 = 12;
+ clock.m2 = 8;
+ }
+ }
+
+ if (IS_IGD(pI830))
+ 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_I9XX(pI830)) {
@@ -1274,8 +1691,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
if (is_sdvo)
{
dpll |= DPLL_DVO_HIGH_SPEED;
- if ((IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) &&
- !is_tv)
+ 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;
@@ -1283,7 +1699,10 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
}
/* compute bitmask from p1 value */
- dpll |= (1 << (clock.p1 - 1)) << 16;
+ if (IS_IGD(pI830))
+ dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD;
+ else
+ dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
switch (clock.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -1485,7 +1904,6 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
((adjusted_mode->CrtcVBlankEnd - 1) << 16));
OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) |
((adjusted_mode->CrtcVSyncEnd - 1) << 16));
- OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
/* pipesrc and dspsize control the size that is scaled from, which should
* always be the user's requested size.
*/
@@ -1504,9 +1922,6 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
#endif
i830WaitForVblank(pScrn);
-
- /* Clear any FIFO underrun status that may have occurred normally */
- OUTREG(pipestat_reg, INREG(pipestat_reg) | FIFO_UNDERRUN);
}
@@ -1565,12 +1980,14 @@ i830_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
unsigned long rotate_pitch;
int align = KB(4), size;
- rotate_pitch = pScrn->displayWidth * pI830->cpp;
+ width = i830_pad_drawable_width(width, pI830->cpp);
+ rotate_pitch = width * pI830->cpp;
size = rotate_pitch * height;
assert(intel_crtc->rotate_mem == NULL);
intel_crtc->rotate_mem = i830_allocate_memory(pScrn, "rotated crtc",
- size, align, 0);
+ size, rotate_pitch, align,
+ 0, TILE_NONE);
if (intel_crtc->rotate_mem == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow memory for rotated CRTC\n");
@@ -1588,14 +2005,15 @@ static PixmapPtr
i830_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
{
ScrnInfoPtr pScrn = crtc->scrn;
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
I830Ptr pI830 = I830PTR(pScrn);
- unsigned long rotate_pitch;
+ int rotate_pitch;
PixmapPtr rotate_pixmap;
if (!data)
data = i830_crtc_shadow_allocate (crtc, width, height);
- rotate_pitch = pScrn->displayWidth * pI830->cpp;
+ rotate_pitch = i830_pad_drawable_width(width, pI830->cpp) * pI830->cpp;
rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
width, height,
@@ -1608,6 +2026,8 @@ i830_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow pixmap for rotated CRTC\n");
}
+ if (intel_crtc->rotate_mem && intel_crtc->rotate_mem->bo)
+ i830_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_mem->bo);
return rotate_pixmap;
}
@@ -1628,6 +2048,31 @@ i830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
}
}
+#if RANDR_13_INTERFACE
+static void
+i830_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
+{
+ if (crtc->enabled)
+ i830PipeSetBase(crtc, x, y);
+}
+#endif
+
+/* The screen bo has changed, reset each active crtc to point at
+ * the same location that it currently points at, but in the new bo
+ */
+void
+i830_set_new_crtc_bo(ScrnInfoPtr pScrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[i];
+
+ if (crtc->enabled && !crtc->transform_in_use)
+ i830PipeSetBase(crtc, crtc->x, crtc->y);
+ }
+}
void
i830DescribeOutputConfiguration(ScrnInfoPtr pScrn)
@@ -1829,11 +2274,20 @@ i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc)
fp = INREG((pipe == 0) ? FPA1 : FPB1);
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
- clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
- clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+ if (IS_IGD(pI830)) {
+ clock.n = ffs((fp & FP_N_IGD_DIV_MASK) >> FP_N_DIV_SHIFT) - 1;
+ clock.m2 = (fp & FP_M2_IGD_DIV_MASK) >> FP_M2_DIV_SHIFT;
+ } else {
+ clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+ clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
+ }
if (IS_I9XX(pI830)) {
- clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
- DPLL_FPA01_P1_POST_DIV_SHIFT);
+ if (IS_IGD(pI830))
+ clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_IGD) >>
+ DPLL_FPA01_P1_POST_DIV_SHIFT_IGD);
+ else
+ clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
+ DPLL_FPA01_P1_POST_DIV_SHIFT);
switch (dpll & DPLL_MODE_MASK) {
case DPLLB_MODE_DAC_SERIAL:
@@ -1850,9 +2304,9 @@ i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc)
}
if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
- i9xx_clock(100000, &clock);
+ intel_clock(pI830, 100000, &clock);
else
- i9xx_clock(96000, &clock);
+ intel_clock(pI830, 96000, &clock);
} else {
Bool is_lvds = (pipe == 1) && (INREG(LVDS) & LVDS_PORT_EN);
@@ -1867,9 +2321,9 @@ i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc)
clock.p2 = 14;
if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
- i8xx_clock(66000, &clock); /* XXX: might not be 66MHz */
+ intel_clock(pI830, 66000, &clock); /* XXX: might not be 66MHz */
else
- i8xx_clock(48000, &clock);
+ intel_clock(pI830, 48000, &clock);
} else {
if (dpll & PLL_P1_DIVIDE_BY_TWO) {
clock.p1 = 2;
@@ -1882,7 +2336,7 @@ i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc)
else
clock.p2 = 2;
- i8xx_clock(48000, &clock);
+ intel_clock(pI830, 48000, &clock);
}
}
@@ -1949,6 +2403,9 @@ static const xf86CrtcFuncsRec i830_crtc_funcs = {
/* .load_cursor_image = i830_crtc_load_cursor_image, */
.load_cursor_argb = i830_crtc_load_cursor_argb,
.destroy = NULL, /* XXX */
+#if RANDR_13_INTERFACE
+ .set_origin = i830_crtc_set_origin,
+#endif
};
void