kmp204x: introduce QRIO GPIO functions

The QRIO GPIO functions can be of general interest. They are thus added
to a qrio.c and their prototype are available from kmp204x.h. The QRIO
prst function are also included in this file, as well as the functions
required for the I2C deblocking support (open-drain).

Signed-off-by: Valentin Longchamp <valentin.longchamp@keymile.com>
[York Sun: Remove extra blank line in board/keymile/kmp204x/qrio.c]
Signed-off-by: York Sun <yorksun@freescale.com>
diff --git a/board/keymile/kmp204x/Makefile b/board/keymile/kmp204x/Makefile
index 3e69ee2..c57ca08 100644
--- a/board/keymile/kmp204x/Makefile
+++ b/board/keymile/kmp204x/Makefile
@@ -8,5 +8,5 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-y	:= kmp204x.o ddr.o eth.o tlb.o pci.o law.o \
+obj-y	:= kmp204x.o ddr.o eth.o tlb.o pci.o law.o qrio.o \
 	../common/common.o ../common/ivm.o
diff --git a/board/keymile/kmp204x/kmp204x.c b/board/keymile/kmp204x/kmp204x.c
index 20a3264..bbb2453 100644
--- a/board/keymile/kmp204x/kmp204x.c
+++ b/board/keymile/kmp204x/kmp204x.c
@@ -77,62 +77,6 @@
 	return 66666666;
 }
 
-#define WDMASK_OFF	0x16
-
-static void qrio_wdmask(u8 bit, bool wden)
-{
-	u16 wdmask;
-	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
-
-	wdmask = in_be16(qrio_base + WDMASK_OFF);
-
-	if (wden)
-		wdmask |= (1 << bit);
-	else
-		wdmask &= ~(1 << bit);
-
-	out_be16(qrio_base + WDMASK_OFF, wdmask);
-}
-
-#define PRST_OFF	0x1a
-
-void qrio_prst(u8 bit, bool en, bool wden)
-{
-	u16 prst;
-	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
-
-	qrio_wdmask(bit, wden);
-
-	prst = in_be16(qrio_base + PRST_OFF);
-
-	if (en)
-		prst &= ~(1 << bit);
-	else
-		prst |= (1 << bit);
-
-	out_be16(qrio_base + PRST_OFF, prst);
-}
-
-#define PRSTCFG_OFF	0x1c
-
-void qrio_prstcfg(u8 bit, u8 mode)
-{
-	u32 prstcfg;
-	u8 i;
-	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
-
-	prstcfg = in_be32(qrio_base + PRSTCFG_OFF);
-
-	for (i = 0; i < 2; i++) {
-		if (mode & (1<<i))
-			set_bit(2*bit+i, &prstcfg);
-		else
-			clear_bit(2*bit+i, &prstcfg);
-	}
-
-	out_be32(qrio_base + PRSTCFG_OFF, prstcfg);
-}
-
 #define NUM_SRDS_BANKS	2
 #define PHY_RST		15
 
diff --git a/board/keymile/kmp204x/kmp204x.h b/board/keymile/kmp204x/kmp204x.h
index b6ba672..0267596 100644
--- a/board/keymile/kmp204x/kmp204x.h
+++ b/board/keymile/kmp204x/kmp204x.h
@@ -5,6 +5,16 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+/* QRIO GPIO ports */
+#define GPIO_A			0x40
+#define GPIO_B			0x60
+
+int qrio_get_gpio(u8 port_off, u8 gpio_nr);
+void qrio_set_opendrain_gpio(u8 port_off, u8 gpio_nr, u8 val);
+void qrio_set_gpio(u8 port_off, u8 gpio_nr, bool value);
+void qrio_gpio_direction_output(u8 port_off, u8 gpio_nr, bool value);
+void qrio_gpio_direction_input(u8 port_off, u8 gpio_nr);
+
 #define PRSTCFG_POWUP_UNIT_CORE_RST	0x0
 #define PRSTCFG_POWUP_UNIT_RST		0x1
 #define PRSTCFG_POWUP_RST		0x3
