[U-Boot] [PATCH 00/10] stm32f7: add clock and pin control drivers

This patchset: - adds support for stm32f7 clock driver. - adds support for stm32f7 pin control driver. - adds device tree nodes for stm32f7 serial & clock. - adds stm32f7 pin control device tree sub nodes : - serial usart1 - ethernet - qspi flash
Vikas Manocha (10): serial: stm32f7: add device tree support clk: stm32f7: add clock driver for stm32f7 family stm32f7: serial: use clock driver to enable clock ARM: DT: stm32f7: add usart1 & clock device tree nodes stm32f7: clk: remove usart1 clock enable from board init PINCTRL: stm32f7: add pin control driver ARM: DT: stm32f7: add pin control device node ARM: DT: stm32f7: add pin control node for serial port pins ARM: DT: stm32f7: add ethernet pin contol node ARM: DT: stm32f7: add qspi pin contol node
arch/arm/dts/stm32f746-disco.dts | 13 ++ arch/arm/dts/stm32f746.dtsi | 72 +++++++++++ arch/arm/mach-stm32/stm32f7/Makefile | 2 +- arch/arm/mach-stm32/stm32f7/soc.c | 2 - board/st/stm32f746-disco/stm32f746-disco.c | 111 +---------------- configs/stm32f746-disco_defconfig | 4 + doc/device-tree-bindings/clock/st,stm32-rcc.txt | 95 +++++++++++++++ .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/clk/Makefile | 2 +- .../stm32f7/clock.c => drivers/clk/clk_stm32f7.c | 66 +++++++++- drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ drivers/serial/serial_stm32x7.c | 40 +++++++ 14 files changed, 549 insertions(+), 119 deletions(-) create mode 100644 doc/device-tree-bindings/clock/st,stm32-rcc.txt create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt rename arch/arm/mach-stm32/stm32f7/clock.c => drivers/clk/clk_stm32f7.c (84%) create mode 100644 drivers/pinctrl/pinctrl_stm32.c

This patch adds device tree support for stm32f7 serial driver & removes serial platform data structure.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- board/st/stm32f746-disco/stm32f746-disco.c | 10 ---------- drivers/serial/serial_stm32x7.c | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 7ed7bf7..72212f4 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -267,16 +267,6 @@ out: return rv; }
-static const struct stm32x7_serial_platdata serial_platdata = { - .base = (struct stm32_usart *)USART1_BASE, - .clock = CONFIG_SYS_CLK_FREQ, -}; - -U_BOOT_DEVICE(stm32x7_serials) = { - .name = "serial_stm32x7", - .platdata = &serial_platdata, -}; - #ifdef CONFIG_ETH_DESIGNWARE const struct stm32_gpio_ctl gpio_ctl_eth = { .mode = STM32_GPIO_MODE_AF, diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index 592c0bd..2e6c676 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -81,6 +81,27 @@ static int stm32_serial_probe(struct udevice *dev) return 0; }
+#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id stm32_serial_id[] = { + {.compatible = "st,stm32-usart"}, + {.compatible = "st,stm32-uart"}, + {} +}; + +static int stm32_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->base = (struct stm32_usart *)addr; + return 0; +} +#endif + static const struct dm_serial_ops stm32_serial_ops = { .putc = stm32_serial_putc, .pending = stm32_serial_pending, @@ -91,6 +112,9 @@ static const struct dm_serial_ops stm32_serial_ops = { U_BOOT_DRIVER(serial_stm32) = { .name = "serial_stm32x7", .id = UCLASS_SERIAL, + .of_match = of_match_ptr(stm32_serial_id), + .ofdata_to_platdata = of_match_ptr(stm32_serial_ofdata_to_platdata), + .platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata), .ops = &stm32_serial_ops, .probe = stm32_serial_probe, .flags = DM_FLAG_PRE_RELOC,

On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
This patch adds device tree support for stm32f7 serial driver & removes serial platform data structure.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
board/st/stm32f746-disco/stm32f746-disco.c | 10 ---------- drivers/serial/serial_stm32x7.c | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

