From 7258b11d2e9a47d2b01620622579f22906960e1a Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 20 Mar 2006 20:02:24 +1100
Subject: [PATCH 01/25] intelfb: prepare for i9xx support.

This code just moves the PLL min/max calculations variables into
a structure, it doesn't change or add any new functionality.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 102 ++++++++++++++++++------------
 drivers/video/intelfb/intelfbhw.h |  15 -----
 2 files changed, 63 insertions(+), 54 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 624c4bc96f0d2..a3a94642b79bd 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -40,6 +40,26 @@
 #include "intelfb.h"
 #include "intelfbhw.h"
 
+struct pll_min_max {
+	int min_m, max_m;
+	int min_m1, max_m1;
+	int min_m2, max_m2;
+	int min_n, max_n;
+	int min_p, max_p;
+	int min_p1, max_p1;
+	int min_vco_freq, max_vco_freq;
+	int p_transition_clock;
+};
+
+#define PLLS_I8xx 0
+#define PLLS_I9xx 1
+#define PLLS_MAX 2
+
+struct pll_min_max plls[PLLS_MAX] = {
+	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000 }, //I8xx
+	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000 }  //I9xx
+};
+
 int
 intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
 		      int *mobile)
@@ -697,17 +717,17 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 
 /* Split the M parameter into M1 and M2. */
 static int
-splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 {
 	int m1, m2;
 
-	m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
-	if (m1 < MIN_M1)
-		m1 = MIN_M1;
-	if (m1 > MAX_M1)
-		m1 = MAX_M1;
+	m1 = (m - 2 - (plls[index].min_m1 + plls[index].max_m2) / 2) / 5 - 2;
+	if (m1 < plls[index].min_m1)
+		m1 = plls[index].min_m1;
+	if (m1 > plls[index].max_m1)
+		m1 = plls[index].max_m1;
 	m2 = m - 5 * (m1 + 2) - 2;
-	if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
+	if (m2 < plls[index].min_m2 || m2 > plls[index].max_m2 || m2 >= m1) {
 		return 1;
 	} else {
 		*retm1 = (unsigned int)m1;
@@ -718,30 +738,34 @@ splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
 
 /* Split the P parameter into P1 and P2. */
 static int
-splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 {
 	int p1, p2;
 
-	if (p % 4 == 0)
-		p2 = 1;
-	else
-		p2 = 0;
-	p1 = (p / (1 << (p2 + 1))) - 2;
-	if (p % 4 == 0 && p1 < MIN_P1) {
-		p2 = 0;
+	if (index==PLLS_I8xx)
+	{
+		if (p % 4 == 0)
+			p2 = 1;
+		else
+			p2 = 0;
 		p1 = (p / (1 << (p2 + 1))) - 2;
+		if (p % 4 == 0 && p1 < plls[index].min_p1) {
+			p2 = 0;
+			p1 = (p / (1 << (p2 + 1))) - 2;
+		}
+		if (p1  < plls[index].min_p1 || p1 > plls[index].max_p1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+			return 1;
+		} else {
+			*retp1 = (unsigned int)p1;
+			*retp2 = (unsigned int)p2;
+			return 0;
+		}
 	}
-	if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
-		return 1;
-	} else {
-		*retp1 = (unsigned int)p1;
-		*retp2 = (unsigned int)p2;
-		return 0;
-	}
+	return 1;
 }
 
 static int
-calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 		u32 *retp2, u32 *retclock)
 {
 	u32 m1, m2, n, p1, p2, n1;
@@ -756,40 +780,40 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 
 	DBG_MSG("Clock is %d\n", clock);
 
-	div_max = MAX_VCO_FREQ / clock;
-	div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+	div_max = plls[index].max_vco_freq / clock;
+	div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
 
-	if (clock <= P_TRANSITION_CLOCK)
+	if (clock <= plls[index].p_transition_clock)
 		p_inc = 4;
 	else
 		p_inc = 2;
 	p_min = ROUND_UP_TO(div_min, p_inc);
 	p_max = ROUND_DOWN_TO(div_max, p_inc);
-	if (p_min < MIN_P)
+	if (p_min < plls[index].min_p)
 		p_min = 4;
-	if (p_max > MAX_P)
+	if (p_max > plls[index].max_p)
 		p_max = 128;
 
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 
 	p = p_min;
 	do {
-		if (splitp(p, &p1, &p2)) {
+		if (splitp(index, p, &p1, &p2)) {
 			WRN_MSG("cannot split p = %d\n", p);
 			p += p_inc;
 			continue;
 		}
-		n = MIN_N;
+		n = plls[index].min_n;
 		f_vco = clock * p;
 
 		do {
 			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
-			if (m < MIN_M)
-				m = MIN_M;
-			if (m > MAX_M)
-				m = MAX_M;
+			if (m < plls[index].min_m)
+				m = plls[index].min_m;
+			if (m > plls[index].max_m)
+				m = plls[index].max_m;
 			f_out = CALC_VCLOCK3(m, n, p);
-			if (splitm(m, &m1, &m2)) {
+			if (splitm(index, m, &m1, &m2)) {
 				WRN_MSG("cannot split m = %d\n", m);
 				n++;
 				continue;
@@ -807,7 +831,7 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 				err_best = f_err;
 			}
 			n++;
-		} while ((n <= MAX_N) && (f_out >= clock));
+		} while ((n <= plls[index].max_n) && (f_out >= clock));
 		p += p_inc;
 	} while ((p <= p_max));
 
@@ -818,8 +842,8 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 	m = m_best;
 	n = n_best;
 	p = p_best;
-	splitm(m, &m1, &m2);
-	splitp(p, &p1, &p2);
+	splitm(index, m, &m1, &m2);
+	splitp(index, p, &p1, &p2);
 	n1 = n - 2;
 
 	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
@@ -929,7 +953,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	/* Desired clock in kHz */
 	clock_target = 1000000000 / var->pixclock;
 
-	if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+	if (calc_pll_params(PLLS_I8xx, clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
 		WRN_MSG("calc_pll_params failed\n");
 		return 1;
 	}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index ba1920159f526..e3c305c66d5c6 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -155,23 +155,8 @@
 /* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
 /* Clock values are in units of kHz */
 #define PLL_REFCLK		48000
-#define MIN_VCO_FREQ		930000
-#define MAX_VCO_FREQ		1400000
 #define MIN_CLOCK		25000
 #define MAX_CLOCK		350000
-#define P_TRANSITION_CLOCK	165000
-#define MIN_M			108
-#define MAX_M			140
-#define MIN_M1			18
-#define MAX_M1			26
-#define MIN_M2			6
-#define MAX_M2			16
-#define MIN_P			4
-#define MAX_P			128
-#define MIN_P1			0
-#define MAX_P1			31
-#define MIN_N			3
-#define MAX_N			16
 
 #define CALC_VCLOCK(m1, m2, n, p1, p2) \
         ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \

From d024960cff5173bef6e83c01cf9cd2763c2c0ab0 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 20 Mar 2006 20:26:45 +1100
Subject: [PATCH 02/25] intelfb: add pll index to the intelfb structure

Add the pll index into the information structure, change get_chipset to
take only the info structure, use plls in correct places
---
 drivers/video/intelfb/intelfb.h    |   3 +
 drivers/video/intelfb/intelfbdrv.c |   3 +-
 drivers/video/intelfb/intelfbhw.c  | 149 ++++++++++++++++++-----------
 drivers/video/intelfb/intelfbhw.h  |   9 +-
 4 files changed, 98 insertions(+), 66 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index da29d007f215d..d0da384348178 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -277,6 +277,9 @@ struct intelfb_info {
 
 	/* driver registered */
 	int registered;
+	
+	/* index into plls */
+	int pll_index;
 };
 
 /*** function prototypes ***/
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 995b47c165a71..7fb9f96bab3fd 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -584,8 +584,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* Get the chipset info. */
 	dinfo->pci_chipset = pdev->device;
 
-	if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
-				  &dinfo->mobile)) {
+	if (intelfbhw_get_chipset(pdev, dinfo)) {
 		cleanup(dinfo);
 		return -ENODEV;
 	}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index a3a94642b79bd..bf742aad08e9f 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -61,67 +61,71 @@ struct pll_min_max plls[PLLS_MAX] = {
 };
 
 int
-intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
-		      int *mobile)
+intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
 {
 	u32 tmp;
-
-	if (!pdev || !name || !chipset || !mobile)
+	if (!pdev || !dinfo)
 		return 1;
 
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_830M:
-		*name = "Intel(R) 830M";
-		*chipset = INTEL_830M;
-		*mobile = 1;
+		dinfo->name = "Intel(R) 830M";
+		dinfo->chipset = INTEL_830M;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_845G:
-		*name = "Intel(R) 845G";
-		*chipset = INTEL_845G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 845G";
+		dinfo->chipset = INTEL_845G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_85XGM:
 		tmp = 0;
-		*mobile = 1;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I8xx;
 		pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
 		switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
 			INTEL_85X_VARIANT_MASK) {
 		case INTEL_VAR_855GME:
-			*name = "Intel(R) 855GME";
-			*chipset = INTEL_855GME;
+			dinfo->name = "Intel(R) 855GME";
+			dinfo->chipset = INTEL_855GME;
 			return 0;
 		case INTEL_VAR_855GM:
-			*name = "Intel(R) 855GM";
-			*chipset = INTEL_855GM;
+			dinfo->name = "Intel(R) 855GM";
+			dinfo->chipset = INTEL_855GM;
 			return 0;
 		case INTEL_VAR_852GME:
-			*name = "Intel(R) 852GME";
-			*chipset = INTEL_852GME;
+			dinfo->name = "Intel(R) 852GME";
+			dinfo->chipset = INTEL_852GME;
 			return 0;
 		case INTEL_VAR_852GM:
-			*name = "Intel(R) 852GM";
-			*chipset = INTEL_852GM;
+			dinfo->name = "Intel(R) 852GM";
+			dinfo->chipset = INTEL_852GM;
 			return 0;
 		default:
-			*name = "Intel(R) 852GM/855GM";
-			*chipset = INTEL_85XGM;
+			dinfo->name = "Intel(R) 852GM/855GM";
+			dinfo->chipset = INTEL_85XGM;
 			return 0;
 		}
 		break;
 	case PCI_DEVICE_ID_INTEL_865G:
-		*name = "Intel(R) 865G";
-		*chipset = INTEL_865G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 865G";
+		dinfo->chipset = INTEL_865G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_915G:
-		*name = "Intel(R) 915G";
-		*chipset = INTEL_915G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 915G";
+		dinfo->chipset = INTEL_915G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I9xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_915GM:
-		*name = "Intel(R) 915GM";
-		*chipset = INTEL_915GM;
-		*mobile = 1;
+		dinfo->name = "Intel(R) 915GM";
+		dinfo->chipset = INTEL_915GM;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I9xx;
 		return 0;
 	default:
 		return 1;
@@ -549,14 +553,33 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 }
 
 
+static int calc_vclock3(int index, int m, int n, int p)
+{
+	return PLL_REFCLK * m / n / p;
+}
+		       
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
+{
+	switch(index)
+	{
+	case PLLS_I9xx:
+		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
+			 ((p1)) * (p2 ? 10 : 5)));
+	case PLLS_I8xx:
+	default:
+		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / 
+			 ((p1+2) * (1 << (p2 + 1)))));
+	}
+}
+
 void
 intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 {
 #if REGDUMP
 	int i, m1, m2, n, p1, p2;
-
+	int index = dinfo->pll_index;
 	DBG_MSG("intelfbhw_print_hw_state\n");
-
+	
 	if (!hw || !dinfo)
 		return;
 	/* Read in as much of the HW state as possible. */
@@ -573,9 +596,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	VGA0: clock is %d\n", 
+	       calc_vclock(index, m1, m2, n, p1, p2));
+	
 	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -585,16 +609,16 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 	printk("	DPLL_A:			0x%08x\n", hw->dpll_a);
 	printk("	DPLL_B:			0x%08x\n", hw->dpll_b);
 	printk("	FPA0:			0x%08x\n", hw->fpa0);
 	printk("	FPA1:			0x%08x\n", hw->fpa1);
 	printk("	FPB0:			0x%08x\n", hw->fpb0);
 	printk("	FPB1:			0x%08x\n", hw->fpb1);
