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

kostap at marvell.com
2016-11-20T15:38:26Z

From: Konstantin Porotchkin <kostap@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@marvell.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Stefan Roese <sr@denx.de>
Cc: Nadav Haklai <nadavh@marvell.com>
Cc: Neta Zur Hershkovits <neta@marvell.com>
Cc: Omri Itach <omrii@marvell.com>
Cc: Igal Liberman <igall@marvell.com>
Cc: Haim Boot <hayim@marvell.com>
Cc: Hanna Hawa <hannah@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@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