[U-Boot] [PATCH 3/6] arm64: mvebu: pinctrl: Add pin control driver for A8K family

kostap at marvell.com kostap at marvell.com
Sun Nov 20 16:38:26 CET 2016


From: Konstantin Porotchkin <kostap at marvell.com>

Add a port of Marvell pin control driver.
The A8K SoC family contains several silicone dies interconnected
in a single package. Every die is normally equuipped with its own
pin controller unit.
Since the UCLASS_PINCTRL device only calls the probe method for
the first detected pin controller, a trick similar to used with
comphy driver is required.
In order to bring up all pin controllers available in A8K SoC,
the arch_early_init_r() function sequentially calls the
uclass_get_device() function for each UCLASS_PINCTRL device.

Change-Id: Iff143827e8f1558a554d77173562c4b52ce179d7
Signed-off-by: Konstantin Porotchkin <kostap at marvell.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Stefan Roese <sr at denx.de>
Cc: Nadav Haklai <nadavh at marvell.com>
Cc: Neta Zur Hershkovits <neta at marvell.com>
Cc: Omri Itach <omrii at marvell.com>
Cc: Igal Liberman <igall at marvell.com>
Cc: Haim Boot <hayim at marvell.com>
Cc: Hanna Hawa <hannah at marvell.com>
---
 arch/arm/include/asm/arch-armada8k/soc-info.h      |  45 +++++
 arch/arm/mach-mvebu/arm64-common.c                 |   1 -
 .../pinctrl/marvell,mvebu-pinctrl.txt              | 113 ++++++++++++
 drivers/pinctrl/Kconfig                            |   1 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/mvebu/Kconfig                      |   7 +
 drivers/pinctrl/mvebu/Makefile                     |  17 ++
 drivers/pinctrl/mvebu/pinctrl-mvebu.c              | 195 +++++++++++++++++++++
 drivers/pinctrl/mvebu/pinctrl-mvebu.h              |  44 +++++
 9 files changed, 423 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/include/asm/arch-armada8k/soc-info.h
 create mode 100644 doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/Kconfig
 create mode 100644 drivers/pinctrl/mvebu/Makefile
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-mvebu.c
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-mvebu.h

diff --git a/arch/arm/include/asm/arch-armada8k/soc-info.h b/arch/arm/include/asm/arch-armada8k/soc-info.h
new file mode 100644
index 0000000..4640deb
--- /dev/null
+++ b/arch/arm/include/asm/arch-armada8k/soc-info.h
@@ -0,0 +1,45 @@
+/*
+ * ***************************************************************************
+ * Copyright (C) 2015 Marvell International Ltd.
+ * ***************************************************************************
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ***************************************************************************
+ */
+
+#ifndef _SOC_INFO_H_
+#define _SOC_INFO_H_
+
+/* General MPP definitions */
+#define MAX_MPP_OPTS		7
+#define MAX_MPP_ID		15
+
+#define MPP_BIT_CNT		4
+#define MPP_FIELD_MASK		0x7
+#define MPP_FIELD_BITS		3
+#define MPP_VAL_MASK		0xF
+
+#define MPPS_PER_REG		(32 / MPP_BIT_CNT)
+#define MAX_MPP_REGS		((MAX_MPP_ID + MPPS_PER_REG) / MPPS_PER_REG)
+
+/* MPP pins and functions correcsponding to UART RX connections
+   This information is used for detection of recovery boot mode (boot from UART) */
+#define MPP_UART_RX_PINS	{ 3, 5 }
+#define MPP_UART_RX_FUNCTIONS	{ 1, 2 }
+
+/* Pin Ctrl driver definitions */
+#define BITS_PER_PIN		4
+#define PIN_FUNC_MASK		((1 << BITS_PER_PIN) - 1)
+#define PIN_REG_SHIFT		3
+#define PIN_FIELD_MASK		((1 << PIN_REG_SHIFT) - 1)
+
+#endif	/* _SOC_INFO_H_ */
diff --git a/arch/arm/mach-mvebu/arm64-common.c b/arch/arm/mach-mvebu/arm64-common.c
index 1fc2ff2..78fe7a7 100644
--- a/arch/arm/mach-mvebu/arm64-common.c
+++ b/arch/arm/mach-mvebu/arm64-common.c
@@ -124,7 +124,6 @@ int arch_early_init_r(void)
 		if (ret)
 			break;
 	}
-
 	/* Cause the SATA device to do its early init */
 	uclass_first_device(UCLASS_AHCI, &dev);
 