-
+	
 	n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -604,9 +628,9 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 	n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -616,16 +640,16 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 #if 0
 	printk("	PALETTE_A:\n");
 	for (i = 0; i < PALETTE_8_ENTRIES)
-		printk("	%3d:	0x%08x\n", i, hw->palette_a[i];
+		printk("	%3d:	0x%08x\n", i, hw->palette_a[i]);
 	printk("	PALETTE_B:\n");
 	for (i = 0; i < PALETTE_8_ENTRIES)
-		printk("	%3d:	0x%08x\n", i, hw->palette_b[i];
+		printk("	%3d:	0x%08x\n", i, hw->palette_b[i]);
 #endif
 
 	printk("	HTOTAL_A:		0x%08x\n", hw->htotal_a);
@@ -700,12 +724,12 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	}
 	for (i = 0; i < 3; i++) {
 		printk("	SWF3%d			0x%08x\n", i,
-			hw->swf3x[i]);
+		       hw->swf3x[i]);
 	}
 	for (i = 0; i < 8; i++)
 		printk("	FENCE%d			0x%08x\n", i,
-			hw->fence[i]);
-
+		       hw->fence[i]);
+		       
 	printk("	INSTPM			0x%08x\n", hw->instpm);
 	printk("	MEM_MODE		0x%08x\n", hw->mem_mode);
 	printk("	FW_BLC_0		0x%08x\n", hw->fw_blc_0);
@@ -715,6 +739,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 #endif
 }
 
+	       
+
 /* Split the M parameter into M1 and M2. */
 static int
 splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
@@ -742,7 +768,17 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 {
 	int p1, p2;
 
-	if (index==PLLS_I8xx)
+	if (index == PLLS_I9xx)
+	{
+		p1 = (p / 10) + 1;
+		p2 = 0;
+		
+		*retp1 = (unsigned int)p1;
+		*retp2 = (unsigned int)p2;
+		return 0;
+	}
+
+	if (index == PLLS_I8xx)
 	{
 		if (p % 4 == 0)
 			p2 = 1;
@@ -812,7 +848,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 				m = plls[index].min_m;
 			if (m > plls[index].max_m)
 				m = plls[index].max_m;
-			f_out = CALC_VCLOCK3(m, n, p);
+			f_out = calc_vclock3(index, m, n, p);
 			if (splitm(index, m, &m1, &m2)) {
 				WRN_MSG("cannot split m = %d\n", m);
 				n++;
@@ -849,14 +885,15 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
 		"f: %d (%d), VCO: %d\n",
 		m, m1, m2, n, n1, p, p1, p2,
-		CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
-		CALC_VCLOCK3(m, n, p) * p);
+		calc_vclock3(index, m, n, p), 
+		calc_vclock(index, m1, m2, n1, p1, p2),
+		calc_vclock3(index, m, n, p) * p);
 	*retm1 = m1;
 	*retm2 = m2;
 	*retn = n1;
 	*retp1 = p1;
 	*retp2 = p2;
-	*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+	*retclock = calc_vclock(index, m1, m2, n1, p1, p2);
 
 	return 0;
 }
@@ -953,7 +990,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	/* Desired clock in kHz */
 	clock_target = 1000000000 / var->pixclock;
 
-	if (calc_pll_params(PLLS_I8xx, clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
 		WRN_MSG("calc_pll_params failed\n");
 		return 1;
 	}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index e3c305c66d5c6..a3ec8f92eb64c 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -158,12 +158,6 @@
 #define MIN_CLOCK		25000
 #define MAX_CLOCK		350000
 
-#define CALC_VCLOCK(m1, m2, n, p1, p2) \
-        ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
-        (((p1) + 2) * (1 << (p2 + 1))))
-
-#define CALC_VCLOCK3(m, n, p)	((PLL_REFCLK * (m) / (n)) / (p))
-
 /* Two pipes */
 #define PIPE_A			0
 #define PIPE_B			1
@@ -507,8 +501,7 @@
 
 
 /* function protoypes */
-extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
-				 int *chipset, int *mobile);
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
 extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
 				int *stolen_size);
 extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);

From 8492f081e5552ff388068f612eae6f55f7210ed4 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 20 Mar 2006 20:54:12 +1100
Subject: [PATCH 03/25] intelfb: change splitm to be brute force

The old splitm didn't always work use a brute force.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index bf742aad08e9f..d52921931a3eb 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -746,20 +746,22 @@ static int
 splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 {
 	int m1, m2;
-
-	m1 = (m - 2 - (plls[index].min_m1 + plls[index].max_m2) / 2) / 5 - 2;
-	if (m1 < plls[index].min_m1)
-		m1 = plls[index].min_m1;
-	if (m1 > plls[index].max_m1)
-		m1 = plls[index].max_m1;
-	m2 = m - 5 * (m1 + 2) - 2;
-	if (m2 < plls[index].min_m2 || m2 > plls[index].max_m2 || m2 >= m1) {
-		return 1;
-	} else {
+	int testm;
+	/* no point optimising too much - brute force m */
+	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++)
+	{
+	  for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++)
+	  {
+	    testm  = ( 5 * ( m1 + 2 )) + (m2 + 2);
+	    if (testm == m)
+	    {
 		*retm1 = (unsigned int)m1;
-		*retm2 = (unsigned int)m2;
+		*retm2 = (unsigned int)m2;	      
 		return 0;
+	    }
+	  }
 	}
+	return 1;
 }
 
 /* Split the P parameter into P1 and P2. */

From 16109b3f4c1f2635afd32eb6d49348590de2cb25 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 20 Mar 2006 21:22:09 +1100
Subject: [PATCH 04/25] intelfb: add p divisor increments for i9xx.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index d52921931a3eb..9a2d8cb4d4007 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -49,6 +49,7 @@ struct pll_min_max {
 	int min_p1, max_p1;
 	int min_vco_freq, max_vco_freq;
 	int p_transition_clock;
+	int p_inc_lo, p_inc_hi;
 };
 
 #define PLLS_I8xx 0
@@ -56,8 +57,8 @@ struct pll_min_max {
 #define PLLS_MAX 2
 
 struct pll_min_max plls[PLLS_MAX] = {
-	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000 }, //I8xx
-	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000 }  //I9xx
+	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 4, 22 }, //I8xx
+	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 10, 5 }  //I9xx
 };
 
 int
@@ -822,15 +823,15 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
 
 	if (clock <= plls[index].p_transition_clock)
-		p_inc = 4;
+		p_inc = plls[index].p_inc_lo;
 	else
-		p_inc = 2;
+		p_inc = plls[index].p_inc_hi;
 	p_min = ROUND_UP_TO(div_min, p_inc);
 	p_max = ROUND_DOWN_TO(div_max, p_inc);
 	if (p_min < plls[index].min_p)
-		p_min = 4;
+		p_min = plls[index].min_p;
 	if (p_max > plls[index].max_p)
-		p_max = 128;
+		p_max = plls[index].max_p;
 
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 

From 0c187addabbaf93512902442b4a90140a21b0ddc Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 11:20:08 +1100
Subject: [PATCH 05/25] intelfb: enable on x86_64

i945G chipsets supports 64-bit.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f87c0171f4eca..190adce607f8f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -741,7 +741,7 @@ config FB_I810_I2C
 
 config FB_INTEL
 	tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
-	depends on FB && EXPERIMENTAL && PCI && X86_32
+	depends on FB && EXPERIMENTAL && PCI && X86
 	select AGP
 	select AGP_INTEL
 	select FB_MODE_HELPERS

From 9639d5ec07a490134f05ac890506a367aaf8663b Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 11:23:55 +1100
Subject: [PATCH 06/25] intelfb: add support for i945G

This just adds the defines and structure for i945G

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfb.h    |  8 +++++---
 drivers/video/intelfb/intelfbdrv.c | 10 ++++++----
 drivers/video/intelfb/intelfbhw.c  |  6 ++++++
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index d0da384348178..fb2739fb746a5 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -8,9 +8,9 @@
 
 
 /*** Version/name ***/
-#define INTELFB_VERSION			"0.9.2"
+#define INTELFB_VERSION			"0.9.3"
 #define INTELFB_MODULE_NAME		"intelfb"
-#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM/945G"
 
 
 /*** Debug/feature defines ***/
@@ -52,6 +52,7 @@
 #define PCI_DEVICE_ID_INTEL_865G	0x2572
 #define PCI_DEVICE_ID_INTEL_915G	0x2582
 #define PCI_DEVICE_ID_INTEL_915GM	0x2592
+#define PCI_DEVICE_ID_INTEL_945G	0x2772
 
 /* Size of MMIO region */
 #define INTEL_REG_SIZE			0x80000
