[ARM] Orion: rework MPP handling

Instead of having board code poke directly into the MPP configuration
registers, and separately calling orion5x_gpio_set_valid_pins() to
indicate which MPP pins can be used as GPIO pins, introduce a helper
function for configuring the roles of each of the MPP pins, and have
that helper function handle gpio validity internally.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Acked-by: Sylver Bruneau <sylver.bruneau@googlemail.com>
Acked-by: Russell King <linux@arm.linux.org.uk>
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile
index 9301bf5..55da46e 100644
--- a/arch/arm/mach-orion5x/Makefile
+++ b/arch/arm/mach-orion5x/Makefile
@@ -1,4 +1,4 @@
-obj-y				+= common.o addr-map.o pci.o gpio.o irq.o
+obj-y				+= common.o addr-map.o pci.o gpio.o irq.o mpp.o
 obj-$(CONFIG_MACH_DB88F5281)	+= db88f5281-setup.o
 obj-$(CONFIG_MACH_RD88F5182)	+= rd88f5182-setup.o
 obj-$(CONFIG_MACH_KUROBOX_PRO)	+= kurobox_pro-setup.o
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index da37c20..97db8d8 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -48,7 +48,7 @@
  * Valid GPIO pins according to MPP setup, used by machine-setup.
  * (/mach-orion/gpio.c).
  */
-void orion5x_gpio_set_valid_pins(u32 pins);
+void orion5x_gpio_set_valid(unsigned pin, int valid);
 void gpio_display(void);	/* debug */
 
 struct machine_desc;
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index eca76b3..3fee400 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -27,6 +27,7 @@
 #include <asm/arch/orion5x.h>
 #include <asm/plat-orion/orion_nand.h>
 #include "common.h"