diff --git a/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt b/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt
new file mode 100644
index 0000000..0973db8
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/marvell,mvebu-pinctrl.txt
@@ -0,0 +1,113 @@
+The pinctrl driver enables Marvell Armada 8K SoCs to configure the multi-purpose
+pins (mpp) to a specific function.
+A Marvell SoC pin configuration node is a node of a group of pins which can
+be used for a specific device or function. Each node requires one or more
+mpp pins or group of pins and a mpp function common to all pins.
+
+Required properties for the pinctrl driver:
+- compatible:	"marvell,mvebu-pinctrl",
+		"marvell,armada-ap806-pinctrl",
+		"marvell,a70x0-pinctrl",
+		"marvell,a80x0-cp0-pinctrl",
+		"marvell,a80x0-cp1-pinctrl"
+- bank-name:	A string defining the pinc controller bank name
+- reg: 		A pair of values defining the pin controller base address
+		and the address space
+- pin-count:	Numeric value defining the amount of multi purpose pins
+		included in this bank
+- max-func:	Numeric value defining the maximum function value for
+		pins in this bank
+- pin-func:	Array of pin function values for every pin in the bank.
+		When the function value for a specific pin equal 0xFF,
+		the pin configuration is skipped and a default function
+		value is used for this pin.
+
+The A8K is a hybrid SoC that contains several silicon dies interconnected in
+a single package. Each such die may have a separate pin controller.
+
+Example:
+/ {
+	ap806 {
+		config-space {
+			pinctl: pinctl at 6F4000 {
+				compatible = "marvell,mvebu-pinctrl",
+					     "marvell,armada-ap806-pinctrl";
+				bank-name ="apn-806";
+				reg = <0x6F4000 0x10>;
+				pin-count = <20>;
+				max-func = <3>;
+				/* MPP Bus:
+					SPI0 [0-3]
+					I2C0 [4-5]
+					UART0 [11,19]
+				*/
+					  /* 0 1 2 3 4 5 6 7 8 9 */
+				pin-func = < 3 3 3 3 3 3 0 0 0 0
+					     0 3 0 0 0 0 0 0 0 3>;
+			};
+		};
+	};
+
+	cp110-master {
+		config-space {
+			cpm_pinctl: pinctl at 44000 {
+				compatible = "marvell,mvebu-pinctrl",
+					     "marvell,a70x0-pinctrl",
+					     "marvell,a80x0-cp0-pinctrl";
+				bank-name ="cp0-110";
+				reg = <0x440000 0x20>;
+				pin-count = <63>;
+				max-func = <0xf>;
+				/* MPP Bus:
+				   [0-31] = 0xff: Keep default CP0_shared_pins:
+				   [11] CLKOUT_MPP_11 (out)
+				   [23] LINK_RD_IN_CP2CP (in)
+				   [25] CLKOUT_MPP_25 (out)
+				   [29] AVS_FB_IN_CP2CP (in)
+				   [32,34] SMI
+				   [31]    GPIO: push button/Wake
+				   [35-36] GPIO
+				   [37-38] I2C
+				   [40-41] SATA[0/1]_PRESENT_ACTIVEn
+				   [42-43] XSMI
+				   [44-55] RGMII1
+				   [56-62] SD
+				*/
+					/*   0    1    2    3    4    5    6    7    8    9 */
+				pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0    7    0    7    0    0    2    2    0
+					     0    0    8    8    1    1    1    1    1    1
+					     1    1    1    1    1    1    0xE  0xE  0xE  0xE
+					     0xE  0xE  0xE>;
+			};
+		};
+	};
+
+	cp110-slave {
+		config-space {
+			cps_pinctl: pinctl at 44000 {
+				compatible = "marvell,mvebu-pinctrl",
+					     "marvell,a80x0-cp1-pinctrl";
+				bank-name ="cp1-110";
+				reg = <0x440000 0x20>;
+				pin-count = <63>;
+				max-func = <0xf>;
+				/* MPP Bus:
+				   [0-11]  RGMII0
+				   [27,31] GE_MDIO/MDC
+				   [32-62] = 0xff: Keep default CP1_shared_pins:
+				*/
+					/*   0    1    2    3    4    5    6    7    8    9 */
+				pin-func = < 0x3  0x3  0x3  0x3  0x3  0x3  0x3  0x3  0x3  0x3
+					     0x3  0x3  0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x8  0xff 0xff
+					     0xff 0x8  0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+					     0xff 0xff 0xff>;
+			};
+		};
+	};
+}
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 12be3cf..efcb4c0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -181,5 +181,6 @@ source "drivers/pinctrl/meson/Kconfig"
 source "drivers/pinctrl/nxp/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/exynos/Kconfig"
