sh: pci: Support slot 4 routing on SDK7786.

SDK7786 supports connecting either slot3 or 4 to the same PCIe port by
way of FPGA muxing. By default the vertical slot 3 on the baseboard is
enabled, so this adds in a command line option for forcibly enabling the
slot 4 edge connector.

If nothing has been specified on the command line, we fall back to
reading the resistor values for card presence to figure out where to
route the port to.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 4a59e68..82f0a33 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_SH_SH03)			+= fixups-sh03.o
 obj-$(CONFIG_SH_HIGHLANDER)		+= fixups-r7780rp.o
 obj-$(CONFIG_SH_SH7785LCR)		+= fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7786)		+= fixups-sdk7786.o
 obj-$(CONFIG_SH_SDK7780)		+= fixups-sdk7780.o
 obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)	+= fixups-sdk7780.o
 obj-$(CONFIG_SH_TITAN)			+= fixups-titan.o
diff --git a/arch/sh/drivers/pci/fixups-sdk7786.c b/arch/sh/drivers/pci/fixups-sdk7786.c
new file mode 100644
index 0000000..058a65a
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-sdk7786.c
@@ -0,0 +1,68 @@
+/*
+ * SDK7786 FPGA PCIe mux handling
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "PCI: " fmt
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <mach/fpga.h>
+
+/*
+ * The SDK7786 FPGA supports mangling of most of the slots in some way or
+ * another. Slots 3/4 are special in that only one can be supported at a
+ * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
+ * (the horizontal edge connector) will disable slot 3 entirely.
+ *
+ * Misconfigurations can be detected through the FPGA via the slot
+ * resistors to determine card presence. Hotplug remains unsupported.
+ */
+static unsigned int slot4en __devinitdata;
+
+char *__devinit pcibios_setup(char *str)
+{
+	if (strcmp(str, "slot4en") == 0) {
+		slot4en = 1;
+		return NULL;
+	}
+
+	return str;
+}
+
+static int __init sdk7786_pci_init(void)
+{
+	u16 data = fpga_read_reg(PCIECR);
+
+	/*
+	 * Enable slot #4 if it's been specified on the command line.
+	 *
+	 * Optionally reroute if slot #4 has a card present while slot #3
+	 * does not, regardless of command line value.
+	 *
+	 * Card presence is logically inverted.
+	 */
+	slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
+	if (slot4en) {
+		pr_info("Activating PCIe slot#4 (disabling slot#3)\n");
+
+		data &= ~PCIECR_PCIEMUX1;
+		fpga_write_reg(data, PCIECR);
+
+		/* Warn about forced rerouting if slot#3 is occupied */
+		if ((data & PCIECR_PRST3) == 0) {
+			pr_warning("Unreachable card detected in slot#3\n");
+			return -EBUSY;
+		}
+	} else
+		pr_info("PCIe slot#4 disabled\n");
+
+	return 0;
+}
+postcore_initcall(sdk7786_pci_init);
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index af4191b..60ee09a 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -268,7 +268,7 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-char * __devinit pcibios_setup(char *str)
+char * __devinit __weak pcibios_setup(char *str)
 {
 	return str;
 }
diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h
index 416b621..8cc7841 100644
--- a/arch/sh/include/mach-sdk7786/mach/fpga.h
+++ b/arch/sh/include/mach-sdk7786/mach/fpga.h
@@ -31,7 +31,16 @@
 #define EXTASR		0x110
 #define SPCAR		0x120
 #define INTMSR		0x130
+
 #define PCIECR		0x140
+#define  PCIECR_PCIEMUX1	BIT(15)
+#define  PCIECR_PCIEMUX0	BIT(14)
+#define  PCIECR_PRST4		BIT(12) /* slot 4 card present */
+#define  PCIECR_PRST3		BIT(11) /* slot 3 card present */
+#define  PCIECR_PRST2		BIT(10) /* slot 2 card present */
+#define  PCIECR_PRST1		BIT(9)  /* slot 1 card present */
+#define  PCIECR_CLKEN		BIT(4)
+
 #define FAER		0x150
 #define USRGPIR		0x160
 /* 0x170 reserved */