@@ -125,7 +126,8 @@ enum intel_chips {
 	INTEL_855GME,
 	INTEL_865G,
 	INTEL_915G,
-	INTEL_915GM
+	INTEL_915GM,
+	INTEL_945G
 };
 
 struct intelfb_hwstate {
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 7fb9f96bab3fd..ce45a684bbea3 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1,8 +1,8 @@
 /*
  * intelfb
  *
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM
- * integrated graphics chips.
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
+ * 945G integrated graphics chips.
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
  *                   2004 Sylvain Meyer
@@ -182,6 +182,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
 	{ 0, }
 };
 
@@ -546,10 +547,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* Set base addresses. */
 	if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
-			(ent->device == PCI_DEVICE_ID_INTEL_915GM)) {
+	    (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
+	    (ent->device == PCI_DEVICE_ID_INTEL_945G)) {
 		aperture_bar = 2;
 		mmio_bar = 0;
-		/* Disable HW cursor on 915G/M (not implemented yet) */
+		/* Disable HW cursor on 9x5G/M (not implemented yet) */
 		hwcursor = 0;
 	}
 	dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 9a2d8cb4d4007..f8c8c0a3f565a 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -128,6 +128,12 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
 		dinfo->mobile = 1;
 		dinfo->pll_index = PLLS_I9xx;
 		return 0;
+	case PCI_DEVICE_ID_INTEL_945G:
+		dinfo->name = "Intel(R) 945G";
+		dinfo->chipset = INTEL_945G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I9xx;
+		return 0;
 	default:
 		return 1;
 	}

From 7679f4d69296de97a7f62458cc4d1c6c884dfcfb Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 12:30:05 +1100
Subject: [PATCH 07/25] intelfb: make i915 modeset

This takes the modeset and pll code from my X driver.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 136 +++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 40 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index f8c8c0a3f565a..0bfa668bec214 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -562,6 +562,8 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 
 static int calc_vclock3(int index, int m, int n, int p)
 {
+	if (p == 0 || n == 0)
+		return 0;
 	return PLL_REFCLK * m / n / p;
 }
 		       
@@ -570,6 +572,8 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
 	switch(index)
 	{
 	case PLLS_I9xx:
+		if (p1 == 0)
+			return 0;
 		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
 			 ((p1)) * (p2 ? 10 : 5)));
 	case PLLS_I8xx:
@@ -779,8 +783,20 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 
 	if (index == PLLS_I9xx)
 	{
-		p1 = (p / 10) + 1;
-		p2 = 0;
+		switch (p) {
+		case 10:
+			p1 = 2;
+			p2 = 0;
+			break;
+		case 20:
+			p1 = 1;
+			p2 = 0;
+			break;
+		default:
+			p1 = (p / 10) + 1;
+			p2 = 0;
+			break;
+		}
 		
 		*retp1 = (unsigned int)p1;
 		*retp2 = (unsigned int)p2;
@@ -813,8 +829,8 @@ static int
 calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 		u32 *retp2, u32 *retclock)
 {
-	u32 m1, m2, n, p1, p2, n1;
-	u32 f_vco, p, p_best = 0, m, f_out;
+	u32 m1, m2, n, p1, p2, n1, testm;
+	u32 f_vco, p, p_best = 0, m, f_out = 0;
 	u32 err_max, err_target, err_best = 10000000;
 	u32 n_best = 0, m_best = 0, f_best, f_err;
 	u32 p_min, p_max, p_inc, div_min, div_max;
@@ -826,7 +842,10 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	DBG_MSG("Clock is %d\n", clock);
 
 	div_max = plls[index].max_vco_freq / clock;
-	div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
+	if (index == PLLS_I9xx)
+		div_min = 5;
+	else
+		div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
 
 	if (clock <= plls[index].p_transition_clock)
 		p_inc = plls[index].p_inc_lo;
@@ -839,6 +858,16 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	if (p_max > plls[index].max_p)
 		p_max = plls[index].max_p;
 
+	if (clock < PLL_REFCLK && index==PLLS_I9xx)
+	{
+	  p_min = 10;
+	  p_max = 20;
+	  /* this makes 640x480 work it really shouldn't 
+	     - SOMEONE WITHOUT DOCS WOZ HERE */
+	  if (clock < 30000)
+	    clock *= 4;
+	}
+
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 
 	p = p_min;
@@ -854,26 +883,28 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 		do {
 			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
 			if (m < plls[index].min_m)
-				m = plls[index].min_m;
+				m = plls[index].min_m + 1;
 			if (m > plls[index].max_m)
-				m = plls[index].max_m;
-			f_out = calc_vclock3(index, m, n, p);
-			if (splitm(index, m, &m1, &m2)) {
-				WRN_MSG("cannot split m = %d\n", m);
-				n++;
-				continue;
-			}
-			if (clock > f_out)
-				f_err = clock - f_out;
-			else
-				f_err = f_out - clock;
-
-			if (f_err < err_best) {
-				m_best = m;
-				n_best = n;
-				p_best = p;
-				f_best = f_out;
-				err_best = f_err;
+				m = plls[index].max_m - 1;
+			for (testm = m - 1; testm <= m; testm++) {
+				f_out = calc_vclock3(index, m, n, p);
+				if (splitm(index, m, &m1, &m2)) {
+					WRN_MSG("cannot split m = %d\n", m);
+					n++;
+					continue;
+				}
+				if (clock > f_out)
+					f_err = clock - f_out;
+				else/* slightly bias the error for bigger clocks */
+					f_err = f_out - clock + 1;
+				
+				if (f_err < err_best) {
+					m_best = m;
+					n_best = n;
+					p_best = p;
+					f_best = f_out;
+					err_best = f_err;
+				}
 			}
 			n++;
 		} while ((n <= plls[index].max_n) && (f_out >= clock));
@@ -1157,6 +1188,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	u32 hsync_reg, htotal_reg, hblank_reg;
 	u32 vsync_reg, vtotal_reg, vblank_reg;
 	u32 src_size_reg;
+	u32 count, tmp_val[3];
 
 	/* Assume single pipe, display plane A, analog CRT. */
 
@@ -1225,6 +1257,28 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 		src_size_reg = SRC_SIZE_A;
 	}
 
+	/* turn off pipe */
+	tmp = INREG(pipe_conf_reg);
+	tmp &= ~PIPECONF_ENABLE;
+	OUTREG(pipe_conf_reg, tmp);
+	
+	count = 0;
+	do{
+	  tmp_val[count%3] = INREG(0x70000);
+	  if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+	    break;
+	  count++;
+	  udelay(1);
+	  if (count % 200 == 0)
+	  {
+	    tmp = INREG(pipe_conf_reg);
+	    tmp &= ~PIPECONF_ENABLE;
+	    OUTREG(pipe_conf_reg, tmp);
+	  }
+	} while(count < 2000);
+
+	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
+
 	/* Disable planes A and B. */
 	tmp = INREG(DSPACNTR);
 	tmp &= ~DISPPLANE_PLANE_ENABLE;
@@ -1242,10 +1296,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	tmp |= ADPA_DPMS_D3;
 	OUTREG(ADPA, tmp);
 
-	/* turn off pipe */
-	tmp = INREG(pipe_conf_reg);
-	tmp &= ~PIPECONF_ENABLE;
-	OUTREG(pipe_conf_reg, tmp);
+	/* do some funky magic - xyzzy */
+	OUTREG(0x61204, 0xabcd0000);
 
 	/* turn off PLL */
 	tmp = INREG(dpll_reg);
@@ -1257,26 +1309,30 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	OUTREG(fp0_reg, *fp0);
 	OUTREG(fp1_reg, *fp1);
 
-	/* Set pipe parameters */
-	OUTREG(hsync_reg, *hs);
-	OUTREG(hblank_reg, *hb);
-	OUTREG(htotal_reg, *ht);
-	OUTREG(vsync_reg, *vs);
-	OUTREG(vblank_reg, *vb);
-	OUTREG(vtotal_reg, *vt);
-	OUTREG(src_size_reg, *ss);
+	/* Enable PLL */
+	tmp = INREG(dpll_reg);
+	tmp |= DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
 
 	/* Set DVOs B/C */
 	OUTREG(DVOB, hw->dvob);
 	OUTREG(DVOC, hw->dvoc);
 
+	/* undo funky magic */
+	OUTREG(0x61204, 0x00000000);
+
 	/* Set ADPA */
+	OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
 	OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
 
-	/* Enable PLL */
-	tmp = INREG(dpll_reg);
-	tmp |= DPLL_VCO_ENABLE;
-	OUTREG(dpll_reg, tmp);
+	/* Set pipe parameters */
+	OUTREG(hsync_reg, *hs);
+	OUTREG(hblank_reg, *hb);
+	OUTREG(htotal_reg, *ht);
+	OUTREG(vsync_reg, *vs);
+	OUTREG(vblank_reg, *vb);
+	OUTREG(vtotal_reg, *vt);
+	OUTREG(src_size_reg, *ss);
 
 	/* Enable pipe */
 	OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);

From 8bb91f6a2d1db8031bfbb367df075f041d0cdfe2 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 13:06:32 +1100
Subject: [PATCH 08/25] intelfb: add hw cursor support for i9xx

This adds hw cursor support for the i9xx chipsets.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfb.h    |  2 ++
 drivers/video/intelfb/intelfbdrv.c | 12 ++++++++----
 drivers/video/intelfb/intelfbhw.c  | 10 +++++++---
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index fb2739fb746a5..de9875c0c08fa 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -284,6 +284,8 @@ struct intelfb_info {
 	int pll_index;
 };
 
+#define IS_I9xx(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G))
+
 /*** function prototypes ***/
 
 extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index ce45a684bbea3..b96001b5d9471 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -6,6 +6,7 @@
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
  *                   2004 Sylvain Meyer
+ *                   2006 David Airlie
  *
  * This driver consists of two parts.  The first part (intelfbdrv.c) provides
  * the basic fbdev interfaces, is derived in part from the radeonfb and
@@ -551,8 +552,6 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
 	    (ent->device == PCI_DEVICE_ID_INTEL_945G)) {
 		aperture_bar = 2;
 		mmio_bar = 0;
-		/* Disable HW cursor on 9x5G/M (not implemented yet) */
-		hwcursor = 0;
 	}
 	dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
 	dinfo->aperture.size     = pci_resource_len(pdev, aperture_bar);
@@ -1468,7 +1467,7 @@ static int
 intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
         struct intelfb_info *dinfo = GET_DINFO(info);
-
+	int ret;
 #if VERBOSE > 0
 	DBG_MSG("intelfb_cursor\n");
 #endif
@@ -1479,7 +1478,12 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 	intelfbhw_cursor_hide(dinfo);
 
 	/* If XFree killed the cursor - restore it */