+#include "mpp.h"
 
 /*****************************************************************************
  * DB-88F5281 on board devices
@@ -298,6 +299,30 @@
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
+static struct orion5x_mpp_mode db88f5281_mpp_modes[] __initdata = {
+	{  0, MPP_GPIO },		/* USB Over Current */
+	{  1, MPP_GPIO },		/* USB Vbat input */
+	{  2, MPP_PCI_ARB },		/* PCI_REQn[2] */
+	{  3, MPP_PCI_ARB },		/* PCI_GNTn[2] */
+	{  4, MPP_PCI_ARB },		/* PCI_REQn[3] */
+	{  5, MPP_PCI_ARB },		/* PCI_GNTn[3] */
+	{  6, MPP_GPIO },		/* JP0, CON17.2 */
+	{  7, MPP_GPIO },		/* JP1, CON17.1 */
+	{  8, MPP_GPIO },		/* JP2, CON11.2 */
+	{  9, MPP_GPIO },		/* JP3, CON11.3 */
+	{ 10, MPP_GPIO },		/* RTC int */
+	{ 11, MPP_GPIO },		/* Baud Rate Generator */
+	{ 12, MPP_GPIO },		/* PCI int 1 */
+	{ 13, MPP_GPIO },		/* PCI int 2 */
+	{ 14, MPP_NAND },		/* NAND_REn[2] */
+	{ 15, MPP_NAND },		/* NAND_WEn[2] */
+	{ 16, MPP_UART },		/* UART1_RX */
+	{ 17, MPP_UART },		/* UART1_TX */
+	{ 18, MPP_UART },		/* UART1_CTSn */
+	{ 19, MPP_UART },		/* UART1_RTSn */
+	{ -1 },
+};
+
 static void __init db88f5281_init(void)
 {
 	/*
@@ -305,26 +330,8 @@
 	 */
 	orion5x_init();
 
-	/*
-	 * Setup Multiplexing Pins:
-	 * MPP0: GPIO (USB Over Current)	MPP1: GPIO (USB Vbat input)
-	 * MPP2: PCI_REQn[2]			MPP3: PCI_GNTn[2]
-	 * MPP4: PCI_REQn[3]			MPP5: PCI_GNTn[3]
-	 * MPP6: GPIO (JP0, CON17.2)		MPP7: GPIO (JP1, CON17.1)
-	 * MPP8: GPIO (JP2, CON11.2)		MPP9: GPIO (JP3, CON11.3)
-	 * MPP10: GPIO (RTC int)		MPP11: GPIO (Baud Rate Generator)
-	 * MPP12: GPIO (PCI int 1)		MPP13: GPIO (PCI int 2)
-	 * MPP14: NAND_REn[2]			MPP15: NAND_WEn[2]
-	 * MPP16: UART1_RX			MPP17: UART1_TX
-	 * MPP18: UART1_CTS			MPP19: UART1_RTS
-	 * MPP-DEV: DEV_D[16:31]
-	 */
-	orion5x_write(MPP_0_7_CTRL, 0x00222203);
-	orion5x_write(MPP_8_15_CTRL, 0x44000000);
-	orion5x_write(MPP_16_19_CTRL, 0);
-	orion5x_write(MPP_DEV_CTRL, 0);
-
-	orion5x_gpio_set_valid_pins(0x00003fc3);
+	orion5x_mpp_conf(db88f5281_mpp_modes);
+	orion5x_write(MPP_DEV_CTRL, 0);		/* DEV_D[31:16] */
 
 	/*
 	 * Configure peripherals.
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 9ec5350..05ce660 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -27,6 +27,7 @@
 #include <asm/mach/pci.h>
 #include <asm/arch/orion5x.h>
 #include "common.h"
+#include "mpp.h"
 
 #define DNS323_GPIO_LED_RIGHT_AMBER	1
 #define DNS323_GPIO_LED_LEFT_AMBER	2
@@ -212,6 +213,29 @@
 /****************************************************************************
  * General Setup
  */
+static struct orion5x_mpp_mode dns323_mpp_modes[] __initdata = {
+	{  0, MPP_PCIE_RST_OUTn },
+	{  1, MPP_GPIO },		/* right amber LED (sata ch0) */
+	{  2, MPP_GPIO },		/* left amber LED (sata ch1) */
+	{  3, MPP_UNUSED },
+	{  4, MPP_GPIO },		/* power button LED */
+	{  5, MPP_GPIO },		/* power button LED */
+	{  6, MPP_GPIO },		/* GMT G751-2f overtemp */
+	{  7, MPP_GPIO },		/* M41T80 nIRQ/OUT/SQW */
+	{  8, MPP_GPIO },		/* triggers power off */
+	{  9, MPP_GPIO },		/* power button switch */
+	{ 10, MPP_GPIO },		/* reset button switch */
+	{ 11, MPP_UNUSED },
+	{ 12, MPP_UNUSED },
+	{ 13, MPP_UNUSED },
+	{ 14, MPP_UNUSED },
+	{ 15, MPP_UNUSED },
+	{ 16, MPP_UNUSED },
+	{ 17, MPP_UNUSED },
+	{ 18, MPP_UNUSED },
+	{ 19, MPP_UNUSED },
+	{ -1 },
+};
 
 /*
  * On the DNS-323 the following devices are attached via I2C:
@@ -247,34 +271,8 @@
 	/* Setup basic Orion functions. Need to be called early. */
 	orion5x_init();
 
-	/* set MPP to 0 as D-Link's 2.6.12.6 kernel did */
-	orion5x_write(MPP_0_7_CTRL, 0);
-	orion5x_write(MPP_8_15_CTRL, 0);
-	orion5x_write(MPP_16_19_CTRL, 0);
-	orion5x_write(MPP_DEV_CTRL, 0);
-
-	/* Define used GPIO pins
-
-	  GPIO Map:
-
-	  |  0 |     | PEX_RST_OUT (not controlled by GPIO)
-	  |  1 | Out | right amber LED (= sata ch0 LED)  (low-active)
-	  |  2 | Out | left  amber LED (= sata ch1 LED)  (low-active)
-	  |  3 | Out | //unknown//
-	  |  4 | Out | power button LED (low-active, together with pin #5)
-	  |  5 | Out | power button LED (low-active, together with pin #4)
-	  |  6 | In  | GMT G751-2f overtemp. shutdown signal (low-active)
-	  |  7 | In  | M41T80 nIRQ/OUT/SQW signal
-	  |  8 | Out | triggers power off (high-active)
-	  |  9 | In  | power button switch (low-active)
-	  | 10 | In  | reset button switch (low-active)
-	  | 11 | Out | //unknown//
-	  | 12 | Out | //unknown//
-	  | 13 | Out | //unknown//
-	  | 14 | Out | //unknown//
-	  | 15 | Out | //unknown//
-	*/
-	orion5x_gpio_set_valid_pins(0x07f6);
+	orion5x_mpp_conf(dns323_mpp_modes);
+	orion5x_write(MPP_DEV_CTRL, 0);		/* DEV_D[31:16] */
 
 	/*
 	 * Configure peripherals.
diff --git a/arch/arm/mach-orion5x/gpio.c b/arch/arm/mach-orion5x/gpio.c
index 8108c31..9fba6a1 100644
--- a/arch/arm/mach-orion5x/gpio.c
+++ b/arch/arm/mach-orion5x/gpio.c
@@ -24,9 +24,12 @@
 static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)];
 static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
 
-void __init orion5x_gpio_set_valid_pins(u32 pins)
+void __init orion5x_gpio_set_valid(unsigned pin, int valid)
 {
-	gpio_valid[0] = pins;
+	if (valid)
+		__set_bit(pin, gpio_valid);
+	else
+		__clear_bit(pin, gpio_valid);
 }
 
 /*
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index 61755fe..f0997a7 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -25,6 +25,7 @@
 #include <asm/arch/orion5x.h>
 #include <asm/plat-orion/orion_nand.h>
 #include "common.h"
+#include "mpp.h"
 
 /*****************************************************************************
  * KUROBOX-PRO Info
@@ -179,6 +180,29 @@
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
+static struct orion5x_mpp_mode kurobox_pro_mpp_modes[] __initdata = {
+	{  0, MPP_UNUSED },
+	{  1, MPP_UNUSED },
+	{  2, MPP_GPIO },		/* GPIO Micon */
+	{  3, MPP_GPIO },		/* GPIO Rtc */
+	{  4, MPP_UNUSED },
+	{  5, MPP_UNUSED },
+	{  6, MPP_NAND },		/* NAND Flash REn */
+	{  7, MPP_NAND },		/* NAND Flash WEn */
+	{  8, MPP_UNUSED },
+	{  9, MPP_UNUSED },
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_UNUSED },
+	{ 12, MPP_SATA_LED },		/* SATA 0 presence */
+	{ 13, MPP_SATA_LED },		/* SATA 1 presence */
+	{ 14, MPP_SATA_LED },		/* SATA 0 active */
+	{ 15, MPP_SATA_LED },		/* SATA 1 active */
+	{ 16, MPP_UNUSED },
+	{ 17, MPP_UNUSED },
+	{ 18, MPP_UNUSED },
+	{ 19, MPP_UNUSED },
+	{ -1 },
+};
 
 static void __init kurobox_pro_init(void)
 {
@@ -187,26 +211,7 @@
 	 */
 	orion5x_init();
 
-	/*
-	 * Setup Multiplexing Pins --
-	 * MPP[0-1] Not used
-	 * MPP[2] GPIO Micon
-	 * MPP[3] GPIO RTC
-	 * MPP[4-5] Not used
-	 * MPP[6] Nand Flash REn
-	 * MPP[7] Nand Flash WEn
-	 * MPP[8-11] Not used
-	 * MPP[12] SATA 0 presence Indication
-	 * MPP[13] SATA 1 presence Indication
-	 * MPP[14] SATA 0 active Indication
-	 * MPP[15] SATA 1 active indication
-	 * MPP[16-19] Not used
-	 */
-	orion5x_write(MPP_0_7_CTRL, 0x44220003);
-	orion5x_write(MPP_8_15_CTRL, 0x55550000);
-	orion5x_write(MPP_16_19_CTRL, 0x0);
-
-	orion5x_gpio_set_valid_pins(0x0000000c);
+	orion5x_mpp_conf(kurobox_pro_mpp_modes);
 
 	/*
 	 * Configure peripherals.
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
new file mode 100644
index 0000000..a48cadb
--- /dev/null
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -0,0 +1,163 @@
+/*
+ * arch/arm/mach-orion5x/mpp.c
+ *
+ * MPP functions for Marvell Orion 5x SoCs
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mbus.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include "common.h"
+#include "mpp.h"
+
+static int is_5181l(void)
+{
+	u32 dev;
+	u32 rev;
+
+	orion5x_pcie_id(&dev, &rev);
+
+	return !!(dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0);
+}
+
+static int is_5182(void)
+{
+	u32 dev;
+	u32 rev;
+
+	orion5x_pcie_id(&dev, &rev);
+
+	return !!(dev == MV88F5182_DEV_ID);
+}
+
+static int is_5281(void)
+{
+	u32 dev;
+	u32 rev;
+
+	orion5x_pcie_id(&dev, &rev);
+
+	return !!(dev == MV88F5281_DEV_ID);
+}
+
+static int __init determine_type_encoding(int mpp, enum orion5x_mpp_type type)
+{
+	switch (type) {
+	case MPP_UNUSED:
+	case MPP_GPIO:
+		if (mpp == 0)
+			return 3;
+		if (mpp >= 1 && mpp <= 15)
+			return 0;
+		if (mpp >= 16 && mpp <= 19) {
+			if (is_5182())
+				return 5;
+			if (type == MPP_UNUSED)
+				return 0;
+		}
+		return -1;
+
+	case MPP_PCIE_RST_OUTn:
+		if (mpp == 0)
+			return 0;
+		return -1;
+
+	case MPP_PCI_ARB:
+		if (mpp >= 0 && mpp <= 7)
+			return 2;
+		return -1;
+
+	case MPP_PCI_PMEn:
+		if (mpp == 2)
+			return 3;
+		return -1;
+
+	case MPP_GIGE:
+		if (mpp >= 8 && mpp <= 19)
+			return 1;
+		return -1;
+
+	case MPP_NAND:
+		if (is_5182() || is_5281()) {
+			if (mpp >= 4 && mpp <= 7)
+				return 4;
+			if (mpp >= 12 && mpp <= 17)
+				return 4;
+		}
+		return -1;
+
+	case MPP_PCI_CLK:
+		if (is_5181l() && mpp >= 6 && mpp <= 7)
+			return 5;
+		return -1;
+
+	case MPP_SATA_LED:
+		if (is_5182()) {
+			if (mpp >= 4 && mpp <= 7)
+				return 5;
+			if (mpp >= 12 && mpp <= 15)
+				return 5;
+		}
+		return -1;
+
+	case MPP_UART:
+		if (mpp >= 16 && mpp <= 19)
+			return 0;
+		return -1;
+	}
+
+	printk(KERN_INFO "unknown MPP type %d\n", type);
+
+	return -1;
+}
+
+void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
+{
+	u32 mpp_0_7_ctrl = readl(MPP_0_7_CTRL);
+	u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
+	u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
+
+	while (mode->mpp >= 0) {
+		u32 *reg;
+		int num_type;
+		int shift;
+
+		if (mode->mpp >= 0 && mode->mpp <= 7)
+			reg = &mpp_0_7_ctrl;
+		else if (mode->mpp >= 8 && mode->mpp <= 15)
+			reg = &mpp_8_15_ctrl;
+		else if (mode->mpp >= 16 && mode->mpp <= 19)
+			reg = &mpp_16_19_ctrl;
+		else {
+			printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
+					"(%d)\n", mode->mpp);
+			continue;
+		}
+
+		num_type = determine_type_encoding(mode->mpp, mode->type);
+		if (num_type < 0) {
+			printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
+					"combination (%d, %d)\n", mode->mpp,
+					mode->type);
+			continue;
+		}
+
+		shift = (mode->mpp & 7) << 2;
+		*reg &= ~(0xf << shift);
+		*reg |= (num_type & 0xf) << shift;
+
+		orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
+
+		mode++;
+	}
+
+	writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
+	writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
+	writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
+}
diff --git a/arch/arm/mach-orion5x/mpp.h b/arch/arm/mach-orion5x/mpp.h
new file mode 100644
index 0000000..290e610
--- /dev/null
+++ b/arch/arm/mach-orion5x/mpp.h
@@ -0,0 +1,74 @@
+#ifndef __ARCH_ORION5X_MPP_H
+#define __ARCH_ORION5X_MPP_H
+
+enum orion5x_mpp_type {
+	/*
+	 * This MPP is unused.
+	 */
+	MPP_UNUSED,
+
+	/*
+	 * This MPP pin is used as a generic GPIO pin.  Valid for
+	 * MPPs 0-15 and device bus data pins 16-31.  On 5182, also
+	 * valid for MPPs 16-19.
+	 */
+	MPP_GPIO,
+
+	/*
+	 * This MPP is used as PCIe_RST_OUTn pin.  Valid for
+	 * MPP 0 only.
+	 */
+	MPP_PCIE_RST_OUTn,
+
+	/*
+	 * This MPP is used as PCI arbiter pin (REQn/GNTn).
+	 * Valid for MPPs 0-7 only.
+	 */
+	MPP_PCI_ARB,
+
+	/*
+	 * This MPP is used as PCI_PMEn pin.  Valid for MPP 2 only.
+	 */
+	MPP_PCI_PMEn,
+
+	/*
+	 * This MPP is used as GigE half-duplex (COL, CRS) or GMII
+	 * (RXERR, CRS, TXERR, TXD[7:4], RXD[7:4]) pin.  Valid for
+	 * MPPs 8-19 only.
+	 */
+	MPP_GIGE,
+
+	/*
+	 * This MPP is used as NAND REn/WEn pin.  Valid for MPPs
+	 * 4-7 and 12-17 only, and only on the 5181l/5182/5281.
+	 */
+	MPP_NAND,
+
+	/*
+	 * This MPP is used as a PCI clock output pin.  Valid for
+	 * MPPs 6-7 only, and only on the 5181l.
+	 */
+	MPP_PCI_CLK,
+
+	/*
+	 * This MPP is used as a SATA presence/activity LED.
+	 * Valid for MPPs 4-7 and 12-15 only, and only on the 5182.
+	 */
+	MPP_SATA_LED,
+
+	/*
+	 * This MPP is used as UART1 RXD/TXD/CTSn/RTSn pin.
+	 * Valid for MPPs 16-19 only.
+	 */
+	MPP_UART,
+};
+
+struct orion5x_mpp_mode {
+	int			mpp;
+	enum orion5x_mpp_type	type;
+};
+
+void orion5x_mpp_conf(struct orion5x_mpp_mode *mode);
+
+
+#endif
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 403ba9a..44ad5de 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -26,6 +26,7 @@
 #include <asm/mach/pci.h>
 #include <asm/arch/orion5x.h>
 #include "common.h"