add basic clock driver support for stm32f7 to enable clocks required by the peripherals.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/mach-stm32/stm32f7/Makefile | 2 +- arch/arm/mach-stm32/stm32f7/soc.c | 2 - configs/stm32f746-disco_defconfig | 1 + doc/device-tree-bindings/clock/st,stm32-rcc.txt | 95 ++++++++++++++++++++++ drivers/clk/Makefile | 2 +- .../stm32f7/clock.c => drivers/clk/clk_stm32f7.c | 63 +++++++++++++- 6 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 doc/device-tree-bindings/clock/st,stm32-rcc.txt rename arch/arm/mach-stm32/stm32f7/clock.c => drivers/clk/clk_stm32f7.c (84%)
diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile index 643d4d9..03269bd 100644 --- a/arch/arm/mach-stm32/stm32f7/Makefile +++ b/arch/arm/mach-stm32/stm32f7/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += timer.o clock.o soc.o +obj-y += timer.o soc.o diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c index 8baee99..06af631 100644 --- a/arch/arm/mach-stm32/stm32f7/soc.c +++ b/arch/arm/mach-stm32/stm32f7/soc.c @@ -17,8 +17,6 @@ u32 get_cpu_rev(void)
int arch_cpu_init(void) { - configure_clocks(); - /* * Configure the memory protection unit (MPU) * 0x00000000 - 0xffffffff: Strong-order, Shareable diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index 51b779a..af1449c 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -38,3 +38,4 @@ CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set +CONFIG_CLK=y diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt new file mode 100644 index 0000000..0532d81 --- /dev/null +++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt @@ -0,0 +1,95 @@ +STMicroelectronics STM32 Reset and Clock Controller +=================================================== + +The RCC IP is both a reset and a clock controller. + +Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage. + +Required properties: +- compatible: Should be: + "st,stm32f42xx-rcc" + "st,stm32f469-rcc" +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below +- #clock-cells: 2, device nodes should specify the clock in their "clocks" + property, containing a phandle to the clock device node, an index selecting + between gated clocks and other clocks and an index specifying the clock to + use. + +Example: + + rcc: rcc@40023800 { + #reset-cells = <1>; + #clock-cells = <2> + compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; + reg = <0x40023800 0x400>; + }; + +Specifying gated clocks +======================= + +The primary index must be set to 0. + +The secondary index is the bit number within the RCC register bank, starting +from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30). + +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31). + +To simplify the usage and to share bit definition with the reset and clock +drivers of the RCC IP, macros are available to generate the index in +human-readble format. + +For STM32F4 series, the macro are available here: + - include/dt-bindings/mfd/stm32f4-rcc.h + +Example: + + /* Gated clock, AHB1 bit 0 (GPIOA) */ + ... { + clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)> + }; + + /* Gated clock, AHB2 bit 4 (CRYP) */ + ... { + clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)> + }; + +Specifying other clocks +======================= + +The primary index must be set to 1. + +The secondary index is bound with the following magic numbers: + + 0 SYSTICK + 1 FCLK + +Example: + + /* Misc clock, FCLK */ + ... { + clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)> + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. +For example, for CRC reset: + crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140 + +example: + + timer2 { + resets = <&rcc STM32F4_APB1_RESET(TIM2)>; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 884c21c..1ed29c7 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -17,5 +17,5 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o - obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_STM32F7) += clk_stm32f7.o diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/drivers/clk/clk_stm32f7.c similarity index 84% rename from arch/arm/mach-stm32/stm32f7/clock.c rename to drivers/clk/clk_stm32f7.c index e1ee173..89b123e 100644 --- a/arch/arm/mach-stm32/stm32f7/clock.c +++ b/drivers/clk/clk_stm32f7.c @@ -1,15 +1,16 @@ /* - * (C) Copyright 2016 + * (C) Copyright 2017 * Vikas Manocha, vikas.manocha@st.com * * SPDX-License-Identifier: GPL-2.0+ */ - #include <common.h> #include <asm/io.h> #include <asm/arch/rcc.h> #include <asm/arch/stm32.h> #include <asm/arch/stm32_periph.h> +#include <clk-uclass.h> +#include <dm.h>
#define RCC_CR_HSION BIT(0) #define RCC_CR_HSEON BIT(16) @@ -212,6 +213,15 @@ unsigned long clock_get(enum clock clck) } }
+static int stm32_clk_enable(struct clk *clk) +{ + u32 offset = clk->id / 32; + u32 bit_index = clk->id % 32; + debug("%s: clkid = %ld, offset from AHB1ENR is %d, bit_index = %d\n", + __func__, clk->id, offset, bit_index); + setbits_le32(&STM32_RCC->ahb1enr + offset, BIT(bit_index)); + return 0; +}
void clock_setup(int peripheral) { @@ -273,3 +283,52 @@ void clock_setup(int peripheral) break; } } + +int stm32_clk_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + +static int stm32_clk_probe(struct udevice *dev) +{ + debug("%s: stm32_clk_probe\n", __func__); + configure_clocks(); + return 0; +} + +static int stm32_clk_of_xlate(struct clk *clk, + struct fdtdec_phandle_args *args) +{ + debug("%s(clk=%p)\n", __func__, clk); + + if (args->args_count != 2) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = args->args[1]; + else + clk->id = 0; + + return 0; +} +static struct clk_ops stm32_clk_ops = { + .of_xlate = stm32_clk_of_xlate, + .enable = stm32_clk_enable, +}; + +static const struct udevice_id stm32_clk_ids[] = { + { .compatible = "st,stm32f42xx-rcc"}, + {} +}; + +U_BOOT_DRIVER(stm32f7_clk) = { + .name = "stm32f7_clk", + .id = UCLASS_CLK, + .of_match = stm32_clk_ids, + .ops = &stm32_clk_ops, + .probe = stm32_clk_probe, + .flags = DM_FLAG_PRE_RELOC, + .ofdata_to_platdata = stm32_clk_ofdata_to_platdata, +};

Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
add basic clock driver support for stm32f7 to enable clocks required by the peripherals.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
arch/arm/mach-stm32/stm32f7/Makefile | 2 +- arch/arm/mach-stm32/stm32f7/soc.c | 2 - configs/stm32f746-disco_defconfig | 1 + doc/device-tree-bindings/clock/st,stm32-rcc.txt | 95 ++++++++++++++++++++++ drivers/clk/Makefile | 2 +- .../stm32f7/clock.c => drivers/clk/clk_stm32f7.c | 63 +++++++++++++- 6 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 doc/device-tree-bindings/clock/st,stm32-rcc.txt rename arch/arm/mach-stm32/stm32f7/clock.c => drivers/clk/clk_stm32f7.c (84%)
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile index 643d4d9..03269bd 100644 --- a/arch/arm/mach-stm32/stm32f7/Makefile +++ b/arch/arm/mach-stm32/stm32f7/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += timer.o clock.o soc.o +obj-y += timer.o soc.o diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c index 8baee99..06af631 100644 --- a/arch/arm/mach-stm32/stm32f7/soc.c +++ b/arch/arm/mach-stm32/stm32f7/soc.c @@ -17,8 +17,6 @@ u32 get_cpu_rev(void)
int arch_cpu_init(void) {
configure_clocks();
/* * Configure the memory protection unit (MPU) * 0x00000000 - 0xffffffff: Strong-order, Shareable
diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index 51b779a..af1449c 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -38,3 +38,4 @@ CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set +CONFIG_CLK=y diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt new file mode 100644 index 0000000..0532d81 --- /dev/null +++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt @@ -0,0 +1,95 @@ +STMicroelectronics STM32 Reset and Clock Controller +===================================================
+The RCC IP is both a reset and a clock controller.
+Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage.
+Required properties: +- compatible: Should be:
- "st,stm32f42xx-rcc"
- "st,stm32f469-rcc"
+- reg: should be register base and length as documented in the
- datasheet
+- #reset-cells: 1, see below +- #clock-cells: 2, device nodes should specify the clock in their "clocks"
- property, containing a phandle to the clock device node, an index selecting
- between gated clocks and other clocks and an index specifying the clock to
- use.
+Example:
rcc: rcc@40023800 {
#reset-cells = <1>;
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
};
+Specifying gated clocks +=======================
+The primary index must be set to 0.
+The secondary index is the bit number within the RCC register bank, starting +from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
+It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
+To simplify the usage and to share bit definition with the reset and clock +drivers of the RCC IP, macros are available to generate the index in +human-readble format.
+For STM32F4 series, the macro are available here:
- include/dt-bindings/mfd/stm32f4-rcc.h
+Example:
/* Gated clock, AHB1 bit 0 (GPIOA) */
... {
clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
};
/* Gated clock, AHB2 bit 4 (CRYP) */
... {
clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
};
+Specifying other clocks +=======================
+The primary index must be set to 1.
+The secondary index is bound with the following magic numbers:
0 SYSTICK
1 FCLK
+Example:
/* Misc clock, FCLK */
... {
clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
};
+Specifying softreset control of devices +=======================================
+Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. +For example, for CRC reset:
- crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
+example:
timer2 {
resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 884c21c..1ed29c7 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -17,5 +17,5 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_STM32F7) += clk_stm32f7.o diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/drivers/clk/clk_stm32f7.c similarity index 84% rename from arch/arm/mach-stm32/stm32f7/clock.c rename to drivers/clk/clk_stm32f7.c index e1ee173..89b123e 100644 --- a/arch/arm/mach-stm32/stm32f7/clock.c +++ b/drivers/clk/clk_stm32f7.c @@ -1,15 +1,16 @@ /*
- (C) Copyright 2016
*/
- (C) Copyright 2017
- Vikas Manocha, vikas.manocha@st.com
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <asm/io.h> #include <asm/arch/rcc.h> #include <asm/arch/stm32.h> #include <asm/arch/stm32_periph.h> +#include <clk-uclass.h> +#include <dm.h>
These two should go below common.h
http://www.denx.de/wiki/U-Boot/CodingStyle
#define RCC_CR_HSION BIT(0) #define RCC_CR_HSEON BIT(16) @@ -212,6 +213,15 @@ unsigned long clock_get(enum clock clck) } }
+static int stm32_clk_enable(struct clk *clk) +{
u32 offset = clk->id / 32;
u32 bit_index = clk->id % 32;
blank line after decls
debug("%s: clkid = %ld, offset from AHB1ENR is %d, bit_index = %d\n",
__func__, clk->id, offset, bit_index);
setbits_le32(&STM32_RCC->ahb1enr + offset, BIT(bit_index));
and before return
return 0;
+}
void clock_setup(int peripheral) { @@ -273,3 +283,52 @@ void clock_setup(int peripheral) break; } }
+int stm32_clk_ofdata_to_platdata(struct udevice *dev) +{
return 0;
Can you drop this function? It doesn't do anything.
+}
+static int stm32_clk_probe(struct udevice *dev) +{
debug("%s: stm32_clk_probe\n", __func__);
configure_clocks();
blank line
return 0;
+}
+static int stm32_clk_of_xlate(struct clk *clk,
struct fdtdec_phandle_args *args)
+{
debug("%s(clk=%p)\n", __func__, clk);
if (args->args_count != 2) {
debug("Invaild args_count: %d\n", args->args_count);
return -EINVAL;
}
if (args->args_count)
clk->id = args->args[1];
else
clk->id = 0;
return 0;
+}
Blank line here
+static struct clk_ops stm32_clk_ops = {
.of_xlate = stm32_clk_of_xlate,
.enable = stm32_clk_enable,
+};
+static const struct udevice_id stm32_clk_ids[] = {
{ .compatible = "st,stm32f42xx-rcc"},
{}
+};
+U_BOOT_DRIVER(stm32f7_clk) = {
.name = "stm32f7_clk",
.id = UCLASS_CLK,
.of_match = stm32_clk_ids,
.ops = &stm32_clk_ops,
.probe = stm32_clk_probe,
.flags = DM_FLAG_PRE_RELOC,
.ofdata_to_platdata = stm32_clk_ofdata_to_platdata,
+};
1.9.1
Regards, Simon

