[U-Boot] [PATCH 0/5] Update STM32 gpio and pinctrl drivers

This series adds: - Add gpio holes management in gpio and pinctrl drivers - Remove useless CONFIG_CLK flag from gpio driver - Move code outside pinctrl probe()
There is a dependency with http://patchwork.ozlabs.org/project/uboot/list/?series=78259 which must be applied first.
Patrice Chotard (5): pinctrl: stm32: Move gpio_dev list filling outside probe() gpio: stm32f7: Add gpio bank holes management gpio: stm32f7: Move STM32_GPIOS_PER_BANK into gpio.h gpio: stm32f7: Remove CONFIG_CLK flag. pinctrl: stm32: Update stm32_pinctrl_get_gpio_dev()
arch/arm/include/asm/arch-stm32/gpio.h | 5 ++ arch/arm/mach-stm32mp/include/mach/gpio.h | 6 ++ drivers/gpio/stm32f7_gpio.c | 104 ++++++++++++++++++++++++----- drivers/pinctrl/pinctrl_stm32.c | 105 ++++++++++++++++++------------ 4 files changed, 159 insertions(+), 61 deletions(-)

Move gpio_dev list filling outside probe() to speed-up U-boot boot sequence execution. This list is populated only when needed.
Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
drivers/pinctrl/pinctrl_stm32.c | 63 +++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 25 deletions(-)
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index bb63da373900..aa92c90b8997 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -54,6 +54,39 @@ static int stm32_pinctrl_get_af(struct udevice *dev, unsigned int offset) 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); @@ -67,6 +100,8 @@ static int stm32_pinctrl_get_pins_count(struct udevice *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 @@ -88,6 +123,9 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, struct gpio_dev_priv *uc_priv; int first_pin = 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); @@ -174,35 +212,10 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, int stm32_pinctrl_probe(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;
INIT_LIST_HEAD(&priv->gpio_dev);
- /* - * 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); - } - /* hwspinlock property is optional, just log the error */ ret = hwspinlock_get_by_index(dev, 0, &priv->hws); if (ret)

On Mon, Dec 03, 2018 at 10:52:50AM +0100, Patrice Chotard wrote:
Move gpio_dev list filling outside probe() to speed-up U-boot boot sequence execution. This list is populated only when needed.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

In some STM32 SoC packages, GPIO bank has not always 16 gpios. Several cases can occur, gpio hole can be located at the beginning, middle or end of the gpio bank or a combination of these 3 configurations.
For that, gpio bindings offer the gpio-ranges DT property which described the gpio bank mapping.
Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
arch/arm/include/asm/arch-stm32/gpio.h | 3 + arch/arm/mach-stm32mp/include/mach/gpio.h | 4 ++ drivers/gpio/stm32f7_gpio.c | 99 ++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 14 deletions(-)
diff --git a/arch/arm/include/asm/arch-stm32/gpio.h b/arch/arm/include/asm/arch-stm32/gpio.h index 84859b144795..8ba15b735596 100644 --- a/arch/arm/include/asm/arch-stm32/gpio.h +++ b/arch/arm/include/asm/arch-stm32/gpio.h @@ -109,6 +109,9 @@ struct stm32_gpio_regs {
struct stm32_gpio_priv { struct stm32_gpio_regs *regs; + unsigned int gpio_range; };
+int stm32_offset_to_index(struct udevice *dev, unsigned int offset); + #endif /* _GPIO_H_ */ diff --git a/arch/arm/mach-stm32mp/include/mach/gpio.h b/arch/arm/mach-stm32mp/include/mach/gpio.h index 5151150b8d88..46bef21f79f3 100644 --- a/arch/arm/mach-stm32mp/include/mach/gpio.h +++ b/arch/arm/mach-stm32mp/include/mach/gpio.h @@ -110,5 +110,9 @@ struct stm32_gpio_regs {
struct stm32_gpio_priv { struct stm32_gpio_regs *regs; + unsigned int gpio_range; }; + +int stm32_offset_to_index(struct udevice *dev, unsigned int offset); + #endif /* _STM32_GPIO_H_ */ diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index a690c437ebc6..55553c9477ff 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -20,12 +20,41 @@ #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16))
+/* + * convert gpio offset to gpio index taking into account gpio holes + * into gpio bank + */ +int stm32_offset_to_index(struct udevice *dev, unsigned int offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + int idx = 0; + int i; + + for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { + if (priv->gpio_range & BIT(i)) { + if (idx == offset) + return idx; + idx++; + } + } + /* shouldn't happen */ + return -EINVAL; +} + static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index;
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index);
@@ -37,12 +66,20 @@ static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index;
clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index);
- writel(BSRR_BIT(offset, value), ®s->bsrr); + writel(BSRR_BIT(idx, value), ®s->bsrr);
return 0; } @@ -51,16 +88,26 @@ static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx; + + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx;
- return readl(®s->idr) & BIT(offset) ? 1 : 0; + return readl(®s->idr) & BIT(idx) ? 1 : 0; }
static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; + int idx;
- writel(BSRR_BIT(offset, value), ®s->bsrr); + idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + writel(BSRR_BIT(idx, value), ®s->bsrr);
return 0; } @@ -69,10 +116,18 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); struct stm32_gpio_regs *regs = priv->regs; - int bits_index = MODE_BITS(offset); - int mask = MODE_BITS_MASK << bits_index; + int bits_index; + int mask; + int idx; u32 mode;
+ idx = stm32_offset_to_index(dev, offset); + if (idx < 0) + return idx; + + bits_index = MODE_BITS(idx); + mask = MODE_BITS_MASK << bits_index; + mode = (readl(®s->moder) & mask) >> bits_index; if (mode == STM32_GPIO_MODE_OUT) return GPIOF_OUTPUT; @@ -96,8 +151,11 @@ static int gpio_stm32_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; fdt_addr_t addr; const char *name; + int ret; + int i;
addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) @@ -108,14 +166,27 @@ static int gpio_stm32_probe(struct udevice *dev) if (!name) return -EINVAL; uc_priv->bank_name = name; - uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", - STM32_GPIOS_PER_BANK); - debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs, - uc_priv->bank_name); + + i = 0; + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, i, &args); + + while (ret != -ENOENT) { + priv->gpio_range |= GENMASK(args.args[2] + args.args[0] - 1, + args.args[0]); + + uc_priv->gpio_count += args.args[2]; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + ++i, &args); + } + + dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", + (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, + priv->gpio_range);
#ifdef CONFIG_CLK struct clk clk; - int ret; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret;