-	if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) {
+	if (dinfo->mobile || IS_I9xx(dinfo))
+	  ret = (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.physical);
+	else
+	  ret = (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12);
+
+	if (ret) {
 		u32 fg, bg;
 
 		DBG_MSG("the cursor was killed - restore it !!\n");
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 0bfa668bec214..92bdde8f9b23b 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1742,7 +1742,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
 	DBG_MSG("intelfbhw_cursor_init\n");
 #endif
 
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1775,7 +1775,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
 #endif
 
 	dinfo->cursor_on = 0;
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1805,7 +1805,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
 	if (dinfo->cursor_blanked)
 		return;
 
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1839,6 +1839,10 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
 	tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
 	      ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
 	OUTREG(CURSOR_A_POSITION, tmp);
+
+	if (IS_I9xx(dinfo)) {
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+	}
 }
 
 void

From 8b91b0b4f2d731b92f59bc82492769a09b4955a6 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 19:23:48 +1100
Subject: [PATCH 09/25] intelfb: fixup whitespace..

repeat after me, I must not take code from X without reformatting...

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 10 ++---
 drivers/video/intelfb/intelfbhw.c  | 66 ++++++++++++++----------------
 2 files changed, 35 insertions(+), 41 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index b96001b5d9471..f659ca8d1652f 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1467,7 +1467,7 @@ static int
 intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
         struct intelfb_info *dinfo = GET_DINFO(info);
-	int ret;
+	u32 physical;
 #if VERBOSE > 0
 	DBG_MSG("intelfb_cursor\n");
 #endif
@@ -1478,12 +1478,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 	intelfbhw_cursor_hide(dinfo);
 
 	/* If XFree killed the cursor - restore it */
-	if (dinfo->mobile || IS_I9xx(dinfo))
-	  ret = (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.physical);
-	else
-	  ret = (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12);
+	physical = (dinfo->mobile || IS_I9xx(dinfo)) ? dinfo->cursor.physical :
+		   (dinfo->cursor.offset << 12);
 
-	if (ret) {
+	if (INREG(CURSOR_A_BASEADDR) != physical) {
 		u32 fg, bg;
 
 		DBG_MSG("the cursor was killed - restore it !!\n");
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 92bdde8f9b23b..2537880b24206 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -566,7 +566,7 @@ static int calc_vclock3(int index, int m, int n, int p)
 		return 0;
 	return PLL_REFCLK * m / n / p;
 }
-		       
+
 static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
 {
 	switch(index)
@@ -578,7 +578,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
 			 ((p1)) * (p2 ? 10 : 5)));
 	case PLLS_I8xx:
 	default:
-		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / 
+		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
 			 ((p1+2) * (1 << (p2 + 1)))));
 	}
 }
@@ -608,7 +608,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
-	printk("	VGA0: clock is %d\n", 
+	printk("	VGA0: clock is %d\n",
 	       calc_vclock(index, m1, m2, n, p1, p2));
 	
 	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -740,7 +740,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	for (i = 0; i < 8; i++)
 		printk("	FENCE%d			0x%08x\n", i,
 		       hw->fence[i]);
-		       
+
 	printk("	INSTPM			0x%08x\n", hw->instpm);
 	printk("	MEM_MODE		0x%08x\n", hw->mem_mode);
 	printk("	FW_BLC_0		0x%08x\n", hw->fw_blc_0);
@@ -750,7 +750,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 #endif
 }
 
-	       
+
 
 /* Split the M parameter into M1 and M2. */
 static int
@@ -759,18 +759,15 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 	int m1, m2;
 	int testm;
 	/* no point optimising too much - brute force m */
-	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++)
-	{
-	  for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++)
-	  {
-	    testm  = ( 5 * ( m1 + 2 )) + (m2 + 2);
-	    if (testm == m)
-	    {
-		*retm1 = (unsigned int)m1;
-		*retm2 = (unsigned int)m2;	      
-		return 0;
-	    }
-	  }
+	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++) {
+		for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++) {
+			testm  = ( 5 * ( m1 + 2 )) + (m2 + 2);
+			if (testm == m) {
+				*retm1 = (unsigned int)m1;
+				*retm2 = (unsigned int)m2;
+				return 0;
+			}
+		}
 	}
 	return 1;
 }
@@ -781,8 +778,7 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 {
 	int p1, p2;
 
-	if (index == PLLS_I9xx)
-	{
+	if (index == PLLS_I9xx) {
 		switch (p) {
 		case 10:
 			p1 = 2;
@@ -803,8 +799,7 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 		return 0;
 	}
 
-	if (index == PLLS_I8xx)
-	{
+	if (index == PLLS_I8xx) {
 		if (p % 4 == 0)
 			p2 = 1;
 		else
@@ -814,7 +809,9 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 			p2 = 0;
 			p1 = (p / (1 << (p2 + 1))) - 2;
 		}
-		if (p1  < plls[index].min_p1 || p1 > plls[index].max_p1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+		if (p1 < plls[index].min_p1 ||
+		    p1 > plls[index].max_p1 ||
+		    (p1 + 2) * (1 << (p2 + 1)) != p) {
 			return 1;
 		} else {
 			*retp1 = (unsigned int)p1;
@@ -858,14 +855,13 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	if (p_max > plls[index].max_p)
 		p_max = plls[index].max_p;
 
-	if (clock < PLL_REFCLK && index==PLLS_I9xx)
-	{
-	  p_min = 10;
-	  p_max = 20;
-	  /* this makes 640x480 work it really shouldn't 
-	     - SOMEONE WITHOUT DOCS WOZ HERE */
-	  if (clock < 30000)
-	    clock *= 4;
+	if (clock < PLL_REFCLK && index == PLLS_I9xx) {
+		p_min = 10;
+		p_max = 20;
+		/* this makes 640x480 work it really shouldn't
+		   - SOMEONE WITHOUT DOCS WOZ HERE */
+		if (clock < 30000)
+			clock *= 4;
 	}
 
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
@@ -925,7 +921,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
 		"f: %d (%d), VCO: %d\n",
 		m, m1, m2, n, n1, p, p1, p2,
-		calc_vclock3(index, m, n, p), 
+		calc_vclock3(index, m, n, p),
 		calc_vclock(index, m1, m2, n1, p1, p2),
 		calc_vclock3(index, m, n, p) * p);
 	*retm1 = m1;
@@ -1030,7 +1026,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	/* Desired clock in kHz */
 	clock_target = 1000000000 / var->pixclock;
 
-	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2, 
+			    &n, &p1, &p2, &clock)) {
 		WRN_MSG("calc_pll_params failed\n");
 		return 1;
 	}
@@ -1263,14 +1260,13 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	OUTREG(pipe_conf_reg, tmp);
 	
 	count = 0;
-	do{
+	do {
 	  tmp_val[count%3] = INREG(0x70000);
 	  if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
 	    break;
 	  count++;
 	  udelay(1);
-	  if (count % 200 == 0)
-	  {
+	  if (count % 200 == 0) {
 	    tmp = INREG(pipe_conf_reg);
 	    tmp &= ~PIPECONF_ENABLE;
 	    OUTREG(pipe_conf_reg, tmp);

From 9a90603f65dd5046ddcd586158abcad7784892b6 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Thu, 23 Mar 2006 21:53:05 +1100
Subject: [PATCH 10/25] intelfb: add i945GM support

Untested i945GM support just add the framework.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfb.h    | 10 ++++++----
 drivers/video/intelfb/intelfbdrv.c |  6 ++++--
 drivers/video/intelfb/intelfbhw.c  |  6 ++++++
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index de9875c0c08fa..43128f9b68f00 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -8,9 +8,9 @@
 
 
 /*** Version/name ***/
-#define INTELFB_VERSION			"0.9.3"
+#define INTELFB_VERSION			"0.9.4"
 #define INTELFB_MODULE_NAME		"intelfb"
-#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM/945G"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM"
 
 
 /*** Debug/feature defines ***/
@@ -53,6 +53,7 @@
 #define PCI_DEVICE_ID_INTEL_915G	0x2582
 #define PCI_DEVICE_ID_INTEL_915GM	0x2592
 #define PCI_DEVICE_ID_INTEL_945G	0x2772
+#define PCI_DEVICE_ID_INTEL_945GM	0x27A2
 
 /* Size of MMIO region */
 #define INTEL_REG_SIZE			0x80000
@@ -127,7 +128,8 @@ enum intel_chips {
 	INTEL_865G,
 	INTEL_915G,
 	INTEL_915GM,
-	INTEL_945G
+	INTEL_945G,
+	INTEL_945GM,
 };
 
 struct intelfb_hwstate {
@@ -284,7 +286,7 @@ struct intelfb_info {
 	int pll_index;
 };
 
-#define IS_I9xx(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G))
+#define IS_I9xx(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
 
 /*** function prototypes ***/
 
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index f659ca8d1652f..54ce74547a3e6 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -2,7 +2,7 @@
  * intelfb
  *
  * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
- * 945G integrated graphics chips.
+ * 945G/945GM integrated graphics chips.
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
  *                   2004 Sylvain Meyer
@@ -184,6 +184,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
 	{ 0, }
 };
 
@@ -549,7 +550,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* Set base addresses. */
 	if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
 	    (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
-	    (ent->device == PCI_DEVICE_ID_INTEL_945G)) {
+	    (ent->device == PCI_DEVICE_ID_INTEL_945G)  ||
+	    (ent->device == PCI_DEVICE_ID_INTEL_945GM)) {
 		aperture_bar = 2;
 		mmio_bar = 0;
 	}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2537880b24206..73e1902dc3bb0 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -134,6 +134,12 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
 		dinfo->mobile = 0;
 		dinfo->pll_index = PLLS_I9xx;
 		return 0;
+	case PCI_DEVICE_ID_INTEL_945GM:
+		dinfo->name = "Intel(R) 945GM";
+		dinfo->chipset = INTEL_945GM;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I9xx;
+		return 0;
 	default:
 		return 1;
 	}

From 46f60b8e67e6fceede851dc69cdee2d7c0de27b9 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Fri, 24 Mar 2006 12:31:14 +1100
Subject: [PATCH 11/25] This patch makes a needlessly global struct static.

Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 73e1902dc3bb0..0c3553c358083 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -56,7 +56,7 @@ struct pll_min_max {
 #define PLLS_I9xx 1
 #define PLLS_MAX 2
 
-struct pll_min_max plls[PLLS_MAX] = {
+static struct pll_min_max plls[PLLS_MAX] = {
 	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 4, 22 }, //I8xx
 	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 10, 5 }  //I9xx
 };

From 3aff13cfb8810cc228e8fdcb92103ed0b11ee38e Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Fri, 31 Mar 2006 17:08:52 +1000
Subject: [PATCH 12/25] intelfb: fixup p calculation

This fixes up the p calculation of p1 and p2 for the i9xx chipsets.
This seems to work a lot better for lower pixel clocks..

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfb.h    |   2 +-
 drivers/video/intelfb/intelfbdrv.c |   2 +-
 drivers/video/intelfb/intelfbhw.c  | 216 ++++++++++++++++++-----------
 drivers/video/intelfb/intelfbhw.h  |   1 +
 4 files changed, 137 insertions(+), 84 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 43128f9b68f00..631a3a95de405 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -286,7 +286,7 @@ struct intelfb_info {
 	int pll_index;
 };
 
-#define IS_I9xx(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
 
 /*** function prototypes ***/
 
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 54ce74547a3e6..9e83664e345cf 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1480,7 +1480,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 	intelfbhw_cursor_hide(dinfo);
 
 	/* If XFree killed the cursor - restore it */
-	physical = (dinfo->mobile || IS_I9xx(dinfo)) ? dinfo->cursor.physical :
+	physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical :
 		   (dinfo->cursor.offset << 12);
 
 	if (INREG(CURSOR_A_BASEADDR) != physical) {
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 0c3553c358083..2bcf249bdf22e 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -47,8 +47,8 @@ struct pll_min_max {
 	int min_n, max_n;
 	int min_p, max_p;
 	int min_p1, max_p1;
-	int min_vco_freq, max_vco_freq;
-	int p_transition_clock;
+	int min_vco, max_vco;
+	int p_transition_clk, ref_clk;
 	int p_inc_lo, p_inc_hi;
 };
 
@@ -57,8 +57,8 @@ struct pll_min_max {
 #define PLLS_MAX 2
 
 static struct pll_min_max plls[PLLS_MAX] = {
-	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 4, 22 }, //I8xx
-	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 10, 5 }  //I9xx
+  { 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 48000, 4, 22 }, //I8xx
+  {  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 96000, 10, 5 }  //I9xx
 };
 
 int
@@ -570,21 +570,26 @@ static int calc_vclock3(int index, int m, int n, int p)
 {
 	if (p == 0 || n == 0)
 		return 0;
-	return PLL_REFCLK * m / n / p;
+	return plls[index].ref_clk * m / n / p;
 }
 
-static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
 {
+	int p2_val;
 	switch(index)
 	{
 	case PLLS_I9xx:
 		if (p1 == 0)
 			return 0;
-		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
-			 ((p1)) * (p2 ? 10 : 5)));
+		if (lvds)
+			p2_val = p2 ? 7 : 14;
+		else
+			p2_val = p2 ? 5 : 10;
+		return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
+			 ((p1)) * (p2_val)));
 	case PLLS_I8xx:
 	default:
-		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
+		return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
 			 ((p1+2) * (1 << (p2 + 1)))));
 	}
 }
@@ -596,7 +601,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	int i, m1, m2, n, p1, p2;
 	int index = dinfo->pll_index;
 	DBG_MSG("intelfbhw_print_hw_state\n");
-	
+
 	if (!hw || !dinfo)
 		return;
 	/* Read in as much of the HW state as possible. */
@@ -611,12 +616,14 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		p1 = 0;
 	else
 		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
+
 	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+
 	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
 	printk("	VGA0: clock is %d\n",
-	       calc_vclock(index, m1, m2, n, p1, p2));
-	
+	       calc_vclock(index, m1, m2, n, p1, p2, 0));
+
 	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -627,39 +634,96 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