Thanks Simon,
On 02/10/2017 08:22 AM, Simon Glass wrote:
Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
add basic clock driver support for stm32f7 to enable clocks required by the peripherals.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
arch/arm/mach-stm32/stm32f7/Makefile | 2 +- arch/arm/mach-stm32/stm32f7/soc.c | 2 - configs/stm32f746-disco_defconfig | 1 + doc/device-tree-bindings/clock/st,stm32-rcc.txt | 95 ++++++++++++++++++++++ drivers/clk/Makefile | 2 +- .../stm32f7/clock.c => drivers/clk/clk_stm32f7.c | 63 +++++++++++++- 6 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 doc/device-tree-bindings/clock/st,stm32-rcc.txt rename arch/arm/mach-stm32/stm32f7/clock.c => drivers/clk/clk_stm32f7.c (84%)
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/arch/arm/mach-stm32/stm32f7/Makefile b/arch/arm/mach-stm32/stm32f7/Makefile index 643d4d9..03269bd 100644 --- a/arch/arm/mach-stm32/stm32f7/Makefile +++ b/arch/arm/mach-stm32/stm32f7/Makefile @@ -5,4 +5,4 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += timer.o clock.o soc.o +obj-y += timer.o soc.o diff --git a/arch/arm/mach-stm32/stm32f7/soc.c b/arch/arm/mach-stm32/stm32f7/soc.c index 8baee99..06af631 100644 --- a/arch/arm/mach-stm32/stm32f7/soc.c +++ b/arch/arm/mach-stm32/stm32f7/soc.c @@ -17,8 +17,6 @@ u32 get_cpu_rev(void)
int arch_cpu_init(void) {
configure_clocks();
/* * Configure the memory protection unit (MPU) * 0x00000000 - 0xffffffff: Strong-order, Shareable
diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index 51b779a..af1449c 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -38,3 +38,4 @@ CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set +CONFIG_CLK=y diff --git a/doc/device-tree-bindings/clock/st,stm32-rcc.txt b/doc/device-tree-bindings/clock/st,stm32-rcc.txt new file mode 100644 index 0000000..0532d81 --- /dev/null +++ b/doc/device-tree-bindings/clock/st,stm32-rcc.txt @@ -0,0 +1,95 @@ +STMicroelectronics STM32 Reset and Clock Controller +===================================================
+The RCC IP is both a reset and a clock controller.
+Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage.
+Required properties: +- compatible: Should be:
- "st,stm32f42xx-rcc"
- "st,stm32f469-rcc"
+- reg: should be register base and length as documented in the
- datasheet
+- #reset-cells: 1, see below +- #clock-cells: 2, device nodes should specify the clock in their "clocks"
- property, containing a phandle to the clock device node, an index selecting
- between gated clocks and other clocks and an index specifying the clock to
- use.
+Example:
rcc: rcc@40023800 {
#reset-cells = <1>;
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
};
+Specifying gated clocks +=======================
+The primary index must be set to 0.
+The secondary index is the bit number within the RCC register bank, starting +from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
+It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
+To simplify the usage and to share bit definition with the reset and clock +drivers of the RCC IP, macros are available to generate the index in +human-readble format.
+For STM32F4 series, the macro are available here:
- include/dt-bindings/mfd/stm32f4-rcc.h
+Example:
/* Gated clock, AHB1 bit 0 (GPIOA) */
... {
clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
};
/* Gated clock, AHB2 bit 4 (CRYP) */
... {
clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
};
+Specifying other clocks +=======================
+The primary index must be set to 1.
+The secondary index is bound with the following magic numbers:
0 SYSTICK
1 FCLK
+Example:
/* Misc clock, FCLK */
... {
clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
};
+Specifying softreset control of devices +=======================================
+Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. +For example, for CRC reset:
- crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
+example:
timer2 {
resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 884c21c..1ed29c7 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -17,5 +17,5 @@ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_STM32F7) += clk_stm32f7.o diff --git a/arch/arm/mach-stm32/stm32f7/clock.c b/drivers/clk/clk_stm32f7.c similarity index 84% rename from arch/arm/mach-stm32/stm32f7/clock.c rename to drivers/clk/clk_stm32f7.c index e1ee173..89b123e 100644 --- a/arch/arm/mach-stm32/stm32f7/clock.c +++ b/drivers/clk/clk_stm32f7.c @@ -1,15 +1,16 @@ /*
- (C) Copyright 2016
*/
- (C) Copyright 2017
- Vikas Manocha, vikas.manocha@st.com
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <asm/io.h> #include <asm/arch/rcc.h> #include <asm/arch/stm32.h> #include <asm/arch/stm32_periph.h> +#include <clk-uclass.h> +#include <dm.h>
These two should go below common.h
ok, will fix in v2.
#define RCC_CR_HSION BIT(0) #define RCC_CR_HSEON BIT(16) @@ -212,6 +213,15 @@ unsigned long clock_get(enum clock clck) } }
+static int stm32_clk_enable(struct clk *clk) +{
u32 offset = clk->id / 32;
u32 bit_index = clk->id % 32;
blank line after decls
ok.
debug("%s: clkid = %ld, offset from AHB1ENR is %d, bit_index = %d\n",
__func__, clk->id, offset, bit_index);
setbits_le32(&STM32_RCC->ahb1enr + offset, BIT(bit_index));
and before return
ok
return 0;
+}
void clock_setup(int peripheral) { @@ -273,3 +283,52 @@ void clock_setup(int peripheral) break; } }
+int stm32_clk_ofdata_to_platdata(struct udevice *dev) +{
return 0;
Can you drop this function? It doesn't do anything.
right, i will remove it.
+}
+static int stm32_clk_probe(struct udevice *dev) +{
debug("%s: stm32_clk_probe\n", __func__);
configure_clocks();
blank line
ok
return 0;
+}
+static int stm32_clk_of_xlate(struct clk *clk,
struct fdtdec_phandle_args *args)
+{
debug("%s(clk=%p)\n", __func__, clk);
if (args->args_count != 2) {
debug("Invaild args_count: %d\n", args->args_count);
return -EINVAL;
}
if (args->args_count)
clk->id = args->args[1];
else
clk->id = 0;
return 0;
+}
Blank line here
ok
Cheers, Vikas
+static struct clk_ops stm32_clk_ops = {
.of_xlate = stm32_clk_of_xlate,
.enable = stm32_clk_enable,
+};
+static const struct udevice_id stm32_clk_ids[] = {
{ .compatible = "st,stm32f42xx-rcc"},
{}
+};
+U_BOOT_DRIVER(stm32f7_clk) = {
.name = "stm32f7_clk",
.id = UCLASS_CLK,
.of_match = stm32_clk_ids,
.ops = &stm32_clk_ops,
.probe = stm32_clk_probe,
.flags = DM_FLAG_PRE_RELOC,
.ofdata_to_platdata = stm32_clk_ofdata_to_platdata,
+};
1.9.1
Regards, Simon .

Signed-off-by: Vikas Manocha vikas.manocha@st.com --- drivers/serial/serial_stm32x7.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index 2e6c676..969d94c 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -6,6 +6,7 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> #include <asm/io.h> #include <serial.h> @@ -76,8 +77,23 @@ static int stm32_serial_probe(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev->platdata; struct stm32_usart *const usart = plat->base; - setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
+#if CONFIG_IS_ENABLED(CLK) + int ret; + struct clk clk; + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } +#endif + + setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); return 0; }

Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
Signed-off-by: Vikas Manocha vikas.manocha@st.com
drivers/serial/serial_stm32x7.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
Nits below
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index 2e6c676..969d94c 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -6,6 +6,7 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> #include <asm/io.h> #include <serial.h> @@ -76,8 +77,23 @@ static int stm32_serial_probe(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev->platdata; struct stm32_usart *const usart = plat->base;
setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
+#if CONFIG_IS_ENABLED(CLK)
Or #ifdef CONFIG_CLK
int ret;
struct clk clk;
blank line here
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
drop blank line (since the statement below relates to this one.
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}
+#endif
setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
blank line
return 0;
}
-- 1.9.1
Regards, Simon