On Mon, Dec 03, 2018 at 10:52:51AM +0100, Patrice Chotard wrote:
In some STM32 SoC packages, GPIO bank has not always 16 gpios. Several cases can occur, gpio hole can be located at the beginning, middle or end of the gpio bank or a combination of these 3 configurations.
For that, gpio bindings offer the gpio-ranges DT property which described the gpio bank mapping.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

To allow access to this define by other driver, move it into gpio.h
Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
arch/arm/include/asm/arch-stm32/gpio.h | 2 ++ arch/arm/mach-stm32mp/include/mach/gpio.h | 2 ++ drivers/gpio/stm32f7_gpio.c | 1 - 3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-stm32/gpio.h b/arch/arm/include/asm/arch-stm32/gpio.h index 8ba15b735596..570e80a6ba80 100644 --- a/arch/arm/include/asm/arch-stm32/gpio.h +++ b/arch/arm/include/asm/arch-stm32/gpio.h @@ -7,6 +7,8 @@ #ifndef _GPIO_H_ #define _GPIO_H_
+#define STM32_GPIOS_PER_BANK 16 + enum stm32_gpio_port { STM32_GPIO_PORT_A = 0, STM32_GPIO_PORT_B, diff --git a/arch/arm/mach-stm32mp/include/mach/gpio.h b/arch/arm/mach-stm32mp/include/mach/gpio.h index 46bef21f79f3..5ca76d21ff1e 100644 --- a/arch/arm/mach-stm32mp/include/mach/gpio.h +++ b/arch/arm/mach-stm32mp/include/mach/gpio.h @@ -8,6 +8,8 @@ #define _STM32_GPIO_H_ #include <asm/gpio.h>
+#define STM32_GPIOS_PER_BANK 16 + enum stm32_gpio_port { STM32_GPIO_PORT_A = 0, STM32_GPIO_PORT_B, diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index 55553c9477ff..34cdafa1e402 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -15,7 +15,6 @@ #include <linux/errno.h> #include <linux/io.h>
-#define STM32_GPIOS_PER_BANK 16 #define MODE_BITS(gpio_pin) (gpio_pin * 2) #define MODE_BITS_MASK 3 #define BSRR_BIT(gpio_pin, value) BIT(gpio_pin + (value ? 0 : 16))

On Mon, Dec 03, 2018 at 10:52:52AM +0100, Patrice Chotard wrote:
To allow access to this define by other driver, move it into gpio.h
Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

