All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-12 21:55 ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This third round tries to address most of the comments made on previous series.

It contains few less patches, as the reset_controller_of_init() patch has been
removed, now that the bootlaoder handles the reset of the timers.

The pinctrl driver has also been removed after Linus review.
It will be reworked to use the generic pinconf bindings, and may contain
changes for other machines (Mediatek), to add support for pinmux property
handling directly in pinconf-generic.

STM32 MCUs are Cortex-M CPU, used in various applications (consumer
electronics, industrial applications, hobbyists...).
Datasheets, user and programming manuals are publicly available on
STMicroelectronics website.

With this series applied, the STM32F419 Discovery can boot succesfully.


Changes since v2:
-----------------
 - Remove pinctrl driver from the series. 
 - Remove reset_controller_of_init(), and reset the timers in the bootloader
 - Add HW flow contrl property for serial driver
 - Lots of changes in the DTS file, as per Andreas recommendations
 - Some Kconfig clean-ups
 - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
 - Various fixes in documentation

Changes since v1:
-----------------
 - Move bindings documentation in their own patches (Andreas)
 - Rename ARM System timer to armv7m-systick (Rob)
 - Add clock-frequency property handling in armv7m-systick (Rob)
 - Re-factor the reset controllers into a single controller (Philipp)
 - Add kerneldoc to reset_controller_of_init (Philipp)
 - Add named constants in include/dt-bindings/reset/ (Philipp)
 - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
 - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
supported by the MCU, in order to limit memory waste in vectors' table (Uwe)


Maxime Coquelin (15):
  scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
    Kernel
  ARM: ARMv7-M: Enlarge vector table up to 256 entries
  dt-bindings: Document the ARM System timer bindings
  clocksource: Add ARM System timer driver
  dt-bindings: Document the STM32 reset bindings
  drivers: reset: Add STM32 reset driver
  dt-bindings: Document the STM32 timer bindings
  clockevent: Add STM32 Timer driver
  dt-bindings: Document the STM32 USART bindings
  serial: stm32-usart: Add STM32 USART Driver
  ARM: Add STM32 family machine
  ARM: dts: Add ARM System timer as clockevent in armv7m
  ARM: dts: Introduce STM32F429 MCU
  ARM: configs: Add STM32 defconfig
  MAINTAINERS: Add entry for STM32 MCUs

 Documentation/arm/stm32/overview.txt               |  32 +
 Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
 .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
 .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
 .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
 MAINTAINERS                                        |   8 +
 arch/arm/Kconfig                                   |  18 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
 arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
 arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
 arch/arm/configs/stm32_defconfig                   |  71 +++
 arch/arm/kernel/entry-v7m.S                        |  13 +-
 arch/arm/mach-stm32/Makefile                       |   1 +
 arch/arm/mach-stm32/Makefile.boot                  |   3 +
 arch/arm/mach-stm32/board-dt.c                     |  19 +
 arch/arm/mm/Kconfig                                |  15 +
 drivers/clocksource/Kconfig                        |  15 +
 drivers/clocksource/Makefile                       |   2 +
 drivers/clocksource/armv7m_systick.c               |  78 +++
 drivers/clocksource/timer-stm32.c                  | 184 ++++++
 drivers/reset/Makefile                             |   1 +
 drivers/reset/reset-stm32.c                        | 125 ++++
 drivers/tty/serial/Kconfig                         |  17 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 scripts/link-vmlinux.sh                            |   2 +-
 30 files changed, 1807 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
 create mode 100644 arch/arm/configs/stm32_defconfig
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c
 create mode 100644 drivers/clocksource/armv7m_systick.c
 create mode 100644 drivers/clocksource/timer-stm32.c
 create mode 100644 drivers/reset/reset-stm32.c
 create mode 100644 drivers/tty/serial/stm32-usart.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-12 21:55 ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This third round tries to address most of the comments made on previous series.

It contains few less patches, as the reset_controller_of_init() patch has been
removed, now that the bootlaoder handles the reset of the timers.

The pinctrl driver has also been removed after Linus review.
It will be reworked to use the generic pinconf bindings, and may contain
changes for other machines (Mediatek), to add support for pinmux property
handling directly in pinconf-generic.

STM32 MCUs are Cortex-M CPU, used in various applications (consumer
electronics, industrial applications, hobbyists...).
Datasheets, user and programming manuals are publicly available on
STMicroelectronics website.

With this series applied, the STM32F419 Discovery can boot succesfully.


Changes since v2:
-----------------
 - Remove pinctrl driver from the series. 
 - Remove reset_controller_of_init(), and reset the timers in the bootloader
 - Add HW flow contrl property for serial driver
 - Lots of changes in the DTS file, as per Andreas recommendations
 - Some Kconfig clean-ups
 - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
 - Various fixes in documentation

Changes since v1:
-----------------
 - Move bindings documentation in their own patches (Andreas)
 - Rename ARM System timer to armv7m-systick (Rob)
 - Add clock-frequency property handling in armv7m-systick (Rob)
 - Re-factor the reset controllers into a single controller (Philipp)
 - Add kerneldoc to reset_controller_of_init (Philipp)
 - Add named constants in include/dt-bindings/reset/ (Philipp)
 - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
 - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
supported by the MCU, in order to limit memory waste in vectors' table (Uwe)


Maxime Coquelin (15):
  scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
    Kernel
  ARM: ARMv7-M: Enlarge vector table up to 256 entries
  dt-bindings: Document the ARM System timer bindings
  clocksource: Add ARM System timer driver
  dt-bindings: Document the STM32 reset bindings
  drivers: reset: Add STM32 reset driver
  dt-bindings: Document the STM32 timer bindings
  clockevent: Add STM32 Timer driver
  dt-bindings: Document the STM32 USART bindings
  serial: stm32-usart: Add STM32 USART Driver
  ARM: Add STM32 family machine
  ARM: dts: Add ARM System timer as clockevent in armv7m
  ARM: dts: Introduce STM32F429 MCU
  ARM: configs: Add STM32 defconfig
  MAINTAINERS: Add entry for STM32 MCUs

 Documentation/arm/stm32/overview.txt               |  32 +
 Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
 .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
 .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
 .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
 MAINTAINERS                                        |   8 +
 arch/arm/Kconfig                                   |  18 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
 arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
 arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
 arch/arm/configs/stm32_defconfig                   |  71 +++
 arch/arm/kernel/entry-v7m.S                        |  13 +-
 arch/arm/mach-stm32/Makefile                       |   1 +
 arch/arm/mach-stm32/Makefile.boot                  |   3 +
 arch/arm/mach-stm32/board-dt.c                     |  19 +
 arch/arm/mm/Kconfig                                |  15 +
 drivers/clocksource/Kconfig                        |  15 +
 drivers/clocksource/Makefile                       |   2 +
 drivers/clocksource/armv7m_systick.c               |  78 +++
 drivers/clocksource/timer-stm32.c                  | 184 ++++++
 drivers/reset/Makefile                             |   1 +
 drivers/reset/reset-stm32.c                        | 125 ++++
 drivers/tty/serial/Kconfig                         |  17 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 scripts/link-vmlinux.sh                            |   2 +-
 30 files changed, 1807 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
 create mode 100644 arch/arm/configs/stm32_defconfig
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c
 create mode 100644 drivers/clocksource/armv7m_systick.c
 create mode 100644 drivers/clocksource/timer-stm32.c
 create mode 100644 drivers/reset/reset-stm32.c
 create mode 100644 drivers/tty/serial/stm32-usart.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-12 21:55 ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This third round tries to address most of the comments made on previous series.

It contains few less patches, as the reset_controller_of_init() patch has been
removed, now that the bootlaoder handles the reset of the timers.

The pinctrl driver has also been removed after Linus review.
It will be reworked to use the generic pinconf bindings, and may contain
changes for other machines (Mediatek), to add support for pinmux property
handling directly in pinconf-generic.

STM32 MCUs are Cortex-M CPU, used in various applications (consumer
electronics, industrial applications, hobbyists...).
Datasheets, user and programming manuals are publicly available on
STMicroelectronics website.

With this series applied, the STM32F419 Discovery can boot succesfully.


Changes since v2:
-----------------
 - Remove pinctrl driver from the series. 
 - Remove reset_controller_of_init(), and reset the timers in the bootloader
 - Add HW flow contrl property for serial driver
 - Lots of changes in the DTS file, as per Andreas recommendations
 - Some Kconfig clean-ups
 - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
 - Various fixes in documentation

Changes since v1:
-----------------
 - Move bindings documentation in their own patches (Andreas)
 - Rename ARM System timer to armv7m-systick (Rob)
 - Add clock-frequency property handling in armv7m-systick (Rob)
 - Re-factor the reset controllers into a single controller (Philipp)
 - Add kerneldoc to reset_controller_of_init (Philipp)
 - Add named constants in include/dt-bindings/reset/ (Philipp)
 - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
 - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
supported by the MCU, in order to limit memory waste in vectors' table (Uwe)


Maxime Coquelin (15):
  scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
    Kernel
  ARM: ARMv7-M: Enlarge vector table up to 256 entries
  dt-bindings: Document the ARM System timer bindings
  clocksource: Add ARM System timer driver
  dt-bindings: Document the STM32 reset bindings
  drivers: reset: Add STM32 reset driver
  dt-bindings: Document the STM32 timer bindings
  clockevent: Add STM32 Timer driver
  dt-bindings: Document the STM32 USART bindings
  serial: stm32-usart: Add STM32 USART Driver
  ARM: Add STM32 family machine
  ARM: dts: Add ARM System timer as clockevent in armv7m
  ARM: dts: Introduce STM32F429 MCU
  ARM: configs: Add STM32 defconfig
  MAINTAINERS: Add entry for STM32 MCUs

 Documentation/arm/stm32/overview.txt               |  32 +
 Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
 .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
 .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
 .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
 MAINTAINERS                                        |   8 +
 arch/arm/Kconfig                                   |  18 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
 arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
 arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
 arch/arm/configs/stm32_defconfig                   |  71 +++
 arch/arm/kernel/entry-v7m.S                        |  13 +-
 arch/arm/mach-stm32/Makefile                       |   1 +
 arch/arm/mach-stm32/Makefile.boot                  |   3 +
 arch/arm/mach-stm32/board-dt.c                     |  19 +
 arch/arm/mm/Kconfig                                |  15 +
 drivers/clocksource/Kconfig                        |  15 +
 drivers/clocksource/Makefile                       |   2 +
 drivers/clocksource/armv7m_systick.c               |  78 +++
 drivers/clocksource/timer-stm32.c                  | 184 ++++++
 drivers/reset/Makefile                             |   1 +
 drivers/reset/reset-stm32.c                        | 125 ++++
 drivers/tty/serial/Kconfig                         |  17 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 scripts/link-vmlinux.sh                            |   2 +-
 30 files changed, 1807 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
 create mode 100644 arch/arm/configs/stm32_defconfig
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c
 create mode 100644 drivers/clocksource/armv7m_systick.c
 create mode 100644 drivers/clocksource/timer-stm32.c
 create mode 100644 drivers/reset/reset-stm32.c
 create mode 100644 drivers/tty/serial/stm32-usart.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  01/15] scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP Kernel
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55     ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TZNg+MwTxZMZA

From: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

When Kernel is executed in place from ROM, the symbol addresses can be
lower than the page offset.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 scripts/link-vmlinux.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 86a4fe7..b055d9d 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -82,7 +82,7 @@ kallsyms()
 		kallsymopt="${kallsymopt} --all-symbols"
 	fi
 
-	if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
+	if [ -n "${CONFIG_ARM}" ] && [ -z "${CONFIG_XIP_KERNEL}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  01/15] scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP Kernel
@ 2015-03-12 21:55     ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

When Kernel is executed in place from ROM, the symbol addresses can be
lower than the page offset.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 scripts/link-vmlinux.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 86a4fe7..b055d9d 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -82,7 +82,7 @@ kallsyms()
 		kallsymopt="${kallsymopt} --all-symbols"
 	fi
 
-	if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
+	if [ -n "${CONFIG_ARM}" ] && [ -z "${CONFIG_XIP_KERNEL}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 01/15] scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP Kernel
@ 2015-03-12 21:55     ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

When Kernel is executed in place from ROM, the symbol addresses can be
lower than the page offset.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 scripts/link-vmlinux.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 86a4fe7..b055d9d 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -82,7 +82,7 @@ kallsyms()
 		kallsymopt="${kallsymopt} --all-symbols"
 	fi
 
-	if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
+	if [ -n "${CONFIG_ARM}" ] && [ -z "${CONFIG_XIP_KERNEL}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 02/15] ARM: ARMv7-M: Enlarge vector table up to 256 entries
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Mark Rutland, linux-doc, Will Deacon, Nikolay Borisov, linux-api,
	Jiri Slaby, Mauro Carvalho Chehab, linux-arch, Russell King,
	Jonathan Corbet, Daniel Lezcano, Antti Palosaari, linux-serial,
	devicetree, Kees Cook, Pawel Moll, Ian Campbell, Rusty Russell,
	Joe Perches, Thomas Gleixner, linux-arm-kernel, Michal Marek,
	linux-gpio, Greg Kroah-Hartman, linux-kernel, mco

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

From Cortex-M reference manuals, the nvic supports up to 240 interrupts.
So the number of entries in vectors table is up to 256.

This patch adds a new config flag to specify the number of external interrupts.
Some ifdeferies are added in order to respect the natural alignment without
wasting too much space on smaller systems.

Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/kernel/entry-v7m.S | 13 +++++++++----
 arch/arm/mm/Kconfig         | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 8944f49..b6c8bb9 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
 ENDPROC(__switch_to)
 
 	.data
-	.align	8
+#if CONFIG_CPU_V7M_NUM_IRQ <= 112
+	.align	9
+#else
+	.align	10
+#endif
+
 /*
- * Vector table (64 words => 256 bytes natural alignment)
+ * Vector table (Natural alignment need to be ensured)
  */
 ENTRY(vector_table)
 	.long	0			@ 0 - Reset stack pointer
@@ -138,6 +143,6 @@ ENTRY(vector_table)
 	.long	__invalid_entry		@ 13 - Reserved
 	.long	__pendsv_entry		@ 14 - PendSV
 	.long	__invalid_entry		@ 15 - SysTick
-	.rept	64 - 16
-	.long	__irq_entry		@ 16..64 - External Interrupts
+	.rept	CONFIG_CPU_V7M_NUM_IRQ
+	.long	__irq_entry		@ External Interrupts
 	.endr
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9b4f29e..aec53b4 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -604,6 +604,21 @@ config CPU_USE_DOMAINS
 	  This option enables or disables the use of domain switching
 	  via the set_fs() function.
 
+config CPU_V7M_NUM_IRQ
+	int "Number of external interrupts connected to the NVIC"
+	depends on CPU_V7M
+	default 90 if ARCH_STM32
+	default 38 if ARCH_EFM32
+	default 240
+	help
+	  This option indicates the number of interrupts connected to the NVIC.
+	  The value can be larger than the real number of interrupts supported
+	  by the system, but must not be lower.
+	  The default value is 240, corresponding to the maximum number of
+	  interrupts supported by the NVIC on Cortex-M family.
+
+	  If unsure, keep default value.
+
 #
 # CPU supports 36-bit I/O
 #
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  02/15] ARM: ARMv7-M: Enlarge vector table up to 256 entries
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

>From Cortex-M reference manuals, the nvic supports up to 240 interrupts.
So the number of entries in vectors table is up to 256.

This patch adds a new config flag to specify the number of external interrupts.
Some ifdeferies are added in order to respect the natural alignment without
wasting too much space on smaller systems.

Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/kernel/entry-v7m.S | 13 +++++++++----
 arch/arm/mm/Kconfig         | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 8944f49..b6c8bb9 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
 ENDPROC(__switch_to)
 
 	.data
-	.align	8
+#if CONFIG_CPU_V7M_NUM_IRQ <= 112
+	.align	9
+#else
+	.align	10
+#endif
+
 /*
- * Vector table (64 words => 256 bytes natural alignment)
+ * Vector table (Natural alignment need to be ensured)
  */
 ENTRY(vector_table)
 	.long	0			@ 0 - Reset stack pointer
@@ -138,6 +143,6 @@ ENTRY(vector_table)
 	.long	__invalid_entry		@ 13 - Reserved
 	.long	__pendsv_entry		@ 14 - PendSV
 	.long	__invalid_entry		@ 15 - SysTick
-	.rept	64 - 16
-	.long	__irq_entry		@ 16..64 - External Interrupts
+	.rept	CONFIG_CPU_V7M_NUM_IRQ
+	.long	__irq_entry		@ External Interrupts
 	.endr
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9b4f29e..aec53b4 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -604,6 +604,21 @@ config CPU_USE_DOMAINS
 	  This option enables or disables the use of domain switching
 	  via the set_fs() function.
 
+config CPU_V7M_NUM_IRQ
+	int "Number of external interrupts connected to the NVIC"
+	depends on CPU_V7M
+	default 90 if ARCH_STM32
+	default 38 if ARCH_EFM32
+	default 240
+	help
+	  This option indicates the number of interrupts connected to the NVIC.
+	  The value can be larger than the real number of interrupts supported
+	  by the system, but must not be lower.
+	  The default value is 240, corresponding to the maximum number of
+	  interrupts supported by the NVIC on Cortex-M family.
+
+	  If unsure, keep default value.
+
 #
 # CPU supports 36-bit I/O
 #
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  02/15] ARM: ARMv7-M: Enlarge vector table up to 256 entries
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 02/15] ARM: ARMv7-M: Enlarge vector table up to 256 entries
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

>From Cortex-M reference manuals, the nvic supports up to 240 interrupts.
So the number of entries in vectors table is up to 256.

This patch adds a new config flag to specify the number of external interrupts.
Some ifdeferies are added in order to respect the natural alignment without
wasting too much space on smaller systems.

Acked-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Acked-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/kernel/entry-v7m.S | 13 +++++++++----
 arch/arm/mm/Kconfig         | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 8944f49..b6c8bb9 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
 ENDPROC(__switch_to)
 
 	.data
-	.align	8
+#if CONFIG_CPU_V7M_NUM_IRQ <= 112
+	.align	9
+#else
+	.align	10
+#endif
+
 /*
- * Vector table (64 words => 256 bytes natural alignment)
+ * Vector table (Natural alignment need to be ensured)
  */
 ENTRY(vector_table)
 	.long	0			@ 0 - Reset stack pointer
@@ -138,6 +143,6 @@ ENTRY(vector_table)
 	.long	__invalid_entry		@ 13 - Reserved
 	.long	__pendsv_entry		@ 14 - PendSV
 	.long	__invalid_entry		@ 15 - SysTick
-	.rept	64 - 16
-	.long	__irq_entry		@ 16..64 - External Interrupts
+	.rept	CONFIG_CPU_V7M_NUM_IRQ
+	.long	__irq_entry		@ External Interrupts
 	.endr
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9b4f29e..aec53b4 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -604,6 +604,21 @@ config CPU_USE_DOMAINS
 	  This option enables or disables the use of domain switching
 	  via the set_fs() function.
 
+config CPU_V7M_NUM_IRQ
+	int "Number of external interrupts connected to the NVIC"
+	depends on CPU_V7M
+	default 90 if ARCH_STM32
+	default 38 if ARCH_EFM32
+	default 240
+	help
+	  This option indicates the number of interrupts connected to the NVIC.
+	  The value can be larger than the real number of interrupts supported
+	  by the system, but must not be lower.
+	  The default value is 240, corresponding to the maximum number of
+	  interrupts supported by the NVIC on Cortex-M family.
+
+	  If unsure, keep default value.
+
 #
 # CPU supports 36-bit I/O
 #
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  03/15] dt-bindings: Document the ARM System timer bindings
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
ARM System timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/arm/armv7m_systick.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt

diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 0000000..7cf4a24
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
+* ARMv7M System Timer
+
+ARMv7-M includes a system timer, known as SysTick. Current driver only
+implements the clocksource feature.
+
+Required properties:
+- compatible	  : Should be "arm,armv7m-systick"
+- reg		  : The address range of the timer
+
+Required clocking property, have to be one of:
+- clocks	  : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM SysTick
+
+Examples:
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clocks = <&clk_systick>;
+};
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clock-frequency = <90000000>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  03/15] dt-bindings: Document the ARM System timer bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
ARM System timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/arm/armv7m_systick.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt

diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 0000000..7cf4a24
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
+* ARMv7M System Timer
+
+ARMv7-M includes a system timer, known as SysTick. Current driver only
+implements the clocksource feature.
+
+Required properties:
+- compatible	  : Should be "arm,armv7m-systick"
+- reg		  : The address range of the timer
+
+Required clocking property, have to be one of:
+- clocks	  : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM SysTick
+
+Examples:
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clocks = <&clk_systick>;
+};
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clock-frequency = <90000000>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 03/15] dt-bindings: Document the ARM System timer bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
ARM System timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/arm/armv7m_systick.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt

diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 0000000..7cf4a24
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
+* ARMv7M System Timer
+
+ARMv7-M includes a system timer, known as SysTick. Current driver only
+implements the clocksource feature.
+
+Required properties:
+- compatible	  : Should be "arm,armv7m-systick"
+- reg		  : The address range of the timer
+
+Required clocking property, have to be one of:
+- clocks	  : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM SysTick
+
+Examples:
+
+systick: timer at e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clocks = <&clk_systick>;
+};
+
+systick: timer at e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clock-frequency = <90000000>;
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  04/15] clocksource: Add ARM System timer driver
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds clocksource support for ARMv7-M's System timer,
also known as SysTick.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig          |  7 ++++
 drivers/clocksource/Makefile         |  1 +
 drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 drivers/clocksource/armv7m_systick.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 1c2506f..b82e58b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
 	help
 	 Use ARM global timer clock source as sched_clock
 
+config ARMV7M_SYSTICK
+	bool
+	select CLKSRC_OF if OF
+	select CLKSRC_MMIO
+	help
+	  This options enables support for the ARMv7M system timer unit
+
 config ATMEL_PIT
 	select CLKSRC_OF if OF
 	def_bool SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 752d5c7..1c9a643 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
+obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
 obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 0000000..23d8249
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define SYST_CSR	0x00
+#define SYST_RVR	0x04
+#define SYST_CVR	0x08
+#define SYST_CALIB	0x0c
+
+#define SYST_CSR_ENABLE BIT(0)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static void __init system_timer_of_register(struct device_node *np)
+{
+	struct clk *clk;
+	void __iomem *base;
+	u32 rate = 0;
+	int ret;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("system-timer: invalid base address\n");
+		return;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			goto out_unmap;
+		}
+
+		rate = clk_get_rate(clk);
+	}
+
+	/* If no clock found, try to get clock-frequency property */
+	if (!rate) {
+		ret = of_property_read_u32(np, "clock-frequency", &rate);
+		if (ret)
+			goto out_unmap;
+	}
+
+	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
+	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
+
+	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
+			200, 24, clocksource_mmio_readl_down);
+	if (ret) {
+		pr_err("failed to init clocksource (%d)\n", ret);
+		goto out_clk_disable;
+	}
+
+	pr_info("ARM System timer initialized as clocksource\n");
+
+	return;
+
+out_clk_disable:
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+out_unmap:
+	iounmap(base);
+	WARN(ret, "ARM System timer register failed (%d)\n", ret);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
+			system_timer_of_register);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  04/15] clocksource: Add ARM System timer driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds clocksource support for ARMv7-M's System timer,
also known as SysTick.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig          |  7 ++++
 drivers/clocksource/Makefile         |  1 +
 drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 drivers/clocksource/armv7m_systick.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 1c2506f..b82e58b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
 	help
 	 Use ARM global timer clock source as sched_clock
 
+config ARMV7M_SYSTICK
+	bool
+	select CLKSRC_OF if OF
+	select CLKSRC_MMIO
+	help
+	  This options enables support for the ARMv7M system timer unit
+
 config ATMEL_PIT
 	select CLKSRC_OF if OF
 	def_bool SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 752d5c7..1c9a643 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
+obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
 obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 0000000..23d8249
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define SYST_CSR	0x00
+#define SYST_RVR	0x04
+#define SYST_CVR	0x08
+#define SYST_CALIB	0x0c
+
+#define SYST_CSR_ENABLE BIT(0)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static void __init system_timer_of_register(struct device_node *np)
+{
+	struct clk *clk;
+	void __iomem *base;
+	u32 rate = 0;
+	int ret;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("system-timer: invalid base address\n");
+		return;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			goto out_unmap;
+		}
+
+		rate = clk_get_rate(clk);
+	}
+
+	/* If no clock found, try to get clock-frequency property */
+	if (!rate) {
+		ret = of_property_read_u32(np, "clock-frequency", &rate);
+		if (ret)
+			goto out_unmap;
+	}
+
+	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
+	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
+
+	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
+			200, 24, clocksource_mmio_readl_down);
+	if (ret) {
+		pr_err("failed to init clocksource (%d)\n", ret);
+		goto out_clk_disable;
+	}
+
+	pr_info("ARM System timer initialized as clocksource\n");
+
+	return;
+
+out_clk_disable:
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+out_unmap:
+	iounmap(base);
+	WARN(ret, "ARM System timer register failed (%d)\n", ret);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
+			system_timer_of_register);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  04/15] clocksource: Add ARM System timer driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds clocksource support for ARMv7-M's System timer,
also known as SysTick.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig          |  7 ++++
 drivers/clocksource/Makefile         |  1 +
 drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 drivers/clocksource/armv7m_systick.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 1c2506f..b82e58b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
 	help
 	 Use ARM global timer clock source as sched_clock
 
+config ARMV7M_SYSTICK
+	bool
+	select CLKSRC_OF if OF
+	select CLKSRC_MMIO
+	help
+	  This options enables support for the ARMv7M system timer unit
+
 config ATMEL_PIT
 	select CLKSRC_OF if OF
 	def_bool SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 752d5c7..1c9a643 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
+obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
 obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 0000000..23d8249
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define SYST_CSR	0x00
+#define SYST_RVR	0x04
+#define SYST_CVR	0x08
+#define SYST_CALIB	0x0c
+
+#define SYST_CSR_ENABLE BIT(0)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static void __init system_timer_of_register(struct device_node *np)
+{
+	struct clk *clk;
+	void __iomem *base;
+	u32 rate = 0;
+	int ret;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("system-timer: invalid base address\n");
+		return;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			goto out_unmap;
+		}
+
+		rate = clk_get_rate(clk);
+	}
+
+	/* If no clock found, try to get clock-frequency property */
+	if (!rate) {
+		ret = of_property_read_u32(np, "clock-frequency", &rate);
+		if (ret)
+			goto out_unmap;
+	}
+
+	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
+	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
+
+	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
+			200, 24, clocksource_mmio_readl_down);
+	if (ret) {
+		pr_err("failed to init clocksource (%d)\n", ret);
+		goto out_clk_disable;
+	}
+
+	pr_info("ARM System timer initialized as clocksource\n");
+
+	return;
+
+out_clk_disable:
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+out_unmap:
+	iounmap(base);
+	WARN(ret, "ARM System timer register failed (%d)\n", ret);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
+			system_timer_of_register);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 reset controller.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt

diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
new file mode 100644
index 0000000..962f961
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -0,0 +1,102 @@
+STMicroelectronics STM32 Peripheral Reset Controller
+====================================================
+
+The RCC IP is both a reset and a clock controller. This documentation only
+document the reset part.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stm32-rcc"
+- reg: should be register base and length as documented in the
+  datasheet
+- #reset-cells: 1, see below
+
+example:
+
+rcc: reset@40023800 {
+	#reset-cells = <1>;
+	compatible = "st,stm32-rcc";
+	reg = <0x40023800 0x400>;
+};
+
+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.
+
+example:
+
+	timer2 {
+		resets			= <&rcc 256>;
+	};
+
+List of indexes for STM32F429:
+ - gpioa: 128
+ - gpiob: 129
+ - gpioc: 130
+ - gpiod: 131
+ - gpioe: 132
+ - gpiof: 133
+ - gpiog: 134
+ - gpioh: 135
+ - gpioi: 136
+ - gpioj: 137
+ - gpiok: 138
+ - crc: 140
+ - dma1: 149
+ - dma2: 150
+ - dma2d: 151
+ - ethmac: 153
+ - otghs: 157
+ - dcmi: 160
+ - cryp: 164
+ - hash: 165
+ - rng: 166
+ - otgfs: 167
+ - fmc: 192
+ - tim2: 256
+ - tim3: 257
+ - tim4: 258
+ - tim5: 259
+ - tim6: 260
+ - tim7: 261
+ - tim12: 262
+ - tim13: 263
+ - tim14: 264
+ - wwdg: 267
+ - spi2: 270
+ - spi3: 271
+ - uart2: 273
+ - uart3: 274
+ - uart4: 275
+ - uart5: 276
+ - i2c1: 277
+ - i2c2: 278
+ - i2c3: 279
+ - can1: 281
+ - can2: 282
+ - pwr: 284
+ - dac: 285
+ - uart7: 286
+ - uart8: 287
+ - tim1: 288
+ - tim8: 289
+ - usart1: 292
+ - usart6: 293
+ - adc: 296
+ - sdio: 299
+ - spi1: 300
+ - spi4: 301
+ - syscfg: 302
+ - tim9: 304
+ - tim10: 305
+ - tim11: 306
+ - spi5: 308
+ - spi6: 309
+ - sai1: 310
+ - ltdc: 31
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 reset controller.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt

diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
new file mode 100644
index 0000000..962f961
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -0,0 +1,102 @@
+STMicroelectronics STM32 Peripheral Reset Controller
+====================================================
+
+The RCC IP is both a reset and a clock controller. This documentation only
+document the reset part.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stm32-rcc"
+- reg: should be register base and length as documented in the
+  datasheet
+- #reset-cells: 1, see below
+
+example:
+
+rcc: reset@40023800 {
+	#reset-cells = <1>;
+	compatible = "st,stm32-rcc";
+	reg = <0x40023800 0x400>;
+};
+
+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.
+
+example:
+
+	timer2 {
+		resets			= <&rcc 256>;
+	};
+
+List of indexes for STM32F429:
+ - gpioa: 128
+ - gpiob: 129
+ - gpioc: 130
+ - gpiod: 131
+ - gpioe: 132
+ - gpiof: 133
+ - gpiog: 134
+ - gpioh: 135
+ - gpioi: 136
+ - gpioj: 137
+ - gpiok: 138
+ - crc: 140
+ - dma1: 149
+ - dma2: 150
+ - dma2d: 151
+ - ethmac: 153
+ - otghs: 157
+ - dcmi: 160
+ - cryp: 164
+ - hash: 165
+ - rng: 166
+ - otgfs: 167
+ - fmc: 192
+ - tim2: 256
+ - tim3: 257
+ - tim4: 258
+ - tim5: 259
+ - tim6: 260
+ - tim7: 261
+ - tim12: 262
+ - tim13: 263
+ - tim14: 264
+ - wwdg: 267
+ - spi2: 270
+ - spi3: 271
+ - uart2: 273
+ - uart3: 274
+ - uart4: 275
+ - uart5: 276
+ - i2c1: 277
+ - i2c2: 278
+ - i2c3: 279
+ - can1: 281
+ - can2: 282
+ - pwr: 284
+ - dac: 285
+ - uart7: 286
+ - uart8: 287
+ - tim1: 288
+ - tim8: 289
+ - usart1: 292
+ - usart6: 293
+ - adc: 296
+ - sdio: 299
+ - spi1: 300
+ - spi4: 301
+ - syscfg: 302
+ - tim9: 304
+ - tim10: 305
+ - tim11: 306
+ - spi5: 308
+ - spi6: 309
+ - sai1: 310
+ - ltdc: 31
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 reset controller.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt

diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
new file mode 100644
index 0000000..962f961
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -0,0 +1,102 @@
+STMicroelectronics STM32 Peripheral Reset Controller
+====================================================
+
+The RCC IP is both a reset and a clock controller. This documentation only
+document the reset part.
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stm32-rcc"
+- reg: should be register base and length as documented in the
+  datasheet
+- #reset-cells: 1, see below
+
+example:
+
+rcc: reset at 40023800 {
+	#reset-cells = <1>;
+	compatible = "st,stm32-rcc";
+	reg = <0x40023800 0x400>;
+};
+
+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.
+
+example:
+
+	timer2 {
+		resets			= <&rcc 256>;
+	};
+
+List of indexes for STM32F429:
+ - gpioa: 128
+ - gpiob: 129
+ - gpioc: 130
+ - gpiod: 131
+ - gpioe: 132
+ - gpiof: 133
+ - gpiog: 134
+ - gpioh: 135
+ - gpioi: 136
+ - gpioj: 137
+ - gpiok: 138
+ - crc: 140
+ - dma1: 149
+ - dma2: 150
+ - dma2d: 151
+ - ethmac: 153
+ - otghs: 157
+ - dcmi: 160
+ - cryp: 164
+ - hash: 165
+ - rng: 166
+ - otgfs: 167
+ - fmc: 192
+ - tim2: 256
+ - tim3: 257
+ - tim4: 258
+ - tim5: 259
+ - tim6: 260
+ - tim7: 261
+ - tim12: 262
+ - tim13: 263
+ - tim14: 264
+ - wwdg: 267
+ - spi2: 270
+ - spi3: 271
+ - uart2: 273
+ - uart3: 274
+ - uart4: 275
+ - uart5: 276
+ - i2c1: 277
+ - i2c2: 278
+ - i2c3: 279
+ - can1: 281
+ - can2: 282
+ - pwr: 284
+ - dac: 285
+ - uart7: 286
+ - uart8: 287
+ - tim1: 288
+ - tim8: 289
+ - usart1: 292
+ - usart6: 293
+ - adc: 296
+ - sdio: 299
+ - spi1: 300
+ - spi4: 301
+ - syscfg: 302
+ - tim9: 304
+ - tim10: 305
+ - tim11: 306
+ - spi5: 308
+ - spi6: 309
+ - sai1: 310
+ - ltdc: 31
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STM32 MCUs family IP can be reset by accessing some shared registers.

The specificity is that some reset lines are used by the timers.
At timer initialization time, the timer has to be reset, that's why
we cannot use a regular driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/reset/Makefile      |   1 +
 drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 drivers/reset/reset-stm32.c

diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..0d389b1
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+	.assert		= stm32_reset_assert,
+	.deassert	= stm32_reset_deassert,
+};
+
+static const struct of_device_id stm32_reset_dt_ids[] = {
+	 { .compatible = "st,stm32-rcc", },
+	 { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
+
+static int stm32_reset_probe(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data;
+	struct resource *res;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->membase))
+		return PTR_ERR(data->membase);
+
+	spin_lock_init(&data->lock);
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = resource_size(res) * 8;
+	data->rcdev.ops = &stm32_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	return reset_controller_register(&data->rcdev);
+}
+
+static int stm32_reset_remove(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data = platform_get_drvdata(pdev);
+
+	reset_controller_unregister(&data->rcdev);
+
+	return 0;
+}
+
+static struct platform_driver stm32_reset_driver = {
+	.probe	= stm32_reset_probe,
+	.remove	= stm32_reset_remove,
+	.driver = {
+		.name		= "stm32-rcc-reset",
+		.of_match_table	= stm32_reset_dt_ids,
+	},
+};
+module_platform_driver(stm32_reset_driver);
+
+MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
+MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
+MODULE_LICENSE("GPL");
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STM32 MCUs family IP can be reset by accessing some shared registers.

The specificity is that some reset lines are used by the timers.
At timer initialization time, the timer has to be reset, that's why
we cannot use a regular driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/reset/Makefile      |   1 +
 drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 drivers/reset/reset-stm32.c

diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..0d389b1
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+	.assert		= stm32_reset_assert,
+	.deassert	= stm32_reset_deassert,
+};
+
+static const struct of_device_id stm32_reset_dt_ids[] = {
+	 { .compatible = "st,stm32-rcc", },
+	 { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
+
+static int stm32_reset_probe(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data;
+	struct resource *res;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->membase))
+		return PTR_ERR(data->membase);
+
+	spin_lock_init(&data->lock);
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = resource_size(res) * 8;
+	data->rcdev.ops = &stm32_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	return reset_controller_register(&data->rcdev);
+}
+
+static int stm32_reset_remove(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data = platform_get_drvdata(pdev);
+
+	reset_controller_unregister(&data->rcdev);
+
+	return 0;
+}
+
+static struct platform_driver stm32_reset_driver = {
+	.probe	= stm32_reset_probe,
+	.remove	= stm32_reset_remove,
+	.driver = {
+		.name		= "stm32-rcc-reset",
+		.of_match_table	= stm32_reset_dt_ids,
+	},
+};
+module_platform_driver(stm32_reset_driver);
+
+MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
+MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
+MODULE_LICENSE("GPL");
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STM32 MCUs family IP can be reset by accessing some shared registers.

The specificity is that some reset lines are used by the timers.
At timer initialization time, the timer has to be reset, that's why
we cannot use a regular driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/reset/Makefile      |   1 +
 drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 drivers/reset/reset-stm32.c

diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..0d389b1
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+	.assert		= stm32_reset_assert,
+	.deassert	= stm32_reset_deassert,
+};
+
+static const struct of_device_id stm32_reset_dt_ids[] = {
+	 { .compatible = "st,stm32-rcc", },
+	 { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
+
+static int stm32_reset_probe(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data;
+	struct resource *res;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->membase))
+		return PTR_ERR(data->membase);
+
+	spin_lock_init(&data->lock);
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = resource_size(res) * 8;
+	data->rcdev.ops = &stm32_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	return reset_controller_register(&data->rcdev);
+}
+
+static int stm32_reset_remove(struct platform_device *pdev)
+{
+	struct stm32_reset_data *data = platform_get_drvdata(pdev);
+
+	reset_controller_unregister(&data->rcdev);
+
+	return 0;
+}
+
+static struct platform_driver stm32_reset_driver = {
+	.probe	= stm32_reset_probe,
+	.remove	= stm32_reset_remove,
+	.driver = {
+		.name		= "stm32-rcc-reset",
+		.of_match_table	= stm32_reset_dt_ids,
+	},
+};
+module_platform_driver(stm32_reset_driver);
+
+MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
+MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
+MODULE_LICENSE("GPL");
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  07/15] dt-bindings: Document the STM32 timer bindings
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Mark Rutland, linux-doc, Will Deacon, Nikolay Borisov, linux-api,
	Jiri Slaby, Mauro Carvalho Chehab, linux-arch, Russell King,
	Jonathan Corbet, Daniel Lezcano, Antti Palosaari, linux-serial,
	devicetree, Kees Cook, Pawel Moll, Ian Campbell, Rusty Russell,
	Joe Perches, Thomas Gleixner, linux-arm-kernel, Michal Marek,
	linux-gpio, Greg Kroah-Hartman, linux-kernel, mco

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/timer/st,stm32-timer.txt   | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 0000000..d3fdeb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,22 @@
+. STMicroelectronics STM32 timer
+
+The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
+
+Required properties:
+- compatible : Should be st,stm32-timer"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Optional properties:
+- resets: Reference to a reset controller asserting the timer
+
+Example:
+
+timer5: timer@40000c00 {
+	compatible = "st,stm32-timer";
+	reg = <0x40000c00 0x400>;
+	interrupts = <50>;
+	resets = <&rrc 259>;
+	clocks = <&clk_pmtr1>;
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  07/15] dt-bindings: Document the STM32 timer bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/timer/st,stm32-timer.txt   | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 0000000..d3fdeb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,22 @@
+. STMicroelectronics STM32 timer
+
+The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
+
+Required properties:
+- compatible : Should be st,stm32-timer"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Optional properties:
+- resets: Reference to a reset controller asserting the timer
+
+Example:
+
+timer5: timer@40000c00 {
+	compatible = "st,stm32-timer";
+	reg = <0x40000c00 0x400>;
+	interrupts = <50>;
+	resets = <&rrc 259>;
+	clocks = <&clk_pmtr1>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  07/15] dt-bindings: Document the STM32 timer bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/timer/st,stm32-timer.txt   | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 0000000..d3fdeb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,22 @@
+. STMicroelectronics STM32 timer
+
+The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
+
+Required properties:
+- compatible : Should be st,stm32-timer"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Optional properties:
+- resets: Reference to a reset controller asserting the timer
+
+Example:
+
+timer5: timer at 40000c00 {
+	compatible = "st,stm32-timer";
+	reg = <0x40000c00 0x400>;
+	interrupts = <50>;
+	resets = <&rrc 259>;
+	clocks = <&clk_pmtr1>;
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  08/15] clockevent: Add STM32 Timer driver
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
The drivers detects whether the time is 16 or 32 bits, and applies a
1024 prescaler value if it is 16 bits.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig       |   8 ++
 drivers/clocksource/Makefile      |   1 +
 drivers/clocksource/timer-stm32.c | 184 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b82e58b..519304b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -101,6 +101,14 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_STM32
+	bool "Clocksource for STM32 SoCs" if !ARCH_STM32
+	depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
+	select CLKSRC_MMIO
+	default ARCH_STM32
+	help
+	  Support to use the timers of STM32 SoCs as clock event device.
+
 config ARM_ARCH_TIMER
 	bool
 	select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 1c9a643..525dafe 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_NSPIRE)	+= zevio-timer.o
 obj-$(CONFIG_ARCH_BCM_MOBILE)	+= bcm_kona_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= cadence_ttc_timer.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= time-efm32.o
+obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.o
 obj-$(CONFIG_FSL_FTM_TIMER)	+= fsl_ftm_timer.o
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 0000000..fad2e2e
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by time-efm32.c from Uwe Kleine-Koenig
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00
+#define TIM_DIER	0x0c
+#define TIM_SR		0x10
+#define TIM_EGR		0x14
+#define TIM_PSC		0x28
+#define TIM_ARR		0x2c
+
+#define TIM_CR1_CEN	BIT(0)
+#define TIM_CR1_OPM	BIT(3)
+#define TIM_CR1_ARPE	BIT(7)
+
+#define TIM_DIER_UIE	BIT(0)
+
+#define TIM_SR_UIF	BIT(0)
+
+#define TIM_EGR_UG	BIT(0)
+
+struct stm32_clock_event_ddata {
+	struct clock_event_device evtdev;
+	unsigned periodic_top;
+	void __iomem *base;
+};
+
+static void stm32_clock_event_set_mode(enum clock_event_mode mode,
+				       struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+	void *base = data->base;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel_relaxed(data->periodic_top, base + TIM_ARR);
+		writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+	default:
+		writel_relaxed(0, base + TIM_CR1);
+		break;
+	}
+}
+
+static int stm32_clock_event_set_next_event(unsigned long evt,
+					    struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+
+	writel_relaxed(evt, data->base + TIM_ARR);
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
+		       data->base + TIM_CR1);
+
+	return 0;
+}
+
+static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
+{
+	struct stm32_clock_event_ddata *data = dev_id;
+
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->evtdev.event_handler(&data->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static struct stm32_clock_event_ddata clock_event_ddata = {
+	.evtdev = {
+		.name = "stm32 clockevent",
+		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+		.set_mode = stm32_clock_event_set_mode,
+		.set_next_event = stm32_clock_event_set_next_event,
+		.rating = 200,
+	},
+};
+
+static void __init stm32_clockevent_init(struct device_node *np)
+{
+	struct stm32_clock_event_ddata *data = &clock_event_ddata;
+	struct clk *clk;
+	struct reset_control *rstc;
+	unsigned long rate, max_delta;
+	int irq, ret, bits, prescaler = 1;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		pr_err("failed to get clock for clockevent (%d)\n", ret);
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		pr_err("failed to enable timer clock for clockevent (%d)\n",
+		       ret);
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+
+	rstc = of_reset_control_get(np, NULL);
+	if (!IS_ERR(rstc)) {
+		reset_control_assert(rstc);
+		reset_control_deassert(rstc);
+	}
+
+	data->base = of_iomap(np, 0);
+	if (!data->base) {
+		pr_err("failed to map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		pr_err("%s: failed to get irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	/* Detect whether the timer is 16 or 32 bits */
+	writel_relaxed(~0UL, data->base + TIM_ARR);
+	max_delta = readl_relaxed(data->base + TIM_ARR);
+	if (max_delta == ~0UL) {
+		prescaler = 1;
+		bits = 32;
+	} else {
+		prescaler = 1024;
+		bits = 16;
+	}
+	writel_relaxed(0, data->base + TIM_ARR);
+
+	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+	clockevents_config_and_register(&data->evtdev,
+					DIV_ROUND_CLOSEST(rate, prescaler),
+					0x1, max_delta);
+
+	ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
+			"stm32 clockevent", data);
+	if (ret) {
+		pr_err("%s: failed to request irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
+			np->full_name, bits);
+
+	return;
+
+err_get_irq:
+	iounmap(data->base);
+err_iomap:
+	clk_disable_unprepare(clk);
+err_clk_enable:
+	clk_put(clk);
+err_clk_get:
+	return;
+}
+
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  08/15] clockevent: Add STM32 Timer driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
The drivers detects whether the time is 16 or 32 bits, and applies a
1024 prescaler value if it is 16 bits.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig       |   8 ++
 drivers/clocksource/Makefile      |   1 +
 drivers/clocksource/timer-stm32.c | 184 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b82e58b..519304b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -101,6 +101,14 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_STM32
+	bool "Clocksource for STM32 SoCs" if !ARCH_STM32
+	depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
+	select CLKSRC_MMIO
+	default ARCH_STM32
+	help
+	  Support to use the timers of STM32 SoCs as clock event device.
+
 config ARM_ARCH_TIMER
 	bool
 	select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 1c9a643..525dafe 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_NSPIRE)	+= zevio-timer.o
 obj-$(CONFIG_ARCH_BCM_MOBILE)	+= bcm_kona_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= cadence_ttc_timer.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= time-efm32.o
+obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.o
 obj-$(CONFIG_FSL_FTM_TIMER)	+= fsl_ftm_timer.o
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 0000000..fad2e2e
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by time-efm32.c from Uwe Kleine-Koenig
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00
+#define TIM_DIER	0x0c
+#define TIM_SR		0x10
+#define TIM_EGR		0x14
+#define TIM_PSC		0x28
+#define TIM_ARR		0x2c
+
+#define TIM_CR1_CEN	BIT(0)
+#define TIM_CR1_OPM	BIT(3)
+#define TIM_CR1_ARPE	BIT(7)
+
+#define TIM_DIER_UIE	BIT(0)
+
+#define TIM_SR_UIF	BIT(0)
+
+#define TIM_EGR_UG	BIT(0)
+
+struct stm32_clock_event_ddata {
+	struct clock_event_device evtdev;
+	unsigned periodic_top;
+	void __iomem *base;
+};
+
+static void stm32_clock_event_set_mode(enum clock_event_mode mode,
+				       struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+	void *base = data->base;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel_relaxed(data->periodic_top, base + TIM_ARR);
+		writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+	default:
+		writel_relaxed(0, base + TIM_CR1);
+		break;
+	}
+}
+
+static int stm32_clock_event_set_next_event(unsigned long evt,
+					    struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+
+	writel_relaxed(evt, data->base + TIM_ARR);
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
+		       data->base + TIM_CR1);
+
+	return 0;
+}
+
+static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
+{
+	struct stm32_clock_event_ddata *data = dev_id;
+
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->evtdev.event_handler(&data->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static struct stm32_clock_event_ddata clock_event_ddata = {
+	.evtdev = {
+		.name = "stm32 clockevent",
+		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+		.set_mode = stm32_clock_event_set_mode,
+		.set_next_event = stm32_clock_event_set_next_event,
+		.rating = 200,
+	},
+};
+
+static void __init stm32_clockevent_init(struct device_node *np)
+{
+	struct stm32_clock_event_ddata *data = &clock_event_ddata;
+	struct clk *clk;
+	struct reset_control *rstc;
+	unsigned long rate, max_delta;
+	int irq, ret, bits, prescaler = 1;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		pr_err("failed to get clock for clockevent (%d)\n", ret);
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		pr_err("failed to enable timer clock for clockevent (%d)\n",
+		       ret);
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+
+	rstc = of_reset_control_get(np, NULL);
+	if (!IS_ERR(rstc)) {
+		reset_control_assert(rstc);
+		reset_control_deassert(rstc);
+	}
+
+	data->base = of_iomap(np, 0);
+	if (!data->base) {
+		pr_err("failed to map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		pr_err("%s: failed to get irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	/* Detect whether the timer is 16 or 32 bits */
+	writel_relaxed(~0UL, data->base + TIM_ARR);
+	max_delta = readl_relaxed(data->base + TIM_ARR);
+	if (max_delta == ~0UL) {
+		prescaler = 1;
+		bits = 32;
+	} else {
+		prescaler = 1024;
+		bits = 16;
+	}
+	writel_relaxed(0, data->base + TIM_ARR);
+
+	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+	clockevents_config_and_register(&data->evtdev,
+					DIV_ROUND_CLOSEST(rate, prescaler),
+					0x1, max_delta);
+
+	ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
+			"stm32 clockevent", data);
+	if (ret) {
+		pr_err("%s: failed to request irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
+			np->full_name, bits);
+
+	return;
+
+err_get_irq:
+	iounmap(data->base);
+err_iomap:
+	clk_disable_unprepare(clk);
+err_clk_enable:
+	clk_put(clk);
+err_clk_get:
+	return;
+}
+
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  08/15] clockevent: Add STM32 Timer driver
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
The drivers detects whether the time is 16 or 32 bits, and applies a
1024 prescaler value if it is 16 bits.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/clocksource/Kconfig       |   8 ++
 drivers/clocksource/Makefile      |   1 +
 drivers/clocksource/timer-stm32.c | 184 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b82e58b..519304b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -101,6 +101,14 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_STM32
+	bool "Clocksource for STM32 SoCs" if !ARCH_STM32
+	depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
+	select CLKSRC_MMIO
+	default ARCH_STM32
+	help
+	  Support to use the timers of STM32 SoCs as clock event device.
+
 config ARM_ARCH_TIMER
 	bool
 	select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 1c9a643..525dafe 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_NSPIRE)	+= zevio-timer.o
 obj-$(CONFIG_ARCH_BCM_MOBILE)	+= bcm_kona_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= cadence_ttc_timer.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= time-efm32.o
+obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.o
 obj-$(CONFIG_FSL_FTM_TIMER)	+= fsl_ftm_timer.o
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 0000000..fad2e2e
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by time-efm32.c from Uwe Kleine-Koenig
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00
+#define TIM_DIER	0x0c
+#define TIM_SR		0x10
+#define TIM_EGR		0x14
+#define TIM_PSC		0x28
+#define TIM_ARR		0x2c
+
+#define TIM_CR1_CEN	BIT(0)
+#define TIM_CR1_OPM	BIT(3)
+#define TIM_CR1_ARPE	BIT(7)
+
+#define TIM_DIER_UIE	BIT(0)
+
+#define TIM_SR_UIF	BIT(0)
+
+#define TIM_EGR_UG	BIT(0)
+
+struct stm32_clock_event_ddata {
+	struct clock_event_device evtdev;
+	unsigned periodic_top;
+	void __iomem *base;
+};
+
+static void stm32_clock_event_set_mode(enum clock_event_mode mode,
+				       struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+	void *base = data->base;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel_relaxed(data->periodic_top, base + TIM_ARR);
+		writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+	default:
+		writel_relaxed(0, base + TIM_CR1);
+		break;
+	}
+}
+
+static int stm32_clock_event_set_next_event(unsigned long evt,
+					    struct clock_event_device *evtdev)
+{
+	struct stm32_clock_event_ddata *data =
+		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+
+	writel_relaxed(evt, data->base + TIM_ARR);
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
+		       data->base + TIM_CR1);
+
+	return 0;
+}
+
+static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
+{
+	struct stm32_clock_event_ddata *data = dev_id;
+
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->evtdev.event_handler(&data->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static struct stm32_clock_event_ddata clock_event_ddata = {
+	.evtdev = {
+		.name = "stm32 clockevent",
+		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+		.set_mode = stm32_clock_event_set_mode,
+		.set_next_event = stm32_clock_event_set_next_event,
+		.rating = 200,
+	},
+};
+
+static void __init stm32_clockevent_init(struct device_node *np)
+{
+	struct stm32_clock_event_ddata *data = &clock_event_ddata;
+	struct clk *clk;
+	struct reset_control *rstc;
+	unsigned long rate, max_delta;
+	int irq, ret, bits, prescaler = 1;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		pr_err("failed to get clock for clockevent (%d)\n", ret);
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		pr_err("failed to enable timer clock for clockevent (%d)\n",
+		       ret);
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+
+	rstc = of_reset_control_get(np, NULL);
+	if (!IS_ERR(rstc)) {
+		reset_control_assert(rstc);
+		reset_control_deassert(rstc);
+	}
+
+	data->base = of_iomap(np, 0);
+	if (!data->base) {
+		pr_err("failed to map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		pr_err("%s: failed to get irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	/* Detect whether the timer is 16 or 32 bits */
+	writel_relaxed(~0UL, data->base + TIM_ARR);
+	max_delta = readl_relaxed(data->base + TIM_ARR);
+	if (max_delta == ~0UL) {
+		prescaler = 1;
+		bits = 32;
+	} else {
+		prescaler = 1024;
+		bits = 16;
+	}
+	writel_relaxed(0, data->base + TIM_ARR);
+
+	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+	writel_relaxed(0, data->base + TIM_SR);
+
+	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+	clockevents_config_and_register(&data->evtdev,
+					DIV_ROUND_CLOSEST(rate, prescaler),
+					0x1, max_delta);
+
+	ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
+			"stm32 clockevent", data);
+	if (ret) {
+		pr_err("%s: failed to request irq.\n", np->full_name);
+		goto err_get_irq;
+	}
+
+	pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
+			np->full_name, bits);
+
+	return;
+
+err_get_irq:
+	iounmap(data->base);
+err_iomap:
+	clk_disable_unprepare(clk);
+err_clk_enable:
+	clk_put(clk);
+err_clk_get:
+	return;
+}
+
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  09/15] dt-bindings: Document the STM32 USART bindings
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 USART

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/serial/st,stm32-usart.txt  | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
new file mode 100644
index 0000000..090a3a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -0,0 +1,32 @@
+* STMicroelectronics STM32 USART
+
+Required properties:
+- compatible: Can be either "st,stm32-usart" or "st,stm32-uart" depending on
+whether the device supports synchronous mode.
+- reg: The address and length of the peripheral registers space
+- interrupts: The interrupt line of the USART instance
+- clocks: The input clock of the USART instance
+
+Optional properties:
+- pinctrl: The reference on the pins configuration
+- st,hw-flow-ctrl: bool flag to enable hardware flow control.
+
+Examples:
+usart4: serial@40004c00 {
+	compatible = "st,stm32-uart";
+	reg = <0x40004c00 0x400>;
+	interrupts = <52>;
+	clocks = <&clk_pclk1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart4>;
+};
+
+usart2: serial@40004400 {
+	compatible = "st,stm32-usart", "st,stm32-uart";
+	reg = <0x40004400 0x400>;
+	interrupts = <38>;
+	clocks = <&clk_pclk1>;
+	st,hw-flow-ctrl;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  09/15] dt-bindings: Document the STM32 USART bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 USART

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/serial/st,stm32-usart.txt  | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
new file mode 100644
index 0000000..090a3a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -0,0 +1,32 @@
+* STMicroelectronics STM32 USART
+
+Required properties:
+- compatible: Can be either "st,stm32-usart" or "st,stm32-uart" depending on
+whether the device supports synchronous mode.
+- reg: The address and length of the peripheral registers space
+- interrupts: The interrupt line of the USART instance
+- clocks: The input clock of the USART instance
+
+Optional properties:
+- pinctrl: The reference on the pins configuration
+- st,hw-flow-ctrl: bool flag to enable hardware flow control.
+
+Examples:
+usart4: serial@40004c00 {
+	compatible = "st,stm32-uart";
+	reg = <0x40004c00 0x400>;
+	interrupts = <52>;
+	clocks = <&clk_pclk1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart4>;
+};
+
+usart2: serial@40004400 {
+	compatible = "st,stm32-usart", "st,stm32-uart";
+	reg = <0x40004400 0x400>;
+	interrupts = <38>;
+	clocks = <&clk_pclk1>;
+	st,hw-flow-ctrl;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  09/15] dt-bindings: Document the STM32 USART bindings
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This adds documentation of device tree bindings for the
STM32 USART

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 .../devicetree/bindings/serial/st,stm32-usart.txt  | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
new file mode 100644
index 0000000..090a3a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -0,0 +1,32 @@
+* STMicroelectronics STM32 USART
+
+Required properties:
+- compatible: Can be either "st,stm32-usart" or "st,stm32-uart" depending on
+whether the device supports synchronous mode.
+- reg: The address and length of the peripheral registers space
+- interrupts: The interrupt line of the USART instance
+- clocks: The input clock of the USART instance
+
+Optional properties:
+- pinctrl: The reference on the pins configuration
+- st,hw-flow-ctrl: bool flag to enable hardware flow control.
+
+Examples:
+usart4: serial at 40004c00 {
+	compatible = "st,stm32-uart";
+	reg = <0x40004c00 0x400>;
+	interrupts = <52>;
+	clocks = <&clk_pclk1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart4>;
+};
+
+usart2: serial at 40004400 {
+	compatible = "st,stm32-usart", "st,stm32-uart";
+	reg = <0x40004400 0x400>;
+	interrupts = <38>;
+	clocks = <&clk_pclk1>;
+	st,hw-flow-ctrl;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55     ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TZNg+MwTxZMZA

From: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This drivers adds support to the STM32 USART controller, which is a
standard serial driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/tty/serial/Kconfig       |  17 +
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 716 insertions(+)
 create mode 100644 drivers/tty/serial/stm32-usart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index d2501f0..880cb4f 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
 	  with "earlycon" on the kernel command line. The console is
 	  enabled when early_param is processed.
 
+config SERIAL_STM32
+	tristate "STMicroelectronics STM32 serial port support"
+	select SERIAL_CORE
+	depends on ARM || COMPILE_TEST
+	help
+	  This driver is for the on-chip Serial Controller on
+	  STMicroelectronics STM32 MCUs.
+	  USART supports Rx & Tx functionality.
+	  It support all industry standard baud rates.
+
+	  If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+	bool "Support for console on STM32"
+	depends on SERIAL_STM32=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 599be4b..67c5023 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 0000000..61bb065
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR		0x00
+#define USART_DR		0x04
+#define USART_BRR		0x08
+#define USART_CR1		0x0c
+#define USART_CR2		0x10
+#define USART_CR3		0x14
+#define USART_GTPR		0x18
+
+/* USART_SR */
+#define USART_SR_PE		BIT(0)
+#define USART_SR_FE		BIT(1)
+#define USART_SR_NF		BIT(2)
+#define USART_SR_ORE		BIT(3)
+#define USART_SR_IDLE		BIT(4)
+#define USART_SR_RXNE		BIT(5)
+#define USART_SR_TC		BIT(6)
+#define USART_SR_TXE		BIT(7)
+#define USART_SR_LBD		BIT(8)
+#define USART_SR_CTS		BIT(9)
+#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
+				 USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX	BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK		GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT	4
+
+/* USART_CR1 */
+#define USART_CR1_SBK		BIT(0)
+#define USART_CR1_RWU		BIT(1)
+#define USART_CR1_RE		BIT(2)
+#define USART_CR1_TE		BIT(3)
+#define USART_CR1_IDLEIE	BIT(4)
+#define USART_CR1_RXNEIE	BIT(5)
+#define USART_CR1_TCIE		BIT(6)
+#define USART_CR1_TXEIE		BIT(7)
+#define USART_CR1_PEIE		BIT(8)
+#define USART_CR1_PS		BIT(9)
+#define USART_CR1_PCE		BIT(10)
+#define USART_CR1_WAKE		BIT(11)
+#define USART_CR1_M		BIT(12)
+#define USART_CR1_UE		BIT(13)
+#define USART_CR1_OVER8		BIT(15)
+#define USART_CR1_IE_MASK	GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK	GENMASK(3, 0)
+#define USART_CR2_LBDL		BIT(5)
+#define USART_CR2_LBDIE		BIT(6)
+#define USART_CR2_LBCL		BIT(8)
+#define USART_CR2_CPHA		BIT(9)
+#define USART_CR2_CPOL		BIT(10)
+#define USART_CR2_CLKEN		BIT(11)
+#define USART_CR2_STOP_2B	BIT(13)
+#define USART_CR2_STOP_MASK	GENMASK(13, 12)
+#define USART_CR2_LINEN		BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE		BIT(0)
+#define USART_CR3_IREN		BIT(1)
+#define USART_CR3_IRLP		BIT(2)
+#define USART_CR3_HDSEL		BIT(3)
+#define USART_CR3_NACK		BIT(4)
+#define USART_CR3_SCEN		BIT(5)
+#define USART_CR3_DMAR		BIT(6)
+#define USART_CR3_DMAT		BIT(7)
+#define USART_CR3_RTSE		BIT(8)
+#define USART_CR3_CTSE		BIT(9)
+#define USART_CR3_CTSIE		BIT(10)
+#define USART_CR3_ONEBIT	BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
+#define USART_GTPR_GT_MASK	GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val |= bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val &= ~bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+	struct tty_port *tport = &port->state->port;
+	unsigned long c;
+	u32 sr;
+	char flag;
+
+	if (port->irq_wake)
+		pm_wakeup_event(tport->tty->dev, 0);
+
+	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+		sr |= USART_SR_DUMMY_RX;
+		c = readl_relaxed(port->membase + USART_DR);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (sr & USART_SR_ERR_MASK) {
+			if (sr & USART_SR_LBD) {
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					continue;
+			} else if (sr & USART_SR_ORE) {
+				port->icount.overrun++;
+			} else if (sr & USART_SR_PE) {
+				port->icount.parity++;
+			} else if (sr & USART_SR_FE) {
+				port->icount.frame++;
+			}
+
+			sr &= port->read_status_mask;
+
+			if (sr & USART_SR_LBD)
+				flag = TTY_BREAK;
+			else if (sr & USART_SR_PE)
+				flag = TTY_PARITY;
+			else if (sr & USART_SR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		writel_relaxed(port->x_char, port->membase + USART_DR);
+		port->x_char = 0;
+		port->icount.tx++;
+		return;
+	}
+
+	if (uart_tx_stopped(port)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	if (uart_circ_empty(xmit)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	port->icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+	struct uart_port *port = ptr;
+	u32 sr;
+
+	spin_lock(&port->lock);
+
+	sr = readl_relaxed(port->membase + USART_SR);
+
+	if (sr & USART_SR_RXNE)
+		stm32_receive_chars(port);
+
+	if (sr & USART_SR_TXE)
+		stm32_transmit_chars(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/*
+	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+	 * We use USART's hardware for CTS/RTS, so don't need any for that.
+	 * Some boards have DTR and DCD implemented using PIO pins,
+	 * code to do this should be hooked in here.
+	 */
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+	/*
+	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	 * and CTS/RTS
+	 */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (uart_circ_empty(xmit))
+		return;
+
+	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+	/* Nothing here yet .. */
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+	const char *name = to_platform_device(port->dev)->name;
+	u32 val;
+
+	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+				name, port)) {
+		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
+		return -ENODEV;
+	}
+
+	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+	u32 val;
+
+	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	unsigned int baud;
+	u32 usardiv, mantissa, fraction;
+	tcflag_t cflag;
+	u32 cr1, cr2, cr3;
+	unsigned long flags;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+	cflag = termios->c_cflag;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Stop serial port and reset value */
+	writel_relaxed(0, port->membase + USART_CR1);
+
+	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+
+	if (cflag & CSTOPB)
+		cr2 = USART_CR2_STOP_2B;
+
+	if (cflag & PARENB) {
+		cr1 |= USART_CR1_PCE;
+		if ((cflag & CSIZE) == CS8)
+			cr1 |= USART_CR1_M;
+	}
+
+	if (cflag & PARODD)
+		cr1 |= USART_CR1_PS;
+
+	if (cflag & CRTSCTS)
+		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
+
+	usardiv = (port->uartclk * 25) / (baud * 4);
+	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
+	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
+	if (fraction & ~USART_BRR_DIV_F_MASK) {
+		fraction = 0;
+		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
+	}
+
+	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+	uart_update_timeout(port, cflag, baud);
+
+	port->read_status_mask = USART_SR_ORE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= USART_SR_LBD;
+
+	/* Characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= USART_SR_LBD;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= USART_SR_ORE;
+	}
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+	writel_relaxed(cr3, port->membase + USART_CR3);
+	writel_relaxed(cr2, port->membase + USART_CR2);
+	writel_relaxed(cr1, port->membase + USART_CR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+	if ((flags & UART_CONFIG_TYPE))
+		port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* No user changeable parameters */
+	return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+		unsigned int oldstate)
+{
+	struct stm32_port *stm32port = container_of(port,
+			struct stm32_port, port);
+	unsigned long flags = 0;
+
+	switch (state) {
+	case UART_PM_STATE_ON:
+		clk_prepare_enable(stm32port->clk);
+		break;
+	case UART_PM_STATE_OFF:
+		spin_lock_irqsave(&port->lock, flags);
+		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+		spin_unlock_irqrestore(&port->lock, flags);
+		clk_disable_unprepare(stm32port->clk);
+		break;
+	}
+}
+
+static struct uart_ops stm32_uart_ops = {
+	.tx_empty	= stm32_tx_empty,
+	.set_mctrl	= stm32_set_mctrl,
+	.get_mctrl	= stm32_get_mctrl,
+	.start_tx	= stm32_start_tx,
+	.stop_tx	= stm32_stop_tx,
+	.stop_rx	= stm32_stop_rx,
+	.break_ctl	= stm32_break_ctl,
+	.startup	= stm32_startup,
+	.shutdown	= stm32_shutdown,
+	.set_termios	= stm32_set_termios,
+	.type		= stm32_type,
+	.release_port	= stm32_release_port,
+	.request_port	= stm32_request_port,
+	.config_port	= stm32_config_port,
+	.verify_port	= stm32_verify_port,
+	.pm		= stm32_pm,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+			  struct platform_device *pdev)
+{
+	struct uart_port *port = &stm32port->port;
+	struct resource *res;
+
+	port->iotype	= UPIO_MEM;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->ops	= &stm32_uart_ops;
+	port->dev	= &pdev->dev;
+	port->irq	= platform_get_irq(pdev, 0);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+	port->mapbase = res->start;
+
+	spin_lock_init(&port->lock);
+
+	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+	if (WARN_ON(IS_ERR(stm32port->clk)))
+		return -EINVAL;
+
+	/* ensure that clk rate is correct by enabling the clk */
+	clk_prepare_enable(stm32port->clk);
+	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+	WARN_ON(stm32port->port.uartclk == 0);
+	clk_disable_unprepare(stm32port->clk);
+
+	return 0;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int id;
+
+	if (!np)
+		return NULL;
+
+	id = of_alias_get_id(np, STM32_SERIAL_NAME);
+
+	if (id < 0)
+		id = 0;
+
+	if (WARN_ON(id >= STM32_MAX_PORTS))
+		return NULL;
+
+	stm32_ports[id].port.line = id;
+	return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+	{ .compatible = "st,stm32-usart", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct stm32_port *stm32port;
+
+	stm32port = stm32_of_get_stm32_port(pdev);
+	if (!stm32port)
+		return -ENODEV;
+
+	ret = stm32_init_port(stm32port, pdev);
+	if (ret)
+		return ret;
+
+	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, &stm32port->port);
+
+	return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+		cpu_relax();
+
+	writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+	struct uart_port *port = &stm32_ports[co->index].port;
+	unsigned long flags;
+	u32 old_cr1, new_cr1;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else {
+		locked = 1;
+		spin_lock_irqsave(&port->lock, flags);
+	}
+
+	/* Save and disable interrupts */
+	old_cr1 = readl_relaxed(port->membase + USART_CR1);
+	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+	writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+	uart_console_write(port, s, cnt, stm32_console_putchar);
+
+	/* Restore interrupt state */
+	writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+	struct stm32_port *stm32port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= STM32_MAX_PORTS)
+		return -ENODEV;
+
+	stm32port = &stm32_ports[co->index];
+
+	/*
+	 * This driver does not support early console initialization
+	 * (use ARM early printk support instead), so we only expect
+	 * this to be called during the uart port registration when the
+	 * driver gets probed and the port should be mapped at that point.
+	 */
+	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+		return -ENXIO;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+	.name		= STM32_SERIAL_NAME,
+	.device		= uart_console_device,
+	.write		= stm32_console_write,
+	.setup		= stm32_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= STM32_SERIAL_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= STM32_MAX_PORTS,
+	.cons		= STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+	.probe		= stm32_serial_probe,
+	.remove		= stm32_serial_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(stm32_match),
+	},
+};
+
+static int __init usart_init(void)
+{
+	int ret;
+	static char banner[] __initdata =
+		KERN_INFO "STM32 USART driver initialized\n";
+
+	printk(banner);
+
+	ret = uart_register_driver(&stm32_usart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&stm32_serial_driver);
+	if (ret)
+		uart_unregister_driver(&stm32_usart_driver);
+
+	return ret;
+}
+
+static void __exit usart_exit(void)
+{
+	platform_driver_unregister(&stm32_serial_driver);
+	uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index b212281..e22dee5 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -258,4 +258,7 @@
 /* Cris v10 / v32 SoC */
 #define PORT_CRIS	112
 
+/* STM32 USART */
+#define PORT_STM32	110
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-12 21:55     ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This drivers adds support to the STM32 USART controller, which is a
standard serial driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/tty/serial/Kconfig       |  17 +
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 716 insertions(+)
 create mode 100644 drivers/tty/serial/stm32-usart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index d2501f0..880cb4f 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
 	  with "earlycon" on the kernel command line. The console is
 	  enabled when early_param is processed.
 
+config SERIAL_STM32
+	tristate "STMicroelectronics STM32 serial port support"
+	select SERIAL_CORE
+	depends on ARM || COMPILE_TEST
+	help
+	  This driver is for the on-chip Serial Controller on
+	  STMicroelectronics STM32 MCUs.
+	  USART supports Rx & Tx functionality.
+	  It support all industry standard baud rates.
+
+	  If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+	bool "Support for console on STM32"
+	depends on SERIAL_STM32=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 599be4b..67c5023 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 0000000..61bb065
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR		0x00
+#define USART_DR		0x04
+#define USART_BRR		0x08
+#define USART_CR1		0x0c
+#define USART_CR2		0x10
+#define USART_CR3		0x14
+#define USART_GTPR		0x18
+
+/* USART_SR */
+#define USART_SR_PE		BIT(0)
+#define USART_SR_FE		BIT(1)
+#define USART_SR_NF		BIT(2)
+#define USART_SR_ORE		BIT(3)
+#define USART_SR_IDLE		BIT(4)
+#define USART_SR_RXNE		BIT(5)
+#define USART_SR_TC		BIT(6)
+#define USART_SR_TXE		BIT(7)
+#define USART_SR_LBD		BIT(8)
+#define USART_SR_CTS		BIT(9)
+#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
+				 USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX	BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK		GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT	4
+
+/* USART_CR1 */
+#define USART_CR1_SBK		BIT(0)
+#define USART_CR1_RWU		BIT(1)
+#define USART_CR1_RE		BIT(2)
+#define USART_CR1_TE		BIT(3)
+#define USART_CR1_IDLEIE	BIT(4)
+#define USART_CR1_RXNEIE	BIT(5)
+#define USART_CR1_TCIE		BIT(6)
+#define USART_CR1_TXEIE		BIT(7)
+#define USART_CR1_PEIE		BIT(8)
+#define USART_CR1_PS		BIT(9)
+#define USART_CR1_PCE		BIT(10)
+#define USART_CR1_WAKE		BIT(11)
+#define USART_CR1_M		BIT(12)
+#define USART_CR1_UE		BIT(13)
+#define USART_CR1_OVER8		BIT(15)
+#define USART_CR1_IE_MASK	GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK	GENMASK(3, 0)
+#define USART_CR2_LBDL		BIT(5)
+#define USART_CR2_LBDIE		BIT(6)
+#define USART_CR2_LBCL		BIT(8)
+#define USART_CR2_CPHA		BIT(9)
+#define USART_CR2_CPOL		BIT(10)
+#define USART_CR2_CLKEN		BIT(11)
+#define USART_CR2_STOP_2B	BIT(13)
+#define USART_CR2_STOP_MASK	GENMASK(13, 12)
+#define USART_CR2_LINEN		BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE		BIT(0)
+#define USART_CR3_IREN		BIT(1)
+#define USART_CR3_IRLP		BIT(2)
+#define USART_CR3_HDSEL		BIT(3)
+#define USART_CR3_NACK		BIT(4)
+#define USART_CR3_SCEN		BIT(5)
+#define USART_CR3_DMAR		BIT(6)
+#define USART_CR3_DMAT		BIT(7)
+#define USART_CR3_RTSE		BIT(8)
+#define USART_CR3_CTSE		BIT(9)
+#define USART_CR3_CTSIE		BIT(10)
+#define USART_CR3_ONEBIT	BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
+#define USART_GTPR_GT_MASK	GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val |= bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val &= ~bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+	struct tty_port *tport = &port->state->port;
+	unsigned long c;
+	u32 sr;
+	char flag;
+
+	if (port->irq_wake)
+		pm_wakeup_event(tport->tty->dev, 0);
+
+	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+		sr |= USART_SR_DUMMY_RX;
+		c = readl_relaxed(port->membase + USART_DR);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (sr & USART_SR_ERR_MASK) {
+			if (sr & USART_SR_LBD) {
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					continue;
+			} else if (sr & USART_SR_ORE) {
+				port->icount.overrun++;
+			} else if (sr & USART_SR_PE) {
+				port->icount.parity++;
+			} else if (sr & USART_SR_FE) {
+				port->icount.frame++;
+			}
+
+			sr &= port->read_status_mask;
+
+			if (sr & USART_SR_LBD)
+				flag = TTY_BREAK;
+			else if (sr & USART_SR_PE)
+				flag = TTY_PARITY;
+			else if (sr & USART_SR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		writel_relaxed(port->x_char, port->membase + USART_DR);
+		port->x_char = 0;
+		port->icount.tx++;
+		return;
+	}
+
+	if (uart_tx_stopped(port)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	if (uart_circ_empty(xmit)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	port->icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+	struct uart_port *port = ptr;
+	u32 sr;
+
+	spin_lock(&port->lock);
+
+	sr = readl_relaxed(port->membase + USART_SR);
+
+	if (sr & USART_SR_RXNE)
+		stm32_receive_chars(port);
+
+	if (sr & USART_SR_TXE)
+		stm32_transmit_chars(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/*
+	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+	 * We use USART's hardware for CTS/RTS, so don't need any for that.
+	 * Some boards have DTR and DCD implemented using PIO pins,
+	 * code to do this should be hooked in here.
+	 */
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+	/*
+	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	 * and CTS/RTS
+	 */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (uart_circ_empty(xmit))
+		return;
+
+	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+	/* Nothing here yet .. */
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+	const char *name = to_platform_device(port->dev)->name;
+	u32 val;
+
+	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+				name, port)) {
+		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
+		return -ENODEV;
+	}
+
+	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+	u32 val;
+
+	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	unsigned int baud;
+	u32 usardiv, mantissa, fraction;
+	tcflag_t cflag;
+	u32 cr1, cr2, cr3;
+	unsigned long flags;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+	cflag = termios->c_cflag;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Stop serial port and reset value */
+	writel_relaxed(0, port->membase + USART_CR1);
+
+	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+
+	if (cflag & CSTOPB)
+		cr2 = USART_CR2_STOP_2B;
+
+	if (cflag & PARENB) {
+		cr1 |= USART_CR1_PCE;
+		if ((cflag & CSIZE) == CS8)
+			cr1 |= USART_CR1_M;
+	}
+
+	if (cflag & PARODD)
+		cr1 |= USART_CR1_PS;
+
+	if (cflag & CRTSCTS)
+		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
+
+	usardiv = (port->uartclk * 25) / (baud * 4);
+	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
+	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
+	if (fraction & ~USART_BRR_DIV_F_MASK) {
+		fraction = 0;
+		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
+	}
+
+	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+	uart_update_timeout(port, cflag, baud);
+
+	port->read_status_mask = USART_SR_ORE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= USART_SR_LBD;
+
+	/* Characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= USART_SR_LBD;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= USART_SR_ORE;
+	}
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+	writel_relaxed(cr3, port->membase + USART_CR3);
+	writel_relaxed(cr2, port->membase + USART_CR2);
+	writel_relaxed(cr1, port->membase + USART_CR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+	if ((flags & UART_CONFIG_TYPE))
+		port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* No user changeable parameters */
+	return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+		unsigned int oldstate)
+{
+	struct stm32_port *stm32port = container_of(port,
+			struct stm32_port, port);
+	unsigned long flags = 0;
+
+	switch (state) {
+	case UART_PM_STATE_ON:
+		clk_prepare_enable(stm32port->clk);
+		break;
+	case UART_PM_STATE_OFF:
+		spin_lock_irqsave(&port->lock, flags);
+		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+		spin_unlock_irqrestore(&port->lock, flags);
+		clk_disable_unprepare(stm32port->clk);
+		break;
+	}
+}
+
+static struct uart_ops stm32_uart_ops = {
+	.tx_empty	= stm32_tx_empty,
+	.set_mctrl	= stm32_set_mctrl,
+	.get_mctrl	= stm32_get_mctrl,
+	.start_tx	= stm32_start_tx,
+	.stop_tx	= stm32_stop_tx,
+	.stop_rx	= stm32_stop_rx,
+	.break_ctl	= stm32_break_ctl,
+	.startup	= stm32_startup,
+	.shutdown	= stm32_shutdown,
+	.set_termios	= stm32_set_termios,
+	.type		= stm32_type,
+	.release_port	= stm32_release_port,
+	.request_port	= stm32_request_port,
+	.config_port	= stm32_config_port,
+	.verify_port	= stm32_verify_port,
+	.pm		= stm32_pm,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+			  struct platform_device *pdev)
+{
+	struct uart_port *port = &stm32port->port;
+	struct resource *res;
+
+	port->iotype	= UPIO_MEM;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->ops	= &stm32_uart_ops;
+	port->dev	= &pdev->dev;
+	port->irq	= platform_get_irq(pdev, 0);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+	port->mapbase = res->start;
+
+	spin_lock_init(&port->lock);
+
+	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+	if (WARN_ON(IS_ERR(stm32port->clk)))
+		return -EINVAL;
+
+	/* ensure that clk rate is correct by enabling the clk */
+	clk_prepare_enable(stm32port->clk);
+	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+	WARN_ON(stm32port->port.uartclk == 0);
+	clk_disable_unprepare(stm32port->clk);
+
+	return 0;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int id;
+
+	if (!np)
+		return NULL;
+
+	id = of_alias_get_id(np, STM32_SERIAL_NAME);
+
+	if (id < 0)
+		id = 0;
+
+	if (WARN_ON(id >= STM32_MAX_PORTS))
+		return NULL;
+
+	stm32_ports[id].port.line = id;
+	return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+	{ .compatible = "st,stm32-usart", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct stm32_port *stm32port;
+
+	stm32port = stm32_of_get_stm32_port(pdev);
+	if (!stm32port)
+		return -ENODEV;
+
+	ret = stm32_init_port(stm32port, pdev);
+	if (ret)
+		return ret;
+
+	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, &stm32port->port);
+
+	return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+		cpu_relax();
+
+	writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+	struct uart_port *port = &stm32_ports[co->index].port;
+	unsigned long flags;
+	u32 old_cr1, new_cr1;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else {
+		locked = 1;
+		spin_lock_irqsave(&port->lock, flags);
+	}
+
+	/* Save and disable interrupts */
+	old_cr1 = readl_relaxed(port->membase + USART_CR1);
+	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+	writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+	uart_console_write(port, s, cnt, stm32_console_putchar);
+
+	/* Restore interrupt state */
+	writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+	struct stm32_port *stm32port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= STM32_MAX_PORTS)
+		return -ENODEV;
+
+	stm32port = &stm32_ports[co->index];
+
+	/*
+	 * This driver does not support early console initialization
+	 * (use ARM early printk support instead), so we only expect
+	 * this to be called during the uart port registration when the
+	 * driver gets probed and the port should be mapped at that point.
+	 */
+	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+		return -ENXIO;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+	.name		= STM32_SERIAL_NAME,
+	.device		= uart_console_device,
+	.write		= stm32_console_write,
+	.setup		= stm32_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= STM32_SERIAL_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= STM32_MAX_PORTS,
+	.cons		= STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+	.probe		= stm32_serial_probe,
+	.remove		= stm32_serial_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(stm32_match),
+	},
+};
+
+static int __init usart_init(void)
+{
+	int ret;
+	static char banner[] __initdata =
+		KERN_INFO "STM32 USART driver initialized\n";
+
+	printk(banner);
+
+	ret = uart_register_driver(&stm32_usart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&stm32_serial_driver);
+	if (ret)
+		uart_unregister_driver(&stm32_usart_driver);
+
+	return ret;
+}
+
+static void __exit usart_exit(void)
+{
+	platform_driver_unregister(&stm32_serial_driver);
+	uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index b212281..e22dee5 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -258,4 +258,7 @@
 /* Cris v10 / v32 SoC */
 #define PORT_CRIS	112
 
+/* STM32 USART */
+#define PORT_STM32	110
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-12 21:55     ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This drivers adds support to the STM32 USART controller, which is a
standard serial driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 drivers/tty/serial/Kconfig       |  17 +
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 716 insertions(+)
 create mode 100644 drivers/tty/serial/stm32-usart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index d2501f0..880cb4f 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
 	  with "earlycon" on the kernel command line. The console is
 	  enabled when early_param is processed.
 
+config SERIAL_STM32
+	tristate "STMicroelectronics STM32 serial port support"
+	select SERIAL_CORE
+	depends on ARM || COMPILE_TEST
+	help
+	  This driver is for the on-chip Serial Controller on
+	  STMicroelectronics STM32 MCUs.
+	  USART supports Rx & Tx functionality.
+	  It support all industry standard baud rates.
+
+	  If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+	bool "Support for console on STM32"
+	depends on SERIAL_STM32=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 599be4b..67c5023 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 0000000..61bb065
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR		0x00
+#define USART_DR		0x04
+#define USART_BRR		0x08
+#define USART_CR1		0x0c
+#define USART_CR2		0x10
+#define USART_CR3		0x14
+#define USART_GTPR		0x18
+
+/* USART_SR */
+#define USART_SR_PE		BIT(0)
+#define USART_SR_FE		BIT(1)
+#define USART_SR_NF		BIT(2)
+#define USART_SR_ORE		BIT(3)
+#define USART_SR_IDLE		BIT(4)
+#define USART_SR_RXNE		BIT(5)
+#define USART_SR_TC		BIT(6)
+#define USART_SR_TXE		BIT(7)
+#define USART_SR_LBD		BIT(8)
+#define USART_SR_CTS		BIT(9)
+#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
+				 USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX	BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK		GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT	4
+
+/* USART_CR1 */
+#define USART_CR1_SBK		BIT(0)
+#define USART_CR1_RWU		BIT(1)
+#define USART_CR1_RE		BIT(2)
+#define USART_CR1_TE		BIT(3)
+#define USART_CR1_IDLEIE	BIT(4)
+#define USART_CR1_RXNEIE	BIT(5)
+#define USART_CR1_TCIE		BIT(6)
+#define USART_CR1_TXEIE		BIT(7)
+#define USART_CR1_PEIE		BIT(8)
+#define USART_CR1_PS		BIT(9)
+#define USART_CR1_PCE		BIT(10)
+#define USART_CR1_WAKE		BIT(11)
+#define USART_CR1_M		BIT(12)
+#define USART_CR1_UE		BIT(13)
+#define USART_CR1_OVER8		BIT(15)
+#define USART_CR1_IE_MASK	GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK	GENMASK(3, 0)
+#define USART_CR2_LBDL		BIT(5)
+#define USART_CR2_LBDIE		BIT(6)
+#define USART_CR2_LBCL		BIT(8)
+#define USART_CR2_CPHA		BIT(9)
+#define USART_CR2_CPOL		BIT(10)
+#define USART_CR2_CLKEN		BIT(11)
+#define USART_CR2_STOP_2B	BIT(13)
+#define USART_CR2_STOP_MASK	GENMASK(13, 12)
+#define USART_CR2_LINEN		BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE		BIT(0)
+#define USART_CR3_IREN		BIT(1)
+#define USART_CR3_IRLP		BIT(2)
+#define USART_CR3_HDSEL		BIT(3)
+#define USART_CR3_NACK		BIT(4)
+#define USART_CR3_SCEN		BIT(5)
+#define USART_CR3_DMAR		BIT(6)
+#define USART_CR3_DMAT		BIT(7)
+#define USART_CR3_RTSE		BIT(8)
+#define USART_CR3_CTSE		BIT(9)
+#define USART_CR3_CTSIE		BIT(10)
+#define USART_CR3_ONEBIT	BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
+#define USART_GTPR_GT_MASK	GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val |= bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+	u32 val;
+
+	val = readl_relaxed(port->membase + reg);
+	val &= ~bits;
+	writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+	struct tty_port *tport = &port->state->port;
+	unsigned long c;
+	u32 sr;
+	char flag;
+
+	if (port->irq_wake)
+		pm_wakeup_event(tport->tty->dev, 0);
+
+	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+		sr |= USART_SR_DUMMY_RX;
+		c = readl_relaxed(port->membase + USART_DR);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (sr & USART_SR_ERR_MASK) {
+			if (sr & USART_SR_LBD) {
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					continue;
+			} else if (sr & USART_SR_ORE) {
+				port->icount.overrun++;
+			} else if (sr & USART_SR_PE) {
+				port->icount.parity++;
+			} else if (sr & USART_SR_FE) {
+				port->icount.frame++;
+			}
+
+			sr &= port->read_status_mask;
+
+			if (sr & USART_SR_LBD)
+				flag = TTY_BREAK;
+			else if (sr & USART_SR_PE)
+				flag = TTY_PARITY;
+			else if (sr & USART_SR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		writel_relaxed(port->x_char, port->membase + USART_DR);
+		port->x_char = 0;
+		port->icount.tx++;
+		return;
+	}
+
+	if (uart_tx_stopped(port)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	if (uart_circ_empty(xmit)) {
+		stm32_stop_tx(port);
+		return;
+	}
+
+	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	port->icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+	struct uart_port *port = ptr;
+	u32 sr;
+
+	spin_lock(&port->lock);
+
+	sr = readl_relaxed(port->membase + USART_SR);
+
+	if (sr & USART_SR_RXNE)
+		stm32_receive_chars(port);
+
+	if (sr & USART_SR_TXE)
+		stm32_transmit_chars(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/*
+	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+	 * We use USART's hardware for CTS/RTS, so don't need any for that.
+	 * Some boards have DTR and DCD implemented using PIO pins,
+	 * code to do this should be hooked in here.
+	 */
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+	/*
+	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	 * and CTS/RTS
+	 */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (uart_circ_empty(xmit))
+		return;
+
+	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+	/* Nothing here yet .. */
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+	const char *name = to_platform_device(port->dev)->name;
+	u32 val;
+
+	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+				name, port)) {
+		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
+		return -ENODEV;
+	}
+
+	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+	u32 val;
+
+	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+	stm32_set_bits(port, USART_CR1, val);
+
+	free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	unsigned int baud;
+	u32 usardiv, mantissa, fraction;
+	tcflag_t cflag;
+	u32 cr1, cr2, cr3;
+	unsigned long flags;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+	cflag = termios->c_cflag;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Stop serial port and reset value */
+	writel_relaxed(0, port->membase + USART_CR1);
+
+	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+
+	if (cflag & CSTOPB)
+		cr2 = USART_CR2_STOP_2B;
+
+	if (cflag & PARENB) {
+		cr1 |= USART_CR1_PCE;
+		if ((cflag & CSIZE) == CS8)
+			cr1 |= USART_CR1_M;
+	}
+
+	if (cflag & PARODD)
+		cr1 |= USART_CR1_PS;
+
+	if (cflag & CRTSCTS)
+		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
+
+	usardiv = (port->uartclk * 25) / (baud * 4);
+	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
+	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
+	if (fraction & ~USART_BRR_DIV_F_MASK) {
+		fraction = 0;
+		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
+	}
+
+	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+	uart_update_timeout(port, cflag, baud);
+
+	port->read_status_mask = USART_SR_ORE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= USART_SR_LBD;
+
+	/* Characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= USART_SR_LBD;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= USART_SR_ORE;
+	}
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+	writel_relaxed(cr3, port->membase + USART_CR3);
+	writel_relaxed(cr2, port->membase + USART_CR2);
+	writel_relaxed(cr1, port->membase + USART_CR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+	if ((flags & UART_CONFIG_TYPE))
+		port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* No user changeable parameters */
+	return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+		unsigned int oldstate)
+{
+	struct stm32_port *stm32port = container_of(port,
+			struct stm32_port, port);
+	unsigned long flags = 0;
+
+	switch (state) {
+	case UART_PM_STATE_ON:
+		clk_prepare_enable(stm32port->clk);
+		break;
+	case UART_PM_STATE_OFF:
+		spin_lock_irqsave(&port->lock, flags);
+		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+		spin_unlock_irqrestore(&port->lock, flags);
+		clk_disable_unprepare(stm32port->clk);
+		break;
+	}
+}
+
+static struct uart_ops stm32_uart_ops = {
+	.tx_empty	= stm32_tx_empty,
+	.set_mctrl	= stm32_set_mctrl,
+	.get_mctrl	= stm32_get_mctrl,
+	.start_tx	= stm32_start_tx,
+	.stop_tx	= stm32_stop_tx,
+	.stop_rx	= stm32_stop_rx,
+	.break_ctl	= stm32_break_ctl,
+	.startup	= stm32_startup,
+	.shutdown	= stm32_shutdown,
+	.set_termios	= stm32_set_termios,
+	.type		= stm32_type,
+	.release_port	= stm32_release_port,
+	.request_port	= stm32_request_port,
+	.config_port	= stm32_config_port,
+	.verify_port	= stm32_verify_port,
+	.pm		= stm32_pm,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+			  struct platform_device *pdev)
+{
+	struct uart_port *port = &stm32port->port;
+	struct resource *res;
+
+	port->iotype	= UPIO_MEM;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->ops	= &stm32_uart_ops;
+	port->dev	= &pdev->dev;
+	port->irq	= platform_get_irq(pdev, 0);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+	port->mapbase = res->start;
+
+	spin_lock_init(&port->lock);
+
+	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+	if (WARN_ON(IS_ERR(stm32port->clk)))
+		return -EINVAL;
+
+	/* ensure that clk rate is correct by enabling the clk */
+	clk_prepare_enable(stm32port->clk);
+	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+	WARN_ON(stm32port->port.uartclk == 0);
+	clk_disable_unprepare(stm32port->clk);
+
+	return 0;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int id;
+
+	if (!np)
+		return NULL;
+
+	id = of_alias_get_id(np, STM32_SERIAL_NAME);
+
+	if (id < 0)
+		id = 0;
+
+	if (WARN_ON(id >= STM32_MAX_PORTS))
+		return NULL;
+
+	stm32_ports[id].port.line = id;
+	return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+	{ .compatible = "st,stm32-usart", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct stm32_port *stm32port;
+
+	stm32port = stm32_of_get_stm32_port(pdev);
+	if (!stm32port)
+		return -ENODEV;
+
+	ret = stm32_init_port(stm32port, pdev);
+	if (ret)
+		return ret;
+
+	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, &stm32port->port);
+
+	return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+		cpu_relax();
+
+	writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+	struct uart_port *port = &stm32_ports[co->index].port;
+	unsigned long flags;
+	u32 old_cr1, new_cr1;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else {
+		locked = 1;
+		spin_lock_irqsave(&port->lock, flags);
+	}
+
+	/* Save and disable interrupts */
+	old_cr1 = readl_relaxed(port->membase + USART_CR1);
+	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+	writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+	uart_console_write(port, s, cnt, stm32_console_putchar);
+
+	/* Restore interrupt state */
+	writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+	struct stm32_port *stm32port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= STM32_MAX_PORTS)
+		return -ENODEV;
+
+	stm32port = &stm32_ports[co->index];
+
+	/*
+	 * This driver does not support early console initialization
+	 * (use ARM early printk support instead), so we only expect
+	 * this to be called during the uart port registration when the
+	 * driver gets probed and the port should be mapped at that point.
+	 */
+	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+		return -ENXIO;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+	.name		= STM32_SERIAL_NAME,
+	.device		= uart_console_device,
+	.write		= stm32_console_write,
+	.setup		= stm32_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= STM32_SERIAL_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= STM32_MAX_PORTS,
+	.cons		= STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+	.probe		= stm32_serial_probe,
+	.remove		= stm32_serial_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(stm32_match),
+	},
+};
+
+static int __init usart_init(void)
+{
+	int ret;
+	static char banner[] __initdata =
+		KERN_INFO "STM32 USART driver initialized\n";
+
+	printk(banner);
+
+	ret = uart_register_driver(&stm32_usart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&stm32_serial_driver);
+	if (ret)
+		uart_unregister_driver(&stm32_usart_driver);
+
+	return ret;
+}
+
+static void __exit usart_exit(void)
+{
+	platform_driver_unregister(&stm32_serial_driver);
+	uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index b212281..e22dee5 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -258,4 +258,7 @@
 /* Cris v10 / v32 SoC */
 #define PORT_CRIS	112
 
+/* STM32 USART */
+#define PORT_STM32	110
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  11/15] ARM: Add STM32 family machine
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STMicrolectronics's STM32 series is a family of Cortex-M
microcontrollers. It is used in various applications, and
proposes a wide range of peripherals.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 Documentation/arm/stm32/overview.txt           | 32 ++++++++++++++++++++++++++
 Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
 arch/arm/Kconfig                               | 18 +++++++++++++++
 arch/arm/Makefile                              |  1 +
 arch/arm/mach-stm32/Makefile                   |  1 +
 arch/arm/mach-stm32/Makefile.boot              |  3 +++
 arch/arm/mach-stm32/board-dt.c                 | 19 +++++++++++++++
 7 files changed, 96 insertions(+)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c

diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 0000000..09aed55
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+			STM32 ARM Linux Overview
+			========================
+
+Introduction
+------------
+
+  The STMicroelectronics family of Cortex-M based MCUs are supported by the
+  'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+  A generic configuration is provided for STM32 family, and can be used as the
+  default by
+	make stm32_defconfig
+
+Layout
+------
+
+  All the files for multiple machine families are located in the platform code
+  contained in arch/arm/mach-stm32
+
+  There is a generic board board-dt.c in the mach folder which support
+  Flattened Device Tree, which means, it works with any compatible board with
+  Device Trees.
+
+
+Document Author
+---------------
+
+  Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 0000000..5206822
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+			STM32F429 Overview
+			==================
+
+  Introduction
+  ------------
+	The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+	It features:
+	- ARM Cortex-M4 up to 180MHz with FPU
+	- 2MB internal Flash Memory
+	- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+	- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+	- LCD controller & Camera interface
+	- Cryptographic processor
+
+  Resources
+  ---------
+	Datasheet and reference manual are publicly available on ST website:
+	- http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+  Document Author
+  ---------------
+	Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9f1f09a..5b1157d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -776,6 +776,24 @@ config ARCH_OMAP1
 	help
 	  Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
 
+config ARCH_STM32
+	bool "STMicrolectronics STM32"
+	depends on !MMU
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARM_NVIC
+	select ARMV7M_SYSTICK
+	select AUTO_ZRELADDR
+	select CLKSRC_OF
+	select COMMON_CLK
+	select CPU_V7M
+	select GENERIC_CLOCKEVENTS
+	select NO_IOPORT_MAP
+	select RESET_CONTROLLER
+	select SPARSE_IRQ
+	select USE_OF
+	help
+	  Support for STMicroelectronics STM32 processors.
+
 endchoice
 
 menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 7f99cd6..982c104 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) 	+= shmobile
 machine-$(CONFIG_ARCH_SIRF)		+= prima2
 machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
+machine-$(CONFIG_ARCH_STM32)		+= stm32
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U300)		+= u300
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 0000000..bd0b7b5
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 0000000..eacfc3f
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 0000000..f2ad772
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+	"st,stm32f429",
+	NULL
+};
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+	.dt_compat = stm32_compat,
+	.restart = armv7m_restart,
+MACHINE_END
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  11/15] ARM: Add STM32 family machine
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STMicrolectronics's STM32 series is a family of Cortex-M
microcontrollers. It is used in various applications, and
proposes a wide range of peripherals.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 Documentation/arm/stm32/overview.txt           | 32 ++++++++++++++++++++++++++
 Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
 arch/arm/Kconfig                               | 18 +++++++++++++++
 arch/arm/Makefile                              |  1 +
 arch/arm/mach-stm32/Makefile                   |  1 +
 arch/arm/mach-stm32/Makefile.boot              |  3 +++
 arch/arm/mach-stm32/board-dt.c                 | 19 +++++++++++++++
 7 files changed, 96 insertions(+)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c

diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 0000000..09aed55
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+			STM32 ARM Linux Overview
+			========================
+
+Introduction
+------------
+
+  The STMicroelectronics family of Cortex-M based MCUs are supported by the
+  'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+  A generic configuration is provided for STM32 family, and can be used as the
+  default by
+	make stm32_defconfig
+
+Layout
+------
+
+  All the files for multiple machine families are located in the platform code
+  contained in arch/arm/mach-stm32
+
+  There is a generic board board-dt.c in the mach folder which support
+  Flattened Device Tree, which means, it works with any compatible board with
+  Device Trees.
+
+
+Document Author
+---------------
+
+  Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 0000000..5206822
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+			STM32F429 Overview
+			==================
+
+  Introduction
+  ------------
+	The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+	It features:
+	- ARM Cortex-M4 up to 180MHz with FPU
+	- 2MB internal Flash Memory
+	- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+	- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+	- LCD controller & Camera interface
+	- Cryptographic processor
+
+  Resources
+  ---------
+	Datasheet and reference manual are publicly available on ST website:
+	- http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+  Document Author
+  ---------------
+	Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9f1f09a..5b1157d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -776,6 +776,24 @@ config ARCH_OMAP1
 	help
 	  Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
 
+config ARCH_STM32
+	bool "STMicrolectronics STM32"
+	depends on !MMU
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARM_NVIC
+	select ARMV7M_SYSTICK
+	select AUTO_ZRELADDR
+	select CLKSRC_OF
+	select COMMON_CLK
+	select CPU_V7M
+	select GENERIC_CLOCKEVENTS
+	select NO_IOPORT_MAP
+	select RESET_CONTROLLER
+	select SPARSE_IRQ
+	select USE_OF
+	help
+	  Support for STMicroelectronics STM32 processors.
+
 endchoice
 
 menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 7f99cd6..982c104 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) 	+= shmobile
 machine-$(CONFIG_ARCH_SIRF)		+= prima2
 machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
+machine-$(CONFIG_ARCH_STM32)		+= stm32
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U300)		+= u300
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 0000000..bd0b7b5
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 0000000..eacfc3f
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 0000000..f2ad772
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+	"st,stm32f429",
+	NULL
+};
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+	.dt_compat = stm32_compat,
+	.restart = armv7m_restart,
+MACHINE_END
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  11/15] ARM: Add STM32 family machine
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

STMicrolectronics's STM32 series is a family of Cortex-M
microcontrollers. It is used in various applications, and
proposes a wide range of peripherals.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 Documentation/arm/stm32/overview.txt           | 32 ++++++++++++++++++++++++++
 Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
 arch/arm/Kconfig                               | 18 +++++++++++++++
 arch/arm/Makefile                              |  1 +
 arch/arm/mach-stm32/Makefile                   |  1 +
 arch/arm/mach-stm32/Makefile.boot              |  3 +++
 arch/arm/mach-stm32/board-dt.c                 | 19 +++++++++++++++
 7 files changed, 96 insertions(+)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c

diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 0000000..09aed55
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+			STM32 ARM Linux Overview
+			========================
+
+Introduction
+------------
+
+  The STMicroelectronics family of Cortex-M based MCUs are supported by the
+  'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+  A generic configuration is provided for STM32 family, and can be used as the
+  default by
+	make stm32_defconfig
+
+Layout
+------
+
+  All the files for multiple machine families are located in the platform code
+  contained in arch/arm/mach-stm32
+
+  There is a generic board board-dt.c in the mach folder which support
+  Flattened Device Tree, which means, it works with any compatible board with
+  Device Trees.
+
+
+Document Author
+---------------
+
+  Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 0000000..5206822
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+			STM32F429 Overview
+			==================
+
+  Introduction
+  ------------
+	The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+	It features:
+	- ARM Cortex-M4 up to 180MHz with FPU
+	- 2MB internal Flash Memory
+	- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+	- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+	- LCD controller & Camera interface
+	- Cryptographic processor
+
+  Resources
+  ---------
+	Datasheet and reference manual are publicly available on ST website:
+	- http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+  Document Author
+  ---------------
+	Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9f1f09a..5b1157d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -776,6 +776,24 @@ config ARCH_OMAP1
 	help
 	  Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
 
+config ARCH_STM32
+	bool "STMicrolectronics STM32"
+	depends on !MMU
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARM_NVIC
+	select ARMV7M_SYSTICK
+	select AUTO_ZRELADDR
+	select CLKSRC_OF
+	select COMMON_CLK
+	select CPU_V7M
+	select GENERIC_CLOCKEVENTS
+	select NO_IOPORT_MAP
+	select RESET_CONTROLLER
+	select SPARSE_IRQ
+	select USE_OF
+	help
+	  Support for STMicroelectronics STM32 processors.
+
 endchoice
 
 menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 7f99cd6..982c104 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) 	+= shmobile
 machine-$(CONFIG_ARCH_SIRF)		+= prima2
 machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
+machine-$(CONFIG_ARCH_STM32)		+= stm32
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U300)		+= u300
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 0000000..bd0b7b5
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 0000000..eacfc3f
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 0000000..f2ad772
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+	"st,stm32f429",
+	NULL
+};
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+	.dt_compat = stm32_compat,
+	.restart = armv7m_restart,
+MACHINE_END
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  12/15] ARM: dts: Add ARM System timer as clockevent in armv7m
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/armv7-m.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0..b1ad7cf 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,12 @@
 		reg = <0xe000e100 0xc00>;
 	};
 
+	systick: timer@e000e010 {
+		compatible = "arm,armv7m-systick";
+		reg = <0xe000e010 0x10>;
+		status = "disabled";
+	};
+
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  12/15] ARM: dts: Add ARM System timer as clockevent in armv7m
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/armv7-m.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0..b1ad7cf 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,12 @@
 		reg = <0xe000e100 0xc00>;
 	};
 
+	systick: timer@e000e010 {
+		compatible = "arm,armv7m-systick";
+		reg = <0xe000e010 0x10>;
+		status = "disabled";
+	};
+
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3 12/15] ARM: dts: Add ARM System timer as clockevent in armv7m
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/armv7-m.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0..b1ad7cf 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,12 @@
 		reg = <0xe000e100 0xc00>;
 	};
 
+	systick: timer at e000e010 {
+		compatible = "arm,armv7m-systick";
+		reg = <0xe000e010 0x10>;
+		status = "disabled";
+	};
+
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  13/15] ARM: dts: Introduce STM32F429 MCU
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:55   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STMicrolectornics's STM32F419 MCU has the following main features:
 - Cortex-M4 core running up to @180MHz
 - 2MB internal flash, 256KBytes internal RAM
 - FMC controller to connect SDRAM, NOR and NAND memories
 - SD/MMC/SDIO support
 - Ethernet controller
 - USB OTFG FS & HS controllers
 - I2C, SPI, CAN busses support
 - Several 16 & 32 bits general purpose timers
 - Serial Audio interface
 - LCD controller

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/Makefile            |   1 +
 arch/arm/boot/dts/stm32f429-disco.dts |  71 +++++++++++
 arch/arm/boot/dts/stm32f429.dtsi      | 226 ++++++++++++++++++++++++++++++++++
 3 files changed, 298 insertions(+)
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index a1c776b..e5dbd03 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -509,6 +509,7 @@ dtb-$(CONFIG_ARCH_STI) += \
 	stih416-b2020.dtb \
 	stih416-b2020e.dtb \
 	stih418-b2199.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 0000000..6b9aa59
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "stm32f429.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32F429i-DISCO board";
+	compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+		linux,stdout-path = &usart1;
+	};
+
+	memory {
+		reg = <0x90000000 0x800000>;
+	};
+
+	aliases {
+		serial0 = &usart1;
+	};
+};
+
+&usart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 0000000..39ffdb8
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+	clocks {
+		clk_sysclk: clk-sysclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_hclk: clk-hclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_pclk1: clk-pclk1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <45000000>;
+		};
+
+		clk_pclk2: clk-pclk2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr1: clk-pmtr1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr2: clk-pmtr2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_systick: clk-systick {
+			compatible = "fixed-factor-clock";
+			clocks = <&clk_hclk>;
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+		};
+	};
+
+	soc {
+		timer2: timer@40000000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000000 0x400>;
+			interrupts = <28>;
+			resets = <&rcc 256>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer3: timer@40000400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000400 0x400>;
+			interrupts = <29>;
+			resets = <&rcc 257>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer4: timer@40000800 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000800 0x400>;
+			interrupts = <30>;
+			resets = <&rcc 258>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer5: timer@40000c00 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000c00 0x400>;
+			interrupts = <50>;
+			resets = <&rcc 259>;
+			clocks = <&clk_pmtr1>;
+		};
+
+		timer6: timer@40001000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001000 0x400>;
+			interrupts = <54>;
+			resets = <&rcc 260>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer7: timer@40001400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001400 0x400>;
+			interrupts = <55>;
+			resets = <&rcc 261>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		usart2: serial@40004400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004400 0x400>;
+			interrupts = <38>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart3: serial@40004800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004800 0x400>;
+			interrupts = <39>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart4: serial@40004c00 {
+			compatible = "st,stm32-uart";
+			reg = <0x40004c00 0x400>;
+			interrupts = <52>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart5: serial@40005000 {
+			compatible = "st,stm32-uart";
+			reg = <0x40005000 0x400>;
+			interrupts = <53>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart7: serial@40007800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007800 0x400>;
+			interrupts = <82>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart8: serial@40007c00 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007c00 0x400>;
+			interrupts = <83>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart1: serial@40011000 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011000 0x400>;
+			interrupts = <37>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		usart6: serial@40011400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011400 0x400>;
+			interrupts = <71>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		rcc: rcc@40023810 {
+			#reset-cells = <1>;
+			compatible = "st,stm32-rcc";
+			reg = <0x40023800 0x400>;
+		};
+	};
+};
+
+&systick {
+	clocks = <&clk_systick>;
+	status = "okay";
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  13/15] ARM: dts: Introduce STM32F429 MCU
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STMicrolectornics's STM32F419 MCU has the following main features:
 - Cortex-M4 core running up to @180MHz
 - 2MB internal flash, 256KBytes internal RAM
 - FMC controller to connect SDRAM, NOR and NAND memories
 - SD/MMC/SDIO support
 - Ethernet controller
 - USB OTFG FS & HS controllers
 - I2C, SPI, CAN busses support
 - Several 16 & 32 bits general purpose timers
 - Serial Audio interface
 - LCD controller

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/Makefile            |   1 +
 arch/arm/boot/dts/stm32f429-disco.dts |  71 +++++++++++
 arch/arm/boot/dts/stm32f429.dtsi      | 226 ++++++++++++++++++++++++++++++++++
 3 files changed, 298 insertions(+)
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index a1c776b..e5dbd03 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -509,6 +509,7 @@ dtb-$(CONFIG_ARCH_STI) += \
 	stih416-b2020.dtb \
 	stih416-b2020e.dtb \
 	stih418-b2199.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 0000000..6b9aa59
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "stm32f429.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32F429i-DISCO board";
+	compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+		linux,stdout-path = &usart1;
+	};
+
+	memory {
+		reg = <0x90000000 0x800000>;
+	};
+
+	aliases {
+		serial0 = &usart1;
+	};
+};
+
+&usart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 0000000..39ffdb8
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+	clocks {
+		clk_sysclk: clk-sysclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_hclk: clk-hclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_pclk1: clk-pclk1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <45000000>;
+		};
+
+		clk_pclk2: clk-pclk2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr1: clk-pmtr1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr2: clk-pmtr2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_systick: clk-systick {
+			compatible = "fixed-factor-clock";
+			clocks = <&clk_hclk>;
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+		};
+	};
+
+	soc {
+		timer2: timer@40000000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000000 0x400>;
+			interrupts = <28>;
+			resets = <&rcc 256>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer3: timer@40000400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000400 0x400>;
+			interrupts = <29>;
+			resets = <&rcc 257>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer4: timer@40000800 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000800 0x400>;
+			interrupts = <30>;
+			resets = <&rcc 258>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer5: timer@40000c00 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000c00 0x400>;
+			interrupts = <50>;
+			resets = <&rcc 259>;
+			clocks = <&clk_pmtr1>;
+		};
+
+		timer6: timer@40001000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001000 0x400>;
+			interrupts = <54>;
+			resets = <&rcc 260>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer7: timer@40001400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001400 0x400>;
+			interrupts = <55>;
+			resets = <&rcc 261>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		usart2: serial@40004400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004400 0x400>;
+			interrupts = <38>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart3: serial@40004800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004800 0x400>;
+			interrupts = <39>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart4: serial@40004c00 {
+			compatible = "st,stm32-uart";
+			reg = <0x40004c00 0x400>;
+			interrupts = <52>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart5: serial@40005000 {
+			compatible = "st,stm32-uart";
+			reg = <0x40005000 0x400>;
+			interrupts = <53>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart7: serial@40007800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007800 0x400>;
+			interrupts = <82>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart8: serial@40007c00 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007c00 0x400>;
+			interrupts = <83>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart1: serial@40011000 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011000 0x400>;
+			interrupts = <37>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		usart6: serial@40011400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011400 0x400>;
+			interrupts = <71>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		rcc: rcc@40023810 {
+			#reset-cells = <1>;
+			compatible = "st,stm32-rcc";
+			reg = <0x40023800 0x400>;
+		};
+	};
+};
+
+&systick {
+	clocks = <&clk_systick>;
+	status = "okay";
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  13/15] ARM: dts: Introduce STM32F429 MCU
@ 2015-03-12 21:55   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

The STMicrolectornics's STM32F419 MCU has the following main features:
 - Cortex-M4 core running up to @180MHz
 - 2MB internal flash, 256KBytes internal RAM
 - FMC controller to connect SDRAM, NOR and NAND memories
 - SD/MMC/SDIO support
 - Ethernet controller
 - USB OTFG FS & HS controllers
 - I2C, SPI, CAN busses support
 - Several 16 & 32 bits general purpose timers
 - Serial Audio interface
 - LCD controller

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/boot/dts/Makefile            |   1 +
 arch/arm/boot/dts/stm32f429-disco.dts |  71 +++++++++++
 arch/arm/boot/dts/stm32f429.dtsi      | 226 ++++++++++++++++++++++++++++++++++
 3 files changed, 298 insertions(+)
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index a1c776b..e5dbd03 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -509,6 +509,7 @@ dtb-$(CONFIG_ARCH_STI) += \
 	stih416-b2020.dtb \
 	stih416-b2020e.dtb \
 	stih418-b2199.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 0000000..6b9aa59
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "stm32f429.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32F429i-DISCO board";
+	compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+		linux,stdout-path = &usart1;
+	};
+
+	memory {
+		reg = <0x90000000 0x800000>;
+	};
+
+	aliases {
+		serial0 = &usart1;
+	};
+};
+
+&usart1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 0000000..39ffdb8
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this file; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+	clocks {
+		clk_sysclk: clk-sysclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_hclk: clk-hclk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_pclk1: clk-pclk1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <45000000>;
+		};
+
+		clk_pclk2: clk-pclk2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr1: clk-pmtr1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <90000000>;
+		};
+
+		clk_pmtr2: clk-pmtr2 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <180000000>;
+		};
+
+		clk_systick: clk-systick {
+			compatible = "fixed-factor-clock";
+			clocks = <&clk_hclk>;
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+		};
+	};
+
+	soc {
+		timer2: timer at 40000000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000000 0x400>;
+			interrupts = <28>;
+			resets = <&rcc 256>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer3: timer at 40000400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000400 0x400>;
+			interrupts = <29>;
+			resets = <&rcc 257>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer4: timer at 40000800 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000800 0x400>;
+			interrupts = <30>;
+			resets = <&rcc 258>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer5: timer at 40000c00 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000c00 0x400>;
+			interrupts = <50>;
+			resets = <&rcc 259>;
+			clocks = <&clk_pmtr1>;
+		};
+
+		timer6: timer at 40001000 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001000 0x400>;
+			interrupts = <54>;
+			resets = <&rcc 260>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		timer7: timer at 40001400 {
+			compatible = "st,stm32-timer";
+			reg = <0x40001400 0x400>;
+			interrupts = <55>;
+			resets = <&rcc 261>;
+			clocks = <&clk_pmtr1>;
+			status = "disabled";
+		};
+
+		usart2: serial at 40004400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004400 0x400>;
+			interrupts = <38>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart3: serial at 40004800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40004800 0x400>;
+			interrupts = <39>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart4: serial at 40004c00 {
+			compatible = "st,stm32-uart";
+			reg = <0x40004c00 0x400>;
+			interrupts = <52>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart5: serial at 40005000 {
+			compatible = "st,stm32-uart";
+			reg = <0x40005000 0x400>;
+			interrupts = <53>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart7: serial at 40007800 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007800 0x400>;
+			interrupts = <82>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart8: serial at 40007c00 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40007c00 0x400>;
+			interrupts = <83>;
+			clocks = <&clk_pclk1>;
+			status = "disabled";
+		};
+
+		usart1: serial at 40011000 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011000 0x400>;
+			interrupts = <37>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		usart6: serial at 40011400 {
+			compatible = "st,stm32-usart", "st,stm32-uart";
+			reg = <0x40011400 0x400>;
+			interrupts = <71>;
+			clocks = <&clk_pclk2>;
+			status = "disabled";
+		};
+
+		rcc: rcc at 40023810 {
+			#reset-cells = <1>;
+			compatible = "st,stm32-rcc";
+			reg = <0x40023800 0x400>;
+		};
+	};
+};
+
+&systick {
+	clocks = <&clk_systick>;
+	status = "okay";
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  14/15] ARM: configs: Add STM32 defconfig
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:56   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds a new config for STM32 MCUs.
STM32F429 Discovery board boots successfully with this config applied.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/configs/stm32_defconfig | 71 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 arch/arm/configs/stm32_defconfig

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 0000000..412a9f9
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,71 @@
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="./rootfs.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x90000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08008000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DWC2=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  14/15] ARM: configs: Add STM32 defconfig
@ 2015-03-12 21:56   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds a new config for STM32 MCUs.
STM32F429 Discovery board boots successfully with this config applied.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/configs/stm32_defconfig | 71 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 arch/arm/configs/stm32_defconfig

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 0000000..412a9f9
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,71 @@
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="./rootfs.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x90000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08008000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DWC2=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  14/15] ARM: configs: Add STM32 defconfig
@ 2015-03-12 21:56   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

This patch adds a new config for STM32 MCUs.
STM32F429 Discovery board boots successfully with this config applied.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 arch/arm/configs/stm32_defconfig | 71 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 arch/arm/configs/stm32_defconfig

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 0000000..412a9f9
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,71 @@
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="./rootfs.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x90000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08008000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DWC2=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  15/15] MAINTAINERS: Add entry for STM32 MCUs
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 21:56   ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Add a MAINTAINER entry covering all STM32 machine and drivers files.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ddc5a8c..08c08c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1467,6 +1467,14 @@ F:	drivers/usb/host/ehci-st.c
 F:	drivers/usb/host/ohci-st.c
 F:	drivers/ata/ahci_st.c
 
+ARM/STM32 ARCHITECTURE
+M:	Maxime Coquelin <mcoquelin.stm32@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+N:	stm32
+F:	drivers/clocksource/armv7m_systick.c
+
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  15/15] MAINTAINERS: Add entry for STM32 MCUs
@ 2015-03-12 21:56   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api,
	mcoquelin.stm32

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Add a MAINTAINER entry covering all STM32 machine and drivers files.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ddc5a8c..08c08c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1467,6 +1467,14 @@ F:	drivers/usb/host/ehci-st.c
 F:	drivers/usb/host/ohci-st.c
 F:	drivers/ata/ahci_st.c
 
+ARM/STM32 ARCHITECTURE
+M:	Maxime Coquelin <mcoquelin.stm32@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+N:	stm32
+F:	drivers/clocksource/armv7m_systick.c
+
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 136+ messages in thread

* [PATCH v3  15/15] MAINTAINERS: Add entry for STM32 MCUs
@ 2015-03-12 21:56   ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-12 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Add a MAINTAINER entry covering all STM32 machine and drivers files.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ddc5a8c..08c08c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1467,6 +1467,14 @@ F:	drivers/usb/host/ehci-st.c
 F:	drivers/usb/host/ohci-st.c
 F:	drivers/ata/ahci_st.c
 
+ARM/STM32 ARCHITECTURE
+M:	Maxime Coquelin <mcoquelin.stm32@gmail.com>
+L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+N:	stm32
+F:	drivers/clocksource/armv7m_systick.c
+
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-12 23:45   ` Chanwoo Choi
  -1 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-12 23:45 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

Dear Maxime,

I'm working for STM32 SoC. So, I'm very interesting in this patch-set.
If you possible, please add me to Cc list on next patch-set.

Best Regards,
Chanwoo Choi


On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 


^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-12 23:45   ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-12 23:45 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

Dear Maxime,

I'm working for STM32 SoC. So, I'm very interesting in this patch-set.
If you possible, please add me to Cc list on next patch-set.

Best Regards,
Chanwoo Choi


On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-12 23:45   ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-12 23:45 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Maxime,

I'm working for STM32 SoC. So, I'm very interesting in this patch-set.
If you possible, please add me to Cc list on next patch-set.

Best Regards,
Chanwoo Choi


On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
  2015-03-12 21:55   ` Maxime Coquelin
  (?)
@ 2015-03-13  0:09     ` Chanwoo Choi
  -1 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:09 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset@40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.
> +
> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:
> + - gpioa: 128
> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31
> +
> 

Last line is un-necessary. When I applied this patch for test
"new blank line at EOF" happen.

+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -99,4 +99,3 @@ List of indexes for STM32F429:
  - spi6: 309
  - sai1: 310
  - ltdc: 31
-

Thanks,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-13  0:09     ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:09 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset@40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.
> +
> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:
> + - gpioa: 128
> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31
> +
> 

Last line is un-necessary. When I applied this patch for test
"new blank line at EOF" happen.

+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -99,4 +99,3 @@ List of indexes for STM32F429:
  - spi6: 309
  - sai1: 310
  - ltdc: 31
-

Thanks,
Chanwoo Choi


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-13  0:09     ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset at 40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.
> +
> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:
> + - gpioa: 128
> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31
> +
> 

Last line is un-necessary. When I applied this patch for test
"new blank line at EOF" happen.

+++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
@@ -99,4 +99,3 @@ List of indexes for STM32F429:
  - spi6: 309
  - sai1: 310
  - ltdc: 31
-

Thanks,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
  2015-03-12 21:55   ` Maxime Coquelin
  (?)
@ 2015-03-13  0:11     ` Chanwoo Choi
  -1 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:11 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +
> 

Last blank line is un-necessary. When I applied this patch for test,
"new blank line at EOF" happen.

Thanks,
Chanwoo Choi



^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-13  0:11     ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:11 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +
> 

Last blank line is un-necessary. When I applied this patch for test,
"new blank line at EOF" happen.

Thanks,
Chanwoo Choi



^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-13  0:11     ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-13  0:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +
> 

Last blank line is un-necessary. When I applied this patch for test,
"new blank line at EOF" happen.

Thanks,
Chanwoo Choi

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
  2015-03-12 21:55   ` Maxime Coquelin
  (?)
@ 2015-03-13  8:50     ` Philipp Zabel
  -1 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:50 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Linus Walleij,
	Arnd Bergmann, stefan, pmeerw, pebolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon

Hi Maxime,

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset@40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.

Using a single value as index is ok, but it should be documented how
this corresponds to the register and bit offsets in the reference
manual.
Maybe add a comment that the index is in fact the register offset / 4 *
32 + bit offset in that register and that not all registers are
dedicated to the rest controller? Otherwise it is confusing (to me at
least) that the indices start at some arbitrary value.

> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:

"List of valid indices", to point out that any other index is invalid?

> + - gpioa: 128

I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...

> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31

That last one should say "ltdc: 314", right?

regards
Philipp


^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-13  8:50     ` Philipp Zabel
  0 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:50 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Linus Walleij,
	Arnd Bergmann, stefan, pmeerw, pebolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, linux-arch, linux-api

Hi Maxime,

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset@40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.

Using a single value as index is ok, but it should be documented how
this corresponds to the register and bit offsets in the reference
manual.
Maybe add a comment that the index is in fact the register offset / 4 *
32 + bit offset in that register and that not all registers are
dedicated to the rest controller? Otherwise it is confusing (to me at
least) that the indices start at some arbitrary value.

> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:

"List of valid indices", to point out that any other index is invalid?

> + - gpioa: 128

I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...

> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31

That last one should say "ltdc: 314", right?

regards
Philipp


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-13  8:50     ` Philipp Zabel
  0 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This adds documentation of device tree bindings for the
> STM32 reset controller.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> 
> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..962f961
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -0,0 +1,102 @@
> +STMicroelectronics STM32 Peripheral Reset Controller
> +====================================================
> +
> +The RCC IP is both a reset and a clock controller. This documentation only
> +document the reset part.
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: Should be "st,stm32-rcc"
> +- reg: should be register base and length as documented in the
> +  datasheet
> +- #reset-cells: 1, see below
> +
> +example:
> +
> +rcc: reset at 40023800 {
> +	#reset-cells = <1>;
> +	compatible = "st,stm32-rcc";
> +	reg = <0x40023800 0x400>;
> +};
> +
> +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.

Using a single value as index is ok, but it should be documented how
this corresponds to the register and bit offsets in the reference
manual.
Maybe add a comment that the index is in fact the register offset / 4 *
32 + bit offset in that register and that not all registers are
dedicated to the rest controller? Otherwise it is confusing (to me at
least) that the indices start at some arbitrary value.

> +example:
> +
> +	timer2 {
> +		resets			= <&rcc 256>;
> +	};
> +
> +List of indexes for STM32F429:

"List of valid indices", to point out that any other index is invalid?

> + - gpioa: 128

I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...

> + - gpiob: 129
> + - gpioc: 130
> + - gpiod: 131
> + - gpioe: 132
> + - gpiof: 133
> + - gpiog: 134
> + - gpioh: 135
> + - gpioi: 136
> + - gpioj: 137
> + - gpiok: 138
> + - crc: 140
> + - dma1: 149
> + - dma2: 150
> + - dma2d: 151
> + - ethmac: 153
> + - otghs: 157
> + - dcmi: 160
> + - cryp: 164
> + - hash: 165
> + - rng: 166
> + - otgfs: 167
> + - fmc: 192
> + - tim2: 256
> + - tim3: 257
> + - tim4: 258
> + - tim5: 259
> + - tim6: 260
> + - tim7: 261
> + - tim12: 262
> + - tim13: 263
> + - tim14: 264
> + - wwdg: 267
> + - spi2: 270
> + - spi3: 271
> + - uart2: 273
> + - uart3: 274
> + - uart4: 275
> + - uart5: 276
> + - i2c1: 277
> + - i2c2: 278
> + - i2c3: 279
> + - can1: 281
> + - can2: 282
> + - pwr: 284
> + - dac: 285
> + - uart7: 286
> + - uart8: 287
> + - tim1: 288
> + - tim8: 289
> + - usart1: 292
> + - usart6: 293
> + - adc: 296
> + - sdio: 299
> + - spi1: 300
> + - spi4: 301
> + - syscfg: 302
> + - tim9: 304
> + - tim10: 305
> + - tim11: 306
> + - spi5: 308
> + - spi6: 309
> + - sai1: 310
> + - ltdc: 31

That last one should say "ltdc: 314", right?

regards
Philipp

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
  2015-03-12 21:55   ` Maxime Coquelin
  (?)
@ 2015-03-13  8:54     ` Philipp Zabel
  -1 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:54 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Linus Walleij,
	Arnd Bergmann, stefan, pmeerw, pebolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.

But this is a regular driver now, should this comment be updated?

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +

regards
Philipp


^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-13  8:54     ` Philipp Zabel
  0 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:54 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Linus Walleij,
	Arnd Bergmann, stefan, pmeerw, pebolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, linux-arch, linux-api

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.

But this is a regular driver now, should this comment be updated?

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +

regards
Philipp


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-13  8:54     ` Philipp Zabel
  0 siblings, 0 replies; 136+ messages in thread
From: Philipp Zabel @ 2015-03-13  8:54 UTC (permalink / raw)
  To: linux-arm-kernel

Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> The STM32 MCUs family IP can be reset by accessing some shared registers.
> 
> The specificity is that some reset lines are used by the timers.
> At timer initialization time, the timer has to be reset, that's why
> we cannot use a regular driver.

But this is a regular driver now, should this comment be updated?

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/reset/Makefile      |   1 +
>  drivers/reset/reset-stm32.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100644 drivers/reset/reset-stm32.c
> 
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 157d421..aed12d1 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_RESET_CONTROLLER) += core.o
>  obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
>  obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
> +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
>  obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
>  obj-$(CONFIG_ARCH_STI) += sti/
> diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
> new file mode 100644
> index 0000000..0d389b1
> --- /dev/null
> +++ b/drivers/reset/reset-stm32.c
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Heavily based on sunxi driver from Maxime Ripard.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +struct stm32_reset_data {
> +	spinlock_t			lock;
> +	void __iomem			*membase;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static int stm32_reset_assert(struct reset_controller_dev *rcdev,
> +			      unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
> +				unsigned long id)
> +{
> +	struct stm32_reset_data *data = container_of(rcdev,
> +						     struct stm32_reset_data,
> +						     rcdev);
> +	int bank = id / BITS_PER_LONG;
> +	int offset = id % BITS_PER_LONG;
> +	unsigned long flags;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&data->lock, flags);
> +
> +	reg = readl_relaxed(data->membase + (bank * 4));
> +	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
> +
> +	spin_unlock_irqrestore(&data->lock, flags);
> +
> +	return 0;
> +}
> +
> +static struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,
> +};
> +
> +static const struct of_device_id stm32_reset_dt_ids[] = {
> +	 { .compatible = "st,stm32-rcc", },
> +	 { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
> +
> +static int stm32_reset_probe(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data;
> +	struct resource *res;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	spin_lock_init(&data->lock);
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = resource_size(res) * 8;
> +	data->rcdev.ops = &stm32_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	return reset_controller_register(&data->rcdev);
> +}
> +
> +static int stm32_reset_remove(struct platform_device *pdev)
> +{
> +	struct stm32_reset_data *data = platform_get_drvdata(pdev);
> +
> +	reset_controller_unregister(&data->rcdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_reset_driver = {
> +	.probe	= stm32_reset_probe,
> +	.remove	= stm32_reset_remove,
> +	.driver = {
> +		.name		= "stm32-rcc-reset",
> +		.of_match_table	= stm32_reset_dt_ids,
> +	},
> +};
> +module_platform_driver(stm32_reset_driver);
> +
> +MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@gmail.com>");
> +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
> +MODULE_LICENSE("GPL");
> +

regards
Philipp

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-12 21:55     ` Maxime Coquelin
  (?)
@ 2015-03-13  9:41       ` Paul Bolle
  -1 siblings, 0 replies; 136+ messages in thread
From: Paul Bolle @ 2015-03-13  9:41 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon

Just a license nit, I'm afraid.

On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */

This states the license is GPL v2.

> +MODULE_LICENSE("GPL");

And
    MODULE_LICENSE("GPL v2");

would match that statement.


Paul Bolle


^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-13  9:41       ` Paul Bolle
  0 siblings, 0 replies; 136+ messages in thread
From: Paul Bolle @ 2015-03-13  9:41 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, linux-arch, linux-api

Just a license nit, I'm afraid.

On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */

This states the license is GPL v2.

> +MODULE_LICENSE("GPL");

And
    MODULE_LICENSE("GPL v2");

would match that statement.


Paul Bolle


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-13  9:41       ` Paul Bolle
  0 siblings, 0 replies; 136+ messages in thread
From: Paul Bolle @ 2015-03-13  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Just a license nit, I'm afraid.

On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */

This states the license is GPL v2.

> +MODULE_LICENSE("GPL");

And
    MODULE_LICENSE("GPL v2");

would match that statement.


Paul Bolle

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-12 21:55     ` Maxime Coquelin
  (?)
@ 2015-03-13 14:19       ` Andy Shevchenko
  -1 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-13 14:19 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, Geert Uytterhoeven, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan, pmeerw,
	pebolle, Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari

On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

My comment below.

>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>           with "earlycon" on the kernel command line. The console is
>           enabled when early_param is processed.
>
> +config SERIAL_STM32
> +       tristate "STMicroelectronics STM32 serial port support"
> +       select SERIAL_CORE
> +       depends on ARM || COMPILE_TEST
> +       help
> +         This driver is for the on-chip Serial Controller on
> +         STMicroelectronics STM32 MCUs.
> +         USART supports Rx & Tx functionality.
> +         It support all industry standard baud rates.
> +
> +         If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +       bool "Support for console on STM32"
> +       depends on SERIAL_STM32=y
> +       select SERIAL_CORE_CONSOLE
> +
>  endmenu
>
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR               0x00
> +#define USART_DR               0x04
> +#define USART_BRR              0x08
> +#define USART_CR1              0x0c
> +#define USART_CR2              0x10
> +#define USART_CR3              0x14
> +#define USART_GTPR             0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE            BIT(0)
> +#define USART_SR_FE            BIT(1)
> +#define USART_SR_NF            BIT(2)
> +#define USART_SR_ORE           BIT(3)
> +#define USART_SR_IDLE          BIT(4)
> +#define USART_SR_RXNE          BIT(5)
> +#define USART_SR_TC            BIT(6)
> +#define USART_SR_TXE           BIT(7)
> +#define USART_SR_LBD           BIT(8)
> +#define USART_SR_CTS           BIT(9)
> +#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
> +                                USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX      BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK          GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT  4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK          BIT(0)
> +#define USART_CR1_RWU          BIT(1)
> +#define USART_CR1_RE           BIT(2)
> +#define USART_CR1_TE           BIT(3)
> +#define USART_CR1_IDLEIE       BIT(4)
> +#define USART_CR1_RXNEIE       BIT(5)
> +#define USART_CR1_TCIE         BIT(6)
> +#define USART_CR1_TXEIE                BIT(7)
> +#define USART_CR1_PEIE         BIT(8)
> +#define USART_CR1_PS           BIT(9)
> +#define USART_CR1_PCE          BIT(10)
> +#define USART_CR1_WAKE         BIT(11)
> +#define USART_CR1_M            BIT(12)
> +#define USART_CR1_UE           BIT(13)
> +#define USART_CR1_OVER8                BIT(15)
> +#define USART_CR1_IE_MASK      GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK     GENMASK(3, 0)
> +#define USART_CR2_LBDL         BIT(5)
> +#define USART_CR2_LBDIE                BIT(6)
> +#define USART_CR2_LBCL         BIT(8)
> +#define USART_CR2_CPHA         BIT(9)
> +#define USART_CR2_CPOL         BIT(10)
> +#define USART_CR2_CLKEN                BIT(11)
> +#define USART_CR2_STOP_2B      BIT(13)
> +#define USART_CR2_STOP_MASK    GENMASK(13, 12)
> +#define USART_CR2_LINEN                BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE          BIT(0)
> +#define USART_CR3_IREN         BIT(1)
> +#define USART_CR3_IRLP         BIT(2)
> +#define USART_CR3_HDSEL                BIT(3)
> +#define USART_CR3_NACK         BIT(4)
> +#define USART_CR3_SCEN         BIT(5)
> +#define USART_CR3_DMAR         BIT(6)
> +#define USART_CR3_DMAT         BIT(7)
> +#define USART_CR3_RTSE         BIT(8)
> +#define USART_CR3_CTSE         BIT(9)
> +#define USART_CR3_CTSIE                BIT(10)
> +#define USART_CR3_ONEBIT       BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK     GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +       struct uart_port port;
> +       struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val |= bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val &= ~bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +       struct tty_port *tport = &port->state->port;
> +       unsigned long c;
> +       u32 sr;
> +       char flag;
> +
> +       if (port->irq_wake)
> +               pm_wakeup_event(tport->tty->dev, 0);
> +
> +       while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +               sr |= USART_SR_DUMMY_RX;
> +               c = readl_relaxed(port->membase + USART_DR);
> +               flag = TTY_NORMAL;
> +               port->icount.rx++;
> +
> +               if (sr & USART_SR_ERR_MASK) {
> +                       if (sr & USART_SR_LBD) {
> +                               port->icount.brk++;
> +                               if (uart_handle_break(port))
> +                                       continue;
> +                       } else if (sr & USART_SR_ORE) {
> +                               port->icount.overrun++;
> +                       } else if (sr & USART_SR_PE) {
> +                               port->icount.parity++;
> +                       } else if (sr & USART_SR_FE) {
> +                               port->icount.frame++;
> +                       }
> +
> +                       sr &= port->read_status_mask;
> +
> +                       if (sr & USART_SR_LBD)
> +                               flag = TTY_BREAK;
> +                       else if (sr & USART_SR_PE)
> +                               flag = TTY_PARITY;
> +                       else if (sr & USART_SR_FE)
> +                               flag = TTY_FRAME;
> +               }
> +
> +               if (uart_handle_sysrq_char(port, c))
> +                       continue;
> +               uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +       }
> +
> +       spin_unlock(&port->lock);
> +       tty_flip_buffer_push(tport);
> +       spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (port->x_char) {
> +               writel_relaxed(port->x_char, port->membase + USART_DR);
> +               port->x_char = 0;
> +               port->icount.tx++;
> +               return;
> +       }
> +
> +       if (uart_tx_stopped(port)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       if (uart_circ_empty(xmit)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +       port->icount.tx++;
> +
> +       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +               uart_write_wakeup(port);
> +
> +       if (uart_circ_empty(xmit))
> +               stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +       struct uart_port *port = ptr;
> +       u32 sr;
> +
> +       spin_lock(&port->lock);
> +
> +       sr = readl_relaxed(port->membase + USART_SR);
> +
> +       if (sr & USART_SR_RXNE)
> +               stm32_receive_chars(port);
> +
> +       if (sr & USART_SR_TXE)
> +               stm32_transmit_chars(port);
> +
> +       spin_unlock(&port->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +       return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +       /*
> +        * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +        * We use USART's hardware for CTS/RTS, so don't need any for that.
> +        * Some boards have DTR and DCD implemented using PIO pins,
> +        * code to do this should be hooked in here.
> +        */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +       /*
> +        * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +        * and CTS/RTS
> +        */
> +       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (uart_circ_empty(xmit))
> +               return;
> +
> +       stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +       /* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +       const char *name = to_platform_device(port->dev)->name;
> +       u32 val;
> +
> +       if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +                               name, port)) {
> +               dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +               return -ENODEV;
> +       }
> +
> +       val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +       u32 val;
> +
> +       val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +                           struct ktermios *old)
> +{
> +       unsigned int baud;
> +       u32 usardiv, mantissa, fraction;
> +       tcflag_t cflag;
> +       u32 cr1, cr2, cr3;
> +       unsigned long flags;
> +
> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +       cflag = termios->c_cflag;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* Stop serial port and reset value */
> +       writel_relaxed(0, port->membase + USART_CR1);
> +
> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +       if (cflag & CSTOPB)
> +               cr2 = USART_CR2_STOP_2B;
> +
> +       if (cflag & PARENB) {
> +               cr1 |= USART_CR1_PCE;
> +               if ((cflag & CSIZE) == CS8)
> +                       cr1 |= USART_CR1_M;
> +       }
> +
> +       if (cflag & PARODD)
> +               cr1 |= USART_CR1_PS;
> +
> +       if (cflag & CRTSCTS)
> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
> +
> +       usardiv = (port->uartclk * 25) / (baud * 4);
> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
> +               fraction = 0;
> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +       }

So, it's a fractional divider. right? Could it be then fractional
divider clock in this first place (see
drivers/clk/clk-fractional-divider.c)?

> +
> +       writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +       uart_update_timeout(port, cflag, baud);
> +
> +       port->read_status_mask = USART_SR_ORE;
> +       if (termios->c_iflag & INPCK)
> +               port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +               port->read_status_mask |= USART_SR_LBD;
> +
> +       /* Characters to ignore */
> +       port->ignore_status_mask = 0;
> +       if (termios->c_iflag & IGNPAR)
> +               port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & IGNBRK) {
> +               port->ignore_status_mask |= USART_SR_LBD;
> +               /*
> +                * If we're ignoring parity and break indicators,
> +                * ignore overruns too (for real raw support).
> +                */
> +               if (termios->c_iflag & IGNPAR)
> +                       port->ignore_status_mask |= USART_SR_ORE;
> +       }
> +
> +       /*
> +        * Ignore all characters if CREAD is not set.
> +        */
> +       if ((termios->c_cflag & CREAD) == 0)
> +               port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +       writel_relaxed(cr3, port->membase + USART_CR3);
> +       writel_relaxed(cr2, port->membase + USART_CR2);
> +       writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +       return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +       return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +       if ((flags & UART_CONFIG_TYPE))
> +               port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +       /* No user changeable parameters */
> +       return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +               unsigned int oldstate)
> +{
> +       struct stm32_port *stm32port = container_of(port,
> +                       struct stm32_port, port);
> +       unsigned long flags = 0;
> +
> +       switch (state) {
> +       case UART_PM_STATE_ON:
> +               clk_prepare_enable(stm32port->clk);
> +               break;
> +       case UART_PM_STATE_OFF:
> +               spin_lock_irqsave(&port->lock, flags);
> +               stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               clk_disable_unprepare(stm32port->clk);
> +               break;
> +       }
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +       .tx_empty       = stm32_tx_empty,
> +       .set_mctrl      = stm32_set_mctrl,
> +       .get_mctrl      = stm32_get_mctrl,
> +       .start_tx       = stm32_start_tx,
> +       .stop_tx        = stm32_stop_tx,
> +       .stop_rx        = stm32_stop_rx,
> +       .break_ctl      = stm32_break_ctl,
> +       .startup        = stm32_startup,
> +       .shutdown       = stm32_shutdown,
> +       .set_termios    = stm32_set_termios,
> +       .type           = stm32_type,
> +       .release_port   = stm32_release_port,
> +       .request_port   = stm32_request_port,
> +       .config_port    = stm32_config_port,
> +       .verify_port    = stm32_verify_port,
> +       .pm             = stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +                         struct platform_device *pdev)
> +{
> +       struct uart_port *port = &stm32port->port;
> +       struct resource *res;
> +
> +       port->iotype    = UPIO_MEM;
> +       port->flags     = UPF_BOOT_AUTOCONF;
> +       port->ops       = &stm32_uart_ops;
> +       port->dev       = &pdev->dev;
> +       port->irq       = platform_get_irq(pdev, 0);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       port->membase = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(port->membase))
> +               return PTR_ERR(port->membase);
> +       port->mapbase = res->start;
> +
> +       spin_lock_init(&port->lock);
> +
> +       stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +       WARN_ON(stm32port->port.uartclk == 0);
> +       clk_disable_unprepare(stm32port->clk);
> +
> +       return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       int id;
> +
> +       if (!np)
> +               return NULL;
> +
> +       id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +       if (id < 0)
> +               id = 0;
> +
> +       if (WARN_ON(id >= STM32_MAX_PORTS))
> +               return NULL;
> +
> +       stm32_ports[id].port.line = id;
> +       return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +       { .compatible = "st,stm32-usart", },
> +       {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct stm32_port *stm32port;
> +
> +       stm32port = stm32_of_get_stm32_port(pdev);
> +       if (!stm32port)
> +               return -ENODEV;
> +
> +       ret = stm32_init_port(stm32port, pdev);
> +       if (ret)
> +               return ret;
> +
> +       ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +       if (ret)
> +               return ret;
> +
> +       platform_set_drvdata(pdev, &stm32port->port);
> +
> +       return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +       struct uart_port *port = platform_get_drvdata(pdev);
> +
> +       return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +       while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +               cpu_relax();
> +
> +       writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +       struct uart_port *port = &stm32_ports[co->index].port;
> +       unsigned long flags;
> +       u32 old_cr1, new_cr1;
> +       int locked = 1;
> +
> +       if (oops_in_progress) {
> +               locked = spin_trylock_irqsave(&port->lock, flags);
> +       } else {
> +               locked = 1;
> +               spin_lock_irqsave(&port->lock, flags);
> +       }
> +
> +       /* Save and disable interrupts */
> +       old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +       new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +       writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +       uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +       /* Restore interrupt state */
> +       writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +       if (locked)
> +               spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +       struct stm32_port *stm32port;
> +       int baud = 9600;
> +       int bits = 8;
> +       int parity = 'n';
> +       int flow = 'n';
> +
> +       if (co->index >= STM32_MAX_PORTS)
> +               return -ENODEV;
> +
> +       stm32port = &stm32_ports[co->index];
> +
> +       /*
> +        * This driver does not support early console initialization
> +        * (use ARM early printk support instead), so we only expect
> +        * this to be called during the uart port registration when the
> +        * driver gets probed and the port should be mapped at that point.
> +        */
> +       if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +               return -ENXIO;
> +
> +       if (options)
> +               uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +       return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +       .name           = STM32_SERIAL_NAME,
> +       .device         = uart_console_device,
> +       .write          = stm32_console_write,
> +       .setup          = stm32_console_setup,
> +       .flags          = CON_PRINTBUFFER,
> +       .index          = -1,
> +       .data           = &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +       .owner          = THIS_MODULE,
> +       .driver_name    = DRIVER_NAME,
> +       .dev_name       = STM32_SERIAL_NAME,
> +       .major          = 0,
> +       .minor          = 0,
> +       .nr             = STM32_MAX_PORTS,
> +       .cons           = STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +       .probe          = stm32_serial_probe,
> +       .remove         = stm32_serial_remove,
> +       .driver = {
> +               .name   = DRIVER_NAME,
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(stm32_match),
> +       },
> +};
> +
> +static int __init usart_init(void)
> +{
> +       int ret;
> +       static char banner[] __initdata =
> +               KERN_INFO "STM32 USART driver initialized\n";
> +
> +       printk(banner);
> +
> +       ret = uart_register_driver(&stm32_usart_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&stm32_serial_driver);
> +       if (ret)
> +               uart_unregister_driver(&stm32_usart_driver);
> +
> +       return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +       platform_driver_unregister(&stm32_serial_driver);
> +       uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS      112
>
> +/* STM32 USART */
> +#define PORT_STM32     110
> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-13 14:19       ` Andy Shevchenko
  0 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-13 14:19 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, Geert Uytterhoeven, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan, pmeerw,
	pebolle, Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, Linux Documentation List, linux-arm Mailing List,
	linux-kernel, devicetree, linux-gpio, linux-serial, linux-arch,
	linux-api

On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

My comment below.

>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>           with "earlycon" on the kernel command line. The console is
>           enabled when early_param is processed.
>
> +config SERIAL_STM32
> +       tristate "STMicroelectronics STM32 serial port support"
> +       select SERIAL_CORE
> +       depends on ARM || COMPILE_TEST
> +       help
> +         This driver is for the on-chip Serial Controller on
> +         STMicroelectronics STM32 MCUs.
> +         USART supports Rx & Tx functionality.
> +         It support all industry standard baud rates.
> +
> +         If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +       bool "Support for console on STM32"
> +       depends on SERIAL_STM32=y
> +       select SERIAL_CORE_CONSOLE
> +
>  endmenu
>
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR               0x00
> +#define USART_DR               0x04
> +#define USART_BRR              0x08
> +#define USART_CR1              0x0c
> +#define USART_CR2              0x10
> +#define USART_CR3              0x14
> +#define USART_GTPR             0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE            BIT(0)
> +#define USART_SR_FE            BIT(1)
> +#define USART_SR_NF            BIT(2)
> +#define USART_SR_ORE           BIT(3)
> +#define USART_SR_IDLE          BIT(4)
> +#define USART_SR_RXNE          BIT(5)
> +#define USART_SR_TC            BIT(6)
> +#define USART_SR_TXE           BIT(7)
> +#define USART_SR_LBD           BIT(8)
> +#define USART_SR_CTS           BIT(9)
> +#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
> +                                USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX      BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK          GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT  4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK          BIT(0)
> +#define USART_CR1_RWU          BIT(1)
> +#define USART_CR1_RE           BIT(2)
> +#define USART_CR1_TE           BIT(3)
> +#define USART_CR1_IDLEIE       BIT(4)
> +#define USART_CR1_RXNEIE       BIT(5)
> +#define USART_CR1_TCIE         BIT(6)
> +#define USART_CR1_TXEIE                BIT(7)
> +#define USART_CR1_PEIE         BIT(8)
> +#define USART_CR1_PS           BIT(9)
> +#define USART_CR1_PCE          BIT(10)
> +#define USART_CR1_WAKE         BIT(11)
> +#define USART_CR1_M            BIT(12)
> +#define USART_CR1_UE           BIT(13)
> +#define USART_CR1_OVER8                BIT(15)
> +#define USART_CR1_IE_MASK      GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK     GENMASK(3, 0)
> +#define USART_CR2_LBDL         BIT(5)
> +#define USART_CR2_LBDIE                BIT(6)
> +#define USART_CR2_LBCL         BIT(8)
> +#define USART_CR2_CPHA         BIT(9)
> +#define USART_CR2_CPOL         BIT(10)
> +#define USART_CR2_CLKEN                BIT(11)
> +#define USART_CR2_STOP_2B      BIT(13)
> +#define USART_CR2_STOP_MASK    GENMASK(13, 12)
> +#define USART_CR2_LINEN                BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE          BIT(0)
> +#define USART_CR3_IREN         BIT(1)
> +#define USART_CR3_IRLP         BIT(2)
> +#define USART_CR3_HDSEL                BIT(3)
> +#define USART_CR3_NACK         BIT(4)
> +#define USART_CR3_SCEN         BIT(5)
> +#define USART_CR3_DMAR         BIT(6)
> +#define USART_CR3_DMAT         BIT(7)
> +#define USART_CR3_RTSE         BIT(8)
> +#define USART_CR3_CTSE         BIT(9)
> +#define USART_CR3_CTSIE                BIT(10)
> +#define USART_CR3_ONEBIT       BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK     GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +       struct uart_port port;
> +       struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val |= bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val &= ~bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +       struct tty_port *tport = &port->state->port;
> +       unsigned long c;
> +       u32 sr;
> +       char flag;
> +
> +       if (port->irq_wake)
> +               pm_wakeup_event(tport->tty->dev, 0);
> +
> +       while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +               sr |= USART_SR_DUMMY_RX;
> +               c = readl_relaxed(port->membase + USART_DR);
> +               flag = TTY_NORMAL;
> +               port->icount.rx++;
> +
> +               if (sr & USART_SR_ERR_MASK) {
> +                       if (sr & USART_SR_LBD) {
> +                               port->icount.brk++;
> +                               if (uart_handle_break(port))
> +                                       continue;
> +                       } else if (sr & USART_SR_ORE) {
> +                               port->icount.overrun++;
> +                       } else if (sr & USART_SR_PE) {
> +                               port->icount.parity++;
> +                       } else if (sr & USART_SR_FE) {
> +                               port->icount.frame++;
> +                       }
> +
> +                       sr &= port->read_status_mask;
> +
> +                       if (sr & USART_SR_LBD)
> +                               flag = TTY_BREAK;
> +                       else if (sr & USART_SR_PE)
> +                               flag = TTY_PARITY;
> +                       else if (sr & USART_SR_FE)
> +                               flag = TTY_FRAME;
> +               }
> +
> +               if (uart_handle_sysrq_char(port, c))
> +                       continue;
> +               uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +       }
> +
> +       spin_unlock(&port->lock);
> +       tty_flip_buffer_push(tport);
> +       spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (port->x_char) {
> +               writel_relaxed(port->x_char, port->membase + USART_DR);
> +               port->x_char = 0;
> +               port->icount.tx++;
> +               return;
> +       }
> +
> +       if (uart_tx_stopped(port)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       if (uart_circ_empty(xmit)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +       port->icount.tx++;
> +
> +       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +               uart_write_wakeup(port);
> +
> +       if (uart_circ_empty(xmit))
> +               stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +       struct uart_port *port = ptr;
> +       u32 sr;
> +
> +       spin_lock(&port->lock);
> +
> +       sr = readl_relaxed(port->membase + USART_SR);
> +
> +       if (sr & USART_SR_RXNE)
> +               stm32_receive_chars(port);
> +
> +       if (sr & USART_SR_TXE)
> +               stm32_transmit_chars(port);
> +
> +       spin_unlock(&port->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +       return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +       /*
> +        * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +        * We use USART's hardware for CTS/RTS, so don't need any for that.
> +        * Some boards have DTR and DCD implemented using PIO pins,
> +        * code to do this should be hooked in here.
> +        */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +       /*
> +        * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +        * and CTS/RTS
> +        */
> +       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (uart_circ_empty(xmit))
> +               return;
> +
> +       stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +       /* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +       const char *name = to_platform_device(port->dev)->name;
> +       u32 val;
> +
> +       if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +                               name, port)) {
> +               dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +               return -ENODEV;
> +       }
> +
> +       val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +       u32 val;
> +
> +       val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +                           struct ktermios *old)
> +{
> +       unsigned int baud;
> +       u32 usardiv, mantissa, fraction;
> +       tcflag_t cflag;
> +       u32 cr1, cr2, cr3;
> +       unsigned long flags;
> +
> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +       cflag = termios->c_cflag;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* Stop serial port and reset value */
> +       writel_relaxed(0, port->membase + USART_CR1);
> +
> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +       if (cflag & CSTOPB)
> +               cr2 = USART_CR2_STOP_2B;
> +
> +       if (cflag & PARENB) {
> +               cr1 |= USART_CR1_PCE;
> +               if ((cflag & CSIZE) == CS8)
> +                       cr1 |= USART_CR1_M;
> +       }
> +
> +       if (cflag & PARODD)
> +               cr1 |= USART_CR1_PS;
> +
> +       if (cflag & CRTSCTS)
> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
> +
> +       usardiv = (port->uartclk * 25) / (baud * 4);
> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
> +               fraction = 0;
> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +       }

So, it's a fractional divider. right? Could it be then fractional
divider clock in this first place (see
drivers/clk/clk-fractional-divider.c)?

> +
> +       writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +       uart_update_timeout(port, cflag, baud);
> +
> +       port->read_status_mask = USART_SR_ORE;
> +       if (termios->c_iflag & INPCK)
> +               port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +               port->read_status_mask |= USART_SR_LBD;
> +
> +       /* Characters to ignore */
> +       port->ignore_status_mask = 0;
> +       if (termios->c_iflag & IGNPAR)
> +               port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & IGNBRK) {
> +               port->ignore_status_mask |= USART_SR_LBD;
> +               /*
> +                * If we're ignoring parity and break indicators,
> +                * ignore overruns too (for real raw support).
> +                */
> +               if (termios->c_iflag & IGNPAR)
> +                       port->ignore_status_mask |= USART_SR_ORE;
> +       }
> +
> +       /*
> +        * Ignore all characters if CREAD is not set.
> +        */
> +       if ((termios->c_cflag & CREAD) == 0)
> +               port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +       writel_relaxed(cr3, port->membase + USART_CR3);
> +       writel_relaxed(cr2, port->membase + USART_CR2);
> +       writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +       return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +       return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +       if ((flags & UART_CONFIG_TYPE))
> +               port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +       /* No user changeable parameters */
> +       return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +               unsigned int oldstate)
> +{
> +       struct stm32_port *stm32port = container_of(port,
> +                       struct stm32_port, port);
> +       unsigned long flags = 0;
> +
> +       switch (state) {
> +       case UART_PM_STATE_ON:
> +               clk_prepare_enable(stm32port->clk);
> +               break;
> +       case UART_PM_STATE_OFF:
> +               spin_lock_irqsave(&port->lock, flags);
> +               stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               clk_disable_unprepare(stm32port->clk);
> +               break;
> +       }
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +       .tx_empty       = stm32_tx_empty,
> +       .set_mctrl      = stm32_set_mctrl,
> +       .get_mctrl      = stm32_get_mctrl,
> +       .start_tx       = stm32_start_tx,
> +       .stop_tx        = stm32_stop_tx,
> +       .stop_rx        = stm32_stop_rx,
> +       .break_ctl      = stm32_break_ctl,
> +       .startup        = stm32_startup,
> +       .shutdown       = stm32_shutdown,
> +       .set_termios    = stm32_set_termios,
> +       .type           = stm32_type,
> +       .release_port   = stm32_release_port,
> +       .request_port   = stm32_request_port,
> +       .config_port    = stm32_config_port,
> +       .verify_port    = stm32_verify_port,
> +       .pm             = stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +                         struct platform_device *pdev)
> +{
> +       struct uart_port *port = &stm32port->port;
> +       struct resource *res;
> +
> +       port->iotype    = UPIO_MEM;
> +       port->flags     = UPF_BOOT_AUTOCONF;
> +       port->ops       = &stm32_uart_ops;
> +       port->dev       = &pdev->dev;
> +       port->irq       = platform_get_irq(pdev, 0);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       port->membase = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(port->membase))
> +               return PTR_ERR(port->membase);
> +       port->mapbase = res->start;
> +
> +       spin_lock_init(&port->lock);
> +
> +       stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +       WARN_ON(stm32port->port.uartclk == 0);
> +       clk_disable_unprepare(stm32port->clk);
> +
> +       return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       int id;
> +
> +       if (!np)
> +               return NULL;
> +
> +       id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +       if (id < 0)
> +               id = 0;
> +
> +       if (WARN_ON(id >= STM32_MAX_PORTS))
> +               return NULL;
> +
> +       stm32_ports[id].port.line = id;
> +       return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +       { .compatible = "st,stm32-usart", },
> +       {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct stm32_port *stm32port;
> +
> +       stm32port = stm32_of_get_stm32_port(pdev);
> +       if (!stm32port)
> +               return -ENODEV;
> +
> +       ret = stm32_init_port(stm32port, pdev);
> +       if (ret)
> +               return ret;
> +
> +       ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +       if (ret)
> +               return ret;
> +
> +       platform_set_drvdata(pdev, &stm32port->port);
> +
> +       return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +       struct uart_port *port = platform_get_drvdata(pdev);
> +
> +       return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +       while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +               cpu_relax();
> +
> +       writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +       struct uart_port *port = &stm32_ports[co->index].port;
> +       unsigned long flags;
> +       u32 old_cr1, new_cr1;
> +       int locked = 1;
> +
> +       if (oops_in_progress) {
> +               locked = spin_trylock_irqsave(&port->lock, flags);
> +       } else {
> +               locked = 1;
> +               spin_lock_irqsave(&port->lock, flags);
> +       }
> +
> +       /* Save and disable interrupts */
> +       old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +       new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +       writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +       uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +       /* Restore interrupt state */
> +       writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +       if (locked)
> +               spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +       struct stm32_port *stm32port;
> +       int baud = 9600;
> +       int bits = 8;
> +       int parity = 'n';
> +       int flow = 'n';
> +
> +       if (co->index >= STM32_MAX_PORTS)
> +               return -ENODEV;
> +
> +       stm32port = &stm32_ports[co->index];
> +
> +       /*
> +        * This driver does not support early console initialization
> +        * (use ARM early printk support instead), so we only expect
> +        * this to be called during the uart port registration when the
> +        * driver gets probed and the port should be mapped at that point.
> +        */
> +       if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +               return -ENXIO;
> +
> +       if (options)
> +               uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +       return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +       .name           = STM32_SERIAL_NAME,
> +       .device         = uart_console_device,
> +       .write          = stm32_console_write,
> +       .setup          = stm32_console_setup,
> +       .flags          = CON_PRINTBUFFER,
> +       .index          = -1,
> +       .data           = &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +       .owner          = THIS_MODULE,
> +       .driver_name    = DRIVER_NAME,
> +       .dev_name       = STM32_SERIAL_NAME,
> +       .major          = 0,
> +       .minor          = 0,
> +       .nr             = STM32_MAX_PORTS,
> +       .cons           = STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +       .probe          = stm32_serial_probe,
> +       .remove         = stm32_serial_remove,
> +       .driver = {
> +               .name   = DRIVER_NAME,
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(stm32_match),
> +       },
> +};
> +
> +static int __init usart_init(void)
> +{
> +       int ret;
> +       static char banner[] __initdata =
> +               KERN_INFO "STM32 USART driver initialized\n";
> +
> +       printk(banner);
> +
> +       ret = uart_register_driver(&stm32_usart_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&stm32_serial_driver);
> +       if (ret)
> +               uart_unregister_driver(&stm32_usart_driver);
> +
> +       return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +       platform_driver_unregister(&stm32_serial_driver);
> +       uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS      112
>
> +/* STM32 USART */
> +#define PORT_STM32     110
> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-13 14:19       ` Andy Shevchenko
  0 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-13 14:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

My comment below.

>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>           with "earlycon" on the kernel command line. The console is
>           enabled when early_param is processed.
>
> +config SERIAL_STM32
> +       tristate "STMicroelectronics STM32 serial port support"
> +       select SERIAL_CORE
> +       depends on ARM || COMPILE_TEST
> +       help
> +         This driver is for the on-chip Serial Controller on
> +         STMicroelectronics STM32 MCUs.
> +         USART supports Rx & Tx functionality.
> +         It support all industry standard baud rates.
> +
> +         If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +       bool "Support for console on STM32"
> +       depends on SERIAL_STM32=y
> +       select SERIAL_CORE_CONSOLE
> +
>  endmenu
>
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR               0x00
> +#define USART_DR               0x04
> +#define USART_BRR              0x08
> +#define USART_CR1              0x0c
> +#define USART_CR2              0x10
> +#define USART_CR3              0x14
> +#define USART_GTPR             0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE            BIT(0)
> +#define USART_SR_FE            BIT(1)
> +#define USART_SR_NF            BIT(2)
> +#define USART_SR_ORE           BIT(3)
> +#define USART_SR_IDLE          BIT(4)
> +#define USART_SR_RXNE          BIT(5)
> +#define USART_SR_TC            BIT(6)
> +#define USART_SR_TXE           BIT(7)
> +#define USART_SR_LBD           BIT(8)
> +#define USART_SR_CTS           BIT(9)
> +#define USART_SR_ERR_MASK      (USART_SR_LBD | USART_SR_ORE | \
> +                                USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX      BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK          GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK   GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT  4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK          BIT(0)
> +#define USART_CR1_RWU          BIT(1)
> +#define USART_CR1_RE           BIT(2)
> +#define USART_CR1_TE           BIT(3)
> +#define USART_CR1_IDLEIE       BIT(4)
> +#define USART_CR1_RXNEIE       BIT(5)
> +#define USART_CR1_TCIE         BIT(6)
> +#define USART_CR1_TXEIE                BIT(7)
> +#define USART_CR1_PEIE         BIT(8)
> +#define USART_CR1_PS           BIT(9)
> +#define USART_CR1_PCE          BIT(10)
> +#define USART_CR1_WAKE         BIT(11)
> +#define USART_CR1_M            BIT(12)
> +#define USART_CR1_UE           BIT(13)
> +#define USART_CR1_OVER8                BIT(15)
> +#define USART_CR1_IE_MASK      GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK     GENMASK(3, 0)
> +#define USART_CR2_LBDL         BIT(5)
> +#define USART_CR2_LBDIE                BIT(6)
> +#define USART_CR2_LBCL         BIT(8)
> +#define USART_CR2_CPHA         BIT(9)
> +#define USART_CR2_CPOL         BIT(10)
> +#define USART_CR2_CLKEN                BIT(11)
> +#define USART_CR2_STOP_2B      BIT(13)
> +#define USART_CR2_STOP_MASK    GENMASK(13, 12)
> +#define USART_CR2_LINEN                BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE          BIT(0)
> +#define USART_CR3_IREN         BIT(1)
> +#define USART_CR3_IRLP         BIT(2)
> +#define USART_CR3_HDSEL                BIT(3)
> +#define USART_CR3_NACK         BIT(4)
> +#define USART_CR3_SCEN         BIT(5)
> +#define USART_CR3_DMAR         BIT(6)
> +#define USART_CR3_DMAT         BIT(7)
> +#define USART_CR3_RTSE         BIT(8)
> +#define USART_CR3_CTSE         BIT(9)
> +#define USART_CR3_CTSIE                BIT(10)
> +#define USART_CR3_ONEBIT       BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK    GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK     GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +       struct uart_port port;
> +       struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val |= bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +       u32 val;
> +
> +       val = readl_relaxed(port->membase + reg);
> +       val &= ~bits;
> +       writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +       struct tty_port *tport = &port->state->port;
> +       unsigned long c;
> +       u32 sr;
> +       char flag;
> +
> +       if (port->irq_wake)
> +               pm_wakeup_event(tport->tty->dev, 0);
> +
> +       while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +               sr |= USART_SR_DUMMY_RX;
> +               c = readl_relaxed(port->membase + USART_DR);
> +               flag = TTY_NORMAL;
> +               port->icount.rx++;
> +
> +               if (sr & USART_SR_ERR_MASK) {
> +                       if (sr & USART_SR_LBD) {
> +                               port->icount.brk++;
> +                               if (uart_handle_break(port))
> +                                       continue;
> +                       } else if (sr & USART_SR_ORE) {
> +                               port->icount.overrun++;
> +                       } else if (sr & USART_SR_PE) {
> +                               port->icount.parity++;
> +                       } else if (sr & USART_SR_FE) {
> +                               port->icount.frame++;
> +                       }
> +
> +                       sr &= port->read_status_mask;
> +
> +                       if (sr & USART_SR_LBD)
> +                               flag = TTY_BREAK;
> +                       else if (sr & USART_SR_PE)
> +                               flag = TTY_PARITY;
> +                       else if (sr & USART_SR_FE)
> +                               flag = TTY_FRAME;
> +               }
> +
> +               if (uart_handle_sysrq_char(port, c))
> +                       continue;
> +               uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +       }
> +
> +       spin_unlock(&port->lock);
> +       tty_flip_buffer_push(tport);
> +       spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (port->x_char) {
> +               writel_relaxed(port->x_char, port->membase + USART_DR);
> +               port->x_char = 0;
> +               port->icount.tx++;
> +               return;
> +       }
> +
> +       if (uart_tx_stopped(port)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       if (uart_circ_empty(xmit)) {
> +               stm32_stop_tx(port);
> +               return;
> +       }
> +
> +       writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +       port->icount.tx++;
> +
> +       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +               uart_write_wakeup(port);
> +
> +       if (uart_circ_empty(xmit))
> +               stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +       struct uart_port *port = ptr;
> +       u32 sr;
> +
> +       spin_lock(&port->lock);
> +
> +       sr = readl_relaxed(port->membase + USART_SR);
> +
> +       if (sr & USART_SR_RXNE)
> +               stm32_receive_chars(port);
> +
> +       if (sr & USART_SR_TXE)
> +               stm32_transmit_chars(port);
> +
> +       spin_unlock(&port->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +       return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +       /*
> +        * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +        * We use USART's hardware for CTS/RTS, so don't need any for that.
> +        * Some boards have DTR and DCD implemented using PIO pins,
> +        * code to do this should be hooked in here.
> +        */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +       /*
> +        * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +        * and CTS/RTS
> +        */
> +       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->state->xmit;
> +
> +       if (uart_circ_empty(xmit))
> +               return;
> +
> +       stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +       stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +       /* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +       const char *name = to_platform_device(port->dev)->name;
> +       u32 val;
> +
> +       if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +                               name, port)) {
> +               dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +               return -ENODEV;
> +       }
> +
> +       val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +       u32 val;
> +
> +       val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +       stm32_set_bits(port, USART_CR1, val);
> +
> +       free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +                           struct ktermios *old)
> +{
> +       unsigned int baud;
> +       u32 usardiv, mantissa, fraction;
> +       tcflag_t cflag;
> +       u32 cr1, cr2, cr3;
> +       unsigned long flags;
> +
> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +       cflag = termios->c_cflag;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* Stop serial port and reset value */
> +       writel_relaxed(0, port->membase + USART_CR1);
> +
> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +       if (cflag & CSTOPB)
> +               cr2 = USART_CR2_STOP_2B;
> +
> +       if (cflag & PARENB) {
> +               cr1 |= USART_CR1_PCE;
> +               if ((cflag & CSIZE) == CS8)
> +                       cr1 |= USART_CR1_M;
> +       }
> +
> +       if (cflag & PARODD)
> +               cr1 |= USART_CR1_PS;
> +
> +       if (cflag & CRTSCTS)
> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
> +
> +       usardiv = (port->uartclk * 25) / (baud * 4);
> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
> +               fraction = 0;
> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +       }

So, it's a fractional divider. right? Could it be then fractional
divider clock in this first place (see
drivers/clk/clk-fractional-divider.c)?

> +
> +       writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +       uart_update_timeout(port, cflag, baud);
> +
> +       port->read_status_mask = USART_SR_ORE;
> +       if (termios->c_iflag & INPCK)
> +               port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +               port->read_status_mask |= USART_SR_LBD;
> +
> +       /* Characters to ignore */
> +       port->ignore_status_mask = 0;
> +       if (termios->c_iflag & IGNPAR)
> +               port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +       if (termios->c_iflag & IGNBRK) {
> +               port->ignore_status_mask |= USART_SR_LBD;
> +               /*
> +                * If we're ignoring parity and break indicators,
> +                * ignore overruns too (for real raw support).
> +                */
> +               if (termios->c_iflag & IGNPAR)
> +                       port->ignore_status_mask |= USART_SR_ORE;
> +       }
> +
> +       /*
> +        * Ignore all characters if CREAD is not set.
> +        */
> +       if ((termios->c_cflag & CREAD) == 0)
> +               port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +       writel_relaxed(cr3, port->membase + USART_CR3);
> +       writel_relaxed(cr2, port->membase + USART_CR2);
> +       writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +       return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +       return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +       if ((flags & UART_CONFIG_TYPE))
> +               port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +       /* No user changeable parameters */
> +       return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +               unsigned int oldstate)
> +{
> +       struct stm32_port *stm32port = container_of(port,
> +                       struct stm32_port, port);
> +       unsigned long flags = 0;
> +
> +       switch (state) {
> +       case UART_PM_STATE_ON:
> +               clk_prepare_enable(stm32port->clk);
> +               break;
> +       case UART_PM_STATE_OFF:
> +               spin_lock_irqsave(&port->lock, flags);
> +               stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               clk_disable_unprepare(stm32port->clk);
> +               break;
> +       }
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +       .tx_empty       = stm32_tx_empty,
> +       .set_mctrl      = stm32_set_mctrl,
> +       .get_mctrl      = stm32_get_mctrl,
> +       .start_tx       = stm32_start_tx,
> +       .stop_tx        = stm32_stop_tx,
> +       .stop_rx        = stm32_stop_rx,
> +       .break_ctl      = stm32_break_ctl,
> +       .startup        = stm32_startup,
> +       .shutdown       = stm32_shutdown,
> +       .set_termios    = stm32_set_termios,
> +       .type           = stm32_type,
> +       .release_port   = stm32_release_port,
> +       .request_port   = stm32_request_port,
> +       .config_port    = stm32_config_port,
> +       .verify_port    = stm32_verify_port,
> +       .pm             = stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +                         struct platform_device *pdev)
> +{
> +       struct uart_port *port = &stm32port->port;
> +       struct resource *res;
> +
> +       port->iotype    = UPIO_MEM;
> +       port->flags     = UPF_BOOT_AUTOCONF;
> +       port->ops       = &stm32_uart_ops;
> +       port->dev       = &pdev->dev;
> +       port->irq       = platform_get_irq(pdev, 0);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       port->membase = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(port->membase))
> +               return PTR_ERR(port->membase);
> +       port->mapbase = res->start;
> +
> +       spin_lock_init(&port->lock);
> +
> +       stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +       WARN_ON(stm32port->port.uartclk == 0);
> +       clk_disable_unprepare(stm32port->clk);
> +
> +       return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       int id;
> +
> +       if (!np)
> +               return NULL;
> +
> +       id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +       if (id < 0)
> +               id = 0;
> +
> +       if (WARN_ON(id >= STM32_MAX_PORTS))
> +               return NULL;
> +
> +       stm32_ports[id].port.line = id;
> +       return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +       { .compatible = "st,stm32-usart", },
> +       {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct stm32_port *stm32port;
> +
> +       stm32port = stm32_of_get_stm32_port(pdev);
> +       if (!stm32port)
> +               return -ENODEV;
> +
> +       ret = stm32_init_port(stm32port, pdev);
> +       if (ret)
> +               return ret;
> +
> +       ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +       if (ret)
> +               return ret;
> +
> +       platform_set_drvdata(pdev, &stm32port->port);
> +
> +       return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +       struct uart_port *port = platform_get_drvdata(pdev);
> +
> +       return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +       while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +               cpu_relax();
> +
> +       writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +       struct uart_port *port = &stm32_ports[co->index].port;
> +       unsigned long flags;
> +       u32 old_cr1, new_cr1;
> +       int locked = 1;
> +
> +       if (oops_in_progress) {
> +               locked = spin_trylock_irqsave(&port->lock, flags);
> +       } else {
> +               locked = 1;
> +               spin_lock_irqsave(&port->lock, flags);
> +       }
> +
> +       /* Save and disable interrupts */
> +       old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +       new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +       writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +       uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +       /* Restore interrupt state */
> +       writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +       if (locked)
> +               spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +       struct stm32_port *stm32port;
> +       int baud = 9600;
> +       int bits = 8;
> +       int parity = 'n';
> +       int flow = 'n';
> +
> +       if (co->index >= STM32_MAX_PORTS)
> +               return -ENODEV;
> +
> +       stm32port = &stm32_ports[co->index];
> +
> +       /*
> +        * This driver does not support early console initialization
> +        * (use ARM early printk support instead), so we only expect
> +        * this to be called during the uart port registration when the
> +        * driver gets probed and the port should be mapped at that point.
> +        */
> +       if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +               return -ENXIO;
> +
> +       if (options)
> +               uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +       return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +       .name           = STM32_SERIAL_NAME,
> +       .device         = uart_console_device,
> +       .write          = stm32_console_write,
> +       .setup          = stm32_console_setup,
> +       .flags          = CON_PRINTBUFFER,
> +       .index          = -1,
> +       .data           = &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +       .owner          = THIS_MODULE,
> +       .driver_name    = DRIVER_NAME,
> +       .dev_name       = STM32_SERIAL_NAME,
> +       .major          = 0,
> +       .minor          = 0,
> +       .nr             = STM32_MAX_PORTS,
> +       .cons           = STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +       .probe          = stm32_serial_probe,
> +       .remove         = stm32_serial_remove,
> +       .driver = {
> +               .name   = DRIVER_NAME,
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(stm32_match),
> +       },
> +};
> +
> +static int __init usart_init(void)
> +{
> +       int ret;
> +       static char banner[] __initdata =
> +               KERN_INFO "STM32 USART driver initialized\n";
> +
> +       printk(banner);
> +
> +       ret = uart_register_driver(&stm32_usart_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&stm32_serial_driver);
> +       if (ret)
> +               uart_unregister_driver(&stm32_usart_driver);
> +
> +       return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +       platform_driver_unregister(&stm32_serial_driver);
> +       uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS      112
>
> +/* STM32 USART */
> +#define PORT_STM32     110
> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
  2015-03-13  0:09     ` Chanwoo Choi
  (?)
@ 2015-03-17 16:57       ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 16:57 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

Hi Chanwoo,

2015-03-13 1:09 GMT+01:00 Chanwoo Choi <cw00.choi@samsung.com>:
> Hi Maxime,
>
> On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
<snip>

>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>> +
>>
>
> Last line is un-necessary. When I applied this patch for test
> "new blank line at EOF" happen.

Thanks, that will be fixed in v4.

Kind regards,
Maxime
>
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -99,4 +99,3 @@ List of indexes for STM32F429:
>   - spi6: 309
>   - sai1: 310
>   - ltdc: 31
> -
>
> Thanks,
> Chanwoo Choi
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-17 16:57       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 16:57 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

Hi Chanwoo,

2015-03-13 1:09 GMT+01:00 Chanwoo Choi <cw00.choi@samsung.com>:
> Hi Maxime,
>
> On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
<snip>

>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>> +
>>
>
> Last line is un-necessary. When I applied this patch for test
> "new blank line at EOF" happen.

Thanks, that will be fixed in v4.

Kind regards,
Maxime
>
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -99,4 +99,3 @@ List of indexes for STM32F429:
>   - spi6: 309
>   - sai1: 310
>   - ltdc: 31
> -
>
> Thanks,
> Chanwoo Choi
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-17 16:57       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 16:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Chanwoo,

2015-03-13 1:09 GMT+01:00 Chanwoo Choi <cw00.choi@samsung.com>:
> Hi Maxime,
>
> On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
<snip>

>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>> +
>>
>
> Last line is un-necessary. When I applied this patch for test
> "new blank line at EOF" happen.

Thanks, that will be fixed in v4.

Kind regards,
Maxime
>
> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
> @@ -99,4 +99,3 @@ List of indexes for STM32F429:
>   - spi6: 309
>   - sai1: 310
>   - ltdc: 31
> -
>
> Thanks,
> Chanwoo Choi
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
  2015-03-13  8:50     ` Philipp Zabel
  (?)
@ 2015-03-17 17:13         ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:13 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Linus Walleij, Arnd Bergmann, Stefan Agner,
	Peter Meerwald, Paul Bolle, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab

Hi Philipp,

2015-03-13 9:50 GMT+01:00 Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>:
> Hi Maxime,
>
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> @@ -0,0 +1,102 @@
>> +STMicroelectronics STM32 Peripheral Reset Controller
>> +====================================================
>> +
>> +The RCC IP is both a reset and a clock controller. This documentation only
>> +document the reset part.
>> +
>> +Please also refer to reset.txt in this directory for common reset
>> +controller binding usage.
>> +
>> +Required properties:
>> +- compatible: Should be "st,stm32-rcc"
>> +- reg: should be register base and length as documented in the
>> +  datasheet
>> +- #reset-cells: 1, see below
>> +
>> +example:
>> +
>> +rcc: reset@40023800 {
>> +     #reset-cells = <1>;
>> +     compatible = "st,stm32-rcc";
>> +     reg = <0x40023800 0x400>;
>> +};
>> +
>> +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.
>
> Using a single value as index is ok, but it should be documented how
> this corresponds to the register and bit offsets in the reference
> manual.
> Maybe add a comment that the index is in fact the register offset / 4 *
> 32 + bit offset in that register and that not all registers are
> dedicated to the rest controller? Otherwise it is confusing (to me at
> least) that the indices start at some arbitrary value.

I agree to better document it. Are you ok with:

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 256>;
>> +     };
>> +
>> +List of indexes for STM32F429:
>
> "List of valid indices", to point out that any other index is invalid?

Right, it will be changed in v4.

>
>> + - gpioa: 128
>
> I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
> clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
> reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...
>
>> + - gpiob: 129
>> + - gpioc: 130
>> + - gpiod: 131
>> + - gpioe: 132
>> + - gpiof: 133
>> + - gpiog: 134
>> + - gpioh: 135
>> + - gpioi: 136
>> + - gpioj: 137
>> + - gpiok: 138
>> + - crc: 140
>> + - dma1: 149
>> + - dma2: 150
>> + - dma2d: 151
>> + - ethmac: 153
>> + - otghs: 157
>> + - dcmi: 160
>> + - cryp: 164
>> + - hash: 165
>> + - rng: 166
>> + - otgfs: 167
>> + - fmc: 192
>> + - tim2: 256
>> + - tim3: 257
>> + - tim4: 258
>> + - tim5: 259
>> + - tim6: 260
>> + - tim7: 261
>> + - tim12: 262
>> + - tim13: 263
>> + - tim14: 264
>> + - wwdg: 267
>> + - spi2: 270
>> + - spi3: 271
>> + - uart2: 273
>> + - uart3: 274
>> + - uart4: 275
>> + - uart5: 276
>> + - i2c1: 277
>> + - i2c2: 278
>> + - i2c3: 279
>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>
> That last one should say "ltdc: 314", right?
Thanks for catching this!
Just fixed it, it will be in v4.

Kind regards,
Maxime

>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-17 17:13         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:13 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Linus Walleij, Arnd Bergmann, Stefan Agner,
	Peter Meerwald, Paul Bolle, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

Hi Philipp,

2015-03-13 9:50 GMT+01:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Hi Maxime,
>
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> @@ -0,0 +1,102 @@
>> +STMicroelectronics STM32 Peripheral Reset Controller
>> +====================================================
>> +
>> +The RCC IP is both a reset and a clock controller. This documentation only
>> +document the reset part.
>> +
>> +Please also refer to reset.txt in this directory for common reset
>> +controller binding usage.
>> +
>> +Required properties:
>> +- compatible: Should be "st,stm32-rcc"
>> +- reg: should be register base and length as documented in the
>> +  datasheet
>> +- #reset-cells: 1, see below
>> +
>> +example:
>> +
>> +rcc: reset@40023800 {
>> +     #reset-cells = <1>;
>> +     compatible = "st,stm32-rcc";
>> +     reg = <0x40023800 0x400>;
>> +};
>> +
>> +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.
>
> Using a single value as index is ok, but it should be documented how
> this corresponds to the register and bit offsets in the reference
> manual.
> Maybe add a comment that the index is in fact the register offset / 4 *
> 32 + bit offset in that register and that not all registers are
> dedicated to the rest controller? Otherwise it is confusing (to me at
> least) that the indices start at some arbitrary value.

I agree to better document it. Are you ok with:

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 256>;
>> +     };
>> +
>> +List of indexes for STM32F429:
>
> "List of valid indices", to point out that any other index is invalid?

Right, it will be changed in v4.

>
>> + - gpioa: 128
>
> I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
> clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
> reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...
>
>> + - gpiob: 129
>> + - gpioc: 130
>> + - gpiod: 131
>> + - gpioe: 132
>> + - gpiof: 133
>> + - gpiog: 134
>> + - gpioh: 135
>> + - gpioi: 136
>> + - gpioj: 137
>> + - gpiok: 138
>> + - crc: 140
>> + - dma1: 149
>> + - dma2: 150
>> + - dma2d: 151
>> + - ethmac: 153
>> + - otghs: 157
>> + - dcmi: 160
>> + - cryp: 164
>> + - hash: 165
>> + - rng: 166
>> + - otgfs: 167
>> + - fmc: 192
>> + - tim2: 256
>> + - tim3: 257
>> + - tim4: 258
>> + - tim5: 259
>> + - tim6: 260
>> + - tim7: 261
>> + - tim12: 262
>> + - tim13: 263
>> + - tim14: 264
>> + - wwdg: 267
>> + - spi2: 270
>> + - spi3: 271
>> + - uart2: 273
>> + - uart3: 274
>> + - uart4: 275
>> + - uart5: 276
>> + - i2c1: 277
>> + - i2c2: 278
>> + - i2c3: 279
>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>
> That last one should say "ltdc: 314", right?
Thanks for catching this!
Just fixed it, it will be in v4.

Kind regards,
Maxime

>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings
@ 2015-03-17 17:13         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Philipp,

2015-03-13 9:50 GMT+01:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Hi Maxime,
>
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This adds documentation of device tree bindings for the
>> STM32 reset controller.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..962f961
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>> @@ -0,0 +1,102 @@
>> +STMicroelectronics STM32 Peripheral Reset Controller
>> +====================================================
>> +
>> +The RCC IP is both a reset and a clock controller. This documentation only
>> +document the reset part.
>> +
>> +Please also refer to reset.txt in this directory for common reset
>> +controller binding usage.
>> +
>> +Required properties:
>> +- compatible: Should be "st,stm32-rcc"
>> +- reg: should be register base and length as documented in the
>> +  datasheet
>> +- #reset-cells: 1, see below
>> +
>> +example:
>> +
>> +rcc: reset at 40023800 {
>> +     #reset-cells = <1>;
>> +     compatible = "st,stm32-rcc";
>> +     reg = <0x40023800 0x400>;
>> +};
>> +
>> +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.
>
> Using a single value as index is ok, but it should be documented how
> this corresponds to the register and bit offsets in the reference
> manual.
> Maybe add a comment that the index is in fact the register offset / 4 *
> 32 + bit offset in that register and that not all registers are
> dedicated to the rest controller? Otherwise it is confusing (to me at
> least) that the indices start at some arbitrary value.

I agree to better document it. Are you ok with:

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 256>;
>> +     };
>> +
>> +List of indexes for STM32F429:
>
> "List of valid indices", to point out that any other index is invalid?

Right, it will be changed in v4.

>
>> + - gpioa: 128
>
> I had to look at the RM0090 Reference manual V8.0, Chapter 6, "Reset and
> clock control for STM32F42xx and STM32F43xxx (RCC)" to see that the
> reset registers indeed start at 0x10 (RCC_AHB1RSTR), ...
>
>> + - gpiob: 129
>> + - gpioc: 130
>> + - gpiod: 131
>> + - gpioe: 132
>> + - gpiof: 133
>> + - gpiog: 134
>> + - gpioh: 135
>> + - gpioi: 136
>> + - gpioj: 137
>> + - gpiok: 138
>> + - crc: 140
>> + - dma1: 149
>> + - dma2: 150
>> + - dma2d: 151
>> + - ethmac: 153
>> + - otghs: 157
>> + - dcmi: 160
>> + - cryp: 164
>> + - hash: 165
>> + - rng: 166
>> + - otgfs: 167
>> + - fmc: 192
>> + - tim2: 256
>> + - tim3: 257
>> + - tim4: 258
>> + - tim5: 259
>> + - tim6: 260
>> + - tim7: 261
>> + - tim12: 262
>> + - tim13: 263
>> + - tim14: 264
>> + - wwdg: 267
>> + - spi2: 270
>> + - spi3: 271
>> + - uart2: 273
>> + - uart3: 274
>> + - uart4: 275
>> + - uart5: 276
>> + - i2c1: 277
>> + - i2c2: 278
>> + - i2c3: 279
>> + - can1: 281
>> + - can2: 282
>> + - pwr: 284
>> + - dac: 285
>> + - uart7: 286
>> + - uart8: 287
>> + - tim1: 288
>> + - tim8: 289
>> + - usart1: 292
>> + - usart6: 293
>> + - adc: 296
>> + - sdio: 299
>> + - spi1: 300
>> + - spi4: 301
>> + - syscfg: 302
>> + - tim9: 304
>> + - tim10: 305
>> + - tim11: 306
>> + - spi5: 308
>> + - spi6: 309
>> + - sai1: 310
>> + - ltdc: 31
>
> That last one should say "ltdc: 314", right?
Thanks for catching this!
Just fixed it, it will be in v4.

Kind regards,
Maxime

>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 06/15] drivers: reset: Add STM32 reset driver
  2015-03-13  8:54     ` Philipp Zabel
  (?)
@ 2015-03-17 17:23       ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:23 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Linus Walleij, Arnd Bergmann, Stefan Agner,
	Peter Meerwald, Paul Bolle, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab

2015-03-13 9:54 GMT+01:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> The STM32 MCUs family IP can be reset by accessing some shared registers.
>>
>> The specificity is that some reset lines are used by the timers.
>> At timer initialization time, the timer has to be reset, that's why
>> we cannot use a regular driver.
>
> But this is a regular driver now, should this comment be updated?
>

Indeed, I changed in v4 to:
    The STM32 MCUs family IPs can be reset by accessing some registers
    from the RCC block.

    The list of available reset lines is documented in the DT bindings.

Thanks,
Maxime
>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-17 17:23       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:23 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Linus Walleij, Arnd Bergmann, Stefan Agner,
	Peter Meerwald, Paul Bolle, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-13 9:54 GMT+01:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> The STM32 MCUs family IP can be reset by accessing some shared registers.
>>
>> The specificity is that some reset lines are used by the timers.
>> At timer initialization time, the timer has to be reset, that's why
>> we cannot use a regular driver.
>
> But this is a regular driver now, should this comment be updated?
>

Indeed, I changed in v4 to:
    The STM32 MCUs family IPs can be reset by accessing some registers
    from the RCC block.

    The list of available reset lines is documented in the DT bindings.

Thanks,
Maxime
>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 06/15] drivers: reset: Add STM32 reset driver
@ 2015-03-17 17:23       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:23 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-13 9:54 GMT+01:00 Philipp Zabel <p.zabel@pengutronix.de>:
> Am Donnerstag, den 12.03.2015, 22:55 +0100 schrieb Maxime Coquelin:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> The STM32 MCUs family IP can be reset by accessing some shared registers.
>>
>> The specificity is that some reset lines are used by the timers.
>> At timer initialization time, the timer has to be reset, that's why
>> we cannot use a regular driver.
>
> But this is a regular driver now, should this comment be updated?
>

Indeed, I changed in v4 to:
    The STM32 MCUs family IPs can be reset by accessing some registers
    from the RCC block.

    The list of available reset lines is documented in the DT bindings.

Thanks,
Maxime
>
> regards
> Philipp
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-13 14:19       ` Andy Shevchenko
  (?)
@ 2015-03-17 17:32         ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:32 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> My comment below.
>
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>
>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> index d2501f0..880cb4f 100644
>> --- a/drivers/tty/serial/Kconfig
>> +++ b/drivers/tty/serial/Kconfig
>> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>>           with "earlycon" on the kernel command line. The console is
>>           enabled when early_param is processed.
>>
>> +config SERIAL_STM32
>> +       tristate "STMicroelectronics STM32 serial port support"
>> +       select SERIAL_CORE
>> +       depends on ARM || COMPILE_TEST
>> +       help
>> +         This driver is for the on-chip Serial Controller on
>> +         STMicroelectronics STM32 MCUs.
>> +         USART supports Rx & Tx functionality.
>> +         It support all industry standard baud rates.
>> +
>> +         If unsure, say N.
>> +
>> +config SERIAL_STM32_CONSOLE
>> +       bool "Support for console on STM32"
>> +       depends on SERIAL_STM32=y
>> +       select SERIAL_CORE_CONSOLE
>> +
>>  endmenu
>>
>>  config SERIAL_MCTRL_GPIO
>> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
>> index 599be4b..67c5023 100644
>> --- a/drivers/tty/serial/Makefile
>> +++ b/drivers/tty/serial/Makefile
>> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
>> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>>
>>  # GPIOLIB helpers for modem control lines
>>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
>> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
>> new file mode 100644
>> index 0000000..61bb065
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@

<snip>

>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                           struct ktermios *old)
>> +{
>> +       unsigned int baud;
>> +       u32 usardiv, mantissa, fraction;
>> +       tcflag_t cflag;
>> +       u32 cr1, cr2, cr3;
>> +       unsigned long flags;
>> +
>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +       cflag = termios->c_cflag;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       /* Stop serial port and reset value */
>> +       writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +       if (cflag & CSTOPB)
>> +               cr2 = USART_CR2_STOP_2B;
>> +
>> +       if (cflag & PARENB) {
>> +               cr1 |= USART_CR1_PCE;
>> +               if ((cflag & CSIZE) == CS8)
>> +                       cr1 |= USART_CR1_M;
>> +       }
>> +
>> +       if (cflag & PARODD)
>> +               cr1 |= USART_CR1_PS;
>> +
>> +       if (cflag & CRTSCTS)
>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>> +
>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +               fraction = 0;
>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +       }
>
> So, it's a fractional divider. right? Could it be then fractional
> divider clock in this first place (see
> drivers/clk/clk-fractional-divider.c)?
>

I'm not sure it makes sense to represent this baudrate divider within
the UART IP as a clock.
What would be the gain?

Kind regards,
Maxime

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:32         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:32 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	Linux Documentation List, linux-arm Mailing List, linux-kernel,
	devicetree, linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> My comment below.
>
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>
>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> index d2501f0..880cb4f 100644
>> --- a/drivers/tty/serial/Kconfig
>> +++ b/drivers/tty/serial/Kconfig
>> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>>           with "earlycon" on the kernel command line. The console is
>>           enabled when early_param is processed.
>>
>> +config SERIAL_STM32
>> +       tristate "STMicroelectronics STM32 serial port support"
>> +       select SERIAL_CORE
>> +       depends on ARM || COMPILE_TEST
>> +       help
>> +         This driver is for the on-chip Serial Controller on
>> +         STMicroelectronics STM32 MCUs.
>> +         USART supports Rx & Tx functionality.
>> +         It support all industry standard baud rates.
>> +
>> +         If unsure, say N.
>> +
>> +config SERIAL_STM32_CONSOLE
>> +       bool "Support for console on STM32"
>> +       depends on SERIAL_STM32=y
>> +       select SERIAL_CORE_CONSOLE
>> +
>>  endmenu
>>
>>  config SERIAL_MCTRL_GPIO
>> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
>> index 599be4b..67c5023 100644
>> --- a/drivers/tty/serial/Makefile
>> +++ b/drivers/tty/serial/Makefile
>> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
>> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>>
>>  # GPIOLIB helpers for modem control lines
>>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
>> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
>> new file mode 100644
>> index 0000000..61bb065
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@

<snip>

>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                           struct ktermios *old)
>> +{
>> +       unsigned int baud;
>> +       u32 usardiv, mantissa, fraction;
>> +       tcflag_t cflag;
>> +       u32 cr1, cr2, cr3;
>> +       unsigned long flags;
>> +
>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +       cflag = termios->c_cflag;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       /* Stop serial port and reset value */
>> +       writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +       if (cflag & CSTOPB)
>> +               cr2 = USART_CR2_STOP_2B;
>> +
>> +       if (cflag & PARENB) {
>> +               cr1 |= USART_CR1_PCE;
>> +               if ((cflag & CSIZE) == CS8)
>> +                       cr1 |= USART_CR1_M;
>> +       }
>> +
>> +       if (cflag & PARODD)
>> +               cr1 |= USART_CR1_PS;
>> +
>> +       if (cflag & CRTSCTS)
>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>> +
>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +               fraction = 0;
>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +       }
>
> So, it's a fractional divider. right? Could it be then fractional
> divider clock in this first place (see
> drivers/clk/clk-fractional-divider.c)?
>

I'm not sure it makes sense to represent this baudrate divider within
the UART IP as a clock.
What would be the gain?

Kind regards,
Maxime

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:32         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Thu, Mar 12, 2015 at 11:55 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> My comment below.
>
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>
>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> index d2501f0..880cb4f 100644
>> --- a/drivers/tty/serial/Kconfig
>> +++ b/drivers/tty/serial/Kconfig
>> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>>           with "earlycon" on the kernel command line. The console is
>>           enabled when early_param is processed.
>>
>> +config SERIAL_STM32
>> +       tristate "STMicroelectronics STM32 serial port support"
>> +       select SERIAL_CORE
>> +       depends on ARM || COMPILE_TEST
>> +       help
>> +         This driver is for the on-chip Serial Controller on
>> +         STMicroelectronics STM32 MCUs.
>> +         USART supports Rx & Tx functionality.
>> +         It support all industry standard baud rates.
>> +
>> +         If unsure, say N.
>> +
>> +config SERIAL_STM32_CONSOLE
>> +       bool "Support for console on STM32"
>> +       depends on SERIAL_STM32=y
>> +       select SERIAL_CORE_CONSOLE
>> +
>>  endmenu
>>
>>  config SERIAL_MCTRL_GPIO
>> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
>> index 599be4b..67c5023 100644
>> --- a/drivers/tty/serial/Makefile
>> +++ b/drivers/tty/serial/Makefile
>> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)       += fsl_lpuart.o
>>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
>>  obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
>>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
>> +obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
>>
>>  # GPIOLIB helpers for modem control lines
>>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
>> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
>> new file mode 100644
>> index 0000000..61bb065
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@

<snip>

>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                           struct ktermios *old)
>> +{
>> +       unsigned int baud;
>> +       u32 usardiv, mantissa, fraction;
>> +       tcflag_t cflag;
>> +       u32 cr1, cr2, cr3;
>> +       unsigned long flags;
>> +
>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +       cflag = termios->c_cflag;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       /* Stop serial port and reset value */
>> +       writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +       if (cflag & CSTOPB)
>> +               cr2 = USART_CR2_STOP_2B;
>> +
>> +       if (cflag & PARENB) {
>> +               cr1 |= USART_CR1_PCE;
>> +               if ((cflag & CSIZE) == CS8)
>> +                       cr1 |= USART_CR1_M;
>> +       }
>> +
>> +       if (cflag & PARODD)
>> +               cr1 |= USART_CR1_PS;
>> +
>> +       if (cflag & CRTSCTS)
>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>> +
>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +               fraction = 0;
>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +       }
>
> So, it's a fractional divider. right? Could it be then fractional
> divider clock in this first place (see
> drivers/clk/clk-fractional-divider.c)?
>

I'm not sure it makes sense to represent this baudrate divider within
the UART IP as a clock.
What would be the gain?

Kind regards,
Maxime

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-13  9:41       ` Paul Bolle
  (?)
@ 2015-03-17 17:39         ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:39 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

2015-03-13 10:41 GMT+01:00 Paul Bolle <pebolle@tiscali.nl>:
> Just a license nit, I'm afraid.
Not a problem, it is not the last round anyway.

>
> On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + *
>> + * Inspired by st-asc.c from STMicroelectronics (c)
>> + */
>
> This states the license is GPL v2.
>
>> +MODULE_LICENSE("GPL");
>
> And
>     MODULE_LICENSE("GPL v2");
>
> would match that statement.

Right, it will be fixed in the v4.

Thanks,
Maxime
>
>
> Paul Bolle
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:39         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:39 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Jonathan Corbet, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-13 10:41 GMT+01:00 Paul Bolle <pebolle@tiscali.nl>:
> Just a license nit, I'm afraid.
Not a problem, it is not the last round anyway.

>
> On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + *
>> + * Inspired by st-asc.c from STMicroelectronics (c)
>> + */
>
> This states the license is GPL v2.
>
>> +MODULE_LICENSE("GPL");
>
> And
>     MODULE_LICENSE("GPL v2");
>
> would match that statement.

Right, it will be fixed in the v4.

Thanks,
Maxime
>
>
> Paul Bolle
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:39         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-17 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-13 10:41 GMT+01:00 Paul Bolle <pebolle@tiscali.nl>:
> Just a license nit, I'm afraid.
Not a problem, it is not the last round anyway.

>
> On Thu, 2015-03-12 at 22:55 +0100, Maxime Coquelin wrote:
>> --- /dev/null
>> +++ b/drivers/tty/serial/stm32-usart.c
>> @@ -0,0 +1,695 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + *
>> + * Inspired by st-asc.c from STMicroelectronics (c)
>> + */
>
> This states the license is GPL v2.
>
>> +MODULE_LICENSE("GPL");
>
> And
>     MODULE_LICENSE("GPL v2");
>
> would match that statement.

Right, it will be fixed in the v4.

Thanks,
Maxime
>
>
> Paul Bolle
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-17 17:32         ` Maxime Coquelin
  (?)
@ 2015-03-17 17:56             ` Andy Shevchenko
  -1 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-17 17:56 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
<mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:

>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                           struct ktermios *old)
>>> +{
>>> +       unsigned int baud;
>>> +       u32 usardiv, mantissa, fraction;
>>> +       tcflag_t cflag;
>>> +       u32 cr1, cr2, cr3;
>>> +       unsigned long flags;
>>> +
>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +       cflag = termios->c_cflag;
>>> +
>>> +       spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +       /* Stop serial port and reset value */
>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +       if (cflag & CSTOPB)
>>> +               cr2 = USART_CR2_STOP_2B;
>>> +
>>> +       if (cflag & PARENB) {
>>> +               cr1 |= USART_CR1_PCE;
>>> +               if ((cflag & CSIZE) == CS8)
>>> +                       cr1 |= USART_CR1_M;
>>> +       }
>>> +
>>> +       if (cflag & PARODD)
>>> +               cr1 |= USART_CR1_PS;
>>> +
>>> +       if (cflag & CRTSCTS)
>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>> +
>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>> +               fraction = 0;
>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>> +       }
>>
>> So, it's a fractional divider. right? Could it be then fractional
>> divider clock in this first place (see
>> drivers/clk/clk-fractional-divider.c)?
>>
>
> I'm not sure it makes sense to represent this baudrate divider within
> the UART IP as a clock.

You have it already. I mean it should be fractional divider clock.

stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+       if (WARN_ON(IS_ERR(stm32port->clk)))
+               return -EINVAL;
+
+       /* ensure that clk rate is correct by enabling the clk */
+       clk_prepare_enable(stm32port->clk);
+       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

> What would be the gain?

Remove custom implementation of the calculations. It will be just one
line to refresh the baud rate. I think we have a lot of duplicates
here and there in the kernel. It would be nice not to bring another
one.

-- 
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:56             ` Andy Shevchenko
  0 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-17 17:56 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	Linux Documentation List, linux-arm Mailing List, linux-kernel,
	devicetree, linux-gpio, linux-serial, Linux-Arch, linux-api

On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:

>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                           struct ktermios *old)
>>> +{
>>> +       unsigned int baud;
>>> +       u32 usardiv, mantissa, fraction;
>>> +       tcflag_t cflag;
>>> +       u32 cr1, cr2, cr3;
>>> +       unsigned long flags;
>>> +
>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +       cflag = termios->c_cflag;
>>> +
>>> +       spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +       /* Stop serial port and reset value */
>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +       if (cflag & CSTOPB)
>>> +               cr2 = USART_CR2_STOP_2B;
>>> +
>>> +       if (cflag & PARENB) {
>>> +               cr1 |= USART_CR1_PCE;
>>> +               if ((cflag & CSIZE) == CS8)
>>> +                       cr1 |= USART_CR1_M;
>>> +       }
>>> +
>>> +       if (cflag & PARODD)
>>> +               cr1 |= USART_CR1_PS;
>>> +
>>> +       if (cflag & CRTSCTS)
>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>> +
>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>> +               fraction = 0;
>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>> +       }
>>
>> So, it's a fractional divider. right? Could it be then fractional
>> divider clock in this first place (see
>> drivers/clk/clk-fractional-divider.c)?
>>
>
> I'm not sure it makes sense to represent this baudrate divider within
> the UART IP as a clock.

You have it already. I mean it should be fractional divider clock.

stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+       if (WARN_ON(IS_ERR(stm32port->clk)))
+               return -EINVAL;
+
+       /* ensure that clk rate is correct by enabling the clk */
+       clk_prepare_enable(stm32port->clk);
+       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

> What would be the gain?

Remove custom implementation of the calculations. It will be just one
line to refresh the baud rate. I think we have a lot of duplicates
here and there in the kernel. It would be nice not to bring another
one.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-17 17:56             ` Andy Shevchenko
  0 siblings, 0 replies; 136+ messages in thread
From: Andy Shevchenko @ 2015-03-17 17:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
<mcoquelin.stm32@gmail.com> wrote:
> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:

>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                           struct ktermios *old)
>>> +{
>>> +       unsigned int baud;
>>> +       u32 usardiv, mantissa, fraction;
>>> +       tcflag_t cflag;
>>> +       u32 cr1, cr2, cr3;
>>> +       unsigned long flags;
>>> +
>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +       cflag = termios->c_cflag;
>>> +
>>> +       spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +       /* Stop serial port and reset value */
>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +       if (cflag & CSTOPB)
>>> +               cr2 = USART_CR2_STOP_2B;
>>> +
>>> +       if (cflag & PARENB) {
>>> +               cr1 |= USART_CR1_PCE;
>>> +               if ((cflag & CSIZE) == CS8)
>>> +                       cr1 |= USART_CR1_M;
>>> +       }
>>> +
>>> +       if (cflag & PARODD)
>>> +               cr1 |= USART_CR1_PS;
>>> +
>>> +       if (cflag & CRTSCTS)
>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>> +
>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>> +               fraction = 0;
>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>> +       }
>>
>> So, it's a fractional divider. right? Could it be then fractional
>> divider clock in this first place (see
>> drivers/clk/clk-fractional-divider.c)?
>>
>
> I'm not sure it makes sense to represent this baudrate divider within
> the UART IP as a clock.

You have it already. I mean it should be fractional divider clock.

stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+       if (WARN_ON(IS_ERR(stm32port->clk)))
+               return -EINVAL;
+
+       /* ensure that clk rate is correct by enabling the clk */
+       clk_prepare_enable(stm32port->clk);
+       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

> What would be the gain?

Remove custom implementation of the calculations. It will be just one
line to refresh the baud rate. I think we have a lot of duplicates
here and there in the kernel. It would be nice not to bring another
one.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
  2015-03-12 21:55 ` Maxime Coquelin
  (?)
@ 2015-03-18 23:35   ` Chanwoo Choi
  -1 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-18 23:35 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

Hi Maxime,

I tested this patch-set on Linux 4.0-rc4 for STM32F429IDISCOVERY board.
I completed the kernel booting successfully without any modification .

Looks good to me for this patch-set.

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>

Best Regards,
Chanwoo Choi

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 


^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-18 23:35   ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-18 23:35 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

Hi Maxime,

I tested this patch-set on Linux 4.0-rc4 for STM32F429IDISCOVERY board.
I completed the kernel booting successfully without any modification .

Looks good to me for this patch-set.

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>

Best Regards,
Chanwoo Choi

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  00/15] Add support to STMicroelectronics STM32 family
@ 2015-03-18 23:35   ` Chanwoo Choi
  0 siblings, 0 replies; 136+ messages in thread
From: Chanwoo Choi @ 2015-03-18 23:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

I tested this patch-set on Linux 4.0-rc4 for STM32F429IDISCOVERY board.
I completed the kernel booting successfully without any modification .

Looks good to me for this patch-set.

Tested-by: Chanwoo Choi <cw00.choi@samsung.com>

Best Regards,
Chanwoo Choi

On 03/13/2015 06:55 AM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This third round tries to address most of the comments made on previous series.
> 
> It contains few less patches, as the reset_controller_of_init() patch has been
> removed, now that the bootlaoder handles the reset of the timers.
> 
> The pinctrl driver has also been removed after Linus review.
> It will be reworked to use the generic pinconf bindings, and may contain
> changes for other machines (Mediatek), to add support for pinmux property
> handling directly in pinconf-generic.
> 
> STM32 MCUs are Cortex-M CPU, used in various applications (consumer
> electronics, industrial applications, hobbyists...).
> Datasheets, user and programming manuals are publicly available on
> STMicroelectronics website.
> 
> With this series applied, the STM32F419 Discovery can boot succesfully.
> 
> 
> Changes since v2:
> -----------------
>  - Remove pinctrl driver from the series. 
>  - Remove reset_controller_of_init(), and reset the timers in the bootloader
>  - Add HW flow contrl property for serial driver
>  - Lots of changes in the DTS file, as per Andreas recommendations
>  - Some Kconfig clean-ups
>  - Adapt the config to be compatible with Andreas' bootwrapper, except UART port.
>  - Various fixes in documentation
> 
> Changes since v1:
> -----------------
>  - Move bindings documentation in their own patches (Andreas)
>  - Rename ARM System timer to armv7m-systick (Rob)
>  - Add clock-frequency property handling in armv7m-systick (Rob)
>  - Re-factor the reset controllers into a single controller (Philipp)
>  - Add kerneldoc to reset_controller_of_init (Philipp)
>  - Add named constants in include/dt-bindings/reset/ (Philipp)
>  - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
>  - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
> supported by the MCU, in order to limit memory waste in vectors' table (Uwe)
> 
> 
> Maxime Coquelin (15):
>   scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
>     Kernel
>   ARM: ARMv7-M: Enlarge vector table up to 256 entries
>   dt-bindings: Document the ARM System timer bindings
>   clocksource: Add ARM System timer driver
>   dt-bindings: Document the STM32 reset bindings
>   drivers: reset: Add STM32 reset driver
>   dt-bindings: Document the STM32 timer bindings
>   clockevent: Add STM32 Timer driver
>   dt-bindings: Document the STM32 USART bindings
>   serial: stm32-usart: Add STM32 USART Driver
>   ARM: Add STM32 family machine
>   ARM: dts: Add ARM System timer as clockevent in armv7m
>   ARM: dts: Introduce STM32F429 MCU
>   ARM: configs: Add STM32 defconfig
>   MAINTAINERS: Add entry for STM32 MCUs
> 
>  Documentation/arm/stm32/overview.txt               |  32 +
>  Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
>  .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
>  .../devicetree/bindings/reset/st,stm32-rcc.txt     | 102 +++
>  .../devicetree/bindings/serial/st,stm32-usart.txt  |  32 +
>  .../devicetree/bindings/timer/st,stm32-timer.txt   |  22 +
>  MAINTAINERS                                        |   8 +
>  arch/arm/Kconfig                                   |  18 +
>  arch/arm/Makefile                                  |   1 +
>  arch/arm/boot/dts/Makefile                         |   1 +
>  arch/arm/boot/dts/armv7-m.dtsi                     |   6 +
>  arch/arm/boot/dts/stm32f429-disco.dts              |  71 +++
>  arch/arm/boot/dts/stm32f429.dtsi                   | 226 +++++++
>  arch/arm/configs/stm32_defconfig                   |  71 +++
>  arch/arm/kernel/entry-v7m.S                        |  13 +-
>  arch/arm/mach-stm32/Makefile                       |   1 +
>  arch/arm/mach-stm32/Makefile.boot                  |   3 +
>  arch/arm/mach-stm32/board-dt.c                     |  19 +
>  arch/arm/mm/Kconfig                                |  15 +
>  drivers/clocksource/Kconfig                        |  15 +
>  drivers/clocksource/Makefile                       |   2 +
>  drivers/clocksource/armv7m_systick.c               |  78 +++
>  drivers/clocksource/timer-stm32.c                  | 184 ++++++
>  drivers/reset/Makefile                             |   1 +
>  drivers/reset/reset-stm32.c                        | 125 ++++
>  drivers/tty/serial/Kconfig                         |  17 +
>  drivers/tty/serial/Makefile                        |   1 +
>  drivers/tty/serial/stm32-usart.c                   | 695 +++++++++++++++++++++
>  include/uapi/linux/serial_core.h                   |   3 +
>  scripts/link-vmlinux.sh                            |   2 +-
>  30 files changed, 1807 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/arm/stm32/overview.txt
>  create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
>  create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
>  create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
>  create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
>  create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
>  create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
>  create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>  create mode 100644 arch/arm/configs/stm32_defconfig
>  create mode 100644 arch/arm/mach-stm32/Makefile
>  create mode 100644 arch/arm/mach-stm32/Makefile.boot
>  create mode 100644 arch/arm/mach-stm32/board-dt.c
>  create mode 100644 drivers/clocksource/armv7m_systick.c
>  create mode 100644 drivers/clocksource/timer-stm32.c
>  create mode 100644 drivers/reset/reset-stm32.c
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-17 17:56             ` Andy Shevchenko
  (?)
@ 2015-03-19 13:55               ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 13:55 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

2015-03-17 18:56 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
>
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                           struct ktermios *old)
>>>> +{
>>>> +       unsigned int baud;
>>>> +       u32 usardiv, mantissa, fraction;
>>>> +       tcflag_t cflag;
>>>> +       u32 cr1, cr2, cr3;
>>>> +       unsigned long flags;
>>>> +
>>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +       cflag = termios->c_cflag;
>>>> +
>>>> +       spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +       /* Stop serial port and reset value */
>>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +       if (cflag & CSTOPB)
>>>> +               cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +       if (cflag & PARENB) {
>>>> +               cr1 |= USART_CR1_PCE;
>>>> +               if ((cflag & CSIZE) == CS8)
>>>> +                       cr1 |= USART_CR1_M;
>>>> +       }
>>>> +
>>>> +       if (cflag & PARODD)
>>>> +               cr1 |= USART_CR1_PS;
>>>> +
>>>> +       if (cflag & CRTSCTS)
>>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>> +
>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>> +               fraction = 0;
>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>> +       }
>>>
>>> So, it's a fractional divider. right? Could it be then fractional
>>> divider clock in this first place (see
>>> drivers/clk/clk-fractional-divider.c)?
>>>
>>
>> I'm not sure it makes sense to represent this baudrate divider within
>> the UART IP as a clock.
>
> You have it already. I mean it should be fractional divider clock.
>
> stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

No I don't have it already.
The clock I get here is coming from outside the IP, so this driver is
a clock consumer.
If I follow your advice, this driver will become both the clock
provider and the only clock consumer of this clock.
I think this is something that should be avoided.

Also, it would require to add another clock in between (a by-16 fixed
divider), because the formula is:
baud = fck / (16 * usart_div)

Finally, representing this as a clock is not really matching the
reality, because we are generating a baud rate, not a frequency.

Really, I would prefer keeping this fractional divider as it is
implemented today.

Kind regards,
Maxime

>
>> What would be the gain?
>
> Remove custom implementation of the calculations. It will be just one
> line to refresh the baud rate. I think we have a lot of duplicates
> here and there in the kernel. It would be nice not to bring another
> one.
>
> --
> With Best Regards,
> Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 13:55               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 13:55 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	Linux Documentation List, linux-arm Mailing List, linux-kernel,
	devicetree, linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-17 18:56 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
>
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                           struct ktermios *old)
>>>> +{
>>>> +       unsigned int baud;
>>>> +       u32 usardiv, mantissa, fraction;
>>>> +       tcflag_t cflag;
>>>> +       u32 cr1, cr2, cr3;
>>>> +       unsigned long flags;
>>>> +
>>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +       cflag = termios->c_cflag;
>>>> +
>>>> +       spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +       /* Stop serial port and reset value */
>>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +       if (cflag & CSTOPB)
>>>> +               cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +       if (cflag & PARENB) {
>>>> +               cr1 |= USART_CR1_PCE;
>>>> +               if ((cflag & CSIZE) == CS8)
>>>> +                       cr1 |= USART_CR1_M;
>>>> +       }
>>>> +
>>>> +       if (cflag & PARODD)
>>>> +               cr1 |= USART_CR1_PS;
>>>> +
>>>> +       if (cflag & CRTSCTS)
>>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>> +
>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>> +               fraction = 0;
>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>> +       }
>>>
>>> So, it's a fractional divider. right? Could it be then fractional
>>> divider clock in this first place (see
>>> drivers/clk/clk-fractional-divider.c)?
>>>
>>
>> I'm not sure it makes sense to represent this baudrate divider within
>> the UART IP as a clock.
>
> You have it already. I mean it should be fractional divider clock.
>
> stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

No I don't have it already.
The clock I get here is coming from outside the IP, so this driver is
a clock consumer.
If I follow your advice, this driver will become both the clock
provider and the only clock consumer of this clock.
I think this is something that should be avoided.

Also, it would require to add another clock in between (a by-16 fixed
divider), because the formula is:
baud = fck / (16 * usart_div)

Finally, representing this as a clock is not really matching the
reality, because we are generating a baud rate, not a frequency.

Really, I would prefer keeping this fractional divider as it is
implemented today.

Kind regards,
Maxime

>
>> What would be the gain?
>
> Remove custom implementation of the calculations. It will be just one
> line to refresh the baud rate. I think we have a lot of duplicates
> here and there in the kernel. It would be nice not to bring another
> one.
>
> --
> With Best Regards,
> Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 13:55               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-17 18:56 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
> On Tue, Mar 17, 2015 at 7:32 PM, Maxime Coquelin
> <mcoquelin.stm32@gmail.com> wrote:
>> 2015-03-13 15:19 GMT+01:00 Andy Shevchenko <andy.shevchenko@gmail.com>:
>
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                           struct ktermios *old)
>>>> +{
>>>> +       unsigned int baud;
>>>> +       u32 usardiv, mantissa, fraction;
>>>> +       tcflag_t cflag;
>>>> +       u32 cr1, cr2, cr3;
>>>> +       unsigned long flags;
>>>> +
>>>> +       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +       cflag = termios->c_cflag;
>>>> +
>>>> +       spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +       /* Stop serial port and reset value */
>>>> +       writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +       cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +       if (cflag & CSTOPB)
>>>> +               cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +       if (cflag & PARENB) {
>>>> +               cr1 |= USART_CR1_PCE;
>>>> +               if ((cflag & CSIZE) == CS8)
>>>> +                       cr1 |= USART_CR1_M;
>>>> +       }
>>>> +
>>>> +       if (cflag & PARODD)
>>>> +               cr1 |= USART_CR1_PS;
>>>> +
>>>> +       if (cflag & CRTSCTS)
>>>> +               cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>> +
>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>> +               fraction = 0;
>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>> +       }
>>>
>>> So, it's a fractional divider. right? Could it be then fractional
>>> divider clock in this first place (see
>>> drivers/clk/clk-fractional-divider.c)?
>>>
>>
>> I'm not sure it makes sense to represent this baudrate divider within
>> the UART IP as a clock.
>
> You have it already. I mean it should be fractional divider clock.
>
> stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +       if (WARN_ON(IS_ERR(stm32port->clk)))
> +               return -EINVAL;
> +
> +       /* ensure that clk rate is correct by enabling the clk */
> +       clk_prepare_enable(stm32port->clk);
> +       stm32port->port.uartclk = clk_get_rate(stm32port->clk);

No I don't have it already.
The clock I get here is coming from outside the IP, so this driver is
a clock consumer.
If I follow your advice, this driver will become both the clock
provider and the only clock consumer of this clock.
I think this is something that should be avoided.

Also, it would require to add another clock in between (a by-16 fixed
divider), because the formula is:
baud = fck / (16 * usart_div)

Finally, representing this as a clock is not really matching the
reality, because we are generating a baud rate, not a frequency.

Really, I would prefer keeping this fractional divider as it is
implemented today.

Kind regards,
Maxime

>
>> What would be the gain?
>
> Remove custom implementation of the calculations. It will be just one
> line to refresh the baud rate. I think we have a lot of duplicates
> here and there in the kernel. It would be nice not to bring another
> one.
>
> --
> With Best Regards,
> Andy Shevchenko

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-19 13:55               ` Maxime Coquelin
  (?)
@ 2015-03-19 14:58                   ` Peter Hurley
  -1 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-19 14:58 UTC (permalink / raw)
  To: Maxime Coquelin, Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>> +                           struct ktermios *old)
[...]
>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>> +               fraction = 0;
>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>> +       }
[...]
> Really, I would prefer keeping this fractional divider as it is
> implemented today.

You have to admit that's basically an unintelligible mess;
how would anyone ever be able to refactor and replace that with a
common divider implementation?

At the very least, please comment on the formula and format.

Regards,
Peter Hurley
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 14:58                   ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-19 14:58 UTC (permalink / raw)
  To: Maxime Coquelin, Andy Shevchenko
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	Linux Documentation List, linux-arm Mailing List, linux-kernel,
	devicetree, linux-gpio, linux-serial, Linux-Arch, linux-api

On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>> +                           struct ktermios *old)
[...]
>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>> +               fraction = 0;
>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>> +       }
[...]
> Really, I would prefer keeping this fractional divider as it is
> implemented today.

You have to admit that's basically an unintelligible mess;
how would anyone ever be able to refactor and replace that with a
common divider implementation?

At the very least, please comment on the formula and format.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 14:58                   ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-19 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>> +                           struct ktermios *old)
[...]
>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>> +               fraction = 0;
>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>> +       }
[...]
> Really, I would prefer keeping this fractional divider as it is
> implemented today.

You have to admit that's basically an unintelligible mess;
how would anyone ever be able to refactor and replace that with a
common divider implementation?

At the very least, please comment on the formula and format.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-19 14:58                   ` Peter Hurley
  (?)
@ 2015-03-19 17:35                       ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 17:35 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton

2015-03-19 15:58 GMT+01:00 Peter Hurley <peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>:
> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>> +                           struct ktermios *old)
> [...]
>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>> +               fraction = 0;
>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>> +       }
> [...]
>> Really, I would prefer keeping this fractional divider as it is
>> implemented today.
>
> You have to admit that's basically an unintelligible mess;
> how would anyone ever be able to refactor and replace that with a
> common divider implementation?
>
> At the very least, please comment on the formula and format.

Ok, I will refactor the implementation, and comment it.

Regards,
Maxime

>
> Regards,
> Peter Hurley
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 17:35                       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 17:35 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, Linux Documentation List, linux-arm Mailing List,
	linux-kernel, devicetree, linux-gpio, linux-serial, Linux-Arch,
	linux-api

2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>> +                           struct ktermios *old)
> [...]
>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>> +               fraction = 0;
>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>> +       }
> [...]
>> Really, I would prefer keeping this fractional divider as it is
>> implemented today.
>
> You have to admit that's basically an unintelligible mess;
> how would anyone ever be able to refactor and replace that with a
> common divider implementation?
>
> At the very least, please comment on the formula and format.

Ok, I will refactor the implementation, and comment it.

Regards,
Maxime

>
> Regards,
> Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-19 17:35                       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-19 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>> +                           struct ktermios *old)
> [...]
>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>> +               fraction = 0;
>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>> +       }
> [...]
>> Really, I would prefer keeping this fractional divider as it is
>> implemented today.
>
> You have to admit that's basically an unintelligible mess;
> how would anyone ever be able to refactor and replace that with a
> common divider implementation?
>
> At the very least, please comment on the formula and format.

Ok, I will refactor the implementation, and comment it.

Regards,
Maxime

>
> Regards,
> Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-19 17:35                       ` Maxime Coquelin
  (?)
@ 2015-03-24 17:21                         ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-24 17:21 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton

Hi Peter,

2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32@gmail.com>:
> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>> +                           struct ktermios *old)
>> [...]
>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>> +               fraction = 0;
>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>> +       }
>> [...]
>>> Really, I would prefer keeping this fractional divider as it is
>>> implemented today.
>>
>> You have to admit that's basically an unintelligible mess;
>> how would anyone ever be able to refactor and replace that with a
>> common divider implementation?
>>
>> At the very least, please comment on the formula and format.
>
> Ok, I will refactor the implementation, and comment it.

The implementation was indeed a mess.
I found some time to refactor the code, and also added support for 8
times oversampling (16 by default).
It will allow to achieve higher speeds, with the side effect of being
less tolerant to clock deviations.

What do you think about the code below?


    usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);

    /*
     * The USART supports 16 or 8 times oversampling.
     * By default we prefer 16 times oversampling, so that the receiver
     * has a better tolerance to clock deviations.
     * 8 times oversampling is only used to achieve higher speeds.
     */
    if (usartdiv < 16) {
        oversampling = 8;
        stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
    } else {
        oversampling = 16;
        stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
    }

    mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
    fraction = usartdiv % oversampling;
    writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks,
Maxime
>
> Regards,
> Maxime
>
>>
>> Regards,
>> Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 17:21                         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-24 17:21 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, Linux Documentation List, linux-arm Mailing List,
	linux-kernel, devicetree, linux-gpio, linux-serial, Linux-Arch,
	linux-api

Hi Peter,

2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32@gmail.com>:
> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>> +                           struct ktermios *old)
>> [...]
>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>> +               fraction = 0;
>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>> +       }
>> [...]
>>> Really, I would prefer keeping this fractional divider as it is
>>> implemented today.
>>
>> You have to admit that's basically an unintelligible mess;
>> how would anyone ever be able to refactor and replace that with a
>> common divider implementation?
>>
>> At the very least, please comment on the formula and format.
>
> Ok, I will refactor the implementation, and comment it.

The implementation was indeed a mess.
I found some time to refactor the code, and also added support for 8
times oversampling (16 by default).
It will allow to achieve higher speeds, with the side effect of being
less tolerant to clock deviations.

What do you think about the code below?


    usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);

    /*
     * The USART supports 16 or 8 times oversampling.
     * By default we prefer 16 times oversampling, so that the receiver
     * has a better tolerance to clock deviations.
     * 8 times oversampling is only used to achieve higher speeds.
     */
    if (usartdiv < 16) {
        oversampling = 8;
        stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
    } else {
        oversampling = 16;
        stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
    }

    mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
    fraction = usartdiv % oversampling;
    writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks,
Maxime
>
> Regards,
> Maxime
>
>>
>> Regards,
>> Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 17:21                         ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-24 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32@gmail.com>:
> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>> +                           struct ktermios *old)
>> [...]
>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>> +               fraction = 0;
>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>> +       }
>> [...]
>>> Really, I would prefer keeping this fractional divider as it is
>>> implemented today.
>>
>> You have to admit that's basically an unintelligible mess;
>> how would anyone ever be able to refactor and replace that with a
>> common divider implementation?
>>
>> At the very least, please comment on the formula and format.
>
> Ok, I will refactor the implementation, and comment it.

The implementation was indeed a mess.
I found some time to refactor the code, and also added support for 8
times oversampling (16 by default).
It will allow to achieve higher speeds, with the side effect of being
less tolerant to clock deviations.

What do you think about the code below?


    usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);

    /*
     * The USART supports 16 or 8 times oversampling.
     * By default we prefer 16 times oversampling, so that the receiver
     * has a better tolerance to clock deviations.
     * 8 times oversampling is only used to achieve higher speeds.
     */
    if (usartdiv < 16) {
        oversampling = 8;
        stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
    } else {
        oversampling = 16;
        stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
    }

    mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
    fraction = usartdiv % oversampling;
    writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks,
Maxime
>
> Regards,
> Maxime
>
>>
>> Regards,
>> Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-24 17:21                         ` Maxime Coquelin
  (?)
@ 2015-03-24 17:44                             ` Peter Hurley
  -1 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 17:44 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby

Hi Maxime,

On 03/24/2015 01:21 PM, Maxime Coquelin wrote:
> Hi Peter,
> 
> 2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>:
>>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>>> +                           struct ktermios *old)
>>> [...]
>>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>>> +               fraction = 0;
>>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>>> +       }
>>> [...]
>>>> Really, I would prefer keeping this fractional divider as it is
>>>> implemented today.
>>>
>>> You have to admit that's basically an unintelligible mess;
>>> how would anyone ever be able to refactor and replace that with a
>>> common divider implementation?
>>>
>>> At the very least, please comment on the formula and format.
>>
>> Ok, I will refactor the implementation, and comment it.
> 
> The implementation was indeed a mess.
> I found some time to refactor the code, and also added support for 8
> times oversampling (16 by default).
> It will allow to achieve higher speeds, with the side effect of being
> less tolerant to clock deviations.
> 
> What do you think about the code below?
> 
> 
>     usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
> 
>     /*
>      * The USART supports 16 or 8 times oversampling.
>      * By default we prefer 16 times oversampling, so that the receiver
>      * has a better tolerance to clock deviations.
>      * 8 times oversampling is only used to achieve higher speeds.
>      */
>     if (usartdiv < 16) {
>         oversampling = 8;
>         stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
>     } else {
>         oversampling = 16;
>         stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
>     }
> 
>     mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
>     fraction = usartdiv % oversampling;
>     writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks! Way better :)
Much more obvious this is a fixed-point divisor.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 17:44                             ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 17:44 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Andy Shevchenko, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, Linux Documentation List, linux-arm Mailing List,
	linux-kernel, devicetree, linux-gpio, linux-serial, Linux-Arch,
	linux-api

Hi Maxime,

On 03/24/2015 01:21 PM, Maxime Coquelin wrote:
> Hi Peter,
> 
> 2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32@gmail.com>:
>> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
>>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>>> +                           struct ktermios *old)
>>> [...]
>>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>>> +               fraction = 0;
>>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>>> +       }
>>> [...]
>>>> Really, I would prefer keeping this fractional divider as it is
>>>> implemented today.
>>>
>>> You have to admit that's basically an unintelligible mess;
>>> how would anyone ever be able to refactor and replace that with a
>>> common divider implementation?
>>>
>>> At the very least, please comment on the formula and format.
>>
>> Ok, I will refactor the implementation, and comment it.
> 
> The implementation was indeed a mess.
> I found some time to refactor the code, and also added support for 8
> times oversampling (16 by default).
> It will allow to achieve higher speeds, with the side effect of being
> less tolerant to clock deviations.
> 
> What do you think about the code below?
> 
> 
>     usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
> 
>     /*
>      * The USART supports 16 or 8 times oversampling.
>      * By default we prefer 16 times oversampling, so that the receiver
>      * has a better tolerance to clock deviations.
>      * 8 times oversampling is only used to achieve higher speeds.
>      */
>     if (usartdiv < 16) {
>         oversampling = 8;
>         stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
>     } else {
>         oversampling = 16;
>         stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
>     }
> 
>     mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
>     fraction = usartdiv % oversampling;
>     writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks! Way better :)
Much more obvious this is a fixed-point divisor.

Regards,
Peter Hurley




^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 17:44                             ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

On 03/24/2015 01:21 PM, Maxime Coquelin wrote:
> Hi Peter,
> 
> 2015-03-19 18:35 GMT+01:00 Maxime Coquelin <mcoquelin.stm32@gmail.com>:
>> 2015-03-19 15:58 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
>>> On 03/19/2015 09:55 AM, Maxime Coquelin wrote:
>>>>>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>>>>>> +                           struct ktermios *old)
>>> [...]
>>>>>>>> +       usardiv = (port->uartclk * 25) / (baud * 4);
>>>>>>>> +       mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>>>>>>>> +       fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>>>>>>>> +       if (fraction & ~USART_BRR_DIV_F_MASK) {
>>>>>>>> +               fraction = 0;
>>>>>>>> +               mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>>>>>>>> +       }
>>> [...]
>>>> Really, I would prefer keeping this fractional divider as it is
>>>> implemented today.
>>>
>>> You have to admit that's basically an unintelligible mess;
>>> how would anyone ever be able to refactor and replace that with a
>>> common divider implementation?
>>>
>>> At the very least, please comment on the formula and format.
>>
>> Ok, I will refactor the implementation, and comment it.
> 
> The implementation was indeed a mess.
> I found some time to refactor the code, and also added support for 8
> times oversampling (16 by default).
> It will allow to achieve higher speeds, with the side effect of being
> less tolerant to clock deviations.
> 
> What do you think about the code below?
> 
> 
>     usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
> 
>     /*
>      * The USART supports 16 or 8 times oversampling.
>      * By default we prefer 16 times oversampling, so that the receiver
>      * has a better tolerance to clock deviations.
>      * 8 times oversampling is only used to achieve higher speeds.
>      */
>     if (usartdiv < 16) {
>         oversampling = 8;
>         stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
>     } else {
>         oversampling = 16;
>         stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
>     }
> 
>     mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
>     fraction = usartdiv % oversampling;
>     writel_relaxed(mantissa | fraction, port->membase + USART_BRR)

Thanks! Way better :)
Much more obvious this is a fixed-point divisor.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-12 21:55     ` Maxime Coquelin
  (?)
@ 2015-03-24 18:23         ` Peter Hurley
  -1 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 18:23 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

Hi Maxime,

On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> 
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

Comments below.

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>  	  with "earlycon" on the kernel command line. The console is
>  	  enabled when early_param is processed.
>  
> +config SERIAL_STM32
> +	tristate "STMicroelectronics STM32 serial port support"
> +	select SERIAL_CORE
> +	depends on ARM || COMPILE_TEST
> +	help
> +	  This driver is for the on-chip Serial Controller on
> +	  STMicroelectronics STM32 MCUs.
> +	  USART supports Rx & Tx functionality.
> +	  It support all industry standard baud rates.
> +
> +	  If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +	bool "Support for console on STM32"
> +	depends on SERIAL_STM32=y
> +	select SERIAL_CORE_CONSOLE
> +
>  endmenu
>  
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
>  
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR		0x00
> +#define USART_DR		0x04
> +#define USART_BRR		0x08
> +#define USART_CR1		0x0c
> +#define USART_CR2		0x10
> +#define USART_CR3		0x14
> +#define USART_GTPR		0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE		BIT(0)
> +#define USART_SR_FE		BIT(1)
> +#define USART_SR_NF		BIT(2)
> +#define USART_SR_ORE		BIT(3)
> +#define USART_SR_IDLE		BIT(4)
> +#define USART_SR_RXNE		BIT(5)
> +#define USART_SR_TC		BIT(6)
> +#define USART_SR_TXE		BIT(7)
> +#define USART_SR_LBD		BIT(8)
> +#define USART_SR_CTS		BIT(9)
> +#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
> +				 USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX	BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK		GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT	4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK		BIT(0)
> +#define USART_CR1_RWU		BIT(1)
> +#define USART_CR1_RE		BIT(2)
> +#define USART_CR1_TE		BIT(3)
> +#define USART_CR1_IDLEIE	BIT(4)
> +#define USART_CR1_RXNEIE	BIT(5)
> +#define USART_CR1_TCIE		BIT(6)
> +#define USART_CR1_TXEIE		BIT(7)
> +#define USART_CR1_PEIE		BIT(8)
> +#define USART_CR1_PS		BIT(9)
> +#define USART_CR1_PCE		BIT(10)
> +#define USART_CR1_WAKE		BIT(11)
> +#define USART_CR1_M		BIT(12)
> +#define USART_CR1_UE		BIT(13)
> +#define USART_CR1_OVER8		BIT(15)
> +#define USART_CR1_IE_MASK	GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK	GENMASK(3, 0)
> +#define USART_CR2_LBDL		BIT(5)
> +#define USART_CR2_LBDIE		BIT(6)
> +#define USART_CR2_LBCL		BIT(8)
> +#define USART_CR2_CPHA		BIT(9)
> +#define USART_CR2_CPOL		BIT(10)
> +#define USART_CR2_CLKEN		BIT(11)
> +#define USART_CR2_STOP_2B	BIT(13)
> +#define USART_CR2_STOP_MASK	GENMASK(13, 12)
> +#define USART_CR2_LINEN		BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE		BIT(0)
> +#define USART_CR3_IREN		BIT(1)
> +#define USART_CR3_IRLP		BIT(2)
> +#define USART_CR3_HDSEL		BIT(3)
> +#define USART_CR3_NACK		BIT(4)
> +#define USART_CR3_SCEN		BIT(5)
> +#define USART_CR3_DMAR		BIT(6)
> +#define USART_CR3_DMAT		BIT(7)
> +#define USART_CR3_RTSE		BIT(8)
> +#define USART_CR3_CTSE		BIT(9)
> +#define USART_CR3_CTSIE		BIT(10)
> +#define USART_CR3_ONEBIT	BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK	GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +	struct uart_port port;
> +	struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val |= bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val &= ~bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +	struct tty_port *tport = &port->state->port;
> +	unsigned long c;
> +	u32 sr;
> +	char flag;
> +
> +	if (port->irq_wake)
> +		pm_wakeup_event(tport->tty->dev, 0);
> +
> +	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +		sr |= USART_SR_DUMMY_RX;
> +		c = readl_relaxed(port->membase + USART_DR);
> +		flag = TTY_NORMAL;
> +		port->icount.rx++;
> +
> +		if (sr & USART_SR_ERR_MASK) {
> +			if (sr & USART_SR_LBD) {
> +				port->icount.brk++;
> +				if (uart_handle_break(port))
> +					continue;
> +			} else if (sr & USART_SR_ORE) {
> +				port->icount.overrun++;
> +			} else if (sr & USART_SR_PE) {
> +				port->icount.parity++;
> +			} else if (sr & USART_SR_FE) {
> +				port->icount.frame++;
> +			}
> +
> +			sr &= port->read_status_mask;
> +
> +			if (sr & USART_SR_LBD)
> +				flag = TTY_BREAK;
> +			else if (sr & USART_SR_PE)
> +				flag = TTY_PARITY;
> +			else if (sr & USART_SR_FE)
> +				flag = TTY_FRAME;
> +		}
> +
> +		if (uart_handle_sysrq_char(port, c))
> +			continue;
> +		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +	}
> +
> +	spin_unlock(&port->lock);
> +	tty_flip_buffer_push(tport);
> +	spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (port->x_char) {
> +		writel_relaxed(port->x_char, port->membase + USART_DR);
> +		port->x_char = 0;
> +		port->icount.tx++;
> +		return;
> +	}
> +
> +	if (uart_tx_stopped(port)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	if (uart_circ_empty(xmit)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +	port->icount.tx++;
> +
> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +		uart_write_wakeup(port);
> +
> +	if (uart_circ_empty(xmit))
> +		stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +	struct uart_port *port = ptr;
> +	u32 sr;
> +
> +	spin_lock(&port->lock);
> +
> +	sr = readl_relaxed(port->membase + USART_SR);
> +
> +	if (sr & USART_SR_RXNE)
> +		stm32_receive_chars(port);
> +
> +	if (sr & USART_SR_TXE)
> +		stm32_transmit_chars(port);
> +
> +	spin_unlock(&port->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +	/*
> +	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +	 * We use USART's hardware for CTS/RTS, so don't need any for that.

If this means that you're enabling autoflow control, then you still need
to respond to the state of TIOCM_RTS, so that both serial core and userspace
can halt input flow.

If the hardware doesn't support separate RTS enable/disable control,
then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
it when raised.


> +	 * Some boards have DTR and DCD implemented using PIO pins,
> +	 * code to do this should be hooked in here.
> +	 */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +	/*
> +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +	 * and CTS/RTS
> +	 */
> +	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (uart_circ_empty(xmit))
> +		return;
> +
> +	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +	/* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +	const char *name = to_platform_device(port->dev)->name;
> +	u32 val;
> +
> +	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +				name, port)) {
> +		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +		return -ENODEV;
> +	}
> +
> +	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +	u32 val;
> +
> +	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +			    struct ktermios *old)
> +{
> +	unsigned int baud;
> +	u32 usardiv, mantissa, fraction;
> +	tcflag_t cflag;
> +	u32 cr1, cr2, cr3;
> +	unsigned long flags;
> +
> +	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +	cflag = termios->c_cflag;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	/* Stop serial port and reset value */
> +	writel_relaxed(0, port->membase + USART_CR1);
> +
> +	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +	if (cflag & CSTOPB)
> +		cr2 = USART_CR2_STOP_2B;
> +
> +	if (cflag & PARENB) {
> +		cr1 |= USART_CR1_PCE;
> +		if ((cflag & CSIZE) == CS8)
> +			cr1 |= USART_CR1_M;
> +	}
> +
> +	if (cflag & PARODD)
> +		cr1 |= USART_CR1_PS;
> +
> +	if (cflag & CRTSCTS)
> +		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;

If this means autoflow control, then you need to define
throttle()/unthrottle() methods, otherwise the serial core won't
be able to throttle the remote when input buffers are about
to overflow.

And you should only enable the autoCTS and let the serial
core enable autoRTS through set_mctrl(TIOCM_RTS).

Just let me know if you need more info about how to do this.

> +
> +	usardiv = (port->uartclk * 25) / (baud * 4);
> +	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +	if (fraction & ~USART_BRR_DIV_F_MASK) {
> +		fraction = 0;
> +		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +	}
> +
> +	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +	uart_update_timeout(port, cflag, baud);
> +
> +	port->read_status_mask = USART_SR_ORE;
> +	if (termios->c_iflag & INPCK)
> +		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +		port->read_status_mask |= USART_SR_LBD;
> +
> +	/* Characters to ignore */
> +	port->ignore_status_mask = 0;
> +	if (termios->c_iflag & IGNPAR)
> +		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & IGNBRK) {
> +		port->ignore_status_mask |= USART_SR_LBD;
> +		/*
> +		 * If we're ignoring parity and break indicators,
> +		 * ignore overruns too (for real raw support).
> +		 */
> +		if (termios->c_iflag & IGNPAR)
> +			port->ignore_status_mask |= USART_SR_ORE;
> +	}
> +
> +	/*
> +	 * Ignore all characters if CREAD is not set.
> +	 */
> +	if ((termios->c_cflag & CREAD) == 0)
> +		port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +	writel_relaxed(cr3, port->membase + USART_CR3);
> +	writel_relaxed(cr2, port->membase + USART_CR2);
> +	writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +	if ((flags & UART_CONFIG_TYPE))

Single parens.

> +		port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +	/* No user changeable parameters */
> +	return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +		unsigned int oldstate)
> +{
> +	struct stm32_port *stm32port = container_of(port,
> +			struct stm32_port, port);
> +	unsigned long flags = 0;
> +
> +	switch (state) {
> +	case UART_PM_STATE_ON:
> +		clk_prepare_enable(stm32port->clk);
> +		break;
> +	case UART_PM_STATE_OFF:
> +		spin_lock_irqsave(&port->lock, flags);
> +		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +		spin_unlock_irqrestore(&port->lock, flags);
> +		clk_disable_unprepare(stm32port->clk);
> +		break;
> +	}
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +	.tx_empty	= stm32_tx_empty,
> +	.set_mctrl	= stm32_set_mctrl,
> +	.get_mctrl	= stm32_get_mctrl,
> +	.start_tx	= stm32_start_tx,
> +	.stop_tx	= stm32_stop_tx,
> +	.stop_rx	= stm32_stop_rx,
> +	.break_ctl	= stm32_break_ctl,
> +	.startup	= stm32_startup,
> +	.shutdown	= stm32_shutdown,
> +	.set_termios	= stm32_set_termios,
> +	.type		= stm32_type,
> +	.release_port	= stm32_release_port,
> +	.request_port	= stm32_request_port,
> +	.config_port	= stm32_config_port,
> +	.verify_port	= stm32_verify_port,
> +	.pm		= stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +			  struct platform_device *pdev)
> +{
> +	struct uart_port *port = &stm32port->port;
> +	struct resource *res;
> +
> +	port->iotype	= UPIO_MEM;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->ops	= &stm32_uart_ops;
> +	port->dev	= &pdev->dev;
> +	port->irq	= platform_get_irq(pdev, 0);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	port->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(port->membase))
> +		return PTR_ERR(port->membase);
> +	port->mapbase = res->start;
> +
> +	spin_lock_init(&port->lock);
> +
> +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +	if (WARN_ON(IS_ERR(stm32port->clk)))

Do you really need a stack trace here? Could this be dev_err() instead?

> +		return -EINVAL;
> +
> +	/* ensure that clk rate is correct by enabling the clk */
> +	clk_prepare_enable(stm32port->clk);
> +	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +	WARN_ON(stm32port->port.uartclk == 0);

Or here?

> +	clk_disable_unprepare(stm32port->clk);
> +
> +	return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int id;
> +
> +	if (!np)
> +		return NULL;
> +
> +	id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +	if (id < 0)
> +		id = 0;
> +
> +	if (WARN_ON(id >= STM32_MAX_PORTS))

Or here?

> +		return NULL;
> +
> +	stm32_ports[id].port.line = id;
> +	return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +	{ .compatible = "st,stm32-usart", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct stm32_port *stm32port;
> +
> +	stm32port = stm32_of_get_stm32_port(pdev);
> +	if (!stm32port)
> +		return -ENODEV;
> +
> +	ret = stm32_init_port(stm32port, pdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, &stm32port->port);
> +
> +	return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +	struct uart_port *port = platform_get_drvdata(pdev);
> +
> +	return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +		cpu_relax();
> +
> +	writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +	struct uart_port *port = &stm32_ports[co->index].port;
> +	unsigned long flags;
> +	u32 old_cr1, new_cr1;
> +	int locked = 1;
> +
> +	if (oops_in_progress) {
> +		locked = spin_trylock_irqsave(&port->lock, flags);
> +	} else {
> +		locked = 1;
> +		spin_lock_irqsave(&port->lock, flags);
> +	}
> +
> +	/* Save and disable interrupts */
> +	old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +	writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +	uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +	/* Restore interrupt state */
> +	writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +	if (locked)
> +		spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +	struct stm32_port *stm32port;
> +	int baud = 9600;
> +	int bits = 8;
> +	int parity = 'n';
> +	int flow = 'n';
> +
> +	if (co->index >= STM32_MAX_PORTS)
> +		return -ENODEV;
> +
> +	stm32port = &stm32_ports[co->index];
> +
> +	/*
> +	 * This driver does not support early console initialization
> +	 * (use ARM early printk support instead), so we only expect
> +	 * this to be called during the uart port registration when the
> +	 * driver gets probed and the port should be mapped at that point.
> +	 */
> +	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +		return -ENXIO;
> +
> +	if (options)
> +		uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +	.name		= STM32_SERIAL_NAME,
> +	.device		= uart_console_device,
> +	.write		= stm32_console_write,
> +	.setup		= stm32_console_setup,
> +	.flags		= CON_PRINTBUFFER,
> +	.index		= -1,
> +	.data		= &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +	.owner		= THIS_MODULE,
> +	.driver_name	= DRIVER_NAME,
> +	.dev_name	= STM32_SERIAL_NAME,
> +	.major		= 0,
> +	.minor		= 0,
> +	.nr		= STM32_MAX_PORTS,
> +	.cons		= STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +	.probe		= stm32_serial_probe,
> +	.remove		= stm32_serial_remove,
> +	.driver	= {
> +		.name	= DRIVER_NAME,
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(stm32_match),
> +	},
> +};
> +
> +static int __init usart_init(void)
> +{
> +	int ret;
> +	static char banner[] __initdata =
> +		KERN_INFO "STM32 USART driver initialized\n";
> +
> +	printk(banner);
> +
> +	ret = uart_register_driver(&stm32_usart_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&stm32_serial_driver);
> +	if (ret)
> +		uart_unregister_driver(&stm32_usart_driver);
> +
> +	return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +	platform_driver_unregister(&stm32_serial_driver);
> +	uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS	112
>  
> +/* STM32 USART */
> +#define PORT_STM32	110

Already taken.

You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Regards,
Peter Hurley

> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 18:23         ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 18:23 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: u.kleine-koenig, afaerber, geert, Rob Herring, Philipp Zabel,
	Linus Walleij, Arnd Bergmann, stefan, pmeerw, pebolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
	Greg Kroah-Hartman, Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

Hi Maxime,

On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

Comments below.

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>  	  with "earlycon" on the kernel command line. The console is
>  	  enabled when early_param is processed.
>  
> +config SERIAL_STM32
> +	tristate "STMicroelectronics STM32 serial port support"
> +	select SERIAL_CORE
> +	depends on ARM || COMPILE_TEST
> +	help
> +	  This driver is for the on-chip Serial Controller on
> +	  STMicroelectronics STM32 MCUs.
> +	  USART supports Rx & Tx functionality.
> +	  It support all industry standard baud rates.
> +
> +	  If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +	bool "Support for console on STM32"
> +	depends on SERIAL_STM32=y
> +	select SERIAL_CORE_CONSOLE
> +
>  endmenu
>  
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
>  
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR		0x00
> +#define USART_DR		0x04
> +#define USART_BRR		0x08
> +#define USART_CR1		0x0c
> +#define USART_CR2		0x10
> +#define USART_CR3		0x14
> +#define USART_GTPR		0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE		BIT(0)
> +#define USART_SR_FE		BIT(1)
> +#define USART_SR_NF		BIT(2)
> +#define USART_SR_ORE		BIT(3)
> +#define USART_SR_IDLE		BIT(4)
> +#define USART_SR_RXNE		BIT(5)
> +#define USART_SR_TC		BIT(6)
> +#define USART_SR_TXE		BIT(7)
> +#define USART_SR_LBD		BIT(8)
> +#define USART_SR_CTS		BIT(9)
> +#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
> +				 USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX	BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK		GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT	4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK		BIT(0)
> +#define USART_CR1_RWU		BIT(1)
> +#define USART_CR1_RE		BIT(2)
> +#define USART_CR1_TE		BIT(3)
> +#define USART_CR1_IDLEIE	BIT(4)
> +#define USART_CR1_RXNEIE	BIT(5)
> +#define USART_CR1_TCIE		BIT(6)
> +#define USART_CR1_TXEIE		BIT(7)
> +#define USART_CR1_PEIE		BIT(8)
> +#define USART_CR1_PS		BIT(9)
> +#define USART_CR1_PCE		BIT(10)
> +#define USART_CR1_WAKE		BIT(11)
> +#define USART_CR1_M		BIT(12)
> +#define USART_CR1_UE		BIT(13)
> +#define USART_CR1_OVER8		BIT(15)
> +#define USART_CR1_IE_MASK	GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK	GENMASK(3, 0)
> +#define USART_CR2_LBDL		BIT(5)
> +#define USART_CR2_LBDIE		BIT(6)
> +#define USART_CR2_LBCL		BIT(8)
> +#define USART_CR2_CPHA		BIT(9)
> +#define USART_CR2_CPOL		BIT(10)
> +#define USART_CR2_CLKEN		BIT(11)
> +#define USART_CR2_STOP_2B	BIT(13)
> +#define USART_CR2_STOP_MASK	GENMASK(13, 12)
> +#define USART_CR2_LINEN		BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE		BIT(0)
> +#define USART_CR3_IREN		BIT(1)
> +#define USART_CR3_IRLP		BIT(2)
> +#define USART_CR3_HDSEL		BIT(3)
> +#define USART_CR3_NACK		BIT(4)
> +#define USART_CR3_SCEN		BIT(5)
> +#define USART_CR3_DMAR		BIT(6)
> +#define USART_CR3_DMAT		BIT(7)
> +#define USART_CR3_RTSE		BIT(8)
> +#define USART_CR3_CTSE		BIT(9)
> +#define USART_CR3_CTSIE		BIT(10)
> +#define USART_CR3_ONEBIT	BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK	GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +	struct uart_port port;
> +	struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val |= bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val &= ~bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +	struct tty_port *tport = &port->state->port;
> +	unsigned long c;
> +	u32 sr;
> +	char flag;
> +
> +	if (port->irq_wake)
> +		pm_wakeup_event(tport->tty->dev, 0);
> +
> +	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +		sr |= USART_SR_DUMMY_RX;
> +		c = readl_relaxed(port->membase + USART_DR);
> +		flag = TTY_NORMAL;
> +		port->icount.rx++;
> +
> +		if (sr & USART_SR_ERR_MASK) {
> +			if (sr & USART_SR_LBD) {
> +				port->icount.brk++;
> +				if (uart_handle_break(port))
> +					continue;
> +			} else if (sr & USART_SR_ORE) {
> +				port->icount.overrun++;
> +			} else if (sr & USART_SR_PE) {
> +				port->icount.parity++;
> +			} else if (sr & USART_SR_FE) {
> +				port->icount.frame++;
> +			}
> +
> +			sr &= port->read_status_mask;
> +
> +			if (sr & USART_SR_LBD)
> +				flag = TTY_BREAK;
> +			else if (sr & USART_SR_PE)
> +				flag = TTY_PARITY;
> +			else if (sr & USART_SR_FE)
> +				flag = TTY_FRAME;
> +		}
> +
> +		if (uart_handle_sysrq_char(port, c))
> +			continue;
> +		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +	}
> +
> +	spin_unlock(&port->lock);
> +	tty_flip_buffer_push(tport);
> +	spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (port->x_char) {
> +		writel_relaxed(port->x_char, port->membase + USART_DR);
> +		port->x_char = 0;
> +		port->icount.tx++;
> +		return;
> +	}
> +
> +	if (uart_tx_stopped(port)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	if (uart_circ_empty(xmit)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +	port->icount.tx++;
> +
> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +		uart_write_wakeup(port);
> +
> +	if (uart_circ_empty(xmit))
> +		stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +	struct uart_port *port = ptr;
> +	u32 sr;
> +
> +	spin_lock(&port->lock);
> +
> +	sr = readl_relaxed(port->membase + USART_SR);
> +
> +	if (sr & USART_SR_RXNE)
> +		stm32_receive_chars(port);
> +
> +	if (sr & USART_SR_TXE)
> +		stm32_transmit_chars(port);
> +
> +	spin_unlock(&port->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +	/*
> +	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +	 * We use USART's hardware for CTS/RTS, so don't need any for that.

If this means that you're enabling autoflow control, then you still need
to respond to the state of TIOCM_RTS, so that both serial core and userspace
can halt input flow.

If the hardware doesn't support separate RTS enable/disable control,
then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
it when raised.


> +	 * Some boards have DTR and DCD implemented using PIO pins,
> +	 * code to do this should be hooked in here.
> +	 */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +	/*
> +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +	 * and CTS/RTS
> +	 */
> +	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (uart_circ_empty(xmit))
> +		return;
> +
> +	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +	/* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +	const char *name = to_platform_device(port->dev)->name;
> +	u32 val;
> +
> +	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +				name, port)) {
> +		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +		return -ENODEV;
> +	}
> +
> +	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +	u32 val;
> +
> +	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +			    struct ktermios *old)
> +{
> +	unsigned int baud;
> +	u32 usardiv, mantissa, fraction;
> +	tcflag_t cflag;
> +	u32 cr1, cr2, cr3;
> +	unsigned long flags;
> +
> +	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +	cflag = termios->c_cflag;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	/* Stop serial port and reset value */
> +	writel_relaxed(0, port->membase + USART_CR1);
> +
> +	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +	if (cflag & CSTOPB)
> +		cr2 = USART_CR2_STOP_2B;
> +
> +	if (cflag & PARENB) {
> +		cr1 |= USART_CR1_PCE;
> +		if ((cflag & CSIZE) == CS8)
> +			cr1 |= USART_CR1_M;
> +	}
> +
> +	if (cflag & PARODD)
> +		cr1 |= USART_CR1_PS;
> +
> +	if (cflag & CRTSCTS)
> +		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;

If this means autoflow control, then you need to define
throttle()/unthrottle() methods, otherwise the serial core won't
be able to throttle the remote when input buffers are about
to overflow.

And you should only enable the autoCTS and let the serial
core enable autoRTS through set_mctrl(TIOCM_RTS).

Just let me know if you need more info about how to do this.

> +
> +	usardiv = (port->uartclk * 25) / (baud * 4);
> +	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +	if (fraction & ~USART_BRR_DIV_F_MASK) {
> +		fraction = 0;
> +		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +	}
> +
> +	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +	uart_update_timeout(port, cflag, baud);
> +
> +	port->read_status_mask = USART_SR_ORE;
> +	if (termios->c_iflag & INPCK)
> +		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +		port->read_status_mask |= USART_SR_LBD;
> +
> +	/* Characters to ignore */
> +	port->ignore_status_mask = 0;
> +	if (termios->c_iflag & IGNPAR)
> +		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & IGNBRK) {
> +		port->ignore_status_mask |= USART_SR_LBD;
> +		/*
> +		 * If we're ignoring parity and break indicators,
> +		 * ignore overruns too (for real raw support).
> +		 */
> +		if (termios->c_iflag & IGNPAR)
> +			port->ignore_status_mask |= USART_SR_ORE;
> +	}
> +
> +	/*
> +	 * Ignore all characters if CREAD is not set.
> +	 */
> +	if ((termios->c_cflag & CREAD) == 0)
> +		port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +	writel_relaxed(cr3, port->membase + USART_CR3);
> +	writel_relaxed(cr2, port->membase + USART_CR2);
> +	writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +	if ((flags & UART_CONFIG_TYPE))

Single parens.

> +		port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +	/* No user changeable parameters */
> +	return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +		unsigned int oldstate)
> +{
> +	struct stm32_port *stm32port = container_of(port,
> +			struct stm32_port, port);
> +	unsigned long flags = 0;
> +
> +	switch (state) {
> +	case UART_PM_STATE_ON:
> +		clk_prepare_enable(stm32port->clk);
> +		break;
> +	case UART_PM_STATE_OFF:
> +		spin_lock_irqsave(&port->lock, flags);
> +		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +		spin_unlock_irqrestore(&port->lock, flags);
> +		clk_disable_unprepare(stm32port->clk);
> +		break;
> +	}
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +	.tx_empty	= stm32_tx_empty,
> +	.set_mctrl	= stm32_set_mctrl,
> +	.get_mctrl	= stm32_get_mctrl,
> +	.start_tx	= stm32_start_tx,
> +	.stop_tx	= stm32_stop_tx,
> +	.stop_rx	= stm32_stop_rx,
> +	.break_ctl	= stm32_break_ctl,
> +	.startup	= stm32_startup,
> +	.shutdown	= stm32_shutdown,
> +	.set_termios	= stm32_set_termios,
> +	.type		= stm32_type,
> +	.release_port	= stm32_release_port,
> +	.request_port	= stm32_request_port,
> +	.config_port	= stm32_config_port,
> +	.verify_port	= stm32_verify_port,
> +	.pm		= stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +			  struct platform_device *pdev)
> +{
> +	struct uart_port *port = &stm32port->port;
> +	struct resource *res;
> +
> +	port->iotype	= UPIO_MEM;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->ops	= &stm32_uart_ops;
> +	port->dev	= &pdev->dev;
> +	port->irq	= platform_get_irq(pdev, 0);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	port->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(port->membase))
> +		return PTR_ERR(port->membase);
> +	port->mapbase = res->start;
> +
> +	spin_lock_init(&port->lock);
> +
> +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +	if (WARN_ON(IS_ERR(stm32port->clk)))

Do you really need a stack trace here? Could this be dev_err() instead?

> +		return -EINVAL;
> +
> +	/* ensure that clk rate is correct by enabling the clk */
> +	clk_prepare_enable(stm32port->clk);
> +	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +	WARN_ON(stm32port->port.uartclk == 0);

Or here?

> +	clk_disable_unprepare(stm32port->clk);
> +
> +	return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int id;
> +
> +	if (!np)
> +		return NULL;
> +
> +	id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +	if (id < 0)
> +		id = 0;
> +
> +	if (WARN_ON(id >= STM32_MAX_PORTS))

Or here?

> +		return NULL;
> +
> +	stm32_ports[id].port.line = id;
> +	return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +	{ .compatible = "st,stm32-usart", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct stm32_port *stm32port;
> +
> +	stm32port = stm32_of_get_stm32_port(pdev);
> +	if (!stm32port)
> +		return -ENODEV;
> +
> +	ret = stm32_init_port(stm32port, pdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, &stm32port->port);
> +
> +	return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +	struct uart_port *port = platform_get_drvdata(pdev);
> +
> +	return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +		cpu_relax();
> +
> +	writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +	struct uart_port *port = &stm32_ports[co->index].port;
> +	unsigned long flags;
> +	u32 old_cr1, new_cr1;
> +	int locked = 1;
> +
> +	if (oops_in_progress) {
> +		locked = spin_trylock_irqsave(&port->lock, flags);
> +	} else {
> +		locked = 1;
> +		spin_lock_irqsave(&port->lock, flags);
> +	}
> +
> +	/* Save and disable interrupts */
> +	old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +	writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +	uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +	/* Restore interrupt state */
> +	writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +	if (locked)
> +		spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +	struct stm32_port *stm32port;
> +	int baud = 9600;
> +	int bits = 8;
> +	int parity = 'n';
> +	int flow = 'n';
> +
> +	if (co->index >= STM32_MAX_PORTS)
> +		return -ENODEV;
> +
> +	stm32port = &stm32_ports[co->index];
> +
> +	/*
> +	 * This driver does not support early console initialization
> +	 * (use ARM early printk support instead), so we only expect
> +	 * this to be called during the uart port registration when the
> +	 * driver gets probed and the port should be mapped at that point.
> +	 */
> +	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +		return -ENXIO;
> +
> +	if (options)
> +		uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +	.name		= STM32_SERIAL_NAME,
> +	.device		= uart_console_device,
> +	.write		= stm32_console_write,
> +	.setup		= stm32_console_setup,
> +	.flags		= CON_PRINTBUFFER,
> +	.index		= -1,
> +	.data		= &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +	.owner		= THIS_MODULE,
> +	.driver_name	= DRIVER_NAME,
> +	.dev_name	= STM32_SERIAL_NAME,
> +	.major		= 0,
> +	.minor		= 0,
> +	.nr		= STM32_MAX_PORTS,
> +	.cons		= STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +	.probe		= stm32_serial_probe,
> +	.remove		= stm32_serial_remove,
> +	.driver	= {
> +		.name	= DRIVER_NAME,
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(stm32_match),
> +	},
> +};
> +
> +static int __init usart_init(void)
> +{
> +	int ret;
> +	static char banner[] __initdata =
> +		KERN_INFO "STM32 USART driver initialized\n";
> +
> +	printk(banner);
> +
> +	ret = uart_register_driver(&stm32_usart_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&stm32_serial_driver);
> +	if (ret)
> +		uart_unregister_driver(&stm32_usart_driver);
> +
> +	return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +	platform_driver_unregister(&stm32_serial_driver);
> +	uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS	112
>  
> +/* STM32 USART */
> +#define PORT_STM32	110

Already taken.

You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Regards,
Peter Hurley

> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> 


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-24 18:23         ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-24 18:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> 
> This drivers adds support to the STM32 USART controller, which is a
> standard serial driver.

Comments below.

> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
>  drivers/tty/serial/Kconfig       |  17 +
>  drivers/tty/serial/Makefile      |   1 +
>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/serial_core.h |   3 +
>  4 files changed, 716 insertions(+)
>  create mode 100644 drivers/tty/serial/stm32-usart.c
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index d2501f0..880cb4f 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1611,6 +1611,23 @@ config SERIAL_SPRD_CONSOLE
>  	  with "earlycon" on the kernel command line. The console is
>  	  enabled when early_param is processed.
>  
> +config SERIAL_STM32
> +	tristate "STMicroelectronics STM32 serial port support"
> +	select SERIAL_CORE
> +	depends on ARM || COMPILE_TEST
> +	help
> +	  This driver is for the on-chip Serial Controller on
> +	  STMicroelectronics STM32 MCUs.
> +	  USART supports Rx & Tx functionality.
> +	  It support all industry standard baud rates.
> +
> +	  If unsure, say N.
> +
> +config SERIAL_STM32_CONSOLE
> +	bool "Support for console on STM32"
> +	depends on SERIAL_STM32=y
> +	select SERIAL_CORE_CONSOLE
> +
>  endmenu
>  
>  config SERIAL_MCTRL_GPIO
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 599be4b..67c5023 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -95,6 +95,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
>  obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
>  obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
>  obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
> +obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
>  
>  # GPIOLIB helpers for modem control lines
>  obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
> new file mode 100644
> index 0000000..61bb065
> --- /dev/null
> +++ b/drivers/tty/serial/stm32-usart.c
> @@ -0,0 +1,695 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + *
> + * Inspired by st-asc.c from STMicroelectronics (c)
> + */
> +
> +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/serial.h>
> +#include <linux/console.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/delay.h>
> +#include <linux/spinlock.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/serial_core.h>
> +#include <linux/clk.h>
> +
> +#define DRIVER_NAME "stm32-usart"
> +
> +/* Register offsets */
> +#define USART_SR		0x00
> +#define USART_DR		0x04
> +#define USART_BRR		0x08
> +#define USART_CR1		0x0c
> +#define USART_CR2		0x10
> +#define USART_CR3		0x14
> +#define USART_GTPR		0x18
> +
> +/* USART_SR */
> +#define USART_SR_PE		BIT(0)
> +#define USART_SR_FE		BIT(1)
> +#define USART_SR_NF		BIT(2)
> +#define USART_SR_ORE		BIT(3)
> +#define USART_SR_IDLE		BIT(4)
> +#define USART_SR_RXNE		BIT(5)
> +#define USART_SR_TC		BIT(6)
> +#define USART_SR_TXE		BIT(7)
> +#define USART_SR_LBD		BIT(8)
> +#define USART_SR_CTS		BIT(9)
> +#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
> +				 USART_SR_FE | USART_SR_PE)
> +/* Dummy bits */
> +#define USART_SR_DUMMY_RX	BIT(16)
> +
> +/* USART_DR */
> +#define USART_DR_MASK		GENMASK(8, 0)
> +
> +/* USART_BRR */
> +#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
> +#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
> +#define USART_BRR_DIV_M_SHIFT	4
> +
> +/* USART_CR1 */
> +#define USART_CR1_SBK		BIT(0)
> +#define USART_CR1_RWU		BIT(1)
> +#define USART_CR1_RE		BIT(2)
> +#define USART_CR1_TE		BIT(3)
> +#define USART_CR1_IDLEIE	BIT(4)
> +#define USART_CR1_RXNEIE	BIT(5)
> +#define USART_CR1_TCIE		BIT(6)
> +#define USART_CR1_TXEIE		BIT(7)
> +#define USART_CR1_PEIE		BIT(8)
> +#define USART_CR1_PS		BIT(9)
> +#define USART_CR1_PCE		BIT(10)
> +#define USART_CR1_WAKE		BIT(11)
> +#define USART_CR1_M		BIT(12)
> +#define USART_CR1_UE		BIT(13)
> +#define USART_CR1_OVER8		BIT(15)
> +#define USART_CR1_IE_MASK	GENMASK(8, 4)
> +
> +/* USART_CR2 */
> +#define USART_CR2_ADD_MASK	GENMASK(3, 0)
> +#define USART_CR2_LBDL		BIT(5)
> +#define USART_CR2_LBDIE		BIT(6)
> +#define USART_CR2_LBCL		BIT(8)
> +#define USART_CR2_CPHA		BIT(9)
> +#define USART_CR2_CPOL		BIT(10)
> +#define USART_CR2_CLKEN		BIT(11)
> +#define USART_CR2_STOP_2B	BIT(13)
> +#define USART_CR2_STOP_MASK	GENMASK(13, 12)
> +#define USART_CR2_LINEN		BIT(14)
> +
> +/* USART_CR3 */
> +#define USART_CR3_EIE		BIT(0)
> +#define USART_CR3_IREN		BIT(1)
> +#define USART_CR3_IRLP		BIT(2)
> +#define USART_CR3_HDSEL		BIT(3)
> +#define USART_CR3_NACK		BIT(4)
> +#define USART_CR3_SCEN		BIT(5)
> +#define USART_CR3_DMAR		BIT(6)
> +#define USART_CR3_DMAT		BIT(7)
> +#define USART_CR3_RTSE		BIT(8)
> +#define USART_CR3_CTSE		BIT(9)
> +#define USART_CR3_CTSIE		BIT(10)
> +#define USART_CR3_ONEBIT	BIT(11)
> +
> +/* USART_GTPR */
> +#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
> +#define USART_GTPR_GT_MASK	GENMASK(15, 8)
> +
> +#define DRIVER_NAME "stm32-usart"
> +#define STM32_SERIAL_NAME "ttyS"
> +#define STM32_MAX_PORTS 6
> +
> +struct stm32_port {
> +	struct uart_port port;
> +	struct clk *clk;
> +};
> +
> +static struct stm32_port stm32_ports[STM32_MAX_PORTS];
> +static struct uart_driver stm32_usart_driver;
> +
> +static void stm32_stop_tx(struct uart_port *port);
> +
> +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val |= bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(port->membase + reg);
> +	val &= ~bits;
> +	writel_relaxed(val, port->membase + reg);
> +}
> +
> +static void stm32_receive_chars(struct uart_port *port)
> +{
> +	struct tty_port *tport = &port->state->port;
> +	unsigned long c;
> +	u32 sr;
> +	char flag;
> +
> +	if (port->irq_wake)
> +		pm_wakeup_event(tport->tty->dev, 0);
> +
> +	while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
> +		sr |= USART_SR_DUMMY_RX;
> +		c = readl_relaxed(port->membase + USART_DR);
> +		flag = TTY_NORMAL;
> +		port->icount.rx++;
> +
> +		if (sr & USART_SR_ERR_MASK) {
> +			if (sr & USART_SR_LBD) {
> +				port->icount.brk++;
> +				if (uart_handle_break(port))
> +					continue;
> +			} else if (sr & USART_SR_ORE) {
> +				port->icount.overrun++;
> +			} else if (sr & USART_SR_PE) {
> +				port->icount.parity++;
> +			} else if (sr & USART_SR_FE) {
> +				port->icount.frame++;
> +			}
> +
> +			sr &= port->read_status_mask;
> +
> +			if (sr & USART_SR_LBD)
> +				flag = TTY_BREAK;
> +			else if (sr & USART_SR_PE)
> +				flag = TTY_PARITY;
> +			else if (sr & USART_SR_FE)
> +				flag = TTY_FRAME;
> +		}
> +
> +		if (uart_handle_sysrq_char(port, c))
> +			continue;
> +		uart_insert_char(port, sr, USART_SR_ORE, c, flag);
> +	}
> +
> +	spin_unlock(&port->lock);
> +	tty_flip_buffer_push(tport);
> +	spin_lock(&port->lock);
> +}
> +
> +static void stm32_transmit_chars(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (port->x_char) {
> +		writel_relaxed(port->x_char, port->membase + USART_DR);
> +		port->x_char = 0;
> +		port->icount.tx++;
> +		return;
> +	}
> +
> +	if (uart_tx_stopped(port)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	if (uart_circ_empty(xmit)) {
> +		stm32_stop_tx(port);
> +		return;
> +	}
> +
> +	writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
> +	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +	port->icount.tx++;
> +
> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +		uart_write_wakeup(port);
> +
> +	if (uart_circ_empty(xmit))
> +		stm32_stop_tx(port);
> +}
> +
> +static irqreturn_t stm32_interrupt(int irq, void *ptr)
> +{
> +	struct uart_port *port = ptr;
> +	u32 sr;
> +
> +	spin_lock(&port->lock);
> +
> +	sr = readl_relaxed(port->membase + USART_SR);
> +
> +	if (sr & USART_SR_RXNE)
> +		stm32_receive_chars(port);
> +
> +	if (sr & USART_SR_TXE)
> +		stm32_transmit_chars(port);
> +
> +	spin_unlock(&port->lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static unsigned int stm32_tx_empty(struct uart_port *port)
> +{
> +	return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
> +}
> +
> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +	/*
> +	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
> +	 * We use USART's hardware for CTS/RTS, so don't need any for that.

If this means that you're enabling autoflow control, then you still need
to respond to the state of TIOCM_RTS, so that both serial core and userspace
can halt input flow.

If the hardware doesn't support separate RTS enable/disable control,
then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
it when raised.


> +	 * Some boards have DTR and DCD implemented using PIO pins,
> +	 * code to do this should be hooked in here.
> +	 */
> +}
> +
> +static unsigned int stm32_get_mctrl(struct uart_port *port)
> +{
> +	/*
> +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> +	 * and CTS/RTS
> +	 */
> +	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
> +}
> +
> +/* There are probably characters waiting to be transmitted. */
> +static void stm32_start_tx(struct uart_port *port)
> +{
> +	struct circ_buf *xmit = &port->state->xmit;
> +
> +	if (uart_circ_empty(xmit))
> +		return;
> +
> +	stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
> +}
> +
> +/* Transmit stop */
> +static void stm32_stop_tx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
> +}
> +
> +/* Receive stop */
> +static void stm32_stop_rx(struct uart_port *port)
> +{
> +	stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
> +}
> +
> +/* Handle breaks - ignored by us */
> +static void stm32_break_ctl(struct uart_port *port, int break_state)
> +{
> +	/* Nothing here yet .. */
> +}
> +
> +static int stm32_startup(struct uart_port *port)
> +{
> +	const char *name = to_platform_device(port->dev)->name;
> +	u32 val;
> +
> +	if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
> +				name, port)) {
> +		dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
> +		return -ENODEV;
> +	}
> +
> +	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	return 0;
> +}
> +
> +static void stm32_shutdown(struct uart_port *port)
> +{
> +	u32 val;
> +
> +	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
> +	stm32_set_bits(port, USART_CR1, val);
> +
> +	free_irq(port->irq, port);
> +}
> +
> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
> +			    struct ktermios *old)
> +{
> +	unsigned int baud;
> +	u32 usardiv, mantissa, fraction;
> +	tcflag_t cflag;
> +	u32 cr1, cr2, cr3;
> +	unsigned long flags;
> +
> +	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
> +	cflag = termios->c_cflag;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	/* Stop serial port and reset value */
> +	writel_relaxed(0, port->membase + USART_CR1);
> +
> +	cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
> +
> +	if (cflag & CSTOPB)
> +		cr2 = USART_CR2_STOP_2B;
> +
> +	if (cflag & PARENB) {
> +		cr1 |= USART_CR1_PCE;
> +		if ((cflag & CSIZE) == CS8)
> +			cr1 |= USART_CR1_M;
> +	}
> +
> +	if (cflag & PARODD)
> +		cr1 |= USART_CR1_PS;
> +
> +	if (cflag & CRTSCTS)
> +		cr3 = USART_CR3_RTSE | USART_CR3_CTSE;

If this means autoflow control, then you need to define
throttle()/unthrottle() methods, otherwise the serial core won't
be able to throttle the remote when input buffers are about
to overflow.

And you should only enable the autoCTS and let the serial
core enable autoRTS through set_mctrl(TIOCM_RTS).

Just let me know if you need more info about how to do this.

> +
> +	usardiv = (port->uartclk * 25) / (baud * 4);
> +	mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
> +	fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
> +	if (fraction & ~USART_BRR_DIV_F_MASK) {
> +		fraction = 0;
> +		mantissa += (1 << USART_BRR_DIV_M_SHIFT);
> +	}
> +
> +	writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
> +
> +	uart_update_timeout(port, cflag, baud);
> +
> +	port->read_status_mask = USART_SR_ORE;
> +	if (termios->c_iflag & INPCK)
> +		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
> +		port->read_status_mask |= USART_SR_LBD;
> +
> +	/* Characters to ignore */
> +	port->ignore_status_mask = 0;
> +	if (termios->c_iflag & IGNPAR)
> +		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
> +	if (termios->c_iflag & IGNBRK) {
> +		port->ignore_status_mask |= USART_SR_LBD;
> +		/*
> +		 * If we're ignoring parity and break indicators,
> +		 * ignore overruns too (for real raw support).
> +		 */
> +		if (termios->c_iflag & IGNPAR)
> +			port->ignore_status_mask |= USART_SR_ORE;
> +	}
> +
> +	/*
> +	 * Ignore all characters if CREAD is not set.
> +	 */
> +	if ((termios->c_cflag & CREAD) == 0)
> +		port->ignore_status_mask |= USART_SR_DUMMY_RX;
> +
> +	writel_relaxed(cr3, port->membase + USART_CR3);
> +	writel_relaxed(cr2, port->membase + USART_CR2);
> +	writel_relaxed(cr1, port->membase + USART_CR1);
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *stm32_type(struct uart_port *port)
> +{
> +	return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
> +}
> +
> +static void stm32_release_port(struct uart_port *port)
> +{
> +}
> +
> +static int stm32_request_port(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static void stm32_config_port(struct uart_port *port, int flags)
> +{
> +	if ((flags & UART_CONFIG_TYPE))

Single parens.

> +		port->type = PORT_STM32;
> +}
> +
> +static int
> +stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +	/* No user changeable parameters */
> +	return -EINVAL;
> +}
> +
> +static void stm32_pm(struct uart_port *port, unsigned int state,
> +		unsigned int oldstate)
> +{
> +	struct stm32_port *stm32port = container_of(port,
> +			struct stm32_port, port);
> +	unsigned long flags = 0;
> +
> +	switch (state) {
> +	case UART_PM_STATE_ON:
> +		clk_prepare_enable(stm32port->clk);
> +		break;
> +	case UART_PM_STATE_OFF:
> +		spin_lock_irqsave(&port->lock, flags);
> +		stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
> +		spin_unlock_irqrestore(&port->lock, flags);
> +		clk_disable_unprepare(stm32port->clk);
> +		break;
> +	}
> +}
> +
> +static struct uart_ops stm32_uart_ops = {
> +	.tx_empty	= stm32_tx_empty,
> +	.set_mctrl	= stm32_set_mctrl,
> +	.get_mctrl	= stm32_get_mctrl,
> +	.start_tx	= stm32_start_tx,
> +	.stop_tx	= stm32_stop_tx,
> +	.stop_rx	= stm32_stop_rx,
> +	.break_ctl	= stm32_break_ctl,
> +	.startup	= stm32_startup,
> +	.shutdown	= stm32_shutdown,
> +	.set_termios	= stm32_set_termios,
> +	.type		= stm32_type,
> +	.release_port	= stm32_release_port,
> +	.request_port	= stm32_request_port,
> +	.config_port	= stm32_config_port,
> +	.verify_port	= stm32_verify_port,
> +	.pm		= stm32_pm,
> +};
> +
> +static int stm32_init_port(struct stm32_port *stm32port,
> +			  struct platform_device *pdev)
> +{
> +	struct uart_port *port = &stm32port->port;
> +	struct resource *res;
> +
> +	port->iotype	= UPIO_MEM;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->ops	= &stm32_uart_ops;
> +	port->dev	= &pdev->dev;
> +	port->irq	= platform_get_irq(pdev, 0);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	port->membase = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(port->membase))
> +		return PTR_ERR(port->membase);
> +	port->mapbase = res->start;
> +
> +	spin_lock_init(&port->lock);
> +
> +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> +
> +	if (WARN_ON(IS_ERR(stm32port->clk)))

Do you really need a stack trace here? Could this be dev_err() instead?

> +		return -EINVAL;
> +
> +	/* ensure that clk rate is correct by enabling the clk */
> +	clk_prepare_enable(stm32port->clk);
> +	stm32port->port.uartclk = clk_get_rate(stm32port->clk);
> +	WARN_ON(stm32port->port.uartclk == 0);

Or here?

> +	clk_disable_unprepare(stm32port->clk);
> +
> +	return 0;
> +}
> +
> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int id;
> +
> +	if (!np)
> +		return NULL;
> +
> +	id = of_alias_get_id(np, STM32_SERIAL_NAME);
> +
> +	if (id < 0)
> +		id = 0;
> +
> +	if (WARN_ON(id >= STM32_MAX_PORTS))

Or here?

> +		return NULL;
> +
> +	stm32_ports[id].port.line = id;
> +	return &stm32_ports[id];
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_match[] = {
> +	{ .compatible = "st,stm32-usart", },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, stm32_match);
> +#endif
> +
> +static int stm32_serial_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct stm32_port *stm32port;
> +
> +	stm32port = stm32_of_get_stm32_port(pdev);
> +	if (!stm32port)
> +		return -ENODEV;
> +
> +	ret = stm32_init_port(stm32port, pdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, &stm32port->port);
> +
> +	return 0;
> +}
> +
> +static int stm32_serial_remove(struct platform_device *pdev)
> +{
> +	struct uart_port *port = platform_get_drvdata(pdev);
> +
> +	return uart_remove_one_port(&stm32_usart_driver, port);
> +}
> +
> +
> +#ifdef CONFIG_SERIAL_STM32_CONSOLE
> +static void stm32_console_putchar(struct uart_port *port, int ch)
> +{
> +	while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
> +		cpu_relax();
> +
> +	writel_relaxed(ch, port->membase + USART_DR);
> +}
> +
> +static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
> +{
> +	struct uart_port *port = &stm32_ports[co->index].port;
> +	unsigned long flags;
> +	u32 old_cr1, new_cr1;
> +	int locked = 1;
> +
> +	if (oops_in_progress) {
> +		locked = spin_trylock_irqsave(&port->lock, flags);
> +	} else {
> +		locked = 1;
> +		spin_lock_irqsave(&port->lock, flags);
> +	}
> +
> +	/* Save and disable interrupts */
> +	old_cr1 = readl_relaxed(port->membase + USART_CR1);
> +	new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
> +	writel_relaxed(new_cr1, port->membase + USART_CR1);
> +
> +	uart_console_write(port, s, cnt, stm32_console_putchar);
> +
> +	/* Restore interrupt state */
> +	writel_relaxed(old_cr1, port->membase + USART_CR1);
> +
> +	if (locked)
> +		spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int stm32_console_setup(struct console *co, char *options)
> +{
> +	struct stm32_port *stm32port;
> +	int baud = 9600;
> +	int bits = 8;
> +	int parity = 'n';
> +	int flow = 'n';
> +
> +	if (co->index >= STM32_MAX_PORTS)
> +		return -ENODEV;
> +
> +	stm32port = &stm32_ports[co->index];
> +
> +	/*
> +	 * This driver does not support early console initialization
> +	 * (use ARM early printk support instead), so we only expect
> +	 * this to be called during the uart port registration when the
> +	 * driver gets probed and the port should be mapped at that point.
> +	 */
> +	if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
> +		return -ENXIO;
> +
> +	if (options)
> +		uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +	return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
> +}
> +
> +static struct console stm32_console = {
> +	.name		= STM32_SERIAL_NAME,
> +	.device		= uart_console_device,
> +	.write		= stm32_console_write,
> +	.setup		= stm32_console_setup,
> +	.flags		= CON_PRINTBUFFER,
> +	.index		= -1,
> +	.data		= &stm32_usart_driver,
> +};
> +
> +#define STM32_SERIAL_CONSOLE (&stm32_console)
> +
> +#else
> +#define STM32_SERIAL_CONSOLE NULL
> +#endif /* CONFIG_SERIAL_STM32_CONSOLE */
> +
> +static struct uart_driver stm32_usart_driver = {
> +	.owner		= THIS_MODULE,
> +	.driver_name	= DRIVER_NAME,
> +	.dev_name	= STM32_SERIAL_NAME,
> +	.major		= 0,
> +	.minor		= 0,
> +	.nr		= STM32_MAX_PORTS,
> +	.cons		= STM32_SERIAL_CONSOLE,
> +};
> +
> +static struct platform_driver stm32_serial_driver = {
> +	.probe		= stm32_serial_probe,
> +	.remove		= stm32_serial_remove,
> +	.driver	= {
> +		.name	= DRIVER_NAME,
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(stm32_match),
> +	},
> +};
> +
> +static int __init usart_init(void)
> +{
> +	int ret;
> +	static char banner[] __initdata =
> +		KERN_INFO "STM32 USART driver initialized\n";
> +
> +	printk(banner);
> +
> +	ret = uart_register_driver(&stm32_usart_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&stm32_serial_driver);
> +	if (ret)
> +		uart_unregister_driver(&stm32_usart_driver);
> +
> +	return ret;
> +}
> +
> +static void __exit usart_exit(void)
> +{
> +	platform_driver_unregister(&stm32_serial_driver);
> +	uart_unregister_driver(&stm32_usart_driver);
> +}
> +
> +module_init(usart_init);
> +module_exit(usart_exit);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index b212281..e22dee5 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -258,4 +258,7 @@
>  /* Cris v10 / v32 SoC */
>  #define PORT_CRIS	112
>  
> +/* STM32 USART */
> +#define PORT_STM32	110

Already taken.

You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Regards,
Peter Hurley

> +
>  #endif /* _UAPILINUX_SERIAL_CORE_H */
> 

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  04/15] clocksource: Add ARM System timer driver
  2015-03-12 21:55   ` Maxime Coquelin
  (?)
@ 2015-03-26  9:50     ` Daniel Lezcano
  -1 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-26  9:50 UTC (permalink / raw)
  To: Maxime Coquelin, u.kleine-koenig, afaerber, geert, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan, pmeerw,
	pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpi

On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This patch adds clocksource support for ARMv7-M's System timer,
> also known as SysTick.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Hi Maxime,

the driver looks good. Three comments below.

   -- Daniel

> ---
>   drivers/clocksource/Kconfig          |  7 ++++
>   drivers/clocksource/Makefile         |  1 +
>   drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 86 insertions(+)
>   create mode 100644 drivers/clocksource/armv7m_systick.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 1c2506f..b82e58b 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>   	help
>   	 Use ARM global timer clock source as sched_clock
>
> +config ARMV7M_SYSTICK
> +	bool
> +	select CLKSRC_OF if OF
> +	select CLKSRC_MMIO
> +	help
> +	  This options enables support for the ARMv7M system timer unit
> +
>   config ATMEL_PIT
>   	select CLKSRC_OF if OF
>   	def_bool SOC_AT91SAM9 || SOC_SAMA5
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 752d5c7..1c9a643 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
>
>   obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
>   obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
> +obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
>   obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
> diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
> new file mode 100644
> index 0000000..23d8249
> --- /dev/null
> +++ b/drivers/clocksource/armv7m_systick.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/clk.h>
> +#include <linux/bitops.h>
> +
> +#define SYST_CSR	0x00
> +#define SYST_RVR	0x04
> +#define SYST_CVR	0x08
> +#define SYST_CALIB	0x0c
> +
> +#define SYST_CSR_ENABLE BIT(0)
> +
> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
> +
> +static void __init system_timer_of_register(struct device_node *np)
> +{
> +	struct clk *clk;
> +	void __iomem *base;
> +	u32 rate = 0;
> +	int ret;
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_warn("system-timer: invalid base address\n");
> +		return;
> +	}
> +
> +	clk = of_clk_get(np, 0);
> +	if (!IS_ERR(clk)) {
> +		ret = clk_prepare_enable(clk);
> +		if (ret) {
> +			clk_put(clk);
> +			goto out_unmap;
> +		}
> +
> +		rate = clk_get_rate(clk);
> +	}
> +
> +	/* If no clock found, try to get clock-frequency property */
> +	if (!rate) {
> +		ret = of_property_read_u32(np, "clock-frequency", &rate);
> +		if (ret)
> +			goto out_unmap;

Shouldn't be 'goto out_clk_disable' ?

> +	}
> +
> +	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
> +	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
> +
> +	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
> +			200, 24, clocksource_mmio_readl_down);
> +	if (ret) {
> +		pr_err("failed to init clocksource (%d)\n", ret);
> +		goto out_clk_disable;
> +	}
> +
> +	pr_info("ARM System timer initialized as clocksource\n");
> +
> +	return;
> +
> +out_clk_disable:
> +	if (!IS_ERR(clk))

Why do you need this check ?

It isn't missing a clk_put ?

> +		clk_disable_unprepare(clk);
> +out_unmap:
> +	iounmap(base);
> +	WARN(ret, "ARM System timer register failed (%d)\n", ret);
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
> +			system_timer_of_register);
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  04/15] clocksource: Add ARM System timer driver
@ 2015-03-26  9:50     ` Daniel Lezcano
  0 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-26  9:50 UTC (permalink / raw)
  To: Maxime Coquelin, u.kleine-koenig, afaerber, geert, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan, pmeerw,
	pebolle
  Cc: Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Russell King, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This patch adds clocksource support for ARMv7-M's System timer,
> also known as SysTick.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Hi Maxime,

the driver looks good. Three comments below.

   -- Daniel

> ---
>   drivers/clocksource/Kconfig          |  7 ++++
>   drivers/clocksource/Makefile         |  1 +
>   drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 86 insertions(+)
>   create mode 100644 drivers/clocksource/armv7m_systick.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 1c2506f..b82e58b 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>   	help
>   	 Use ARM global timer clock source as sched_clock
>
> +config ARMV7M_SYSTICK
> +	bool
> +	select CLKSRC_OF if OF
> +	select CLKSRC_MMIO
> +	help
> +	  This options enables support for the ARMv7M system timer unit
> +
>   config ATMEL_PIT
>   	select CLKSRC_OF if OF
>   	def_bool SOC_AT91SAM9 || SOC_SAMA5
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 752d5c7..1c9a643 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
>
>   obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
>   obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
> +obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
>   obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
> diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
> new file mode 100644
> index 0000000..23d8249
> --- /dev/null
> +++ b/drivers/clocksource/armv7m_systick.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/clk.h>
> +#include <linux/bitops.h>
> +
> +#define SYST_CSR	0x00
> +#define SYST_RVR	0x04
> +#define SYST_CVR	0x08
> +#define SYST_CALIB	0x0c
> +
> +#define SYST_CSR_ENABLE BIT(0)
> +
> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
> +
> +static void __init system_timer_of_register(struct device_node *np)
> +{
> +	struct clk *clk;
> +	void __iomem *base;
> +	u32 rate = 0;
> +	int ret;
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_warn("system-timer: invalid base address\n");
> +		return;
> +	}
> +
> +	clk = of_clk_get(np, 0);
> +	if (!IS_ERR(clk)) {
> +		ret = clk_prepare_enable(clk);
> +		if (ret) {
> +			clk_put(clk);
> +			goto out_unmap;
> +		}
> +
> +		rate = clk_get_rate(clk);
> +	}
> +
> +	/* If no clock found, try to get clock-frequency property */
> +	if (!rate) {
> +		ret = of_property_read_u32(np, "clock-frequency", &rate);
> +		if (ret)
> +			goto out_unmap;

Shouldn't be 'goto out_clk_disable' ?

> +	}
> +
> +	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
> +	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
> +
> +	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
> +			200, 24, clocksource_mmio_readl_down);
> +	if (ret) {
> +		pr_err("failed to init clocksource (%d)\n", ret);
> +		goto out_clk_disable;
> +	}
> +
> +	pr_info("ARM System timer initialized as clocksource\n");
> +
> +	return;
> +
> +out_clk_disable:
> +	if (!IS_ERR(clk))

Why do you need this check ?

It isn't missing a clk_put ?

> +		clk_disable_unprepare(clk);
> +out_unmap:
> +	iounmap(base);
> +	WARN(ret, "ARM System timer register failed (%d)\n", ret);
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
> +			system_timer_of_register);
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  04/15] clocksource: Add ARM System timer driver
@ 2015-03-26  9:50     ` Daniel Lezcano
  0 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-26  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
> This patch adds clocksource support for ARMv7-M's System timer,
> also known as SysTick.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>

Hi Maxime,

the driver looks good. Three comments below.

   -- Daniel

> ---
>   drivers/clocksource/Kconfig          |  7 ++++
>   drivers/clocksource/Makefile         |  1 +
>   drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 86 insertions(+)
>   create mode 100644 drivers/clocksource/armv7m_systick.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 1c2506f..b82e58b 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>   	help
>   	 Use ARM global timer clock source as sched_clock
>
> +config ARMV7M_SYSTICK
> +	bool
> +	select CLKSRC_OF if OF
> +	select CLKSRC_MMIO
> +	help
> +	  This options enables support for the ARMv7M system timer unit
> +
>   config ATMEL_PIT
>   	select CLKSRC_OF if OF
>   	def_bool SOC_AT91SAM9 || SOC_SAMA5
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 752d5c7..1c9a643 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
>
>   obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
>   obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
> +obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
>   obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
> diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
> new file mode 100644
> index 0000000..23d8249
> --- /dev/null
> +++ b/drivers/clocksource/armv7m_systick.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/clk.h>
> +#include <linux/bitops.h>
> +
> +#define SYST_CSR	0x00
> +#define SYST_RVR	0x04
> +#define SYST_CVR	0x08
> +#define SYST_CALIB	0x0c
> +
> +#define SYST_CSR_ENABLE BIT(0)
> +
> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
> +
> +static void __init system_timer_of_register(struct device_node *np)
> +{
> +	struct clk *clk;
> +	void __iomem *base;
> +	u32 rate = 0;
> +	int ret;
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_warn("system-timer: invalid base address\n");
> +		return;
> +	}
> +
> +	clk = of_clk_get(np, 0);
> +	if (!IS_ERR(clk)) {
> +		ret = clk_prepare_enable(clk);
> +		if (ret) {
> +			clk_put(clk);
> +			goto out_unmap;
> +		}
> +
> +		rate = clk_get_rate(clk);
> +	}
> +
> +	/* If no clock found, try to get clock-frequency property */
> +	if (!rate) {
> +		ret = of_property_read_u32(np, "clock-frequency", &rate);
> +		if (ret)
> +			goto out_unmap;

Shouldn't be 'goto out_clk_disable' ?

> +	}
> +
> +	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
> +	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
> +
> +	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
> +			200, 24, clocksource_mmio_readl_down);
> +	if (ret) {
> +		pr_err("failed to init clocksource (%d)\n", ret);
> +		goto out_clk_disable;
> +	}
> +
> +	pr_info("ARM System timer initialized as clocksource\n");
> +
> +	return;
> +
> +out_clk_disable:
> +	if (!IS_ERR(clk))

Why do you need this check ?

It isn't missing a clk_put ?

> +		clk_disable_unprepare(clk);
> +out_unmap:
> +	iounmap(base);
> +	WARN(ret, "ARM System timer register failed (%d)\n", ret);
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
> +			system_timer_of_register);
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-24 18:23         ` Peter Hurley
  (?)
@ 2015-03-26 15:46             ` Russell King - ARM Linux
  -1 siblings, 0 replies; 136+ messages in thread
From: Russell King - ARM Linux @ 2015-03-26 15:46 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Maxime Coquelin, u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ,
	afaerber-l3A5Bk7waGM, geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan-XLVq0VzYD2Y,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, pebolle-IWqWACnzNjzz+pZb47iToQ,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo

On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
> Hi Maxime,
> 
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
> > +{
> > +	/*
> > +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> > +	 * and CTS/RTS

It's also worth noting that this comment is wrong.  This is used to get
the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
because the core tracks their state.

...

> > +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> > +
> > +	if (WARN_ON(IS_ERR(stm32port->clk)))
> 
> Do you really need a stack trace here? Could this be dev_err() instead?
> 
> > +		return -EINVAL;

Also, propagate the error code.

> > +
> > +	/* ensure that clk rate is correct by enabling the clk */
> > +	clk_prepare_enable(stm32port->clk);

And remember to check the return value of clk_prepare_enable().

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 15:46             ` Russell King - ARM Linux
  0 siblings, 0 replies; 136+ messages in thread
From: Russell King - ARM Linux @ 2015-03-26 15:46 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Maxime Coquelin, u.kleine-koenig, afaerber, geert, Rob Herring,
	Philipp Zabel, Linus Walleij, Arnd Bergmann, stefan, pmeerw,
	pebolle, Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, linux-arch, linux-api

On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
> Hi Maxime,
> 
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
> > +{
> > +	/*
> > +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> > +	 * and CTS/RTS

It's also worth noting that this comment is wrong.  This is used to get
the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
because the core tracks their state.

...

> > +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> > +
> > +	if (WARN_ON(IS_ERR(stm32port->clk)))
> 
> Do you really need a stack trace here? Could this be dev_err() instead?
> 
> > +		return -EINVAL;

Also, propagate the error code.

> > +
> > +	/* ensure that clk rate is correct by enabling the clk */
> > +	clk_prepare_enable(stm32port->clk);

And remember to check the return value of clk_prepare_enable().

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3  10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 15:46             ` Russell King - ARM Linux
  0 siblings, 0 replies; 136+ messages in thread
From: Russell King - ARM Linux @ 2015-03-26 15:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
> Hi Maxime,
> 
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
> > +{
> > +	/*
> > +	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
> > +	 * and CTS/RTS

It's also worth noting that this comment is wrong.  This is used to get
the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
because the core tracks their state.

...

> > +	stm32port->clk = devm_clk_get(&pdev->dev, NULL);
> > +
> > +	if (WARN_ON(IS_ERR(stm32port->clk)))
> 
> Do you really need a stack trace here? Could this be dev_err() instead?
> 
> > +		return -EINVAL;

Also, propagate the error code.

> > +
> > +	/* ensure that clk rate is correct by enabling the clk */
> > +	clk_prepare_enable(stm32port->clk);

And remember to check the return value of clk_prepare_enable().

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
  2015-03-26  9:50     ` Daniel Lezcano
  (?)
@ 2015-03-26 20:19       ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 20:19 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab

Hi Daniel,

  Thanks for the review. Please find my answers below.

2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This patch adds clocksource support for ARMv7-M's System timer,
>> also known as SysTick.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
>
> Hi Maxime,
>
> the driver looks good. Three comments below.
>
>   -- Daniel
>
>
>> ---
>>   drivers/clocksource/Kconfig          |  7 ++++
>>   drivers/clocksource/Makefile         |  1 +
>>   drivers/clocksource/armv7m_systick.c | 78
>> ++++++++++++++++++++++++++++++++++++
>>   3 files changed, 86 insertions(+)
>>   create mode 100644 drivers/clocksource/armv7m_systick.c
>>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 1c2506f..b82e58b 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>>         help
>>          Use ARM global timer clock source as sched_clock
>>
>> +config ARMV7M_SYSTICK
>> +       bool
>> +       select CLKSRC_OF if OF
>> +       select CLKSRC_MMIO
>> +       help
>> +         This options enables support for the ARMv7M system timer unit
>> +
>>   config ATMEL_PIT
>>         select CLKSRC_OF if OF
>>         def_bool SOC_AT91SAM9 || SOC_SAMA5
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index 752d5c7..1c9a643 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)               += mtk_timer.o
>>
>>   obj-$(CONFIG_ARM_ARCH_TIMER)          += arm_arch_timer.o
>>   obj-$(CONFIG_ARM_GLOBAL_TIMER)                += arm_global_timer.o
>> +obj-$(CONFIG_ARMV7M_SYSTICK)           += armv7m_systick.o
>>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)    += metag_generic.o
>>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
>>   obj-$(CONFIG_ARCH_KEYSTONE)           += timer-keystone.o
>> diff --git a/drivers/clocksource/armv7m_systick.c
>> b/drivers/clocksource/armv7m_systick.c
>> new file mode 100644
>> index 0000000..23d8249
>> --- /dev/null
>> +++ b/drivers/clocksource/armv7m_systick.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/clk.h>
>> +#include <linux/bitops.h>
>> +
>> +#define SYST_CSR       0x00
>> +#define SYST_RVR       0x04
>> +#define SYST_CVR       0x08
>> +#define SYST_CALIB     0x0c
>> +
>> +#define SYST_CSR_ENABLE BIT(0)
>> +
>> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
>> +
>> +static void __init system_timer_of_register(struct device_node *np)
>> +{
>> +       struct clk *clk;
>> +       void __iomem *base;
>> +       u32 rate = 0;
>> +       int ret;
>> +
>> +       base = of_iomap(np, 0);
>> +       if (!base) {
>> +               pr_warn("system-timer: invalid base address\n");
>> +               return;
>> +       }
>> +
>> +       clk = of_clk_get(np, 0);
>> +       if (!IS_ERR(clk)) {
>> +               ret = clk_prepare_enable(clk);
>> +               if (ret) {
>> +                       clk_put(clk);
>> +                       goto out_unmap;
>> +               }
>> +
>> +               rate = clk_get_rate(clk);
>> +       }
>> +
>> +       /* If no clock found, try to get clock-frequency property */
>> +       if (!rate) {
>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>> +               if (ret)
>> +                       goto out_unmap;
>
>
> Shouldn't be 'goto out_clk_disable' ?

No, because I assumed !rate means we failed to get the clock.
Actually, clk_get_rate could return 0, so relying on rate value is not safe.

I propose to get clock-frequency property if IS_ERR(clk).

Is it fine for you?

>
>> +       }
>> +
>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>> +
>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>> rate,
>> +                       200, 24, clocksource_mmio_readl_down);
>> +       if (ret) {
>> +               pr_err("failed to init clocksource (%d)\n", ret);
>> +               goto out_clk_disable;
>> +       }
>> +
>> +       pr_info("ARM System timer initialized as clocksource\n");
>> +
>> +       return;
>> +
>> +out_clk_disable:
>> +       if (!IS_ERR(clk))
>
>
> Why do you need this check ?

To handle the case were no clock was found, but a clk-frequency value
was provided.

>
> It isn't missing a clk_put ?

Right, thanks for spotting this.

I wonder if it makes sense to implement the error path.
If we fail to initialize the clocksource, the system will be unusable.

Maybe I should just perform a BUG_ON() in the error cases, as most of
the other clocksource drivers do.
What is your view?

Regards,
Maxime

>
>> +               clk_disable_unprepare(clk);
>> +out_unmap:
>> +       iounmap(base);
>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
>> +                       system_timer_of_register);
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-26 20:19       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 20:19 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab, Joe Perches,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, Linux-Arch, linux-api

Hi Daniel,

  Thanks for the review. Please find my answers below.

2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This patch adds clocksource support for ARMv7-M's System timer,
>> also known as SysTick.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
>
> Hi Maxime,
>
> the driver looks good. Three comments below.
>
>   -- Daniel
>
>
>> ---
>>   drivers/clocksource/Kconfig          |  7 ++++
>>   drivers/clocksource/Makefile         |  1 +
>>   drivers/clocksource/armv7m_systick.c | 78
>> ++++++++++++++++++++++++++++++++++++
>>   3 files changed, 86 insertions(+)
>>   create mode 100644 drivers/clocksource/armv7m_systick.c
>>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 1c2506f..b82e58b 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>>         help
>>          Use ARM global timer clock source as sched_clock
>>
>> +config ARMV7M_SYSTICK
>> +       bool
>> +       select CLKSRC_OF if OF
>> +       select CLKSRC_MMIO
>> +       help
>> +         This options enables support for the ARMv7M system timer unit
>> +
>>   config ATMEL_PIT
>>         select CLKSRC_OF if OF
>>         def_bool SOC_AT91SAM9 || SOC_SAMA5
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index 752d5c7..1c9a643 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)               += mtk_timer.o
>>
>>   obj-$(CONFIG_ARM_ARCH_TIMER)          += arm_arch_timer.o
>>   obj-$(CONFIG_ARM_GLOBAL_TIMER)                += arm_global_timer.o
>> +obj-$(CONFIG_ARMV7M_SYSTICK)           += armv7m_systick.o
>>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)    += metag_generic.o
>>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
>>   obj-$(CONFIG_ARCH_KEYSTONE)           += timer-keystone.o
>> diff --git a/drivers/clocksource/armv7m_systick.c
>> b/drivers/clocksource/armv7m_systick.c
>> new file mode 100644
>> index 0000000..23d8249
>> --- /dev/null
>> +++ b/drivers/clocksource/armv7m_systick.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/clk.h>
>> +#include <linux/bitops.h>
>> +
>> +#define SYST_CSR       0x00
>> +#define SYST_RVR       0x04
>> +#define SYST_CVR       0x08
>> +#define SYST_CALIB     0x0c
>> +
>> +#define SYST_CSR_ENABLE BIT(0)
>> +
>> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
>> +
>> +static void __init system_timer_of_register(struct device_node *np)
>> +{
>> +       struct clk *clk;
>> +       void __iomem *base;
>> +       u32 rate = 0;
>> +       int ret;
>> +
>> +       base = of_iomap(np, 0);
>> +       if (!base) {
>> +               pr_warn("system-timer: invalid base address\n");
>> +               return;
>> +       }
>> +
>> +       clk = of_clk_get(np, 0);
>> +       if (!IS_ERR(clk)) {
>> +               ret = clk_prepare_enable(clk);
>> +               if (ret) {
>> +                       clk_put(clk);
>> +                       goto out_unmap;
>> +               }
>> +
>> +               rate = clk_get_rate(clk);
>> +       }
>> +
>> +       /* If no clock found, try to get clock-frequency property */
>> +       if (!rate) {
>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>> +               if (ret)
>> +                       goto out_unmap;
>
>
> Shouldn't be 'goto out_clk_disable' ?

No, because I assumed !rate means we failed to get the clock.
Actually, clk_get_rate could return 0, so relying on rate value is not safe.

I propose to get clock-frequency property if IS_ERR(clk).

Is it fine for you?

>
>> +       }
>> +
>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>> +
>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>> rate,
>> +                       200, 24, clocksource_mmio_readl_down);
>> +       if (ret) {
>> +               pr_err("failed to init clocksource (%d)\n", ret);
>> +               goto out_clk_disable;
>> +       }
>> +
>> +       pr_info("ARM System timer initialized as clocksource\n");
>> +
>> +       return;
>> +
>> +out_clk_disable:
>> +       if (!IS_ERR(clk))
>
>
> Why do you need this check ?

To handle the case were no clock was found, but a clk-frequency value
was provided.

>
> It isn't missing a clk_put ?

Right, thanks for spotting this.

I wonder if it makes sense to implement the error path.
If we fail to initialize the clocksource, the system will be unusable.

Maybe I should just perform a BUG_ON() in the error cases, as most of
the other clocksource drivers do.
What is your view?

Regards,
Maxime

>
>> +               clk_disable_unprepare(clk);
>> +out_unmap:
>> +       iounmap(base);
>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
>> +                       system_timer_of_register);
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-26 20:19       ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Daniel,

  Thanks for the review. Please find my answers below.

2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This patch adds clocksource support for ARMv7-M's System timer,
>> also known as SysTick.
>>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>
>
> Hi Maxime,
>
> the driver looks good. Three comments below.
>
>   -- Daniel
>
>
>> ---
>>   drivers/clocksource/Kconfig          |  7 ++++
>>   drivers/clocksource/Makefile         |  1 +
>>   drivers/clocksource/armv7m_systick.c | 78
>> ++++++++++++++++++++++++++++++++++++
>>   3 files changed, 86 insertions(+)
>>   create mode 100644 drivers/clocksource/armv7m_systick.c
>>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 1c2506f..b82e58b 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -134,6 +134,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>>         help
>>          Use ARM global timer clock source as sched_clock
>>
>> +config ARMV7M_SYSTICK
>> +       bool
>> +       select CLKSRC_OF if OF
>> +       select CLKSRC_MMIO
>> +       help
>> +         This options enables support for the ARMv7M system timer unit
>> +
>>   config ATMEL_PIT
>>         select CLKSRC_OF if OF
>>         def_bool SOC_AT91SAM9 || SOC_SAMA5
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index 752d5c7..1c9a643 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -44,6 +44,7 @@ obj-$(CONFIG_MTK_TIMER)               += mtk_timer.o
>>
>>   obj-$(CONFIG_ARM_ARCH_TIMER)          += arm_arch_timer.o
>>   obj-$(CONFIG_ARM_GLOBAL_TIMER)                += arm_global_timer.o
>> +obj-$(CONFIG_ARMV7M_SYSTICK)           += armv7m_systick.o
>>   obj-$(CONFIG_CLKSRC_METAG_GENERIC)    += metag_generic.o
>>   obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
>>   obj-$(CONFIG_ARCH_KEYSTONE)           += timer-keystone.o
>> diff --git a/drivers/clocksource/armv7m_systick.c
>> b/drivers/clocksource/armv7m_systick.c
>> new file mode 100644
>> index 0000000..23d8249
>> --- /dev/null
>> +++ b/drivers/clocksource/armv7m_systick.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Copyright (C) Maxime Coquelin 2015
>> + * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> + * License terms:  GNU General Public License (GPL), version 2
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/clk.h>
>> +#include <linux/bitops.h>
>> +
>> +#define SYST_CSR       0x00
>> +#define SYST_RVR       0x04
>> +#define SYST_CVR       0x08
>> +#define SYST_CALIB     0x0c
>> +
>> +#define SYST_CSR_ENABLE BIT(0)
>> +
>> +#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
>> +
>> +static void __init system_timer_of_register(struct device_node *np)
>> +{
>> +       struct clk *clk;
>> +       void __iomem *base;
>> +       u32 rate = 0;
>> +       int ret;
>> +
>> +       base = of_iomap(np, 0);
>> +       if (!base) {
>> +               pr_warn("system-timer: invalid base address\n");
>> +               return;
>> +       }
>> +
>> +       clk = of_clk_get(np, 0);
>> +       if (!IS_ERR(clk)) {
>> +               ret = clk_prepare_enable(clk);
>> +               if (ret) {
>> +                       clk_put(clk);
>> +                       goto out_unmap;
>> +               }
>> +
>> +               rate = clk_get_rate(clk);
>> +       }
>> +
>> +       /* If no clock found, try to get clock-frequency property */
>> +       if (!rate) {
>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>> +               if (ret)
>> +                       goto out_unmap;
>
>
> Shouldn't be 'goto out_clk_disable' ?

No, because I assumed !rate means we failed to get the clock.
Actually, clk_get_rate could return 0, so relying on rate value is not safe.

I propose to get clock-frequency property if IS_ERR(clk).

Is it fine for you?

>
>> +       }
>> +
>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>> +
>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>> rate,
>> +                       200, 24, clocksource_mmio_readl_down);
>> +       if (ret) {
>> +               pr_err("failed to init clocksource (%d)\n", ret);
>> +               goto out_clk_disable;
>> +       }
>> +
>> +       pr_info("ARM System timer initialized as clocksource\n");
>> +
>> +       return;
>> +
>> +out_clk_disable:
>> +       if (!IS_ERR(clk))
>
>
> Why do you need this check ?

To handle the case were no clock was found, but a clk-frequency value
was provided.

>
> It isn't missing a clk_put ?

Right, thanks for spotting this.

I wonder if it makes sense to implement the error path.
If we fail to initialize the clocksource, the system will be unusable.

Maybe I should just perform a BUG_ON() in the error cases, as most of
the other clocksource drivers do.
What is your view?

Regards,
Maxime

>
>> +               clk_disable_unprepare(clk);
>> +out_unmap:
>> +       iounmap(base);
>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
>> +                       system_timer_of_register);
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-24 18:23         ` Peter Hurley
  (?)
@ 2015-03-26 22:03           ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:03 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

HI Peter

2015-03-24 19:23 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> Hi Maxime,
>
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> Comments below.

Thanks for the review, please find my answsers below
>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>

...

>> +static unsigned int stm32_tx_empty(struct uart_port *port)
>> +{
>> +     return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
>> +}
>> +
>> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
>> +{
>> +     /*
>> +      * This routine is used for seting signals of: DTR, DCD, CTS/RTS
>> +      * We use USART's hardware for CTS/RTS, so don't need any for that.
>
> If this means that you're enabling autoflow control, then you still need
> to respond to the state of TIOCM_RTS, so that both serial core and userspace
> can halt input flow.
>
> If the hardware doesn't support separate RTS enable/disable control,
> then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
> it when raised.
>
>
>> +      * Some boards have DTR and DCD implemented using PIO pins,
>> +      * code to do this should be hooked in here.
>> +      */
>> +}
>> +
>> +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> +{
>> +     /*
>> +      * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> +      * and CTS/RTS
>> +      */
>> +     return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
>> +}
>> +

...
>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                         struct ktermios *old)
>> +{
>> +     unsigned int baud;
>> +     u32 usardiv, mantissa, fraction;
>> +     tcflag_t cflag;
>> +     u32 cr1, cr2, cr3;
>> +     unsigned long flags;
>> +
>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +     cflag = termios->c_cflag;
>> +
>> +     spin_lock_irqsave(&port->lock, flags);
>> +
>> +     /* Stop serial port and reset value */
>> +     writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +     if (cflag & CSTOPB)
>> +             cr2 = USART_CR2_STOP_2B;
>> +
>> +     if (cflag & PARENB) {
>> +             cr1 |= USART_CR1_PCE;
>> +             if ((cflag & CSIZE) == CS8)
>> +                     cr1 |= USART_CR1_M;
>> +     }
>> +
>> +     if (cflag & PARODD)
>> +             cr1 |= USART_CR1_PS;
>> +
>> +     if (cflag & CRTSCTS)
>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>
> If this means autoflow control, then you need to define
> throttle()/unthrottle() methods, otherwise the serial core won't
> be able to throttle the remote when input buffers are about
> to overflow.
>
> And you should only enable the autoCTS and let the serial
> core enable autoRTS through set_mctrl(TIOCM_RTS).
>
> Just let me know if you need more info about how to do this.

Ok, let's see if I have well understood.

USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
TIOCM_RTS  value.
The throttle callback should disable the rx interrupt, and the
unthrottle enable it.
For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.

Am I right?
>
>> +
>> +     usardiv = (port->uartclk * 25) / (baud * 4);
>> +     mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +     fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +     if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +             fraction = 0;
>> +             mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +     }
>> +
>> +     writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
>> +
>> +     uart_update_timeout(port, cflag, baud);
>> +
>> +     port->read_status_mask = USART_SR_ORE;
>> +     if (termios->c_iflag & INPCK)
>> +             port->read_status_mask |= USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
>> +             port->read_status_mask |= USART_SR_LBD;
>> +
>> +     /* Characters to ignore */
>> +     port->ignore_status_mask = 0;
>> +     if (termios->c_iflag & IGNPAR)
>> +             port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & IGNBRK) {
>> +             port->ignore_status_mask |= USART_SR_LBD;
>> +             /*
>> +              * If we're ignoring parity and break indicators,
>> +              * ignore overruns too (for real raw support).
>> +              */
>> +             if (termios->c_iflag & IGNPAR)
>> +                     port->ignore_status_mask |= USART_SR_ORE;
>> +     }
>> +
>> +     /*
>> +      * Ignore all characters if CREAD is not set.
>> +      */
>> +     if ((termios->c_cflag & CREAD) == 0)
>> +             port->ignore_status_mask |= USART_SR_DUMMY_RX;
>> +
>> +     writel_relaxed(cr3, port->membase + USART_CR3);
>> +     writel_relaxed(cr2, port->membase + USART_CR2);
>> +     writel_relaxed(cr1, port->membase + USART_CR1);
>> +
>> +     spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
...

>> +static void stm32_config_port(struct uart_port *port, int flags)
>> +{
>> +     if ((flags & UART_CONFIG_TYPE))
>
> Single parens.

Sure.

>
>> +             port->type = PORT_STM32;
>> +}
>> +
...

>> +
>> +static int stm32_init_port(struct stm32_port *stm32port,
>> +                       struct platform_device *pdev)
>> +{
>> +     struct uart_port *port = &stm32port->port;
>> +     struct resource *res;
>> +
>> +     port->iotype    = UPIO_MEM;
>> +     port->flags     = UPF_BOOT_AUTOCONF;
>> +     port->ops       = &stm32_uart_ops;
>> +     port->dev       = &pdev->dev;
>> +     port->irq       = platform_get_irq(pdev, 0);
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     port->membase = devm_ioremap_resource(&pdev->dev, res);
>> +     if (IS_ERR(port->membase))
>> +             return PTR_ERR(port->membase);
>> +     port->mapbase = res->start;
>> +
>> +     spin_lock_init(&port->lock);
>> +
>> +     stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> +
>> +     if (WARN_ON(IS_ERR(stm32port->clk)))
>
> Do you really need a stack trace here? Could this be dev_err() instead?

No I don't, dev_err() will be enough.
>
>> +             return -EINVAL;
>> +
>> +     /* ensure that clk rate is correct by enabling the clk */
>> +     clk_prepare_enable(stm32port->clk);
>> +     stm32port->port.uartclk = clk_get_rate(stm32port->clk);
>> +     WARN_ON(stm32port->port.uartclk == 0);
>
> Or here?
Same here.

>
>> +     clk_disable_unprepare(stm32port->clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
>> +{
>> +     struct device_node *np = pdev->dev.of_node;
>> +     int id;
>> +
>> +     if (!np)
>> +             return NULL;
>> +
>> +     id = of_alias_get_id(np, STM32_SERIAL_NAME);
>> +
>> +     if (id < 0)
>> +             id = 0;
>> +
>> +     if (WARN_ON(id >= STM32_MAX_PORTS))
>
> Or here?

I will return PTR_ERR(-EINVAL); instead.
>
>> +             return NULL;
>> +
>> +     stm32_ports[id].port.line = id;
>> +     return &stm32_ports[id];
>> +}
>> +
...

>> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
>> index b212281..e22dee5 100644
>> --- a/include/uapi/linux/serial_core.h
>> +++ b/include/uapi/linux/serial_core.h
>> @@ -258,4 +258,7 @@
>>  /* Cris v10 / v32 SoC */
>>  #define PORT_CRIS    112
>>
>> +/* STM32 USART */
>> +#define PORT_STM32   110
>
> Already taken.
>
> You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Sure, I made a mistake during the rebase conflict resolution.

Thanks,
Maxime

>
> Regards,
> Peter Hurley
>
>> +
>>  #endif /* _UAPILINUX_SERIAL_CORE_H */
>>
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 22:03           ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:03 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

HI Peter

2015-03-24 19:23 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> Hi Maxime,
>
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> Comments below.

Thanks for the review, please find my answsers below
>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>

...

>> +static unsigned int stm32_tx_empty(struct uart_port *port)
>> +{
>> +     return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
>> +}
>> +
>> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
>> +{
>> +     /*
>> +      * This routine is used for seting signals of: DTR, DCD, CTS/RTS
>> +      * We use USART's hardware for CTS/RTS, so don't need any for that.
>
> If this means that you're enabling autoflow control, then you still need
> to respond to the state of TIOCM_RTS, so that both serial core and userspace
> can halt input flow.
>
> If the hardware doesn't support separate RTS enable/disable control,
> then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
> it when raised.
>
>
>> +      * Some boards have DTR and DCD implemented using PIO pins,
>> +      * code to do this should be hooked in here.
>> +      */
>> +}
>> +
>> +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> +{
>> +     /*
>> +      * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> +      * and CTS/RTS
>> +      */
>> +     return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
>> +}
>> +

...
>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                         struct ktermios *old)
>> +{
>> +     unsigned int baud;
>> +     u32 usardiv, mantissa, fraction;
>> +     tcflag_t cflag;
>> +     u32 cr1, cr2, cr3;
>> +     unsigned long flags;
>> +
>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +     cflag = termios->c_cflag;
>> +
>> +     spin_lock_irqsave(&port->lock, flags);
>> +
>> +     /* Stop serial port and reset value */
>> +     writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +     if (cflag & CSTOPB)
>> +             cr2 = USART_CR2_STOP_2B;
>> +
>> +     if (cflag & PARENB) {
>> +             cr1 |= USART_CR1_PCE;
>> +             if ((cflag & CSIZE) == CS8)
>> +                     cr1 |= USART_CR1_M;
>> +     }
>> +
>> +     if (cflag & PARODD)
>> +             cr1 |= USART_CR1_PS;
>> +
>> +     if (cflag & CRTSCTS)
>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>
> If this means autoflow control, then you need to define
> throttle()/unthrottle() methods, otherwise the serial core won't
> be able to throttle the remote when input buffers are about
> to overflow.
>
> And you should only enable the autoCTS and let the serial
> core enable autoRTS through set_mctrl(TIOCM_RTS).
>
> Just let me know if you need more info about how to do this.

Ok, let's see if I have well understood.

USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
TIOCM_RTS  value.
The throttle callback should disable the rx interrupt, and the
unthrottle enable it.
For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.

Am I right?
>
>> +
>> +     usardiv = (port->uartclk * 25) / (baud * 4);
>> +     mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +     fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +     if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +             fraction = 0;
>> +             mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +     }
>> +
>> +     writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
>> +
>> +     uart_update_timeout(port, cflag, baud);
>> +
>> +     port->read_status_mask = USART_SR_ORE;
>> +     if (termios->c_iflag & INPCK)
>> +             port->read_status_mask |= USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
>> +             port->read_status_mask |= USART_SR_LBD;
>> +
>> +     /* Characters to ignore */
>> +     port->ignore_status_mask = 0;
>> +     if (termios->c_iflag & IGNPAR)
>> +             port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & IGNBRK) {
>> +             port->ignore_status_mask |= USART_SR_LBD;
>> +             /*
>> +              * If we're ignoring parity and break indicators,
>> +              * ignore overruns too (for real raw support).
>> +              */
>> +             if (termios->c_iflag & IGNPAR)
>> +                     port->ignore_status_mask |= USART_SR_ORE;
>> +     }
>> +
>> +     /*
>> +      * Ignore all characters if CREAD is not set.
>> +      */
>> +     if ((termios->c_cflag & CREAD) == 0)
>> +             port->ignore_status_mask |= USART_SR_DUMMY_RX;
>> +
>> +     writel_relaxed(cr3, port->membase + USART_CR3);
>> +     writel_relaxed(cr2, port->membase + USART_CR2);
>> +     writel_relaxed(cr1, port->membase + USART_CR1);
>> +
>> +     spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
...

>> +static void stm32_config_port(struct uart_port *port, int flags)
>> +{
>> +     if ((flags & UART_CONFIG_TYPE))
>
> Single parens.

Sure.

>
>> +             port->type = PORT_STM32;
>> +}
>> +
...

>> +
>> +static int stm32_init_port(struct stm32_port *stm32port,
>> +                       struct platform_device *pdev)
>> +{
>> +     struct uart_port *port = &stm32port->port;
>> +     struct resource *res;
>> +
>> +     port->iotype    = UPIO_MEM;
>> +     port->flags     = UPF_BOOT_AUTOCONF;
>> +     port->ops       = &stm32_uart_ops;
>> +     port->dev       = &pdev->dev;
>> +     port->irq       = platform_get_irq(pdev, 0);
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     port->membase = devm_ioremap_resource(&pdev->dev, res);
>> +     if (IS_ERR(port->membase))
>> +             return PTR_ERR(port->membase);
>> +     port->mapbase = res->start;
>> +
>> +     spin_lock_init(&port->lock);
>> +
>> +     stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> +
>> +     if (WARN_ON(IS_ERR(stm32port->clk)))
>
> Do you really need a stack trace here? Could this be dev_err() instead?

No I don't, dev_err() will be enough.
>
>> +             return -EINVAL;
>> +
>> +     /* ensure that clk rate is correct by enabling the clk */
>> +     clk_prepare_enable(stm32port->clk);
>> +     stm32port->port.uartclk = clk_get_rate(stm32port->clk);
>> +     WARN_ON(stm32port->port.uartclk == 0);
>
> Or here?
Same here.

>
>> +     clk_disable_unprepare(stm32port->clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
>> +{
>> +     struct device_node *np = pdev->dev.of_node;
>> +     int id;
>> +
>> +     if (!np)
>> +             return NULL;
>> +
>> +     id = of_alias_get_id(np, STM32_SERIAL_NAME);
>> +
>> +     if (id < 0)
>> +             id = 0;
>> +
>> +     if (WARN_ON(id >= STM32_MAX_PORTS))
>
> Or here?

I will return PTR_ERR(-EINVAL); instead.
>
>> +             return NULL;
>> +
>> +     stm32_ports[id].port.line = id;
>> +     return &stm32_ports[id];
>> +}
>> +
...

>> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
>> index b212281..e22dee5 100644
>> --- a/include/uapi/linux/serial_core.h
>> +++ b/include/uapi/linux/serial_core.h
>> @@ -258,4 +258,7 @@
>>  /* Cris v10 / v32 SoC */
>>  #define PORT_CRIS    112
>>
>> +/* STM32 USART */
>> +#define PORT_STM32   110
>
> Already taken.
>
> You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Sure, I made a mistake during the rebase conflict resolution.

Thanks,
Maxime

>
> Regards,
> Peter Hurley
>
>> +
>>  #endif /* _UAPILINUX_SERIAL_CORE_H */
>>
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 22:03           ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:03 UTC (permalink / raw)
  To: linux-arm-kernel

HI Peter

2015-03-24 19:23 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> Hi Maxime,
>
> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>> This drivers adds support to the STM32 USART controller, which is a
>> standard serial driver.
>
> Comments below.

Thanks for the review, please find my answsers below
>
>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> ---
>>  drivers/tty/serial/Kconfig       |  17 +
>>  drivers/tty/serial/Makefile      |   1 +
>>  drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/serial_core.h |   3 +
>>  4 files changed, 716 insertions(+)
>>  create mode 100644 drivers/tty/serial/stm32-usart.c
>>

...

>> +static unsigned int stm32_tx_empty(struct uart_port *port)
>> +{
>> +     return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
>> +}
>> +
>> +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
>> +{
>> +     /*
>> +      * This routine is used for seting signals of: DTR, DCD, CTS/RTS
>> +      * We use USART's hardware for CTS/RTS, so don't need any for that.
>
> If this means that you're enabling autoflow control, then you still need
> to respond to the state of TIOCM_RTS, so that both serial core and userspace
> can halt input flow.
>
> If the hardware doesn't support separate RTS enable/disable control,
> then you need to disable autoRTS when TIOCM_RTS is clear, and re-enable
> it when raised.
>
>
>> +      * Some boards have DTR and DCD implemented using PIO pins,
>> +      * code to do this should be hooked in here.
>> +      */
>> +}
>> +
>> +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> +{
>> +     /*
>> +      * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> +      * and CTS/RTS
>> +      */
>> +     return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
>> +}
>> +

...
>> +
>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>> +                         struct ktermios *old)
>> +{
>> +     unsigned int baud;
>> +     u32 usardiv, mantissa, fraction;
>> +     tcflag_t cflag;
>> +     u32 cr1, cr2, cr3;
>> +     unsigned long flags;
>> +
>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>> +     cflag = termios->c_cflag;
>> +
>> +     spin_lock_irqsave(&port->lock, flags);
>> +
>> +     /* Stop serial port and reset value */
>> +     writel_relaxed(0, port->membase + USART_CR1);
>> +
>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>> +
>> +     if (cflag & CSTOPB)
>> +             cr2 = USART_CR2_STOP_2B;
>> +
>> +     if (cflag & PARENB) {
>> +             cr1 |= USART_CR1_PCE;
>> +             if ((cflag & CSIZE) == CS8)
>> +                     cr1 |= USART_CR1_M;
>> +     }
>> +
>> +     if (cflag & PARODD)
>> +             cr1 |= USART_CR1_PS;
>> +
>> +     if (cflag & CRTSCTS)
>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>
> If this means autoflow control, then you need to define
> throttle()/unthrottle() methods, otherwise the serial core won't
> be able to throttle the remote when input buffers are about
> to overflow.
>
> And you should only enable the autoCTS and let the serial
> core enable autoRTS through set_mctrl(TIOCM_RTS).
>
> Just let me know if you need more info about how to do this.

Ok, let's see if I have well understood.

USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
TIOCM_RTS  value.
The throttle callback should disable the rx interrupt, and the
unthrottle enable it.
For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.

Am I right?
>
>> +
>> +     usardiv = (port->uartclk * 25) / (baud * 4);
>> +     mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
>> +     fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
>> +     if (fraction & ~USART_BRR_DIV_F_MASK) {
>> +             fraction = 0;
>> +             mantissa += (1 << USART_BRR_DIV_M_SHIFT);
>> +     }
>> +
>> +     writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
>> +
>> +     uart_update_timeout(port, cflag, baud);
>> +
>> +     port->read_status_mask = USART_SR_ORE;
>> +     if (termios->c_iflag & INPCK)
>> +             port->read_status_mask |= USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
>> +             port->read_status_mask |= USART_SR_LBD;
>> +
>> +     /* Characters to ignore */
>> +     port->ignore_status_mask = 0;
>> +     if (termios->c_iflag & IGNPAR)
>> +             port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
>> +     if (termios->c_iflag & IGNBRK) {
>> +             port->ignore_status_mask |= USART_SR_LBD;
>> +             /*
>> +              * If we're ignoring parity and break indicators,
>> +              * ignore overruns too (for real raw support).
>> +              */
>> +             if (termios->c_iflag & IGNPAR)
>> +                     port->ignore_status_mask |= USART_SR_ORE;
>> +     }
>> +
>> +     /*
>> +      * Ignore all characters if CREAD is not set.
>> +      */
>> +     if ((termios->c_cflag & CREAD) == 0)
>> +             port->ignore_status_mask |= USART_SR_DUMMY_RX;
>> +
>> +     writel_relaxed(cr3, port->membase + USART_CR3);
>> +     writel_relaxed(cr2, port->membase + USART_CR2);
>> +     writel_relaxed(cr1, port->membase + USART_CR1);
>> +
>> +     spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
...

>> +static void stm32_config_port(struct uart_port *port, int flags)
>> +{
>> +     if ((flags & UART_CONFIG_TYPE))
>
> Single parens.

Sure.

>
>> +             port->type = PORT_STM32;
>> +}
>> +
...

>> +
>> +static int stm32_init_port(struct stm32_port *stm32port,
>> +                       struct platform_device *pdev)
>> +{
>> +     struct uart_port *port = &stm32port->port;
>> +     struct resource *res;
>> +
>> +     port->iotype    = UPIO_MEM;
>> +     port->flags     = UPF_BOOT_AUTOCONF;
>> +     port->ops       = &stm32_uart_ops;
>> +     port->dev       = &pdev->dev;
>> +     port->irq       = platform_get_irq(pdev, 0);
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     port->membase = devm_ioremap_resource(&pdev->dev, res);
>> +     if (IS_ERR(port->membase))
>> +             return PTR_ERR(port->membase);
>> +     port->mapbase = res->start;
>> +
>> +     spin_lock_init(&port->lock);
>> +
>> +     stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> +
>> +     if (WARN_ON(IS_ERR(stm32port->clk)))
>
> Do you really need a stack trace here? Could this be dev_err() instead?

No I don't, dev_err() will be enough.
>
>> +             return -EINVAL;
>> +
>> +     /* ensure that clk rate is correct by enabling the clk */
>> +     clk_prepare_enable(stm32port->clk);
>> +     stm32port->port.uartclk = clk_get_rate(stm32port->clk);
>> +     WARN_ON(stm32port->port.uartclk == 0);
>
> Or here?
Same here.

>
>> +     clk_disable_unprepare(stm32port->clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
>> +{
>> +     struct device_node *np = pdev->dev.of_node;
>> +     int id;
>> +
>> +     if (!np)
>> +             return NULL;
>> +
>> +     id = of_alias_get_id(np, STM32_SERIAL_NAME);
>> +
>> +     if (id < 0)
>> +             id = 0;
>> +
>> +     if (WARN_ON(id >= STM32_MAX_PORTS))
>
> Or here?

I will return PTR_ERR(-EINVAL); instead.
>
>> +             return NULL;
>> +
>> +     stm32_ports[id].port.line = id;
>> +     return &stm32_ports[id];
>> +}
>> +
...

>> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
>> index b212281..e22dee5 100644
>> --- a/include/uapi/linux/serial_core.h
>> +++ b/include/uapi/linux/serial_core.h
>> @@ -258,4 +258,7 @@
>>  /* Cris v10 / v32 SoC */
>>  #define PORT_CRIS    112
>>
>> +/* STM32 USART */
>> +#define PORT_STM32   110
>
> Already taken.
>
> You'll want to make sure v4 applies cleanly to Greg's tty-next branch.

Sure, I made a mistake during the rebase conflict resolution.

Thanks,
Maxime

>
> Regards,
> Peter Hurley
>
>> +
>>  #endif /* _UAPILINUX_SERIAL_CORE_H */
>>
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-26 15:46             ` Russell King - ARM Linux
  (?)
@ 2015-03-26 22:05               ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:05 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Peter Hurley, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller

2015-03-26 16:46 GMT+01:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
>> Hi Maxime,
>>
>> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> > +{
>> > +   /*
>> > +    * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> > +    * and CTS/RTS
>
> It's also worth noting that this comment is wrong.  This is used to get
> the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
> because the core tracks their state.

OK, thanks for pointing this.
I will fix the comment in the v4.

>
> ...
>
>> > +   stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> > +
>> > +   if (WARN_ON(IS_ERR(stm32port->clk)))
>>
>> Do you really need a stack trace here? Could this be dev_err() instead?
>>
>> > +           return -EINVAL;
>
> Also, propagate the error code.
Ok.

>
>> > +
>> > +   /* ensure that clk rate is correct by enabling the clk */
>> > +   clk_prepare_enable(stm32port->clk);
>
> And remember to check the return value of clk_prepare_enable().
I will.

Thanks for the review,
Maxime

>
> --
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 22:05               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:05 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Peter Hurley, Uwe Kleine-König, Andreas Färber,
	Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
	Arnd Bergmann, Stefan Agner, Peter Meerwald, Paul Bolle,
	Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman,
	Jiri Slaby, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will Deacon, Nikolay Borisov, Rusty Russell, Kees Cook,
	Michal Marek, linux-doc, linux-arm-kernel, linux-kernel,
	devicetree, linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-26 16:46 GMT+01:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
>> Hi Maxime,
>>
>> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> > +{
>> > +   /*
>> > +    * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> > +    * and CTS/RTS
>
> It's also worth noting that this comment is wrong.  This is used to get
> the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
> because the core tracks their state.

OK, thanks for pointing this.
I will fix the comment in the v4.

>
> ...
>
>> > +   stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> > +
>> > +   if (WARN_ON(IS_ERR(stm32port->clk)))
>>
>> Do you really need a stack trace here? Could this be dev_err() instead?
>>
>> > +           return -EINVAL;
>
> Also, propagate the error code.
Ok.

>
>> > +
>> > +   /* ensure that clk rate is correct by enabling the clk */
>> > +   clk_prepare_enable(stm32port->clk);
>
> And remember to check the return value of clk_prepare_enable().
I will.

Thanks for the review,
Maxime

>
> --
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-26 22:05               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-26 22:05 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-26 16:46 GMT+01:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Tue, Mar 24, 2015 at 02:23:38PM -0400, Peter Hurley wrote:
>> Hi Maxime,
>>
>> On 03/12/2015 05:55 PM, Maxime Coquelin wrote:
>> > +static unsigned int stm32_get_mctrl(struct uart_port *port)
>> > +{
>> > +   /*
>> > +    * This routine is used for geting signals of: DTR, DCD, DSR, RI,
>> > +    * and CTS/RTS
>
> It's also worth noting that this comment is wrong.  This is used to get
> the state of DCD, DSR, RI and CTS.  DTR and RTS are *not* included
> because the core tracks their state.

OK, thanks for pointing this.
I will fix the comment in the v4.

>
> ...
>
>> > +   stm32port->clk = devm_clk_get(&pdev->dev, NULL);
>> > +
>> > +   if (WARN_ON(IS_ERR(stm32port->clk)))
>>
>> Do you really need a stack trace here? Could this be dev_err() instead?
>>
>> > +           return -EINVAL;
>
> Also, propagate the error code.
Ok.

>
>> > +
>> > +   /* ensure that clk rate is correct by enabling the clk */
>> > +   clk_prepare_enable(stm32port->clk);
>
> And remember to check the return value of clk_prepare_enable().
I will.

Thanks for the review,
Maxime

>
> --
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
  2015-03-26 20:19       ` Maxime Coquelin
  (?)
@ 2015-03-27  8:36         ` Daniel Lezcano
  -1 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-27  8:36 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab

On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
> Hi Daniel,
>
>    Thanks for the review. Please find my answers below.
>
> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>
>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>> This patch adds clocksource support for ARMv7-M's System timer,
>>> also known as SysTick.
>>>
>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>>
>> Hi Maxime,
>>
>> the driver looks good. Three comments below.
>>
>>    -- Daniel
>>
>>

[ ... ]

>>> +static void __init system_timer_of_register(struct device_node *np)
>>> +{
>>> +       struct clk *clk;
>>> +       void __iomem *base;
>>> +       u32 rate = 0;
>>> +       int ret;
>>> +
>>> +       base = of_iomap(np, 0);
>>> +       if (!base) {
>>> +               pr_warn("system-timer: invalid base address\n");
>>> +               return;
>>> +       }
>>> +
>>> +       clk = of_clk_get(np, 0);
>>> +       if (!IS_ERR(clk)) {
>>> +               ret = clk_prepare_enable(clk);
>>> +               if (ret) {
>>> +                       clk_put(clk);
>>> +                       goto out_unmap;
>>> +               }
>>> +
>>> +               rate = clk_get_rate(clk);
>>> +       }
>>> +
>>> +       /* If no clock found, try to get clock-frequency property */
>>> +       if (!rate) {
>>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>>> +               if (ret)
>>> +                       goto out_unmap;
>>
>>
>> Shouldn't be 'goto out_clk_disable' ?
>
> No, because I assumed !rate means we failed to get the clock.
> Actually, clk_get_rate could return 0, so relying on rate value is not safe.
>
> I propose to get clock-frequency property if IS_ERR(clk).
>
> Is it fine for you?

Why not invert the conditions ? If the 'clock-frequency' is specified in 
the DT then it overrides the clk_get_rate(). So the resulting code will be:

ret = of_property_read_u32(np, "clock-frequency", &rate);
if (ret) {
	clk = of_clk_get(np, 0);
	if (IS_ERR(clk))
		goto out_unmap;

	ret = clk_prepare_enable(clk);
	if (ret)
		goto out_clk_put;

	rate = clk_get_rate(clk);
	if (!rate)
		goto out_clk_unprepare;
}



>>> +       }
>>> +
>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>> +
>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>> rate,
>>> +                       200, 24, clocksource_mmio_readl_down);
>>> +       if (ret) {
>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>> +               goto out_clk_disable;
>>> +       }
>>> +
>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>> +
>>> +       return;
>>> +
>>> +out_clk_disable:
>>> +       if (!IS_ERR(clk))
>>
>>
>> Why do you need this check ?
>
> To handle the case were no clock was found, but a clk-frequency value
> was provided.
>
>>
>> It isn't missing a clk_put ?
>
> Right, thanks for spotting this.
>
> I wonder if it makes sense to implement the error path.
> If we fail to initialize the clocksource, the system will be unusable.
>
> Maybe I should just perform a BUG_ON() in the error cases, as most of
> the other clocksource drivers do.
> What is your view?

I prefer to not BUG_ON in the init functions because it already happen 
that drivers were bugging at init time and when a driver was reused on 
another platform with several timers available, the board was not able 
to boot because one timer was not used, hence not defined in the DT. I 
don't know if that could be the case for this platform but I prefer to 
keep thing going smoothly and return from init even if that lead to a 
kernel hang. Of course, the errors must be displayed (pr_warn, pr_err, 
pr_notice, etc ...).

>>
>>> +               clk_disable_unprepare(clk);
>>> +out_unmap:
>>> +       iounmap(base);
>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);

pr_warn

Thanks

   -- Daniel

-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-27  8:36         ` Daniel Lezcano
  0 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-27  8:36 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab, Joe Perches,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, Linux-Arch, linux-api

On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
> Hi Daniel,
>
>    Thanks for the review. Please find my answers below.
>
> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>
>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>> This patch adds clocksource support for ARMv7-M's System timer,
>>> also known as SysTick.
>>>
>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>>
>> Hi Maxime,
>>
>> the driver looks good. Three comments below.
>>
>>    -- Daniel
>>
>>

[ ... ]

>>> +static void __init system_timer_of_register(struct device_node *np)
>>> +{
>>> +       struct clk *clk;
>>> +       void __iomem *base;
>>> +       u32 rate = 0;
>>> +       int ret;
>>> +
>>> +       base = of_iomap(np, 0);
>>> +       if (!base) {
>>> +               pr_warn("system-timer: invalid base address\n");
>>> +               return;
>>> +       }
>>> +
>>> +       clk = of_clk_get(np, 0);
>>> +       if (!IS_ERR(clk)) {
>>> +               ret = clk_prepare_enable(clk);
>>> +               if (ret) {
>>> +                       clk_put(clk);
>>> +                       goto out_unmap;
>>> +               }
>>> +
>>> +               rate = clk_get_rate(clk);
>>> +       }
>>> +
>>> +       /* If no clock found, try to get clock-frequency property */
>>> +       if (!rate) {
>>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>>> +               if (ret)
>>> +                       goto out_unmap;
>>
>>
>> Shouldn't be 'goto out_clk_disable' ?
>
> No, because I assumed !rate means we failed to get the clock.
> Actually, clk_get_rate could return 0, so relying on rate value is not safe.
>
> I propose to get clock-frequency property if IS_ERR(clk).
>
> Is it fine for you?

Why not invert the conditions ? If the 'clock-frequency' is specified in 
the DT then it overrides the clk_get_rate(). So the resulting code will be:

ret = of_property_read_u32(np, "clock-frequency", &rate);
if (ret) {
	clk = of_clk_get(np, 0);
	if (IS_ERR(clk))
		goto out_unmap;

	ret = clk_prepare_enable(clk);
	if (ret)
		goto out_clk_put;

	rate = clk_get_rate(clk);
	if (!rate)
		goto out_clk_unprepare;
}



>>> +       }
>>> +
>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>> +
>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>> rate,
>>> +                       200, 24, clocksource_mmio_readl_down);
>>> +       if (ret) {
>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>> +               goto out_clk_disable;
>>> +       }
>>> +
>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>> +
>>> +       return;
>>> +
>>> +out_clk_disable:
>>> +       if (!IS_ERR(clk))
>>
>>
>> Why do you need this check ?
>
> To handle the case were no clock was found, but a clk-frequency value
> was provided.
>
>>
>> It isn't missing a clk_put ?
>
> Right, thanks for spotting this.
>
> I wonder if it makes sense to implement the error path.
> If we fail to initialize the clocksource, the system will be unusable.
>
> Maybe I should just perform a BUG_ON() in the error cases, as most of
> the other clocksource drivers do.
> What is your view?

I prefer to not BUG_ON in the init functions because it already happen 
that drivers were bugging at init time and when a driver was reused on 
another platform with several timers available, the board was not able 
to boot because one timer was not used, hence not defined in the DT. I 
don't know if that could be the case for this platform but I prefer to 
keep thing going smoothly and return from init even if that lead to a 
kernel hang. Of course, the errors must be displayed (pr_warn, pr_err, 
pr_notice, etc ...).

>>
>>> +               clk_disable_unprepare(clk);
>>> +out_unmap:
>>> +       iounmap(base);
>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);

pr_warn

Thanks

   -- Daniel

-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-27  8:36         ` Daniel Lezcano
  0 siblings, 0 replies; 136+ messages in thread
From: Daniel Lezcano @ 2015-03-27  8:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
> Hi Daniel,
>
>    Thanks for the review. Please find my answers below.
>
> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>
>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>> This patch adds clocksource support for ARMv7-M's System timer,
>>> also known as SysTick.
>>>
>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>
>>
>> Hi Maxime,
>>
>> the driver looks good. Three comments below.
>>
>>    -- Daniel
>>
>>

[ ... ]

>>> +static void __init system_timer_of_register(struct device_node *np)
>>> +{
>>> +       struct clk *clk;
>>> +       void __iomem *base;
>>> +       u32 rate = 0;
>>> +       int ret;
>>> +
>>> +       base = of_iomap(np, 0);
>>> +       if (!base) {
>>> +               pr_warn("system-timer: invalid base address\n");
>>> +               return;
>>> +       }
>>> +
>>> +       clk = of_clk_get(np, 0);
>>> +       if (!IS_ERR(clk)) {
>>> +               ret = clk_prepare_enable(clk);
>>> +               if (ret) {
>>> +                       clk_put(clk);
>>> +                       goto out_unmap;
>>> +               }
>>> +
>>> +               rate = clk_get_rate(clk);
>>> +       }
>>> +
>>> +       /* If no clock found, try to get clock-frequency property */
>>> +       if (!rate) {
>>> +               ret = of_property_read_u32(np, "clock-frequency", &rate);
>>> +               if (ret)
>>> +                       goto out_unmap;
>>
>>
>> Shouldn't be 'goto out_clk_disable' ?
>
> No, because I assumed !rate means we failed to get the clock.
> Actually, clk_get_rate could return 0, so relying on rate value is not safe.
>
> I propose to get clock-frequency property if IS_ERR(clk).
>
> Is it fine for you?

Why not invert the conditions ? If the 'clock-frequency' is specified in 
the DT then it overrides the clk_get_rate(). So the resulting code will be:

ret = of_property_read_u32(np, "clock-frequency", &rate);
if (ret) {
	clk = of_clk_get(np, 0);
	if (IS_ERR(clk))
		goto out_unmap;

	ret = clk_prepare_enable(clk);
	if (ret)
		goto out_clk_put;

	rate = clk_get_rate(clk);
	if (!rate)
		goto out_clk_unprepare;
}



>>> +       }
>>> +
>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>> +
>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>> rate,
>>> +                       200, 24, clocksource_mmio_readl_down);
>>> +       if (ret) {
>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>> +               goto out_clk_disable;
>>> +       }
>>> +
>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>> +
>>> +       return;
>>> +
>>> +out_clk_disable:
>>> +       if (!IS_ERR(clk))
>>
>>
>> Why do you need this check ?
>
> To handle the case were no clock was found, but a clk-frequency value
> was provided.
>
>>
>> It isn't missing a clk_put ?
>
> Right, thanks for spotting this.
>
> I wonder if it makes sense to implement the error path.
> If we fail to initialize the clocksource, the system will be unusable.
>
> Maybe I should just perform a BUG_ON() in the error cases, as most of
> the other clocksource drivers do.
> What is your view?

I prefer to not BUG_ON in the init functions because it already happen 
that drivers were bugging at init time and when a driver was reused on 
another platform with several timers available, the board was not able 
to boot because one timer was not used, hence not defined in the DT. I 
don't know if that could be the case for this platform but I prefer to 
keep thing going smoothly and return from init even if that lead to a 
kernel hang. Of course, the errors must be displayed (pr_warn, pr_err, 
pr_notice, etc ...).

>>
>>> +               clk_disable_unprepare(clk);
>>> +out_unmap:
>>> +       iounmap(base);
>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);

pr_warn

Thanks

   -- Daniel

-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-26 22:03           ` Maxime Coquelin
  (?)
@ 2015-03-27 11:32             ` Peter Hurley
  -1 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-27 11:32 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                         struct ktermios *old)
>>> +{
>>> +     unsigned int baud;
>>> +     u32 usardiv, mantissa, fraction;
>>> +     tcflag_t cflag;
>>> +     u32 cr1, cr2, cr3;
>>> +     unsigned long flags;
>>> +
>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +     cflag = termios->c_cflag;
>>> +
>>> +     spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +     /* Stop serial port and reset value */
>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +     if (cflag & CSTOPB)
>>> +             cr2 = USART_CR2_STOP_2B;
>>> +
>>> +     if (cflag & PARENB) {
>>> +             cr1 |= USART_CR1_PCE;
>>> +             if ((cflag & CSIZE) == CS8)
>>> +                     cr1 |= USART_CR1_M;
>>> +     }
>>> +
>>> +     if (cflag & PARODD)
>>> +             cr1 |= USART_CR1_PS;
>>> +
>>> +     if (cflag & CRTSCTS)
>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>
>> If this means autoflow control, then you need to define
>> throttle()/unthrottle() methods, otherwise the serial core won't
>> be able to throttle the remote when input buffers are about
>> to overflow.
>>
>> And you should only enable the autoCTS and let the serial
>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>
>> Just let me know if you need more info about how to do this.
> 
> Ok, let's see if I have well understood.
> 
> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
> TIOCM_RTS  value.
> The throttle callback should disable the rx interrupt, and the
> unthrottle enable it.
> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
> 
> Am I right?

Yeah, basically. You also have to indicate to the serial core that you
require throttle/unthrottle handling in this mode by setting port->status.

Your set_termios() method would look like:

	port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
	if (cflag & CRTSCTS) {
		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
		cr3 = USART_CR3_CTSE;
	}

and your set_mctrl() method would look like:

	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
		stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
	else
		stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);

The UPSTAT_AUTOCTS doesn't really do anything right now but please
use it anyway to indicate this driver has that functionality.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-27 11:32             ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-27 11:32 UTC (permalink / raw)
  To: Maxime Coquelin
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                         struct ktermios *old)
>>> +{
>>> +     unsigned int baud;
>>> +     u32 usardiv, mantissa, fraction;
>>> +     tcflag_t cflag;
>>> +     u32 cr1, cr2, cr3;
>>> +     unsigned long flags;
>>> +
>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +     cflag = termios->c_cflag;
>>> +
>>> +     spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +     /* Stop serial port and reset value */
>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +     if (cflag & CSTOPB)
>>> +             cr2 = USART_CR2_STOP_2B;
>>> +
>>> +     if (cflag & PARENB) {
>>> +             cr1 |= USART_CR1_PCE;
>>> +             if ((cflag & CSIZE) == CS8)
>>> +                     cr1 |= USART_CR1_M;
>>> +     }
>>> +
>>> +     if (cflag & PARODD)
>>> +             cr1 |= USART_CR1_PS;
>>> +
>>> +     if (cflag & CRTSCTS)
>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>
>> If this means autoflow control, then you need to define
>> throttle()/unthrottle() methods, otherwise the serial core won't
>> be able to throttle the remote when input buffers are about
>> to overflow.
>>
>> And you should only enable the autoCTS and let the serial
>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>
>> Just let me know if you need more info about how to do this.
> 
> Ok, let's see if I have well understood.
> 
> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
> TIOCM_RTS  value.
> The throttle callback should disable the rx interrupt, and the
> unthrottle enable it.
> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
> 
> Am I right?

Yeah, basically. You also have to indicate to the serial core that you
require throttle/unthrottle handling in this mode by setting port->status.

Your set_termios() method would look like:

	port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
	if (cflag & CRTSCTS) {
		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
		cr3 = USART_CR3_CTSE;
	}

and your set_mctrl() method would look like:

	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
		stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
	else
		stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);

The UPSTAT_AUTOCTS doesn't really do anything right now but please
use it anyway to indicate this driver has that functionality.

Regards,
Peter Hurley


^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-27 11:32             ` Peter Hurley
  0 siblings, 0 replies; 136+ messages in thread
From: Peter Hurley @ 2015-03-27 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>> +                         struct ktermios *old)
>>> +{
>>> +     unsigned int baud;
>>> +     u32 usardiv, mantissa, fraction;
>>> +     tcflag_t cflag;
>>> +     u32 cr1, cr2, cr3;
>>> +     unsigned long flags;
>>> +
>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>> +     cflag = termios->c_cflag;
>>> +
>>> +     spin_lock_irqsave(&port->lock, flags);
>>> +
>>> +     /* Stop serial port and reset value */
>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>> +
>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>> +
>>> +     if (cflag & CSTOPB)
>>> +             cr2 = USART_CR2_STOP_2B;
>>> +
>>> +     if (cflag & PARENB) {
>>> +             cr1 |= USART_CR1_PCE;
>>> +             if ((cflag & CSIZE) == CS8)
>>> +                     cr1 |= USART_CR1_M;
>>> +     }
>>> +
>>> +     if (cflag & PARODD)
>>> +             cr1 |= USART_CR1_PS;
>>> +
>>> +     if (cflag & CRTSCTS)
>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>
>> If this means autoflow control, then you need to define
>> throttle()/unthrottle() methods, otherwise the serial core won't
>> be able to throttle the remote when input buffers are about
>> to overflow.
>>
>> And you should only enable the autoCTS and let the serial
>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>
>> Just let me know if you need more info about how to do this.
> 
> Ok, let's see if I have well understood.
> 
> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
> TIOCM_RTS  value.
> The throttle callback should disable the rx interrupt, and the
> unthrottle enable it.
> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
> 
> Am I right?

Yeah, basically. You also have to indicate to the serial core that you
require throttle/unthrottle handling in this mode by setting port->status.

Your set_termios() method would look like:

	port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
	if (cflag & CRTSCTS) {
		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
		cr3 = USART_CR3_CTSE;
	}

and your set_mctrl() method would look like:

	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
		stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
	else
		stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);

The UPSTAT_AUTOCTS doesn't really do anything right now but please
use it anyway to indicate this driver has that functionality.

Regards,
Peter Hurley

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
  2015-03-27 11:32             ` Peter Hurley
  (?)
@ 2015-03-27 12:30               ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:30 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller

2015-03-27 12:32 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                         struct ktermios *old)
>>>> +{
>>>> +     unsigned int baud;
>>>> +     u32 usardiv, mantissa, fraction;
>>>> +     tcflag_t cflag;
>>>> +     u32 cr1, cr2, cr3;
>>>> +     unsigned long flags;
>>>> +
>>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +     cflag = termios->c_cflag;
>>>> +
>>>> +     spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +     /* Stop serial port and reset value */
>>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +     if (cflag & CSTOPB)
>>>> +             cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +     if (cflag & PARENB) {
>>>> +             cr1 |= USART_CR1_PCE;
>>>> +             if ((cflag & CSIZE) == CS8)
>>>> +                     cr1 |= USART_CR1_M;
>>>> +     }
>>>> +
>>>> +     if (cflag & PARODD)
>>>> +             cr1 |= USART_CR1_PS;
>>>> +
>>>> +     if (cflag & CRTSCTS)
>>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>
>>> If this means autoflow control, then you need to define
>>> throttle()/unthrottle() methods, otherwise the serial core won't
>>> be able to throttle the remote when input buffers are about
>>> to overflow.
>>>
>>> And you should only enable the autoCTS and let the serial
>>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>>
>>> Just let me know if you need more info about how to do this.
>>
>> Ok, let's see if I have well understood.
>>
>> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
>> TIOCM_RTS  value.
>> The throttle callback should disable the rx interrupt, and the
>> unthrottle enable it.
>> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
>>
>> Am I right?
>
> Yeah, basically. You also have to indicate to the serial core that you
> require throttle/unthrottle handling in this mode by setting port->status.
>
> Your set_termios() method would look like:
>
>         port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
>         if (cflag & CRTSCTS) {
>                 port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
>                 cr3 = USART_CR3_CTSE;
>         }
>
> and your set_mctrl() method would look like:
>
>         if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
>                 stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
>         else
>                 stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);
>
> The UPSTAT_AUTOCTS doesn't really do anything right now but please
> use it anyway to indicate this driver has that functionality.

Ok, thanks for your support.

I will implement this in the v4.

Regards,
Maxime

>
> Regards,
> Peter Hurley
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-27 12:30               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:30 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Daniel Lezcano, Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby,
	Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
	Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon,
	Nikolay Borisov, Rusty Russell, Kees Cook, Michal Marek,
	linux-doc, linux-arm-kernel, linux-kernel, devicetree,
	linux-gpio, linux-serial, Linux-Arch, linux-api

2015-03-27 12:32 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                         struct ktermios *old)
>>>> +{
>>>> +     unsigned int baud;
>>>> +     u32 usardiv, mantissa, fraction;
>>>> +     tcflag_t cflag;
>>>> +     u32 cr1, cr2, cr3;
>>>> +     unsigned long flags;
>>>> +
>>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +     cflag = termios->c_cflag;
>>>> +
>>>> +     spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +     /* Stop serial port and reset value */
>>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +     if (cflag & CSTOPB)
>>>> +             cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +     if (cflag & PARENB) {
>>>> +             cr1 |= USART_CR1_PCE;
>>>> +             if ((cflag & CSIZE) == CS8)
>>>> +                     cr1 |= USART_CR1_M;
>>>> +     }
>>>> +
>>>> +     if (cflag & PARODD)
>>>> +             cr1 |= USART_CR1_PS;
>>>> +
>>>> +     if (cflag & CRTSCTS)
>>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>
>>> If this means autoflow control, then you need to define
>>> throttle()/unthrottle() methods, otherwise the serial core won't
>>> be able to throttle the remote when input buffers are about
>>> to overflow.
>>>
>>> And you should only enable the autoCTS and let the serial
>>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>>
>>> Just let me know if you need more info about how to do this.
>>
>> Ok, let's see if I have well understood.
>>
>> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
>> TIOCM_RTS  value.
>> The throttle callback should disable the rx interrupt, and the
>> unthrottle enable it.
>> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
>>
>> Am I right?
>
> Yeah, basically. You also have to indicate to the serial core that you
> require throttle/unthrottle handling in this mode by setting port->status.
>
> Your set_termios() method would look like:
>
>         port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
>         if (cflag & CRTSCTS) {
>                 port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
>                 cr3 = USART_CR3_CTSE;
>         }
>
> and your set_mctrl() method would look like:
>
>         if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
>                 stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
>         else
>                 stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);
>
> The UPSTAT_AUTOCTS doesn't really do anything right now but please
> use it anyway to indicate this driver has that functionality.

Ok, thanks for your support.

I will implement this in the v4.

Regards,
Maxime

>
> Regards,
> Peter Hurley
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver
@ 2015-03-27 12:30               ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:30 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-27 12:32 GMT+01:00 Peter Hurley <peter@hurleysoftware.com>:
> On 03/26/2015 06:03 PM, Maxime Coquelin wrote:
>>>> +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
>>>> +                         struct ktermios *old)
>>>> +{
>>>> +     unsigned int baud;
>>>> +     u32 usardiv, mantissa, fraction;
>>>> +     tcflag_t cflag;
>>>> +     u32 cr1, cr2, cr3;
>>>> +     unsigned long flags;
>>>> +
>>>> +     baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>> +     cflag = termios->c_cflag;
>>>> +
>>>> +     spin_lock_irqsave(&port->lock, flags);
>>>> +
>>>> +     /* Stop serial port and reset value */
>>>> +     writel_relaxed(0, port->membase + USART_CR1);
>>>> +
>>>> +     cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
>>>> +
>>>> +     if (cflag & CSTOPB)
>>>> +             cr2 = USART_CR2_STOP_2B;
>>>> +
>>>> +     if (cflag & PARENB) {
>>>> +             cr1 |= USART_CR1_PCE;
>>>> +             if ((cflag & CSIZE) == CS8)
>>>> +                     cr1 |= USART_CR1_M;
>>>> +     }
>>>> +
>>>> +     if (cflag & PARODD)
>>>> +             cr1 |= USART_CR1_PS;
>>>> +
>>>> +     if (cflag & CRTSCTS)
>>>> +             cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
>>>
>>> If this means autoflow control, then you need to define
>>> throttle()/unthrottle() methods, otherwise the serial core won't
>>> be able to throttle the remote when input buffers are about
>>> to overflow.
>>>
>>> And you should only enable the autoCTS and let the serial
>>> core enable autoRTS through set_mctrl(TIOCM_RTS).
>>>
>>> Just let me know if you need more info about how to do this.
>>
>> Ok, let's see if I have well understood.
>>
>> USART_CR3_RTSE should be set/cleared in set_mctrl(), depending on
>> TIOCM_RTS  value.
>> The throttle callback should disable the rx interrupt, and the
>> unthrottle enable it.
>> For CTS, it should be enabled in set_termios() if CRTSCTS, as done here.
>>
>> Am I right?
>
> Yeah, basically. You also have to indicate to the serial core that you
> require throttle/unthrottle handling in this mode by setting port->status.
>
> Your set_termios() method would look like:
>
>         port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
>         if (cflag & CRTSCTS) {
>                 port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
>                 cr3 = USART_CR3_CTSE;
>         }
>
> and your set_mctrl() method would look like:
>
>         if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
>                 stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
>         else
>                 stm32_clear_bits(port, USART_CR3, USART_CR3_RTSE);
>
> The UPSTAT_AUTOCTS doesn't really do anything right now but please
> use it anyway to indicate this driver has that functionality.

Ok, thanks for your support.

I will implement this in the v4.

Regards,
Maxime

>
> Regards,
> Peter Hurley
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
  2015-03-27  8:36         ` Daniel Lezcano
  (?)
@ 2015-03-27 12:33           ` Maxime Coquelin
  -1 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:33 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab

2015-03-27 9:36 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
>>
>> Hi Daniel,
>>
>>    Thanks for the review. Please find my answers below.
>>
>> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>>>
>>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>>
>>>>
>>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>>
>>>> This patch adds clocksource support for ARMv7-M's System timer,
>>>> also known as SysTick.
>>>>
>>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>>
>>>
>>> Hi Maxime,
>>>
>>> the driver looks good. Three comments below.
>>>
>>>    -- Daniel
>>>
>>>
>
> [ ... ]
>
>
>>>> +static void __init system_timer_of_register(struct device_node *np)
>>>> +{
>>>> +       struct clk *clk;
>>>> +       void __iomem *base;
>>>> +       u32 rate = 0;
>>>> +       int ret;
>>>> +
>>>> +       base = of_iomap(np, 0);
>>>> +       if (!base) {
>>>> +               pr_warn("system-timer: invalid base address\n");
>>>> +               return;
>>>> +       }
>>>> +
>>>> +       clk = of_clk_get(np, 0);
>>>> +       if (!IS_ERR(clk)) {
>>>> +               ret = clk_prepare_enable(clk);
>>>> +               if (ret) {
>>>> +                       clk_put(clk);
>>>> +                       goto out_unmap;
>>>> +               }
>>>> +
>>>> +               rate = clk_get_rate(clk);
>>>> +       }
>>>> +
>>>> +       /* If no clock found, try to get clock-frequency property */
>>>> +       if (!rate) {
>>>> +               ret = of_property_read_u32(np, "clock-frequency",
>>>> &rate);
>>>> +               if (ret)
>>>> +                       goto out_unmap;
>>>
>>>
>>>
>>> Shouldn't be 'goto out_clk_disable' ?
>>
>>
>> No, because I assumed !rate means we failed to get the clock.
>> Actually, clk_get_rate could return 0, so relying on rate value is not
>> safe.
>>
>> I propose to get clock-frequency property if IS_ERR(clk).
>>
>> Is it fine for you?
>
>
> Why not invert the conditions ? If the 'clock-frequency' is specified in the
> DT then it overrides the clk_get_rate(). So the resulting code will be:
>
> ret = of_property_read_u32(np, "clock-frequency", &rate);
> if (ret) {
>         clk = of_clk_get(np, 0);
>         if (IS_ERR(clk))
>                 goto out_unmap;
>
>         ret = clk_prepare_enable(clk);
>         if (ret)
>                 goto out_clk_put;
>
>         rate = clk_get_rate(clk);
>         if (!rate)
>                 goto out_clk_unprepare;
>
> }

Ok, it looks sensible.
I will do this in next version.

>
>
>
>>>> +       }
>>>> +
>>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>>> +
>>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>>> rate,
>>>> +                       200, 24, clocksource_mmio_readl_down);
>>>> +       if (ret) {
>>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>>> +               goto out_clk_disable;
>>>> +       }
>>>> +
>>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>>> +
>>>> +       return;
>>>> +
>>>> +out_clk_disable:
>>>> +       if (!IS_ERR(clk))
>>>
>>>
>>>
>>> Why do you need this check ?
>>
>>
>> To handle the case were no clock was found, but a clk-frequency value
>> was provided.
>>
>>>
>>> It isn't missing a clk_put ?
>>
>>
>> Right, thanks for spotting this.
>>
>> I wonder if it makes sense to implement the error path.
>> If we fail to initialize the clocksource, the system will be unusable.
>>
>> Maybe I should just perform a BUG_ON() in the error cases, as most of
>> the other clocksource drivers do.
>> What is your view?
>
>
> I prefer to not BUG_ON in the init functions because it already happen that
> drivers were bugging at init time and when a driver was reused on another
> platform with several timers available, the board was not able to boot
> because one timer was not used, hence not defined in the DT. I don't know if
> that could be the case for this platform but I prefer to keep thing going
> smoothly and return from init even if that lead to a kernel hang. Of course,
> the errors must be displayed (pr_warn, pr_err, pr_notice, etc ...).

Ok, let's keep the error path, that's much cleaner indeed.

>
>>>
>>>> +               clk_disable_unprepare(clk);
>>>> +out_unmap:
>>>> +       iounmap(base);
>>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>
>
> pr_warn

Sure, will fix.

Thanks,
Maxime

>
> Thanks
>
>   -- Daniel
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 136+ messages in thread

* Re: [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-27 12:33           ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:33 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
	Rob Herring, Philipp Zabel, Linus Walleij, Arnd Bergmann,
	Stefan Agner, Peter Meerwald, Paul Bolle, Jonathan Corbet,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
	Thomas Gleixner, Greg Kroah-Hartman, Jiri Slaby, Andrew Morton,
	David S. Miller, Mauro Carvalho Chehab, Joe Perches,
	Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov,
	Rusty Russell, Kees Cook, Michal Marek, linux-doc,
	linux-arm-kernel, linux-kernel, devicetree, linux-gpio,
	linux-serial, Linux-Arch, linux-api

2015-03-27 9:36 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
>>
>> Hi Daniel,
>>
>>    Thanks for the review. Please find my answers below.
>>
>> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>>>
>>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>>
>>>>
>>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>>
>>>> This patch adds clocksource support for ARMv7-M's System timer,
>>>> also known as SysTick.
>>>>
>>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>>
>>>
>>> Hi Maxime,
>>>
>>> the driver looks good. Three comments below.
>>>
>>>    -- Daniel
>>>
>>>
>
> [ ... ]
>
>
>>>> +static void __init system_timer_of_register(struct device_node *np)
>>>> +{
>>>> +       struct clk *clk;
>>>> +       void __iomem *base;
>>>> +       u32 rate = 0;
>>>> +       int ret;
>>>> +
>>>> +       base = of_iomap(np, 0);
>>>> +       if (!base) {
>>>> +               pr_warn("system-timer: invalid base address\n");
>>>> +               return;
>>>> +       }
>>>> +
>>>> +       clk = of_clk_get(np, 0);
>>>> +       if (!IS_ERR(clk)) {
>>>> +               ret = clk_prepare_enable(clk);
>>>> +               if (ret) {
>>>> +                       clk_put(clk);
>>>> +                       goto out_unmap;
>>>> +               }
>>>> +
>>>> +               rate = clk_get_rate(clk);
>>>> +       }
>>>> +
>>>> +       /* If no clock found, try to get clock-frequency property */
>>>> +       if (!rate) {
>>>> +               ret = of_property_read_u32(np, "clock-frequency",
>>>> &rate);
>>>> +               if (ret)
>>>> +                       goto out_unmap;
>>>
>>>
>>>
>>> Shouldn't be 'goto out_clk_disable' ?
>>
>>
>> No, because I assumed !rate means we failed to get the clock.
>> Actually, clk_get_rate could return 0, so relying on rate value is not
>> safe.
>>
>> I propose to get clock-frequency property if IS_ERR(clk).
>>
>> Is it fine for you?
>
>
> Why not invert the conditions ? If the 'clock-frequency' is specified in the
> DT then it overrides the clk_get_rate(). So the resulting code will be:
>
> ret = of_property_read_u32(np, "clock-frequency", &rate);
> if (ret) {
>         clk = of_clk_get(np, 0);
>         if (IS_ERR(clk))
>                 goto out_unmap;
>
>         ret = clk_prepare_enable(clk);
>         if (ret)
>                 goto out_clk_put;
>
>         rate = clk_get_rate(clk);
>         if (!rate)
>                 goto out_clk_unprepare;
>
> }

Ok, it looks sensible.
I will do this in next version.

>
>
>
>>>> +       }
>>>> +
>>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>>> +
>>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>>> rate,
>>>> +                       200, 24, clocksource_mmio_readl_down);
>>>> +       if (ret) {
>>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>>> +               goto out_clk_disable;
>>>> +       }
>>>> +
>>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>>> +
>>>> +       return;
>>>> +
>>>> +out_clk_disable:
>>>> +       if (!IS_ERR(clk))
>>>
>>>
>>>
>>> Why do you need this check ?
>>
>>
>> To handle the case were no clock was found, but a clk-frequency value
>> was provided.
>>
>>>
>>> It isn't missing a clk_put ?
>>
>>
>> Right, thanks for spotting this.
>>
>> I wonder if it makes sense to implement the error path.
>> If we fail to initialize the clocksource, the system will be unusable.
>>
>> Maybe I should just perform a BUG_ON() in the error cases, as most of
>> the other clocksource drivers do.
>> What is your view?
>
>
> I prefer to not BUG_ON in the init functions because it already happen that
> drivers were bugging at init time and when a driver was reused on another
> platform with several timers available, the board was not able to boot
> because one timer was not used, hence not defined in the DT. I don't know if
> that could be the case for this platform but I prefer to keep thing going
> smoothly and return from init even if that lead to a kernel hang. Of course,
> the errors must be displayed (pr_warn, pr_err, pr_notice, etc ...).

Ok, let's keep the error path, that's much cleaner indeed.

>
>>>
>>>> +               clk_disable_unprepare(clk);
>>>> +out_unmap:
>>>> +       iounmap(base);
>>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>
>
> pr_warn

Sure, will fix.

Thanks,
Maxime

>
> Thanks
>
>   -- Daniel
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

* [PATCH v3 04/15] clocksource: Add ARM System timer driver
@ 2015-03-27 12:33           ` Maxime Coquelin
  0 siblings, 0 replies; 136+ messages in thread
From: Maxime Coquelin @ 2015-03-27 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

2015-03-27 9:36 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
> On 03/26/2015 09:19 PM, Maxime Coquelin wrote:
>>
>> Hi Daniel,
>>
>>    Thanks for the review. Please find my answers below.
>>
>> 2015-03-26 10:50 GMT+01:00 Daniel Lezcano <daniel.lezcano@linaro.org>:
>>>
>>> On 03/12/2015 10:55 PM, Maxime Coquelin wrote:
>>>>
>>>>
>>>> From: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>>
>>>> This patch adds clocksource support for ARMv7-M's System timer,
>>>> also known as SysTick.
>>>>
>>>> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>>>
>>>
>>>
>>> Hi Maxime,
>>>
>>> the driver looks good. Three comments below.
>>>
>>>    -- Daniel
>>>
>>>
>
> [ ... ]
>
>
>>>> +static void __init system_timer_of_register(struct device_node *np)
>>>> +{
>>>> +       struct clk *clk;
>>>> +       void __iomem *base;
>>>> +       u32 rate = 0;
>>>> +       int ret;
>>>> +
>>>> +       base = of_iomap(np, 0);
>>>> +       if (!base) {
>>>> +               pr_warn("system-timer: invalid base address\n");
>>>> +               return;
>>>> +       }
>>>> +
>>>> +       clk = of_clk_get(np, 0);
>>>> +       if (!IS_ERR(clk)) {
>>>> +               ret = clk_prepare_enable(clk);
>>>> +               if (ret) {
>>>> +                       clk_put(clk);
>>>> +                       goto out_unmap;
>>>> +               }
>>>> +
>>>> +               rate = clk_get_rate(clk);
>>>> +       }
>>>> +
>>>> +       /* If no clock found, try to get clock-frequency property */
>>>> +       if (!rate) {
>>>> +               ret = of_property_read_u32(np, "clock-frequency",
>>>> &rate);
>>>> +               if (ret)
>>>> +                       goto out_unmap;
>>>
>>>
>>>
>>> Shouldn't be 'goto out_clk_disable' ?
>>
>>
>> No, because I assumed !rate means we failed to get the clock.
>> Actually, clk_get_rate could return 0, so relying on rate value is not
>> safe.
>>
>> I propose to get clock-frequency property if IS_ERR(clk).
>>
>> Is it fine for you?
>
>
> Why not invert the conditions ? If the 'clock-frequency' is specified in the
> DT then it overrides the clk_get_rate(). So the resulting code will be:
>
> ret = of_property_read_u32(np, "clock-frequency", &rate);
> if (ret) {
>         clk = of_clk_get(np, 0);
>         if (IS_ERR(clk))
>                 goto out_unmap;
>
>         ret = clk_prepare_enable(clk);
>         if (ret)
>                 goto out_clk_put;
>
>         rate = clk_get_rate(clk);
>         if (!rate)
>                 goto out_clk_unprepare;
>
> }

Ok, it looks sensible.
I will do this in next version.

>
>
>
>>>> +       }
>>>> +
>>>> +       writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
>>>> +       writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
>>>> +
>>>> +       ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer",
>>>> rate,
>>>> +                       200, 24, clocksource_mmio_readl_down);
>>>> +       if (ret) {
>>>> +               pr_err("failed to init clocksource (%d)\n", ret);
>>>> +               goto out_clk_disable;
>>>> +       }
>>>> +
>>>> +       pr_info("ARM System timer initialized as clocksource\n");
>>>> +
>>>> +       return;
>>>> +
>>>> +out_clk_disable:
>>>> +       if (!IS_ERR(clk))
>>>
>>>
>>>
>>> Why do you need this check ?
>>
>>
>> To handle the case were no clock was found, but a clk-frequency value
>> was provided.
>>
>>>
>>> It isn't missing a clk_put ?
>>
>>
>> Right, thanks for spotting this.
>>
>> I wonder if it makes sense to implement the error path.
>> If we fail to initialize the clocksource, the system will be unusable.
>>
>> Maybe I should just perform a BUG_ON() in the error cases, as most of
>> the other clocksource drivers do.
>> What is your view?
>
>
> I prefer to not BUG_ON in the init functions because it already happen that
> drivers were bugging at init time and when a driver was reused on another
> platform with several timers available, the board was not able to boot
> because one timer was not used, hence not defined in the DT. I don't know if
> that could be the case for this platform but I prefer to keep thing going
> smoothly and return from init even if that lead to a kernel hang. Of course,
> the errors must be displayed (pr_warn, pr_err, pr_notice, etc ...).

Ok, let's keep the error path, that's much cleaner indeed.

>
>>>
>>>> +               clk_disable_unprepare(clk);
>>>> +out_unmap:
>>>> +       iounmap(base);
>>>> +       WARN(ret, "ARM System timer register failed (%d)\n", ret);
>
>
> pr_warn

Sure, will fix.

Thanks,
Maxime

>
> Thanks
>
>   -- Daniel
>
>
> --
>  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

^ permalink raw reply	[flat|nested] 136+ messages in thread

end of thread, other threads:[~2015-03-27 12:34 UTC | newest]

Thread overview: 136+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-12 21:55 [PATCH v3 00/15] Add support to STMicroelectronics STM32 family Maxime Coquelin
2015-03-12 21:55 ` Maxime Coquelin
2015-03-12 21:55 ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 02/15] ARM: ARMv7-M: Enlarge vector table up to 256 entries Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 03/15] dt-bindings: Document the ARM System timer bindings Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 04/15] clocksource: Add ARM System timer driver Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-26  9:50   ` Daniel Lezcano
2015-03-26  9:50     ` Daniel Lezcano
2015-03-26  9:50     ` Daniel Lezcano
2015-03-26 20:19     ` Maxime Coquelin
2015-03-26 20:19       ` Maxime Coquelin
2015-03-26 20:19       ` Maxime Coquelin
2015-03-27  8:36       ` Daniel Lezcano
2015-03-27  8:36         ` Daniel Lezcano
2015-03-27  8:36         ` Daniel Lezcano
2015-03-27 12:33         ` Maxime Coquelin
2015-03-27 12:33           ` Maxime Coquelin
2015-03-27 12:33           ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 05/15] dt-bindings: Document the STM32 reset bindings Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-13  0:09   ` Chanwoo Choi
2015-03-13  0:09     ` Chanwoo Choi
2015-03-13  0:09     ` Chanwoo Choi
2015-03-17 16:57     ` Maxime Coquelin
2015-03-17 16:57       ` Maxime Coquelin
2015-03-17 16:57       ` Maxime Coquelin
2015-03-13  8:50   ` Philipp Zabel
2015-03-13  8:50     ` Philipp Zabel
2015-03-13  8:50     ` Philipp Zabel
     [not found]     ` <1426236654.3083.19.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2015-03-17 17:13       ` Maxime Coquelin
2015-03-17 17:13         ` Maxime Coquelin
2015-03-17 17:13         ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 06/15] drivers: reset: Add STM32 reset driver Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-13  0:11   ` Chanwoo Choi
2015-03-13  0:11     ` Chanwoo Choi
2015-03-13  0:11     ` Chanwoo Choi
2015-03-13  8:54   ` Philipp Zabel
2015-03-13  8:54     ` Philipp Zabel
2015-03-13  8:54     ` Philipp Zabel
2015-03-17 17:23     ` Maxime Coquelin
2015-03-17 17:23       ` Maxime Coquelin
2015-03-17 17:23       ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 07/15] dt-bindings: Document the STM32 timer bindings Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 08/15] clockevent: Add STM32 Timer driver Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 09/15] dt-bindings: Document the STM32 USART bindings Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
     [not found] ` <1426197361-19290-1-git-send-email-maxime.coquelin-qxv4g6HH51o@public.gmane.org>
2015-03-12 21:55   ` [PATCH v3 01/15] scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP Kernel Maxime Coquelin
2015-03-12 21:55     ` Maxime Coquelin
2015-03-12 21:55     ` Maxime Coquelin
2015-03-12 21:55   ` [PATCH v3 10/15] serial: stm32-usart: Add STM32 USART Driver Maxime Coquelin
2015-03-12 21:55     ` Maxime Coquelin
2015-03-12 21:55     ` Maxime Coquelin
2015-03-13  9:41     ` Paul Bolle
2015-03-13  9:41       ` Paul Bolle
2015-03-13  9:41       ` Paul Bolle
2015-03-17 17:39       ` Maxime Coquelin
2015-03-17 17:39         ` Maxime Coquelin
2015-03-17 17:39         ` Maxime Coquelin
2015-03-13 14:19     ` Andy Shevchenko
2015-03-13 14:19       ` Andy Shevchenko
2015-03-13 14:19       ` Andy Shevchenko
2015-03-17 17:32       ` Maxime Coquelin
2015-03-17 17:32         ` Maxime Coquelin
2015-03-17 17:32         ` Maxime Coquelin
     [not found]         ` <CALszF6BWuUYRh+3rWnSQLApkAHA5dQXw=6x6D_evRtb+5B_ukA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-03-17 17:56           ` Andy Shevchenko
2015-03-17 17:56             ` Andy Shevchenko
2015-03-17 17:56             ` Andy Shevchenko
2015-03-19 13:55             ` Maxime Coquelin
2015-03-19 13:55               ` Maxime Coquelin
2015-03-19 13:55               ` Maxime Coquelin
     [not found]               ` <CALszF6A5Zu7i0hxSLTS-nfOAXmd0__jLjB=fHxK93Ex5Vbi9LA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-03-19 14:58                 ` Peter Hurley
2015-03-19 14:58                   ` Peter Hurley
2015-03-19 14:58                   ` Peter Hurley
     [not found]                   ` <550AE41C.8070803-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
2015-03-19 17:35                     ` Maxime Coquelin
2015-03-19 17:35                       ` Maxime Coquelin
2015-03-19 17:35                       ` Maxime Coquelin
2015-03-24 17:21                       ` Maxime Coquelin
2015-03-24 17:21                         ` Maxime Coquelin
2015-03-24 17:21                         ` Maxime Coquelin
     [not found]                         ` <CALszF6Dg7t9+F9NG+xREPQeaAj7T6D1GuGabkr8EvOAAdtg7yA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-03-24 17:44                           ` Peter Hurley
2015-03-24 17:44                             ` Peter Hurley
2015-03-24 17:44                             ` Peter Hurley
     [not found]     ` <1426197361-19290-11-git-send-email-maxime.coquelin-qxv4g6HH51o@public.gmane.org>
2015-03-24 18:23       ` Peter Hurley
2015-03-24 18:23         ` Peter Hurley
2015-03-24 18:23         ` Peter Hurley
     [not found]         ` <5511ABAA.2010303-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
2015-03-26 15:46           ` Russell King - ARM Linux
2015-03-26 15:46             ` Russell King - ARM Linux
2015-03-26 15:46             ` Russell King - ARM Linux
2015-03-26 22:05             ` Maxime Coquelin
2015-03-26 22:05               ` Maxime Coquelin
2015-03-26 22:05               ` Maxime Coquelin
2015-03-26 22:03         ` Maxime Coquelin
2015-03-26 22:03           ` Maxime Coquelin
2015-03-26 22:03           ` Maxime Coquelin
2015-03-27 11:32           ` Peter Hurley
2015-03-27 11:32             ` Peter Hurley
2015-03-27 11:32             ` Peter Hurley
2015-03-27 12:30             ` Maxime Coquelin
2015-03-27 12:30               ` Maxime Coquelin
2015-03-27 12:30               ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 11/15] ARM: Add STM32 family machine Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 12/15] ARM: dts: Add ARM System timer as clockevent in armv7m Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55 ` [PATCH v3 13/15] ARM: dts: Introduce STM32F429 MCU Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:55   ` Maxime Coquelin
2015-03-12 21:56 ` [PATCH v3 14/15] ARM: configs: Add STM32 defconfig Maxime Coquelin
2015-03-12 21:56   ` Maxime Coquelin
2015-03-12 21:56   ` Maxime Coquelin
2015-03-12 21:56 ` [PATCH v3 15/15] MAINTAINERS: Add entry for STM32 MCUs Maxime Coquelin
2015-03-12 21:56   ` Maxime Coquelin
2015-03-12 21:56   ` Maxime Coquelin
2015-03-12 23:45 ` [PATCH v3 00/15] Add support to STMicroelectronics STM32 family Chanwoo Choi
2015-03-12 23:45   ` Chanwoo Choi
2015-03-12 23:45   ` Chanwoo Choi
2015-03-18 23:35 ` Chanwoo Choi
2015-03-18 23:35   ` Chanwoo Choi
2015-03-18 23:35   ` Chanwoo Choi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.