Thanks Simon,
On 02/10/2017 08:22 AM, Simon Glass wrote:
Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
Signed-off-by: Vikas Manocha vikas.manocha@st.com
drivers/serial/serial_stm32x7.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
Nits below
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index 2e6c676..969d94c 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -6,6 +6,7 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> #include <asm/io.h> #include <serial.h> @@ -76,8 +77,23 @@ static int stm32_serial_probe(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev->platdata; struct stm32_usart *const usart = plat->base;
setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
+#if CONFIG_IS_ENABLED(CLK)
Or #ifdef CONFIG_CLK
int ret;
struct clk clk;
blank line here
ok, i will add/remove the blank lines it in v2 for this and for other blanks line comments below. Thanks to highlight.
Cheers, Vikas
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
drop blank line (since the statement below relates to this one.
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}
+#endif
setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
blank line
return 0;
}
-- 1.9.1
Regards, Simon .

Also created alias for usart1 and specified oscillator clock for stm32f7 discovery board.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/dts/stm32f746-disco.dts | 5 +++++ arch/arm/dts/stm32f746.dtsi | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm/dts/stm32f746-disco.dts b/arch/arm/dts/stm32f746-disco.dts index bad0698..454b515 100644 --- a/arch/arm/dts/stm32f746-disco.dts +++ b/arch/arm/dts/stm32f746-disco.dts @@ -61,10 +61,15 @@ };
aliases { + serial0 = &usart1; spi0 = &qspi; }; };
+&clk_hse { + clock-frequency = <25000000>; +}; + &mac { status = "okay"; phy-mode = "rmii"; diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index 3902e76..afcd327 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -48,7 +48,16 @@ #include <dt-bindings/pinctrl/stm32f746-pinfunc.h>
/ { + clocks { + clk_hse: clk-hse { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; + soc { + u-boot,dm-pre-reloc; mac: ethernet@40028000 { compatible = "st,stm32-dwmac"; reg = <0x40028000 0x8000>; @@ -71,6 +80,24 @@ spi-max-frequency = <108000000>; status = "disabled"; }; + usart1: serial@40011000 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&rcc 0 164>; + status = "disabled"; + u-boot,dm-pre-reloc; + }; + rcc: rcc@40023810 { + #reset-cells = <1>; + #clock-cells = <2>; + compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; + reg = <0x40023800 0x400>; + clocks = <&clk_hse>; + u-boot,dm-pre-reloc; + }; + + }; };

Before clock driver availability it was required to enable usart1 clock for serial init but now with clock driver is taking care of usart1 clock.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- board/st/stm32f746-disco/stm32f746-disco.c | 1 - drivers/clk/clk_stm32f7.c | 3 --- 2 files changed, 4 deletions(-)
diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 72212f4..ee1deb5 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -380,7 +380,6 @@ int board_early_init_f(void) int res;
res = uart_setup_gpio(); - clock_setup(USART1_CLOCK_CFG); if (res) return res;
diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f7.c index 89b123e..60cf502 100644 --- a/drivers/clk/clk_stm32f7.c +++ b/drivers/clk/clk_stm32f7.c @@ -226,9 +226,6 @@ static int stm32_clk_enable(struct clk *clk) void clock_setup(int peripheral) { switch (peripheral) { - case USART1_CLOCK_CFG: - setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_USART1EN); - break; case GPIO_A_CLOCK_CFG: setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_A_EN); break;

This driver uses the same pin control binding as that of linux, binding document of this patch is copied from linux. One addition done is for GPIO input and output mode configuration which was missing.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- configs/stm32f746-disco_defconfig | 3 + .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl_stm32.c
diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index af1449c..e77ebfc 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -39,3 +39,6 @@ CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set CONFIG_CLK=y +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_FULL is not set +CONFIG_PINCTRL_STM32=y diff --git a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt new file mode 100644 index 0000000..c41ae91 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt @@ -0,0 +1,133 @@ +* STM32 GPIO and Pin Mux/Config controller + +STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pins and +also provides ability to multiplex and configure the output of various on-chip +controllers onto these pads. + +Pin controller node: +Required properies: + - compatible: value should be one of the following: + (a) "st,stm32f429-pinctrl" + (b) "st,stm32f746-pinctrl" + - #address-cells: The value of this property must be 1 + - #size-cells : The value of this property must be 1 + - ranges : defines mapping between pin controller node (parent) to + gpio-bank node (children). + - pins-are-numbered: Specify the subnodes are using numbered pinmux to + specify pins. + +GPIO controller/bank node: +Required properties: + - gpio-controller : Indicates this device is a GPIO controller + - #gpio-cells : Should be two. + The first cell is the pin number + The second one is the polarity: + - 0 for active high + - 1 for active low + - reg : The gpio address range, relative to the pinctrl range + - clocks : clock that drives this bank + - st,bank-name : Should be a name string for this bank as specified in + the datasheet + +Optional properties: + - reset: : Reference to the reset controller + - interrupt-parent: phandle of the interrupt parent to which the external + GPIO interrupts are forwarded to. + - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node + which includes IRQ mux selection register, and the offset of the IRQ mux + selection register. + +Example: +#include <dt-bindings/pinctrl/stm32f429-pinfunc.h> +... + + pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32f429-pinctrl"; + ranges = <0 0x40020000 0x3000>; + pins-are-numbered; + + gpioa: gpio@40020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOA"; + }; + ... + pin-functions nodes follow... + }; + +Contents of function subnode node: +---------------------------------- +Subnode format +A pinctrl node should contain at least one subnode representing the +pinctrl group available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive, output high/low and output speed. + + node { + pinmux = <PIN_NUMBER_PINMUX>; + GENERIC_PINCONFIG; + }; + +Required properties: +- pinmux: integer array, represents gpio pin number and mux setting. + Supported pin number and mux varies for different SoCs, and are defined in + dt-bindings/pinctrl/<soc>-pinfunc.h directly. + These defines are calculated as: + ((port * 16 + line) << 8) | function + With: + - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11) + - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15) + - function: The function number, can be: + * 0 : GPIO IN + * 1 : Alternate Function 0 + * 2 : Alternate Function 1 + * 3 : Alternate Function 2 + * ... + * 16 : Alternate Function 15 + * 17 : Analog + * 18 : GPIO OUT + +Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use. + Available options are: + - bias-disable, + - bias-pull-down, + - bias-pull-up, + - drive-push-pull, + - drive-open-drain, + - output-low + - output-high + - slew-rate = <x>, with x being: + < 0 > : Low speed + < 1 > : Medium speed + < 2 > : Fast speed + < 3 > : High speed + +Example: + +pin-controller { +... + usart1_pins_a: usart1@0 { + pins1 { + pinmux = <STM32F429_PA9_FUNC_USART1_TX>; + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = <STM32F429_PA10_FUNC_USART1_RX>; + bias-disable; + }; + }; +}; + +&usart1 { + pinctrl-0 = <&usart1_pins_a>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..2dc420c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,15 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config PINCTRL_STM32 + bool "ST STM32 pin control driver" + depends on DM + help + Supports pin multiplexing control on stm32 SoCs. The driver is + controlled by a device tree node which contains both the GPIO + definitions and pin control functions for each available multiplex + function. + endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..2e23b05 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/ +obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c new file mode 100644 index 0000000..c794056 --- /dev/null +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -0,0 +1,118 @@ +#include <common.h> +#include <asm/arch/gpio.h> +#include <dm.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) +{ + gpio_dsc->port = (port_pin & 0xF000) >> 12; + gpio_dsc->pin = (port_pin & 0x0F00) >> 8; + debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port, + gpio_dsc->pin); + return 0; +} + +static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) +{ + gpio_fn &= 0x00FF; + + switch (gpio_fn) { + case 0: + gpio_ctl->mode = STM32_GPIO_MODE_IN; + break; + case 1 ... 16: + gpio_ctl->mode = STM32_GPIO_MODE_AF; + gpio_ctl->af = gpio_fn - 1; + break; + case 17: + gpio_ctl->mode = STM32_GPIO_MODE_AN; + break; + default: + gpio_ctl->mode = STM32_GPIO_MODE_OUT; + break; + } + + gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0); + + if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain")) + gpio_ctl->otype = STM32_GPIO_OTYPE_OD; + else + gpio_ctl->otype = STM32_GPIO_OTYPE_PP; + + if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up")) + gpio_ctl->pupd = STM32_GPIO_PUPD_UP; + else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down")) + gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN; + else + gpio_ctl->pupd = STM32_GPIO_PUPD_NO; + + debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n", + __func__, gpio_fn, gpio_ctl->speed, gpio_ctl->otype, + gpio_ctl->pupd); + return 0; +} + +static int stm32_pinctrl_set_state_simple(struct udevice *dev, + struct udevice *periph) +{ + u32 pin_mux[50]; + struct fdtdec_phandle_args args; + int rv, len; + + /* Get node pinctrl-0 */ + rv = fdtdec_parse_phandle_with_args(gd->fdt_blob, periph->of_offset, + "pinctrl-0", 0, 0, 0, &args); + if (rv) + return rv; + /* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for + * usart1) of pin controller phandle "pinctrl-0" */ + fdt_for_each_subnode(args.node, gd->fdt_blob, args.node) { + struct stm32_gpio_dsc gpio_dsc; + struct stm32_gpio_ctl gpio_ctl; + int i; + /* just to get the length of "pinmux" to allocate + * correct size or memory */ + fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len); + len /= 4; + debug("%s: no of pinmux entries= %d\n", __func__, len); + rv = fdtdec_get_int_array(gd->fdt_blob, args.node, + "pinmux", pin_mux, len); + if (rv) + return rv; + for (i = 0; i < len; i++) { + debug("%s: pinmux = %x\n", __func__, *(pin_mux + i)); + prep_gpio_dsc(&gpio_dsc, *(pin_mux + i)); + prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node); + + rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl); + debug("%s: rv = %d\n\n", __func__, rv); + if (rv) + return rv; + } + } + return 0; +} + +static int stm32_pinctrl_probe(struct udevice *dev) +{ + return 0; +} +static struct pinctrl_ops stm32_pinctrl_ops = { + .set_state_simple = stm32_pinctrl_set_state_simple, +}; + +static const struct udevice_id stm32_pinctrl_ids[] = { + { .compatible = "st,stm32f746-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_stm32) = { + .name = "pinctrl_stm32", + .id = UCLASS_PINCTRL, + .of_match = stm32_pinctrl_ids, + .ops = &stm32_pinctrl_ops, + .probe = stm32_pinctrl_probe, + .bind = dm_scan_fdt_dev, +};

Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
This driver uses the same pin control binding as that of linux, binding document of this patch is copied from linux. One addition done is for GPIO input and output mode configuration which was missing.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
configs/stm32f746-disco_defconfig | 3 + .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl_stm32.c
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index af1449c..e77ebfc 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -39,3 +39,6 @@ CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set CONFIG_CLK=y +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_FULL is not set +CONFIG_PINCTRL_STM32=y diff --git a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt new file mode 100644 index 0000000..c41ae91 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt @@ -0,0 +1,133 @@ +* STM32 GPIO and Pin Mux/Config controller
+STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pins and +also provides ability to multiplex and configure the output of various on-chip +controllers onto these pads.
+Pin controller node: +Required properies:
- compatible: value should be one of the following:
- (a) "st,stm32f429-pinctrl"
- (b) "st,stm32f746-pinctrl"
- #address-cells: The value of this property must be 1
- #size-cells : The value of this property must be 1
- ranges : defines mapping between pin controller node (parent) to
- gpio-bank node (children).
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
- specify pins.
+GPIO controller/bank node: +Required properties:
- gpio-controller : Indicates this device is a GPIO controller
- #gpio-cells : Should be two.
The first cell is the pin number
The second one is the polarity:
- 0 for active high
- 1 for active low
- reg : The gpio address range, relative to the pinctrl range
- clocks : clock that drives this bank
- st,bank-name : Should be a name string for this bank as specified in
- the datasheet
+Optional properties:
- reset: : Reference to the reset controller
- interrupt-parent: phandle of the interrupt parent to which the external
- GPIO interrupts are forwarded to.
- st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
- which includes IRQ mux selection register, and the offset of the IRQ mux
- selection register.
+Example: +#include <dt-bindings/pinctrl/stm32f429-pinfunc.h> +...
pin-controller {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stm32f429-pinctrl";
ranges = <0 0x40020000 0x3000>;
pins-are-numbered;
gpioa: gpio@40020000 {
gpio-controller;
#gpio-cells = <2>;
reg = <0x0 0x400>;
resets = <&reset_ahb1 0>;
st,bank-name = "GPIOA";
};
...
pin-functions nodes follow...
};
+Contents of function subnode node: +---------------------------------- +Subnode format +A pinctrl node should contain at least one subnode representing the +pinctrl group available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive, output high/low and output speed.
- node {
pinmux = <PIN_NUMBER_PINMUX>;
GENERIC_PINCONFIG;
- };
+Required properties: +- pinmux: integer array, represents gpio pin number and mux setting.
- Supported pin number and mux varies for different SoCs, and are defined in
- dt-bindings/pinctrl/<soc>-pinfunc.h directly.
- These defines are calculated as:
- ((port * 16 + line) << 8) | function
- With:
- port: The gpio port index (PA = 0, PB = 1, ..., PK = 11)
- line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15)
- function: The function number, can be:
* 0 : GPIO IN
* 1 : Alternate Function 0
* 2 : Alternate Function 1
* 3 : Alternate Function 2
* ...
* 16 : Alternate Function 15
* 17 : Analog
* 18 : GPIO OUT
+Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use.
- Available options are:
- bias-disable,
- bias-pull-down,
- bias-pull-up,
- drive-push-pull,
- drive-open-drain,
- output-low
- output-high
- slew-rate = <x>, with x being:
< 0 > : Low speed
< 1 > : Medium speed
< 2 > : Fast speed
< 3 > : High speed
+Example:
+pin-controller { +...
usart1_pins_a: usart1@0 {
pins1 {
pinmux = <STM32F429_PA9_FUNC_USART1_TX>;
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32F429_PA10_FUNC_USART1_RX>;
bias-disable;
};
};
+};
+&usart1 {
pinctrl-0 = <&usart1_pins_a>;
pinctrl-names = "default";
status = "okay";
+}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..2dc420c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,15 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config PINCTRL_STM32
bool "ST STM32 pin control driver"
depends on DM
help
Supports pin multiplexing control on stm32 SoCs. The driver is
controlled by a device tree node which contains both the GPIO
definitions and pin control functions for each available multiplex
function.
endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..2e23b05 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/ +obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c new file mode 100644 index 0000000..c794056 --- /dev/null +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -0,0 +1,118 @@ +#include <common.h> +#include <asm/arch/gpio.h> +#include <dm.h> +#include <dm/pinctrl.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) +{
gpio_dsc->port = (port_pin & 0xF000) >> 12;
gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
gpio_dsc->pin);
blank line
return 0;
+}
+static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) +{
gpio_fn &= 0x00FF;
switch (gpio_fn) {
case 0:
gpio_ctl->mode = STM32_GPIO_MODE_IN;
break;
case 1 ... 16:
gpio_ctl->mode = STM32_GPIO_MODE_AF;
gpio_ctl->af = gpio_fn - 1;
break;
case 17:
gpio_ctl->mode = STM32_GPIO_MODE_AN;
break;
default:
gpio_ctl->mode = STM32_GPIO_MODE_OUT;
break;
}
gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
else
gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
else
gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
__func__, gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
gpio_ctl->pupd);
blank line
return 0;
+}
+static int stm32_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
+{
u32 pin_mux[50];
struct fdtdec_phandle_args args;
int rv, len;
/* Get node pinctrl-0 */
rv = fdtdec_parse_phandle_with_args(gd->fdt_blob, periph->of_offset,
"pinctrl-0", 0, 0, 0, &args);
if (rv)
return rv;
/* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
* usart1) of pin controller phandle "pinctrl-0" */
fdt_for_each_subnode(args.node, gd->fdt_blob, args.node) {
struct stm32_gpio_dsc gpio_dsc;
struct stm32_gpio_ctl gpio_ctl;
int i;
blank line
/* just to get the length of "pinmux" to allocate
* correct size or memory */
/* * Just to get the ... * ... */
also try to use more of the columns
fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len);
len /= 4;
debug("%s: no of pinmux entries= %d\n", __func__, len);
rv = fdtdec_get_int_array(gd->fdt_blob, args.node,
"pinmux", pin_mux, len);
Can you use fdtdec_get_int_array_count() ?
if (rv)
return rv;
return -EINVAL
since rv will contain an FDT error (different values)
for (i = 0; i < len; i++) {
debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node);
rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl);
debug("%s: rv = %d\n\n", __func__, rv);
if (rv)
return rv;
}
}
return 0;
+}
+static int stm32_pinctrl_probe(struct udevice *dev) +{
return 0;
+}
drop this function?
+static struct pinctrl_ops stm32_pinctrl_ops = {
.set_state_simple = stm32_pinctrl_set_state_simple,
+};
+static const struct udevice_id stm32_pinctrl_ids[] = {
{ .compatible = "st,stm32f746-pinctrl" },
{ }
+};
+U_BOOT_DRIVER(pinctrl_stm32) = {
.name = "pinctrl_stm32",
.id = UCLASS_PINCTRL,
.of_match = stm32_pinctrl_ids,
.ops = &stm32_pinctrl_ops,
.probe = stm32_pinctrl_probe,
.bind = dm_scan_fdt_dev,
+};
1.9.1
Regards, Simon