+#include "mpp.h"
 
 /*****************************************************************************
  * RD-88F5182 Info
@@ -241,6 +242,30 @@
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
+static struct orion5x_mpp_mode rd88f5182_mpp_modes[] __initdata = {
+	{  0, MPP_GPIO },		/* Debug Led */
+	{  1, MPP_GPIO },		/* Reset Switch */
+	{  2, MPP_UNUSED },
+	{  3, MPP_GPIO },		/* RTC Int */
+	{  4, MPP_GPIO },
+	{  5, MPP_GPIO },
+	{  6, MPP_GPIO },		/* PCI_intA */
+	{  7, MPP_GPIO },		/* PCI_intB */
+	{  8, MPP_UNUSED },
+	{  9, MPP_UNUSED },
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_UNUSED },
+	{ 12, MPP_SATA_LED },		/* SATA 0 presence */
+	{ 13, MPP_SATA_LED },		/* SATA 1 presence */
+	{ 14, MPP_SATA_LED },		/* SATA 0 active */
+	{ 15, MPP_SATA_LED },		/* SATA 1 active */
+	{ 16, MPP_UNUSED },
+	{ 17, MPP_UNUSED },
+	{ 18, MPP_UNUSED },
+	{ 19, MPP_UNUSED },
+	{ -1 },
+};
+
 static void __init rd88f5182_init(void)
 {
 	/*
@@ -248,22 +273,9 @@
 	 */
 	orion5x_init();
 
+	orion5x_mpp_conf(rd88f5182_mpp_modes);
+
 	/*
-	 * Setup Multiplexing Pins --
-	 * MPP[0] Debug Led (GPIO - Out)
-	 * MPP[1] Debug Led (GPIO - Out)
-	 * MPP[2] N/A
-	 * MPP[3] RTC_Int (GPIO - In)
-	 * MPP[4] GPIO
-	 * MPP[5] GPIO
-	 * MPP[6] PCI_intA (GPIO - In)
-	 * MPP[7] PCI_intB (GPIO - In)
-	 * MPP[8-11] N/A
-	 * MPP[12] SATA 0 presence Indication
-	 * MPP[13] SATA 1 presence Indication
-	 * MPP[14] SATA 0 active Indication
-	 * MPP[15] SATA 1 active indication
-	 * MPP[16-19] Not used
 	 * MPP[20] PCI Clock to MV88F5182
 	 * MPP[21] PCI Clock to mini PCI CON11
 	 * MPP[22] USB 0 over current indication
@@ -272,12 +284,6 @@
 	 * MPP[25] USB 0 over current enable
 	 */
 
-	orion5x_write(MPP_0_7_CTRL, 0x00000003);
-	orion5x_write(MPP_8_15_CTRL, 0x55550000);
-	orion5x_write(MPP_16_19_CTRL, 0x5555);
-
-	orion5x_gpio_set_valid_pins(0x000000fb);
-
 	/*
 	 * Configure peripherals.
 	 */
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index 0ec067f..5ad7ad9 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -28,6 +28,7 @@
 #include <asm/mach/pci.h>
 #include <asm/arch/orion5x.h>
 #include "common.h"
+#include "mpp.h"
 
 #define QNAP_TS209_NOR_BOOT_BASE 0xf4000000
 #define QNAP_TS209_NOR_BOOT_SIZE SZ_8M
@@ -332,6 +333,30 @@
 
  * General Setup
  ****************************************************************************/
+static struct orion5x_mpp_mode ts209_mpp_modes[] __initdata = {
+	{  0, MPP_UNUSED },
+	{  1, MPP_GPIO },		/* USB copy button */
+	{  2, MPP_GPIO },		/* Load defaults button */
+	{  3, MPP_GPIO },		/* GPIO RTC */
+	{  4, MPP_UNUSED },
+	{  5, MPP_UNUSED },
+	{  6, MPP_GPIO },		/* PCI Int A */
+	{  7, MPP_GPIO },		/* PCI Int B */
+	{  8, MPP_UNUSED },
+	{  9, MPP_UNUSED },
+	{ 10, MPP_UNUSED },
+	{ 11, MPP_UNUSED },
+	{ 12, MPP_SATA_LED },		/* SATA 0 presence */
+	{ 13, MPP_SATA_LED },		/* SATA 1 presence */
+	{ 14, MPP_SATA_LED },		/* SATA 0 active */
+	{ 15, MPP_SATA_LED },		/* SATA 1 active */
+	{ 16, MPP_UART },		/* UART1 RXD */
+	{ 17, MPP_UART },		/* UART1 TXD */
+	{ 18, MPP_GPIO },		/* SW_RST */
+	{ 19, MPP_UNUSED },
+	{ -1 },
+};
+
 /*
  * QNAP TS-[12]09 specific power off method via UART1-attached PIC
  */
@@ -364,33 +389,14 @@
 	 */
 	orion5x_init();
 
+	orion5x_mpp_conf(ts209_mpp_modes);
+
 	/*
-	 * Setup Multiplexing Pins --
-	 * MPP[0] Reserved
-	 * MPP[1] USB copy button (0 active)
-	 * MPP[2] Load defaults button (0 active)
-	 * MPP[3] GPIO RTC
-	 * MPP[4-5] Reserved
-	 * MPP[6] PCI Int A
-	 * MPP[7] PCI Int B
-	 * MPP[8-11] Reserved
-	 * MPP[12] SATA 0 presence
-	 * MPP[13] SATA 1 presence
-	 * MPP[14] SATA 0 active
-	 * MPP[15] SATA 1 active
-	 * MPP[16] UART1 RXD
-	 * MPP[17] UART1 TXD
-	 * MPP[18] SW_RST (0 active)
-	 * MPP[19] Reserved
 	 * MPP[20] PCI clock 0
 	 * MPP[21] PCI clock 1
 	 * MPP[22] USB 0 over current
 	 * MPP[23-25] Reserved
 	 */
-	orion5x_write(MPP_0_7_CTRL, 0x3);
-	orion5x_write(MPP_8_15_CTRL, 0x55550000);
-	orion5x_write(MPP_16_19_CTRL, 0x5500);
-	orion5x_gpio_set_valid_pins(0x3cc0fff);
 
 	/*
 	 * Configure peripherals.