diff --git a/board/keymile/kmp204x/qrio.c b/board/keymile/kmp204x/qrio.c
new file mode 100644
index 0000000..49f9aa2
--- /dev/null
+++ b/board/keymile/kmp204x/qrio.c
@@ -0,0 +1,146 @@
+/*
+ * (C) Copyright 2013 Keymile AG
+ * Valentin Longchamp <valentin.longchamp@keymile.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+#include "../common/common.h"
+#include "kmp204x.h"
+
+/* QRIO GPIO register offsets */
+#define DIRECT_OFF		0x18
+#define GPRT_OFF		0x1c
+
+int qrio_get_gpio(u8 port_off, u8 gpio_nr)
+{
+	u32 gprt;
+
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	gprt = in_be32(qrio_base + port_off + GPRT_OFF);
+
+	return (gprt >> gpio_nr) & 1U;
+}
+
+void qrio_set_gpio(u8 port_off, u8 gpio_nr, bool value)
+{
+	u32 gprt, mask;
+
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	mask = 1U << gpio_nr;
+
+	gprt = in_be32(qrio_base + port_off + GPRT_OFF);
+	if (value)
+		gprt |= mask;
+	else
+		gprt &= ~mask;
+
+	out_be32(qrio_base + port_off + GPRT_OFF, gprt);
+}
+
+void qrio_gpio_direction_output(u8 port_off, u8 gpio_nr, bool value)
+{
+	u32 direct, mask;
+
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	mask = 1U << gpio_nr;
+
+	direct = in_be32(qrio_base + port_off + DIRECT_OFF);
+	direct |= mask;
+	out_be32(qrio_base + port_off + DIRECT_OFF, direct);
+
+	qrio_set_gpio(port_off, gpio_nr, value);
+}
+
+void qrio_gpio_direction_input(u8 port_off, u8 gpio_nr)
+{
+	u32 direct, mask;
+
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	mask = 1U << gpio_nr;
+
+	direct = in_be32(qrio_base + port_off + DIRECT_OFF);
+	direct &= ~mask;
+	out_be32(qrio_base + port_off + DIRECT_OFF, direct);
+}
+
+void qrio_set_opendrain_gpio(u8 port_off, u8 gpio_nr, u8 val)
+{
+	u32 direct, mask;
+
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	mask = 1U << gpio_nr;
+
+	direct = in_be32(qrio_base + port_off + DIRECT_OFF);
+	if (val == 0)
+		/* set to output -> GPIO drives low */
+		direct |= mask;
+	else
+		/* set to input -> GPIO floating */
+		direct &= ~mask;
+
+	out_be32(qrio_base + port_off + DIRECT_OFF, direct);
+}
+
+#define WDMASK_OFF	0x16
+
+static void qrio_wdmask(u8 bit, bool wden)
+{
+	u16 wdmask;
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	wdmask = in_be16(qrio_base + WDMASK_OFF);
+
+	if (wden)
+		wdmask |= (1 << bit);
+	else
+		wdmask &= ~(1 << bit);
+
+	out_be16(qrio_base + WDMASK_OFF, wdmask);
+}
+
+#define PRST_OFF	0x1a
+
+void qrio_prst(u8 bit, bool en, bool wden)
+{
+	u16 prst;
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	qrio_wdmask(bit, wden);
+
+	prst = in_be16(qrio_base + PRST_OFF);
+
+	if (en)
+		prst &= ~(1 << bit);
+	else
+		prst |= (1 << bit);
+
+	out_be16(qrio_base + PRST_OFF, prst);
+}
+
+#define PRSTCFG_OFF	0x1c
+
+void qrio_prstcfg(u8 bit, u8 mode)
+{
+	u32 prstcfg;
+	u8 i;
+	void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE;
+
+	prstcfg = in_be32(qrio_base + PRSTCFG_OFF);
+
+	for (i = 0; i < 2; i++) {
+		if (mode & (1<<i))
+			set_bit(2*bit+i, &prstcfg);
+		else
+			clear_bit(2*bit+i, &prstcfg);
+	}
+
+	out_be32(qrio_base + PRSTCFG_OFF, prstcfg);
+}