Hi Simon,
On 02/10/2017 08:22 AM, Simon Glass wrote:
Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
This driver uses the same pin control binding as that of linux, binding document of this patch is copied from linux. One addition done is for GPIO input and output mode configuration which was missing.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
configs/stm32f746-disco_defconfig | 3 + .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl_stm32.c
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index af1449c..e77ebfc 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -39,3 +39,6 @@ CONFIG_STM32_QSPI=y CONFIG_OF_LIBFDT_OVERLAY=y # CONFIG_EFI_LOADER is not set CONFIG_CLK=y +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_FULL is not set +CONFIG_PINCTRL_STM32=y diff --git a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt new file mode 100644 index 0000000..c41ae91 --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt @@ -0,0 +1,133 @@ +* STM32 GPIO and Pin Mux/Config controller
+STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pins and +also provides ability to multiplex and configure the output of various on-chip +controllers onto these pads.
+Pin controller node: +Required properies:
- compatible: value should be one of the following:
- (a) "st,stm32f429-pinctrl"
- (b) "st,stm32f746-pinctrl"
- #address-cells: The value of this property must be 1
- #size-cells : The value of this property must be 1
- ranges : defines mapping between pin controller node (parent) to
- gpio-bank node (children).
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
- specify pins.
+GPIO controller/bank node: +Required properties:
- gpio-controller : Indicates this device is a GPIO controller
- #gpio-cells : Should be two.
The first cell is the pin number
The second one is the polarity:
- 0 for active high
- 1 for active low
- reg : The gpio address range, relative to the pinctrl range
- clocks : clock that drives this bank
- st,bank-name : Should be a name string for this bank as specified in
- the datasheet
+Optional properties:
- reset: : Reference to the reset controller
- interrupt-parent: phandle of the interrupt parent to which the external
- GPIO interrupts are forwarded to.
- st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
- which includes IRQ mux selection register, and the offset of the IRQ mux
- selection register.
+Example: +#include <dt-bindings/pinctrl/stm32f429-pinfunc.h> +...
pin-controller {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stm32f429-pinctrl";
ranges = <0 0x40020000 0x3000>;
pins-are-numbered;
gpioa: gpio@40020000 {
gpio-controller;
#gpio-cells = <2>;
reg = <0x0 0x400>;
resets = <&reset_ahb1 0>;
st,bank-name = "GPIOA";
};
...
pin-functions nodes follow...
};
+Contents of function subnode node: +---------------------------------- +Subnode format +A pinctrl node should contain at least one subnode representing the +pinctrl group available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive, output high/low and output speed.
- node {
pinmux = <PIN_NUMBER_PINMUX>;
GENERIC_PINCONFIG;
- };
+Required properties: +- pinmux: integer array, represents gpio pin number and mux setting.
- Supported pin number and mux varies for different SoCs, and are defined in
- dt-bindings/pinctrl/<soc>-pinfunc.h directly.
- These defines are calculated as:
- ((port * 16 + line) << 8) | function
- With:
- port: The gpio port index (PA = 0, PB = 1, ..., PK = 11)
- line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15)
- function: The function number, can be:
* 0 : GPIO IN
* 1 : Alternate Function 0
* 2 : Alternate Function 1
* 3 : Alternate Function 2
* ...
* 16 : Alternate Function 15
* 17 : Analog
* 18 : GPIO OUT
+Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use.
- Available options are:
- bias-disable,
- bias-pull-down,
- bias-pull-up,
- drive-push-pull,
- drive-open-drain,
- output-low
- output-high
- slew-rate = <x>, with x being:
< 0 > : Low speed
< 1 > : Medium speed
< 2 > : Fast speed
< 3 > : High speed
+Example:
+pin-controller { +...
usart1_pins_a: usart1@0 {
pins1 {
pinmux = <STM32F429_PA9_FUNC_USART1_TX>;
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32F429_PA10_FUNC_USART1_RX>;
bias-disable;
};
};
+};
+&usart1 {
pinctrl-0 = <&usart1_pins_a>;
pinctrl-names = "default";
status = "okay";
+}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index efcb4c0..2dc420c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -175,6 +175,15 @@ config PIC32_PINCTRL by a device tree node which contains both GPIO defintion and pin control functions.
+config PINCTRL_STM32
bool "ST STM32 pin control driver"
depends on DM
help
Supports pin multiplexing control on stm32 SoCs. The driver is
controlled by a device tree node which contains both the GPIO
definitions and pin control functions for each available multiplex
function.
endif
source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 512112a..2e23b05 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/ +obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c new file mode 100644 index 0000000..c794056 --- /dev/null +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -0,0 +1,118 @@ +#include <common.h> +#include <asm/arch/gpio.h> +#include <dm.h> +#include <dm/pinctrl.h>
+DECLARE_GLOBAL_DATA_PTR;
+static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) +{
gpio_dsc->port = (port_pin & 0xF000) >> 12;
gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
gpio_dsc->pin);
blank line
return 0;
+}
+static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) +{
gpio_fn &= 0x00FF;
switch (gpio_fn) {
case 0:
gpio_ctl->mode = STM32_GPIO_MODE_IN;
break;
case 1 ... 16:
gpio_ctl->mode = STM32_GPIO_MODE_AF;
gpio_ctl->af = gpio_fn - 1;
break;
case 17:
gpio_ctl->mode = STM32_GPIO_MODE_AN;
break;
default:
gpio_ctl->mode = STM32_GPIO_MODE_OUT;
break;
}
gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
else
gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
else
gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
__func__, gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
gpio_ctl->pupd);
blank line
ok
return 0;
+}
+static int stm32_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
+{
u32 pin_mux[50];
struct fdtdec_phandle_args args;
int rv, len;
/* Get node pinctrl-0 */
rv = fdtdec_parse_phandle_with_args(gd->fdt_blob, periph->of_offset,
"pinctrl-0", 0, 0, 0, &args);
if (rv)
return rv;
/* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
* usart1) of pin controller phandle "pinctrl-0" */
fdt_for_each_subnode(args.node, gd->fdt_blob, args.node) {
struct stm32_gpio_dsc gpio_dsc;
struct stm32_gpio_ctl gpio_ctl;
int i;
blank line
ok
/* just to get the length of "pinmux" to allocate
* correct size or memory */
/*
- Just to get the ...
- ...
*/
also try to use more of the columns
yes, I will do it in v2 :-)
fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len);
len /= 4;
debug("%s: no of pinmux entries= %d\n", __func__, len);
rv = fdtdec_get_int_array(gd->fdt_blob, args.node,
"pinmux", pin_mux, len);
Can you use fdtdec_get_int_array_count() ?
Yes but it's almost same, the only difference being xxx_array_count is relaxed on lenght/count. And in this case we are reading length of the property just before.
In any case, i will change it to xxx_array_count in v2.
if (rv)
return rv;
return -EINVAL
since rv will contain an FDT error (different values)
ok.
for (i = 0; i < len; i++) {
debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node);
rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl);
debug("%s: rv = %d\n\n", __func__, rv);
if (rv)
return rv;
}
}
return 0;
+}
+static int stm32_pinctrl_probe(struct udevice *dev) +{
return 0;
+}
drop this function?
Yes agree.
Cheers, Vikas
+static struct pinctrl_ops stm32_pinctrl_ops = {
.set_state_simple = stm32_pinctrl_set_state_simple,
+};
+static const struct udevice_id stm32_pinctrl_ids[] = {
{ .compatible = "st,stm32f746-pinctrl" },
{ }
+};
+U_BOOT_DRIVER(pinctrl_stm32) = {
.name = "pinctrl_stm32",
.id = UCLASS_PINCTRL,
.of_match = stm32_pinctrl_ids,
.ops = &stm32_pinctrl_ops,
.probe = stm32_pinctrl_probe,
.bind = dm_scan_fdt_dev,
+};
1.9.1
Regards, Simon .

