pinctrl: uniphier: add UniPhier pinctrl core support
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Fri, 11 Sep 2015 11:17:32 +0000 (20:17 +0900)
committerMasahiro Yamada <yamada.masahiro@socionext.com>
Wed, 23 Sep 2015 14:21:32 +0000 (23:21 +0900)
The core support for the pinctrl drivers for all the UniPhier SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/uniphier/Kconfig [new file with mode: 0644]
drivers/pinctrl/uniphier/Makefile [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier.h [new file with mode: 0644]

index b8146df99b6e035a93a23655af4b3c0e8b600847..3b6e3b7060d0001cb54a28bbc36fcc76e2c75423 100644 (file)
@@ -124,4 +124,6 @@ config PINCTRL_SANDBOX
 
 endif
 
+source "drivers/pinctrl/uniphier/Kconfig"
+
 endmenu
index f537df4e886399952e4eb123793fe12c7351b8c0..e56a17f9665a77674eee136a22e128648839af7a 100644 (file)
@@ -3,3 +3,5 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)    += pinctrl-generic.o
 
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_PINCTRL_SANDBOX)  += pinctrl-sandbox.o
+
+obj-$(CONFIG_ARCH_UNIPHIER)    += uniphier/
diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig
new file mode 100644 (file)
index 0000000..29a623d
--- /dev/null
@@ -0,0 +1,6 @@
+if ARCH_UNIPHIER
+
+config PINCTRL_UNIPHIER_CORE
+       bool
+
+endif
diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile
new file mode 100644 (file)
index 0000000..748aa1b
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_PINCTRL_UNIPHIER_CORE)            += pinctrl-uniphier-core.o
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
new file mode 100644 (file)
index 0000000..37a920c
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <mapmem.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+#include "pinctrl-uniphier.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int uniphier_pinctrl_get_groups_count(struct udevice *dev)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->socdata->groups_count;
+}
+
+static const char *uniphier_pinctrl_get_group_name(struct udevice *dev,
+                                                  unsigned selector)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->socdata->groups[selector].name;
+}
+
+static int uniphier_pinmux_get_functions_count(struct udevice *dev)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->socdata->functions_count;
+}
+
+static const char *uniphier_pinmux_get_function_name(struct udevice *dev,
+                                                    unsigned selector)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->socdata->functions[selector];
+}
+
+static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+       int pins_count = priv->socdata->pins_count;
+       const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
+       int i;
+
+       for (i = 0; i < pins_count; i++) {
+               if (pins[i].number == pin) {
+                       unsigned int iectrl;
+                       u32 tmp;
+
+                       iectrl = uniphier_pin_get_iectrl(pins[i].data);
+                       tmp = readl(priv->base + UNIPHIER_PINCTRL_IECTRL);
+                       tmp |= 1 << iectrl;
+                       writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL);
+               }
+       }
+}
+
+static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
+                                   unsigned muxval)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+       unsigned mux_bits = priv->socdata->mux_bits;
+       unsigned reg_stride = priv->socdata->reg_stride;
+       unsigned reg, reg_end, shift, mask;
+       u32 tmp;
+
+       reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
+       reg_end = reg + reg_stride;
+       shift = pin * mux_bits % 32;
+       mask = (1U << mux_bits) - 1;
+
+       /*
+        * If reg_stride is greater than 4, the MSB of each pinsel shall be
+        * stored in the offset+4.
+        */
+       for (; reg < reg_end; reg += 4) {
+               tmp = readl(priv->base + reg);
+               tmp &= ~(mask << shift);
+               tmp |= (mask & muxval) << shift;
+               writel(tmp, priv->base + reg);
+
+               muxval >>= mux_bits;
+       }
+
+       if (priv->socdata->load_pinctrl)
+               writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX);
+
+       /* some pins need input-enabling */
+       uniphier_pinconf_input_enable(dev, pin);
+}
+
+static int uniphier_pinmux_group_set(struct udevice *dev,
+                                    unsigned group_selector,
+                                    unsigned func_selector)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct uniphier_pinctrl_group *grp =
+                                       &priv->socdata->groups[group_selector];
+       int i;
+
+       for (i = 0; i < grp->num_pins; i++)
+               uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]);
+
+       return 0;
+}
+
+const struct pinctrl_ops uniphier_pinctrl_ops = {
+       .get_groups_count = uniphier_pinctrl_get_groups_count,
+       .get_group_name = uniphier_pinctrl_get_group_name,
+       .get_functions_count = uniphier_pinmux_get_functions_count,
+       .get_function_name = uniphier_pinmux_get_function_name,
+       .pinmux_group_set = uniphier_pinmux_group_set,
+       .set_state = pinctrl_generic_set_state,
+};
+
+int uniphier_pinctrl_probe(struct udevice *dev,
+                          struct uniphier_pinctrl_socdata *socdata)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+       fdt_addr_t addr;
+       fdt_size_t size;
+
+       addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
+                                   &size);
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       priv->base = map_sysmem(addr, size);
+       if (!priv->base)
+               return -ENOMEM;
+
+       priv->socdata = socdata;
+
+       return 0;
+}
+
+int uniphier_pinctrl_remove(struct udevice *dev)
+{
+       struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
+
+       unmap_sysmem(priv->base);
+
+       return 0;
+}
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
new file mode 100644 (file)
index 0000000..7eaec6a
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __PINCTRL_UNIPHIER_H__
+#define __PINCTRL_UNIPHIER_H__
+
+/* TODO: move this to include/linux/bug.h */
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#define UNIPHIER_PINCTRL_PINMUX_BASE   0x0
+#define UNIPHIER_PINCTRL_LOAD_PINMUX   0x700
+#define UNIPHIER_PINCTRL_IECTRL                0xd00
+
+#define UNIPHIER_PIN_ATTR_PACKED(iectrl)       (iectrl)
+
+static inline unsigned int uniphier_pin_get_iectrl(unsigned long data)
+{
+       return data;
+}
+
+/**
+ * struct uniphier_pinctrl_pin - pin data for UniPhier SoC
+ *
+ * @number: pin number
+ * @data: additional per-pin data
+ */
+struct uniphier_pinctrl_pin {
+       unsigned number;
+       unsigned long data;
+};
+
+/**
+ * struct uniphier_pinctrl_group - pin group data for UniPhier SoC
+ *
+ * @name: pin group name
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @muxvals: array of values to be set to pinmux registers
+ */
+struct uniphier_pinctrl_group {
+       const char *name;
+       const unsigned *pins;
+       unsigned num_pins;
+       const unsigned *muxvals;
+};
+
+/**
+ * struct uniphier_pinctrl_socdata - SoC data for UniPhier pin controller
+ *
+ * @pins: array of pin data
+ * @pins_count: number of pin data
+ * @groups: array of pin group data
+ * @groups_count: number of pin group data
+ * @functions: array of pinmux function names
+ * @functions_count: number of pinmux functions
+ * @mux_bits: bit width of each pinmux register
+ * @reg_stride: stride of pinmux register address
+ * @load_pinctrl: if true, LOAD_PINMUX register must be set to one for new
+ *               values in pinmux registers to become really effective
+ */
+struct uniphier_pinctrl_socdata {
+       const struct uniphier_pinctrl_pin *pins;
+       int pins_count;
+       const struct uniphier_pinctrl_group *groups;
+       int groups_count;
+       const char * const *functions;
+       int functions_count;
+       unsigned mux_bits;
+       unsigned reg_stride;
+       bool load_pinctrl;
+};
+
+#define UNIPHIER_PINCTRL_PIN(a, b)                                     \
+{                                                                      \
+       .number = a,                                                    \
+       .data = UNIPHIER_PIN_ATTR_PACKED(b),                            \
+}
+
+#define UNIPHIER_PINCTRL_GROUP(grp)                                    \
+       {                                                               \
+               .name = #grp,                                           \
+               .pins = grp##_pins,                                     \
+               .num_pins = ARRAY_SIZE(grp##_pins),                     \
+               .muxvals = grp##_muxvals +                              \
+                       BUILD_BUG_ON_ZERO(ARRAY_SIZE(grp##_pins) !=     \
+                                         ARRAY_SIZE(grp##_muxvals)),   \
+       }
+
+/**
+ * struct uniphier_pinctrl_priv - private data for UniPhier pinctrl driver
+ *
+ * @base: base address of the pinctrl device
+ * @socdata: SoC specific data
+ */
+struct uniphier_pinctrl_priv {
+       void __iomem *base;
+       struct uniphier_pinctrl_socdata *socdata;
+};
+
+extern const struct pinctrl_ops uniphier_pinctrl_ops;
+
+int uniphier_pinctrl_probe(struct udevice *dev,
+                          struct uniphier_pinctrl_socdata *socdata);
+
+int uniphier_pinctrl_remove(struct udevice *dev);
+
+#endif /* __PINCTRL_UNIPHIER_H__ */