+source "drivers/pinctrl/mvebu/Kconfig"
 
 endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f28b5c1..512112a 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
 obj-$(CONFIG_PIC32_PINCTRL)	+= pinctrl_pic32.o
 obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
+obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
new file mode 100644
index 0000000..cf9c299
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -0,0 +1,7 @@
+config PINCTRL_MVEBU
+	depends on ARCH_MVEBU
+	bool
+	default y
+	help
+	   Support pin multiplexing and pin configuration control on
+	   Marvell's Armada-8K SoC.
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
new file mode 100644
index 0000000..7db2b97
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -0,0 +1,17 @@
+#* ***************************************************************************
+#* Copyright (C) 2016 Marvell International Ltd.
+#* ***************************************************************************
+#* This program is free software: you can redistribute it and/or modify it
+#* under the terms of the GNU General Public License as published by the Free
+#* Software Foundation, either version 2 of the License, or any later version.
+#*
+#* This program is distributed in the hope that it will be useful,
+#* but WITHOUT ANY WARRANTY; without even the implied warranty of
+#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#* GNU General Public License for more details.
+#*
+#* You should have received a copy of the GNU General Public License
+#* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#* ***************************************************************************
+
+obj-$(CONFIG_PINCTRL_MVEBU)	+= pinctrl-mvebu.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
new file mode 100644
index 0000000..02fcd2f
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -0,0 +1,195 @@
+/*
+ * ***************************************************************************
+ * Copyright (C) 2016 Marvell International Ltd.
+ * ***************************************************************************
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ***************************************************************************
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <asm/arch/fdt.h>
+#include <asm/arch-armada8k/soc-info.h>
+#include "pinctrl-mvebu.h"
+
+/*
+ * mvebu_pinctrl_set_state: configure pin functions.
+ * dev: the pinctrl device to be configured.
+ * config: the state to be configured.
+ */
+int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+	const void *blob = gd->fdt_blob;
+	int node = config->of_offset;
+	struct mvebu_pinctrl_priv *priv;
+	u32 pin_arr[CONFIG_MAX_PINS_PER_BANK];
+	u32 function;
+	int i, pin_count;
+
+	priv = dev_get_priv(dev);
+	if (!priv) {
+		printf("%s: Failed to get private\n", __func__);
+		return -EINVAL;
+	}
+
+	pin_count = fdtdec_get_int_array_count(blob, node, "marvell,pins", pin_arr, CONFIG_MAX_PINS_PER_BANK);
+	if (pin_count <= 0) {
+		error("Failed reading pins array for pinconfig %s (%d)\n", config->name, pin_count);
+		return -EINVAL;
+	}
+
+	function = fdtdec_get_int(blob, node, "marvell,function", 0xFF);
+
+	for (i = 0; i < pin_count; i++) {
+		int reg_offset;
+		int field_offset;
+		u32 reg, mask;
+		int pin = pin_arr[i];
+
+		if (function > priv->max_func) {
+			error("Illegal function %d for pinconfig %s\n", function, config->name);
+			return -EINVAL;
+		}
+
+		/* Calculate register address and bit in register */
+		reg_offset   = priv->reg_direction * 4 * (pin >> (PIN_REG_SHIFT));
+		field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
+		mask = ~(PIN_FUNC_MASK << field_offset);
+
+		/* Clip value to field resolution */
+		function &= PIN_FUNC_MASK;
+
+		reg = readl(priv->base_reg + reg_offset);
+		reg = (reg & mask) | (function << field_offset);
+		writel(reg, priv->base_reg + reg_offset);
+	}
+
+	return 0;
+}
+
+/*
+ * mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
+ * dev: the pinctrl device to be configured.
+ * config: the state to be configured.
+ */
+static int mvebu_pinctrl_set_state_all(struct udevice *dev, struct udevice *config)
+{
+	const void *blob = gd->fdt_blob;
+	int node = config->of_offset;
+	struct mvebu_pinctrl_priv *priv;
+	u32 func_arr[CONFIG_MAX_PINS_PER_BANK];
+	int pin, err;
+
+	priv = dev_get_priv(dev);
+	if (!priv) {
+		printf("%s: Failed to get private\n", __func__);
+		return -EINVAL;
+	}
+
+	err = fdtdec_get_int_array(blob, node, "pin-func", func_arr, priv->pin_cnt);
+	if (err) {
+		error("Failed reading pin functions for bank %s\n", priv->bank_name);
+		return -EINVAL;
+	}
+
+	for (pin = 0; pin < priv->pin_cnt; pin++) {
+		int reg_offset;
+		int field_offset;
+		u32 reg, mask;
+		u32 func = func_arr[pin];
+
+		/* Bypass pins with function 0xFF */
+		if (func == 0xFF) {
+			debug("Warning: pin %d value is not modified (kept as default\n", pin);
+			continue;
+		} else if (func > priv->max_func) {
+			error("Illegal function %d for pin %d\n", func, pin);
+			return -EINVAL;
+		}
+
+		/* Calculate register address and bit in register */
+		reg_offset   = priv->reg_direction * 4 * (pin >> (PIN_REG_SHIFT));
+		field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
+		mask = ~(PIN_FUNC_MASK << field_offset);
+
+		/* Clip value to field resolution */
+		func &= PIN_FUNC_MASK;
+
+		reg = readl(priv->base_reg + reg_offset);
+		reg = (reg & mask) | (func << field_offset);
+		writel(reg, priv->base_reg + reg_offset);
+	}
+
+	return 0;
+}
+
+int mvebu_pinctl_probe(struct udevice *dev)
+{
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	struct mvebu_pinctrl_priv *priv;
+	fdt_addr_t base;
+
+	priv = dev_get_priv(dev);
+	if (!priv) {
+		printf("%s: Failed to get private\n", __func__);
+		return -EINVAL;
+	}
+
+	base = dev_get_addr(dev);
+	if (base == FDT_ADDR_T_NONE) {
+		printf("%s: Failed to get base address\n", __func__);
+		return -EINVAL;
+	}
+
+	priv->base_reg  = (u8 *)base;
+	priv->pin_cnt   = fdtdec_get_int(blob, node, "pin-count", CONFIG_MAX_PINS_PER_BANK);
+	priv->max_func  = fdtdec_get_int(blob, node, "max-func", CONFIG_MAX_FUNC);
+	priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
+
+	priv->reg_direction = 1;
+	if (fdtdec_get_bool(blob, node, "reverse-reg"))
+		priv->reg_direction = -1;
+
+	return mvebu_pinctrl_set_state_all(dev, dev);
+}
+
+
+static struct pinctrl_ops mvebu_pinctrl_ops = {
+	.set_state	= mvebu_pinctrl_set_state
+};
+
+static const struct udevice_id mvebu_pinctrl_ids[] = {
+	{ .compatible = "marvell,mvebu-pinctrl" },
+	{ .compatible = "marvell,armada-ap806-pinctrl" },
+	{ .compatible = "marvell,a70x0-pinctrl" },
+	{ .compatible = "marvell,a80x0-cp0-pinctrl" },
+	{ .compatible = "marvell,a80x0-cp1-pinctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_mvebu) = {
+	.name		= "mvebu_pinctrl",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= mvebu_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv),
+	.ops		= &mvebu_pinctrl_ops,
+	.probe		= mvebu_pinctl_probe
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
new file mode 100644
index 0000000..61c84ce
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
@@ -0,0 +1,44 @@
+/*
+ * ***************************************************************************
+ * Copyright (C) 2016 Marvell International Ltd.
+ * ***************************************************************************
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, either version 2 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ***************************************************************************
+ */
+
+ #ifndef __PINCTRL_MVEBU_H_
+ #define __PINCTRL_MVEBU_H_
+
+ #define CONFIG_MAX_PINCTL_BANKS	4
+ #define CONFIG_MAX_PINS_PER_BANK	100
+ #define CONFIG_MAX_FUNC		0xF
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct mvebu_pin_bank_data: mvebu-pinctrl bank data
+ * @base_reg: controller base address for this bank
+ * @pin_cnt:  number of ping included in this bank
+ * @max_func: maximum configurable function value for pins in this bank
+ * @reg_direction:
+ * @bank_name: the pins bank name
+ */
+struct mvebu_pinctrl_priv {
+	u8		*base_reg;
+	u32		pin_cnt;
+	u32		max_func;
+	int		reg_direction;
+	const char	*bank_name;
+};
+
+#endif /* __PINCTRL_MVEBU_H_ */
-- 
2.7.4



More information about the U-Boot mailing list