Hi Vikas,
On 10 February 2017 at 14:39, vikas vikas.manocha@st.com wrote:
Hi Simon,
On 02/10/2017 08:22 AM, Simon Glass wrote:
Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
This driver uses the same pin control binding as that of linux, binding document of this patch is copied from linux. One addition done is for GPIO input and output mode configuration which was missing.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
configs/stm32f746-disco_defconfig | 3 + .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl_stm32.c
Reviewed-by: Simon Glass sjg@chromium.org
nits below
[..]
fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len);
len /= 4;
debug("%s: no of pinmux entries= %d\n", __func__, len);
rv = fdtdec_get_int_array(gd->fdt_blob, args.node,
"pinmux", pin_mux, len);
Can you use fdtdec_get_int_array_count() ?
Yes but it's almost same, the only difference being xxx_array_count is relaxed on lenght/count. And in this case we are reading length of the property just before.
In any case, i will change it to xxx_array_count in v2.
Yes your code works. I'm only suggesting the change because, in a way, fdt_get_property() is quite a low-level function. You can do what you want with an fdtdec function and thus avoid using libfdt directly.
[...]
Regards, Simon

Thanks Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Saturday, February 11, 2017 12:20 PM To: Vikas MANOCHA vikas.manocha@st.com Cc: U-Boot Mailing List u-boot@lists.denx.de; Beniamino Galvani b.galvani@gmail.com; Daniel Schwierzeck daniel.schwierzeck@gmail.com; Heiko Stübner heiko@sntech.de; Kever Yang kever.yang@rock-chips.com; Konstantin Porotchkin kostap@marvell.com; Masahiro Yamada yamada.masahiro@socionext.com; Minkyu Kang mk7.kang@samsung.com; Peng Fan van.freenix@gmail.com; Stefan Roese sr@denx.de; Thomas Abraham thomas.ab@samsung.com; Wenyou Yang wenyou.yang@atmel.com; Wills Wang wills.wang@live.com Subject: Re: [PATCH 06/10] PINCTRL: stm32f7: add pin control driver
Hi Vikas,
On 10 February 2017 at 14:39, vikas vikas.manocha@st.com wrote:
Hi Simon,
On 02/10/2017 08:22 AM, Simon Glass wrote:
Hi Vikas,
On 4 February 2017 at 15:43, Vikas Manocha vikas.manocha@st.com wrote:
This driver uses the same pin control binding as that of linux, binding document of this patch is copied from linux. One addition done is for GPIO input and output mode configuration which was missing.
Signed-off-by: Vikas Manocha vikas.manocha@st.com
configs/stm32f746-disco_defconfig | 3 + .../pinctrl/st,stm32-pinctrl.txt | 133 +++++++++++++++++++++ drivers/pinctrl/Kconfig | 9 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl_stm32.c | 118 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl_stm32.c
Reviewed-by: Simon Glass sjg@chromium.org
nits below
[..]
fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len);
len /= 4;
debug("%s: no of pinmux entries= %d\n", __func__, len);
rv = fdtdec_get_int_array(gd->fdt_blob, args.node,
"pinmux", pin_mux,
- len);
Can you use fdtdec_get_int_array_count() ?
Yes but it's almost same, the only difference being xxx_array_count is relaxed on lenght/count. And in this case we are reading length of the property just before.
In any case, i will change it to xxx_array_count in v2.
Yes your code works. I'm only suggesting the change because, in a way, fdt_get_property() is quite a low-level function. You can do what you want with an fdtdec function and thus avoid using libfdt directly.
Ah..got it, I will remove the length check & use xxx_array_count in v3.
Cheers, Vikas
[...]
Regards, Simon

Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/dts/stm32f746.dtsi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index afcd327..f59eca8 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -97,7 +97,14 @@ u-boot,dm-pre-reloc; };
- + pinctrl: pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32f746-pinctrl"; + ranges = <0 0x40020000 0x3000>; + u-boot,dm-pre-reloc; + pins-are-numbered; + }; }; };

