#include <common.h>
#include <dm.h>
-#include <dm/pinctrl.h>
+#include <hwspinlock.h>
+#include <log.h>
+#include <malloc.h>
#include <asm/arch/gpio.h>
#include <asm/gpio.h>
#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/libfdt.h>
DECLARE_GLOBAL_DATA_PTR;
#define OTYPE_MSK 1
#define AFR_MASK 0xF
-#ifndef CONFIG_SPL_BUILD
struct stm32_pinctrl_priv {
+ struct hwspinlock hws;
int pinctrl_ngpios;
struct list_head gpio_dev;
};
struct list_head list;
};
-#define MAX_PIN_PER_BANK 16
+#ifndef CONFIG_SPL_BUILD
static char pin_name[PINNAME_SIZE];
+#define PINMUX_MODE_COUNT 5
+static const char * const pinmux_mode[PINMUX_MODE_COUNT] = {
+ "gpio input",
+ "gpio output",
+ "analog",
+ "unknown",
+ "alt function",
+};
+
+static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset)
+{
+ struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct stm32_gpio_regs *regs = priv->regs;
+ u32 af;
+ u32 alt_shift = (offset % 8) * 4;
+ u32 alt_index = offset / 8;
+
+ af = (readl(®s->afr[alt_index]) &
+ GENMASK(alt_shift + 3, alt_shift)) >> alt_shift;
+
+ return af;
+}
+
+static int stm32_populate_gpio_dev_list(struct udevice *dev)
+{
+ struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
+ struct udevice *gpio_dev;
+ struct udevice *child;
+ struct stm32_gpio_bank *gpio_bank;
+ int ret;
+
+ /*
+ * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
+ * a list with all gpio device reference which belongs to the
+ * current pin-controller. This list is used to find pin_name and
+ * pin muxing
+ */
+ list_for_each_entry(child, &dev->child_head, sibling_node) {
+ ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
+ &gpio_dev);
+ if (ret < 0)
+ continue;
+
+ gpio_bank = malloc(sizeof(*gpio_bank));
+ if (!gpio_bank) {
+ dev_err(dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ gpio_bank->gpio_dev = gpio_dev;
+ list_add_tail(&gpio_bank->list, &priv->gpio_dev);
+ }
+
+ return 0;
+}
+
static int stm32_pinctrl_get_pins_count(struct udevice *dev)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
if (priv->pinctrl_ngpios)
return priv->pinctrl_ngpios;
+ if (list_empty(&priv->gpio_dev))
+ stm32_populate_gpio_dev_list(dev);
/*
* walk through all banks to retrieve the pin-controller
* pins number
}
static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev,
- unsigned int selector)
+ unsigned int selector,
+ unsigned int *idx)
{
struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
struct stm32_gpio_bank *gpio_bank;
struct gpio_dev_priv *uc_priv;
- int first_pin = 0;
+ int pin_count = 0;
+
+ if (list_empty(&priv->gpio_dev))
+ stm32_populate_gpio_dev_list(dev);
/* look up for the bank which owns the requested pin */
list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
- if (selector < (first_pin + uc_priv->gpio_count))
- /* we found the bank */
- return gpio_bank->gpio_dev;
+ if (selector < (pin_count + uc_priv->gpio_count)) {
+ /*
+ * we found the bank, convert pin selector to
+ * gpio bank index
+ */
+ *idx = stm32_offset_to_index(gpio_bank->gpio_dev,
+ selector - pin_count);
+ if (IS_ERR_VALUE(*idx))
+ return NULL;
- first_pin += uc_priv->gpio_count;
+ return gpio_bank->gpio_dev;
+ }
+ pin_count += uc_priv->gpio_count;
}
return NULL;
{
struct gpio_dev_priv *uc_priv;
struct udevice *gpio_dev;
+ unsigned int gpio_idx;
/* look up for the bank which owns the requested pin */
- gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector);
+ gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
if (!gpio_dev) {
snprintf(pin_name, PINNAME_SIZE, "Error");
} else {
snprintf(pin_name, PINNAME_SIZE, "%s%d",
uc_priv->bank_name,
- selector % MAX_PIN_PER_BANK);
+ gpio_idx);
}
return pin_name;
}
-int stm32_pinctrl_probe(struct udevice *dev)
+
+static int stm32_pinctrl_get_pin_muxing(struct udevice *dev,
+ unsigned int selector,
+ char *buf,
+ int size)
{
- struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
struct udevice *gpio_dev;
- struct udevice *child;
- struct stm32_gpio_bank *gpio_bank;
- int ret;
+ const char *label;
+ int mode;
+ int af_num;
+ unsigned int gpio_idx;
- INIT_LIST_HEAD(&priv->gpio_dev);
+ /* look up for the bank which owns the requested pin */
+ gpio_dev = stm32_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
- /*
- * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
- * a list with all gpio device reference which belongs to the
- * current pin-controller. This list is used to find pin_name and
- * pin muxing
- */
- list_for_each_entry(child, &dev->child_head, sibling_node) {
- ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
- &gpio_dev);
- if (ret < 0)
- continue;
+ if (!gpio_dev)
+ return -ENODEV;
- gpio_bank = malloc(sizeof(*gpio_bank));
- if (!gpio_bank) {
- dev_err(dev, "Not enough memory\n");
- return -ENOMEM;
- }
+ mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label);
- gpio_bank->gpio_dev = gpio_dev;
- list_add_tail(&gpio_bank->list, &priv->gpio_dev);
+ dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n",
+ selector, gpio_idx, mode);
+
+
+ switch (mode) {
+ case GPIOF_UNKNOWN:
+ /* should never happen */
+ return -EINVAL;
+ case GPIOF_UNUSED:
+ snprintf(buf, size, "%s", pinmux_mode[mode]);
+ break;
+ case GPIOF_FUNC:
+ af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx);
+ snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num);
+ break;
+ case GPIOF_OUTPUT:
+ case GPIOF_INPUT:
+ snprintf(buf, size, "%s %s",
+ pinmux_mode[mode], label ? label : "");
+ break;
}
return 0;
}
+
#endif
+static int stm32_pinctrl_probe(struct udevice *dev)
+{
+ struct stm32_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ INIT_LIST_HEAD(&priv->gpio_dev);
+
+ /* hwspinlock property is optional, just log the error */
+ ret = hwspinlock_get_by_index(dev, 0, &priv->hws);
+ if (ret)
+ debug("%s: hwspinlock_get_by_index may have failed (%d)\n",
+ __func__, ret);
+
+ return 0;
+}
+
static int stm32_gpio_config(struct gpio_desc *desc,
const struct stm32_gpio_ctl *ctl)
{
struct stm32_gpio_priv *priv = dev_get_priv(desc->dev);
struct stm32_gpio_regs *regs = priv->regs;
+ struct stm32_pinctrl_priv *ctrl_priv;
+ int ret;
u32 index;
if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 ||
ctl->pupd > 2 || ctl->speed > 3)
return -EINVAL;
+ ctrl_priv = dev_get_priv(dev_get_parent(desc->dev));
+ ret = hwspinlock_lock_timeout(&ctrl_priv->hws, 10);
+ if (ret == -ETIME) {
+ dev_err(desc->dev, "HWSpinlock timeout\n");
+ return ret;
+ }
+
index = (desc->offset & 0x07) * 4;
clrsetbits_le32(®s->afr[desc->offset >> 3], AFR_MASK << index,
ctl->af << index);
index = desc->offset;
clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index);
+ hwspinlock_unlock(&ctrl_priv->hws);
+
return 0;
}
return 0;
}
+static int stm32_pinctrl_bind(struct udevice *dev)
+{
+ ofnode node;
+ const char *name;
+ int ret;
+
+ dev_for_each_subnode(node, dev) {
+ debug("%s: bind %s\n", __func__, ofnode_get_name(node));
+
+ ofnode_get_property(node, "gpio-controller", &ret);
+ if (ret < 0)
+ continue;
+ /* Get the name of each gpio node */
+ name = ofnode_get_name(node);
+ if (!name)
+ return -EINVAL;
+
+ /* Bind each gpio node */
+ ret = device_bind_driver_to_node(dev, "gpio_stm32",
+ name, node, NULL);
+ if (ret)
+ return ret;
+
+ debug("%s: bind %s\n", __func__, name);
+ }
+
+ return 0;
+}
+
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
#ifndef CONFIG_SPL_BUILD
.get_pin_name = stm32_pinctrl_get_pin_name,
.get_pins_count = stm32_pinctrl_get_pins_count,
+ .get_pin_muxing = stm32_pinctrl_get_pin_muxing,
#endif
};
{ .compatible = "st,stm32f429-pinctrl" },
{ .compatible = "st,stm32f469-pinctrl" },
{ .compatible = "st,stm32f746-pinctrl" },
+ { .compatible = "st,stm32f769-pinctrl" },
{ .compatible = "st,stm32h743-pinctrl" },
{ .compatible = "st,stm32mp157-pinctrl" },
{ .compatible = "st,stm32mp157-z-pinctrl" },
.id = UCLASS_PINCTRL,
.of_match = stm32_pinctrl_ids,
.ops = &stm32_pinctrl_ops,
- .bind = dm_scan_fdt_dev,
-#ifndef CONFIG_SPL_BUILD
+ .bind = stm32_pinctrl_bind,
.probe = stm32_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv),
-#endif
};