As all STM32 SoCs supports CONFIG_CLK flag, it becomes useless in this driver, remove it.
Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
drivers/gpio/stm32f7_gpio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c index 34cdafa1e402..f160b4e68957 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32f7_gpio.c @@ -151,6 +151,7 @@ static int gpio_stm32_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct stm32_gpio_priv *priv = dev_get_priv(dev); struct ofnode_phandle_args args; + struct clk clk; fdt_addr_t addr; const char *name; int ret; @@ -184,8 +185,6 @@ static int gpio_stm32_probe(struct udevice *dev) (u32 *)priv->regs, uc_priv->bank_name, uc_priv->gpio_count, priv->gpio_range);
-#ifdef CONFIG_CLK - struct clk clk; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; @@ -197,7 +196,6 @@ static int gpio_stm32_probe(struct udevice *dev) return ret; } debug("clock enabled for device %s\n", dev->name); -#endif
return 0; }

On Mon, Dec 03, 2018 at 10:52:53AM +0100, Patrice Chotard wrote:
As all STM32 SoCs supports CONFIG_CLK flag, it becomes useless in this driver, remove it.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!

Due to gpio holes management, stm32_pinctrl_get_gpio_dev() must be updated.
stm32_pinctrl_get_gpio_dev() returns from a given pin selectors the corresponding bank gpio device and the gpio_offset inside this gpio bank.
Update also all functions which makes usage of stm32_pinctrl_get_gpio_dev.
Signed-off-by: Patrice Chotard patrice.chotard@st.com ---
drivers/pinctrl/pinctrl_stm32.c | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-)
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index aa92c90b8997..24affe0414ce 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -28,8 +28,6 @@ struct stm32_gpio_bank {
#ifndef CONFIG_SPL_BUILD
-#define MAX_PIN_PER_BANK 16 - static char pin_name[PINNAME_SIZE]; #define PINMUX_MODE_COUNT 5 static const char * const pinmux_mode[PINMUX_MODE_COUNT] = { @@ -116,12 +114,13 @@ static int stm32_pinctrl_get_pins_count(struct udevice *dev) }
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); @@ -130,11 +129,19 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, 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 (*idx < 0) + return NULL;
- first_pin += uc_priv->gpio_count; + return gpio_bank->gpio_dev; + } + pin_count += uc_priv->gpio_count; }
return NULL; @@ -145,9 +152,10 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev, { 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 { @@ -155,7 +163,7 @@ static const char *stm32_pinctrl_get_pin_name(struct udevice *dev,
snprintf(pin_name, PINNAME_SIZE, "%s%d", uc_priv->bank_name, - selector % MAX_PIN_PER_BANK); + gpio_idx); }
return pin_name; @@ -168,23 +176,21 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, { struct udevice *gpio_dev; const char *label; - int gpio_pin; int mode; int af_num; + 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) return -ENODEV;
- /* translate pin-controller pin number to gpio pin number */ - gpio_pin = selector % MAX_PIN_PER_BANK; + mode = gpio_get_raw_function(gpio_dev, gpio_idx, &label);
- mode = gpio_get_raw_function(gpio_dev, gpio_pin, &label); + dev_dbg(dev, "selector = %d gpio_idx = %d mode = %d\n", + selector, gpio_idx, mode);
- dev_dbg(dev, "selector = %d gpio_pin = %d mode = %d\n", - selector, gpio_pin, mode);
switch (mode) { case GPIOF_UNKNOWN: @@ -194,7 +200,7 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, snprintf(buf, size, "%s", pinmux_mode[mode]); break; case GPIOF_FUNC: - af_num = stm32_pinctrl_get_af(gpio_dev, gpio_pin); + af_num = stm32_pinctrl_get_af(gpio_dev, gpio_idx); snprintf(buf, size, "%s %d", pinmux_mode[mode], af_num); break; case GPIOF_OUTPUT:

On Mon, Dec 03, 2018 at 10:52:54AM +0100, Patrice Chotard wrote:
Due to gpio holes management, stm32_pinctrl_get_gpio_dev() must be updated.
stm32_pinctrl_get_gpio_dev() returns from a given pin selectors the corresponding bank gpio device and the gpio_offset inside this gpio bank.
Update also all functions which makes usage of stm32_pinctrl_get_gpio_dev.
Signed-off-by: Patrice Chotard patrice.chotard@st.com
Applied to u-boot/master, thanks!
participants (2)
-
Patrice Chotard
-
Tom Rini