And remove the uart pin configuration from board initialization.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/dts/stm32f746-disco.dts | 6 ++++++ arch/arm/dts/stm32f746.dtsi | 13 +++++++++++++ board/st/stm32f746-disco/stm32f746-disco.c | 25 +------------------------ 3 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/arch/arm/dts/stm32f746-disco.dts b/arch/arm/dts/stm32f746-disco.dts index 454b515..6734f23 100644 --- a/arch/arm/dts/stm32f746-disco.dts +++ b/arch/arm/dts/stm32f746-disco.dts @@ -70,6 +70,12 @@ clock-frequency = <25000000>; };
+&usart1 { + pinctrl-0 = <&usart1_pins_a>; + pinctrl-names = "default"; + status = "okay"; +}; + &mac { status = "okay"; phy-mode = "rmii"; diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index f59eca8..867f399 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -104,6 +104,19 @@ ranges = <0 0x40020000 0x3000>; u-boot,dm-pre-reloc; pins-are-numbered; + + usart1_pins_a: usart1@0 { + pins1 { + pinmux = <STM32F746_PA9_FUNC_USART1_TX>; + bias-disable; + drive-push-pull; + slew-rate = <2>; + }; + pins2 { + pinmux = <STM32F746_PB7_FUNC_USART1_RX>; + bias-disable; + }; + }; }; }; }; diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index ee1deb5..9ebc36b 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -27,14 +27,6 @@ const struct stm32_gpio_ctl gpio_ctl_gpout = { .af = STM32_GPIO_AF0 };
-const struct stm32_gpio_ctl gpio_ctl_usart = { - .mode = STM32_GPIO_MODE_AF, - .otype = STM32_GPIO_OTYPE_PP, - .speed = STM32_GPIO_SPEED_50M, - .pupd = STM32_GPIO_PUPD_UP, - .af = STM32_GPIO_AF7 -}; - const struct stm32_gpio_ctl gpio_ctl_fmc = { .mode = STM32_GPIO_MODE_AF, .otype = STM32_GPIO_OTYPE_PP, @@ -245,26 +237,11 @@ int dram_init(void) return rv; }
-static const struct stm32_gpio_dsc usart_gpio[] = { - {STM32_GPIO_PORT_A, STM32_GPIO_PIN_9}, /* TX */ - {STM32_GPIO_PORT_B, STM32_GPIO_PIN_7}, /* RX */ -}; - int uart_setup_gpio(void) { - int i; - int rv = 0; - clock_setup(GPIO_A_CLOCK_CFG); clock_setup(GPIO_B_CLOCK_CFG); - for (i = 0; i < ARRAY_SIZE(usart_gpio); i++) { - rv = stm32_gpio_config(&usart_gpio[i], &gpio_ctl_usart); - if (rv) - goto out; - } - -out: - return rv; + return 0; }
#ifdef CONFIG_ETH_DESIGNWARE

