From: Tom Rini <trini@kernel.crashing.org>

Adrian Cox has modified the Sandpoint code to once again work on the older
X2 version of the board.  The older version has a number of are on the
older version.

Signed-off-by: Adrian Cox <adrian@humboldt.co.uk>
Signed-off-by: Tom Rini <trini@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ppc/platforms/sandpoint.c  |   96 ++++++++++++++++++++++++++++----
 25-akpm/arch/ppc/syslib/mpc10x_common.c |   13 ++--
 25-akpm/arch/ppc/syslib/open_pic.c      |    9 ++-
 25-akpm/include/asm-ppc/open_pic.h      |    1 
 4 files changed, 100 insertions(+), 19 deletions(-)

diff -puN arch/ppc/platforms/sandpoint.c~ppc32-add-support-for-sandpoint-x2 arch/ppc/platforms/sandpoint.c
--- 25/arch/ppc/platforms/sandpoint.c~ppc32-add-support-for-sandpoint-x2	Thu Nov  4 14:36:30 2004
+++ 25-akpm/arch/ppc/platforms/sandpoint.c	Thu Nov  4 14:36:30 2004
@@ -60,11 +60,6 @@
  * of the amount of memory in the system.  Once a method of determining
  * what version of DINK initializes the system for us, if applicable, is
  * found, we can hopefully stop hardcoding 32MB of RAM.
- *
- * It is important to note that this code only supports the Sandpoint X3
- * (all flavors) platform, and it does not support the X2 anymore.  Code
- * that at one time worked on the X2 can be found at:
- * ftp://source.mvista.com/pub/linuxppc/obsolete/sandpoint/
  */
 
 #include <linux/config.h>
@@ -107,9 +102,13 @@
 
 #include "sandpoint.h"
 
+/* Set non-zero if an X2 Sandpoint detected. */
+static int sandpoint_is_x2;
+
 unsigned char __res[sizeof(bd_t)];
 
 static void sandpoint_halt(void);
+static void sandpoint_probe_type(void);
 
 /*
  * Define all of the IRQ senses and polarities.  Taken from the
@@ -129,7 +128,7 @@ static u_char sandpoint_openpic_initsens
  * Motorola SPS Sandpoint interrupt routing.
  */
 static inline int
-sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+x3_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
 	static char pci_irq_table[][4] =
 	/*
@@ -149,6 +148,27 @@ sandpoint_map_irq(struct pci_dev *dev, u
 	return PCI_IRQ_TABLE_LOOKUP;
 }
 
+static inline int
+x2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *	PCI IDSEL/INTPIN->INTLINE
+	 * 	   A   B   C   D
+	 */
+	{
+		{ 18,  0,  0,  0 },	/* IDSEL 11 - i8259 on Windbond */
+		{  0,  0,  0,  0 },	/* IDSEL 12 - unused */
+		{ 16, 17, 18, 19 },	/* IDSEL 13 - PCI slot 1 */
+		{ 17, 18, 19, 16 },	/* IDSEL 14 - PCI slot 2 */
+		{ 18, 19, 16, 17 },	/* IDSEL 15 - PCI slot 3 */
+		{ 19, 16, 17, 18 },	/* IDSEL 16 - PCI slot 4 */
+	};
+
+	const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
 static void __init
 sandpoint_setup_winbond_83553(struct pci_controller *hose)
 {
@@ -216,6 +236,18 @@ sandpoint_setup_winbond_83553(struct pci
 	return;
 }
 
+/* On the sandpoint X2, we must avoid sending configuration cycles to
+ * device #12 (IDSEL addr = AD12).
+ */
+static int
+x2_exclude_device(u_char bus, u_char devfn)
+{
+	if ((bus == 0) && (PCI_SLOT(devfn) == SANDPOINT_HOST_BRIDGE_IDSEL))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	else
+		return PCIBIOS_SUCCESSFUL;
+}
+
 static void __init
 sandpoint_find_bridges(void)
 {
@@ -241,7 +273,11 @@ sandpoint_find_bridges(void)
 		ppc_md.pcibios_fixup = NULL;
 		ppc_md.pcibios_fixup_bus = NULL;
 		ppc_md.pci_swizzle = common_swizzle;
-		ppc_md.pci_map_irq = sandpoint_map_irq;
+		if (sandpoint_is_x2) {
+			ppc_md.pci_map_irq = x2_map_irq;
+			ppc_md.pci_exclude_device = x2_exclude_device;
+		} else
+			ppc_md.pci_map_irq = x3_map_irq;
 	}
 	else {
 		if (ppc_md.progress)
@@ -255,6 +291,11 @@ sandpoint_find_bridges(void)
 static void __init
 sandpoint_setup_arch(void)
 {
+	/* Probe for Sandpoint model */
+	sandpoint_probe_type();
+	if (sandpoint_is_x2)
+		epic_serial_mode = 0;
+
 	loops_per_jiffy = 100000000 / HZ;
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -319,13 +360,48 @@ sandpoint_setup_arch(void)
 }
 
 /*
+ * To probe the Sandpoint type, we need to check for a connection between GPIO
+ * pins 6 and 7 on the NS87308 SuperIO.
+ */
+static void __init sandpoint_probe_type(void)
+{
+	u8 x;
+	/* First, ensure that the GPIO pins are enabled. */
+	SANDPOINT_87308_SELECT_DEV(0x07); /* Select GPIO logical device */
+	SANDPOINT_87308_CFG_OUTB(0x60, 0x07); /* Base address 0x700 */
+	SANDPOINT_87308_CFG_OUTB(0x61, 0x00);
+	SANDPOINT_87308_CFG_OUTB(0x30, 0x01); /* Enable */
+
+	/* Now, set pin 7 to output and pin 6 to input. */
+	outb((inb(0x701) | 0x80) & 0xbf, 0x701);
+	/* Set push-pull output */
+	outb(inb(0x702) | 0x80, 0x702);
+	/* Set pull-up on input */
+	outb(inb(0x703) | 0x40, 0x703);
+	/* Set output high and check */
+	x = inb(0x700);
+	outb(x | 0x80, 0x700);
+	x = inb(0x700);
+	sandpoint_is_x2 = ! (x & 0x40);
+	if (ppc_md.progress && sandpoint_is_x2)
+		ppc_md.progress("High output says X2", 0);
+	/* Set output low and check */
+	outb(x & 0x7f, 0x700);
+	sandpoint_is_x2 |= inb(0x700) & 0x40;
+	if (ppc_md.progress && sandpoint_is_x2)
+		ppc_md.progress("Low output says X2", 0);
+	if (ppc_md.progress && ! sandpoint_is_x2)
+		ppc_md.progress("Sandpoint is X3", 0);
+}
+
+/*
  * Fix IDE interrupts.
  */
 static int __init
 sandpoint_fix_winbond_83553(void)
 {
-	/* Make all 8259 interrupt level sensitive */
-	outb(0xf8, 0x4d0);
+	/* Make some 8259 interrupt level sensitive */
+	outb(0xe0, 0x4d0);
 	outb(0xde, 0x4d1);
 
 	return 0;
@@ -398,7 +474,7 @@ sandpoint_init_IRQ(void)
 	OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses);
 
 	mpc10x_set_openpic();
-	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+	openpic_hookup_cascade(sandpoint_is_x2 ? 17 : NUM_8259_INTERRUPTS, "82c59 cascade",
 			i8259_irq);
 
 	/*
diff -puN arch/ppc/syslib/mpc10x_common.c~ppc32-add-support-for-sandpoint-x2 arch/ppc/syslib/mpc10x_common.c
--- 25/arch/ppc/syslib/mpc10x_common.c~ppc32-add-support-for-sandpoint-x2	Thu Nov  4 14:36:30 2004
+++ 25-akpm/arch/ppc/syslib/mpc10x_common.c	Thu Nov  4 14:36:30 2004
@@ -43,7 +43,7 @@
 
 #ifdef CONFIG_MPC10X_OPENPIC
 #ifdef CONFIG_EPIC_SERIAL_MODE
-#define EPIC_IRQ_BASE 16
+#define EPIC_IRQ_BASE (epic_serial_mode ? 16 : 5)
 #else
 #define EPIC_IRQ_BASE 5
 #endif
@@ -69,20 +69,16 @@ static struct ocp_def mpc10x_i2c_ocp = {
 	.vendor		= OCP_VENDOR_MOTOROLA,
 	.function	= OCP_FUNC_IIC,
 	.index		= 0,
-	.irq		= MPC10X_I2C_IRQ,
 	.additions	= &mpc10x_i2c_data
 };
 
 static struct ocp_def mpc10x_dma_ocp[2] = {
 {	.vendor		= OCP_VENDOR_MOTOROLA,
 	.function	= OCP_FUNC_DMA,
-	.index		= 0,
-	.irq		= MPC10X_DMA0_IRQ
-},
+	.index		= 0 },
 {	.vendor		= OCP_VENDOR_MOTOROLA,
 	.function	= OCP_FUNC_DMA,
-	.index		= 1,
-	.irq		= MPC10X_DMA1_IRQ }
+	.index		= 1 }
 };
 
 /* Set resources to match bridge memory map */
@@ -292,12 +288,15 @@ mpc10x_bridge_init(struct pci_controller
 				MPC10X_EUMB_EPIC_SIZE);
 #endif
 		mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET;
+		mpc10x_i2c_ocp.irq = MPC10X_I2C_IRQ;
 		ocp_add_one_device(&mpc10x_i2c_ocp);
 		mpc10x_dma_ocp[0].paddr = phys_eumb_base +
 					MPC10X_EUMB_DMA_OFFSET + 0x100;
+		mpc10x_dma_ocp[0].irq = MPC10X_DMA0_IRQ;
 		ocp_add_one_device(&mpc10x_dma_ocp[0]);
 		mpc10x_dma_ocp[1].paddr = phys_eumb_base +
 					MPC10X_EUMB_DMA_OFFSET + 0x200;
+		mpc10x_dma_ocp[1].irq = MPC10X_DMA1_IRQ;
 		ocp_add_one_device(&mpc10x_dma_ocp[1]);
 	}
 
diff -puN arch/ppc/syslib/open_pic.c~ppc32-add-support-for-sandpoint-x2 arch/ppc/syslib/open_pic.c
--- 25/arch/ppc/syslib/open_pic.c~ppc32-add-support-for-sandpoint-x2	Thu Nov  4 14:36:30 2004
+++ 25-akpm/arch/ppc/syslib/open_pic.c	Thu Nov  4 14:36:30 2004
@@ -261,6 +261,9 @@ static void openpic_safe_writefield_IPI(
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_EPIC_SERIAL_MODE
+/* On platforms that may use EPIC serial mode, the default is enabled. */
+int epic_serial_mode = 1;
+
 static void __init openpic_eicr_set_clk(u_int clkval)
 {
 	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
@@ -415,8 +418,10 @@ void __init openpic_init(int offset)
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
 	openpic_disable_8259_pass_through();
 #ifdef CONFIG_EPIC_SERIAL_MODE
-	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
-	openpic_enable_sie();
+	if (epic_serial_mode) {
+		openpic_eicr_set_clk(7);	/* Slowest value until we know better */
+		openpic_enable_sie();
+	}
 #endif
 	openpic_set_priority(0);
 
diff -puN include/asm-ppc/open_pic.h~ppc32-add-support-for-sandpoint-x2 include/asm-ppc/open_pic.h
--- 25/include/asm-ppc/open_pic.h~ppc32-add-support-for-sandpoint-x2	Thu Nov  4 14:36:30 2004
+++ 25-akpm/include/asm-ppc/open_pic.h	Thu Nov  4 14:36:30 2004
@@ -36,6 +36,7 @@ extern struct hw_interrupt_type open_pic
 extern u_int OpenPIC_NumInitSenses;
 extern u_char *OpenPIC_InitSenses;
 extern void* OpenPIC_Addr;
+extern int epic_serial_mode;
 
 /* Exported functions */
 extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
_