-	printk("	VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
-	
+	printk("	VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+
 	printk("	DPLL_A:			0x%08x\n", hw->dpll_a);
 	printk("	DPLL_B:			0x%08x\n", hw->dpll_b);
 	printk("	FPA0:			0x%08x\n", hw->fpa0);
 	printk("	FPA1:			0x%08x\n", hw->fpa1);
 	printk("	FPB0:			0x%08x\n", hw->fpb0);
 	printk("	FPB1:			0x%08x\n", hw->fpb1);
-	
+
 	n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-		p1 = 0;
-	else
-		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
-	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+
+	if (IS_I9XX(dinfo)) {
+		int tmpp1;
+
+		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+			p1 = 0;
+		else
+			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff;
+
+		tmpp1 = p1;
+
+		switch (tmpp1)
+		{
+		case 0x1: p1 = 1; break;
+		case 0x2: p1 = 2; break;
+		case 0x4: p1 = 3; break;
+		case 0x8: p1 = 4; break;
+		case 0x10: p1 = 5; break;
+		case 0x20: p1 = 6; break;
+		case 0x40: p1 = 7; break;
+		case 0x80: p1 = 8; break;
+		default: break;
+		}
+
+		p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
+
+	} else {
+		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+			p1 = 0;
+		else
+			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+		p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	}
+
 	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
-	printk("	PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
-	
+	printk("	PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+
 	n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-		p1 = 0;
-	else
-		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
-	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+
+	if (IS_I9XX(dinfo)) {
+		int tmpp1;
+
+		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+			p1 = 0;
+		else
+			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff;
+
+		tmpp1 = p1;
+
+		switch (tmpp1)
+		{
+		case 0x1: p1 = 1; break;
+		case 0x2: p1 = 2; break;
+		case 0x4: p1 = 3; break;
+		case 0x8: p1 = 4; break;
+		case 0x10: p1 = 5; break;
+		case 0x20: p1 = 6; break;
+		case 0x40: p1 = 7; break;
+		case 0x80: p1 = 8; break;
+		default: break;
+		}
+
+		p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
+
+	} else {
+		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+			p1 = 0;
+		else
+			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+		p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	}
 	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
-	printk("	PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
-	
+	printk("	PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+
 #if 0
 	printk("	PALETTE_A:\n");
 	for (i = 0; i < PALETTE_8_ENTRIES)
@@ -767,7 +831,7 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 	/* no point optimising too much - brute force m */
 	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++) {
 		for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++) {
-			testm  = ( 5 * ( m1 + 2 )) + (m2 + 2);
+			testm = (5 * (m1 + 2)) + (m2 + 2);
 			if (testm == m) {
 				*retm1 = (unsigned int)m1;
 				*retm2 = (unsigned int)m2;
@@ -785,21 +849,11 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 	int p1, p2;
 
 	if (index == PLLS_I9xx) {
-		switch (p) {
-		case 10:
-			p1 = 2;
-			p2 = 0;
-			break;
-		case 20:
-			p1 = 1;
-			p2 = 0;
-			break;
-		default:
-			p1 = (p / 10) + 1;
-			p2 = 0;
-			break;
-		}
-		
+
+		p2 = 0; // for now
+
+		p1 = p / (p2 ? 5 : 10);
+
 		*retp1 = (unsigned int)p1;
 		*retp2 = (unsigned int)p2;
 		return 0;
@@ -844,13 +898,13 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 
 	DBG_MSG("Clock is %d\n", clock);
 
-	div_max = plls[index].max_vco_freq / clock;
+	div_max = plls[index].max_vco / clock;
 	if (index == PLLS_I9xx)
 		div_min = 5;
 	else
-		div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
+		div_min = ROUND_UP_TO(plls[index].min_vco, clock) / clock;
 
-	if (clock <= plls[index].p_transition_clock)
+	if (clock <= plls[index].p_transition_clk)
 		p_inc = plls[index].p_inc_lo;
 	else
 		p_inc = plls[index].p_inc_hi;
@@ -861,15 +915,6 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	if (p_max > plls[index].max_p)
 		p_max = plls[index].max_p;
 
-	if (clock < PLL_REFCLK && index == PLLS_I9xx) {
-		p_min = 10;
-		p_max = 20;
-		/* this makes 640x480 work it really shouldn't
-		   - SOMEONE WITHOUT DOCS WOZ HERE */
-		if (clock < 30000)
-			clock *= 4;
-	}
-
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 
 	p = p_min;
@@ -883,7 +928,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 		f_vco = clock * p;
 
 		do {
-			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
+			m = ROUND_UP_TO(f_vco * n, plls[index].ref_clk) / plls[index].ref_clk;
 			if (m < plls[index].min_m)
 				m = plls[index].min_m + 1;
 			if (m > plls[index].max_m)
@@ -899,7 +944,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 					f_err = clock - f_out;
 				else/* slightly bias the error for bigger clocks */
 					f_err = f_out - clock + 1;
-				
+
 				if (f_err < err_best) {
 					m_best = m;
 					n_best = n;
@@ -928,14 +973,14 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 		"f: %d (%d), VCO: %d\n",
 		m, m1, m2, n, n1, p, p1, p2,
 		calc_vclock3(index, m, n, p),
-		calc_vclock(index, m1, m2, n1, p1, p2),
+		calc_vclock(index, m1, m2, n1, p1, p2, 0),
 		calc_vclock3(index, m, n, p) * p);
 	*retm1 = m1;
 	*retm2 = m2;
 	*retn = n1;
 	*retp1 = p1;
 	*retp2 = p2;
-	*retclock = calc_vclock(index, m1, m2, n1, p1, p2);
+	*retclock = calc_vclock(index, m1, m2, n1, p1, p2, 0);
 
 	return 0;
 }
@@ -1032,7 +1077,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	/* Desired clock in kHz */
 	clock_target = 1000000000 / var->pixclock;
 
-	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2, 
+	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2,
 			    &n, &p1, &p2, &clock)) {
 		WRN_MSG("calc_pll_params failed\n");
 		return 1;
@@ -1053,7 +1098,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	*dpll &= ~DPLL_P1_FORCE_DIV2;
 	*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
 		   (DPLL_P1_MASK << DPLL_P1_SHIFT));
-	*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+
+	if (IS_I9XX(dinfo)) {
+		*dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
+		*dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
+	} else {
+		*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+	}
+
 	*fp0 = (n << FP_N_DIVISOR_SHIFT) |
 	       (m1 << FP_M1_DIVISOR_SHIFT) |
 	       (m2 << FP_M2_DIVISOR_SHIFT);
@@ -1264,19 +1316,19 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	tmp = INREG(pipe_conf_reg);
 	tmp &= ~PIPECONF_ENABLE;
 	OUTREG(pipe_conf_reg, tmp);
-	
+
 	count = 0;
 	do {
-	  tmp_val[count%3] = INREG(0x70000);
-	  if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
-	    break;
-	  count++;
-	  udelay(1);
-	  if (count % 200 == 0) {
-	    tmp = INREG(pipe_conf_reg);
-	    tmp &= ~PIPECONF_ENABLE;
-	    OUTREG(pipe_conf_reg, tmp);
-	  }
+		tmp_val[count%3] = INREG(0x70000);
+		if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+			break;
+		count++;
+		udelay(1);
+		if (count % 200 == 0) {
+			tmp = INREG(pipe_conf_reg);
+			tmp &= ~PIPECONF_ENABLE;
+			OUTREG(pipe_conf_reg, tmp);
+		}
 	} while(count < 2000);
 
 	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
@@ -1289,7 +1341,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	tmp &= ~DISPPLANE_PLANE_ENABLE;
 	OUTREG(DSPBCNTR, tmp);
 
-	/* Wait for vblank.  For now, just wait for a 50Hz cycle (20ms)) */
+	/* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
 	mdelay(20);
 
 	/* Disable Sync */
@@ -1359,7 +1411,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 			OUTREG(DSPACNTR,
 			       hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
 			mdelay(1);
-              }
+		}
 	}
 
 	OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
@@ -1744,7 +1796,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
 	DBG_MSG("intelfbhw_cursor_init\n");
 #endif
 
-	if (dinfo->mobile || IS_I9xx(dinfo)) {
+	if (dinfo->mobile || IS_I9XX(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1777,7 +1829,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
 #endif
 
 	dinfo->cursor_on = 0;
-	if (dinfo->mobile || IS_I9xx(dinfo)) {
+	if (dinfo->mobile || IS_I9XX(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1807,7 +1859,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
 	if (dinfo->cursor_blanked)
 		return;
 
-	if (dinfo->mobile || IS_I9xx(dinfo)) {
+	if (dinfo->mobile || IS_I9XX(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1833,8 +1885,8 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
 #endif
 
 	/*
-	 * Sets the position.  The coordinates are assumed to already
-	 * have any offset adjusted.  Assume that the cursor is never
+	 * Sets the position. The coordinates are assumed to already
+	 * have any offset adjusted. Assume that the cursor is never
 	 * completely off-screen, and that x, y are always >= 0.
 	 */
 
@@ -1842,7 +1894,7 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
 	      ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
 	OUTREG(CURSOR_A_POSITION, tmp);
 
-	if (IS_I9xx(dinfo)) {
+	if (IS_I9XX(dinfo)) {
 		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
 	}
 }
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index a3ec8f92eb64c..10acda098b71e 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -133,6 +133,7 @@
 #define DPLL_VGA_MODE_DISABLE		(1 << 28)
 #define DPLL_P2_MASK			1
 #define DPLL_P2_SHIFT			23
+#define DPLL_I9XX_P2_SHIFT              24
 #define DPLL_P1_FORCE_DIV2		(1 << 21)
 #define DPLL_P1_MASK			0x1f
 #define DPLL_P1_SHIFT			16

From 3587c50991b96fee2d26942f380e36e4f40fad71 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 3 Apr 2006 14:46:55 +1000
Subject: [PATCH 13/25] intelfb: fixup pitch calculation like X does

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 17 +++++++++++++++++
 drivers/video/intelfb/intelfbhw.c  |  2 +-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 9e83664e345cf..2aba6a4a9eae9 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1164,16 +1164,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 	struct fb_var_screeninfo v;
 	struct intelfb_info *dinfo;
 	static int first = 1;
+	int i;
+	/* Good pitches to allow tiling.  Don't care about pitches < 1024. */
+	static const int pitches[] = {
+		128 * 8,
+		128 * 16,
+		128 * 32,
+		128 * 64,
+		0
+	};
 
 	DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
 
 	dinfo = GET_DINFO(info);
 
+	/* update the pitch */
 	if (intelfbhw_validate_mode(dinfo, var) != 0)
 		return -EINVAL;
 
 	v = *var;
 
+	for (i = 0; pitches[i] != 0; i++) {
+		if (pitches[i] >= v.xres_virtual) {
+			v.xres_virtual = pitches[i];
+			break;
+		}
+	}
+
 	/* Check for a supported bpp. */
 	if (v.bits_per_pixel <= 8) {
 		v.bits_per_pixel = 8;
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2bcf249bdf22e..4284c75545125 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1210,7 +1210,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
 	      (vactive << SRC_SIZE_VERT_SHIFT);
 
-	hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
+	hw->disp_a_stride = dinfo->pitch;
 	DBG_MSG("pitch is %d\n", hw->disp_a_stride);
 
 	hw->disp_a_base = hw->disp_a_stride * var->yoffset +

From 51d797474f87b375819d084f7583a2864c5656c4 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 3 Apr 2006 16:19:26 +1000
Subject: [PATCH 14/25] intelfb: some cleanups for intelfbhw

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 71 +++++++++++++++----------------
 1 file changed, 34 insertions(+), 37 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 4284c75545125..05f0a3c9440f8 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -41,14 +41,10 @@
 #include "intelfbhw.h"
 
 struct pll_min_max {
-	int min_m, max_m;
-	int min_m1, max_m1;
-	int min_m2, max_m2;
-	int min_n, max_n;
-	int min_p, max_p;
-	int min_p1, max_p1;
-	int min_vco, max_vco;
-	int p_transition_clk, ref_clk;
+	int min_m, max_m, min_m1, max_m1;
+	int min_m2, max_m2, min_n, max_n;
+	int min_p, max_p, min_p1, max_p1;
+	int min_vco, max_vco, p_transition_clk, ref_clk;
 	int p_inc_lo, p_inc_hi;
 };
 
@@ -57,8 +53,17 @@ struct pll_min_max {
 #define PLLS_MAX 2
 
 static struct pll_min_max plls[PLLS_MAX] = {
-  { 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 48000, 4, 22 }, //I8xx
-  {  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 96000, 10, 5 }  //I9xx
+	{ 108, 140, 18, 26,
+	  6, 16, 3, 16,
+	  4, 128, 0, 31,
+	  930000, 1400000, 165000, 48000,
+	  4, 2 }, //I8xx
+
+	{ 75, 120, 10, 20,
+	  5, 9, 4, 7,
+	  5, 80, 1, 8,
+	  1400000, 2800000, 200000, 96000,
+	  10, 5 }  //I9xx
 };
 
 int
@@ -698,8 +703,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 
 		tmpp1 = p1;
 
-		switch (tmpp1)
-		{
+		switch (tmpp1) {
 		case 0x1: p1 = 1; break;
 		case 0x2: p1 = 2; break;
 		case 0x4: p1 = 3; break;
@@ -710,7 +714,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 		case 0x80: p1 = 8; break;
 		default: break;
 		}
-
+		
 		p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
 
 	} else {
@@ -849,8 +853,7 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 	int p1, p2;
 
 	if (index == PLLS_I9xx) {
-
-		p2 = 0; // for now
+		p2 = (p % 10) ? 1 : 0;
 
 		p1 = p / (p2 ? 5 : 10);
 
@@ -890,7 +893,8 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 	u32 f_vco, p, p_best = 0, m, f_out = 0;
 	u32 err_max, err_target, err_best = 10000000;
 	u32 n_best = 0, m_best = 0, f_best, f_err;
-	u32 p_min, p_max, p_inc, div_min, div_max;
+	u32 p_min, p_max, p_inc, div_max;
+	struct pll_min_max *pll = &plls[index];
 
 	/* Accept 0.5% difference, but aim for 0.1% */
 	err_max = 5 * clock / 1000;
@@ -898,22 +902,15 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 
 	DBG_MSG("Clock is %d\n", clock);
 
-	div_max = plls[index].max_vco / clock;
-	if (index == PLLS_I9xx)
-		div_min = 5;
-	else
-		div_min = ROUND_UP_TO(plls[index].min_vco, clock) / clock;
+	div_max = pll->max_vco / clock;
 
-	if (clock <= plls[index].p_transition_clk)
-		p_inc = plls[index].p_inc_lo;
-	else
-		p_inc = plls[index].p_inc_hi;
-	p_min = ROUND_UP_TO(div_min, p_inc);
+	p_inc = (clock <= pll->p_transition_clk) ? pll->p_inc_lo : pll->p_inc_hi;
+	p_min = p_inc;
 	p_max = ROUND_DOWN_TO(div_max, p_inc);
-	if (p_min < plls[index].min_p)
-		p_min = plls[index].min_p;
-	if (p_max > plls[index].max_p)
-		p_max = plls[index].max_p;
+	if (p_min < pll->min_p)
+		p_min = pll->min_p;
+	if (p_max > pll->max_p)
+		p_max = pll->max_p;
 
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 
@@ -924,15 +921,15 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 			p += p_inc;
 			continue;
 		}
-		n = plls[index].min_n;
+		n = pll->min_n;
 		f_vco = clock * p;
 
 		do {
-			m = ROUND_UP_TO(f_vco * n, plls[index].ref_clk) / plls[index].ref_clk;
-			if (m < plls[index].min_m)
-				m = plls[index].min_m + 1;
-			if (m > plls[index].max_m)
-				m = plls[index].max_m - 1;
+			m = ROUND_UP_TO(f_vco * n, pll->ref_clk) / pll->ref_clk;
+			if (m < pll->min_m)
+				m = pll->min_m + 1;
+			if (m > pll->max_m)
+				m = pll->max_m - 1;
 			for (testm = m - 1; testm <= m; testm++) {
 				f_out = calc_vclock3(index, m, n, p);
 				if (splitm(index, m, &m1, &m2)) {
@@ -954,7 +951,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 				}
 			}
 			n++;
-		} while ((n <= plls[index].max_n) && (f_out >= clock));
+		} while ((n <= pll->max_n) && (f_out >= clock));
 		p += p_inc;
 	} while ((p <= p_max));
 

From df7df8ab7b38ca80bbaf5ffafd401d6c739fd45f Mon Sep 17 00:00:00 2001
From: Dennis Munsie <dmunsie@cecropia.com>
Date: Sat, 27 May 2006 18:17:52 +1000
Subject: [PATCH 15/25] intelfb -- uses stride alignment of 64 on the 9xx
 chipsets.

Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfb.h    | 1 +
 drivers/video/intelfb/intelfbdrv.c | 5 ++++-
 drivers/video/intelfb/intelfbhw.c  | 7 +++++--
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 631a3a95de405..469b06c291804 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -59,6 +59,7 @@
 #define INTEL_REG_SIZE			0x80000
 
 #define STRIDE_ALIGNMENT		16
+#define STRIDE_ALIGNMENT_I9XX		64
 
 #define PALETTE_8_ENTRIES		256
 
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 2aba6a4a9eae9..b92bc908335e9 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1141,7 +1141,10 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
 	}
 
 	/* Make sure the line length is a aligned correctly. */
-	dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
+	if (IS_I9XX(dinfo))
+		dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX);
+	else
+		dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
 
 	if (FIXED_MODE(dinfo))
 		dinfo->pitch = dinfo->initial_pitch;
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 05f0a3c9440f8..eba8f8f6a4d4a 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1005,6 +1005,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
 	u32 vsync_pol, hsync_pol;
 	u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
+	u32 stride_alignment;
 
 	DBG_MSG("intelfbhw_mode_to_hw\n");
 
@@ -1216,9 +1217,11 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
 	hw->disp_a_base += dinfo->fb.offset << 12;
 
 	/* Check stride alignment. */
-	if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
+	stride_alignment = IS_I9XX(dinfo) ? STRIDE_ALIGNMENT_I9XX :
+					    STRIDE_ALIGNMENT;
+	if (hw->disp_a_stride % stride_alignment != 0) {
 		WRN_MSG("display stride %d has bad alignment %d\n",
-			hw->disp_a_stride, STRIDE_ALIGNMENT);
+			hw->disp_a_stride, stride_alignment);
 		return 1;
 	}
 

From 1aecb393091d3c0787f92445420d96ef58c9782a Mon Sep 17 00:00:00 2001
From: Eric Hustvedt <ehustvedt@cecropia.com>
Date: Sat, 27 May 2006 18:30:00 +1000
Subject: [PATCH 16/25] Adds support for 256MB aperture on 945 chipsets to the
 intelfb driver and corrects calculation of stolen memory overhead.

Signed-off-by: Eric Hustvedt <ehustvedt@cecropia.com>
Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 46 ++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 13 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index eba8f8f6a4d4a..82a2b9048df99 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -156,6 +156,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
 {
 	struct pci_dev *bridge_dev;
 	u16 tmp;
+	int stolen_overhead;
 
 	if (!pdev || !aperture_size || !stolen_size)
 		return 1;
@@ -170,21 +171,41 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
 	tmp = 0;
 	pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
 	switch (pdev->device) {
-	case PCI_DEVICE_ID_INTEL_830M:
-	case PCI_DEVICE_ID_INTEL_845G:
+	case PCI_DEVICE_ID_INTEL_915G:
+	case PCI_DEVICE_ID_INTEL_915GM:
+	case PCI_DEVICE_ID_INTEL_945G:
+	case PCI_DEVICE_ID_INTEL_945GM:
+		/* 915 and 945 chipsets support a 256MB aperture.
+		   Aperture size is determined by inspected the
+		   base address of the aperture. */
+		if (pci_resource_start(pdev, 2) & 0x08000000)
+			*aperture_size = MB(128);
+		else
+			*aperture_size = MB(256);
+		break;
+	default:
 		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
 			*aperture_size = MB(64);
 		else
 			*aperture_size = MB(128);
+		break;
+	}
+
+	/* Stolen memory size is reduced by the GTT and the popup.
+	   GTT is 1K per MB of aperture size, and popup is 4K. */
+	stolen_overhead = (*aperture_size / MB(1)) + 4;
+	switch(pdev->device) {
+	case PCI_DEVICE_ID_INTEL_830M:
+	case PCI_DEVICE_ID_INTEL_845G:
 		switch (tmp & INTEL_830_GMCH_GMS_MASK) {
 		case INTEL_830_GMCH_GMS_STOLEN_512:
-			*stolen_size = KB(512) - KB(132);
+			*stolen_size = KB(512) - KB(stolen_overhead);
 			return 0;
 		case INTEL_830_GMCH_GMS_STOLEN_1024:
-			*stolen_size = MB(1) - KB(132);
+			*stolen_size = MB(1) - KB(stolen_overhead);
 			return 0;
 		case INTEL_830_GMCH_GMS_STOLEN_8192:
-			*stolen_size = MB(8) - KB(132);
+			*stolen_size = MB(8) - KB(stolen_overhead);
 			return 0;
 		case INTEL_830_GMCH_GMS_LOCAL:
 			ERR_MSG("only local memory found\n");
@@ -199,28 +220,27 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
 		}
 		break;
 	default:
-		*aperture_size = MB(128);
 		switch (tmp & INTEL_855_GMCH_GMS_MASK) {
 		case INTEL_855_GMCH_GMS_STOLEN_1M:
-			*stolen_size = MB(1) - KB(132);
+			*stolen_size = MB(1) - KB(stolen_overhead);
 			return 0;
 		case INTEL_855_GMCH_GMS_STOLEN_4M:
-			*stolen_size = MB(4) - KB(132);
+			*stolen_size = MB(4) - KB(stolen_overhead);
 			return 0;
 		case INTEL_855_GMCH_GMS_STOLEN_8M:
-			*stolen_size = MB(8) - KB(132);
+			*stolen_size = MB(8) - KB(stolen_overhead);
 			return 0;
 		case INTEL_855_GMCH_GMS_STOLEN_16M:
-			*stolen_size = MB(16) - KB(132);
+			*stolen_size = MB(16) - KB(stolen_overhead);
 			return 0;
 		case INTEL_855_GMCH_GMS_STOLEN_32M:
-			*stolen_size = MB(32) - KB(132);
+			*stolen_size = MB(32) - KB(stolen_overhead);
 			return 0;
 		case INTEL_915G_GMCH_GMS_STOLEN_48M:
-			*stolen_size = MB(48) - KB(132);
+			*stolen_size = MB(48) - KB(stolen_overhead);
 			return 0;
 		case INTEL_915G_GMCH_GMS_STOLEN_64M:
-			*stolen_size = MB(64) - KB(132);
+			*stolen_size = MB(64) - KB(stolen_overhead);
 			return 0;
 		case INTEL_855_GMCH_GMS_DISABLED:
 			ERR_MSG("video memory is disabled\n");

From 2c47430a03bbcc3c9a623a07eca5baf92c7d20c8 Mon Sep 17 00:00:00 2001
From: Dennis Munsie <dmunsie@cecropia.com>
Date: Sat, 27 May 2006 18:33:35 +1000
Subject: [PATCH 17/25] intelfb driver -- use the regular modedb table instead
 of the VESA modedb table.  Ideally, the 9xx stride patch should be applied
 first, since there are modes in the VESA table that won't work without that
 patch.

Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index b92bc908335e9..e1ac4651adc74 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1033,15 +1033,13 @@ intelfb_init_var(struct intelfb_info *dinfo)
 	} else {
 		if (mode) {
 			msrc = fb_find_mode(var, dinfo->info, mode,
-					    vesa_modes, VESA_MODEDB_SIZE,
-					    NULL, 0);
+					    NULL, 0, NULL, 0);
 			if (msrc)
 				msrc |= 8;
 		}
 		if (!msrc) {
 			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
-					    vesa_modes, VESA_MODEDB_SIZE,
-					    NULL, 0);
+					    NULL, 0, NULL, 0);
 		}
 	}
 

From c9daa873c3a7c769821ec6c8258adf098bb0435c Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Sat, 27 May 2006 18:44:02 +1000
Subject: [PATCH 18/25] intelfb: align with changes from my X driver.

This just realigns the PLL calculation routines with the ones from my X.org
driver.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 73 ++++++++++++++-----------------
 1 file changed, 34 insertions(+), 39 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 82a2b9048df99..5a621df5bf022 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -600,23 +600,19 @@ static int calc_vclock3(int index, int m, int n, int p)
 
 static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
 {
-	int p2_val;
-	switch(index)
-	{
-	case PLLS_I9xx:
-		if (p1 == 0)
-			return 0;
-		if (lvds)
-			p2_val = p2 ? 7 : 14;
-		else
-			p2_val = p2 ? 5 : 10;
-		return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
-			 ((p1)) * (p2_val)));
-	case PLLS_I8xx:
-	default:
-		return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
-			 ((p1+2) * (1 << (p2 + 1)))));
+	struct pll_min_max *pll = &plls[index];
+	u32 m, vco, p;
+
+	m = (5 * (m1 + 2)) + (m2 + 2);
+	n += 2;
+	vco = pll->ref_clk * m / n;
+
+	if (index == PLLS_I8xx) {
+		p = ((p1 + 2) * (1 << (p2 + 1)));
+	} else {
+		p = ((p1) * (p2 ? 5 : 10));
 	}
+	return vco / p;
 }
 
 void
@@ -852,9 +848,11 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 {
 	int m1, m2;
 	int testm;
+	struct pll_min_max *pll = &plls[index];
+
 	/* no point optimising too much - brute force m */
-	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++) {
-		for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++) {
+	for (m1 = pll->min_m1; m1 < pll->max_m1 + 1; m1++) {
+		for (m2 = pll->min_m2; m2 < pll->max_m2 + 1; m2++) {
 			testm = (5 * (m1 + 2)) + (m2 + 2);
 			if (testm == m) {
 				*retm1 = (unsigned int)m1;
@@ -871,6 +869,7 @@ static int
 splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 {
 	int p1, p2;
+	struct pll_min_max *pll = &plls[index];
 
 	if (index == PLLS_I9xx) {
 		p2 = (p % 10) ? 1 : 0;
@@ -882,27 +881,23 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 		return 0;
 	}
 
-	if (index == PLLS_I8xx) {
-		if (p % 4 == 0)
-			p2 = 1;
-		else
-			p2 = 0;
+	if (p % 4 == 0)
+		p2 = 1;
+	else
+		p2 = 0;
+	p1 = (p / (1 << (p2 + 1))) - 2;
+	if (p % 4 == 0 && p1 < pll->min_p1) {
+		p2 = 0;
 		p1 = (p / (1 << (p2 + 1))) - 2;
-		if (p % 4 == 0 && p1 < plls[index].min_p1) {
-			p2 = 0;
-			p1 = (p / (1 << (p2 + 1))) - 2;
-		}
-		if (p1 < plls[index].min_p1 ||
-		    p1 > plls[index].max_p1 ||
-		    (p1 + 2) * (1 << (p2 + 1)) != p) {
-			return 1;
-		} else {
-			*retp1 = (unsigned int)p1;
-			*retp2 = (unsigned int)p2;
-			return 0;
-		}
 	}
-	return 1;
+	if (p1 < pll->min_p1 || p1 > pll->max_p1 ||
+	    (p1 + 2) * (1 << (p2 + 1)) != p) {
+		return 1;
+	} else {
+		*retp1 = (unsigned int)p1;
+		*retp2 = (unsigned int)p2;
+		return 0;
+	}
 }
 
 static int
@@ -952,7 +947,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 				m = pll->max_m - 1;
 			for (testm = m - 1; testm <= m; testm++) {
 				f_out = calc_vclock3(index, m, n, p);
-				if (splitm(index, m, &m1, &m2)) {
+				if (splitm(index, testm, &m1, &m2)) {
 					WRN_MSG("cannot split m = %d\n", m);
 					n++;
 					continue;
@@ -963,7 +958,7 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
 					f_err = f_out - clock + 1;
 
 				if (f_err < err_best) {
-					m_best = m;
+					m_best = testm;
 					n_best = n;
 					p_best = p;
 					f_best = f_out;

From f728377f6786bcdf1dbf33394360164e86f40094 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Sat, 27 May 2006 18:56:02 +1000
Subject: [PATCH 19/25] sync modesetting code with X.org

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 5a621df5bf022..16c9c192b4be6 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1359,6 +1359,10 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	/* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
 	mdelay(20);
 
+	OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);
+	OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);
+	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
+
 	/* Disable Sync */
 	tmp = INREG(ADPA);
 	tmp &= ~ADPA_DPMS_CONTROL_MASK;
@@ -1374,14 +1378,11 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
 	OUTREG(dpll_reg, tmp);
 
 	/* Set PLL parameters */
-	OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
 	OUTREG(fp0_reg, *fp0);
 	OUTREG(fp1_reg, *fp1);
 
 	/* Enable PLL */
-	tmp = INREG(dpll_reg);
-	tmp |= DPLL_VCO_ENABLE;
-	OUTREG(dpll_reg, tmp);
+	OUTREG(dpll_reg, *dpll);
 
 	/* Set DVOs B/C */
 	OUTREG(DVOB, hw->dvob);

From 65eb2f97db17f6f6a92cad3aad93b531f991ebf1 Mon Sep 17 00:00:00 2001
From: Eric Hustvedt <ehustvedt@cecropia.com>
Date: Mon, 29 May 2006 18:38:55 +1000
Subject: [PATCH 20/25] intelfb: int option fix

Fix integer option parsing in the intelfb driver. The macro wasn't
accounting for the equal sign past the option name. As a result,
the vram option always returned 0.

Signed-off-by: Eric Hustvedt <ehustvedt@cecropia.com>
Signed-off-by: Dennis Munsie <dmunsie@cecropia.com
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index e1ac4651adc74..e302d2b742ab0 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -264,7 +264,7 @@ MODULE_PARM_DESC(mode,
 
 #ifndef MODULE
 #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
-#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)
+#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0)
 #define OPT_STRVAL(opt, name) (opt + strlen(name))
 
 static __inline__ char *

From 080a416802153dbbb20ab4f4fa1225867096d071 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Mon, 29 May 2006 18:45:19 +1000
Subject: [PATCH 21/25] Revert "intelfb driver -- use the regular modedb table
 instead of the VESA"

This reverts 2c47430a03bbcc3c9a623a07eca5baf92c7d20c8 commit.
This conflicts with a patch in -mm from Antonino reapply later.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index e302d2b742ab0..65059ba32044d 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1033,13 +1033,15 @@ intelfb_init_var(struct intelfb_info *dinfo)
 	} else {
 		if (mode) {
 			msrc = fb_find_mode(var, dinfo->info, mode,
-					    NULL, 0, NULL, 0);
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
 			if (msrc)
 				msrc |= 8;
 		}
 		if (!msrc) {
 			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
-					    NULL, 0, NULL, 0);
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
 		}
 	}
 

From 56e004e5435c008728b1444b51d757da2e098976 Mon Sep 17 00:00:00 2001
From: "Antonino A. Daplas" <adaplas@gmail.com>
Date: Mon, 29 May 2006 18:49:08 +1000
Subject: [PATCH 22/25] intelfb: use firmware EDID for mode database

Use firmware EDID for the driver's private mode database.

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Cc: Sylvain Meyer <sylvain.meyer@worldonline.fr>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 36 +++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 65059ba32044d..dfe2abc63aad8 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -132,6 +132,7 @@
 
 #include "intelfb.h"
 #include "intelfbhw.h"
+#include "../edid.h"
 
 static void __devinit get_initial_mode(struct intelfb_info *dinfo);
 static void update_dinfo(struct intelfb_info *dinfo,
@@ -1031,13 +1032,42 @@ intelfb_init_var(struct intelfb_info *dinfo)
 		       sizeof(struct fb_var_screeninfo));
 		msrc = 5;
 	} else {
+		const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev);
+		u8 *edid_d = NULL;
+
+		if (edid_s) {
+			edid_d = kmalloc(128, GFP_KERNEL);
+
+			if (edid_d) {
+				memcpy(edid_d, edid_s, 128);
+				fb_edid_to_monspecs(edid_d,
+						    &dinfo->info->monspecs);
+				kfree(edid_d);
+			}
+		}
+
 		if (mode) {
+			printk("intelfb: Looking for mode in private "
+			       "database\n");
 			msrc = fb_find_mode(var, dinfo->info, mode,
-					    vesa_modes, VESA_MODEDB_SIZE,
+					    dinfo->info->monspecs.modedb,
+					    dinfo->info->monspecs.modedb_len,
 					    NULL, 0);
-			if (msrc)
-				msrc |= 8;
+
+			if (msrc && msrc > 1) {
+				printk("intelfb: No mode in private database, "
+				       "intelfb: looking for mode in global "
+				       "database ");
+				msrc = fb_find_mode(var, dinfo->info, mode,
+						    vesa_modes,
+						    VESA_MODEDB_SIZE, NULL, 0);
+
+				if (msrc)
+					msrc |= 8;
+			}
+
 		}
+
 		if (!msrc) {
 			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
 					    vesa_modes, VESA_MODEDB_SIZE,

From 7a532c69c37dbb46bfd0276160e624f06552adfc Mon Sep 17 00:00:00 2001
From: Dennis Munsie <dmunsie@cecropia.com>
Date: Mon, 29 May 2006 18:58:09 +1000
Subject: [PATCH 23/25] intelfb: use regular modedb table instead of VESA

intelfb driver -- use the regular modedb table instead of the VESA modedb
table.  Ideally, the 9xx stride patch should be applied first, since there
are modes in the VESA table that won't work without that patch.

Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index dfe2abc63aad8..85bf55897f772 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1059,8 +1059,7 @@ intelfb_init_var(struct intelfb_info *dinfo)
 				       "intelfb: looking for mode in global "
 				       "database ");
 				msrc = fb_find_mode(var, dinfo->info, mode,
-						    vesa_modes,
-						    VESA_MODEDB_SIZE, NULL, 0);
+						    NULL, 0, NULL, 0);
 
 				if (msrc)
 					msrc |= 8;
@@ -1070,8 +1069,7 @@ intelfb_init_var(struct intelfb_info *dinfo)
 
 		if (!msrc) {
 			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
-					    vesa_modes, VESA_MODEDB_SIZE,
-					    NULL, 0);
+					    NULL, 0, NULL, 0);
 		}
 	}
 

From 72109368de7aaa5d489d9ca4641f4a11a6fc7653 Mon Sep 17 00:00:00 2001
From: Dennis Munsie <dmunsie@cecropia.com>
Date: Wed, 7 Jun 2006 18:53:38 +1000
Subject: [PATCH 24/25] Removed hard coded EDID buffer size.

Signed-off-by: Dennis Munsie <dmunsie@cecropia.com>
Acked-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbdrv.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 85bf55897f772..076fa56be192a 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1036,10 +1036,10 @@ intelfb_init_var(struct intelfb_info *dinfo)
 		u8 *edid_d = NULL;
 
 		if (edid_s) {
-			edid_d = kmalloc(128, GFP_KERNEL);
+			edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
 
 			if (edid_d) {
-				memcpy(edid_d, edid_s, 128);
+				memcpy(edid_d, edid_s, EDID_LENGTH);
 				fb_edid_to_monspecs(edid_d,
 						    &dinfo->info->monspecs);
 				kfree(edid_d);

From 2abac1db3522d9f56c695d1b42e77f3e52d4c51a Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@linux.ie>
Date: Sun, 18 Jun 2006 16:12:27 +1000
Subject: [PATCH 25/25] intelfb: fixup clock calculation debugging.

The debugging code for pll clocks was wrong and causing div by 0.

Signed-off-by: Dave Airlie <airlied@linux.ie>
---
 drivers/video/intelfb/intelfbhw.c | 104 +++++++++---------------------
 1 file changed, 32 insertions(+), 72 deletions(-)

diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 16c9c192b4be6..426b7430b1254 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -615,6 +615,33 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
 	return vco / p;
 }
 
+static void
+intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
+{
+	int p1, p2;
+
+	if (IS_I9XX(dinfo)) {
+		if (dpll & DPLL_P1_FORCE_DIV2)
+			p1 = 1;
+		else
+			p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
+		
+		p1 = ffs(p1);
+
+		p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
+	} else {
+		if (dpll & DPLL_P1_FORCE_DIV2)
+			p1 = 0;
+		else
+			p1 = (dpll >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+		p2 = (dpll >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	}
+
+	*o_p1 = p1;
+	*o_p2 = p2;
+}
+
+
 void
 intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 {
@@ -633,12 +660,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-	if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
-		p1 = 0;
-	else
-		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
 
-	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+	intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
 
 	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
@@ -648,11 +671,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-	if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
-		p1 = 0;
-	else
-		p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
-	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
+
+	intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
 	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
 	printk("	VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
@@ -668,38 +688,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 
-	if (IS_I9XX(dinfo)) {
-		int tmpp1;
-
-		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-			p1 = 0;
-		else
-			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff;
-
-		tmpp1 = p1;
-
-		switch (tmpp1)
-		{
-		case 0x1: p1 = 1; break;
-		case 0x2: p1 = 2; break;
-		case 0x4: p1 = 3; break;
-		case 0x8: p1 = 4; break;
-		case 0x10: p1 = 5; break;
-		case 0x20: p1 = 6; break;
-		case 0x40: p1 = 7; break;
-		case 0x80: p1 = 8; break;
-		default: break;
-		}
-
-		p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
-
-	} else {
-		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-			p1 = 0;
-		else
-			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
-		p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
-	}
+	intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
 
 	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
@@ -709,37 +698,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 
-	if (IS_I9XX(dinfo)) {
-		int tmpp1;
-
-		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-			p1 = 0;
-		else
-			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff;
-
-		tmpp1 = p1;
-
-		switch (tmpp1) {
-		case 0x1: p1 = 1; break;
-		case 0x2: p1 = 2; break;
-		case 0x4: p1 = 3; break;
-		case 0x8: p1 = 4; break;
-		case 0x10: p1 = 5; break;
-		case 0x20: p1 = 6; break;
-		case 0x40: p1 = 7; break;
-		case 0x80: p1 = 8; break;
-		default: break;
-		}
-		
-		p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
+	intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
 
-	} else {
-		if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
-			p1 = 0;
-		else
-			p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
-		p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
-	}
 	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
 	       m1, m2, n, p1, p2);
 	printk("	PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));