It also removes the ethernet pin configuration done during the board initialization.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/dts/stm32f746-disco.dts | 1 + arch/arm/dts/stm32f746.dtsi | 14 +++++++++++++ board/st/stm32f746-disco/stm32f746-disco.c | 32 ------------------------------ 3 files changed, 15 insertions(+), 32 deletions(-)
diff --git a/arch/arm/dts/stm32f746-disco.dts b/arch/arm/dts/stm32f746-disco.dts index 6734f23..3d6002f 100644 --- a/arch/arm/dts/stm32f746-disco.dts +++ b/arch/arm/dts/stm32f746-disco.dts @@ -78,6 +78,7 @@
&mac { status = "okay"; + pinctrl-0 = <ðernet_mii>; phy-mode = "rmii"; phy-handle = <&phy0>;
diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index 867f399..431e79c 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -117,6 +117,20 @@ bias-disable; }; }; + ethernet_mii: mii@0 { + pins { + pinmux = <STM32F746_PG13_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0>, + <STM32F746_PG14_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1>, + <STM32F746_PG11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN>, + <STM32F746_PA2_FUNC_ETH_MDIO>, + <STM32F746_PC1_FUNC_ETH_MDC>, + <STM32F746_PA1_FUNC_ETH_MII_RX_CLK_ETH_RMII_REF_CLK>, + <STM32F746_PA7_FUNC_ETH_MII_RX_DV_ETH_RMII_CRS_DV>, + <STM32F746_PC4_FUNC_ETH_MII_RXD0_ETH_RMII_RXD0>, + <STM32F746_PC5_FUNC_ETH_MII_RXD1_ETH_RMII_RXD1>; + slew-rate = <2>; + }; + }; }; }; }; diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 9ebc36b..8343f82 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -245,48 +245,16 @@ int uart_setup_gpio(void) }
#ifdef CONFIG_ETH_DESIGNWARE -const struct stm32_gpio_ctl gpio_ctl_eth = { - .mode = STM32_GPIO_MODE_AF, - .otype = STM32_GPIO_OTYPE_PP, - .speed = STM32_GPIO_SPEED_100M, - .pupd = STM32_GPIO_PUPD_NO, - .af = STM32_GPIO_AF11 -}; - -static const struct stm32_gpio_dsc eth_gpio[] = { - {STM32_GPIO_PORT_A, STM32_GPIO_PIN_1}, /* ETH_RMII_REF_CLK */ - {STM32_GPIO_PORT_A, STM32_GPIO_PIN_2}, /* ETH_MDIO */ - {STM32_GPIO_PORT_A, STM32_GPIO_PIN_7}, /* ETH_RMII_CRS_DV */ - - {STM32_GPIO_PORT_C, STM32_GPIO_PIN_1}, /* ETH_MDC */ - {STM32_GPIO_PORT_C, STM32_GPIO_PIN_4}, /* ETH_RMII_RXD0 */ - {STM32_GPIO_PORT_C, STM32_GPIO_PIN_5}, /* ETH_RMII_RXD1 */ - - {STM32_GPIO_PORT_G, STM32_GPIO_PIN_11}, /* ETH_RMII_TX_EN */ - {STM32_GPIO_PORT_G, STM32_GPIO_PIN_13}, /* ETH_RMII_TXD0 */ - {STM32_GPIO_PORT_G, STM32_GPIO_PIN_14}, /* ETH_RMII_TXD1 */ -};
static int stmmac_setup(void) { - int res = 0; - int i; - clock_setup(SYSCFG_CLOCK_CFG); - /* Set >RMII mode */ STM32_SYSCFG->pmc |= SYSCFG_PMC_MII_RMII_SEL;
clock_setup(GPIO_A_CLOCK_CFG); clock_setup(GPIO_C_CLOCK_CFG); clock_setup(GPIO_G_CLOCK_CFG); - - for (i = 0; i < ARRAY_SIZE(eth_gpio); i++) { - res = stm32_gpio_config(ð_gpio[i], &gpio_ctl_eth); - if (res) - return res; - } - clock_setup(STMMAC_CLOCK_CFG);
return 0;

It also removes the qspi pin configuration done during the board initialization.
Signed-off-by: Vikas Manocha vikas.manocha@st.com --- arch/arm/dts/stm32f746-disco.dts | 1 + arch/arm/dts/stm32f746.dtsi | 11 ++++++++ board/st/stm32f746-disco/stm32f746-disco.c | 43 ------------------------------ 3 files changed, 12 insertions(+), 43 deletions(-)
diff --git a/arch/arm/dts/stm32f746-disco.dts b/arch/arm/dts/stm32f746-disco.dts index 3d6002f..07e0ca7 100644 --- a/arch/arm/dts/stm32f746-disco.dts +++ b/arch/arm/dts/stm32f746-disco.dts @@ -93,6 +93,7 @@ };
&qspi { + pinctrl-0 = <&qspi_pins>; status = "okay";
qflash0: n25q128a { diff --git a/arch/arm/dts/stm32f746.dtsi b/arch/arm/dts/stm32f746.dtsi index 431e79c..b2b0b5f 100644 --- a/arch/arm/dts/stm32f746.dtsi +++ b/arch/arm/dts/stm32f746.dtsi @@ -131,6 +131,17 @@ slew-rate = <2>; }; }; + qspi_pins: qspi@0{ + pins { + pinmux = <STM32F746_PB2_FUNC_QUADSPI_CLK>, + <STM32F746_PB6_FUNC_QUADSPI_BK1_NCS>, + <STM32F746_PD11_FUNC_QUADSPI_BK1_IO0>, + <STM32F746_PD12_FUNC_QUADSPI_BK1_IO1>, + <STM32F746_PD13_FUNC_QUADSPI_BK1_IO3>, + <STM32F746_PE2_FUNC_QUADSPI_BK1_IO2>; + slew-rate = <2>; + }; + }; }; }; }; diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 8343f82..fdad8d1 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -262,55 +262,12 @@ static int stmmac_setup(void) #endif
#ifdef CONFIG_STM32_QSPI -const struct stm32_gpio_ctl gpio_ctl_qspi_9 = { - .mode = STM32_GPIO_MODE_AF, - .otype = STM32_GPIO_OTYPE_PP, - .speed = STM32_GPIO_SPEED_100M, - .pupd = STM32_GPIO_PUPD_NO, - .af = STM32_GPIO_AF9 -}; - -const struct stm32_gpio_ctl gpio_ctl_qspi_10 = { - .mode = STM32_GPIO_MODE_AF, - .otype = STM32_GPIO_OTYPE_PP, - .speed = STM32_GPIO_SPEED_100M, - .pupd = STM32_GPIO_PUPD_NO, - .af = STM32_GPIO_AF10 -}; - -static const struct stm32_gpio_dsc qspi_af9_gpio[] = { - {STM32_GPIO_PORT_B, STM32_GPIO_PIN_2}, /* QUADSPI_CLK */ - {STM32_GPIO_PORT_D, STM32_GPIO_PIN_11}, /* QUADSPI_BK1_IO0 */ - {STM32_GPIO_PORT_D, STM32_GPIO_PIN_12}, /* QUADSPI_BK1_IO1 */ - {STM32_GPIO_PORT_D, STM32_GPIO_PIN_13}, /* QUADSPI_BK1_IO3 */ - {STM32_GPIO_PORT_E, STM32_GPIO_PIN_2}, /* QUADSPI_BK1_IO2 */ -}; - -static const struct stm32_gpio_dsc qspi_af10_gpio[] = { - {STM32_GPIO_PORT_B, STM32_GPIO_PIN_6}, /* QUADSPI_BK1_NCS */ -};
static int qspi_setup(void) { - int res = 0; - int i; - clock_setup(GPIO_B_CLOCK_CFG); clock_setup(GPIO_D_CLOCK_CFG); clock_setup(GPIO_E_CLOCK_CFG); - - for (i = 0; i < ARRAY_SIZE(qspi_af9_gpio); i++) { - res = stm32_gpio_config(&qspi_af9_gpio[i], &gpio_ctl_qspi_9); - if (res) - return res; - } - - for (i = 0; i < ARRAY_SIZE(qspi_af10_gpio); i++) { - res = stm32_gpio_config(&qspi_af10_gpio[i], &gpio_ctl_qspi_10); - if (res) - return res; - } - return 0; } #endif
participants (4)
-
Simon Glass
-
vikas
-
Vikas MANOCHA
-
Vikas Manocha