All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit
@ 2015-06-23 21:19 ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This patchset adds a very basic initial support for TWR-K70F120M
development kit which is based on ARM Cortex-M4 Freescale Kinetis K70 SoC.

I've found this a very lovely piece of equipment which allowed me to
explore mysterious world of noMMU Linux. Therefore I think it deserves
proper support from upstream Linux kernel side.

I based my work on K70 Sub-Family Reference Manual Rev. 3,
K70P256M150SF3RM.pdf and commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

The BSP published by Emcraft is based on Linux 2.6.33, does not use
OF Device Tree and implements its own NVIC, clock source, IOMUX and DMA
controller support routines. I wrote clear remarks whenever I'd used parts
of the code from their repository.

I decided to make use of recent additions to linux-next whenever it was
suitable, i.e.:

o all devices are configured in .dts files
o for NVIC I used in-tree driver
o for systick I used recently added arm,armv7m-systick driver
o for clock sources I implemented drivers that in shape are similar
      to efm32gg drivers (another ARM Cortex-M4 based platform - already
      supported by upstream kernel so I could use it as a reference on how
      things should possibly be done)
o for IOMUX I implemented very simplified pinctrl OF-friendly driver
  (which is sufficient for now, at least to configure UART pins)
o for DMA I extended existing Freescale eDMA driver
o for UART I also extended existing Freescale lpuart driver

You may find the first three patches a bit controversial. They intrude into
sensitive parts of ARM support in kernel tree. You may not like it, but
that's how it started to work for me. I tried to minimize the impact as
much as I could, however any better proposals are more than welcome.

Note that U-boot on my TWR-K70F120M is a bit modest and does not support
DTBs. Therefore the only option for having bootable uImage is zImage with
DTB attached at the end. In short it can be done like this:

make uImage                  (this creates normal uImage along with zImage)
make kinetis-twr-k70f120m.dtb
cat arch/arm/boot/zImage arch/arm/boot/dts/kinetis-twr-k70f120m.dtb >Image
mkimage -A arm -O linux -C none -T kernel -a 0x08008000 -e 0x08008001 \
        -n 'Linux-next-with-dtb' -d Image uImage

I'm booting this image over local network using TFTP. The userspace resides
in initramfs and consists of busybox and a few very basic command line
tools.

This initial support is just a beginning. My TWR-K70F120M is equipped with
many interesting features to which many drivers can be written.

During my work I was using Segger J-Link PRO JTAG which works nicely with
this development board - I can't imagine myself doing all this stuff
without it.

Paul Osmialowski (9):
  arm: select different compiler flags for ARM CortexM3
  arm: do not place huge encoder tables on stack when it is too small
  arm: add call to CPU idle quirks handler
  arm: allow copying of vector table to internal SRAM memory
  arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  arm: twr-k70f120m: clock source drivers for Kinetis SoC
  arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  arm: twr-k70f120m: extend Freescale eDMA driver with ability to
    support Kinetis SoC
  arm: twr-k70f120m: extend Freescale lpuart driver with ability to
    support Kinetis SoC

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +
 .../devicetree/bindings/clock/kinetis-clock.txt    |  25 +
 Documentation/devicetree/bindings/dma/fsl-edma.txt |  38 +-
 .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++
 .../devicetree/bindings/serial/fsl-lpuart.txt      |   6 +-
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  18 +
 arch/arm/Kconfig                                   |  29 +-
 arch/arm/Kconfig-nommu                             |  16 +
 arch/arm/Makefile                                  |   2 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |  43 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 215 +++++++++
 arch/arm/kernel/entry-v7m.S                        |   3 +
 arch/arm/kernel/process.c                          |   7 +
 arch/arm/mach-kinetis/Kconfig                      |  15 +
 arch/arm/mach-kinetis/Makefile                     |   5 +
 arch/arm/mach-kinetis/Makefile.boot                |   3 +
 arch/arm/mach-kinetis/include/mach/idle.h          |  33 ++
 arch/arm/mach-kinetis/include/mach/kinetis.h       | 170 +++++++
 arch/arm/mach-kinetis/include/mach/memory.h        |  61 +++
 arch/arm/mach-kinetis/include/mach/power.h         |  83 ++++
 arch/arm/mach-kinetis/kinetis_platform.c           |  61 +++
 arch/arm/mm/Kconfig                                |  12 +-
 arch/arm/mm/proc-v7m.S                             |  11 +
 arch/arm/tools/mach-types                          |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 297 ++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 294 ++++++++++++
 drivers/dma/fsl-edma.c                             |  81 +++-
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
 drivers/tty/serial/fsl_lpuart.c                    |  90 +++-
 include/dt-bindings/clock/kinetis-mcg.h            |  25 +
 lib/zlib_inflate/inflate.c                         |   5 +
 36 files changed, 2210 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 arch/arm/boot/dts/kinetis-twr-k70f120m.dts
 create mode 100644 arch/arm/boot/dts/kinetis.dtsi
 create mode 100644 arch/arm/mach-kinetis/Kconfig
 create mode 100644 arch/arm/mach-kinetis/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/include/mach/idle.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/kinetis.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/power.h
 create mode 100644 arch/arm/mach-kinetis/kinetis_platform.c
 create mode 100644 drivers/clk/clk-kinetis.c
 create mode 100644 drivers/clocksource/timer-kinetis.c
 create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c
 create mode 100644 include/dt-bindings/clock/kinetis-mcg.h

-- 
2.3.6


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

* [PATCH 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit
@ 2015-06-23 21:19 ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This patchset adds a very basic initial support for TWR-K70F120M
development kit which is based on ARM Cortex-M4 Freescale Kinetis K70 SoC.

I've found this a very lovely piece of equipment which allowed me to
explore mysterious world of noMMU Linux. Therefore I think it deserves
proper support from upstream Linux kernel side.

I based my work on K70 Sub-Family Reference Manual Rev. 3,
K70P256M150SF3RM.pdf and commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

The BSP published by Emcraft is based on Linux 2.6.33, does not use
OF Device Tree and implements its own NVIC, clock source, IOMUX and DMA
controller support routines. I wrote clear remarks whenever I'd used parts
of the code from their repository.

I decided to make use of recent additions to linux-next whenever it was
suitable, i.e.:

o all devices are configured in .dts files
o for NVIC I used in-tree driver
o for systick I used recently added arm,armv7m-systick driver
o for clock sources I implemented drivers that in shape are similar
      to efm32gg drivers (another ARM Cortex-M4 based platform - already
      supported by upstream kernel so I could use it as a reference on how
      things should possibly be done)
o for IOMUX I implemented very simplified pinctrl OF-friendly driver
  (which is sufficient for now, at least to configure UART pins)
o for DMA I extended existing Freescale eDMA driver
o for UART I also extended existing Freescale lpuart driver

You may find the first three patches a bit controversial. They intrude into
sensitive parts of ARM support in kernel tree. You may not like it, but
that's how it started to work for me. I tried to minimize the impact as
much as I could, however any better proposals are more than welcome.

Note that U-boot on my TWR-K70F120M is a bit modest and does not support
DTBs. Therefore the only option for having bootable uImage is zImage with
DTB attached at the end. In short it can be done like this:

make uImage                  (this creates normal uImage along with zImage)
make kinetis-twr-k70f120m.dtb
cat arch/arm/boot/zImage arch/arm/boot/dts/kinetis-twr-k70f120m.dtb >Image
mkimage -A arm -O linux -C none -T kernel -a 0x08008000 -e 0x08008001 \
        -n 'Linux-next-with-dtb' -d Image uImage

I'm booting this image over local network using TFTP. The userspace resides
in initramfs and consists of busybox and a few very basic command line
tools.

This initial support is just a beginning. My TWR-K70F120M is equipped with
many interesting features to which many drivers can be written.

During my work I was using Segger J-Link PRO JTAG which works nicely with
this development board - I can't imagine myself doing all this stuff
without it.

Paul Osmialowski (9):
  arm: select different compiler flags for ARM CortexM3
  arm: do not place huge encoder tables on stack when it is too small
  arm: add call to CPU idle quirks handler
  arm: allow copying of vector table to internal SRAM memory
  arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  arm: twr-k70f120m: clock source drivers for Kinetis SoC
  arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  arm: twr-k70f120m: extend Freescale eDMA driver with ability to
    support Kinetis SoC
  arm: twr-k70f120m: extend Freescale lpuart driver with ability to
    support Kinetis SoC

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +
 .../devicetree/bindings/clock/kinetis-clock.txt    |  25 +
 Documentation/devicetree/bindings/dma/fsl-edma.txt |  38 +-
 .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++
 .../devicetree/bindings/serial/fsl-lpuart.txt      |   6 +-
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  18 +
 arch/arm/Kconfig                                   |  29 +-
 arch/arm/Kconfig-nommu                             |  16 +
 arch/arm/Makefile                                  |   2 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |  43 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 215 +++++++++
 arch/arm/kernel/entry-v7m.S                        |   3 +
 arch/arm/kernel/process.c                          |   7 +
 arch/arm/mach-kinetis/Kconfig                      |  15 +
 arch/arm/mach-kinetis/Makefile                     |   5 +
 arch/arm/mach-kinetis/Makefile.boot                |   3 +
 arch/arm/mach-kinetis/include/mach/idle.h          |  33 ++
 arch/arm/mach-kinetis/include/mach/kinetis.h       | 170 +++++++
 arch/arm/mach-kinetis/include/mach/memory.h        |  61 +++
 arch/arm/mach-kinetis/include/mach/power.h         |  83 ++++
 arch/arm/mach-kinetis/kinetis_platform.c           |  61 +++
 arch/arm/mm/Kconfig                                |  12 +-
 arch/arm/mm/proc-v7m.S                             |  11 +
 arch/arm/tools/mach-types                          |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 297 ++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 294 ++++++++++++
 drivers/dma/fsl-edma.c                             |  81 +++-
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
 drivers/tty/serial/fsl_lpuart.c                    |  90 +++-
 include/dt-bindings/clock/kinetis-mcg.h            |  25 +
 lib/zlib_inflate/inflate.c                         |   5 +
 36 files changed, 2210 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 arch/arm/boot/dts/kinetis-twr-k70f120m.dts
 create mode 100644 arch/arm/boot/dts/kinetis.dtsi
 create mode 100644 arch/arm/mach-kinetis/Kconfig
 create mode 100644 arch/arm/mach-kinetis/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/include/mach/idle.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/kinetis.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/power.h
 create mode 100644 arch/arm/mach-kinetis/kinetis_platform.c
 create mode 100644 drivers/clk/clk-kinetis.c
 create mode 100644 drivers/clocksource/timer-kinetis.c
 create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c
 create mode 100644 include/dt-bindings/clock/kinetis-mcg.h

-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired by two commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
 RT #62654. Fixed kernel crashes while running httpd by enabling
 "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
 generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
 Cortex-M3 Errata it may result in incorrect base register when interrupted
 or faulted.

by: Yuri Tikhonov <yur@emcraft.com>

2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
 RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
 sure only the correct instructions will be generated.

by: Sergei Poselenov <sposelenov@emcraft.com>

I reworked these patches to make them less intrusive.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig    |  2 +-
 arch/arm/Makefile   |  1 +
 arch/arm/mm/Kconfig | 11 ++++++++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a750c14..8e3a833 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -32,7 +32,7 @@ config ARM
 	select HANDLE_DOMAIN_IRQ
 	select HARDIRQS_SW_RESEND
 	select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
-	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7M3 || CPU_32v7) && !CPU_32v6
 	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
 	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
 	select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 07ab3d2..a7e1007 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -58,6 +58,7 @@ endif
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M3)	=-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-m3 -Wa,-mcpu=cortex-m3
 arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
 arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c6b976..d19cb4d 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -401,12 +401,18 @@ config CPU_V7
 # ARMv7M
 config CPU_V7M
 	bool
-	select CPU_32v7M
+	select CPU_32v7M if !CPU_CORTEXM3
+	select CPU_32v7M3 if CPU_CORTEXM3
 	select CPU_ABRT_NOMMU
 	select CPU_CACHE_NOP
 	select CPU_PABRT_LEGACY
 	select CPU_THUMBONLY
 
+# ARM CortexM3
+config CPU_CORTEXM3
+	bool
+	select CPU_V7M
+
 config CPU_THUMBONLY
 	bool
 	# There are no CPUs available with MMU that don't implement an ARM ISA:
@@ -457,6 +463,9 @@ config CPU_32v7
 config CPU_32v7M
 	bool
 
+config CPU_32v7M3
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
-- 
2.3.6


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

* [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired by two commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
 RT #62654. Fixed kernel crashes while running httpd by enabling
 "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
 generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
 Cortex-M3 Errata it may result in incorrect base register when interrupted
 or faulted.

by: Yuri Tikhonov <yur@emcraft.com>

2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
 RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
 sure only the correct instructions will be generated.

by: Sergei Poselenov <sposelenov@emcraft.com>

I reworked these patches to make them less intrusive.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig    |  2 +-
 arch/arm/Makefile   |  1 +
 arch/arm/mm/Kconfig | 11 ++++++++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a750c14..8e3a833 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -32,7 +32,7 @@ config ARM
 	select HANDLE_DOMAIN_IRQ
 	select HARDIRQS_SW_RESEND
 	select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
-	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7M3 || CPU_32v7) && !CPU_32v6
 	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
 	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
 	select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 07ab3d2..a7e1007 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -58,6 +58,7 @@ endif
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M3)	=-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-m3 -Wa,-mcpu=cortex-m3
 arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
 arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c6b976..d19cb4d 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -401,12 +401,18 @@ config CPU_V7
 # ARMv7M
 config CPU_V7M
 	bool
-	select CPU_32v7M
+	select CPU_32v7M if !CPU_CORTEXM3
+	select CPU_32v7M3 if CPU_CORTEXM3
 	select CPU_ABRT_NOMMU
 	select CPU_CACHE_NOP
 	select CPU_PABRT_LEGACY
 	select CPU_THUMBONLY
 
+# ARM CortexM3
+config CPU_CORTEXM3
+	bool
+	select CPU_V7M
+
 config CPU_THUMBONLY
 	bool
 	# There are no CPUs available with MMU that don't implement an ARM ISA:
@@ -457,6 +463,9 @@ config CPU_32v7
 config CPU_32v7M
 	bool
 
+config CPU_32v7M3
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
-- 
2.3.6


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

* [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired by two commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
 RT #62654. Fixed kernel crashes while running httpd by enabling
 "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
 generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
 Cortex-M3 Errata it may result in incorrect base register when interrupted
 or faulted.

by: Yuri Tikhonov <yur-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
 RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
 sure only the correct instructions will be generated.

by: Sergei Poselenov <sposelenov-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

I reworked these patches to make them less intrusive.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 arch/arm/Kconfig    |  2 +-
 arch/arm/Makefile   |  1 +
 arch/arm/mm/Kconfig | 11 ++++++++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a750c14..8e3a833 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -32,7 +32,7 @@ config ARM
 	select HANDLE_DOMAIN_IRQ
 	select HARDIRQS_SW_RESEND
 	select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
-	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7M3 || CPU_32v7) && !CPU_32v6
 	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
 	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
 	select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 07ab3d2..a7e1007 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -58,6 +58,7 @@ endif
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M3)	=-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-m3 -Wa,-mcpu=cortex-m3
 arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
 arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c6b976..d19cb4d 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -401,12 +401,18 @@ config CPU_V7
 # ARMv7M
 config CPU_V7M
 	bool
-	select CPU_32v7M
+	select CPU_32v7M if !CPU_CORTEXM3
+	select CPU_32v7M3 if CPU_CORTEXM3
 	select CPU_ABRT_NOMMU
 	select CPU_CACHE_NOP
 	select CPU_PABRT_LEGACY
 	select CPU_THUMBONLY
 
+# ARM CortexM3
+config CPU_CORTEXM3
+	bool
+	select CPU_V7M
+
 config CPU_THUMBONLY
 	bool
 	# There are no CPUs available with MMU that don't implement an ARM ISA:
@@ -457,6 +463,9 @@ config CPU_32v7
 config CPU_32v7M
 	bool
 
+config CPU_32v7M3
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Since stack on Cortex-M3 is too small, we need configuration option
to avoid using it for huge encoder tables of zlib.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig-nommu     | 4 ++++
 lib/zlib_inflate/inflate.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index aed66d5..965ca97 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,7 @@ config ARM_MPU
 
          If your CPU has an MPU then you should choose 'y' here unless you
          know that you do not want to use the MPU.
+
+config ZLIB_INFLATE_STACK_SAVING
+	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
+	depends on ZLIB_INFLATE
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 58a733b..917b7cf 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -75,9 +75,14 @@ int zlib_inflateInit2(z_streamp strm, int windowBits)
    Return state with length and distance decoding tables and index sizes set to
    fixed code decoding.  This returns fixed tables from inffixed.h.
  */
+#ifdef CONFIG_ZLIB_INFLATE_STACK_SAVING
+#   include "inffixed.h"
+#endif
 static void zlib_fixedtables(struct inflate_state *state)
 {
+#ifndef CONFIG_ZLIB_INFLATE_STACK_SAVING
 #   include "inffixed.h"
+#endif
     state->lencode = lenfix;
     state->lenbits = 9;
     state->distcode = distfix;
-- 
2.3.6


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

* [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Since stack on Cortex-M3 is too small, we need configuration option
to avoid using it for huge encoder tables of zlib.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig-nommu     | 4 ++++
 lib/zlib_inflate/inflate.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index aed66d5..965ca97 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,7 @@ config ARM_MPU
 
          If your CPU has an MPU then you should choose 'y' here unless you
          know that you do not want to use the MPU.
+
+config ZLIB_INFLATE_STACK_SAVING
+	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
+	depends on ZLIB_INFLATE
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 58a733b..917b7cf 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -75,9 +75,14 @@ int zlib_inflateInit2(z_streamp strm, int windowBits)
    Return state with length and distance decoding tables and index sizes set to
    fixed code decoding.  This returns fixed tables from inffixed.h.
  */
+#ifdef CONFIG_ZLIB_INFLATE_STACK_SAVING
+#   include "inffixed.h"
+#endif
 static void zlib_fixedtables(struct inflate_state *state)
 {
+#ifndef CONFIG_ZLIB_INFLATE_STACK_SAVING
 #   include "inffixed.h"
+#endif
     state->lencode = lenfix;
     state->lenbits = 9;
     state->distcode = distfix;
-- 
2.3.6


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

* [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
  2015-06-23 21:19   ` [PATCH 1/9] arm: select different compiler flags for ARM CortexM3 Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 3/9] arm: add call to CPU idle quirks handler Paul Osmialowski
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Since stack on Cortex-M3 is too small, we need configuration option
to avoid using it for huge encoder tables of zlib.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 arch/arm/Kconfig-nommu     | 4 ++++
 lib/zlib_inflate/inflate.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index aed66d5..965ca97 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,7 @@ config ARM_MPU
 
          If your CPU has an MPU then you should choose 'y' here unless you
          know that you do not want to use the MPU.
+
+config ZLIB_INFLATE_STACK_SAVING
+	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
+	depends on ZLIB_INFLATE
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 58a733b..917b7cf 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -75,9 +75,14 @@ int zlib_inflateInit2(z_streamp strm, int windowBits)
    Return state with length and distance decoding tables and index sizes set to
    fixed code decoding.  This returns fixed tables from inffixed.h.
  */
+#ifdef CONFIG_ZLIB_INFLATE_STACK_SAVING
+#   include "inffixed.h"
+#endif
 static void zlib_fixedtables(struct inflate_state *state)
 {
+#ifndef CONFIG_ZLIB_INFLATE_STACK_SAVING
 #   include "inffixed.h"
+#endif
     state->lencode = lenfix;
     state->lenbits = 9;
     state->distcode = distfix;
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (2 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Some SoCs need additional actions to be performed after arch idle,
e.g. Kinetis requires invalidation of the I/D bus cache.

Such handler could be held in provided <mach/idle.h> header file.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig          | 7 +++++++
 arch/arm/kernel/process.c | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8e3a833..8ef8f8f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
 config NEED_SG_DMA_LENGTH
 	bool
 
+config NEED_MACH_IDLE_H
+	bool
+
+config ARM_CPU_IDLE_QUIRKS
+	bool
+	select NEED_MACH_IDLE_H
+
 config ARM_DMA_USE_IOMMU
 	bool
 	select ARM_HAS_SG_CHAIN
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f192a2a..0033460 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -37,6 +37,10 @@
 #include <asm/tls.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_NEED_MACH_IDLE_H
+#include <mach/idle.h>
+#endif
+
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
@@ -70,6 +74,9 @@ void arch_cpu_idle(void)
 		arm_pm_idle();
 	else
 		cpu_do_idle();
+#ifdef CONFIG_ARM_CPU_IDLE_QUIRKS
+	handle_cpu_idle_quirks();
+#endif
 	local_irq_enable();
 }
 
-- 
2.3.6


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

* [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (3 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  2015-06-23 21:51     ` Russell King - ARM Linux
  2015-06-23 21:59     ` Arnd Bergmann
  -1 siblings, 2 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Some SoCs need additional actions to be performed after arch idle,
e.g. Kinetis requires invalidation of the I/D bus cache.

Such handler could be held in provided <mach/idle.h> header file.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig          | 7 +++++++
 arch/arm/kernel/process.c | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8e3a833..8ef8f8f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
 config NEED_SG_DMA_LENGTH
 	bool
 
+config NEED_MACH_IDLE_H
+	bool
+
+config ARM_CPU_IDLE_QUIRKS
+	bool
+	select NEED_MACH_IDLE_H
+
 config ARM_DMA_USE_IOMMU
 	bool
 	select ARM_HAS_SG_CHAIN
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f192a2a..0033460 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -37,6 +37,10 @@
 #include <asm/tls.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_NEED_MACH_IDLE_H
+#include <mach/idle.h>
+#endif
+
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
@@ -70,6 +74,9 @@ void arch_cpu_idle(void)
 		arm_pm_idle();
 	else
 		cpu_do_idle();
+#ifdef CONFIG_ARM_CPU_IDLE_QUIRKS
+	handle_cpu_idle_quirks();
+#endif
 	local_irq_enable();
 }
 
-- 
2.3.6


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

* [PATCH 3/9] arm: add call to CPU idle quirks handler
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
  2015-06-23 21:19   ` [PATCH 1/9] arm: select different compiler flags for ARM CortexM3 Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory Paul Osmialowski
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Some SoCs need additional actions to be performed after arch idle,
e.g. Kinetis requires invalidation of the I/D bus cache.

Such handler could be held in provided <mach/idle.h> header file.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 arch/arm/Kconfig          | 7 +++++++
 arch/arm/kernel/process.c | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8e3a833..8ef8f8f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
 config NEED_SG_DMA_LENGTH
 	bool
 
+config NEED_MACH_IDLE_H
+	bool
+
+config ARM_CPU_IDLE_QUIRKS
+	bool
+	select NEED_MACH_IDLE_H
+
 config ARM_DMA_USE_IOMMU
 	bool
 	select ARM_HAS_SG_CHAIN
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f192a2a..0033460 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -37,6 +37,10 @@
 #include <asm/tls.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_NEED_MACH_IDLE_H
+#include <mach/idle.h>
+#endif
+
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
@@ -70,6 +74,9 @@ void arch_cpu_idle(void)
 		arm_pm_idle();
 	else
 		cpu_do_idle();
+#ifdef CONFIG_ARM_CPU_IDLE_QUIRKS
+	handle_cpu_idle_quirks();
+#endif
 	local_irq_enable();
 }
 
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on part of the commit published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

2ce1841b590d014d8738215fb1ffe05f53c8d9f0 "some commit"

by: Dmitry Cherkassov <d_cherkasov@emcraft.com>

The ARM v7M allows setting the vector table either in
the boot memory or in the internal SRAM memory, controlled
by Bit 29 in the Vector Table Base register. This implies
that the OS vector table needs to be copied to the internal RAM.

New option CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR allows specification
of the desired destination for the OS vector table.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig-nommu      | 11 +++++++++++
 arch/arm/kernel/entry-v7m.S |  3 +++
 arch/arm/mm/proc-v7m.S      | 11 +++++++++++
 3 files changed, 25 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 965ca97..98220e8 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -66,3 +66,14 @@ config ARM_MPU
 config ZLIB_INFLATE_STACK_SAVING
 	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
 	depends on ZLIB_INFLATE
+
+config COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x00000000
+	depends on CPU_V7M
+	help
+	  The ARM v7M allows setting the vector table either in
+	  the boot memory or in the internal SRAM memory, controlled
+	  by Bit 29 in the Vector Table Base register.
+	  This implies that the OS vector table needs to be copied to
+	  the internal RAM.
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index b6c8bb9..114096e 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -146,3 +146,6 @@ ENTRY(vector_table)
 	.rept	CONFIG_CPU_V7M_NUM_IRQ
 	.long	__irq_entry		@ External Interrupts
 	.endr
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+ENTRY(vector_table_end)
+#endif
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index 67d9209..ded9504 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -83,7 +83,18 @@ ENDPROC(cpu_v7m_do_resume)
 __v7m_setup:
 	@ Configure the vector table base address
 	ldr	r0, =BASEADDR_V7M_SCB
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+	ldr	r12, =CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	mov	r5, r12			@ Copy the kernel vector_table to
+	ldr	r6, =vector_table	@ the in-SRAM vector table
+	ldr	r4, =vector_table_end
+1:	ldr	r3, [r6], #4
+	str	r3, [r5], #4
+	cmp	r6, r4
+	bne	1b			@ End of the copy code
+#else
 	ldr	r12, =vector_table
+#endif
 	str	r12, [r0, V7M_SCB_VTOR]
 
 	@ enable UsageFault, BusFault and MemManage fault.
-- 
2.3.6


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

* [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on part of the commit published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

2ce1841b590d014d8738215fb1ffe05f53c8d9f0 "some commit"

by: Dmitry Cherkassov <d_cherkasov@emcraft.com>

The ARM v7M allows setting the vector table either in
the boot memory or in the internal SRAM memory, controlled
by Bit 29 in the Vector Table Base register. This implies
that the OS vector table needs to be copied to the internal RAM.

New option CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR allows specification
of the desired destination for the OS vector table.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig-nommu      | 11 +++++++++++
 arch/arm/kernel/entry-v7m.S |  3 +++
 arch/arm/mm/proc-v7m.S      | 11 +++++++++++
 3 files changed, 25 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 965ca97..98220e8 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -66,3 +66,14 @@ config ARM_MPU
 config ZLIB_INFLATE_STACK_SAVING
 	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
 	depends on ZLIB_INFLATE
+
+config COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x00000000
+	depends on CPU_V7M
+	help
+	  The ARM v7M allows setting the vector table either in
+	  the boot memory or in the internal SRAM memory, controlled
+	  by Bit 29 in the Vector Table Base register.
+	  This implies that the OS vector table needs to be copied to
+	  the internal RAM.
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index b6c8bb9..114096e 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -146,3 +146,6 @@ ENTRY(vector_table)
 	.rept	CONFIG_CPU_V7M_NUM_IRQ
 	.long	__irq_entry		@ External Interrupts
 	.endr
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+ENTRY(vector_table_end)
+#endif
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index 67d9209..ded9504 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -83,7 +83,18 @@ ENDPROC(cpu_v7m_do_resume)
 __v7m_setup:
 	@ Configure the vector table base address
 	ldr	r0, =BASEADDR_V7M_SCB
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+	ldr	r12, =CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	mov	r5, r12			@ Copy the kernel vector_table to
+	ldr	r6, =vector_table	@ the in-SRAM vector table
+	ldr	r4, =vector_table_end
+1:	ldr	r3, [r6], #4
+	str	r3, [r5], #4
+	cmp	r6, r4
+	bne	1b			@ End of the copy code
+#else
 	ldr	r12, =vector_table
+#endif
 	str	r12, [r0, V7M_SCB_VTOR]
 
 	@ enable UsageFault, BusFault and MemManage fault.
-- 
2.3.6


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

* [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
                     ` (2 preceding siblings ...)
  2015-06-23 21:19   ` [PATCH 3/9] arm: add call to CPU idle quirks handler Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 7/9] arm: twr-k70f120m: IOMUX driver " Paul Osmialowski
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on part of the commit published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

2ce1841b590d014d8738215fb1ffe05f53c8d9f0 "some commit"

by: Dmitry Cherkassov <d_cherkasov-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

The ARM v7M allows setting the vector table either in
the boot memory or in the internal SRAM memory, controlled
by Bit 29 in the Vector Table Base register. This implies
that the OS vector table needs to be copied to the internal RAM.

New option CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR allows specification
of the desired destination for the OS vector table.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 arch/arm/Kconfig-nommu      | 11 +++++++++++
 arch/arm/kernel/entry-v7m.S |  3 +++
 arch/arm/mm/proc-v7m.S      | 11 +++++++++++
 3 files changed, 25 insertions(+)

diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 965ca97..98220e8 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -66,3 +66,14 @@ config ARM_MPU
 config ZLIB_INFLATE_STACK_SAVING
 	bool 'Do not place huge encoder tables on stack' if ZLIB_INFLATE
 	depends on ZLIB_INFLATE
+
+config COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x00000000
+	depends on CPU_V7M
+	help
+	  The ARM v7M allows setting the vector table either in
+	  the boot memory or in the internal SRAM memory, controlled
+	  by Bit 29 in the Vector Table Base register.
+	  This implies that the OS vector table needs to be copied to
+	  the internal RAM.
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index b6c8bb9..114096e 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -146,3 +146,6 @@ ENTRY(vector_table)
 	.rept	CONFIG_CPU_V7M_NUM_IRQ
 	.long	__irq_entry		@ External Interrupts
 	.endr
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+ENTRY(vector_table_end)
+#endif
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index 67d9209..ded9504 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -83,7 +83,18 @@ ENDPROC(cpu_v7m_do_resume)
 __v7m_setup:
 	@ Configure the vector table base address
 	ldr	r0, =BASEADDR_V7M_SCB
+#if CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR > 0x00000000
+	ldr	r12, =CONFIG_COPY_VECTOR_TABLE_TO_SRAM_ADDR
+	mov	r5, r12			@ Copy the kernel vector_table to
+	ldr	r6, =vector_table	@ the in-SRAM vector table
+	ldr	r4, =vector_table_end
+1:	ldr	r3, [r6], #4
+	str	r3, [r5], #4
+	cmp	r6, r4
+	bne	1b			@ End of the copy code
+#else
 	ldr	r12, =vector_table
+#endif
 	str	r12, [r0, V7M_SCB_VTOR]
 
 	@ enable UsageFault, BusFault and MemManage fault.
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (6 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired a serie by commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

Entry commit: f014da1df860ad702d923c95cb97e068bd302cb0
 RT75957. twr-k70f120m: basic support

by: Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/arm/fsl.txt |   6 +
 arch/arm/Kconfig                              |  14 ++-
 arch/arm/Kconfig-nommu                        |   1 +
 arch/arm/Makefile                             |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts    |  16 +++
 arch/arm/boot/dts/kinetis.dtsi                |   5 +
 arch/arm/mach-kinetis/Kconfig                 |   9 ++
 arch/arm/mach-kinetis/Makefile                |   5 +
 arch/arm/mach-kinetis/Makefile.boot           |   3 +
 arch/arm/mach-kinetis/include/mach/idle.h     |  33 +++++
 arch/arm/mach-kinetis/include/mach/kinetis.h  | 170 ++++++++++++++++++++++++++
 arch/arm/mach-kinetis/kinetis_platform.c      |  61 +++++++++
 arch/arm/mm/Kconfig                           |   1 +
 arch/arm/tools/mach-types                     |   1 +
 14 files changed, 325 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/kinetis-twr-k70f120m.dts
 create mode 100644 arch/arm/boot/dts/kinetis.dtsi
 create mode 100644 arch/arm/mach-kinetis/Kconfig
 create mode 100644 arch/arm/mach-kinetis/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/include/mach/idle.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/kinetis.h
 create mode 100644 arch/arm/mach-kinetis/kinetis_platform.c

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 2a3ba73..36179fd 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -135,3 +135,9 @@ LS2085A ARMv8 based Simulator model
 Required root node properties:
     - compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
 
+Freescale Kinetis SoC Device Tree Bindings
+------------------------------------------
+
+TWR-K70F120M Kinetis K70 based development board.
+Required root node compatible properties:
+  - compatible = "fsl,kinetis-twr-k70f120m"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8ef8f8f..747cdea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -877,6 +877,8 @@ source "arch/arm/mach-ixp4xx/Kconfig"
 
 source "arch/arm/mach-keystone/Kconfig"
 
+source "arch/arm/mach-kinetis/Kconfig"
+
 source "arch/arm/mach-ks8695/Kconfig"
 
 source "arch/arm/mach-meson/Kconfig"
@@ -971,6 +973,16 @@ config ARCH_EFM32
 	  Support for Energy Micro's (now Silicon Labs) efm32 Giant Gecko
 	  processors.
 
+config ARCH_KINETIS
+	bool "Freescale Kinetis MCU"
+	depends on ARM_SINGLE_ARMV7M
+	select CPU_CORTEXM3
+	select ARM_CPU_IDLE_QUIRKS
+	select ARMV7M_SYSTICK
+	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
+	help
+	  This enables support for the Freescale Kinetis MCUs
+
 config ARCH_LPC18XX
 	bool "NXP LPC18xx/LPC43xx"
 	depends on ARM_SINGLE_ARMV7M
@@ -1740,7 +1752,7 @@ source "mm/Kconfig"
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
 	range 11 64 if ARCH_SHMOBILE_LEGACY
-	default "12" if SOC_AM33XX
+	default "12" if SOC_AM33XX || ARCH_KINETIS
 	default "9" if SA1111 || ARCH_EFM32
 	default "11"
 	help
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 98220e8..2b08e7a 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -69,6 +69,7 @@ config ZLIB_INFLATE_STACK_SAVING
 
 config COPY_VECTOR_TABLE_TO_SRAM_ADDR
 	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x20000000 if ARCH_KINETIS
 	default 0x00000000
 	depends on CPU_V7M
 	help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a7e1007..761db56 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -171,6 +171,7 @@ machine-$(CONFIG_ARCH_IOP32X)		+= iop32x
 machine-$(CONFIG_ARCH_IOP33X)		+= iop33x
 machine-$(CONFIG_ARCH_IXP4XX)		+= ixp4xx
 machine-$(CONFIG_ARCH_KEYSTONE)		+= keystone
+machine-$(CONFIG_ARCH_KINETIS)		+= kinetis
 machine-$(CONFIG_ARCH_KS8695)		+= ks8695
 machine-$(CONFIG_ARCH_LPC18XX)		+= lpc18xx
 machine-$(CONFIG_ARCH_LPC32XX)		+= lpc32xx
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
new file mode 100644
index 0000000..edccf37
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -0,0 +1,16 @@
+/*
+ * Device tree for TWR-K70F120M development board.
+ *
+ */
+
+/dts-v1/;
+#include "kinetis.dtsi"
+
+/ {
+	model = "Freescale TWR-K70F120M Development Kit";
+	compatible = "fsl,kinetis-twr-k70f120m";
+
+	memory {
+		reg = <0x8000000 0x8000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
new file mode 100644
index 0000000..93d2a8a
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -0,0 +1,5 @@
+/*
+ * Device tree for Freescale Kinetis SoC.
+ *
+ */
+#include "armv7-m.dtsi"
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
new file mode 100644
index 0000000..300bcea
--- /dev/null
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -0,0 +1,9 @@
+if ARCH_KINETIS
+
+config MACH_KINETIS
+	bool "Kinetis K70 based development board"
+	default y
+	help
+	  Say Y here if you are using Kinetis K70 based development board
+
+endif
diff --git a/arch/arm/mach-kinetis/Makefile b/arch/arm/mach-kinetis/Makefile
new file mode 100644
index 0000000..3746b3d
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Freescale Kinetis platform files
+#
+
+obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o
diff --git a/arch/arm/mach-kinetis/Makefile.boot b/arch/arm/mach-kinetis/Makefile.boot
new file mode 100644
index 0000000..3b442ab
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x08008000
+params_phys-y	:= 0x08000100
+initrd_phys-y	:= 0x08100000
diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
new file mode 100644
index 0000000..0aafefd
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/idle.h
@@ -0,0 +1,33 @@
+/*
+ * Based on original code by Vladimir Khusainov <vlad@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Vladimir Khusainov <vlad@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_IDLE_H
+#define _MACH_KINETIS_IDLE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/io.h>
+
+static inline void handle_cpu_idle_quirks(void)
+{
+	/*
+	 * This is a dirty hack that invalidates the I/D bus cache
+	 * on Kinetis K70. This must be done after arch idle.
+	 */
+	writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_IDLE_H */
diff --git a/arch/arm/mach-kinetis/include/mach/kinetis.h b/arch/arm/mach-kinetis/include/mach/kinetis.h
new file mode 100644
index 0000000..54d0a8b
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/kinetis.h
@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_KINETIS_H
+#define _MACH_KINETIS_KINETIS_H
+
+#include <asm/byteorder.h>
+
+/*
+ * This Kinetis port assumes that the CPU works in little-endian mode.
+ * Switching to big-endian will require different bit offsets in peripheral
+ * devices' registers. Also, some bit groups may lay on byte edges, so issue
+ * with big-endian cannot be fixed only by defining bit offsets differently
+ * for the big-endian mode.
+ */
+#ifndef __LITTLE_ENDIAN
+#error This Kinetis port assumes that the CPU works in little-endian mode
+#endif
+
+/*
+ * Peripheral memory map
+ */
+#define KINETIS_AIPS0PERIPH_BASE	0x40000000
+#define KINETIS_AIPS1PERIPH_BASE	0x40080000
+
+#ifndef __ASSEMBLY__
+
+#include <asm/types.h>
+
+/*
+ * Limits for the `kinetis_periph_enable()` function:
+ *     1. The number of SIM_SCGC[] registers
+ *     2. The number of bits in those registers
+ */
+#define KINETIS_SIM_CG_NUMREGS	7
+#define KINETIS_SIM_CG_NUMBITS	32
+
+/*
+ * System Integration Module (SIM) register map
+ *
+ * This map actually covers two hardware modules:
+ *     1. SIM low-power logic, at 0x40047000
+ *     2. System integration module (SIM), at 0x40048000
+ */
+struct kinetis_sim_regs {
+	u32 sopt1;	/* System Options Register 1 */
+	u32 rsv0[1024];
+	u32 sopt2;	/* System Options Register 2 */
+	u32 rsv1;
+	u32 sopt4;	/* System Options Register 4 */
+	u32 sopt5;	/* System Options Register 5 */
+	u32 sopt6;	/* System Options Register 6 */
+	u32 sopt7;	/* System Options Register 7 */
+	u32 rsv2[2];
+	u32 sdid;	/* System Device Identification Register */
+	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
+	u32 clkdiv1;	/* System Clock Divider Register 1 */
+	u32 clkdiv2;	/* System Clock Divider Register 2 */
+	u32 fcfg1;	/* Flash Configuration Register 1 */
+	u32 fcfg2;	/* Flash Configuration Register 2 */
+	u32 uidh;	/* Unique Identification Register High */
+	u32 uidmh;	/* Unique Identification Register Mid-High */
+	u32 uidml;	/* Unique Identification Register Mid Low */
+	u32 uidl;	/* Unique Identification Register Low */
+	u32 clkdiv3;	/* System Clock Divider Register 3 */
+	u32 clkdiv4;	/* System Clock Divider Register 4 */
+	u32 mcr;	/* Misc Control Register */
+};
+
+/*
+ * SIM registers base
+ */
+#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
+#define KINETIS_SIM_PTR(reg) \
+	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
+#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_SET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
+#define KINETIS_SIM_RESET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
+#define KINETIS_SIM_ISSET(reg, mask) \
+	(KINETIS_SIM_RD(reg) & (mask))
+
+/*
+ * SIM registers
+ */
+/*
+ * System Options Register 2
+ */
+/* USB HS clock source select */
+#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
+#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+
+/* USB FS clock source select */
+#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
+#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
+
+/*
+ * System Clock Divider Register 1
+ */
+/* Clock 1 output divider value (for the core/system clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_BITS	28
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV1_BITS)
+/* Clock 2 output divider value (for the peripheral clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_BITS	24
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV2_BITS)
+
+/*
+ * System Clock Divider Register 2
+ */
+/* USB HS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT	8
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT)
+/* USB HS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_BIT	9
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBHSDIV_BIT)
+
+/* USB FS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT	0
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT)
+/* USB FS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_BIT	1
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBFSDIV_BIT)
+
+/*
+ * System Clock Divider Register 3
+ */
+/* LCD Controller clock divider divisor */
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITS	16
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH	12
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCDIV_BITS)
+/* LCD Controller clock divider fraction */
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS)
+
+/*
+ * Misc Control Register
+ */
+/* 60 MHz ULPI clock (ULPI_CLK) output enable */
+#define KINETIS_SIM_MCR_ULPICLKOBE_MSK	(1 << 30)
+/* Start LCDC display */
+#define KINETIS_SIM_MCR_LCDSTART_MSK	(1 << 16)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _MACH_KINETIS_KINETIS_H */
diff --git a/arch/arm/mach-kinetis/kinetis_platform.c b/arch/arm/mach-kinetis/kinetis_platform.c
new file mode 100644
index 0000000..f1b6607
--- /dev/null
+++ b/arch/arm/mach-kinetis/kinetis_platform.c
@@ -0,0 +1,61 @@
+/*
+ * kinetis_platform.c - Freescale Kinetis K70F120M Development Board
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/v7m.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+/*
+ * Map required regions.
+ * This being the no-MMU Linux, I am not mapping anything
+ * since all I/O registers are available at their physical addresses.
+ */
+static void __init kinetis_map_io(void)
+{
+}
+
+/*
+ * Freescale Kinetis platform initialization
+ */
+static void __init kinetis_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *const kinetis_compat[] __initconst = {
+	"fsl,kinetis-twr-k70f120m",
+	NULL
+};
+
+/*
+ * Freescale Kinetis platform machine description
+ */
+DT_MACHINE_START(KINETIS, "Freescale Kinetis")
+	.dt_compat	= kinetis_compat,
+	.restart	= armv7m_restart,
+	/*
+	 * Physical address of the serial port used for the early
+	 * kernel debugging.
+	 * This address is actually never used in the MMU-less kernel
+	 * (since no mapping is needed to access this port),
+	 * but let's keep these fields filled out for consistency.
+	 */
+	.map_io		= kinetis_map_io,
+	.init_machine	= kinetis_init,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index d19cb4d..b611ac6 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -618,6 +618,7 @@ config CPU_V7M_NUM_IRQ
 	depends on CPU_V7M
 	default 90 if ARCH_STM32
 	default 38 if ARCH_EFM32
+	default 106 if ARCH_KINETIS
 	default 112 if SOC_VF610
 	default 240
 	help
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2ed1b8a..1d05516 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
 marzen			MACH_MARZEN		MARZEN			3790
 krome			MACH_KROME		KROME			3797
 armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
+kinetis			MACH_KINETIS		KINETIS			3896
 mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
 mt4			MACH_MT4		MT4			3981
 u8520			MACH_U8520		U8520			3990
-- 
2.3.6


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

* [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired a serie by commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

Entry commit: f014da1df860ad702d923c95cb97e068bd302cb0
 RT75957. twr-k70f120m: basic support

by: Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/arm/fsl.txt |   6 +
 arch/arm/Kconfig                              |  14 ++-
 arch/arm/Kconfig-nommu                        |   1 +
 arch/arm/Makefile                             |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts    |  16 +++
 arch/arm/boot/dts/kinetis.dtsi                |   5 +
 arch/arm/mach-kinetis/Kconfig                 |   9 ++
 arch/arm/mach-kinetis/Makefile                |   5 +
 arch/arm/mach-kinetis/Makefile.boot           |   3 +
 arch/arm/mach-kinetis/include/mach/idle.h     |  33 +++++
 arch/arm/mach-kinetis/include/mach/kinetis.h  | 170 ++++++++++++++++++++++++++
 arch/arm/mach-kinetis/kinetis_platform.c      |  61 +++++++++
 arch/arm/mm/Kconfig                           |   1 +
 arch/arm/tools/mach-types                     |   1 +
 14 files changed, 325 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/kinetis-twr-k70f120m.dts
 create mode 100644 arch/arm/boot/dts/kinetis.dtsi
 create mode 100644 arch/arm/mach-kinetis/Kconfig
 create mode 100644 arch/arm/mach-kinetis/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/include/mach/idle.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/kinetis.h
 create mode 100644 arch/arm/mach-kinetis/kinetis_platform.c

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 2a3ba73..36179fd 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -135,3 +135,9 @@ LS2085A ARMv8 based Simulator model
 Required root node properties:
     - compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
 
+Freescale Kinetis SoC Device Tree Bindings
+------------------------------------------
+
+TWR-K70F120M Kinetis K70 based development board.
+Required root node compatible properties:
+  - compatible = "fsl,kinetis-twr-k70f120m"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8ef8f8f..747cdea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -877,6 +877,8 @@ source "arch/arm/mach-ixp4xx/Kconfig"
 
 source "arch/arm/mach-keystone/Kconfig"
 
+source "arch/arm/mach-kinetis/Kconfig"
+
 source "arch/arm/mach-ks8695/Kconfig"
 
 source "arch/arm/mach-meson/Kconfig"
@@ -971,6 +973,16 @@ config ARCH_EFM32
 	  Support for Energy Micro's (now Silicon Labs) efm32 Giant Gecko
 	  processors.
 
+config ARCH_KINETIS
+	bool "Freescale Kinetis MCU"
+	depends on ARM_SINGLE_ARMV7M
+	select CPU_CORTEXM3
+	select ARM_CPU_IDLE_QUIRKS
+	select ARMV7M_SYSTICK
+	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
+	help
+	  This enables support for the Freescale Kinetis MCUs
+
 config ARCH_LPC18XX
 	bool "NXP LPC18xx/LPC43xx"
 	depends on ARM_SINGLE_ARMV7M
@@ -1740,7 +1752,7 @@ source "mm/Kconfig"
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
 	range 11 64 if ARCH_SHMOBILE_LEGACY
-	default "12" if SOC_AM33XX
+	default "12" if SOC_AM33XX || ARCH_KINETIS
 	default "9" if SA1111 || ARCH_EFM32
 	default "11"
 	help
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 98220e8..2b08e7a 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -69,6 +69,7 @@ config ZLIB_INFLATE_STACK_SAVING
 
 config COPY_VECTOR_TABLE_TO_SRAM_ADDR
 	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x20000000 if ARCH_KINETIS
 	default 0x00000000
 	depends on CPU_V7M
 	help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a7e1007..761db56 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -171,6 +171,7 @@ machine-$(CONFIG_ARCH_IOP32X)		+= iop32x
 machine-$(CONFIG_ARCH_IOP33X)		+= iop33x
 machine-$(CONFIG_ARCH_IXP4XX)		+= ixp4xx
 machine-$(CONFIG_ARCH_KEYSTONE)		+= keystone
+machine-$(CONFIG_ARCH_KINETIS)		+= kinetis
 machine-$(CONFIG_ARCH_KS8695)		+= ks8695
 machine-$(CONFIG_ARCH_LPC18XX)		+= lpc18xx
 machine-$(CONFIG_ARCH_LPC32XX)		+= lpc32xx
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
new file mode 100644
index 0000000..edccf37
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -0,0 +1,16 @@
+/*
+ * Device tree for TWR-K70F120M development board.
+ *
+ */
+
+/dts-v1/;
+#include "kinetis.dtsi"
+
+/ {
+	model = "Freescale TWR-K70F120M Development Kit";
+	compatible = "fsl,kinetis-twr-k70f120m";
+
+	memory {
+		reg = <0x8000000 0x8000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
new file mode 100644
index 0000000..93d2a8a
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -0,0 +1,5 @@
+/*
+ * Device tree for Freescale Kinetis SoC.
+ *
+ */
+#include "armv7-m.dtsi"
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
new file mode 100644
index 0000000..300bcea
--- /dev/null
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -0,0 +1,9 @@
+if ARCH_KINETIS
+
+config MACH_KINETIS
+	bool "Kinetis K70 based development board"
+	default y
+	help
+	  Say Y here if you are using Kinetis K70 based development board
+
+endif
diff --git a/arch/arm/mach-kinetis/Makefile b/arch/arm/mach-kinetis/Makefile
new file mode 100644
index 0000000..3746b3d
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Freescale Kinetis platform files
+#
+
+obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o
diff --git a/arch/arm/mach-kinetis/Makefile.boot b/arch/arm/mach-kinetis/Makefile.boot
new file mode 100644
index 0000000..3b442ab
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x08008000
+params_phys-y	:= 0x08000100
+initrd_phys-y	:= 0x08100000
diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
new file mode 100644
index 0000000..0aafefd
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/idle.h
@@ -0,0 +1,33 @@
+/*
+ * Based on original code by Vladimir Khusainov <vlad@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Vladimir Khusainov <vlad@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_IDLE_H
+#define _MACH_KINETIS_IDLE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/io.h>
+
+static inline void handle_cpu_idle_quirks(void)
+{
+	/*
+	 * This is a dirty hack that invalidates the I/D bus cache
+	 * on Kinetis K70. This must be done after arch idle.
+	 */
+	writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_IDLE_H */
diff --git a/arch/arm/mach-kinetis/include/mach/kinetis.h b/arch/arm/mach-kinetis/include/mach/kinetis.h
new file mode 100644
index 0000000..54d0a8b
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/kinetis.h
@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_KINETIS_H
+#define _MACH_KINETIS_KINETIS_H
+
+#include <asm/byteorder.h>
+
+/*
+ * This Kinetis port assumes that the CPU works in little-endian mode.
+ * Switching to big-endian will require different bit offsets in peripheral
+ * devices' registers. Also, some bit groups may lay on byte edges, so issue
+ * with big-endian cannot be fixed only by defining bit offsets differently
+ * for the big-endian mode.
+ */
+#ifndef __LITTLE_ENDIAN
+#error This Kinetis port assumes that the CPU works in little-endian mode
+#endif
+
+/*
+ * Peripheral memory map
+ */
+#define KINETIS_AIPS0PERIPH_BASE	0x40000000
+#define KINETIS_AIPS1PERIPH_BASE	0x40080000
+
+#ifndef __ASSEMBLY__
+
+#include <asm/types.h>
+
+/*
+ * Limits for the `kinetis_periph_enable()` function:
+ *     1. The number of SIM_SCGC[] registers
+ *     2. The number of bits in those registers
+ */
+#define KINETIS_SIM_CG_NUMREGS	7
+#define KINETIS_SIM_CG_NUMBITS	32
+
+/*
+ * System Integration Module (SIM) register map
+ *
+ * This map actually covers two hardware modules:
+ *     1. SIM low-power logic, at 0x40047000
+ *     2. System integration module (SIM), at 0x40048000
+ */
+struct kinetis_sim_regs {
+	u32 sopt1;	/* System Options Register 1 */
+	u32 rsv0[1024];
+	u32 sopt2;	/* System Options Register 2 */
+	u32 rsv1;
+	u32 sopt4;	/* System Options Register 4 */
+	u32 sopt5;	/* System Options Register 5 */
+	u32 sopt6;	/* System Options Register 6 */
+	u32 sopt7;	/* System Options Register 7 */
+	u32 rsv2[2];
+	u32 sdid;	/* System Device Identification Register */
+	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
+	u32 clkdiv1;	/* System Clock Divider Register 1 */
+	u32 clkdiv2;	/* System Clock Divider Register 2 */
+	u32 fcfg1;	/* Flash Configuration Register 1 */
+	u32 fcfg2;	/* Flash Configuration Register 2 */
+	u32 uidh;	/* Unique Identification Register High */
+	u32 uidmh;	/* Unique Identification Register Mid-High */
+	u32 uidml;	/* Unique Identification Register Mid Low */
+	u32 uidl;	/* Unique Identification Register Low */
+	u32 clkdiv3;	/* System Clock Divider Register 3 */
+	u32 clkdiv4;	/* System Clock Divider Register 4 */
+	u32 mcr;	/* Misc Control Register */
+};
+
+/*
+ * SIM registers base
+ */
+#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
+#define KINETIS_SIM_PTR(reg) \
+	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
+#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_SET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
+#define KINETIS_SIM_RESET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
+#define KINETIS_SIM_ISSET(reg, mask) \
+	(KINETIS_SIM_RD(reg) & (mask))
+
+/*
+ * SIM registers
+ */
+/*
+ * System Options Register 2
+ */
+/* USB HS clock source select */
+#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
+#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+
+/* USB FS clock source select */
+#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
+#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
+
+/*
+ * System Clock Divider Register 1
+ */
+/* Clock 1 output divider value (for the core/system clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_BITS	28
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV1_BITS)
+/* Clock 2 output divider value (for the peripheral clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_BITS	24
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV2_BITS)
+
+/*
+ * System Clock Divider Register 2
+ */
+/* USB HS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT	8
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT)
+/* USB HS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_BIT	9
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBHSDIV_BIT)
+
+/* USB FS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT	0
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT)
+/* USB FS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_BIT	1
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBFSDIV_BIT)
+
+/*
+ * System Clock Divider Register 3
+ */
+/* LCD Controller clock divider divisor */
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITS	16
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH	12
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCDIV_BITS)
+/* LCD Controller clock divider fraction */
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS)
+
+/*
+ * Misc Control Register
+ */
+/* 60 MHz ULPI clock (ULPI_CLK) output enable */
+#define KINETIS_SIM_MCR_ULPICLKOBE_MSK	(1 << 30)
+/* Start LCDC display */
+#define KINETIS_SIM_MCR_LCDSTART_MSK	(1 << 16)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _MACH_KINETIS_KINETIS_H */
diff --git a/arch/arm/mach-kinetis/kinetis_platform.c b/arch/arm/mach-kinetis/kinetis_platform.c
new file mode 100644
index 0000000..f1b6607
--- /dev/null
+++ b/arch/arm/mach-kinetis/kinetis_platform.c
@@ -0,0 +1,61 @@
+/*
+ * kinetis_platform.c - Freescale Kinetis K70F120M Development Board
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/v7m.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+/*
+ * Map required regions.
+ * This being the no-MMU Linux, I am not mapping anything
+ * since all I/O registers are available at their physical addresses.
+ */
+static void __init kinetis_map_io(void)
+{
+}
+
+/*
+ * Freescale Kinetis platform initialization
+ */
+static void __init kinetis_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *const kinetis_compat[] __initconst = {
+	"fsl,kinetis-twr-k70f120m",
+	NULL
+};
+
+/*
+ * Freescale Kinetis platform machine description
+ */
+DT_MACHINE_START(KINETIS, "Freescale Kinetis")
+	.dt_compat	= kinetis_compat,
+	.restart	= armv7m_restart,
+	/*
+	 * Physical address of the serial port used for the early
+	 * kernel debugging.
+	 * This address is actually never used in the MMU-less kernel
+	 * (since no mapping is needed to access this port),
+	 * but let's keep these fields filled out for consistency.
+	 */
+	.map_io		= kinetis_map_io,
+	.init_machine	= kinetis_init,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index d19cb4d..b611ac6 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -618,6 +618,7 @@ config CPU_V7M_NUM_IRQ
 	depends on CPU_V7M
 	default 90 if ARCH_STM32
 	default 38 if ARCH_EFM32
+	default 106 if ARCH_KINETIS
 	default 112 if SOC_VF610
 	default 240
 	help
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2ed1b8a..1d05516 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
 marzen			MACH_MARZEN		MARZEN			3790
 krome			MACH_KROME		KROME			3797
 armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
+kinetis			MACH_KINETIS		KINETIS			3896
 mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
 mt4			MACH_MT4		MT4			3981
 u8520			MACH_U8520		U8520			3990
-- 
2.3.6


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

* [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This one is inspired a serie by commits published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

Entry commit: f014da1df860ad702d923c95cb97e068bd302cb0
 RT75957. twr-k70f120m: basic support

by: Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 Documentation/devicetree/bindings/arm/fsl.txt |   6 +
 arch/arm/Kconfig                              |  14 ++-
 arch/arm/Kconfig-nommu                        |   1 +
 arch/arm/Makefile                             |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts    |  16 +++
 arch/arm/boot/dts/kinetis.dtsi                |   5 +
 arch/arm/mach-kinetis/Kconfig                 |   9 ++
 arch/arm/mach-kinetis/Makefile                |   5 +
 arch/arm/mach-kinetis/Makefile.boot           |   3 +
 arch/arm/mach-kinetis/include/mach/idle.h     |  33 +++++
 arch/arm/mach-kinetis/include/mach/kinetis.h  | 170 ++++++++++++++++++++++++++
 arch/arm/mach-kinetis/kinetis_platform.c      |  61 +++++++++
 arch/arm/mm/Kconfig                           |   1 +
 arch/arm/tools/mach-types                     |   1 +
 14 files changed, 325 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/kinetis-twr-k70f120m.dts
 create mode 100644 arch/arm/boot/dts/kinetis.dtsi
 create mode 100644 arch/arm/mach-kinetis/Kconfig
 create mode 100644 arch/arm/mach-kinetis/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/include/mach/idle.h
 create mode 100644 arch/arm/mach-kinetis/include/mach/kinetis.h
 create mode 100644 arch/arm/mach-kinetis/kinetis_platform.c

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 2a3ba73..36179fd 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -135,3 +135,9 @@ LS2085A ARMv8 based Simulator model
 Required root node properties:
     - compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
 
+Freescale Kinetis SoC Device Tree Bindings
+------------------------------------------
+
+TWR-K70F120M Kinetis K70 based development board.
+Required root node compatible properties:
+  - compatible = "fsl,kinetis-twr-k70f120m"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8ef8f8f..747cdea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -877,6 +877,8 @@ source "arch/arm/mach-ixp4xx/Kconfig"
 
 source "arch/arm/mach-keystone/Kconfig"
 
+source "arch/arm/mach-kinetis/Kconfig"
+
 source "arch/arm/mach-ks8695/Kconfig"
 
 source "arch/arm/mach-meson/Kconfig"
@@ -971,6 +973,16 @@ config ARCH_EFM32
 	  Support for Energy Micro's (now Silicon Labs) efm32 Giant Gecko
 	  processors.
 
+config ARCH_KINETIS
+	bool "Freescale Kinetis MCU"
+	depends on ARM_SINGLE_ARMV7M
+	select CPU_CORTEXM3
+	select ARM_CPU_IDLE_QUIRKS
+	select ARMV7M_SYSTICK
+	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
+	help
+	  This enables support for the Freescale Kinetis MCUs
+
 config ARCH_LPC18XX
 	bool "NXP LPC18xx/LPC43xx"
 	depends on ARM_SINGLE_ARMV7M
@@ -1740,7 +1752,7 @@ source "mm/Kconfig"
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
 	range 11 64 if ARCH_SHMOBILE_LEGACY
-	default "12" if SOC_AM33XX
+	default "12" if SOC_AM33XX || ARCH_KINETIS
 	default "9" if SA1111 || ARCH_EFM32
 	default "11"
 	help
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 98220e8..2b08e7a 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -69,6 +69,7 @@ config ZLIB_INFLATE_STACK_SAVING
 
 config COPY_VECTOR_TABLE_TO_SRAM_ADDR
 	hex 'If non-zero, copy Vector Table to this SRAM Address' if CPU_V7M
+	default 0x20000000 if ARCH_KINETIS
 	default 0x00000000
 	depends on CPU_V7M
 	help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a7e1007..761db56 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -171,6 +171,7 @@ machine-$(CONFIG_ARCH_IOP32X)		+= iop32x
 machine-$(CONFIG_ARCH_IOP33X)		+= iop33x
 machine-$(CONFIG_ARCH_IXP4XX)		+= ixp4xx
 machine-$(CONFIG_ARCH_KEYSTONE)		+= keystone
+machine-$(CONFIG_ARCH_KINETIS)		+= kinetis
 machine-$(CONFIG_ARCH_KS8695)		+= ks8695
 machine-$(CONFIG_ARCH_LPC18XX)		+= lpc18xx
 machine-$(CONFIG_ARCH_LPC32XX)		+= lpc32xx
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
new file mode 100644
index 0000000..edccf37
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -0,0 +1,16 @@
+/*
+ * Device tree for TWR-K70F120M development board.
+ *
+ */
+
+/dts-v1/;
+#include "kinetis.dtsi"
+
+/ {
+	model = "Freescale TWR-K70F120M Development Kit";
+	compatible = "fsl,kinetis-twr-k70f120m";
+
+	memory {
+		reg = <0x8000000 0x8000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
new file mode 100644
index 0000000..93d2a8a
--- /dev/null
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -0,0 +1,5 @@
+/*
+ * Device tree for Freescale Kinetis SoC.
+ *
+ */
+#include "armv7-m.dtsi"
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
new file mode 100644
index 0000000..300bcea
--- /dev/null
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -0,0 +1,9 @@
+if ARCH_KINETIS
+
+config MACH_KINETIS
+	bool "Kinetis K70 based development board"
+	default y
+	help
+	  Say Y here if you are using Kinetis K70 based development board
+
+endif
diff --git a/arch/arm/mach-kinetis/Makefile b/arch/arm/mach-kinetis/Makefile
new file mode 100644
index 0000000..3746b3d
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Freescale Kinetis platform files
+#
+
+obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o
diff --git a/arch/arm/mach-kinetis/Makefile.boot b/arch/arm/mach-kinetis/Makefile.boot
new file mode 100644
index 0000000..3b442ab
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0x08008000
+params_phys-y	:= 0x08000100
+initrd_phys-y	:= 0x08100000
diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
new file mode 100644
index 0000000..0aafefd
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/idle.h
@@ -0,0 +1,33 @@
+/*
+ * Based on original code by Vladimir Khusainov <vlad-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Vladimir Khusainov <vlad-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_IDLE_H
+#define _MACH_KINETIS_IDLE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/io.h>
+
+static inline void handle_cpu_idle_quirks(void)
+{
+	/*
+	 * This is a dirty hack that invalidates the I/D bus cache
+	 * on Kinetis K70. This must be done after arch idle.
+	 */
+	writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_IDLE_H */
diff --git a/arch/arm/mach-kinetis/include/mach/kinetis.h b/arch/arm/mach-kinetis/include/mach/kinetis.h
new file mode 100644
index 0000000..54d0a8b
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/kinetis.h
@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_KINETIS_H
+#define _MACH_KINETIS_KINETIS_H
+
+#include <asm/byteorder.h>
+
+/*
+ * This Kinetis port assumes that the CPU works in little-endian mode.
+ * Switching to big-endian will require different bit offsets in peripheral
+ * devices' registers. Also, some bit groups may lay on byte edges, so issue
+ * with big-endian cannot be fixed only by defining bit offsets differently
+ * for the big-endian mode.
+ */
+#ifndef __LITTLE_ENDIAN
+#error This Kinetis port assumes that the CPU works in little-endian mode
+#endif
+
+/*
+ * Peripheral memory map
+ */
+#define KINETIS_AIPS0PERIPH_BASE	0x40000000
+#define KINETIS_AIPS1PERIPH_BASE	0x40080000
+
+#ifndef __ASSEMBLY__
+
+#include <asm/types.h>
+
+/*
+ * Limits for the `kinetis_periph_enable()` function:
+ *     1. The number of SIM_SCGC[] registers
+ *     2. The number of bits in those registers
+ */
+#define KINETIS_SIM_CG_NUMREGS	7
+#define KINETIS_SIM_CG_NUMBITS	32
+
+/*
+ * System Integration Module (SIM) register map
+ *
+ * This map actually covers two hardware modules:
+ *     1. SIM low-power logic, at 0x40047000
+ *     2. System integration module (SIM), at 0x40048000
+ */
+struct kinetis_sim_regs {
+	u32 sopt1;	/* System Options Register 1 */
+	u32 rsv0[1024];
+	u32 sopt2;	/* System Options Register 2 */
+	u32 rsv1;
+	u32 sopt4;	/* System Options Register 4 */
+	u32 sopt5;	/* System Options Register 5 */
+	u32 sopt6;	/* System Options Register 6 */
+	u32 sopt7;	/* System Options Register 7 */
+	u32 rsv2[2];
+	u32 sdid;	/* System Device Identification Register */
+	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
+	u32 clkdiv1;	/* System Clock Divider Register 1 */
+	u32 clkdiv2;	/* System Clock Divider Register 2 */
+	u32 fcfg1;	/* Flash Configuration Register 1 */
+	u32 fcfg2;	/* Flash Configuration Register 2 */
+	u32 uidh;	/* Unique Identification Register High */
+	u32 uidmh;	/* Unique Identification Register Mid-High */
+	u32 uidml;	/* Unique Identification Register Mid Low */
+	u32 uidl;	/* Unique Identification Register Low */
+	u32 clkdiv3;	/* System Clock Divider Register 3 */
+	u32 clkdiv4;	/* System Clock Divider Register 4 */
+	u32 mcr;	/* Misc Control Register */
+};
+
+/*
+ * SIM registers base
+ */
+#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
+#define KINETIS_SIM_PTR(reg) \
+	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
+#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
+#define KINETIS_SIM_SET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
+#define KINETIS_SIM_RESET(reg, mask) \
+	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
+#define KINETIS_SIM_ISSET(reg, mask) \
+	(KINETIS_SIM_RD(reg) & (mask))
+
+/*
+ * SIM registers
+ */
+/*
+ * System Options Register 2
+ */
+/* USB HS clock source select */
+#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
+#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
+
+/* USB FS clock source select */
+#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
+#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
+#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
+
+/*
+ * System Clock Divider Register 1
+ */
+/* Clock 1 output divider value (for the core/system clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_BITS	28
+#define KINETIS_SIM_CLKDIV1_OUTDIV1_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV1_BITS)
+/* Clock 2 output divider value (for the peripheral clock) */
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_BITS	24
+#define KINETIS_SIM_CLKDIV1_OUTDIV2_MSK \
+	(((1 << 4) - 1) << KINETIS_SIM_CLKDIV1_OUTDIV2_BITS)
+
+/*
+ * System Clock Divider Register 2
+ */
+/* USB HS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT	8
+#define KINETIS_SIM_CLKDIV2_USBHSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBHSFRAC_BIT)
+/* USB HS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_BIT	9
+#define KINETIS_SIM_CLKDIV2_USBHSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBHSDIV_BIT)
+
+/* USB FS clock divider fraction */
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT	0
+#define KINETIS_SIM_CLKDIV2_USBFSFRAC_MSK \
+	(1 << KINETIS_SIM_CLKDIV2_USBFSFRAC_BIT)
+/* USB FS clock divider divisor */
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_BIT	1
+#define KINETIS_SIM_CLKDIV2_USBFSDIV_MSK \
+	(7 << KINETIS_SIM_CLKDIV2_USBFSDIV_BIT)
+
+/*
+ * System Clock Divider Register 3
+ */
+/* LCD Controller clock divider divisor */
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITS	16
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH	12
+#define KINETIS_SIM_CLKDIV3_LCDCDIV_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCDIV_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCDIV_BITS)
+/* LCD Controller clock divider fraction */
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH	8
+#define KINETIS_SIM_CLKDIV3_LCDCFRAC_MSK \
+	(((1 << KINETIS_SIM_CLKDIV3_LCDCFRAC_BITWIDTH) - 1) << \
+	KINETIS_SIM_CLKDIV3_LCDCFRAC_BITS)
+
+/*
+ * Misc Control Register
+ */
+/* 60 MHz ULPI clock (ULPI_CLK) output enable */
+#define KINETIS_SIM_MCR_ULPICLKOBE_MSK	(1 << 30)
+/* Start LCDC display */
+#define KINETIS_SIM_MCR_LCDSTART_MSK	(1 << 16)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _MACH_KINETIS_KINETIS_H */
diff --git a/arch/arm/mach-kinetis/kinetis_platform.c b/arch/arm/mach-kinetis/kinetis_platform.c
new file mode 100644
index 0000000..f1b6607
--- /dev/null
+++ b/arch/arm/mach-kinetis/kinetis_platform.c
@@ -0,0 +1,61 @@
+/*
+ * kinetis_platform.c - Freescale Kinetis K70F120M Development Board
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/v7m.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+/*
+ * Map required regions.
+ * This being the no-MMU Linux, I am not mapping anything
+ * since all I/O registers are available at their physical addresses.
+ */
+static void __init kinetis_map_io(void)
+{
+}
+
+/*
+ * Freescale Kinetis platform initialization
+ */
+static void __init kinetis_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *const kinetis_compat[] __initconst = {
+	"fsl,kinetis-twr-k70f120m",
+	NULL
+};
+
+/*
+ * Freescale Kinetis platform machine description
+ */
+DT_MACHINE_START(KINETIS, "Freescale Kinetis")
+	.dt_compat	= kinetis_compat,
+	.restart	= armv7m_restart,
+	/*
+	 * Physical address of the serial port used for the early
+	 * kernel debugging.
+	 * This address is actually never used in the MMU-less kernel
+	 * (since no mapping is needed to access this port),
+	 * but let's keep these fields filled out for consistency.
+	 */
+	.map_io		= kinetis_map_io,
+	.init_machine	= kinetis_init,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index d19cb4d..b611ac6 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -618,6 +618,7 @@ config CPU_V7M_NUM_IRQ
 	depends on CPU_V7M
 	default 90 if ARCH_STM32
 	default 38 if ARCH_EFM32
+	default 106 if ARCH_KINETIS
 	default 112 if SOC_VF610
 	default 240
 	help
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 2ed1b8a..1d05516 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
 marzen			MACH_MARZEN		MARZEN			3790
 krome			MACH_KROME		KROME			3797
 armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
+kinetis			MACH_KINETIS		KINETIS			3896
 mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
 mt4			MACH_MT4		MT4			3981
 u8520			MACH_U8520		U8520			3990
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on K70P256M150SF3RM.pdf

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  25 ++
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  18 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  50 ++++
 arch/arm/mach-kinetis/include/mach/power.h         |  83 ++++++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 226 ++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 294 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |  10 +
 12 files changed, 718 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 arch/arm/mach-kinetis/include/mach/power.h
 create mode 100644 drivers/clk/clk-kinetis.c
 create mode 100644 drivers/clocksource/timer-kinetis.c
 create mode 100644 include/dt-bindings/clock/kinetis-mcg.h

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..9c9c4fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,25 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Address and length of the register set.
+- #clock-cells: Should be <1>.
+
+Example:
+
+mcg: cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>;
+	#clock-cells = <1>;
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg CLOCK_UART1>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
new file mode 100644
index 0000000..49dddf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,18 @@
+Freescale Kinetis SoC Periodic Interrupt Timer (PIT)
+
+Required properties:
+
+- compatible: Should be "fsl,kinetis-pit-timer".
+- reg: Specifies base physical address and size of the register sets for the
+  clock event device.
+- interrupts: Should be the clock event device interrupt.
+- clocks: The clocks provided by the SoC to drive the timer.
+
+Example:
+
+pit0: timer@40037100 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037100 0x10>;
+	interrupts = <68>;
+	clocks = <&mcg CLOCK_PIT>;
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 747cdea..8630aff 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -979,6 +979,7 @@ config ARCH_KINETIS
 	select CPU_CORTEXM3
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index edccf37..a6efc29 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -14,3 +14,7 @@
 		reg = <0x8000000 0x8000000>;
 	};
 };
+
+&pit0 {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..770760f 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,53 @@
  *
  */
 #include "armv7-m.dtsi"
+#include "dt-bindings/clock/kinetis-mcg.h"
+
+/ {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
+	soc {
+		pit0: timer@40037100 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037100 0x10>;
+			interrupts = <68>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit1: timer@40037110 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037110 0x10>;
+			interrupts = <69>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit2: timer@40037120 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037120 0x10>;
+			interrupts = <70>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit3: timer@40037130 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037130 0x10>;
+			interrupts = <71>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		mcg: cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>;
+			#clock-cells = <1>;
+		};
+	};
+};
diff --git a/arch/arm/mach-kinetis/include/mach/power.h b/arch/arm/mach-kinetis/include/mach/power.h
new file mode 100644
index 0000000..e67bd4e
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/power.h
@@ -0,0 +1,83 @@
+/*
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_POWER_H
+#define _MACH_KINETIS_POWER_H
+
+/*
+ * Pack the SIM_SCGC[] register index and the bit index in that register into
+ * a single word. This is similar to the implementation of `dev_t` in
+ * the Linux kernel with its `MAJOR(dev)`, `MINOR(dev)` and
+ * `MKDEV(major,minor)` macros.
+ *
+ * This is useful when you want to have an array of `kinetis_clock_gate_t`s:
+ * you do not have to use a 2-dimensional array or a real structure.
+ */
+typedef u32 kinetis_clock_gate_t;
+#define KINETIS_CG_IDX_BITS	16
+#define KINETIS_CG_IDX_MASK	((1U << KINETIS_CG_IDX_BITS) - 1)
+/*
+ * Extract the register number and the bit index from a `kinetis_clock_gate_t`.
+ * The register number counts from 0,
+ * i.e. the register number for SIM_SCGC7 is 6.
+ */
+#define KINETIS_CG_REG(gate)	((unsigned int) ((gate) >> KINETIS_CG_IDX_BITS))
+#define KINETIS_CG_IDX(gate)	((unsigned int) ((gate) & KINETIS_CG_IDX_MASK))
+/*
+ * Build a `kinetis_clock_gate_t` from a register number and a bit index
+ */
+#define KINETIS_MKCG(reg, idx) \
+	(((kinetis_clock_gate_t)(reg) << KINETIS_CG_IDX_BITS) | \
+	(kinetis_clock_gate_t)(idx))
+
+/*
+ * Clock gates for the modules inside the MCU
+ */
+/* UARTs */
+#define KINETIS_CG_UART0	KINETIS_MKCG(3, 10)	/* SIM_SCGC4[10] */
+#define KINETIS_CG_UART1	KINETIS_MKCG(3, 11)	/* SIM_SCGC4[11] */
+#define KINETIS_CG_UART2	KINETIS_MKCG(3, 12)	/* SIM_SCGC4[12] */
+#define KINETIS_CG_UART3	KINETIS_MKCG(3, 13)	/* SIM_SCGC4[13] */
+#define KINETIS_CG_UART4	KINETIS_MKCG(0, 10)	/* SIM_SCGC1[10] */
+#define KINETIS_CG_UART5	KINETIS_MKCG(0, 11)	/* SIM_SCGC1[11] */
+/* Ports */
+#define KINETIS_CG_PORTA	KINETIS_MKCG(4, 9)	/* SIM_SCGC5[9] */
+#define KINETIS_CG_PORTB	KINETIS_MKCG(4, 10)	/* SIM_SCGC5[10] */
+#define KINETIS_CG_PORTC	KINETIS_MKCG(4, 11)	/* SIM_SCGC5[11] */
+#define KINETIS_CG_PORTD	KINETIS_MKCG(4, 12)	/* SIM_SCGC5[12] */
+#define KINETIS_CG_PORTE	KINETIS_MKCG(4, 13)	/* SIM_SCGC5[13] */
+#define KINETIS_CG_PORTF	KINETIS_MKCG(4, 14)	/* SIM_SCGC5[14] */
+/* ENET */
+#define KINETIS_CG_ENET		KINETIS_MKCG(1, 0)	/* SIM_SCGC2[0] */
+/* Periodic Interrupt Timer (PIT) */
+#define KINETIS_CG_PIT		KINETIS_MKCG(5, 23)	/* SIM_SCGC6[23] */
+/* LCD Controller */
+#define KINETIS_CG_LCDC		KINETIS_MKCG(2, 22)	/* SIM_SCGC3[22] */
+/* DMA controller and DMA request multiplexer */
+#define KINETIS_CG_DMA		KINETIS_MKCG(6, 1)	/* SIM_SCGC7[1] */
+#define KINETIS_CG_DMAMUX0	KINETIS_MKCG(5, 1)	/* SIM_SCGC6[1] */
+#define KINETIS_CG_DMAMUX1	KINETIS_MKCG(5, 2)	/* SIM_SCGC6[2] */
+/* USB High Speed */
+#define KINETIS_CG_USBHS	KINETIS_MKCG(5, 20)	/* SIM_SCGC6[20] */
+/* USB Full Speed */
+#define KINETIS_CG_USBFS	KINETIS_MKCG(3, 18)	/* SIM_SCGC4[18] */
+/* ADC modules */
+#define KINETIS_CG_ADC0		KINETIS_MKCG(5, 27)	/* SIM_SCGC6[27] */
+#define KINETIS_CG_ADC1		KINETIS_MKCG(2, 27)	/* SIM_SCGC3[27] */
+#define KINETIS_CG_ADC2		KINETIS_MKCG(5, 28)	/* SIM_SCGC6[28] */
+#define KINETIS_CG_ADC3		KINETIS_MKCG(2, 28)	/* SIM_SCGC3[28] */
+/* ESDHC */
+#define KINETIS_CG_ESDHC	KINETIS_MKCG(2, 17)	/* SIM_SCGC3[17] */
+/* SPI */
+#define KINETIS_CG_SPI0		KINETIS_MKCG(5, 12)	/* SIM_SCGC6[12] */
+#define KINETIS_CG_SPI1		KINETIS_MKCG(5, 13)	/* SIM_SCGC6[13] */
+#define KINETIS_CG_SPI2		KINETIS_MKCG(2, 12)	/* SIM_SCGC3[12] */
+
+#endif /*_MACH_KINETIS_POWER_H */
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b241c17..58718ed 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
+obj-$(CONFIG_ARCH_KINETIS)		+= clk-kinetis.o
 obj-$(CONFIG_MACH_LOONGSON32)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
new file mode 100644
index 0000000..dea1054
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,226 @@
+/*
+ * clk-kinetis.c - Clock driver for Kinetis K70 MCG
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/err.h>
+#include <mach/kinetis.h>
+#include <mach/power.h>
+
+#include <dt-bindings/clock/kinetis-mcg.h>
+
+/*
+ * Frequencies on OSC0 (EXTAL0/XTAL0) and OSC1 (EXTAL1/XTAL1)
+ *
+ * These frequencies should be set to the same values as in U-Boot.
+ */
+#define KINETIS_OSC0_RATE	50000000	/* 50 MHz */
+#define KINETIS_OSC1_RATE	12000000	/* 12 MHz */
+
+/*
+ * MCG Control 5 Register
+ */
+/* PLL External Reference Divider */
+#define KINETIS_MCG_C5_PRDIV_BITS	0
+#define KINETIS_MCG_C5_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C5_PRDIV_BITS)
+/* PLL Stop Enable */
+#define KINETIS_MCG_C5_PLLSTEN_MSK	(1 << 5)
+/* PLL Clock Enable */
+#define KINETIS_MCG_C5_PLLCLKEN_MSK	(1 << 6)
+/* PLL External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C5_PLLREFSEL_BIT	7
+#define KINETIS_MCG_C5_PLLREFSEL_MSK	(1 << KINETIS_MCG_C5_PLLREFSEL_BIT)
+/*
+ * MCG Control 6 Register
+ */
+/* VCO Divider */
+#define KINETIS_MCG_C6_VDIV_BITS	0
+#define KINETIS_MCG_C6_VDIV_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C6_VDIV_BITS)
+/* PLL Select */
+#define KINETIS_MCG_C6_PLLS_MSK		(1 << 6)
+/*
+ * MCG Control 11 Register
+ */
+/* PLL1 External Reference Divider */
+#define KINETIS_MCG_C11_PRDIV_BITS	0
+#define KINETIS_MCG_C11_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C11_PRDIV_BITS)
+/* PLL Clock Select: PLL0 or PLL1 */
+#define KINETIS_MCG_C11_PLLCS_MSK	(1 << 4)
+/* PLL1 Stop Enable */
+#define KINETIS_MCG_C11_PLLSTEN1_MSK	(1 << 5)
+/* PLL1 Clock Enable */
+#define KINETIS_MCG_C11_PLLCLKEN1_MSK	(1 << 6)
+/* PLL1 External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C11_PLLREFSEL1_BIT	7
+#define KINETIS_MCG_C11_PLLREFSEL1_MSK	(1 << KINETIS_MCG_C11_PLLREFSEL1_BIT)
+/*
+ * MCG Control 12 Register
+ */
+/* VCO1 Divider */
+#define KINETIS_MCG_C12_VDIV1_BITS	0
+#define KINETIS_MCG_C12_VDIV1_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C12_VDIV1_BITS)
+
+/*
+ * Multipurpose Clock Generator (MCG) register map
+ *
+ * See Chapter 25 of the K70 Reference Manual
+ */
+struct kinetis_mcg_regs {
+	u8 c1;		/* MCG Control 1 Register */
+	u8 c2;		/* MCG Control 2 Register */
+	u8 c3;		/* MCG Control 3 Register */
+	u8 c4;		/* MCG Control 4 Register */
+	u8 c5;		/* MCG Control 5 Register */
+	u8 c6;		/* MCG Control 6 Register */
+	u8 status;	/* MCG Status Register */
+	u8 rsv0;
+	u8 atc;		/* MCG Auto Trim Control Register */
+	u8 rsv1;
+	u8 atcvh;	/* MCG Auto Trim Compare Value High Register */
+	u8 atcvl;	/* MCG Auto Trim Compare Value Low Register */
+	u8 c7;		/* MCG Control 7 Register */
+	u8 c8;		/* MCG Control 8 Register */
+	u8 rsv2;
+	u8 c10;		/* MCG Control 10 Register */
+	u8 c11;		/* MCG Control 11 Register */
+	u8 c12;		/* MCG Control 12 Register */
+	u8 status2;	/* MCG Status 2 Register */
+	u8 rsv3;
+};
+
+#define KINETIS_MCG_PTR(base, reg) \
+	(&(((struct kinetis_mcg_regs *)(base))->reg))
+#define KINETIS_MCG_RD(base, reg) readb_relaxed(KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_WR(base, reg, val) \
+	writeb_relaxed((val), KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_ISSET(base, reg, mask) \
+	(KINETIS_MCG_RD(base, reg) & (mask))
+
+static struct clk *clk[CLOCK_END];
+static struct clk_onecell_data clk_data = {
+	.clks = clk,
+	.clk_num = ARRAY_SIZE(clk),
+};
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[CLOCK_END];
+	int i;
+	void __iomem *base;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+
+	for (i = 0; i < ARRAY_SIZE(clk); ++i)
+		clk[i] = ERR_PTR(-ENOENT);
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(KINETIS_MCG_ISSET(base, c11, KINETIS_MCG_C11_PLLCS_MSK));
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c11,
+				KINETIS_MCG_C11_PLLREFSEL1_MSK));
+	else
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c5,
+				KINETIS_MCG_C5_PLLREFSEL_MSK));
+
+	/*
+	 * Start with the MCG input clock
+	 */
+	mcgout = osc_sel ? KINETIS_OSC1_RATE : KINETIS_OSC0_RATE;
+
+	/*
+	 * Apply dividers and multipliers of the selected PLL
+	 */
+	if (pll_sel) {
+		/*
+		 * PLL1 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c11) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c12) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c5) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c6) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[CLOCK_MCGOUTCLK] = mcgout;
+
+	clock_val[CLOCK_CCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[CLOCK_PCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	clk[CLOCK_MCGOUTCLK] = clk_register_fixed_rate(NULL, "MCGOUTCLK",
+			NULL, CLK_IS_ROOT, clock_val[CLOCK_MCGOUTCLK]);
+
+	clk[CLOCK_CCLK] = clk_register_fixed_rate(NULL, "CCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_CCLK]);
+
+	clk[CLOCK_PCLK] = clk_register_fixed_rate(NULL, "PCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_PCLK]);
+
+	clk[CLOCK_PIT] = clk_register_gate(NULL, "PIT", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
+			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f1c77e..1d2ecde 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -106,6 +106,11 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_KINETIS
+	bool "Clocksource for Kinetis SoCs"
+	depends on OF && ARM && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f1ae0e7..6da77a8 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -36,6 +36,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_KINETIS)	+= timer-kinetis.o
 obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_LPC32XX)	+= time-lpc32xx.o
diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
new file mode 100644
index 0000000..634f365
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,294 @@
+/*
+ * timer-kinetis.c - Timer driver for Kinetis K70
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/io.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_device.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <mach/kinetis.h>
+
+#define KINETIS_PIT_CHANNELS 4
+
+#define KINETIS_PIT0_IRQ 68
+#define KINETIS_PIT1_IRQ 69
+#define KINETIS_PIT2_IRQ 70
+#define KINETIS_PIT3_IRQ 71
+
+/*
+ * PIT Timer Control Register
+ */
+/* Timer Interrupt Enable Bit */
+#define KINETIS_PIT_TCTRL_TIE_MSK	(1 << 1)
+/* Timer Enable Bit */
+#define KINETIS_PIT_TCTRL_TEN_MSK	(1 << 0)
+/*
+ * PIT Timer Flag Register
+ */
+/* Timer Interrupt Flag */
+#define KINETIS_PIT_TFLG_TIF_MSK	(1 << 0)
+
+/*
+ * PIT control registers base
+ */
+#define KINETIS_PIT_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00037000)
+#define KINETIS_PIT_MCR			IOMEM(KINETIS_PIT_BASE + 0x0)
+
+/*
+ * Periodic Interrupt Timer (PIT) registers
+ */
+struct kinetis_pit_channel_regs {
+	u32 ldval;	/* Timer Load Value Register */
+	u32 cval;	/* Current Timer Value Register */
+	u32 tctrl;	/* Timer Control Register */
+	u32 tflg;	/* Timer Flag Register */
+};
+
+#define KINETIS_PIT_PTR(base, reg) \
+	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
+#define KINETIS_PIT_RD(base, reg) readl(KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_WR(base, reg, val) \
+	writel((val), KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_SET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) | (mask))
+#define KINETIS_PIT_RESET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(void __iomem *base, int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(void __iomem *base, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	writel(0, KINETIS_PIT_MCR);
+
+	KINETIS_PIT_WR(base, tctrl, 0);
+	KINETIS_PIT_WR(base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(base, ldval, ticks);
+	KINETIS_PIT_WR(base, cval, 0);
+	KINETIS_PIT_WR(base, tctrl, KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+/*
+ * Clock event device set mode function
+ */
+static void kinetis_clockevent_tmr_set_mode(
+	enum clock_event_mode mode, struct clock_event_device *clk)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		kinetis_pit_enable(pit->base, 1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		kinetis_pit_enable(pit->base, 0);
+	}
+}
+
+/*
+ * Configure the timer to generate an interrupt in the specified amount of ticks
+ */
+static int kinetis_clockevent_tmr_set_next_event(
+	unsigned long delta, struct clock_event_device *c)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(c, struct kinetis_clock_event_ddata, evtdev);
+	unsigned long flags;
+
+	raw_local_irq_save(flags);
+	kinetis_pit_init(pit->base, delta);
+	kinetis_pit_enable(pit->base, 1);
+	raw_local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_mode	= kinetis_clockevent_tmr_set_mode,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer3",
+		},
+	},
+};
+
+/*
+ * Timer IRQ handler
+ */
+static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
+{
+	struct kinetis_clock_event_ddata *tmr = dev_id;
+
+	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&(tmr->evtdev));
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * System timer IRQ action
+ */
+static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
+	{
+		.name = "Kinetis Kernel Time Tick (pit0)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[0],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit1)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[1],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit2)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[2],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit3)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[3],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	},
+};
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct clk *clk;
+	void __iomem *base;
+	unsigned long rate;
+	int irq, chan;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("failed to get clock for clockevent\n");
+		return;
+	}
+
+	if (clk_prepare_enable(clk)) {
+		pr_err("failed to enable timer clock for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+	if (!(rate / HZ)) {
+		pr_err("failed to get proper clock rate for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to get map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq <= 0) {
+		pr_err("failed to get irq for clockevent\n");
+		goto err_get_irq;
+	}
+
+	chan = of_alias_get_id(np, "pit");
+	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+		pr_err("failed to calculate channel number for clockevent\n");
+		goto err_get_irq;
+	}
+	kinetis_clockevent_tmrs[chan].base = base;
+
+	/*
+	 * Set the fields required for the set_next_event method
+	 * (tickless kernel support)
+	 */
+	clockevents_calc_mult_shift(&(kinetis_clockevent_tmrs[chan].evtdev),
+					rate, max_delay_in_sec);
+	kinetis_clockevent_tmrs[chan].evtdev.max_delta_ns =
+					max_delay_in_sec * NSEC_PER_SEC;
+	kinetis_clockevent_tmrs[chan].evtdev.min_delta_ns =
+			clockevent_delta2ns(0xf,
+				&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	clockevents_register_device(&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	kinetis_pit_init(base, (rate / HZ) - 1);
+	kinetis_pit_enable(base, 1);
+
+	setup_irq(irq, &(kinetis_clockevent_irqaction[chan]));
+
+	return;
+
+err_get_irq:
+
+	iounmap(base);
+err_iomap:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
new file mode 100644
index 0000000..681732f
--- /dev/null
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -0,0 +1,10 @@
+#ifndef _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+#define _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+
+#define CLOCK_MCGOUTCLK		 0
+#define CLOCK_CCLK		 1
+#define CLOCK_PCLK		 2
+#define CLOCK_PIT		 3
+#define CLOCK_END		 4
+
+#endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on K70P256M150SF3RM.pdf

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  25 ++
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  18 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  50 ++++
 arch/arm/mach-kinetis/include/mach/power.h         |  83 ++++++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 226 ++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 294 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |  10 +
 12 files changed, 718 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 arch/arm/mach-kinetis/include/mach/power.h
 create mode 100644 drivers/clk/clk-kinetis.c
 create mode 100644 drivers/clocksource/timer-kinetis.c
 create mode 100644 include/dt-bindings/clock/kinetis-mcg.h

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..9c9c4fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,25 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Address and length of the register set.
+- #clock-cells: Should be <1>.
+
+Example:
+
+mcg: cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>;
+	#clock-cells = <1>;
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg CLOCK_UART1>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
new file mode 100644
index 0000000..49dddf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,18 @@
+Freescale Kinetis SoC Periodic Interrupt Timer (PIT)
+
+Required properties:
+
+- compatible: Should be "fsl,kinetis-pit-timer".
+- reg: Specifies base physical address and size of the register sets for the
+  clock event device.
+- interrupts: Should be the clock event device interrupt.
+- clocks: The clocks provided by the SoC to drive the timer.
+
+Example:
+
+pit0: timer@40037100 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037100 0x10>;
+	interrupts = <68>;
+	clocks = <&mcg CLOCK_PIT>;
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 747cdea..8630aff 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -979,6 +979,7 @@ config ARCH_KINETIS
 	select CPU_CORTEXM3
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index edccf37..a6efc29 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -14,3 +14,7 @@
 		reg = <0x8000000 0x8000000>;
 	};
 };
+
+&pit0 {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..770760f 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,53 @@
  *
  */
 #include "armv7-m.dtsi"
+#include "dt-bindings/clock/kinetis-mcg.h"
+
+/ {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
+	soc {
+		pit0: timer@40037100 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037100 0x10>;
+			interrupts = <68>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit1: timer@40037110 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037110 0x10>;
+			interrupts = <69>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit2: timer@40037120 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037120 0x10>;
+			interrupts = <70>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit3: timer@40037130 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037130 0x10>;
+			interrupts = <71>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		mcg: cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>;
+			#clock-cells = <1>;
+		};
+	};
+};
diff --git a/arch/arm/mach-kinetis/include/mach/power.h b/arch/arm/mach-kinetis/include/mach/power.h
new file mode 100644
index 0000000..e67bd4e
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/power.h
@@ -0,0 +1,83 @@
+/*
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_POWER_H
+#define _MACH_KINETIS_POWER_H
+
+/*
+ * Pack the SIM_SCGC[] register index and the bit index in that register into
+ * a single word. This is similar to the implementation of `dev_t` in
+ * the Linux kernel with its `MAJOR(dev)`, `MINOR(dev)` and
+ * `MKDEV(major,minor)` macros.
+ *
+ * This is useful when you want to have an array of `kinetis_clock_gate_t`s:
+ * you do not have to use a 2-dimensional array or a real structure.
+ */
+typedef u32 kinetis_clock_gate_t;
+#define KINETIS_CG_IDX_BITS	16
+#define KINETIS_CG_IDX_MASK	((1U << KINETIS_CG_IDX_BITS) - 1)
+/*
+ * Extract the register number and the bit index from a `kinetis_clock_gate_t`.
+ * The register number counts from 0,
+ * i.e. the register number for SIM_SCGC7 is 6.
+ */
+#define KINETIS_CG_REG(gate)	((unsigned int) ((gate) >> KINETIS_CG_IDX_BITS))
+#define KINETIS_CG_IDX(gate)	((unsigned int) ((gate) & KINETIS_CG_IDX_MASK))
+/*
+ * Build a `kinetis_clock_gate_t` from a register number and a bit index
+ */
+#define KINETIS_MKCG(reg, idx) \
+	(((kinetis_clock_gate_t)(reg) << KINETIS_CG_IDX_BITS) | \
+	(kinetis_clock_gate_t)(idx))
+
+/*
+ * Clock gates for the modules inside the MCU
+ */
+/* UARTs */
+#define KINETIS_CG_UART0	KINETIS_MKCG(3, 10)	/* SIM_SCGC4[10] */
+#define KINETIS_CG_UART1	KINETIS_MKCG(3, 11)	/* SIM_SCGC4[11] */
+#define KINETIS_CG_UART2	KINETIS_MKCG(3, 12)	/* SIM_SCGC4[12] */
+#define KINETIS_CG_UART3	KINETIS_MKCG(3, 13)	/* SIM_SCGC4[13] */
+#define KINETIS_CG_UART4	KINETIS_MKCG(0, 10)	/* SIM_SCGC1[10] */
+#define KINETIS_CG_UART5	KINETIS_MKCG(0, 11)	/* SIM_SCGC1[11] */
+/* Ports */
+#define KINETIS_CG_PORTA	KINETIS_MKCG(4, 9)	/* SIM_SCGC5[9] */
+#define KINETIS_CG_PORTB	KINETIS_MKCG(4, 10)	/* SIM_SCGC5[10] */
+#define KINETIS_CG_PORTC	KINETIS_MKCG(4, 11)	/* SIM_SCGC5[11] */
+#define KINETIS_CG_PORTD	KINETIS_MKCG(4, 12)	/* SIM_SCGC5[12] */
+#define KINETIS_CG_PORTE	KINETIS_MKCG(4, 13)	/* SIM_SCGC5[13] */
+#define KINETIS_CG_PORTF	KINETIS_MKCG(4, 14)	/* SIM_SCGC5[14] */
+/* ENET */
+#define KINETIS_CG_ENET		KINETIS_MKCG(1, 0)	/* SIM_SCGC2[0] */
+/* Periodic Interrupt Timer (PIT) */
+#define KINETIS_CG_PIT		KINETIS_MKCG(5, 23)	/* SIM_SCGC6[23] */
+/* LCD Controller */
+#define KINETIS_CG_LCDC		KINETIS_MKCG(2, 22)	/* SIM_SCGC3[22] */
+/* DMA controller and DMA request multiplexer */
+#define KINETIS_CG_DMA		KINETIS_MKCG(6, 1)	/* SIM_SCGC7[1] */
+#define KINETIS_CG_DMAMUX0	KINETIS_MKCG(5, 1)	/* SIM_SCGC6[1] */
+#define KINETIS_CG_DMAMUX1	KINETIS_MKCG(5, 2)	/* SIM_SCGC6[2] */
+/* USB High Speed */
+#define KINETIS_CG_USBHS	KINETIS_MKCG(5, 20)	/* SIM_SCGC6[20] */
+/* USB Full Speed */
+#define KINETIS_CG_USBFS	KINETIS_MKCG(3, 18)	/* SIM_SCGC4[18] */
+/* ADC modules */
+#define KINETIS_CG_ADC0		KINETIS_MKCG(5, 27)	/* SIM_SCGC6[27] */
+#define KINETIS_CG_ADC1		KINETIS_MKCG(2, 27)	/* SIM_SCGC3[27] */
+#define KINETIS_CG_ADC2		KINETIS_MKCG(5, 28)	/* SIM_SCGC6[28] */
+#define KINETIS_CG_ADC3		KINETIS_MKCG(2, 28)	/* SIM_SCGC3[28] */
+/* ESDHC */
+#define KINETIS_CG_ESDHC	KINETIS_MKCG(2, 17)	/* SIM_SCGC3[17] */
+/* SPI */
+#define KINETIS_CG_SPI0		KINETIS_MKCG(5, 12)	/* SIM_SCGC6[12] */
+#define KINETIS_CG_SPI1		KINETIS_MKCG(5, 13)	/* SIM_SCGC6[13] */
+#define KINETIS_CG_SPI2		KINETIS_MKCG(2, 12)	/* SIM_SCGC3[12] */
+
+#endif /*_MACH_KINETIS_POWER_H */
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b241c17..58718ed 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
+obj-$(CONFIG_ARCH_KINETIS)		+= clk-kinetis.o
 obj-$(CONFIG_MACH_LOONGSON32)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
new file mode 100644
index 0000000..dea1054
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,226 @@
+/*
+ * clk-kinetis.c - Clock driver for Kinetis K70 MCG
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/err.h>
+#include <mach/kinetis.h>
+#include <mach/power.h>
+
+#include <dt-bindings/clock/kinetis-mcg.h>
+
+/*
+ * Frequencies on OSC0 (EXTAL0/XTAL0) and OSC1 (EXTAL1/XTAL1)
+ *
+ * These frequencies should be set to the same values as in U-Boot.
+ */
+#define KINETIS_OSC0_RATE	50000000	/* 50 MHz */
+#define KINETIS_OSC1_RATE	12000000	/* 12 MHz */
+
+/*
+ * MCG Control 5 Register
+ */
+/* PLL External Reference Divider */
+#define KINETIS_MCG_C5_PRDIV_BITS	0
+#define KINETIS_MCG_C5_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C5_PRDIV_BITS)
+/* PLL Stop Enable */
+#define KINETIS_MCG_C5_PLLSTEN_MSK	(1 << 5)
+/* PLL Clock Enable */
+#define KINETIS_MCG_C5_PLLCLKEN_MSK	(1 << 6)
+/* PLL External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C5_PLLREFSEL_BIT	7
+#define KINETIS_MCG_C5_PLLREFSEL_MSK	(1 << KINETIS_MCG_C5_PLLREFSEL_BIT)
+/*
+ * MCG Control 6 Register
+ */
+/* VCO Divider */
+#define KINETIS_MCG_C6_VDIV_BITS	0
+#define KINETIS_MCG_C6_VDIV_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C6_VDIV_BITS)
+/* PLL Select */
+#define KINETIS_MCG_C6_PLLS_MSK		(1 << 6)
+/*
+ * MCG Control 11 Register
+ */
+/* PLL1 External Reference Divider */
+#define KINETIS_MCG_C11_PRDIV_BITS	0
+#define KINETIS_MCG_C11_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C11_PRDIV_BITS)
+/* PLL Clock Select: PLL0 or PLL1 */
+#define KINETIS_MCG_C11_PLLCS_MSK	(1 << 4)
+/* PLL1 Stop Enable */
+#define KINETIS_MCG_C11_PLLSTEN1_MSK	(1 << 5)
+/* PLL1 Clock Enable */
+#define KINETIS_MCG_C11_PLLCLKEN1_MSK	(1 << 6)
+/* PLL1 External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C11_PLLREFSEL1_BIT	7
+#define KINETIS_MCG_C11_PLLREFSEL1_MSK	(1 << KINETIS_MCG_C11_PLLREFSEL1_BIT)
+/*
+ * MCG Control 12 Register
+ */
+/* VCO1 Divider */
+#define KINETIS_MCG_C12_VDIV1_BITS	0
+#define KINETIS_MCG_C12_VDIV1_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C12_VDIV1_BITS)
+
+/*
+ * Multipurpose Clock Generator (MCG) register map
+ *
+ * See Chapter 25 of the K70 Reference Manual
+ */
+struct kinetis_mcg_regs {
+	u8 c1;		/* MCG Control 1 Register */
+	u8 c2;		/* MCG Control 2 Register */
+	u8 c3;		/* MCG Control 3 Register */
+	u8 c4;		/* MCG Control 4 Register */
+	u8 c5;		/* MCG Control 5 Register */
+	u8 c6;		/* MCG Control 6 Register */
+	u8 status;	/* MCG Status Register */
+	u8 rsv0;
+	u8 atc;		/* MCG Auto Trim Control Register */
+	u8 rsv1;
+	u8 atcvh;	/* MCG Auto Trim Compare Value High Register */
+	u8 atcvl;	/* MCG Auto Trim Compare Value Low Register */
+	u8 c7;		/* MCG Control 7 Register */
+	u8 c8;		/* MCG Control 8 Register */
+	u8 rsv2;
+	u8 c10;		/* MCG Control 10 Register */
+	u8 c11;		/* MCG Control 11 Register */
+	u8 c12;		/* MCG Control 12 Register */
+	u8 status2;	/* MCG Status 2 Register */
+	u8 rsv3;
+};
+
+#define KINETIS_MCG_PTR(base, reg) \
+	(&(((struct kinetis_mcg_regs *)(base))->reg))
+#define KINETIS_MCG_RD(base, reg) readb_relaxed(KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_WR(base, reg, val) \
+	writeb_relaxed((val), KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_ISSET(base, reg, mask) \
+	(KINETIS_MCG_RD(base, reg) & (mask))
+
+static struct clk *clk[CLOCK_END];
+static struct clk_onecell_data clk_data = {
+	.clks = clk,
+	.clk_num = ARRAY_SIZE(clk),
+};
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[CLOCK_END];
+	int i;
+	void __iomem *base;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+
+	for (i = 0; i < ARRAY_SIZE(clk); ++i)
+		clk[i] = ERR_PTR(-ENOENT);
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(KINETIS_MCG_ISSET(base, c11, KINETIS_MCG_C11_PLLCS_MSK));
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c11,
+				KINETIS_MCG_C11_PLLREFSEL1_MSK));
+	else
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c5,
+				KINETIS_MCG_C5_PLLREFSEL_MSK));
+
+	/*
+	 * Start with the MCG input clock
+	 */
+	mcgout = osc_sel ? KINETIS_OSC1_RATE : KINETIS_OSC0_RATE;
+
+	/*
+	 * Apply dividers and multipliers of the selected PLL
+	 */
+	if (pll_sel) {
+		/*
+		 * PLL1 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c11) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c12) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c5) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c6) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[CLOCK_MCGOUTCLK] = mcgout;
+
+	clock_val[CLOCK_CCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[CLOCK_PCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	clk[CLOCK_MCGOUTCLK] = clk_register_fixed_rate(NULL, "MCGOUTCLK",
+			NULL, CLK_IS_ROOT, clock_val[CLOCK_MCGOUTCLK]);
+
+	clk[CLOCK_CCLK] = clk_register_fixed_rate(NULL, "CCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_CCLK]);
+
+	clk[CLOCK_PCLK] = clk_register_fixed_rate(NULL, "PCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_PCLK]);
+
+	clk[CLOCK_PIT] = clk_register_gate(NULL, "PIT", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
+			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f1c77e..1d2ecde 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -106,6 +106,11 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_KINETIS
+	bool "Clocksource for Kinetis SoCs"
+	depends on OF && ARM && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f1ae0e7..6da77a8 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -36,6 +36,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_KINETIS)	+= timer-kinetis.o
 obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_LPC32XX)	+= time-lpc32xx.o
diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
new file mode 100644
index 0000000..634f365
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,294 @@
+/*
+ * timer-kinetis.c - Timer driver for Kinetis K70
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/io.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_device.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <mach/kinetis.h>
+
+#define KINETIS_PIT_CHANNELS 4
+
+#define KINETIS_PIT0_IRQ 68
+#define KINETIS_PIT1_IRQ 69
+#define KINETIS_PIT2_IRQ 70
+#define KINETIS_PIT3_IRQ 71
+
+/*
+ * PIT Timer Control Register
+ */
+/* Timer Interrupt Enable Bit */
+#define KINETIS_PIT_TCTRL_TIE_MSK	(1 << 1)
+/* Timer Enable Bit */
+#define KINETIS_PIT_TCTRL_TEN_MSK	(1 << 0)
+/*
+ * PIT Timer Flag Register
+ */
+/* Timer Interrupt Flag */
+#define KINETIS_PIT_TFLG_TIF_MSK	(1 << 0)
+
+/*
+ * PIT control registers base
+ */
+#define KINETIS_PIT_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00037000)
+#define KINETIS_PIT_MCR			IOMEM(KINETIS_PIT_BASE + 0x0)
+
+/*
+ * Periodic Interrupt Timer (PIT) registers
+ */
+struct kinetis_pit_channel_regs {
+	u32 ldval;	/* Timer Load Value Register */
+	u32 cval;	/* Current Timer Value Register */
+	u32 tctrl;	/* Timer Control Register */
+	u32 tflg;	/* Timer Flag Register */
+};
+
+#define KINETIS_PIT_PTR(base, reg) \
+	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
+#define KINETIS_PIT_RD(base, reg) readl(KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_WR(base, reg, val) \
+	writel((val), KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_SET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) | (mask))
+#define KINETIS_PIT_RESET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(void __iomem *base, int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(void __iomem *base, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	writel(0, KINETIS_PIT_MCR);
+
+	KINETIS_PIT_WR(base, tctrl, 0);
+	KINETIS_PIT_WR(base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(base, ldval, ticks);
+	KINETIS_PIT_WR(base, cval, 0);
+	KINETIS_PIT_WR(base, tctrl, KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+/*
+ * Clock event device set mode function
+ */
+static void kinetis_clockevent_tmr_set_mode(
+	enum clock_event_mode mode, struct clock_event_device *clk)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		kinetis_pit_enable(pit->base, 1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		kinetis_pit_enable(pit->base, 0);
+	}
+}
+
+/*
+ * Configure the timer to generate an interrupt in the specified amount of ticks
+ */
+static int kinetis_clockevent_tmr_set_next_event(
+	unsigned long delta, struct clock_event_device *c)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(c, struct kinetis_clock_event_ddata, evtdev);
+	unsigned long flags;
+
+	raw_local_irq_save(flags);
+	kinetis_pit_init(pit->base, delta);
+	kinetis_pit_enable(pit->base, 1);
+	raw_local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_mode	= kinetis_clockevent_tmr_set_mode,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer3",
+		},
+	},
+};
+
+/*
+ * Timer IRQ handler
+ */
+static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
+{
+	struct kinetis_clock_event_ddata *tmr = dev_id;
+
+	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&(tmr->evtdev));
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * System timer IRQ action
+ */
+static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
+	{
+		.name = "Kinetis Kernel Time Tick (pit0)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[0],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit1)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[1],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit2)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[2],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit3)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[3],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	},
+};
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct clk *clk;
+	void __iomem *base;
+	unsigned long rate;
+	int irq, chan;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("failed to get clock for clockevent\n");
+		return;
+	}
+
+	if (clk_prepare_enable(clk)) {
+		pr_err("failed to enable timer clock for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+	if (!(rate / HZ)) {
+		pr_err("failed to get proper clock rate for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to get map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq <= 0) {
+		pr_err("failed to get irq for clockevent\n");
+		goto err_get_irq;
+	}
+
+	chan = of_alias_get_id(np, "pit");
+	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+		pr_err("failed to calculate channel number for clockevent\n");
+		goto err_get_irq;
+	}
+	kinetis_clockevent_tmrs[chan].base = base;
+
+	/*
+	 * Set the fields required for the set_next_event method
+	 * (tickless kernel support)
+	 */
+	clockevents_calc_mult_shift(&(kinetis_clockevent_tmrs[chan].evtdev),
+					rate, max_delay_in_sec);
+	kinetis_clockevent_tmrs[chan].evtdev.max_delta_ns =
+					max_delay_in_sec * NSEC_PER_SEC;
+	kinetis_clockevent_tmrs[chan].evtdev.min_delta_ns =
+			clockevent_delta2ns(0xf,
+				&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	clockevents_register_device(&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	kinetis_pit_init(base, (rate / HZ) - 1);
+	kinetis_pit_enable(base, 1);
+
+	setup_irq(irq, &(kinetis_clockevent_irqaction[chan]));
+
+	return;
+
+err_get_irq:
+
+	iounmap(base);
+err_iomap:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
new file mode 100644
index 0000000..681732f
--- /dev/null
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -0,0 +1,10 @@
+#ifndef _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+#define _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+
+#define CLOCK_MCGOUTCLK		 0
+#define CLOCK_CCLK		 1
+#define CLOCK_PCLK		 2
+#define CLOCK_PIT		 3
+#define CLOCK_END		 4
+
+#endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
                     ` (3 preceding siblings ...)
  2015-06-23 21:19   ` [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 7/9] arm: twr-k70f120m: IOMUX driver " Paul Osmialowski
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Based on K70P256M150SF3RM.pdf

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  25 ++
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  18 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  50 ++++
 arch/arm/mach-kinetis/include/mach/power.h         |  83 ++++++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 226 ++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 294 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |  10 +
 12 files changed, 718 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 arch/arm/mach-kinetis/include/mach/power.h
 create mode 100644 drivers/clk/clk-kinetis.c
 create mode 100644 drivers/clocksource/timer-kinetis.c
 create mode 100644 include/dt-bindings/clock/kinetis-mcg.h

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..9c9c4fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,25 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Address and length of the register set.
+- #clock-cells: Should be <1>.
+
+Example:
+
+mcg: cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>;
+	#clock-cells = <1>;
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg CLOCK_UART1>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
new file mode 100644
index 0000000..49dddf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,18 @@
+Freescale Kinetis SoC Periodic Interrupt Timer (PIT)
+
+Required properties:
+
+- compatible: Should be "fsl,kinetis-pit-timer".
+- reg: Specifies base physical address and size of the register sets for the
+  clock event device.
+- interrupts: Should be the clock event device interrupt.
+- clocks: The clocks provided by the SoC to drive the timer.
+
+Example:
+
+pit0: timer@40037100 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037100 0x10>;
+	interrupts = <68>;
+	clocks = <&mcg CLOCK_PIT>;
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 747cdea..8630aff 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -979,6 +979,7 @@ config ARCH_KINETIS
 	select CPU_CORTEXM3
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index edccf37..a6efc29 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -14,3 +14,7 @@
 		reg = <0x8000000 0x8000000>;
 	};
 };
+
+&pit0 {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..770760f 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,53 @@
  *
  */
 #include "armv7-m.dtsi"
+#include "dt-bindings/clock/kinetis-mcg.h"
+
+/ {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
+	soc {
+		pit0: timer@40037100 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037100 0x10>;
+			interrupts = <68>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit1: timer@40037110 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037110 0x10>;
+			interrupts = <69>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit2: timer@40037120 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037120 0x10>;
+			interrupts = <70>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		pit3: timer@40037130 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037130 0x10>;
+			interrupts = <71>;
+			clocks = <&mcg CLOCK_PIT>;
+			status = "disabled";
+		};
+
+		mcg: cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>;
+			#clock-cells = <1>;
+		};
+	};
+};
diff --git a/arch/arm/mach-kinetis/include/mach/power.h b/arch/arm/mach-kinetis/include/mach/power.h
new file mode 100644
index 0000000..e67bd4e
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/power.h
@@ -0,0 +1,83 @@
+/*
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_POWER_H
+#define _MACH_KINETIS_POWER_H
+
+/*
+ * Pack the SIM_SCGC[] register index and the bit index in that register into
+ * a single word. This is similar to the implementation of `dev_t` in
+ * the Linux kernel with its `MAJOR(dev)`, `MINOR(dev)` and
+ * `MKDEV(major,minor)` macros.
+ *
+ * This is useful when you want to have an array of `kinetis_clock_gate_t`s:
+ * you do not have to use a 2-dimensional array or a real structure.
+ */
+typedef u32 kinetis_clock_gate_t;
+#define KINETIS_CG_IDX_BITS	16
+#define KINETIS_CG_IDX_MASK	((1U << KINETIS_CG_IDX_BITS) - 1)
+/*
+ * Extract the register number and the bit index from a `kinetis_clock_gate_t`.
+ * The register number counts from 0,
+ * i.e. the register number for SIM_SCGC7 is 6.
+ */
+#define KINETIS_CG_REG(gate)	((unsigned int) ((gate) >> KINETIS_CG_IDX_BITS))
+#define KINETIS_CG_IDX(gate)	((unsigned int) ((gate) & KINETIS_CG_IDX_MASK))
+/*
+ * Build a `kinetis_clock_gate_t` from a register number and a bit index
+ */
+#define KINETIS_MKCG(reg, idx) \
+	(((kinetis_clock_gate_t)(reg) << KINETIS_CG_IDX_BITS) | \
+	(kinetis_clock_gate_t)(idx))
+
+/*
+ * Clock gates for the modules inside the MCU
+ */
+/* UARTs */
+#define KINETIS_CG_UART0	KINETIS_MKCG(3, 10)	/* SIM_SCGC4[10] */
+#define KINETIS_CG_UART1	KINETIS_MKCG(3, 11)	/* SIM_SCGC4[11] */
+#define KINETIS_CG_UART2	KINETIS_MKCG(3, 12)	/* SIM_SCGC4[12] */
+#define KINETIS_CG_UART3	KINETIS_MKCG(3, 13)	/* SIM_SCGC4[13] */
+#define KINETIS_CG_UART4	KINETIS_MKCG(0, 10)	/* SIM_SCGC1[10] */
+#define KINETIS_CG_UART5	KINETIS_MKCG(0, 11)	/* SIM_SCGC1[11] */
+/* Ports */
+#define KINETIS_CG_PORTA	KINETIS_MKCG(4, 9)	/* SIM_SCGC5[9] */
+#define KINETIS_CG_PORTB	KINETIS_MKCG(4, 10)	/* SIM_SCGC5[10] */
+#define KINETIS_CG_PORTC	KINETIS_MKCG(4, 11)	/* SIM_SCGC5[11] */
+#define KINETIS_CG_PORTD	KINETIS_MKCG(4, 12)	/* SIM_SCGC5[12] */
+#define KINETIS_CG_PORTE	KINETIS_MKCG(4, 13)	/* SIM_SCGC5[13] */
+#define KINETIS_CG_PORTF	KINETIS_MKCG(4, 14)	/* SIM_SCGC5[14] */
+/* ENET */
+#define KINETIS_CG_ENET		KINETIS_MKCG(1, 0)	/* SIM_SCGC2[0] */
+/* Periodic Interrupt Timer (PIT) */
+#define KINETIS_CG_PIT		KINETIS_MKCG(5, 23)	/* SIM_SCGC6[23] */
+/* LCD Controller */
+#define KINETIS_CG_LCDC		KINETIS_MKCG(2, 22)	/* SIM_SCGC3[22] */
+/* DMA controller and DMA request multiplexer */
+#define KINETIS_CG_DMA		KINETIS_MKCG(6, 1)	/* SIM_SCGC7[1] */
+#define KINETIS_CG_DMAMUX0	KINETIS_MKCG(5, 1)	/* SIM_SCGC6[1] */
+#define KINETIS_CG_DMAMUX1	KINETIS_MKCG(5, 2)	/* SIM_SCGC6[2] */
+/* USB High Speed */
+#define KINETIS_CG_USBHS	KINETIS_MKCG(5, 20)	/* SIM_SCGC6[20] */
+/* USB Full Speed */
+#define KINETIS_CG_USBFS	KINETIS_MKCG(3, 18)	/* SIM_SCGC4[18] */
+/* ADC modules */
+#define KINETIS_CG_ADC0		KINETIS_MKCG(5, 27)	/* SIM_SCGC6[27] */
+#define KINETIS_CG_ADC1		KINETIS_MKCG(2, 27)	/* SIM_SCGC3[27] */
+#define KINETIS_CG_ADC2		KINETIS_MKCG(5, 28)	/* SIM_SCGC6[28] */
+#define KINETIS_CG_ADC3		KINETIS_MKCG(2, 28)	/* SIM_SCGC3[28] */
+/* ESDHC */
+#define KINETIS_CG_ESDHC	KINETIS_MKCG(2, 17)	/* SIM_SCGC3[17] */
+/* SPI */
+#define KINETIS_CG_SPI0		KINETIS_MKCG(5, 12)	/* SIM_SCGC6[12] */
+#define KINETIS_CG_SPI1		KINETIS_MKCG(5, 13)	/* SIM_SCGC6[13] */
+#define KINETIS_CG_SPI2		KINETIS_MKCG(2, 12)	/* SIM_SCGC3[12] */
+
+#endif /*_MACH_KINETIS_POWER_H */
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b241c17..58718ed 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
+obj-$(CONFIG_ARCH_KINETIS)		+= clk-kinetis.o
 obj-$(CONFIG_MACH_LOONGSON32)		+= clk-ls1x.o
 obj-$(CONFIG_COMMON_CLK_MAX_GEN)	+= clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
new file mode 100644
index 0000000..dea1054
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,226 @@
+/*
+ * clk-kinetis.c - Clock driver for Kinetis K70 MCG
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/err.h>
+#include <mach/kinetis.h>
+#include <mach/power.h>
+
+#include <dt-bindings/clock/kinetis-mcg.h>
+
+/*
+ * Frequencies on OSC0 (EXTAL0/XTAL0) and OSC1 (EXTAL1/XTAL1)
+ *
+ * These frequencies should be set to the same values as in U-Boot.
+ */
+#define KINETIS_OSC0_RATE	50000000	/* 50 MHz */
+#define KINETIS_OSC1_RATE	12000000	/* 12 MHz */
+
+/*
+ * MCG Control 5 Register
+ */
+/* PLL External Reference Divider */
+#define KINETIS_MCG_C5_PRDIV_BITS	0
+#define KINETIS_MCG_C5_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C5_PRDIV_BITS)
+/* PLL Stop Enable */
+#define KINETIS_MCG_C5_PLLSTEN_MSK	(1 << 5)
+/* PLL Clock Enable */
+#define KINETIS_MCG_C5_PLLCLKEN_MSK	(1 << 6)
+/* PLL External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C5_PLLREFSEL_BIT	7
+#define KINETIS_MCG_C5_PLLREFSEL_MSK	(1 << KINETIS_MCG_C5_PLLREFSEL_BIT)
+/*
+ * MCG Control 6 Register
+ */
+/* VCO Divider */
+#define KINETIS_MCG_C6_VDIV_BITS	0
+#define KINETIS_MCG_C6_VDIV_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C6_VDIV_BITS)
+/* PLL Select */
+#define KINETIS_MCG_C6_PLLS_MSK		(1 << 6)
+/*
+ * MCG Control 11 Register
+ */
+/* PLL1 External Reference Divider */
+#define KINETIS_MCG_C11_PRDIV_BITS	0
+#define KINETIS_MCG_C11_PRDIV_MSK \
+	(((1 << 3) - 1) << KINETIS_MCG_C11_PRDIV_BITS)
+/* PLL Clock Select: PLL0 or PLL1 */
+#define KINETIS_MCG_C11_PLLCS_MSK	(1 << 4)
+/* PLL1 Stop Enable */
+#define KINETIS_MCG_C11_PLLSTEN1_MSK	(1 << 5)
+/* PLL1 Clock Enable */
+#define KINETIS_MCG_C11_PLLCLKEN1_MSK	(1 << 6)
+/* PLL1 External Reference Select (for K70@120MHz) */
+#define KINETIS_MCG_C11_PLLREFSEL1_BIT	7
+#define KINETIS_MCG_C11_PLLREFSEL1_MSK	(1 << KINETIS_MCG_C11_PLLREFSEL1_BIT)
+/*
+ * MCG Control 12 Register
+ */
+/* VCO1 Divider */
+#define KINETIS_MCG_C12_VDIV1_BITS	0
+#define KINETIS_MCG_C12_VDIV1_MSK \
+	(((1 << 5) - 1) << KINETIS_MCG_C12_VDIV1_BITS)
+
+/*
+ * Multipurpose Clock Generator (MCG) register map
+ *
+ * See Chapter 25 of the K70 Reference Manual
+ */
+struct kinetis_mcg_regs {
+	u8 c1;		/* MCG Control 1 Register */
+	u8 c2;		/* MCG Control 2 Register */
+	u8 c3;		/* MCG Control 3 Register */
+	u8 c4;		/* MCG Control 4 Register */
+	u8 c5;		/* MCG Control 5 Register */
+	u8 c6;		/* MCG Control 6 Register */
+	u8 status;	/* MCG Status Register */
+	u8 rsv0;
+	u8 atc;		/* MCG Auto Trim Control Register */
+	u8 rsv1;
+	u8 atcvh;	/* MCG Auto Trim Compare Value High Register */
+	u8 atcvl;	/* MCG Auto Trim Compare Value Low Register */
+	u8 c7;		/* MCG Control 7 Register */
+	u8 c8;		/* MCG Control 8 Register */
+	u8 rsv2;
+	u8 c10;		/* MCG Control 10 Register */
+	u8 c11;		/* MCG Control 11 Register */
+	u8 c12;		/* MCG Control 12 Register */
+	u8 status2;	/* MCG Status 2 Register */
+	u8 rsv3;
+};
+
+#define KINETIS_MCG_PTR(base, reg) \
+	(&(((struct kinetis_mcg_regs *)(base))->reg))
+#define KINETIS_MCG_RD(base, reg) readb_relaxed(KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_WR(base, reg, val) \
+	writeb_relaxed((val), KINETIS_MCG_PTR(base, reg))
+#define KINETIS_MCG_ISSET(base, reg, mask) \
+	(KINETIS_MCG_RD(base, reg) & (mask))
+
+static struct clk *clk[CLOCK_END];
+static struct clk_onecell_data clk_data = {
+	.clks = clk,
+	.clk_num = ARRAY_SIZE(clk),
+};
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[CLOCK_END];
+	int i;
+	void __iomem *base;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+
+	for (i = 0; i < ARRAY_SIZE(clk); ++i)
+		clk[i] = ERR_PTR(-ENOENT);
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(KINETIS_MCG_ISSET(base, c11, KINETIS_MCG_C11_PLLCS_MSK));
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c11,
+				KINETIS_MCG_C11_PLLREFSEL1_MSK));
+	else
+		osc_sel = !!(KINETIS_MCG_ISSET(base, c5,
+				KINETIS_MCG_C5_PLLREFSEL_MSK));
+
+	/*
+	 * Start with the MCG input clock
+	 */
+	mcgout = osc_sel ? KINETIS_OSC1_RATE : KINETIS_OSC0_RATE;
+
+	/*
+	 * Apply dividers and multipliers of the selected PLL
+	 */
+	if (pll_sel) {
+		/*
+		 * PLL1 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c11) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c12) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((KINETIS_MCG_RD(base, c5) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((KINETIS_MCG_RD(base, c6) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[CLOCK_MCGOUTCLK] = mcgout;
+
+	clock_val[CLOCK_CCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[CLOCK_PCLK] = mcgout /
+		(((KINETIS_SIM_RD(clkdiv1) & KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+		KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	clk[CLOCK_MCGOUTCLK] = clk_register_fixed_rate(NULL, "MCGOUTCLK",
+			NULL, CLK_IS_ROOT, clock_val[CLOCK_MCGOUTCLK]);
+
+	clk[CLOCK_CCLK] = clk_register_fixed_rate(NULL, "CCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_CCLK]);
+
+	clk[CLOCK_PCLK] = clk_register_fixed_rate(NULL, "PCLK", "MCGOUTCLK",
+			0, clock_val[CLOCK_PCLK]);
+
+	clk[CLOCK_PIT] = clk_register_gate(NULL, "PIT", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
+			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f1c77e..1d2ecde 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -106,6 +106,11 @@ config CLKSRC_EFM32
 	  Support to use the timers of EFM32 SoCs as clock source and clock
 	  event device.
 
+config CLKSRC_KINETIS
+	bool "Clocksource for Kinetis SoCs"
+	depends on OF && ARM && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f1ae0e7..6da77a8 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -36,6 +36,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_KINETIS)	+= timer-kinetis.o
 obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_LPC32XX)	+= time-lpc32xx.o
diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
new file mode 100644
index 0000000..634f365
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,294 @@
+/*
+ * timer-kinetis.c - Timer driver for Kinetis K70
+ *
+ * Based on legacy pre-OF code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/io.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_device.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <mach/kinetis.h>
+
+#define KINETIS_PIT_CHANNELS 4
+
+#define KINETIS_PIT0_IRQ 68
+#define KINETIS_PIT1_IRQ 69
+#define KINETIS_PIT2_IRQ 70
+#define KINETIS_PIT3_IRQ 71
+
+/*
+ * PIT Timer Control Register
+ */
+/* Timer Interrupt Enable Bit */
+#define KINETIS_PIT_TCTRL_TIE_MSK	(1 << 1)
+/* Timer Enable Bit */
+#define KINETIS_PIT_TCTRL_TEN_MSK	(1 << 0)
+/*
+ * PIT Timer Flag Register
+ */
+/* Timer Interrupt Flag */
+#define KINETIS_PIT_TFLG_TIF_MSK	(1 << 0)
+
+/*
+ * PIT control registers base
+ */
+#define KINETIS_PIT_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00037000)
+#define KINETIS_PIT_MCR			IOMEM(KINETIS_PIT_BASE + 0x0)
+
+/*
+ * Periodic Interrupt Timer (PIT) registers
+ */
+struct kinetis_pit_channel_regs {
+	u32 ldval;	/* Timer Load Value Register */
+	u32 cval;	/* Current Timer Value Register */
+	u32 tctrl;	/* Timer Control Register */
+	u32 tflg;	/* Timer Flag Register */
+};
+
+#define KINETIS_PIT_PTR(base, reg) \
+	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
+#define KINETIS_PIT_RD(base, reg) readl(KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_WR(base, reg, val) \
+	writel((val), KINETIS_PIT_PTR(base, reg))
+#define KINETIS_PIT_SET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) | (mask))
+#define KINETIS_PIT_RESET(base, reg, mask) \
+	KINETIS_PIT_WR(base, reg, (KINETIS_PIT_RD(base, reg)) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(void __iomem *base, int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(base, tctrl, KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(void __iomem *base, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	writel(0, KINETIS_PIT_MCR);
+
+	KINETIS_PIT_WR(base, tctrl, 0);
+	KINETIS_PIT_WR(base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(base, ldval, ticks);
+	KINETIS_PIT_WR(base, cval, 0);
+	KINETIS_PIT_WR(base, tctrl, KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+/*
+ * Clock event device set mode function
+ */
+static void kinetis_clockevent_tmr_set_mode(
+	enum clock_event_mode mode, struct clock_event_device *clk)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		kinetis_pit_enable(pit->base, 1);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		kinetis_pit_enable(pit->base, 0);
+	}
+}
+
+/*
+ * Configure the timer to generate an interrupt in the specified amount of ticks
+ */
+static int kinetis_clockevent_tmr_set_next_event(
+	unsigned long delta, struct clock_event_device *c)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(c, struct kinetis_clock_event_ddata, evtdev);
+	unsigned long flags;
+
+	raw_local_irq_save(flags);
+	kinetis_pit_init(pit->base, delta);
+	kinetis_pit_enable(pit->base, 1);
+	raw_local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_mode	= kinetis_clockevent_tmr_set_mode,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "fsl,kinetis-pit-timer3",
+		},
+	},
+};
+
+/*
+ * Timer IRQ handler
+ */
+static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
+{
+	struct kinetis_clock_event_ddata *tmr = dev_id;
+
+	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&(tmr->evtdev));
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * System timer IRQ action
+ */
+static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
+	{
+		.name = "Kinetis Kernel Time Tick (pit0)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[0],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit1)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[1],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit2)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[2],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	}, {
+		.name = "Kinetis Kernel Time Tick (pit3)",
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+		.dev_id = &kinetis_clockevent_tmrs[3],
+		.handler = kinetis_clockevent_tmr_irq_handler,
+	},
+};
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct clk *clk;
+	void __iomem *base;
+	unsigned long rate;
+	int irq, chan;
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("failed to get clock for clockevent\n");
+		return;
+	}
+
+	if (clk_prepare_enable(clk)) {
+		pr_err("failed to enable timer clock for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	rate = clk_get_rate(clk);
+	if (!(rate / HZ)) {
+		pr_err("failed to get proper clock rate for clockevent\n");
+		goto err_clk_enable;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to get map registers for clockevent\n");
+		goto err_iomap;
+	}
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq <= 0) {
+		pr_err("failed to get irq for clockevent\n");
+		goto err_get_irq;
+	}
+
+	chan = of_alias_get_id(np, "pit");
+	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+		pr_err("failed to calculate channel number for clockevent\n");
+		goto err_get_irq;
+	}
+	kinetis_clockevent_tmrs[chan].base = base;
+
+	/*
+	 * Set the fields required for the set_next_event method
+	 * (tickless kernel support)
+	 */
+	clockevents_calc_mult_shift(&(kinetis_clockevent_tmrs[chan].evtdev),
+					rate, max_delay_in_sec);
+	kinetis_clockevent_tmrs[chan].evtdev.max_delta_ns =
+					max_delay_in_sec * NSEC_PER_SEC;
+	kinetis_clockevent_tmrs[chan].evtdev.min_delta_ns =
+			clockevent_delta2ns(0xf,
+				&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	clockevents_register_device(&(kinetis_clockevent_tmrs[chan].evtdev));
+
+	kinetis_pit_init(base, (rate / HZ) - 1);
+	kinetis_pit_enable(base, 1);
+
+	setup_irq(irq, &(kinetis_clockevent_irqaction[chan]));
+
+	return;
+
+err_get_irq:
+
+	iounmap(base);
+err_iomap:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
new file mode 100644
index 0000000..681732f
--- /dev/null
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -0,0 +1,10 @@
+#ifndef _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+#define _DT_BINDINGS_CLOCK_KINETIS_MCG_H
+
+#define CLOCK_MCGOUTCLK		 0
+#define CLOCK_CCLK		 1
+#define CLOCK_PCLK		 2
+#define CLOCK_PIT		 3
+#define CLOCK_END		 4
+
+#endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (9 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This is very cheap and simple implementation of pinctrl driver
for Kinetis SoC - its primary role is to provide means for enabling UART
fuctionality on I/O PORT_E which will be utilized by the commits
yet to come.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 arch/arm/mach-kinetis/Kconfig                      |   6 +
 drivers/clk/clk-kinetis.c                          |  28 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |   8 +-
 9 files changed, 659 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
 create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
new file mode 100644
index 0000000..04798c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
@@ -0,0 +1,31 @@
+Freescale Kinetis IOMUX Controller
+
+This controller is largely based on i.MX IOMUX Controller. Please refer to
+fsl,imx-pinctrl.txt in this directory for more detailed description.
+
+Required properties:
+- compatible: Should be "fsl,kinetis-iomuxc".
+- reg: Should contain the physical address and length of the gpio/pinmux
+  register range.
+- clocks: Clock that drives this I/O port.
+- fsl,pins: Two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
+  a pin working on a specific function, CONFIG is the pad setting value
+  such as pull enable, pull select, drive strength enable. Please refer to
+  Kinetis datasheet for the valid pad config settings.
+
+Example:
+
+portE: pinmux@4004d000 {
+	compatible = "fsl,kinetis-padconf";
+	reg = <0x4004d000 0x1000>;
+	clocks = <&mcg CLOCK_PORTE>;
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8630aff..662447c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -980,6 +980,7 @@ config ARCH_KINETIS
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 770760f..f3f22b5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -11,9 +11,57 @@
 		pit1 = &pit1;
 		pit2 = &pit2;
 		pit3 = &pit3;
+		pmx0 = &portA;
+		pmx1 = &portB;
+		pmx2 = &portC;
+		pmx3 = &portD;
+		pmx4 = &portE;
+		pmx5 = &portF;
 	};
 
 	soc {
+		portA: pinmux@40049000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x40049000 0x1000>;
+			clocks = <&mcg CLOCK_PORTA>;
+			status = "disabled";
+		};
+
+		portB: pinmux@4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg CLOCK_PORTB>;
+			status = "disabled";
+		};
+
+		portC: pinmux@4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg CLOCK_PORTC>;
+			status = "disabled";
+		};
+
+		portD: pinmux@4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg CLOCK_PORTD>;
+			status = "disabled";
+		};
+
+		portE: pinmux@4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg CLOCK_PORTE>;
+			status = "disabled";
+		};
+
+		portF: pinmux@4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg CLOCK_PORTF>;
+			status = "disabled";
+		};
+
 		pit0: timer@40037100 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037100 0x10>;
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
index 300bcea..c9a9d3a 100644
--- a/arch/arm/mach-kinetis/Kconfig
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -1,8 +1,14 @@
 if ARCH_KINETIS
 
+config SOC_K70
+	bool
+	depends on ARCH_KINETIS
+	select PINCTRL_KINETIS
+
 config MACH_KINETIS
 	bool "Kinetis K70 based development board"
 	default y
+	select SOC_K70
 	help
 	  Say Y here if you are using Kinetis K70 based development board
 
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index dea1054..b6620c0 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -220,6 +220,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
 			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
 
+	/*
+	 * Port control clock gates,
+	 *   see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_PORTA] = clk_register_gate(NULL, "PORTA", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTA)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTA), 0, NULL);
+
+	clk[CLOCK_PORTB] = clk_register_gate(NULL, "PORTB", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTB)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTB), 0, NULL);
+
+	clk[CLOCK_PORTC] = clk_register_gate(NULL, "PORTC", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTC)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTC), 0, NULL);
+
+	clk[CLOCK_PORTD] = clk_register_gate(NULL, "PORTD", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTD)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTD), 0, NULL);
+
+	clk[CLOCK_PORTE] = clk_register_gate(NULL, "PORTE", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTE)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTE), 0, NULL);
+
+	clk[CLOCK_PORTF] = clk_register_gate(NULL, "PORTF", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..2d0dfa9 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -94,6 +94,14 @@ config PINCTRL_IMX7D
 	help
 	  Say Y here to enable the imx7d pinctrl driver
 
+config PINCTRL_KINETIS
+	bool "Kinetis pinctrl driver"
+	depends on OF
+	depends on SOC_K70
+	select PINMUX
+	help
+	  Say Y here to enable the Kinetis pinctrl driver
+
 config PINCTRL_VF610
 	bool "Freescale Vybrid VF610 pinctrl driver"
 	depends on SOC_VF610
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index 343cb43..8db5f4c 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6dl.o
 obj-$(CONFIG_PINCTRL_IMX6SL)	+= pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_IMX6SX)	+= pinctrl-imx6sx.o
 obj-$(CONFIG_PINCTRL_IMX7D)	+= pinctrl-imx7d.o
+obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o
 obj-$(CONFIG_PINCTRL_VF610)	+= pinctrl-vf610.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
diff --git a/drivers/pinctrl/freescale/pinctrl-kinetis.c b/drivers/pinctrl/freescale/pinctrl-kinetis.c
new file mode 100644
index 0000000..baa913e
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,529 @@
+/*
+ * pinctrl-kinetis.c - iomux for Kinetis MCUs
+ *
+ * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng@linaro.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+/**
+ * struct kinetis_pin_group - describes a single pin
+ * @mux_reg: the mux register for this pin.
+ * @mux_mode: the mux mode for this pin.
+ */
+struct kinetis_pin {
+	u32 mux_reg;
+	u32 mux_mode;
+};
+
+/**
+ * struct kinetis_pin_group - describes a pin group
+ * @name: the name of this specific pin group
+ * @npins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @pins: array of pins
+ */
+struct kinetis_pin_group {
+	const char *name;
+	unsigned npins;
+	struct kinetis_pin *pins;
+};
+
+/**
+ * struct kinetis_pmx_func - describes pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct kinetis_pmx_func {
+	const char *name;
+	const char **groups;
+	unsigned num_groups;
+};
+
+struct kinetis_pinctrl_soc_info {
+	struct device			*dev;
+	struct kinetis_pin_group	*groups;
+	unsigned int			ngroups;
+	struct kinetis_pmx_func		*functions;
+	unsigned int			nfunctions;
+};
+
+struct kinetis_pinctrl {
+	int				port_id;
+	struct device			*dev;
+	struct pinctrl_dev		*pctl;
+	void __iomem			*base;
+	struct clk			*clk;
+	struct kinetis_pinctrl_soc_info	info;
+};
+
+static const struct of_device_id kinetis_pinctrl_of_match[] = {
+	{ .compatible = "fsl,kinetis-padconf", },
+	{ /* sentinel */ }
+};
+
+/*
+ * PORTx register map
+ */
+struct kinetis_port_regs {
+	u32 pcr[32];	/* Pin Control Registers */
+	u32 gpclr;	/* Global Pin Control Low Register */
+	u32 gpchr;	/* Global Pin Control High Register */
+	u32 rsv0[6];
+	u32 isfr;	/* Interrupt Status Flag Register */
+	u32 rsv1[7];
+	u32 dfer;	/* Digital Filter Enable Register */
+	u32 dfcr;	/* Digital Filter Clock Register */
+	u32 dfwr;	/* Digital Filter Width Register */
+};
+
+/*
+ * PORTx registers base
+ */
+#define KINETIS_PORT_PTR(base, reg) \
+	(&(((struct kinetis_port_regs *)(base))->reg))
+#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_WR(base, reg, val) \
+		writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_SET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
+#define KINETIS_PORT_RESET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))
+
+static const struct kinetis_pin_group *kinetis_pinctrl_find_group_by_name(
+				const struct kinetis_pinctrl_soc_info *info,
+				const char *name)
+{
+	const struct kinetis_pin_group *grp = NULL;
+	int i;
+
+	for (i = 0; i < info->ngroups; i++) {
+		if (!strcmp(info->groups[i].name, name)) {
+			grp = &info->groups[i];
+			break;
+		}
+	}
+
+	return grp;
+}
+
+static int kinetis_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->ngroups;
+}
+
+static const char *kinetis_get_group_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->groups[selector].name;
+}
+
+static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
+			struct device_node *np,
+			struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	const struct kinetis_pin_group *grp;
+	struct pinctrl_map *new_map;
+	struct device_node *parent;
+
+	/*
+	 * first find the group of this node and check if we need create
+	 * config maps for pins
+	 */
+	grp = kinetis_pinctrl_find_group_by_name(info, np->name);
+	if (!grp) {
+		dev_err(info->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	*map = new_map;
+	*num_maps = 1;
+
+	/* create mux map */
+	parent = of_get_parent(np);
+	if (!parent) {
+		dev_err(info->dev, "%s has no parent\n", np->name);
+		kfree(new_map);
+		return -EINVAL;
+	}
+	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map[0].data.mux.function = parent->name;
+	new_map[0].data.mux.group = np->name;
+	of_node_put(parent);
+
+	dev_dbg(info->dev, "maps: function %s group %s\n",
+		(*map)->data.mux.function, (*map)->data.mux.group);
+
+	return 0;
+}
+
+static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
+				struct pinctrl_map *map, unsigned num_maps)
+{
+	kfree(map);
+}
+
+static int kinetis_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->nfunctions;
+}
+
+static const char *kinetis_get_function_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->functions[selector].name;
+}
+
+static int kinetis_get_function_groups(struct pinctrl_dev *pctldev,
+				unsigned selector,
+				const char * const **groups,
+				unsigned * const num_groups)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	*groups = info->functions[selector].groups;
+	*num_groups = info->functions[selector].num_groups;
+
+	return 0;
+}
+
+static int kinetis_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
+				unsigned group)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	struct kinetis_pin_group *grp = &info->groups[group];
+	unsigned int npins = grp->npins;
+	struct kinetis_pin *pin;
+	int i;
+
+	for (i = 0; i < npins; i++) {
+		pin = &grp->pins[i];
+		KINETIS_PORT_WR(kpctl->base, pcr[pin->mux_reg], pin->mux_mode);
+	}
+
+	return 0;
+}
+
+static const struct pinctrl_ops kinetis_pctrl_ops = {
+	.get_groups_count = kinetis_get_groups_count,
+	.get_group_name = kinetis_get_group_name,
+	.dt_node_to_map = kinetis_dt_node_to_map,
+	.dt_free_map = kinetis_dt_free_map,
+};
+
+static const struct pinmux_ops kinetis_pmx_ops = {
+	.get_functions_count = kinetis_get_functions_count,
+	.get_function_name = kinetis_get_function_name,
+	.get_function_groups = kinetis_get_function_groups,
+	.set_mux = kinetis_set_mux,
+};
+
+static struct pinctrl_desc kinetis_pinctrl_desc = {
+	.pctlops = &kinetis_pctrl_ops,
+	.pmxops = &kinetis_pmx_ops,
+	.owner = THIS_MODULE,
+};
+
+#define KINETIS_PIN_SIZE 8
+
+static int kinetis_pinctrl_parse_groups(struct device_node *np,
+				    struct kinetis_pin_group *grp,
+				    struct kinetis_pinctrl_soc_info *info,
+				    u32 index)
+{
+	int size;
+	const int pin_size = KINETIS_PIN_SIZE;
+	const __be32 *list;
+	int i;
+
+	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+	/* Initialise group */
+	grp->name = np->name;
+
+	list = of_get_property(np, "fsl,pins", &size);
+	if (!list) {
+		dev_err(info->dev, "no fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	/* we do not check return since it's safe node passed down */
+	if (!size || size % pin_size) {
+		dev_err(info->dev, "Invalid fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	grp->npins = size / pin_size;
+	grp->pins = devm_kzalloc(info->dev,
+				grp->npins * sizeof(struct kinetis_pin),
+				GFP_KERNEL);
+	if (!grp->pins)
+		return -ENOMEM;
+
+	for (i = 0; i < grp->npins; i++) {
+		grp->pins[i].mux_reg = be32_to_cpu(*list++);
+		grp->pins[i].mux_mode = be32_to_cpu(*list++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_parse_functions(struct device_node *np,
+				       struct kinetis_pinctrl_soc_info *info,
+				       u32 index)
+{
+	struct device_node *child;
+	struct kinetis_pmx_func *func;
+	struct kinetis_pin_group *grp;
+	static u32 grp_index;
+	u32 i = 0;
+
+	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+	func = &info->functions[index];
+
+	/* Initialise function */
+	func->name = np->name;
+	func->num_groups = of_get_child_count(np);
+	if (func->num_groups == 0) {
+		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
+		return -EINVAL;
+	}
+	func->groups = devm_kzalloc(info->dev,
+			func->num_groups * sizeof(char *), GFP_KERNEL);
+
+	for_each_child_of_node(np, child) {
+		func->groups[i] = child->name;
+		grp = &info->groups[grp_index++];
+		kinetis_pinctrl_parse_groups(child, grp, info, i++);
+	}
+
+	return 0;
+}
+
+/*
+ * Check if the DT contains pins in the direct child nodes. This indicates the
+ * newer DT format to store pins. This function returns true if the first found
+ * fsl,pins property is in a child of np. Otherwise false is returned.
+ */
+static bool kinetis_pinctrl_dt_is_flat_functions(struct device_node *np)
+{
+	struct device_node *function_np;
+	struct device_node *pinctrl_np;
+
+	for_each_child_of_node(np, function_np) {
+		if (of_property_read_bool(function_np, "fsl,pins"))
+			return true;
+
+		for_each_child_of_node(function_np, pinctrl_np) {
+			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
+				struct kinetis_pinctrl_soc_info *info)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *child;
+	u32 nfuncs = 0;
+	u32 i = 0;
+	bool flat_funcs;
+
+	if (!np)
+		return -ENODEV;
+
+	flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);
+	if (flat_funcs) {
+		nfuncs = 1;
+	} else {
+		nfuncs = of_get_child_count(np);
+		if (nfuncs <= 0) {
+			dev_err(&pdev->dev, "no functions defined\n");
+			return -EINVAL;
+		}
+	}
+
+	info->nfunctions = nfuncs;
+	info->functions = devm_kzalloc(&pdev->dev,
+				nfuncs * sizeof(struct kinetis_pmx_func),
+				GFP_KERNEL);
+	if (!info->functions)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		info->ngroups = of_get_child_count(np);
+	} else {
+		info->ngroups = 0;
+		for_each_child_of_node(np, child)
+			info->ngroups += of_get_child_count(child);
+	}
+	if (!(info->ngroups)) {
+		dev_err(&pdev->dev, "no groups found\n");
+		return -EINVAL;
+	}
+	info->groups = devm_kzalloc(&pdev->dev,
+			info->ngroups * sizeof(struct kinetis_pin_group),
+			GFP_KERNEL);
+	if (!info->groups)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		kinetis_pinctrl_parse_functions(np, info, 0);
+	} else {
+		for_each_child_of_node(np, child)
+			kinetis_pinctrl_parse_functions(child, info, i++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct kinetis_pinctrl *kpctl;
+	struct resource *res;
+	int ret;
+
+	kpctl = devm_kzalloc(&pdev->dev, sizeof(struct kinetis_pinctrl),
+					GFP_KERNEL);
+	if (!kpctl)
+		return -ENOMEM;
+
+	ret = of_alias_get_id(np, "pmx");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	kpctl->port_id = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	kpctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kpctl->base))
+		return PTR_ERR(kpctl->base);
+
+	kpctl->clk = of_clk_get(np, 0);
+	if (IS_ERR(kpctl->clk)) {
+		dev_err(&pdev->dev, "failed to get clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		return PTR_ERR(kpctl->clk);
+	}
+
+	ret = clk_prepare_enable(kpctl->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		goto err_clk_enable;
+	}
+
+	kpctl->info.dev = &pdev->dev;
+	ret = kinetis_pinctrl_probe_dt(pdev, &kpctl->info);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to probe dt properties\n");
+		return ret;
+	}
+
+	kpctl->dev = &pdev->dev;
+	kinetis_pinctrl_desc.name = dev_name(&pdev->dev);
+
+	platform_set_drvdata(pdev, kpctl);
+	kpctl->pctl = pinctrl_register(&kinetis_pinctrl_desc,
+					&pdev->dev, kpctl);
+	if (IS_ERR(kpctl->pctl)) {
+		dev_err(&pdev->dev, "could not register Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+		ret = PTR_ERR(kpctl->pctl);
+		goto err_pinctrl_register;
+	}
+
+	dev_info(&pdev->dev, "initialized Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+
+	return 0;
+
+err_pinctrl_register:
+
+err_clk_enable:
+
+	clk_put(kpctl->clk);
+
+	return ret;
+}
+
+static int kinetis_pinctrl_remove(struct platform_device *pdev)
+{
+	struct kinetis_pinctrl *kpctl = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(kpctl->pctl);
+	clk_disable_unprepare(kpctl->clk);
+	clk_put(kpctl->clk);
+	return 0;
+}
+
+static struct platform_driver kinetis_pinctrl_driver = {
+	.driver = {
+		.name = "kinetis-pinctrl",
+		.of_match_table = kinetis_pinctrl_of_match,
+	},
+	.probe = kinetis_pinctrl_probe,
+	.remove = kinetis_pinctrl_remove,
+};
+
+static int __init kinetis_pinctrl_init(void)
+{
+	return platform_driver_register(&kinetis_pinctrl_driver);
+}
+arch_initcall(kinetis_pinctrl_init);
+
+static void __exit kinetis_pinctrl_exit(void)
+{
+	platform_driver_unregister(&kinetis_pinctrl_driver);
+}
+module_exit(kinetis_pinctrl_exit);
+
+MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 681732f..5eaeeec 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -5,6 +5,12 @@
 #define CLOCK_CCLK		 1
 #define CLOCK_PCLK		 2
 #define CLOCK_PIT		 3
-#define CLOCK_END		 4
+#define CLOCK_PORTA		 4
+#define CLOCK_PORTB		 5
+#define CLOCK_PORTC		 6
+#define CLOCK_PORTD		 7
+#define CLOCK_PORTE		 8
+#define CLOCK_PORTF		 9
+#define CLOCK_END		10
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (10 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  2015-06-24 10:21     ` Paul Bolle
       [not found]   ` <1435094387-20146-8-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
  -1 siblings, 2 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This is very cheap and simple implementation of pinctrl driver
for Kinetis SoC - its primary role is to provide means for enabling UART
fuctionality on I/O PORT_E which will be utilized by the commits
yet to come.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 arch/arm/mach-kinetis/Kconfig                      |   6 +
 drivers/clk/clk-kinetis.c                          |  28 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |   8 +-
 9 files changed, 659 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
 create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
new file mode 100644
index 0000000..04798c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
@@ -0,0 +1,31 @@
+Freescale Kinetis IOMUX Controller
+
+This controller is largely based on i.MX IOMUX Controller. Please refer to
+fsl,imx-pinctrl.txt in this directory for more detailed description.
+
+Required properties:
+- compatible: Should be "fsl,kinetis-iomuxc".
+- reg: Should contain the physical address and length of the gpio/pinmux
+  register range.
+- clocks: Clock that drives this I/O port.
+- fsl,pins: Two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
+  a pin working on a specific function, CONFIG is the pad setting value
+  such as pull enable, pull select, drive strength enable. Please refer to
+  Kinetis datasheet for the valid pad config settings.
+
+Example:
+
+portE: pinmux@4004d000 {
+	compatible = "fsl,kinetis-padconf";
+	reg = <0x4004d000 0x1000>;
+	clocks = <&mcg CLOCK_PORTE>;
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8630aff..662447c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -980,6 +980,7 @@ config ARCH_KINETIS
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 770760f..f3f22b5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -11,9 +11,57 @@
 		pit1 = &pit1;
 		pit2 = &pit2;
 		pit3 = &pit3;
+		pmx0 = &portA;
+		pmx1 = &portB;
+		pmx2 = &portC;
+		pmx3 = &portD;
+		pmx4 = &portE;
+		pmx5 = &portF;
 	};
 
 	soc {
+		portA: pinmux@40049000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x40049000 0x1000>;
+			clocks = <&mcg CLOCK_PORTA>;
+			status = "disabled";
+		};
+
+		portB: pinmux@4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg CLOCK_PORTB>;
+			status = "disabled";
+		};
+
+		portC: pinmux@4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg CLOCK_PORTC>;
+			status = "disabled";
+		};
+
+		portD: pinmux@4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg CLOCK_PORTD>;
+			status = "disabled";
+		};
+
+		portE: pinmux@4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg CLOCK_PORTE>;
+			status = "disabled";
+		};
+
+		portF: pinmux@4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg CLOCK_PORTF>;
+			status = "disabled";
+		};
+
 		pit0: timer@40037100 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037100 0x10>;
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
index 300bcea..c9a9d3a 100644
--- a/arch/arm/mach-kinetis/Kconfig
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -1,8 +1,14 @@
 if ARCH_KINETIS
 
+config SOC_K70
+	bool
+	depends on ARCH_KINETIS
+	select PINCTRL_KINETIS
+
 config MACH_KINETIS
 	bool "Kinetis K70 based development board"
 	default y
+	select SOC_K70
 	help
 	  Say Y here if you are using Kinetis K70 based development board
 
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index dea1054..b6620c0 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -220,6 +220,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
 			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
 
+	/*
+	 * Port control clock gates,
+	 *   see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_PORTA] = clk_register_gate(NULL, "PORTA", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTA)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTA), 0, NULL);
+
+	clk[CLOCK_PORTB] = clk_register_gate(NULL, "PORTB", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTB)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTB), 0, NULL);
+
+	clk[CLOCK_PORTC] = clk_register_gate(NULL, "PORTC", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTC)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTC), 0, NULL);
+
+	clk[CLOCK_PORTD] = clk_register_gate(NULL, "PORTD", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTD)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTD), 0, NULL);
+
+	clk[CLOCK_PORTE] = clk_register_gate(NULL, "PORTE", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTE)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTE), 0, NULL);
+
+	clk[CLOCK_PORTF] = clk_register_gate(NULL, "PORTF", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..2d0dfa9 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -94,6 +94,14 @@ config PINCTRL_IMX7D
 	help
 	  Say Y here to enable the imx7d pinctrl driver
 
+config PINCTRL_KINETIS
+	bool "Kinetis pinctrl driver"
+	depends on OF
+	depends on SOC_K70
+	select PINMUX
+	help
+	  Say Y here to enable the Kinetis pinctrl driver
+
 config PINCTRL_VF610
 	bool "Freescale Vybrid VF610 pinctrl driver"
 	depends on SOC_VF610
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index 343cb43..8db5f4c 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6dl.o
 obj-$(CONFIG_PINCTRL_IMX6SL)	+= pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_IMX6SX)	+= pinctrl-imx6sx.o
 obj-$(CONFIG_PINCTRL_IMX7D)	+= pinctrl-imx7d.o
+obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o
 obj-$(CONFIG_PINCTRL_VF610)	+= pinctrl-vf610.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
diff --git a/drivers/pinctrl/freescale/pinctrl-kinetis.c b/drivers/pinctrl/freescale/pinctrl-kinetis.c
new file mode 100644
index 0000000..baa913e
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,529 @@
+/*
+ * pinctrl-kinetis.c - iomux for Kinetis MCUs
+ *
+ * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng@linaro.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+/**
+ * struct kinetis_pin_group - describes a single pin
+ * @mux_reg: the mux register for this pin.
+ * @mux_mode: the mux mode for this pin.
+ */
+struct kinetis_pin {
+	u32 mux_reg;
+	u32 mux_mode;
+};
+
+/**
+ * struct kinetis_pin_group - describes a pin group
+ * @name: the name of this specific pin group
+ * @npins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @pins: array of pins
+ */
+struct kinetis_pin_group {
+	const char *name;
+	unsigned npins;
+	struct kinetis_pin *pins;
+};
+
+/**
+ * struct kinetis_pmx_func - describes pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct kinetis_pmx_func {
+	const char *name;
+	const char **groups;
+	unsigned num_groups;
+};
+
+struct kinetis_pinctrl_soc_info {
+	struct device			*dev;
+	struct kinetis_pin_group	*groups;
+	unsigned int			ngroups;
+	struct kinetis_pmx_func		*functions;
+	unsigned int			nfunctions;
+};
+
+struct kinetis_pinctrl {
+	int				port_id;
+	struct device			*dev;
+	struct pinctrl_dev		*pctl;
+	void __iomem			*base;
+	struct clk			*clk;
+	struct kinetis_pinctrl_soc_info	info;
+};
+
+static const struct of_device_id kinetis_pinctrl_of_match[] = {
+	{ .compatible = "fsl,kinetis-padconf", },
+	{ /* sentinel */ }
+};
+
+/*
+ * PORTx register map
+ */
+struct kinetis_port_regs {
+	u32 pcr[32];	/* Pin Control Registers */
+	u32 gpclr;	/* Global Pin Control Low Register */
+	u32 gpchr;	/* Global Pin Control High Register */
+	u32 rsv0[6];
+	u32 isfr;	/* Interrupt Status Flag Register */
+	u32 rsv1[7];
+	u32 dfer;	/* Digital Filter Enable Register */
+	u32 dfcr;	/* Digital Filter Clock Register */
+	u32 dfwr;	/* Digital Filter Width Register */
+};
+
+/*
+ * PORTx registers base
+ */
+#define KINETIS_PORT_PTR(base, reg) \
+	(&(((struct kinetis_port_regs *)(base))->reg))
+#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_WR(base, reg, val) \
+		writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_SET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
+#define KINETIS_PORT_RESET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))
+
+static const struct kinetis_pin_group *kinetis_pinctrl_find_group_by_name(
+				const struct kinetis_pinctrl_soc_info *info,
+				const char *name)
+{
+	const struct kinetis_pin_group *grp = NULL;
+	int i;
+
+	for (i = 0; i < info->ngroups; i++) {
+		if (!strcmp(info->groups[i].name, name)) {
+			grp = &info->groups[i];
+			break;
+		}
+	}
+
+	return grp;
+}
+
+static int kinetis_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->ngroups;
+}
+
+static const char *kinetis_get_group_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->groups[selector].name;
+}
+
+static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
+			struct device_node *np,
+			struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	const struct kinetis_pin_group *grp;
+	struct pinctrl_map *new_map;
+	struct device_node *parent;
+
+	/*
+	 * first find the group of this node and check if we need create
+	 * config maps for pins
+	 */
+	grp = kinetis_pinctrl_find_group_by_name(info, np->name);
+	if (!grp) {
+		dev_err(info->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	*map = new_map;
+	*num_maps = 1;
+
+	/* create mux map */
+	parent = of_get_parent(np);
+	if (!parent) {
+		dev_err(info->dev, "%s has no parent\n", np->name);
+		kfree(new_map);
+		return -EINVAL;
+	}
+	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map[0].data.mux.function = parent->name;
+	new_map[0].data.mux.group = np->name;
+	of_node_put(parent);
+
+	dev_dbg(info->dev, "maps: function %s group %s\n",
+		(*map)->data.mux.function, (*map)->data.mux.group);
+
+	return 0;
+}
+
+static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
+				struct pinctrl_map *map, unsigned num_maps)
+{
+	kfree(map);
+}
+
+static int kinetis_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->nfunctions;
+}
+
+static const char *kinetis_get_function_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->functions[selector].name;
+}
+
+static int kinetis_get_function_groups(struct pinctrl_dev *pctldev,
+				unsigned selector,
+				const char * const **groups,
+				unsigned * const num_groups)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	*groups = info->functions[selector].groups;
+	*num_groups = info->functions[selector].num_groups;
+
+	return 0;
+}
+
+static int kinetis_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
+				unsigned group)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	struct kinetis_pin_group *grp = &info->groups[group];
+	unsigned int npins = grp->npins;
+	struct kinetis_pin *pin;
+	int i;
+
+	for (i = 0; i < npins; i++) {
+		pin = &grp->pins[i];
+		KINETIS_PORT_WR(kpctl->base, pcr[pin->mux_reg], pin->mux_mode);
+	}
+
+	return 0;
+}
+
+static const struct pinctrl_ops kinetis_pctrl_ops = {
+	.get_groups_count = kinetis_get_groups_count,
+	.get_group_name = kinetis_get_group_name,
+	.dt_node_to_map = kinetis_dt_node_to_map,
+	.dt_free_map = kinetis_dt_free_map,
+};
+
+static const struct pinmux_ops kinetis_pmx_ops = {
+	.get_functions_count = kinetis_get_functions_count,
+	.get_function_name = kinetis_get_function_name,
+	.get_function_groups = kinetis_get_function_groups,
+	.set_mux = kinetis_set_mux,
+};
+
+static struct pinctrl_desc kinetis_pinctrl_desc = {
+	.pctlops = &kinetis_pctrl_ops,
+	.pmxops = &kinetis_pmx_ops,
+	.owner = THIS_MODULE,
+};
+
+#define KINETIS_PIN_SIZE 8
+
+static int kinetis_pinctrl_parse_groups(struct device_node *np,
+				    struct kinetis_pin_group *grp,
+				    struct kinetis_pinctrl_soc_info *info,
+				    u32 index)
+{
+	int size;
+	const int pin_size = KINETIS_PIN_SIZE;
+	const __be32 *list;
+	int i;
+
+	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+	/* Initialise group */
+	grp->name = np->name;
+
+	list = of_get_property(np, "fsl,pins", &size);
+	if (!list) {
+		dev_err(info->dev, "no fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	/* we do not check return since it's safe node passed down */
+	if (!size || size % pin_size) {
+		dev_err(info->dev, "Invalid fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	grp->npins = size / pin_size;
+	grp->pins = devm_kzalloc(info->dev,
+				grp->npins * sizeof(struct kinetis_pin),
+				GFP_KERNEL);
+	if (!grp->pins)
+		return -ENOMEM;
+
+	for (i = 0; i < grp->npins; i++) {
+		grp->pins[i].mux_reg = be32_to_cpu(*list++);
+		grp->pins[i].mux_mode = be32_to_cpu(*list++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_parse_functions(struct device_node *np,
+				       struct kinetis_pinctrl_soc_info *info,
+				       u32 index)
+{
+	struct device_node *child;
+	struct kinetis_pmx_func *func;
+	struct kinetis_pin_group *grp;
+	static u32 grp_index;
+	u32 i = 0;
+
+	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+	func = &info->functions[index];
+
+	/* Initialise function */
+	func->name = np->name;
+	func->num_groups = of_get_child_count(np);
+	if (func->num_groups == 0) {
+		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
+		return -EINVAL;
+	}
+	func->groups = devm_kzalloc(info->dev,
+			func->num_groups * sizeof(char *), GFP_KERNEL);
+
+	for_each_child_of_node(np, child) {
+		func->groups[i] = child->name;
+		grp = &info->groups[grp_index++];
+		kinetis_pinctrl_parse_groups(child, grp, info, i++);
+	}
+
+	return 0;
+}
+
+/*
+ * Check if the DT contains pins in the direct child nodes. This indicates the
+ * newer DT format to store pins. This function returns true if the first found
+ * fsl,pins property is in a child of np. Otherwise false is returned.
+ */
+static bool kinetis_pinctrl_dt_is_flat_functions(struct device_node *np)
+{
+	struct device_node *function_np;
+	struct device_node *pinctrl_np;
+
+	for_each_child_of_node(np, function_np) {
+		if (of_property_read_bool(function_np, "fsl,pins"))
+			return true;
+
+		for_each_child_of_node(function_np, pinctrl_np) {
+			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
+				struct kinetis_pinctrl_soc_info *info)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *child;
+	u32 nfuncs = 0;
+	u32 i = 0;
+	bool flat_funcs;
+
+	if (!np)
+		return -ENODEV;
+
+	flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);
+	if (flat_funcs) {
+		nfuncs = 1;
+	} else {
+		nfuncs = of_get_child_count(np);
+		if (nfuncs <= 0) {
+			dev_err(&pdev->dev, "no functions defined\n");
+			return -EINVAL;
+		}
+	}
+
+	info->nfunctions = nfuncs;
+	info->functions = devm_kzalloc(&pdev->dev,
+				nfuncs * sizeof(struct kinetis_pmx_func),
+				GFP_KERNEL);
+	if (!info->functions)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		info->ngroups = of_get_child_count(np);
+	} else {
+		info->ngroups = 0;
+		for_each_child_of_node(np, child)
+			info->ngroups += of_get_child_count(child);
+	}
+	if (!(info->ngroups)) {
+		dev_err(&pdev->dev, "no groups found\n");
+		return -EINVAL;
+	}
+	info->groups = devm_kzalloc(&pdev->dev,
+			info->ngroups * sizeof(struct kinetis_pin_group),
+			GFP_KERNEL);
+	if (!info->groups)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		kinetis_pinctrl_parse_functions(np, info, 0);
+	} else {
+		for_each_child_of_node(np, child)
+			kinetis_pinctrl_parse_functions(child, info, i++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct kinetis_pinctrl *kpctl;
+	struct resource *res;
+	int ret;
+
+	kpctl = devm_kzalloc(&pdev->dev, sizeof(struct kinetis_pinctrl),
+					GFP_KERNEL);
+	if (!kpctl)
+		return -ENOMEM;
+
+	ret = of_alias_get_id(np, "pmx");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	kpctl->port_id = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	kpctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kpctl->base))
+		return PTR_ERR(kpctl->base);
+
+	kpctl->clk = of_clk_get(np, 0);
+	if (IS_ERR(kpctl->clk)) {
+		dev_err(&pdev->dev, "failed to get clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		return PTR_ERR(kpctl->clk);
+	}
+
+	ret = clk_prepare_enable(kpctl->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		goto err_clk_enable;
+	}
+
+	kpctl->info.dev = &pdev->dev;
+	ret = kinetis_pinctrl_probe_dt(pdev, &kpctl->info);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to probe dt properties\n");
+		return ret;
+	}
+
+	kpctl->dev = &pdev->dev;
+	kinetis_pinctrl_desc.name = dev_name(&pdev->dev);
+
+	platform_set_drvdata(pdev, kpctl);
+	kpctl->pctl = pinctrl_register(&kinetis_pinctrl_desc,
+					&pdev->dev, kpctl);
+	if (IS_ERR(kpctl->pctl)) {
+		dev_err(&pdev->dev, "could not register Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+		ret = PTR_ERR(kpctl->pctl);
+		goto err_pinctrl_register;
+	}
+
+	dev_info(&pdev->dev, "initialized Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+
+	return 0;
+
+err_pinctrl_register:
+
+err_clk_enable:
+
+	clk_put(kpctl->clk);
+
+	return ret;
+}
+
+static int kinetis_pinctrl_remove(struct platform_device *pdev)
+{
+	struct kinetis_pinctrl *kpctl = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(kpctl->pctl);
+	clk_disable_unprepare(kpctl->clk);
+	clk_put(kpctl->clk);
+	return 0;
+}
+
+static struct platform_driver kinetis_pinctrl_driver = {
+	.driver = {
+		.name = "kinetis-pinctrl",
+		.of_match_table = kinetis_pinctrl_of_match,
+	},
+	.probe = kinetis_pinctrl_probe,
+	.remove = kinetis_pinctrl_remove,
+};
+
+static int __init kinetis_pinctrl_init(void)
+{
+	return platform_driver_register(&kinetis_pinctrl_driver);
+}
+arch_initcall(kinetis_pinctrl_init);
+
+static void __exit kinetis_pinctrl_exit(void)
+{
+	platform_driver_unregister(&kinetis_pinctrl_driver);
+}
+module_exit(kinetis_pinctrl_exit);
+
+MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 681732f..5eaeeec 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -5,6 +5,12 @@
 #define CLOCK_CCLK		 1
 #define CLOCK_PCLK		 2
 #define CLOCK_PIT		 3
-#define CLOCK_END		 4
+#define CLOCK_PORTA		 4
+#define CLOCK_PORTB		 5
+#define CLOCK_PORTC		 6
+#define CLOCK_PORTD		 7
+#define CLOCK_PORTE		 8
+#define CLOCK_PORTF		 9
+#define CLOCK_END		10
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
                     ` (4 preceding siblings ...)
  2015-06-23 21:19   ` [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC Paul Osmialowski
@ 2015-06-23 21:19   ` Paul Osmialowski
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This is very cheap and simple implementation of pinctrl driver
for Kinetis SoC - its primary role is to provide means for enabling UART
fuctionality on I/O PORT_E which will be utilized by the commits
yet to come.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 arch/arm/mach-kinetis/Kconfig                      |   6 +
 drivers/clk/clk-kinetis.c                          |  28 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
 include/dt-bindings/clock/kinetis-mcg.h            |   8 +-
 9 files changed, 659 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
 create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
new file mode 100644
index 0000000..04798c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
@@ -0,0 +1,31 @@
+Freescale Kinetis IOMUX Controller
+
+This controller is largely based on i.MX IOMUX Controller. Please refer to
+fsl,imx-pinctrl.txt in this directory for more detailed description.
+
+Required properties:
+- compatible: Should be "fsl,kinetis-iomuxc".
+- reg: Should contain the physical address and length of the gpio/pinmux
+  register range.
+- clocks: Clock that drives this I/O port.
+- fsl,pins: Two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
+  a pin working on a specific function, CONFIG is the pad setting value
+  such as pull enable, pull select, drive strength enable. Please refer to
+  Kinetis datasheet for the valid pad config settings.
+
+Example:
+
+portE: pinmux@4004d000 {
+	compatible = "fsl,kinetis-padconf";
+	reg = <0x4004d000 0x1000>;
+	clocks = <&mcg CLOCK_PORTE>;
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8630aff..662447c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -980,6 +980,7 @@ config ARCH_KINETIS
 	select ARM_CPU_IDLE_QUIRKS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 770760f..f3f22b5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -11,9 +11,57 @@
 		pit1 = &pit1;
 		pit2 = &pit2;
 		pit3 = &pit3;
+		pmx0 = &portA;
+		pmx1 = &portB;
+		pmx2 = &portC;
+		pmx3 = &portD;
+		pmx4 = &portE;
+		pmx5 = &portF;
 	};
 
 	soc {
+		portA: pinmux@40049000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x40049000 0x1000>;
+			clocks = <&mcg CLOCK_PORTA>;
+			status = "disabled";
+		};
+
+		portB: pinmux@4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg CLOCK_PORTB>;
+			status = "disabled";
+		};
+
+		portC: pinmux@4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg CLOCK_PORTC>;
+			status = "disabled";
+		};
+
+		portD: pinmux@4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg CLOCK_PORTD>;
+			status = "disabled";
+		};
+
+		portE: pinmux@4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg CLOCK_PORTE>;
+			status = "disabled";
+		};
+
+		portF: pinmux@4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg CLOCK_PORTF>;
+			status = "disabled";
+		};
+
 		pit0: timer@40037100 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037100 0x10>;
diff --git a/arch/arm/mach-kinetis/Kconfig b/arch/arm/mach-kinetis/Kconfig
index 300bcea..c9a9d3a 100644
--- a/arch/arm/mach-kinetis/Kconfig
+++ b/arch/arm/mach-kinetis/Kconfig
@@ -1,8 +1,14 @@
 if ARCH_KINETIS
 
+config SOC_K70
+	bool
+	depends on ARCH_KINETIS
+	select PINCTRL_KINETIS
+
 config MACH_KINETIS
 	bool "Kinetis K70 based development board"
 	default y
+	select SOC_K70
 	help
 	  Say Y here if you are using Kinetis K70 based development board
 
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index dea1054..b6620c0 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -220,6 +220,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PIT)]),
 			KINETIS_CG_IDX(KINETIS_CG_PIT), 0, NULL);
 
+	/*
+	 * Port control clock gates,
+	 *   see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_PORTA] = clk_register_gate(NULL, "PORTA", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTA)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTA), 0, NULL);
+
+	clk[CLOCK_PORTB] = clk_register_gate(NULL, "PORTB", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTB)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTB), 0, NULL);
+
+	clk[CLOCK_PORTC] = clk_register_gate(NULL, "PORTC", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTC)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTC), 0, NULL);
+
+	clk[CLOCK_PORTD] = clk_register_gate(NULL, "PORTD", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTD)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTD), 0, NULL);
+
+	clk[CLOCK_PORTE] = clk_register_gate(NULL, "PORTE", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTE)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTE), 0, NULL);
+
+	clk[CLOCK_PORTF] = clk_register_gate(NULL, "PORTF", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
+			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..2d0dfa9 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -94,6 +94,14 @@ config PINCTRL_IMX7D
 	help
 	  Say Y here to enable the imx7d pinctrl driver
 
+config PINCTRL_KINETIS
+	bool "Kinetis pinctrl driver"
+	depends on OF
+	depends on SOC_K70
+	select PINMUX
+	help
+	  Say Y here to enable the Kinetis pinctrl driver
+
 config PINCTRL_VF610
 	bool "Freescale Vybrid VF610 pinctrl driver"
 	depends on SOC_VF610
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index 343cb43..8db5f4c 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q)	+= pinctrl-imx6dl.o
 obj-$(CONFIG_PINCTRL_IMX6SL)	+= pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_IMX6SX)	+= pinctrl-imx6sx.o
 obj-$(CONFIG_PINCTRL_IMX7D)	+= pinctrl-imx7d.o
+obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o
 obj-$(CONFIG_PINCTRL_VF610)	+= pinctrl-vf610.o
 obj-$(CONFIG_PINCTRL_MXS)	+= pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)	+= pinctrl-imx23.o
diff --git a/drivers/pinctrl/freescale/pinctrl-kinetis.c b/drivers/pinctrl/freescale/pinctrl-kinetis.c
new file mode 100644
index 0000000..baa913e
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,529 @@
+/*
+ * pinctrl-kinetis.c - iomux for Kinetis MCUs
+ *
+ * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+/**
+ * struct kinetis_pin_group - describes a single pin
+ * @mux_reg: the mux register for this pin.
+ * @mux_mode: the mux mode for this pin.
+ */
+struct kinetis_pin {
+	u32 mux_reg;
+	u32 mux_mode;
+};
+
+/**
+ * struct kinetis_pin_group - describes a pin group
+ * @name: the name of this specific pin group
+ * @npins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @pins: array of pins
+ */
+struct kinetis_pin_group {
+	const char *name;
+	unsigned npins;
+	struct kinetis_pin *pins;
+};
+
+/**
+ * struct kinetis_pmx_func - describes pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct kinetis_pmx_func {
+	const char *name;
+	const char **groups;
+	unsigned num_groups;
+};
+
+struct kinetis_pinctrl_soc_info {
+	struct device			*dev;
+	struct kinetis_pin_group	*groups;
+	unsigned int			ngroups;
+	struct kinetis_pmx_func		*functions;
+	unsigned int			nfunctions;
+};
+
+struct kinetis_pinctrl {
+	int				port_id;
+	struct device			*dev;
+	struct pinctrl_dev		*pctl;
+	void __iomem			*base;
+	struct clk			*clk;
+	struct kinetis_pinctrl_soc_info	info;
+};
+
+static const struct of_device_id kinetis_pinctrl_of_match[] = {
+	{ .compatible = "fsl,kinetis-padconf", },
+	{ /* sentinel */ }
+};
+
+/*
+ * PORTx register map
+ */
+struct kinetis_port_regs {
+	u32 pcr[32];	/* Pin Control Registers */
+	u32 gpclr;	/* Global Pin Control Low Register */
+	u32 gpchr;	/* Global Pin Control High Register */
+	u32 rsv0[6];
+	u32 isfr;	/* Interrupt Status Flag Register */
+	u32 rsv1[7];
+	u32 dfer;	/* Digital Filter Enable Register */
+	u32 dfcr;	/* Digital Filter Clock Register */
+	u32 dfwr;	/* Digital Filter Width Register */
+};
+
+/*
+ * PORTx registers base
+ */
+#define KINETIS_PORT_PTR(base, reg) \
+	(&(((struct kinetis_port_regs *)(base))->reg))
+#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_WR(base, reg, val) \
+		writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
+#define KINETIS_PORT_SET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
+#define KINETIS_PORT_RESET(base, reg, mask) \
+	KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))
+
+static const struct kinetis_pin_group *kinetis_pinctrl_find_group_by_name(
+				const struct kinetis_pinctrl_soc_info *info,
+				const char *name)
+{
+	const struct kinetis_pin_group *grp = NULL;
+	int i;
+
+	for (i = 0; i < info->ngroups; i++) {
+		if (!strcmp(info->groups[i].name, name)) {
+			grp = &info->groups[i];
+			break;
+		}
+	}
+
+	return grp;
+}
+
+static int kinetis_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->ngroups;
+}
+
+static const char *kinetis_get_group_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->groups[selector].name;
+}
+
+static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
+			struct device_node *np,
+			struct pinctrl_map **map, unsigned *num_maps)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	const struct kinetis_pin_group *grp;
+	struct pinctrl_map *new_map;
+	struct device_node *parent;
+
+	/*
+	 * first find the group of this node and check if we need create
+	 * config maps for pins
+	 */
+	grp = kinetis_pinctrl_find_group_by_name(info, np->name);
+	if (!grp) {
+		dev_err(info->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	*map = new_map;
+	*num_maps = 1;
+
+	/* create mux map */
+	parent = of_get_parent(np);
+	if (!parent) {
+		dev_err(info->dev, "%s has no parent\n", np->name);
+		kfree(new_map);
+		return -EINVAL;
+	}
+	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map[0].data.mux.function = parent->name;
+	new_map[0].data.mux.group = np->name;
+	of_node_put(parent);
+
+	dev_dbg(info->dev, "maps: function %s group %s\n",
+		(*map)->data.mux.function, (*map)->data.mux.group);
+
+	return 0;
+}
+
+static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
+				struct pinctrl_map *map, unsigned num_maps)
+{
+	kfree(map);
+}
+
+static int kinetis_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->nfunctions;
+}
+
+static const char *kinetis_get_function_name(struct pinctrl_dev *pctldev,
+				unsigned selector)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	return info->functions[selector].name;
+}
+
+static int kinetis_get_function_groups(struct pinctrl_dev *pctldev,
+				unsigned selector,
+				const char * const **groups,
+				unsigned * const num_groups)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+
+	*groups = info->functions[selector].groups;
+	*num_groups = info->functions[selector].num_groups;
+
+	return 0;
+}
+
+static int kinetis_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
+				unsigned group)
+{
+	struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
+	struct kinetis_pin_group *grp = &info->groups[group];
+	unsigned int npins = grp->npins;
+	struct kinetis_pin *pin;
+	int i;
+
+	for (i = 0; i < npins; i++) {
+		pin = &grp->pins[i];
+		KINETIS_PORT_WR(kpctl->base, pcr[pin->mux_reg], pin->mux_mode);
+	}
+
+	return 0;
+}
+
+static const struct pinctrl_ops kinetis_pctrl_ops = {
+	.get_groups_count = kinetis_get_groups_count,
+	.get_group_name = kinetis_get_group_name,
+	.dt_node_to_map = kinetis_dt_node_to_map,
+	.dt_free_map = kinetis_dt_free_map,
+};
+
+static const struct pinmux_ops kinetis_pmx_ops = {
+	.get_functions_count = kinetis_get_functions_count,
+	.get_function_name = kinetis_get_function_name,
+	.get_function_groups = kinetis_get_function_groups,
+	.set_mux = kinetis_set_mux,
+};
+
+static struct pinctrl_desc kinetis_pinctrl_desc = {
+	.pctlops = &kinetis_pctrl_ops,
+	.pmxops = &kinetis_pmx_ops,
+	.owner = THIS_MODULE,
+};
+
+#define KINETIS_PIN_SIZE 8
+
+static int kinetis_pinctrl_parse_groups(struct device_node *np,
+				    struct kinetis_pin_group *grp,
+				    struct kinetis_pinctrl_soc_info *info,
+				    u32 index)
+{
+	int size;
+	const int pin_size = KINETIS_PIN_SIZE;
+	const __be32 *list;
+	int i;
+
+	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+	/* Initialise group */
+	grp->name = np->name;
+
+	list = of_get_property(np, "fsl,pins", &size);
+	if (!list) {
+		dev_err(info->dev, "no fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	/* we do not check return since it's safe node passed down */
+	if (!size || size % pin_size) {
+		dev_err(info->dev, "Invalid fsl,pins property in node %s\n",
+					np->full_name);
+		return -EINVAL;
+	}
+
+	grp->npins = size / pin_size;
+	grp->pins = devm_kzalloc(info->dev,
+				grp->npins * sizeof(struct kinetis_pin),
+				GFP_KERNEL);
+	if (!grp->pins)
+		return -ENOMEM;
+
+	for (i = 0; i < grp->npins; i++) {
+		grp->pins[i].mux_reg = be32_to_cpu(*list++);
+		grp->pins[i].mux_mode = be32_to_cpu(*list++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_parse_functions(struct device_node *np,
+				       struct kinetis_pinctrl_soc_info *info,
+				       u32 index)
+{
+	struct device_node *child;
+	struct kinetis_pmx_func *func;
+	struct kinetis_pin_group *grp;
+	static u32 grp_index;
+	u32 i = 0;
+
+	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+	func = &info->functions[index];
+
+	/* Initialise function */
+	func->name = np->name;
+	func->num_groups = of_get_child_count(np);
+	if (func->num_groups == 0) {
+		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
+		return -EINVAL;
+	}
+	func->groups = devm_kzalloc(info->dev,
+			func->num_groups * sizeof(char *), GFP_KERNEL);
+
+	for_each_child_of_node(np, child) {
+		func->groups[i] = child->name;
+		grp = &info->groups[grp_index++];
+		kinetis_pinctrl_parse_groups(child, grp, info, i++);
+	}
+
+	return 0;
+}
+
+/*
+ * Check if the DT contains pins in the direct child nodes. This indicates the
+ * newer DT format to store pins. This function returns true if the first found
+ * fsl,pins property is in a child of np. Otherwise false is returned.
+ */
+static bool kinetis_pinctrl_dt_is_flat_functions(struct device_node *np)
+{
+	struct device_node *function_np;
+	struct device_node *pinctrl_np;
+
+	for_each_child_of_node(np, function_np) {
+		if (of_property_read_bool(function_np, "fsl,pins"))
+			return true;
+
+		for_each_child_of_node(function_np, pinctrl_np) {
+			if (of_property_read_bool(pinctrl_np, "fsl,pins"))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
+				struct kinetis_pinctrl_soc_info *info)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *child;
+	u32 nfuncs = 0;
+	u32 i = 0;
+	bool flat_funcs;
+
+	if (!np)
+		return -ENODEV;
+
+	flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);
+	if (flat_funcs) {
+		nfuncs = 1;
+	} else {
+		nfuncs = of_get_child_count(np);
+		if (nfuncs <= 0) {
+			dev_err(&pdev->dev, "no functions defined\n");
+			return -EINVAL;
+		}
+	}
+
+	info->nfunctions = nfuncs;
+	info->functions = devm_kzalloc(&pdev->dev,
+				nfuncs * sizeof(struct kinetis_pmx_func),
+				GFP_KERNEL);
+	if (!info->functions)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		info->ngroups = of_get_child_count(np);
+	} else {
+		info->ngroups = 0;
+		for_each_child_of_node(np, child)
+			info->ngroups += of_get_child_count(child);
+	}
+	if (!(info->ngroups)) {
+		dev_err(&pdev->dev, "no groups found\n");
+		return -EINVAL;
+	}
+	info->groups = devm_kzalloc(&pdev->dev,
+			info->ngroups * sizeof(struct kinetis_pin_group),
+			GFP_KERNEL);
+	if (!info->groups)
+		return -ENOMEM;
+
+	if (flat_funcs) {
+		kinetis_pinctrl_parse_functions(np, info, 0);
+	} else {
+		for_each_child_of_node(np, child)
+			kinetis_pinctrl_parse_functions(child, info, i++);
+	}
+
+	return 0;
+}
+
+static int kinetis_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct kinetis_pinctrl *kpctl;
+	struct resource *res;
+	int ret;
+
+	kpctl = devm_kzalloc(&pdev->dev, sizeof(struct kinetis_pinctrl),
+					GFP_KERNEL);
+	if (!kpctl)
+		return -ENOMEM;
+
+	ret = of_alias_get_id(np, "pmx");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	kpctl->port_id = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	kpctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(kpctl->base))
+		return PTR_ERR(kpctl->base);
+
+	kpctl->clk = of_clk_get(np, 0);
+	if (IS_ERR(kpctl->clk)) {
+		dev_err(&pdev->dev, "failed to get clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		return PTR_ERR(kpctl->clk);
+	}
+
+	ret = clk_prepare_enable(kpctl->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock for PORT_%c\n",
+					'A' + kpctl->port_id);
+		goto err_clk_enable;
+	}
+
+	kpctl->info.dev = &pdev->dev;
+	ret = kinetis_pinctrl_probe_dt(pdev, &kpctl->info);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to probe dt properties\n");
+		return ret;
+	}
+
+	kpctl->dev = &pdev->dev;
+	kinetis_pinctrl_desc.name = dev_name(&pdev->dev);
+
+	platform_set_drvdata(pdev, kpctl);
+	kpctl->pctl = pinctrl_register(&kinetis_pinctrl_desc,
+					&pdev->dev, kpctl);
+	if (IS_ERR(kpctl->pctl)) {
+		dev_err(&pdev->dev, "could not register Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+		ret = PTR_ERR(kpctl->pctl);
+		goto err_pinctrl_register;
+	}
+
+	dev_info(&pdev->dev, "initialized Kinetis I/O PORT_%c\n",
+					'A' + kpctl->port_id);
+
+	return 0;
+
+err_pinctrl_register:
+
+err_clk_enable:
+
+	clk_put(kpctl->clk);
+
+	return ret;
+}
+
+static int kinetis_pinctrl_remove(struct platform_device *pdev)
+{
+	struct kinetis_pinctrl *kpctl = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(kpctl->pctl);
+	clk_disable_unprepare(kpctl->clk);
+	clk_put(kpctl->clk);
+	return 0;
+}
+
+static struct platform_driver kinetis_pinctrl_driver = {
+	.driver = {
+		.name = "kinetis-pinctrl",
+		.of_match_table = kinetis_pinctrl_of_match,
+	},
+	.probe = kinetis_pinctrl_probe,
+	.remove = kinetis_pinctrl_remove,
+};
+
+static int __init kinetis_pinctrl_init(void)
+{
+	return platform_driver_register(&kinetis_pinctrl_driver);
+}
+arch_initcall(kinetis_pinctrl_init);
+
+static void __exit kinetis_pinctrl_exit(void)
+{
+	platform_driver_unregister(&kinetis_pinctrl_driver);
+}
+module_exit(kinetis_pinctrl_exit);
+
+MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 681732f..5eaeeec 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -5,6 +5,12 @@
 #define CLOCK_CCLK		 1
 #define CLOCK_PCLK		 2
 #define CLOCK_PIT		 3
-#define CLOCK_END		 4
+#define CLOCK_PORTA		 4
+#define CLOCK_PORTB		 5
+#define CLOCK_PORTC		 6
+#define CLOCK_PORTD		 7
+#define CLOCK_PORTE		 8
+#define CLOCK_PORTF		 9
+#define CLOCK_END		10
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (11 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Surprisingly small amount of work was required in order to extend already
existing eDMA driver with the support for Kinetis SoC architecture.

Note that <mach/memory.h> is needed (which is denoted by
CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
operation of DMA allocation functions.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
 arch/arm/Kconfig                                   |  4 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
 arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 15 ++++
 drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
 include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
 7 files changed, 235 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..e1ee406 100644
--- a/Documentation/devicetree/bindings/dma/fsl-edma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-edma.txt
@@ -9,6 +9,7 @@ group, DMAMUX0 or DMAMUX1, but not both.
 Required properties:
 - compatible :
 	- "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+	- "fsl,kinetis-edma" for eDMA used similar to that on Kinetis SoC
 - reg : Specifies base physical address(s) and size of the eDMA registers.
 	The 1st region is eDMA control register's address and size.
 	The 2nd and the 3rd regions are programmable channel multiplexing
@@ -16,7 +17,8 @@ Required properties:
 - interrupts : A list of interrupt-specifiers, one for each entry in
 	interrupt-names.
 - interrupt-names : Should contain:
-	"edma-tx" - the transmission interrupt
+	"edma-tx" - the transmission interrupt (Vybrid)
+	"edma-tx-n,m" - interrupt for channels n (0-15) and m (16-31) (Kinetis)
 	"edma-err" - the error interrupt
 - #dma-cells : Must be <2>.
 	The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
@@ -28,6 +30,7 @@ Required properties:
 - clock-names : A list of channel group clock names. Should contain:
 	"dmamux0" - clock name of mux0 group
 	"dmamux1" - clock name of mux1 group
+	"edma"    - clock gate for whole controller (Kinetis only)
 - clocks : A list of phandle and clock-specifier pairs, one for each entry in
 	clock-names.
 
@@ -54,6 +57,39 @@ edma0: dma-controller@40018000 {
 		<&clks VF610_CLK_DMAMUX1>;
 };
 
+edma: dma-controller@40008000 {
+	compatible = "fsl,kinetis-edma";
+	reg = <0x40008000 0x2000>, /* DMAC */
+		<0x40021000 0x1000>, /* DMAMUX0 */
+		<0x40022000 0x1000>; /* DMAMUX1 */
+	#dma-cells = <2>;
+	dma-channels = <32>;
+	interrupts =	 <0>,  <1>,  <2>,  <3>,
+			 <4>,  <5>,  <6>,  <7>,
+			 <8>,  <9>, <10>, <11>,
+			<12>, <13>, <14>, <15>,
+			<16>;
+	interrupt-names = "edma-tx-0,16",
+			  "edma-tx-1,17",
+			  "edma-tx-2,18",
+			  "edma-tx-3,19",
+			  "edma-tx-4,20",
+			  "edma-tx-5,21",
+			  "edma-tx-6,22",
+			  "edma-tx-7,23",
+			  "edma-tx-8,24",
+			  "edma-tx-9,25",
+			  "edma-tx-10,26",
+			  "edma-tx-11,27",
+			  "edma-tx-12,28",
+			  "edma-tx-13,29",
+			  "edma-tx-14,30",
+			  "edma-tx-15,31",
+			  "edma-err";
+	clocks = <&mcg CLOCK_EDMA>,
+		 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 662447c..154436a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -981,6 +981,10 @@ config ARCH_KINETIS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
 	select PINCTRL
+	select DMADEVICES
+	select FSL_EDMA
+	select DMA_OF
+	select NEED_MACH_MEMORY_H
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index f3f22b5..7638103 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -20,6 +20,40 @@
 	};
 
 	soc {
+		edma: dma-controller@40008000 {
+			compatible = "fsl,kinetis-edma";
+			reg = <0x40008000 0x2000>, /* DMAC */
+				<0x40021000 0x1000>, /* DMAMUX0 */
+				<0x40022000 0x1000>; /* DMAMUX1 */
+			#dma-cells = <2>;
+			dma-channels = <32>;
+			interrupts =	 <0>,  <1>,  <2>,  <3>,
+					 <4>,  <5>,  <6>,  <7>,
+					 <8>,  <9>, <10>, <11>,
+					<12>, <13>, <14>, <15>,
+					<16>;
+			interrupt-names = "edma-tx-0,16",
+					  "edma-tx-1,17",
+					  "edma-tx-2,18",
+					  "edma-tx-3,19",
+					  "edma-tx-4,20",
+					  "edma-tx-5,21",
+					  "edma-tx-6,22",
+					  "edma-tx-7,23",
+					  "edma-tx-8,24",
+					  "edma-tx-9,25",
+					  "edma-tx-10,26",
+					  "edma-tx-11,27",
+					  "edma-tx-12,28",
+					  "edma-tx-13,29",
+					  "edma-tx-14,30",
+					  "edma-tx-15,31",
+					  "edma-err";
+			clocks = <&mcg CLOCK_EDMA>,
+				 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux@40049000 {
 			compatible = "fsl,kinetis-padconf";
 			reg = <0x40049000 0x1000>;
diff --git a/arch/arm/mach-kinetis/include/mach/memory.h b/arch/arm/mach-kinetis/include/mach/memory.h
new file mode 100644
index 0000000..8bad034
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/memory.h
@@ -0,0 +1,61 @@
+/*
+ * Based on original code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_MEMORY_H
+#define _MACH_KINETIS_MEMORY_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * On Kinetis K70, consistent DMA memory resides in a special
+ * DDRAM alias region (non-cacheable DDRAM at 0x80000000).
+ *
+ */
+#define KINETIS_PHYS_DMA_OFFSET UL(0x80000000)
+
+/*
+ * Mask of the field used to distinguish DDRAM aliases
+ */
+#define KINETIS_DRAM_ALIAS_MASK UL(0xf8000000)
+
+/*
+ * This macro converts an address in the kernel run-time memory
+ * to an alias in the non-cacheable memory region
+ */
+#define KINETIS_DMA_ALIAS_ADDR(addr)					\
+		(((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK) |	\
+		(KINETIS_PHYS_DMA_OFFSET & KINETIS_DRAM_ALIAS_MASK))
+
+/*
+ * This macro converts an address in the kernel code or
+ * in the non-cacheable DMA region to an alias in
+ * the run-time kernel memory region
+ */
+#define KINETIS_PHYS_ALIAS_ADDR(addr) \
+		((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK)
+
+#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr)
+
+#define __arch_pfn_to_dma(dev, pfn) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(__pfn_to_phys(pfn)))
+
+#define __arch_dma_to_virt(dev, addr) \
+		((void *)KINETIS_PHYS_ALIAS_ADDR(addr))
+
+#define __arch_virt_to_dma(dev, addr) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(addr))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_MEMORY_H */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index b6620c0..454096c 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -248,6 +248,21 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
 			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
 
+	/*
+	 * DMA clock gates, see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_EDMA] = clk_register_gate(NULL, "EDMA", "CCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMA)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMA), 0, NULL);
+
+	clk[CLOCK_DMAMUX0] = clk_register_gate(NULL, "DMAMUX0", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX0)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX0), 0, NULL);
+
+	clk[CLOCK_DMAMUX1] = clk_register_gate(NULL, "DMAMUX1", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..655d819 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -161,14 +161,42 @@ struct fsl_edma_desc {
 	struct fsl_edma_sw_tcd		tcd[];
 };
 
+#ifdef CONFIG_ARCH_KINETIS
+static const char * const txirq_names[] = {
+	"edma-tx-0,16",
+	"edma-tx-1,17",
+	"edma-tx-2,18",
+	"edma-tx-3,19",
+	"edma-tx-4,20",
+	"edma-tx-5,21",
+	"edma-tx-6,22",
+	"edma-tx-7,23",
+	"edma-tx-8,24",
+	"edma-tx-9,25",
+	"edma-tx-10,26",
+	"edma-tx-11,27",
+	"edma-tx-12,28",
+	"edma-tx-13,29",
+	"edma-tx-14,30",
+	"edma-tx-15,31",
+};
+#endif
+
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+#ifdef CONFIG_ARCH_KINETIS
+	struct clk		*clk;
+#endif
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
+#ifdef CONFIG_ARCH_KINETIS
+	int			txirq[ARRAY_SIZE(txirq_names)];
+#else
 	int			txirq;
+#endif
 	int			errirq;
 	bool			big_endian;
 	struct fsl_edma_chan	chans[];
@@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+#ifndef CONFIG_ARCH_KINETIS
 static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 {
 	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
@@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 
 	return fsl_edma_err_handler(irq, dev_id);
 }
+#endif
 
 static void fsl_edma_issue_pending(struct dma_chan *chan)
 {
@@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
 }
 
 static int
-fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+fsl_edma_irq_init(struct platform_device *pdev,
+		  struct fsl_edma_engine *fsl_edma)
 {
 	int ret;
+#ifdef CONFIG_ARCH_KINETIS
+	int i;
 
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
+					txirq_names[i]);
+		if (fsl_edma->txirq[i] < 0) {
+			dev_err(&pdev->dev, "Can't get %s irq.\n",
+						txirq_names[i]);
+			return fsl_edma->txirq[i];
+		}
+	}
+#else
 	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
 	if (fsl_edma->txirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
 		return fsl_edma->txirq;
 	}
+#endif
 
 	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
 	if (fsl_edma->errirq < 0) {
@@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 		return fsl_edma->errirq;
 	}
 
+#ifdef CONFIG_ARCH_KINETIS
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
+			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
+			return  ret;
+		}
+	}
+#else
 	if (fsl_edma->txirq == fsl_edma->errirq) {
 		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
 				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
@@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
 			return  ret;
 		}
+#endif
 
 		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
 				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
@@ -825,7 +880,9 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
 			return  ret;
 		}
+#ifndef CONFIG_ARCH_KINETIS
 	}
+#endif
 
 	return 0;
 }
@@ -858,6 +915,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+#ifdef CONFIG_ARCH_KINETIS
+	fsl_edma->clk = devm_clk_get(&pdev->dev, "edma");
+	if (IS_ERR(fsl_edma->clk)) {
+		dev_err(&pdev->dev, "Missing EDMA clock.\n");
+		return PTR_ERR(fsl_edma->clk);
+	}
+
+	ret = clk_prepare_enable(fsl_edma->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "EDMA clk failed.\n");
+		return ret;
+	}
+#endif
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,11 +1027,19 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+#ifdef CONFIG_ARCH_KINETIS
+	clk_disable_unprepare(fsl_edma->clk);
+#endif
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+#ifdef CONFIG_ARCH_KINETIS
+	{ .compatible = "fsl,kinetis-edma", },
+#else
 	{ .compatible = "fsl,vf610-edma", },
+#endif
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 5eaeeec..d853c3c 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -11,6 +11,9 @@
 #define CLOCK_PORTD		 7
 #define CLOCK_PORTE		 8
 #define CLOCK_PORTF		 9
-#define CLOCK_END		10
+#define CLOCK_EDMA		10
+#define CLOCK_DMAMUX0		11
+#define CLOCK_DMAMUX1		12
+#define CLOCK_END		13
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Surprisingly small amount of work was required in order to extend already
existing eDMA driver with the support for Kinetis SoC architecture.

Note that <mach/memory.h> is needed (which is denoted by
CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
operation of DMA allocation functions.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
 arch/arm/Kconfig                                   |  4 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
 arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 15 ++++
 drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
 include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
 7 files changed, 235 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..e1ee406 100644
--- a/Documentation/devicetree/bindings/dma/fsl-edma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-edma.txt
@@ -9,6 +9,7 @@ group, DMAMUX0 or DMAMUX1, but not both.
 Required properties:
 - compatible :
 	- "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+	- "fsl,kinetis-edma" for eDMA used similar to that on Kinetis SoC
 - reg : Specifies base physical address(s) and size of the eDMA registers.
 	The 1st region is eDMA control register's address and size.
 	The 2nd and the 3rd regions are programmable channel multiplexing
@@ -16,7 +17,8 @@ Required properties:
 - interrupts : A list of interrupt-specifiers, one for each entry in
 	interrupt-names.
 - interrupt-names : Should contain:
-	"edma-tx" - the transmission interrupt
+	"edma-tx" - the transmission interrupt (Vybrid)
+	"edma-tx-n,m" - interrupt for channels n (0-15) and m (16-31) (Kinetis)
 	"edma-err" - the error interrupt
 - #dma-cells : Must be <2>.
 	The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
@@ -28,6 +30,7 @@ Required properties:
 - clock-names : A list of channel group clock names. Should contain:
 	"dmamux0" - clock name of mux0 group
 	"dmamux1" - clock name of mux1 group
+	"edma"    - clock gate for whole controller (Kinetis only)
 - clocks : A list of phandle and clock-specifier pairs, one for each entry in
 	clock-names.
 
@@ -54,6 +57,39 @@ edma0: dma-controller@40018000 {
 		<&clks VF610_CLK_DMAMUX1>;
 };
 
+edma: dma-controller@40008000 {
+	compatible = "fsl,kinetis-edma";
+	reg = <0x40008000 0x2000>, /* DMAC */
+		<0x40021000 0x1000>, /* DMAMUX0 */
+		<0x40022000 0x1000>; /* DMAMUX1 */
+	#dma-cells = <2>;
+	dma-channels = <32>;
+	interrupts =	 <0>,  <1>,  <2>,  <3>,
+			 <4>,  <5>,  <6>,  <7>,
+			 <8>,  <9>, <10>, <11>,
+			<12>, <13>, <14>, <15>,
+			<16>;
+	interrupt-names = "edma-tx-0,16",
+			  "edma-tx-1,17",
+			  "edma-tx-2,18",
+			  "edma-tx-3,19",
+			  "edma-tx-4,20",
+			  "edma-tx-5,21",
+			  "edma-tx-6,22",
+			  "edma-tx-7,23",
+			  "edma-tx-8,24",
+			  "edma-tx-9,25",
+			  "edma-tx-10,26",
+			  "edma-tx-11,27",
+			  "edma-tx-12,28",
+			  "edma-tx-13,29",
+			  "edma-tx-14,30",
+			  "edma-tx-15,31",
+			  "edma-err";
+	clocks = <&mcg CLOCK_EDMA>,
+		 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 662447c..154436a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -981,6 +981,10 @@ config ARCH_KINETIS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
 	select PINCTRL
+	select DMADEVICES
+	select FSL_EDMA
+	select DMA_OF
+	select NEED_MACH_MEMORY_H
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index f3f22b5..7638103 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -20,6 +20,40 @@
 	};
 
 	soc {
+		edma: dma-controller@40008000 {
+			compatible = "fsl,kinetis-edma";
+			reg = <0x40008000 0x2000>, /* DMAC */
+				<0x40021000 0x1000>, /* DMAMUX0 */
+				<0x40022000 0x1000>; /* DMAMUX1 */
+			#dma-cells = <2>;
+			dma-channels = <32>;
+			interrupts =	 <0>,  <1>,  <2>,  <3>,
+					 <4>,  <5>,  <6>,  <7>,
+					 <8>,  <9>, <10>, <11>,
+					<12>, <13>, <14>, <15>,
+					<16>;
+			interrupt-names = "edma-tx-0,16",
+					  "edma-tx-1,17",
+					  "edma-tx-2,18",
+					  "edma-tx-3,19",
+					  "edma-tx-4,20",
+					  "edma-tx-5,21",
+					  "edma-tx-6,22",
+					  "edma-tx-7,23",
+					  "edma-tx-8,24",
+					  "edma-tx-9,25",
+					  "edma-tx-10,26",
+					  "edma-tx-11,27",
+					  "edma-tx-12,28",
+					  "edma-tx-13,29",
+					  "edma-tx-14,30",
+					  "edma-tx-15,31",
+					  "edma-err";
+			clocks = <&mcg CLOCK_EDMA>,
+				 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux@40049000 {
 			compatible = "fsl,kinetis-padconf";
 			reg = <0x40049000 0x1000>;
diff --git a/arch/arm/mach-kinetis/include/mach/memory.h b/arch/arm/mach-kinetis/include/mach/memory.h
new file mode 100644
index 0000000..8bad034
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/memory.h
@@ -0,0 +1,61 @@
+/*
+ * Based on original code by Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev@emcraft.com>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_MEMORY_H
+#define _MACH_KINETIS_MEMORY_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * On Kinetis K70, consistent DMA memory resides in a special
+ * DDRAM alias region (non-cacheable DDRAM at 0x80000000).
+ *
+ */
+#define KINETIS_PHYS_DMA_OFFSET UL(0x80000000)
+
+/*
+ * Mask of the field used to distinguish DDRAM aliases
+ */
+#define KINETIS_DRAM_ALIAS_MASK UL(0xf8000000)
+
+/*
+ * This macro converts an address in the kernel run-time memory
+ * to an alias in the non-cacheable memory region
+ */
+#define KINETIS_DMA_ALIAS_ADDR(addr)					\
+		(((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK) |	\
+		(KINETIS_PHYS_DMA_OFFSET & KINETIS_DRAM_ALIAS_MASK))
+
+/*
+ * This macro converts an address in the kernel code or
+ * in the non-cacheable DMA region to an alias in
+ * the run-time kernel memory region
+ */
+#define KINETIS_PHYS_ALIAS_ADDR(addr) \
+		((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK)
+
+#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr)
+
+#define __arch_pfn_to_dma(dev, pfn) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(__pfn_to_phys(pfn)))
+
+#define __arch_dma_to_virt(dev, addr) \
+		((void *)KINETIS_PHYS_ALIAS_ADDR(addr))
+
+#define __arch_virt_to_dma(dev, addr) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(addr))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_MEMORY_H */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index b6620c0..454096c 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -248,6 +248,21 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
 			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
 
+	/*
+	 * DMA clock gates, see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_EDMA] = clk_register_gate(NULL, "EDMA", "CCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMA)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMA), 0, NULL);
+
+	clk[CLOCK_DMAMUX0] = clk_register_gate(NULL, "DMAMUX0", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX0)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX0), 0, NULL);
+
+	clk[CLOCK_DMAMUX1] = clk_register_gate(NULL, "DMAMUX1", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..655d819 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -161,14 +161,42 @@ struct fsl_edma_desc {
 	struct fsl_edma_sw_tcd		tcd[];
 };
 
+#ifdef CONFIG_ARCH_KINETIS
+static const char * const txirq_names[] = {
+	"edma-tx-0,16",
+	"edma-tx-1,17",
+	"edma-tx-2,18",
+	"edma-tx-3,19",
+	"edma-tx-4,20",
+	"edma-tx-5,21",
+	"edma-tx-6,22",
+	"edma-tx-7,23",
+	"edma-tx-8,24",
+	"edma-tx-9,25",
+	"edma-tx-10,26",
+	"edma-tx-11,27",
+	"edma-tx-12,28",
+	"edma-tx-13,29",
+	"edma-tx-14,30",
+	"edma-tx-15,31",
+};
+#endif
+
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+#ifdef CONFIG_ARCH_KINETIS
+	struct clk		*clk;
+#endif
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
+#ifdef CONFIG_ARCH_KINETIS
+	int			txirq[ARRAY_SIZE(txirq_names)];
+#else
 	int			txirq;
+#endif
 	int			errirq;
 	bool			big_endian;
 	struct fsl_edma_chan	chans[];
@@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+#ifndef CONFIG_ARCH_KINETIS
 static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 {
 	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
@@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 
 	return fsl_edma_err_handler(irq, dev_id);
 }
+#endif
 
 static void fsl_edma_issue_pending(struct dma_chan *chan)
 {
@@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
 }
 
 static int
-fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+fsl_edma_irq_init(struct platform_device *pdev,
+		  struct fsl_edma_engine *fsl_edma)
 {
 	int ret;
+#ifdef CONFIG_ARCH_KINETIS
+	int i;
 
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
+					txirq_names[i]);
+		if (fsl_edma->txirq[i] < 0) {
+			dev_err(&pdev->dev, "Can't get %s irq.\n",
+						txirq_names[i]);
+			return fsl_edma->txirq[i];
+		}
+	}
+#else
 	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
 	if (fsl_edma->txirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
 		return fsl_edma->txirq;
 	}
+#endif
 
 	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
 	if (fsl_edma->errirq < 0) {
@@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 		return fsl_edma->errirq;
 	}
 
+#ifdef CONFIG_ARCH_KINETIS
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
+			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
+			return  ret;
+		}
+	}
+#else
 	if (fsl_edma->txirq == fsl_edma->errirq) {
 		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
 				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
@@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
 			return  ret;
 		}
+#endif
 
 		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
 				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
@@ -825,7 +880,9 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
 			return  ret;
 		}
+#ifndef CONFIG_ARCH_KINETIS
 	}
+#endif
 
 	return 0;
 }
@@ -858,6 +915,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+#ifdef CONFIG_ARCH_KINETIS
+	fsl_edma->clk = devm_clk_get(&pdev->dev, "edma");
+	if (IS_ERR(fsl_edma->clk)) {
+		dev_err(&pdev->dev, "Missing EDMA clock.\n");
+		return PTR_ERR(fsl_edma->clk);
+	}
+
+	ret = clk_prepare_enable(fsl_edma->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "EDMA clk failed.\n");
+		return ret;
+	}
+#endif
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,11 +1027,19 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+#ifdef CONFIG_ARCH_KINETIS
+	clk_disable_unprepare(fsl_edma->clk);
+#endif
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+#ifdef CONFIG_ARCH_KINETIS
+	{ .compatible = "fsl,kinetis-edma", },
+#else
 	{ .compatible = "fsl,vf610-edma", },
+#endif
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 5eaeeec..d853c3c 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -11,6 +11,9 @@
 #define CLOCK_PORTD		 7
 #define CLOCK_PORTE		 8
 #define CLOCK_PORTF		 9
-#define CLOCK_END		10
+#define CLOCK_EDMA		10
+#define CLOCK_DMAMUX0		11
+#define CLOCK_DMAMUX1		12
+#define CLOCK_END		13
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

Surprisingly small amount of work was required in order to extend already
existing eDMA driver with the support for Kinetis SoC architecture.

Note that <mach/memory.h> is needed (which is denoted by
CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
operation of DMA allocation functions.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
 arch/arm/Kconfig                                   |  4 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
 arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 15 ++++
 drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
 include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
 7 files changed, 235 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..e1ee406 100644
--- a/Documentation/devicetree/bindings/dma/fsl-edma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-edma.txt
@@ -9,6 +9,7 @@ group, DMAMUX0 or DMAMUX1, but not both.
 Required properties:
 - compatible :
 	- "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+	- "fsl,kinetis-edma" for eDMA used similar to that on Kinetis SoC
 - reg : Specifies base physical address(s) and size of the eDMA registers.
 	The 1st region is eDMA control register's address and size.
 	The 2nd and the 3rd regions are programmable channel multiplexing
@@ -16,7 +17,8 @@ Required properties:
 - interrupts : A list of interrupt-specifiers, one for each entry in
 	interrupt-names.
 - interrupt-names : Should contain:
-	"edma-tx" - the transmission interrupt
+	"edma-tx" - the transmission interrupt (Vybrid)
+	"edma-tx-n,m" - interrupt for channels n (0-15) and m (16-31) (Kinetis)
 	"edma-err" - the error interrupt
 - #dma-cells : Must be <2>.
 	The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
@@ -28,6 +30,7 @@ Required properties:
 - clock-names : A list of channel group clock names. Should contain:
 	"dmamux0" - clock name of mux0 group
 	"dmamux1" - clock name of mux1 group
+	"edma"    - clock gate for whole controller (Kinetis only)
 - clocks : A list of phandle and clock-specifier pairs, one for each entry in
 	clock-names.
 
@@ -54,6 +57,39 @@ edma0: dma-controller@40018000 {
 		<&clks VF610_CLK_DMAMUX1>;
 };
 
+edma: dma-controller@40008000 {
+	compatible = "fsl,kinetis-edma";
+	reg = <0x40008000 0x2000>, /* DMAC */
+		<0x40021000 0x1000>, /* DMAMUX0 */
+		<0x40022000 0x1000>; /* DMAMUX1 */
+	#dma-cells = <2>;
+	dma-channels = <32>;
+	interrupts =	 <0>,  <1>,  <2>,  <3>,
+			 <4>,  <5>,  <6>,  <7>,
+			 <8>,  <9>, <10>, <11>,
+			<12>, <13>, <14>, <15>,
+			<16>;
+	interrupt-names = "edma-tx-0,16",
+			  "edma-tx-1,17",
+			  "edma-tx-2,18",
+			  "edma-tx-3,19",
+			  "edma-tx-4,20",
+			  "edma-tx-5,21",
+			  "edma-tx-6,22",
+			  "edma-tx-7,23",
+			  "edma-tx-8,24",
+			  "edma-tx-9,25",
+			  "edma-tx-10,26",
+			  "edma-tx-11,27",
+			  "edma-tx-12,28",
+			  "edma-tx-13,29",
+			  "edma-tx-14,30",
+			  "edma-tx-15,31",
+			  "edma-err";
+	clocks = <&mcg CLOCK_EDMA>,
+		 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 662447c..154436a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -981,6 +981,10 @@ config ARCH_KINETIS
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
 	select PINCTRL
+	select DMADEVICES
+	select FSL_EDMA
+	select DMA_OF
+	select NEED_MACH_MEMORY_H
 	select ZLIB_INFLATE_STACK_SAVING if ZLIB_INFLATE
 	help
 	  This enables support for the Freescale Kinetis MCUs
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index f3f22b5..7638103 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -20,6 +20,40 @@
 	};
 
 	soc {
+		edma: dma-controller@40008000 {
+			compatible = "fsl,kinetis-edma";
+			reg = <0x40008000 0x2000>, /* DMAC */
+				<0x40021000 0x1000>, /* DMAMUX0 */
+				<0x40022000 0x1000>; /* DMAMUX1 */
+			#dma-cells = <2>;
+			dma-channels = <32>;
+			interrupts =	 <0>,  <1>,  <2>,  <3>,
+					 <4>,  <5>,  <6>,  <7>,
+					 <8>,  <9>, <10>, <11>,
+					<12>, <13>, <14>, <15>,
+					<16>;
+			interrupt-names = "edma-tx-0,16",
+					  "edma-tx-1,17",
+					  "edma-tx-2,18",
+					  "edma-tx-3,19",
+					  "edma-tx-4,20",
+					  "edma-tx-5,21",
+					  "edma-tx-6,22",
+					  "edma-tx-7,23",
+					  "edma-tx-8,24",
+					  "edma-tx-9,25",
+					  "edma-tx-10,26",
+					  "edma-tx-11,27",
+					  "edma-tx-12,28",
+					  "edma-tx-13,29",
+					  "edma-tx-14,30",
+					  "edma-tx-15,31",
+					  "edma-err";
+			clocks = <&mcg CLOCK_EDMA>,
+				 <&mcg CLOCK_DMAMUX0>, <&mcg CLOCK_DMAMUX1>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux@40049000 {
 			compatible = "fsl,kinetis-padconf";
 			reg = <0x40049000 0x1000>;
diff --git a/arch/arm/mach-kinetis/include/mach/memory.h b/arch/arm/mach-kinetis/include/mach/memory.h
new file mode 100644
index 0000000..8bad034
--- /dev/null
+++ b/arch/arm/mach-kinetis/include/mach/memory.h
@@ -0,0 +1,61 @@
+/*
+ * Based on original code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * (C) Copyright 2011, 2012
+ * Emcraft Systems, <www.emcraft.com>
+ * Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef _MACH_KINETIS_MEMORY_H
+#define _MACH_KINETIS_MEMORY_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * On Kinetis K70, consistent DMA memory resides in a special
+ * DDRAM alias region (non-cacheable DDRAM at 0x80000000).
+ *
+ */
+#define KINETIS_PHYS_DMA_OFFSET UL(0x80000000)
+
+/*
+ * Mask of the field used to distinguish DDRAM aliases
+ */
+#define KINETIS_DRAM_ALIAS_MASK UL(0xf8000000)
+
+/*
+ * This macro converts an address in the kernel run-time memory
+ * to an alias in the non-cacheable memory region
+ */
+#define KINETIS_DMA_ALIAS_ADDR(addr)					\
+		(((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK) |	\
+		(KINETIS_PHYS_DMA_OFFSET & KINETIS_DRAM_ALIAS_MASK))
+
+/*
+ * This macro converts an address in the kernel code or
+ * in the non-cacheable DMA region to an alias in
+ * the run-time kernel memory region
+ */
+#define KINETIS_PHYS_ALIAS_ADDR(addr) \
+		((unsigned long)(addr) & ~KINETIS_DRAM_ALIAS_MASK)
+
+#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr)
+
+#define __arch_pfn_to_dma(dev, pfn) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(__pfn_to_phys(pfn)))
+
+#define __arch_dma_to_virt(dev, addr) \
+		((void *)KINETIS_PHYS_ALIAS_ADDR(addr))
+
+#define __arch_virt_to_dma(dev, addr) \
+		((dma_addr_t)KINETIS_DMA_ALIAS_ADDR(addr))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /*_MACH_KINETIS_MEMORY_H */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index b6620c0..454096c 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -248,6 +248,21 @@ static void __init kinetis_mcg_init(struct device_node *np)
 			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_PORTF)]),
 			KINETIS_CG_IDX(KINETIS_CG_PORTF), 0, NULL);
 
+	/*
+	 * DMA clock gates, see K70 Sub-Family Reference Manual, Rev. 3 pg. 223:
+	 */
+	clk[CLOCK_EDMA] = clk_register_gate(NULL, "EDMA", "CCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMA)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMA), 0, NULL);
+
+	clk[CLOCK_DMAMUX0] = clk_register_gate(NULL, "DMAMUX0", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX0)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX0), 0, NULL);
+
+	clk[CLOCK_DMAMUX1] = clk_register_gate(NULL, "DMAMUX1", "PCLK", 0,
+		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
+		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..655d819 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -161,14 +161,42 @@ struct fsl_edma_desc {
 	struct fsl_edma_sw_tcd		tcd[];
 };
 
+#ifdef CONFIG_ARCH_KINETIS
+static const char * const txirq_names[] = {
+	"edma-tx-0,16",
+	"edma-tx-1,17",
+	"edma-tx-2,18",
+	"edma-tx-3,19",
+	"edma-tx-4,20",
+	"edma-tx-5,21",
+	"edma-tx-6,22",
+	"edma-tx-7,23",
+	"edma-tx-8,24",
+	"edma-tx-9,25",
+	"edma-tx-10,26",
+	"edma-tx-11,27",
+	"edma-tx-12,28",
+	"edma-tx-13,29",
+	"edma-tx-14,30",
+	"edma-tx-15,31",
+};
+#endif
+
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+#ifdef CONFIG_ARCH_KINETIS
+	struct clk		*clk;
+#endif
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
+#ifdef CONFIG_ARCH_KINETIS
+	int			txirq[ARRAY_SIZE(txirq_names)];
+#else
 	int			txirq;
+#endif
 	int			errirq;
 	bool			big_endian;
 	struct fsl_edma_chan	chans[];
@@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+#ifndef CONFIG_ARCH_KINETIS
 static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 {
 	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
@@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
 
 	return fsl_edma_err_handler(irq, dev_id);
 }
+#endif
 
 static void fsl_edma_issue_pending(struct dma_chan *chan)
 {
@@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
 }
 
 static int
-fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+fsl_edma_irq_init(struct platform_device *pdev,
+		  struct fsl_edma_engine *fsl_edma)
 {
 	int ret;
+#ifdef CONFIG_ARCH_KINETIS
+	int i;
 
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
+					txirq_names[i]);
+		if (fsl_edma->txirq[i] < 0) {
+			dev_err(&pdev->dev, "Can't get %s irq.\n",
+						txirq_names[i]);
+			return fsl_edma->txirq[i];
+		}
+	}
+#else
 	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
 	if (fsl_edma->txirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
 		return fsl_edma->txirq;
 	}
+#endif
 
 	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
 	if (fsl_edma->errirq < 0) {
@@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 		return fsl_edma->errirq;
 	}
 
+#ifdef CONFIG_ARCH_KINETIS
+	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
+		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
+			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
+			return  ret;
+		}
+	}
+#else
 	if (fsl_edma->txirq == fsl_edma->errirq) {
 		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
 				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
@@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
 			return  ret;
 		}
+#endif
 
 		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
 				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
@@ -825,7 +880,9 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
 			return  ret;
 		}
+#ifndef CONFIG_ARCH_KINETIS
 	}
+#endif
 
 	return 0;
 }
@@ -858,6 +915,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+#ifdef CONFIG_ARCH_KINETIS
+	fsl_edma->clk = devm_clk_get(&pdev->dev, "edma");
+	if (IS_ERR(fsl_edma->clk)) {
+		dev_err(&pdev->dev, "Missing EDMA clock.\n");
+		return PTR_ERR(fsl_edma->clk);
+	}
+
+	ret = clk_prepare_enable(fsl_edma->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "EDMA clk failed.\n");
+		return ret;
+	}
+#endif
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,11 +1027,19 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+#ifdef CONFIG_ARCH_KINETIS
+	clk_disable_unprepare(fsl_edma->clk);
+#endif
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+#ifdef CONFIG_ARCH_KINETIS
+	{ .compatible = "fsl,kinetis-edma", },
+#else
 	{ .compatible = "fsl,vf610-edma", },
+#endif
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index 5eaeeec..d853c3c 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -11,6 +11,9 @@
 #define CLOCK_PORTD		 7
 #define CLOCK_PORTE		 8
 #define CLOCK_PORTF		 9
-#define CLOCK_END		10
+#define CLOCK_EDMA		10
+#define CLOCK_DMAMUX0		11
+#define CLOCK_DMAMUX1		12
+#define CLOCK_END		13
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6

--
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] 86+ messages in thread

* [PATCH 9/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
                   ` (13 preceding siblings ...)
  (?)
@ 2015-06-23 21:19 ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This adds Kinetis SoC UART support to Freescale lpuart driver.

Apart from some small changes (e.g. phony handler for error interrupt),
somewhat bigger change was required by rx DMA operation model: for Kinetis
the transfer residue should be consumed when handling interrupt caused by
IDLE state. As a reference I used DMA related code from pre-OF UART driver
published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

9dc9c6dd13fa3058c776ac71a5a9f71ec89712d3
 RT76540. serial: kinetis_uart: Support receiving from UART using DMA

by Alexander Potashev <aspotashev@emcraft.com>

Note that enabling tx DMA resulted in messy output, so I didn't configure
it in the .dts file - however nothing in the code prevents one from doing
so. Also note that original reference UART driver did not implement tx DMA
at all.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  6 +-
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         | 23 ++++++
 arch/arm/boot/dts/kinetis.dtsi                     | 78 +++++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 28 +++++++
 drivers/tty/serial/fsl_lpuart.c                    | 90 ++++++++++++++++++----
 include/dt-bindings/clock/kinetis-mcg.h            |  8 +-
 6 files changed, 216 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index c95005e..9a8d672 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -6,6 +6,8 @@ Required properties:
     on Vybrid vf610 SoC with 8-bit register organization
   - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
     on LS1021A SoC with 32-bit big-endian register organization
+  - "fsl,kinetis-lpuart" for lpuart compatible with the one integrated
+    on Kinetis SoC with 8-bit register organization
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
 - clocks : phandle + clock specifier pairs, one for each entry in clock-names
@@ -15,7 +17,9 @@ Optional properties:
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
 
-Note: Optional properties for DMA support. Write them both or both not.
+Note: Optional properties for DMA support.
+        For Kinetis SoC, write "rx" only.
+        For others, write them both or both not.
 
 Example:
 
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index a6efc29..5d8470a 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -10,11 +10,34 @@
 	model = "Freescale TWR-K70F120M Development Kit";
 	compatible = "fsl,kinetis-twr-k70f120m";
 
+	chosen {
+		bootargs = "console=ttyLP2,115200";
+	};
+
 	memory {
 		reg = <0x8000000 0x8000000>;
 	};
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "ok";
+};
+
+&portE {
+	status = "ok";
+
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
+
 &pit0 {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 7638103..8d276af 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -17,9 +17,87 @@
 		pmx3 = &portD;
 		pmx4 = &portE;
 		pmx5 = &portF;
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+		serial5 = &uart5;
 	};
 
 	soc {
+		uart0: serial@4006a000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006a000 0x1000>;
+			interrupts = <45>, <46>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART0>;
+			clock-names = "ipg";
+			dmas = <&edma 0 2>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart1: serial@4006b000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006b000 0x1000>;
+			interrupts = <47>, <48>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART1>;
+			clock-names = "ipg";
+			dmas = <&edma 0 4>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart2: serial@4006c000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006c000 0x1000>;
+			interrupts = <49>, <50>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART2>;
+			clock-names = "ipg";
+			dmas = <&edma 0 6>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart3: serial@4006d000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006d000 0x1000>;
+			interrupts = <51>, <52>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART3>;
+			clock-names = "ipg";
+			dmas = <&edma 0 8>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart4: serial@400ea000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400ea000 0x1000>;
+			interrupts = <53>, <54>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART4>;
+			clock-names = "ipg";
+			dmas = <&edma 0 10>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart5: serial@400eb000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400eb000 0x1000>;
+			interrupts = <55>, <56>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART5>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller@40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index 454096c..1fea509 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -263,6 +263,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
 		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
 
+	/*
+	 * UART0 and UART1 are clocked from the core clock, the remaining UARTs
+	 * are clocked from the bus clock.
+	 */
+	clk[CLOCK_UART0] = clk_register_gate(NULL, "UART0", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART0)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART0), 0, NULL);
+
+	clk[CLOCK_UART1] = clk_register_gate(NULL, "UART1", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART1)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART1), 0, NULL);
+
+	clk[CLOCK_UART2] = clk_register_gate(NULL, "UART2", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART2)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART2), 0, NULL);
+
+	clk[CLOCK_UART3] = clk_register_gate(NULL, "UART3", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART3)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART3), 0, NULL);
+
+	clk[CLOCK_UART4] = clk_register_gate(NULL, "UART4", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART4)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART4), 0, NULL);
+
+	clk[CLOCK_UART5] = clk_register_gate(NULL, "UART5", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART5)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART5), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 08ce76f..acf4094 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -236,6 +236,8 @@ struct lpuart_port {
 	unsigned int		txfifo_size;
 	unsigned int		rxfifo_size;
 	bool			lpuart32;
+	bool			kinetis;
+	int			kinetis_err_irq;
 
 	bool			lpuart_dma_tx_use;
 	bool			lpuart_dma_rx_use;
@@ -264,6 +266,9 @@ static const struct of_device_id lpuart_dt_ids[] = {
 	{
 		.compatible = "fsl,ls1021a-lpuart",
 	},
+	{
+		.compatible = "fsl,kinetis-lpuart",
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -350,7 +355,9 @@ static void lpuart_pio_tx(struct lpuart_port *sport)
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	while (!uart_circ_empty(xmit) &&
-		readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -471,7 +478,10 @@ static void lpuart_dma_rx_complete(void *arg)
 	unsigned long flags;
 
 	async_tx_ack(sport->dma_rx_desc);
-	mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
+	if (!(sport->kinetis)) {
+		mod_timer(&sport->lpuart_timer,
+				jiffies + sport->dma_rx_timeout);
+	}
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -483,16 +493,14 @@ static void lpuart_dma_rx_complete(void *arg)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-static void lpuart_timer_func(unsigned long data)
+static inline void lpuart_dma_rx_extract_residue(struct lpuart_port *sport)
 {
-	struct lpuart_port *sport = (struct lpuart_port *)data;
 	struct tty_port *port = &sport->port.state->port;
 	struct dma_tx_state state;
 	unsigned long flags;
 	unsigned char temp;
 	int count;
 
-	del_timer(&sport->lpuart_timer);
 	dmaengine_pause(sport->dma_rx_chan);
 	dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
 	dmaengine_terminate_all(sport->dma_rx_chan);
@@ -510,6 +518,14 @@ static void lpuart_timer_func(unsigned long data)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
+static void lpuart_timer_func(unsigned long data)
+{
+	struct lpuart_port *sport = (struct lpuart_port *)data;
+
+	del_timer(&sport->lpuart_timer);
+	lpuart_dma_rx_extract_residue(sport);
+}
+
 static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 {
 	unsigned long flags;
@@ -517,8 +533,10 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
-	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
-	add_timer(&sport->lpuart_timer);
+	if (!(sport->kinetis)) {
+		sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+		add_timer(&sport->lpuart_timer);
+	}
 
 	lpuart_dma_rx(sport);
 	temp = readb(sport->port.membase + UARTCR5);
@@ -532,7 +550,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 	struct circ_buf *xmit = &sport->port.state->xmit;
 
 	while (!uart_circ_empty(xmit) &&
-		(readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -766,13 +786,20 @@ out:
 static irqreturn_t lpuart_int(int irq, void *dev_id)
 {
 	struct lpuart_port *sport = dev_id;
-	unsigned char sts, crdma;
+	unsigned char sts, crdma, tmp;
 
 	sts = readb(sport->port.membase + UARTSR1);
 	crdma = readb(sport->port.membase + UARTCR5);
 
-	if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
-		if (sport->lpuart_dma_rx_use)
+	if (sport->kinetis && sport->lpuart_dma_rx_use) {
+		if (sts & UARTSR1_IDLE) {
+			/* Clear S[IDLE] flag by reading from UARTx_D */
+			tmp = readb(sport->port.membase + UARTDR);
+			lpuart_dma_rx_extract_residue(sport);
+			lpuart_prepare_rx(sport);
+		}
+	} else if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+		if ((!(sport->kinetis)) && (sport->lpuart_dma_rx_use))
 			lpuart_prepare_rx(sport);
 		else
 			lpuart_rxint(irq, dev_id);
@@ -807,6 +834,11 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t lpuart_errint(int irq, void *data)
+{
+	return IRQ_HANDLED;
+}
+
 /* return TIOCSER_TEMT when transmitter is not busy */
 static unsigned int lpuart_tx_empty(struct uart_port *port)
 {
@@ -1086,8 +1118,11 @@ static int lpuart_startup(struct uart_port *port)
 
 	if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
 		sport->lpuart_dma_rx_use = true;
-		setup_timer(&sport->lpuart_timer, lpuart_timer_func,
-			    (unsigned long)sport);
+		if (sport->kinetis)
+			lpuart_prepare_rx(sport);
+		else
+			setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+					(unsigned long)sport);
 	} else
 		sport->lpuart_dma_rx_use = false;
 
@@ -1105,12 +1140,23 @@ static int lpuart_startup(struct uart_port *port)
 	if (ret)
 		return ret;
 
+	if (sport->kinetis) {
+		ret = devm_request_irq(port->dev, sport->kinetis_err_irq,
+					lpuart_errint, 0, DRIVER_NAME, sport);
+		if (ret) {
+			devm_free_irq(port->dev, port->irq, sport);
+			return ret;
+		}
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	lpuart_setup_watermark(sport);
 
 	temp = readb(sport->port.membase + UARTCR2);
 	temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
+	if (sport->kinetis && sport->lpuart_dma_rx_use)
+		temp |= UARTCR2_ILIE;
 	writeb(temp, sport->port.membase + UARTCR2);
 
 	spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1169,6 +1215,9 @@ static void lpuart_shutdown(struct uart_port *port)
 
 	devm_free_irq(port->dev, port->irq, sport);
 
+	if (sport->kinetis)
+		devm_free_irq(port->dev, sport->kinetis_err_irq, sport);
+
 	if (sport->lpuart_dma_rx_use) {
 		lpuart_dma_rx_free(&sport->port);
 		del_timer_sync(&sport->lpuart_timer);
@@ -1781,6 +1830,8 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 	sport->port.line = ret;
 	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
+	sport->kinetis = of_device_is_compatible(np, "fsl,kinetis-lpuart");
+	spin_lock_init(&(sport->port.lock));
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1788,10 +1839,19 @@ static int lpuart_probe(struct platform_device *pdev)
 		return PTR_ERR(sport->port.membase);
 
 	sport->port.mapbase = res->start;
+	sport->port.mapsize = resource_size(res);
 	sport->port.dev = &pdev->dev;
 	sport->port.type = PORT_LPUART;
 	sport->port.iotype = UPIO_MEM;
-	sport->port.irq = platform_get_irq(pdev, 0);
+
+	if (sport->kinetis) {
+		sport->port.irq = platform_get_irq_byname(pdev, "uart-stat");
+		sport->kinetis_err_irq =
+				platform_get_irq_byname(pdev, "uart-err");
+	} else {
+		sport->port.irq = platform_get_irq(pdev, 0);
+	}
+
 	if (sport->lpuart32)
 		sport->port.ops = &lpuart32_pops;
 	else
@@ -1829,7 +1889,7 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 
 	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
-	if (!sport->dma_tx_chan)
+	if ((!sport->dma_tx_chan) && (!sport->kinetis))
 		dev_info(sport->port.dev, "DMA tx channel request failed, "
 				"operating without tx DMA\n");
 
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index d853c3c..541c3fd 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -14,6 +14,12 @@
 #define CLOCK_EDMA		10
 #define CLOCK_DMAMUX0		11
 #define CLOCK_DMAMUX1		12
-#define CLOCK_END		13
+#define CLOCK_UART0		13
+#define CLOCK_UART1		14
+#define CLOCK_UART2		15
+#define CLOCK_UART3		16
+#define CLOCK_UART4		17
+#define CLOCK_UART5		18
+#define CLOCK_END		19
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 9/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support Kinetis SoC
       [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-06-23 21:19   ` Paul Osmialowski
  2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This adds Kinetis SoC UART support to Freescale lpuart driver.

Apart from some small changes (e.g. phony handler for error interrupt),
somewhat bigger change was required by rx DMA operation model: for Kinetis
the transfer residue should be consumed when handling interrupt caused by
IDLE state. As a reference I used DMA related code from pre-OF UART driver
published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

9dc9c6dd13fa3058c776ac71a5a9f71ec89712d3
 RT76540. serial: kinetis_uart: Support receiving from UART using DMA

by Alexander Potashev <aspotashev@emcraft.com>

Note that enabling tx DMA resulted in messy output, so I didn't configure
it in the .dts file - however nothing in the code prevents one from doing
so. Also note that original reference UART driver did not implement tx DMA
at all.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  6 +-
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         | 23 ++++++
 arch/arm/boot/dts/kinetis.dtsi                     | 78 +++++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 28 +++++++
 drivers/tty/serial/fsl_lpuart.c                    | 90 ++++++++++++++++++----
 include/dt-bindings/clock/kinetis-mcg.h            |  8 +-
 6 files changed, 216 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index c95005e..9a8d672 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -6,6 +6,8 @@ Required properties:
     on Vybrid vf610 SoC with 8-bit register organization
   - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
     on LS1021A SoC with 32-bit big-endian register organization
+  - "fsl,kinetis-lpuart" for lpuart compatible with the one integrated
+    on Kinetis SoC with 8-bit register organization
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
 - clocks : phandle + clock specifier pairs, one for each entry in clock-names
@@ -15,7 +17,9 @@ Optional properties:
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
 
-Note: Optional properties for DMA support. Write them both or both not.
+Note: Optional properties for DMA support.
+        For Kinetis SoC, write "rx" only.
+        For others, write them both or both not.
 
 Example:
 
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index a6efc29..5d8470a 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -10,11 +10,34 @@
 	model = "Freescale TWR-K70F120M Development Kit";
 	compatible = "fsl,kinetis-twr-k70f120m";
 
+	chosen {
+		bootargs = "console=ttyLP2,115200";
+	};
+
 	memory {
 		reg = <0x8000000 0x8000000>;
 	};
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "ok";
+};
+
+&portE {
+	status = "ok";
+
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
+
 &pit0 {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 7638103..8d276af 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -17,9 +17,87 @@
 		pmx3 = &portD;
 		pmx4 = &portE;
 		pmx5 = &portF;
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+		serial5 = &uart5;
 	};
 
 	soc {
+		uart0: serial@4006a000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006a000 0x1000>;
+			interrupts = <45>, <46>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART0>;
+			clock-names = "ipg";
+			dmas = <&edma 0 2>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart1: serial@4006b000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006b000 0x1000>;
+			interrupts = <47>, <48>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART1>;
+			clock-names = "ipg";
+			dmas = <&edma 0 4>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart2: serial@4006c000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006c000 0x1000>;
+			interrupts = <49>, <50>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART2>;
+			clock-names = "ipg";
+			dmas = <&edma 0 6>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart3: serial@4006d000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006d000 0x1000>;
+			interrupts = <51>, <52>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART3>;
+			clock-names = "ipg";
+			dmas = <&edma 0 8>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart4: serial@400ea000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400ea000 0x1000>;
+			interrupts = <53>, <54>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART4>;
+			clock-names = "ipg";
+			dmas = <&edma 0 10>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart5: serial@400eb000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400eb000 0x1000>;
+			interrupts = <55>, <56>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART5>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller@40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index 454096c..1fea509 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -263,6 +263,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
 		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
 
+	/*
+	 * UART0 and UART1 are clocked from the core clock, the remaining UARTs
+	 * are clocked from the bus clock.
+	 */
+	clk[CLOCK_UART0] = clk_register_gate(NULL, "UART0", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART0)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART0), 0, NULL);
+
+	clk[CLOCK_UART1] = clk_register_gate(NULL, "UART1", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART1)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART1), 0, NULL);
+
+	clk[CLOCK_UART2] = clk_register_gate(NULL, "UART2", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART2)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART2), 0, NULL);
+
+	clk[CLOCK_UART3] = clk_register_gate(NULL, "UART3", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART3)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART3), 0, NULL);
+
+	clk[CLOCK_UART4] = clk_register_gate(NULL, "UART4", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART4)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART4), 0, NULL);
+
+	clk[CLOCK_UART5] = clk_register_gate(NULL, "UART5", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART5)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART5), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 08ce76f..acf4094 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -236,6 +236,8 @@ struct lpuart_port {
 	unsigned int		txfifo_size;
 	unsigned int		rxfifo_size;
 	bool			lpuart32;
+	bool			kinetis;
+	int			kinetis_err_irq;
 
 	bool			lpuart_dma_tx_use;
 	bool			lpuart_dma_rx_use;
@@ -264,6 +266,9 @@ static const struct of_device_id lpuart_dt_ids[] = {
 	{
 		.compatible = "fsl,ls1021a-lpuart",
 	},
+	{
+		.compatible = "fsl,kinetis-lpuart",
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -350,7 +355,9 @@ static void lpuart_pio_tx(struct lpuart_port *sport)
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	while (!uart_circ_empty(xmit) &&
-		readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -471,7 +478,10 @@ static void lpuart_dma_rx_complete(void *arg)
 	unsigned long flags;
 
 	async_tx_ack(sport->dma_rx_desc);
-	mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
+	if (!(sport->kinetis)) {
+		mod_timer(&sport->lpuart_timer,
+				jiffies + sport->dma_rx_timeout);
+	}
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -483,16 +493,14 @@ static void lpuart_dma_rx_complete(void *arg)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-static void lpuart_timer_func(unsigned long data)
+static inline void lpuart_dma_rx_extract_residue(struct lpuart_port *sport)
 {
-	struct lpuart_port *sport = (struct lpuart_port *)data;
 	struct tty_port *port = &sport->port.state->port;
 	struct dma_tx_state state;
 	unsigned long flags;
 	unsigned char temp;
 	int count;
 
-	del_timer(&sport->lpuart_timer);
 	dmaengine_pause(sport->dma_rx_chan);
 	dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
 	dmaengine_terminate_all(sport->dma_rx_chan);
@@ -510,6 +518,14 @@ static void lpuart_timer_func(unsigned long data)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
+static void lpuart_timer_func(unsigned long data)
+{
+	struct lpuart_port *sport = (struct lpuart_port *)data;
+
+	del_timer(&sport->lpuart_timer);
+	lpuart_dma_rx_extract_residue(sport);
+}
+
 static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 {
 	unsigned long flags;
@@ -517,8 +533,10 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
-	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
-	add_timer(&sport->lpuart_timer);
+	if (!(sport->kinetis)) {
+		sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+		add_timer(&sport->lpuart_timer);
+	}
 
 	lpuart_dma_rx(sport);
 	temp = readb(sport->port.membase + UARTCR5);
@@ -532,7 +550,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 	struct circ_buf *xmit = &sport->port.state->xmit;
 
 	while (!uart_circ_empty(xmit) &&
-		(readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -766,13 +786,20 @@ out:
 static irqreturn_t lpuart_int(int irq, void *dev_id)
 {
 	struct lpuart_port *sport = dev_id;
-	unsigned char sts, crdma;
+	unsigned char sts, crdma, tmp;
 
 	sts = readb(sport->port.membase + UARTSR1);
 	crdma = readb(sport->port.membase + UARTCR5);
 
-	if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
-		if (sport->lpuart_dma_rx_use)
+	if (sport->kinetis && sport->lpuart_dma_rx_use) {
+		if (sts & UARTSR1_IDLE) {
+			/* Clear S[IDLE] flag by reading from UARTx_D */
+			tmp = readb(sport->port.membase + UARTDR);
+			lpuart_dma_rx_extract_residue(sport);
+			lpuart_prepare_rx(sport);
+		}
+	} else if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+		if ((!(sport->kinetis)) && (sport->lpuart_dma_rx_use))
 			lpuart_prepare_rx(sport);
 		else
 			lpuart_rxint(irq, dev_id);
@@ -807,6 +834,11 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t lpuart_errint(int irq, void *data)
+{
+	return IRQ_HANDLED;
+}
+
 /* return TIOCSER_TEMT when transmitter is not busy */
 static unsigned int lpuart_tx_empty(struct uart_port *port)
 {
@@ -1086,8 +1118,11 @@ static int lpuart_startup(struct uart_port *port)
 
 	if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
 		sport->lpuart_dma_rx_use = true;
-		setup_timer(&sport->lpuart_timer, lpuart_timer_func,
-			    (unsigned long)sport);
+		if (sport->kinetis)
+			lpuart_prepare_rx(sport);
+		else
+			setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+					(unsigned long)sport);
 	} else
 		sport->lpuart_dma_rx_use = false;
 
@@ -1105,12 +1140,23 @@ static int lpuart_startup(struct uart_port *port)
 	if (ret)
 		return ret;
 
+	if (sport->kinetis) {
+		ret = devm_request_irq(port->dev, sport->kinetis_err_irq,
+					lpuart_errint, 0, DRIVER_NAME, sport);
+		if (ret) {
+			devm_free_irq(port->dev, port->irq, sport);
+			return ret;
+		}
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	lpuart_setup_watermark(sport);
 
 	temp = readb(sport->port.membase + UARTCR2);
 	temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
+	if (sport->kinetis && sport->lpuart_dma_rx_use)
+		temp |= UARTCR2_ILIE;
 	writeb(temp, sport->port.membase + UARTCR2);
 
 	spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1169,6 +1215,9 @@ static void lpuart_shutdown(struct uart_port *port)
 
 	devm_free_irq(port->dev, port->irq, sport);
 
+	if (sport->kinetis)
+		devm_free_irq(port->dev, sport->kinetis_err_irq, sport);
+
 	if (sport->lpuart_dma_rx_use) {
 		lpuart_dma_rx_free(&sport->port);
 		del_timer_sync(&sport->lpuart_timer);
@@ -1781,6 +1830,8 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 	sport->port.line = ret;
 	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
+	sport->kinetis = of_device_is_compatible(np, "fsl,kinetis-lpuart");
+	spin_lock_init(&(sport->port.lock));
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1788,10 +1839,19 @@ static int lpuart_probe(struct platform_device *pdev)
 		return PTR_ERR(sport->port.membase);
 
 	sport->port.mapbase = res->start;
+	sport->port.mapsize = resource_size(res);
 	sport->port.dev = &pdev->dev;
 	sport->port.type = PORT_LPUART;
 	sport->port.iotype = UPIO_MEM;
-	sport->port.irq = platform_get_irq(pdev, 0);
+
+	if (sport->kinetis) {
+		sport->port.irq = platform_get_irq_byname(pdev, "uart-stat");
+		sport->kinetis_err_irq =
+				platform_get_irq_byname(pdev, "uart-err");
+	} else {
+		sport->port.irq = platform_get_irq(pdev, 0);
+	}
+
 	if (sport->lpuart32)
 		sport->port.ops = &lpuart32_pops;
 	else
@@ -1829,7 +1889,7 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 
 	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
-	if (!sport->dma_tx_chan)
+	if ((!sport->dma_tx_chan) && (!sport->kinetis))
 		dev_info(sport->port.dev, "DMA tx channel request failed, "
 				"operating without tx DMA\n");
 
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index d853c3c..541c3fd 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -14,6 +14,12 @@
 #define CLOCK_EDMA		10
 #define CLOCK_DMAMUX0		11
 #define CLOCK_DMAMUX1		12
-#define CLOCK_END		13
+#define CLOCK_UART0		13
+#define CLOCK_UART1		14
+#define CLOCK_UART2		15
+#define CLOCK_UART3		16
+#define CLOCK_UART4		17
+#define CLOCK_UART5		18
+#define CLOCK_END		19
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6


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

* [PATCH 9/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support Kinetis SoC
@ 2015-06-23 21:19   ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-23 21:19 UTC (permalink / raw)
  To: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas
  Cc: Paul Osmialowski, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

This adds Kinetis SoC UART support to Freescale lpuart driver.

Apart from some small changes (e.g. phony handler for error interrupt),
somewhat bigger change was required by rx DMA operation model: for Kinetis
the transfer residue should be consumed when handling interrupt caused by
IDLE state. As a reference I used DMA related code from pre-OF UART driver
published on Emcraft git repo:

https://github.com/EmcraftSystems/linux-emcraft.git

9dc9c6dd13fa3058c776ac71a5a9f71ec89712d3
 RT76540. serial: kinetis_uart: Support receiving from UART using DMA

by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

Note that enabling tx DMA resulted in messy output, so I didn't configure
it in the .dts file - however nothing in the code prevents one from doing
so. Also note that original reference UART driver did not implement tx DMA
at all.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  6 +-
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         | 23 ++++++
 arch/arm/boot/dts/kinetis.dtsi                     | 78 +++++++++++++++++++
 drivers/clk/clk-kinetis.c                          | 28 +++++++
 drivers/tty/serial/fsl_lpuart.c                    | 90 ++++++++++++++++++----
 include/dt-bindings/clock/kinetis-mcg.h            |  8 +-
 6 files changed, 216 insertions(+), 17 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index c95005e..9a8d672 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -6,6 +6,8 @@ Required properties:
     on Vybrid vf610 SoC with 8-bit register organization
   - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
     on LS1021A SoC with 32-bit big-endian register organization
+  - "fsl,kinetis-lpuart" for lpuart compatible with the one integrated
+    on Kinetis SoC with 8-bit register organization
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
 - clocks : phandle + clock specifier pairs, one for each entry in clock-names
@@ -15,7 +17,9 @@ Optional properties:
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
 
-Note: Optional properties for DMA support. Write them both or both not.
+Note: Optional properties for DMA support.
+        For Kinetis SoC, write "rx" only.
+        For others, write them both or both not.
 
 Example:
 
diff --git a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
index a6efc29..5d8470a 100644
--- a/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
+++ b/arch/arm/boot/dts/kinetis-twr-k70f120m.dts
@@ -10,11 +10,34 @@
 	model = "Freescale TWR-K70F120M Development Kit";
 	compatible = "fsl,kinetis-twr-k70f120m";
 
+	chosen {
+		bootargs = "console=ttyLP2,115200";
+	};
+
 	memory {
 		reg = <0x8000000 0x8000000>;
 	};
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "ok";
+};
+
+&portE {
+	status = "ok";
+
+	uart2 {
+		uart2_pins: pinmux_uart2_pins {
+			fsl,pins = <
+				16	0x300 /* E.16 = UART2_TX */
+				17	0x300 /* E.17 = UART2_RX */
+			>;
+		};
+	};
+};
+
 &pit0 {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 7638103..8d276af 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -17,9 +17,87 @@
 		pmx3 = &portD;
 		pmx4 = &portE;
 		pmx5 = &portF;
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+		serial5 = &uart5;
 	};
 
 	soc {
+		uart0: serial@4006a000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006a000 0x1000>;
+			interrupts = <45>, <46>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART0>;
+			clock-names = "ipg";
+			dmas = <&edma 0 2>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart1: serial@4006b000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006b000 0x1000>;
+			interrupts = <47>, <48>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART1>;
+			clock-names = "ipg";
+			dmas = <&edma 0 4>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart2: serial@4006c000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006c000 0x1000>;
+			interrupts = <49>, <50>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART2>;
+			clock-names = "ipg";
+			dmas = <&edma 0 6>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart3: serial@4006d000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006d000 0x1000>;
+			interrupts = <51>, <52>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART3>;
+			clock-names = "ipg";
+			dmas = <&edma 0 8>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart4: serial@400ea000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400ea000 0x1000>;
+			interrupts = <53>, <54>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART4>;
+			clock-names = "ipg";
+			dmas = <&edma 0 10>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart5: serial@400eb000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400eb000 0x1000>;
+			interrupts = <55>, <56>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg CLOCK_UART5>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller@40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
index 454096c..1fea509 100644
--- a/drivers/clk/clk-kinetis.c
+++ b/drivers/clk/clk-kinetis.c
@@ -263,6 +263,34 @@ static void __init kinetis_mcg_init(struct device_node *np)
 		KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_DMAMUX1)]),
 		KINETIS_CG_IDX(KINETIS_CG_DMAMUX1), 0, NULL);
 
+	/*
+	 * UART0 and UART1 are clocked from the core clock, the remaining UARTs
+	 * are clocked from the bus clock.
+	 */
+	clk[CLOCK_UART0] = clk_register_gate(NULL, "UART0", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART0)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART0), 0, NULL);
+
+	clk[CLOCK_UART1] = clk_register_gate(NULL, "UART1", "CCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART1)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART1), 0, NULL);
+
+	clk[CLOCK_UART2] = clk_register_gate(NULL, "UART2", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART2)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART2), 0, NULL);
+
+	clk[CLOCK_UART3] = clk_register_gate(NULL, "UART3", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART3)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART3), 0, NULL);
+
+	clk[CLOCK_UART4] = clk_register_gate(NULL, "UART4", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART4)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART4), 0, NULL);
+
+	clk[CLOCK_UART5] = clk_register_gate(NULL, "UART5", "PCLK", 0,
+			KINETIS_SIM_PTR(scgc[KINETIS_CG_REG(KINETIS_CG_UART5)]),
+			KINETIS_CG_IDX(KINETIS_CG_UART5), 0, NULL);
+
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
 
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 08ce76f..acf4094 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -236,6 +236,8 @@ struct lpuart_port {
 	unsigned int		txfifo_size;
 	unsigned int		rxfifo_size;
 	bool			lpuart32;
+	bool			kinetis;
+	int			kinetis_err_irq;
 
 	bool			lpuart_dma_tx_use;
 	bool			lpuart_dma_rx_use;
@@ -264,6 +266,9 @@ static const struct of_device_id lpuart_dt_ids[] = {
 	{
 		.compatible = "fsl,ls1021a-lpuart",
 	},
+	{
+		.compatible = "fsl,kinetis-lpuart",
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -350,7 +355,9 @@ static void lpuart_pio_tx(struct lpuart_port *sport)
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	while (!uart_circ_empty(xmit) &&
-		readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -471,7 +478,10 @@ static void lpuart_dma_rx_complete(void *arg)
 	unsigned long flags;
 
 	async_tx_ack(sport->dma_rx_desc);
-	mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
+	if (!(sport->kinetis)) {
+		mod_timer(&sport->lpuart_timer,
+				jiffies + sport->dma_rx_timeout);
+	}
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -483,16 +493,14 @@ static void lpuart_dma_rx_complete(void *arg)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-static void lpuart_timer_func(unsigned long data)
+static inline void lpuart_dma_rx_extract_residue(struct lpuart_port *sport)
 {
-	struct lpuart_port *sport = (struct lpuart_port *)data;
 	struct tty_port *port = &sport->port.state->port;
 	struct dma_tx_state state;
 	unsigned long flags;
 	unsigned char temp;
 	int count;
 
-	del_timer(&sport->lpuart_timer);
 	dmaengine_pause(sport->dma_rx_chan);
 	dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
 	dmaengine_terminate_all(sport->dma_rx_chan);
@@ -510,6 +518,14 @@ static void lpuart_timer_func(unsigned long data)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
+static void lpuart_timer_func(unsigned long data)
+{
+	struct lpuart_port *sport = (struct lpuart_port *)data;
+
+	del_timer(&sport->lpuart_timer);
+	lpuart_dma_rx_extract_residue(sport);
+}
+
 static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 {
 	unsigned long flags;
@@ -517,8 +533,10 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
-	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
-	add_timer(&sport->lpuart_timer);
+	if (!(sport->kinetis)) {
+		sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+		add_timer(&sport->lpuart_timer);
+	}
 
 	lpuart_dma_rx(sport);
 	temp = readb(sport->port.membase + UARTCR5);
@@ -532,7 +550,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 	struct circ_buf *xmit = &sport->port.state->xmit;
 
 	while (!uart_circ_empty(xmit) &&
-		(readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
+	    (sport->kinetis ?
+	      (readb(sport->port.membase + UARTSR1) & UARTSR1_TDRE) :
+	      (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size))) {
 		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -766,13 +786,20 @@ out:
 static irqreturn_t lpuart_int(int irq, void *dev_id)
 {
 	struct lpuart_port *sport = dev_id;
-	unsigned char sts, crdma;
+	unsigned char sts, crdma, tmp;
 
 	sts = readb(sport->port.membase + UARTSR1);
 	crdma = readb(sport->port.membase + UARTCR5);
 
-	if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
-		if (sport->lpuart_dma_rx_use)
+	if (sport->kinetis && sport->lpuart_dma_rx_use) {
+		if (sts & UARTSR1_IDLE) {
+			/* Clear S[IDLE] flag by reading from UARTx_D */
+			tmp = readb(sport->port.membase + UARTDR);
+			lpuart_dma_rx_extract_residue(sport);
+			lpuart_prepare_rx(sport);
+		}
+	} else if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+		if ((!(sport->kinetis)) && (sport->lpuart_dma_rx_use))
 			lpuart_prepare_rx(sport);
 		else
 			lpuart_rxint(irq, dev_id);
@@ -807,6 +834,11 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t lpuart_errint(int irq, void *data)
+{
+	return IRQ_HANDLED;
+}
+
 /* return TIOCSER_TEMT when transmitter is not busy */
 static unsigned int lpuart_tx_empty(struct uart_port *port)
 {
@@ -1086,8 +1118,11 @@ static int lpuart_startup(struct uart_port *port)
 
 	if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
 		sport->lpuart_dma_rx_use = true;
-		setup_timer(&sport->lpuart_timer, lpuart_timer_func,
-			    (unsigned long)sport);
+		if (sport->kinetis)
+			lpuart_prepare_rx(sport);
+		else
+			setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+					(unsigned long)sport);
 	} else
 		sport->lpuart_dma_rx_use = false;
 
@@ -1105,12 +1140,23 @@ static int lpuart_startup(struct uart_port *port)
 	if (ret)
 		return ret;
 
+	if (sport->kinetis) {
+		ret = devm_request_irq(port->dev, sport->kinetis_err_irq,
+					lpuart_errint, 0, DRIVER_NAME, sport);
+		if (ret) {
+			devm_free_irq(port->dev, port->irq, sport);
+			return ret;
+		}
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 
 	lpuart_setup_watermark(sport);
 
 	temp = readb(sport->port.membase + UARTCR2);
 	temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
+	if (sport->kinetis && sport->lpuart_dma_rx_use)
+		temp |= UARTCR2_ILIE;
 	writeb(temp, sport->port.membase + UARTCR2);
 
 	spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1169,6 +1215,9 @@ static void lpuart_shutdown(struct uart_port *port)
 
 	devm_free_irq(port->dev, port->irq, sport);
 
+	if (sport->kinetis)
+		devm_free_irq(port->dev, sport->kinetis_err_irq, sport);
+
 	if (sport->lpuart_dma_rx_use) {
 		lpuart_dma_rx_free(&sport->port);
 		del_timer_sync(&sport->lpuart_timer);
@@ -1781,6 +1830,8 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 	sport->port.line = ret;
 	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
+	sport->kinetis = of_device_is_compatible(np, "fsl,kinetis-lpuart");
+	spin_lock_init(&(sport->port.lock));
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1788,10 +1839,19 @@ static int lpuart_probe(struct platform_device *pdev)
 		return PTR_ERR(sport->port.membase);
 
 	sport->port.mapbase = res->start;
+	sport->port.mapsize = resource_size(res);
 	sport->port.dev = &pdev->dev;
 	sport->port.type = PORT_LPUART;
 	sport->port.iotype = UPIO_MEM;
-	sport->port.irq = platform_get_irq(pdev, 0);
+
+	if (sport->kinetis) {
+		sport->port.irq = platform_get_irq_byname(pdev, "uart-stat");
+		sport->kinetis_err_irq =
+				platform_get_irq_byname(pdev, "uart-err");
+	} else {
+		sport->port.irq = platform_get_irq(pdev, 0);
+	}
+
 	if (sport->lpuart32)
 		sport->port.ops = &lpuart32_pops;
 	else
@@ -1829,7 +1889,7 @@ static int lpuart_probe(struct platform_device *pdev)
 	}
 
 	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
-	if (!sport->dma_tx_chan)
+	if ((!sport->dma_tx_chan) && (!sport->kinetis))
 		dev_info(sport->port.dev, "DMA tx channel request failed, "
 				"operating without tx DMA\n");
 
diff --git a/include/dt-bindings/clock/kinetis-mcg.h b/include/dt-bindings/clock/kinetis-mcg.h
index d853c3c..541c3fd 100644
--- a/include/dt-bindings/clock/kinetis-mcg.h
+++ b/include/dt-bindings/clock/kinetis-mcg.h
@@ -14,6 +14,12 @@
 #define CLOCK_EDMA		10
 #define CLOCK_DMAMUX0		11
 #define CLOCK_DMAMUX1		12
-#define CLOCK_END		13
+#define CLOCK_UART0		13
+#define CLOCK_UART1		14
+#define CLOCK_UART2		15
+#define CLOCK_UART3		16
+#define CLOCK_UART4		17
+#define CLOCK_UART5		18
+#define CLOCK_END		19
 
 #endif /* _DT_BINDINGS_CLOCK_KINETIS_MCG_H */
-- 
2.3.6

--
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] 86+ messages in thread

* Re: [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
  2015-06-23 21:19   ` Paul Osmialowski
@ 2015-06-23 21:48     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 21:48 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Arnd Bergmann, Olof Johansson, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

On Tue, Jun 23, 2015 at 11:19:39PM +0200, Paul Osmialowski wrote:
> This one is inspired by two commits published on Emcraft git repo:
> 
> https://github.com/EmcraftSystems/linux-emcraft.git
> 
> 1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
>  RT #62654. Fixed kernel crashes while running httpd by enabling
>  "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
>  generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
>  Cortex-M3 Errata it may result in incorrect base register when interrupted
>  or faulted.
> 
> by: Yuri Tikhonov <yur@emcraft.com>
> 
> 2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
>  RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
>  sure only the correct instructions will be generated.
> 
> by: Sergei Poselenov <sposelenov@emcraft.com>
> 
> I reworked these patches to make them less intrusive.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

NAK.

The EFM32 code already added core support for Cortex-M3 cores, under
the symbol CPU_V7M.  Rather than implementing a whole new set of
Cortex-M3 support alongside the existing code, please work with the
EFM32 maintainer (Uwe Kleine-König) to come up with a common set of
core changes that you can all agree on for Cortex-M3.

Please also try to be a little smarter with whom you're sending your
patches to, the Cc list looks to be excessively long - having soo many
recipients on your message is a good way to get your message rejected
by mailing lists as spam.

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

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

* [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
@ 2015-06-23 21:48     ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 21:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 23, 2015 at 11:19:39PM +0200, Paul Osmialowski wrote:
> This one is inspired by two commits published on Emcraft git repo:
> 
> https://github.com/EmcraftSystems/linux-emcraft.git
> 
> 1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
>  RT #62654. Fixed kernel crashes while running httpd by enabling
>  "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
>  generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
>  Cortex-M3 Errata it may result in incorrect base register when interrupted
>  or faulted.
> 
> by: Yuri Tikhonov <yur@emcraft.com>
> 
> 2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
>  RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
>  sure only the correct instructions will be generated.
> 
> by: Sergei Poselenov <sposelenov@emcraft.com>
> 
> I reworked these patches to make them less intrusive.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

NAK.

The EFM32 code already added core support for Cortex-M3 cores, under
the symbol CPU_V7M.  Rather than implementing a whole new set of
Cortex-M3 support alongside the existing code, please work with the
EFM32 maintainer (Uwe Kleine-K?nig) to come up with a common set of
core changes that you can all agree on for Cortex-M3.

Please also try to be a little smarter with whom you're sending your
patches to, the Cc list looks to be excessively long - having soo many
recipients on your message is a good way to get your message rejected
by mailing lists as spam.

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

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:51     ` Russell King - ARM Linux
  2015-06-23 21:59     ` Arnd Bergmann
  1 sibling, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 21:51 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Arnd Bergmann, Olof Johansson, linux-kernel, linux-arm-kernel

On Tue, Jun 23, 2015 at 11:19:41PM +0200, Paul Osmialowski wrote:
> Some SoCs need additional actions to be performed after arch idle,
> e.g. Kinetis requires invalidation of the I/D bus cache.
> 
> Such handler could be held in provided <mach/idle.h> header file.

NAK.  This is what the arm_pm_idle hook is there for.

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

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

* [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-23 21:51     ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 21:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 23, 2015 at 11:19:41PM +0200, Paul Osmialowski wrote:
> Some SoCs need additional actions to be performed after arch idle,
> e.g. Kinetis requires invalidation of the I/D bus cache.
> 
> Such handler could be held in provided <mach/idle.h> header file.

NAK.  This is what the arm_pm_idle hook is there for.

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

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-23 21:19 ` Paul Osmialowski
@ 2015-06-23 21:59     ` Arnd Bergmann
  2015-06-23 21:59     ` Arnd Bergmann
  1 sibling, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 21:59 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime

On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> Some SoCs need additional actions to be performed after arch idle,
> e.g. Kinetis requires invalidation of the I/D bus cache.
> 
> Such handler could be held in provided <mach/idle.h> header file.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig          | 7 +++++++
>  arch/arm/kernel/process.c | 7 +++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 8e3a833..8ef8f8f 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>  config NEED_SG_DMA_LENGTH
>  	bool
>  
> +config NEED_MACH_IDLE_H
> +	bool
> +
> +config ARM_CPU_IDLE_QUIRKS
> +	bool
> +	select NEED_MACH_IDLE_H
> +

We're not adding header files like this, please come up
with another solution. How about a cpuidle driver, or
possibly just overriding arm_pm_idle()?


	Arnd

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-23 21:59     ` Arnd Bergmann
  0 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 21:59 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Rob Herring, Russell King, Sergey Senozhatsky,
	Shawn Guo, Simon Horman, Stefan Agner, Stephen Boyd,
	Thomas Gleixner, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, Pawel Moll, linux-kernel, linux-arm-kernel,
	linux-clk, linux-gpio, linux-serial, devicetree, dmaengine,
	Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov,
	Alexander Potashev

On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> Some SoCs need additional actions to be performed after arch idle,
> e.g. Kinetis requires invalidation of the I/D bus cache.
> 
> Such handler could be held in provided <mach/idle.h> header file.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig          | 7 +++++++
>  arch/arm/kernel/process.c | 7 +++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 8e3a833..8ef8f8f 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>  config NEED_SG_DMA_LENGTH
>  	bool
>  
> +config NEED_MACH_IDLE_H
> +	bool
> +
> +config ARM_CPU_IDLE_QUIRKS
> +	bool
> +	select NEED_MACH_IDLE_H
> +

We're not adding header files like this, please come up
with another solution. How about a cpuidle driver, or
possibly just overriding arm_pm_idle()?


	Arnd

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  2015-06-23 21:19   ` Paul Osmialowski
@ 2015-06-23 22:05     ` Arnd Bergmann
  -1 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 22:05 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime

On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
> @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
>  config FORCE_MAX_ZONEORDER
>  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
>  	range 11 64 if ARCH_SHMOBILE_LEGACY
> -	default "12" if SOC_AM33XX
> +	default "12" if SOC_AM33XX || ARCH_KINETIS
>  	default "9" if SA1111 || ARCH_EFM32
>  	default "11"
>  	help

Put it in the defconfig?

> +#
> +
> +obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o

just use

obj-y	+= kinetis.o

> diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
> new file mode 100644
> index 0000000..0aafefd
> --- /dev/null
> +++ b/arch/arm/mach-kinetis/include/mach/idle.h

No mach/*.h files please.

> +/*
> + * This Kinetis port assumes that the CPU works in little-endian mode.
> + * Switching to big-endian will require different bit offsets in peripheral
> + * devices' registers. Also, some bit groups may lay on byte edges, so issue
> + * with big-endian cannot be fixed only by defining bit offsets differently
> + * for the big-endian mode.
> + */
> +#ifndef __LITTLE_ENDIAN
> +#error This Kinetis port assumes that the CPU works in little-endian mode
> +#endif

Fix the drivers instead?

> +/*
> + * Peripheral memory map
> + */
> +#define KINETIS_AIPS0PERIPH_BASE	0x40000000
> +#define KINETIS_AIPS1PERIPH_BASE	0x40080000

Move it into DT

> +/*
> + * System Integration Module (SIM) register map
> + *
> + * This map actually covers two hardware modules:
> + *     1. SIM low-power logic, at 0x40047000
> + *     2. System integration module (SIM), at 0x40048000
> + */
> +struct kinetis_sim_regs {
> +	u32 sopt1;	/* System Options Register 1 */
> +	u32 rsv0[1024];
> +	u32 sopt2;	/* System Options Register 2 */
> +	u32 rsv1;
> +	u32 sopt4;	/* System Options Register 4 */
> +	u32 sopt5;	/* System Options Register 5 */
> +	u32 sopt6;	/* System Options Register 6 */
> +	u32 sopt7;	/* System Options Register 7 */
> +	u32 rsv2[2];
> +	u32 sdid;	/* System Device Identification Register */
> +	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
> +	u32 clkdiv1;	/* System Clock Divider Register 1 */
> +	u32 clkdiv2;	/* System Clock Divider Register 2 */
> +	u32 fcfg1;	/* Flash Configuration Register 1 */
> +	u32 fcfg2;	/* Flash Configuration Register 2 */
> +	u32 uidh;	/* Unique Identification Register High */
> +	u32 uidmh;	/* Unique Identification Register Mid-High */
> +	u32 uidml;	/* Unique Identification Register Mid Low */
> +	u32 uidl;	/* Unique Identification Register Low */
> +	u32 clkdiv3;	/* System Clock Divider Register 3 */
> +	u32 clkdiv4;	/* System Clock Divider Register 4 */
> +	u32 mcr;	/* Misc Control Register */
> +};

Move it into the driver that uses these.

> +/*
> + * SIM registers base
> + */
> +#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
> +#define KINETIS_SIM_PTR(reg) \
> +	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
> +#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
> +#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
> +#define KINETIS_SIM_SET(reg, mask) \
> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
> +#define KINETIS_SIM_RESET(reg, mask) \
> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
> +#define KINETIS_SIM_ISSET(reg, mask) \
> +	(KINETIS_SIM_RD(reg) & (mask))
> +
> +/*
> + * SIM registers
> + */
> +/*
> + * System Options Register 2
> + */
> +/* USB HS clock source select */
> +#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
> +#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +
> +/* USB FS clock source select */
> +#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
> +#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
> +

remove all these here.

> +/*
> + * Map required regions.
> + * This being the no-MMU Linux, I am not mapping anything
> + * since all I/O registers are available at their physical addresses.
> + */
> +static void __init kinetis_map_io(void)
> +{
> +}

Not needed, remove.

> +/*
> + * Freescale Kinetis platform initialization
> + */
> +static void __init kinetis_init(void)
> +{
> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +}

same here.

> diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
> index 2ed1b8a..1d05516 100644
> --- a/arch/arm/tools/mach-types
> +++ b/arch/arm/tools/mach-types
> @@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
>  marzen			MACH_MARZEN		MARZEN			3790
>  krome			MACH_KROME		KROME			3797
>  armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
> +kinetis			MACH_KINETIS		KINETIS			3896
>  mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
>  mt4			MACH_MT4		MT4			3981
>  u8520			MACH_U8520		U8520			3990

Unused, please remove.

	Arnd

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
@ 2015-06-23 22:05     ` Arnd Bergmann
  0 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 22:05 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Rob Herring, Russell King, Sergey Senozhatsky,
	Shawn Guo, Simon Horman, Stefan Agner, Stephen Boyd,
	Thomas Gleixner, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, Pawel Moll, linux-kernel, linux-arm-kernel,
	linux-clk, linux-gpio, linux-serial, devicetree, dmaengine,
	Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov,
	Alexander Potashev

On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
> @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
>  config FORCE_MAX_ZONEORDER
>  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
>  	range 11 64 if ARCH_SHMOBILE_LEGACY
> -	default "12" if SOC_AM33XX
> +	default "12" if SOC_AM33XX || ARCH_KINETIS
>  	default "9" if SA1111 || ARCH_EFM32
>  	default "11"
>  	help

Put it in the defconfig?

> +#
> +
> +obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o

just use

obj-y	+= kinetis.o

> diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
> new file mode 100644
> index 0000000..0aafefd
> --- /dev/null
> +++ b/arch/arm/mach-kinetis/include/mach/idle.h

No mach/*.h files please.

> +/*
> + * This Kinetis port assumes that the CPU works in little-endian mode.
> + * Switching to big-endian will require different bit offsets in peripheral
> + * devices' registers. Also, some bit groups may lay on byte edges, so issue
> + * with big-endian cannot be fixed only by defining bit offsets differently
> + * for the big-endian mode.
> + */
> +#ifndef __LITTLE_ENDIAN
> +#error This Kinetis port assumes that the CPU works in little-endian mode
> +#endif

Fix the drivers instead?

> +/*
> + * Peripheral memory map
> + */
> +#define KINETIS_AIPS0PERIPH_BASE	0x40000000
> +#define KINETIS_AIPS1PERIPH_BASE	0x40080000

Move it into DT

> +/*
> + * System Integration Module (SIM) register map
> + *
> + * This map actually covers two hardware modules:
> + *     1. SIM low-power logic, at 0x40047000
> + *     2. System integration module (SIM), at 0x40048000
> + */
> +struct kinetis_sim_regs {
> +	u32 sopt1;	/* System Options Register 1 */
> +	u32 rsv0[1024];
> +	u32 sopt2;	/* System Options Register 2 */
> +	u32 rsv1;
> +	u32 sopt4;	/* System Options Register 4 */
> +	u32 sopt5;	/* System Options Register 5 */
> +	u32 sopt6;	/* System Options Register 6 */
> +	u32 sopt7;	/* System Options Register 7 */
> +	u32 rsv2[2];
> +	u32 sdid;	/* System Device Identification Register */
> +	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
> +	u32 clkdiv1;	/* System Clock Divider Register 1 */
> +	u32 clkdiv2;	/* System Clock Divider Register 2 */
> +	u32 fcfg1;	/* Flash Configuration Register 1 */
> +	u32 fcfg2;	/* Flash Configuration Register 2 */
> +	u32 uidh;	/* Unique Identification Register High */
> +	u32 uidmh;	/* Unique Identification Register Mid-High */
> +	u32 uidml;	/* Unique Identification Register Mid Low */
> +	u32 uidl;	/* Unique Identification Register Low */
> +	u32 clkdiv3;	/* System Clock Divider Register 3 */
> +	u32 clkdiv4;	/* System Clock Divider Register 4 */
> +	u32 mcr;	/* Misc Control Register */
> +};

Move it into the driver that uses these.

> +/*
> + * SIM registers base
> + */
> +#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
> +#define KINETIS_SIM_PTR(reg) \
> +	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
> +#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
> +#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
> +#define KINETIS_SIM_SET(reg, mask) \
> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
> +#define KINETIS_SIM_RESET(reg, mask) \
> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
> +#define KINETIS_SIM_ISSET(reg, mask) \
> +	(KINETIS_SIM_RD(reg) & (mask))
> +
> +/*
> + * SIM registers
> + */
> +/*
> + * System Options Register 2
> + */
> +/* USB HS clock source select */
> +#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
> +#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
> +
> +/* USB FS clock source select */
> +#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
> +#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
> +#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
> +

remove all these here.

> +/*
> + * Map required regions.
> + * This being the no-MMU Linux, I am not mapping anything
> + * since all I/O registers are available at their physical addresses.
> + */
> +static void __init kinetis_map_io(void)
> +{
> +}

Not needed, remove.

> +/*
> + * Freescale Kinetis platform initialization
> + */
> +static void __init kinetis_init(void)
> +{
> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +}

same here.

> diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
> index 2ed1b8a..1d05516 100644
> --- a/arch/arm/tools/mach-types
> +++ b/arch/arm/tools/mach-types
> @@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
>  marzen			MACH_MARZEN		MARZEN			3790
>  krome			MACH_KROME		KROME			3797
>  armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
> +kinetis			MACH_KINETIS		KINETIS			3896
>  mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
>  mt4			MACH_MT4		MT4			3981
>  u8520			MACH_U8520		U8520			3990

Unused, please remove.

	Arnd

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
  2015-06-23 21:19   ` Paul Osmialowski
  (?)
  (?)
@ 2015-06-23 22:24   ` Stephen Boyd
  -1 siblings, 0 replies; 86+ messages in thread
From: Stephen Boyd @ 2015-06-23 22:24 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On 06/23/2015 02:19 PM, Paul Osmialowski wrote:
>
> diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
> new file mode 100644
> index 0000000..dea1054
> --- /dev/null
> +++ b/drivers/clk/clk-kinetis.c
> @@ -0,0 +1,226 @@
> +/*
> + * clk-kinetis.c - Clock driver for Kinetis K70 MCG
> + *
> + * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>

Is this using the consumer API? Please remove this include.

> +#include <linux/io.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/err.h>
> +#include <mach/kinetis.h>
> +#include <mach/power.h>

It would be nice if we didn't need these mach includes so that this
driver can be easily build tested.

> +
> +#include <dt-bindings/clock/kinetis-mcg.h>
[..]
> +}
> +
> +CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);

A clocksource isn't the same as a clk provider. Please split this patch
into two, one for the clk provider (drivers/clk) and one for the
clocksource driver (drivers/clocksource).

> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 0f1c77e..1d2ecde 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -106,6 +106,11 @@ config CLKSRC_EFM32
>  	  Support to use the timers of EFM32 SoCs as clock source and clock
>  	  event device.
>  
> +config CLKSRC_KINETIS
> +	bool "Clocksource for Kinetis SoCs"
> +	depends on OF && ARM && ARCH_KINETIS

Doesn't ARCH_KINETIS imply ARM? Seems that we can drop the ARM
dependency here.

> +	select CLKSRC_OF
>
>
> diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
> new file mode 100644
> index 0000000..634f365
> --- /dev/null
> +++ b/drivers/clocksource/timer-kinetis.c
[..]
> +
> +/*
> + * Clock event device set mode function
> + */
> +static void kinetis_clockevent_tmr_set_mode(
> +	enum clock_event_mode mode, struct clock_event_device *clk)

s/clk/evt/ ?

> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		kinetis_pit_enable(pit->base, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		kinetis_pit_enable(pit->base, 0);
> +	}
> +}
> +
> +/*
> + * Configure the timer to generate an interrupt in the specified amount of ticks
> + */
> +static int kinetis_clockevent_tmr_set_next_event(
> +	unsigned long delta, struct clock_event_device *c)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
> +	unsigned long flags;
> +
> +	raw_local_irq_save(flags);

What is this protecting against?

> +	kinetis_pit_init(pit->base, delta);
> +	kinetis_pit_enable(pit->base, 1);
> +	raw_local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_mode	= kinetis_clockevent_tmr_set_mode,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer1",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer2",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer3",
> +		},
> +	},
> +};
> +
> +/*
> + * Timer IRQ handler
> + */
> +static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
> +{
> +	struct kinetis_clock_event_ddata *tmr = dev_id;
> +
> +	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
> +
> +	tmr->evtdev.event_handler(&(tmr->evtdev));

Unnecessary parentheses, please remove them.

> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * System timer IRQ action
> + */
> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.name = "Kinetis Kernel Time Tick (pit0)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[0],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit1)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[1],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit2)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[2],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit3)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[3],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	},
> +};

Any reason we can't just use request_irq() instead of having a set of
static irq actions?

> +
> +static void __init kinetis_clockevent_init(struct device_node *np)
> +{
[..]
> irq;
> +	}
> +
> +	chan = of_alias_get_id(np, "pit");
> +	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {

Unnecessary parentheses, please remove them.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-23 22:24     ` Stephen Boyd
  0 siblings, 0 replies; 86+ messages in thread
From: Stephen Boyd @ 2015-06-23 22:24 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On 06/23/2015 02:19 PM, Paul Osmialowski wrote:
>
> diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
> new file mode 100644
> index 0000000..dea1054
> --- /dev/null
> +++ b/drivers/clk/clk-kinetis.c
> @@ -0,0 +1,226 @@
> +/*
> + * clk-kinetis.c - Clock driver for Kinetis K70 MCG
> + *
> + * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>

Is this using the consumer API? Please remove this include.

> +#include <linux/io.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/err.h>
> +#include <mach/kinetis.h>
> +#include <mach/power.h>

It would be nice if we didn't need these mach includes so that this
driver can be easily build tested.

> +
> +#include <dt-bindings/clock/kinetis-mcg.h>
[..]
> +}
> +
> +CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);

A clocksource isn't the same as a clk provider. Please split this patch
into two, one for the clk provider (drivers/clk) and one for the
clocksource driver (drivers/clocksource).

> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 0f1c77e..1d2ecde 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -106,6 +106,11 @@ config CLKSRC_EFM32
>  	  Support to use the timers of EFM32 SoCs as clock source and clock
>  	  event device.
>  
> +config CLKSRC_KINETIS
> +	bool "Clocksource for Kinetis SoCs"
> +	depends on OF && ARM && ARCH_KINETIS

Doesn't ARCH_KINETIS imply ARM? Seems that we can drop the ARM
dependency here.

> +	select CLKSRC_OF
>
>
> diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
> new file mode 100644
> index 0000000..634f365
> --- /dev/null
> +++ b/drivers/clocksource/timer-kinetis.c
[..]
> +
> +/*
> + * Clock event device set mode function
> + */
> +static void kinetis_clockevent_tmr_set_mode(
> +	enum clock_event_mode mode, struct clock_event_device *clk)

s/clk/evt/ ?

> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		kinetis_pit_enable(pit->base, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		kinetis_pit_enable(pit->base, 0);
> +	}
> +}
> +
> +/*
> + * Configure the timer to generate an interrupt in the specified amount of ticks
> + */
> +static int kinetis_clockevent_tmr_set_next_event(
> +	unsigned long delta, struct clock_event_device *c)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
> +	unsigned long flags;
> +
> +	raw_local_irq_save(flags);

What is this protecting against?

> +	kinetis_pit_init(pit->base, delta);
> +	kinetis_pit_enable(pit->base, 1);
> +	raw_local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_mode	= kinetis_clockevent_tmr_set_mode,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer1",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer2",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer3",
> +		},
> +	},
> +};
> +
> +/*
> + * Timer IRQ handler
> + */
> +static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
> +{
> +	struct kinetis_clock_event_ddata *tmr = dev_id;
> +
> +	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
> +
> +	tmr->evtdev.event_handler(&(tmr->evtdev));

Unnecessary parentheses, please remove them.

> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * System timer IRQ action
> + */
> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.name = "Kinetis Kernel Time Tick (pit0)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[0],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit1)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[1],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit2)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[2],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit3)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[3],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	},
> +};

Any reason we can't just use request_irq() instead of having a set of
static irq actions?

> +
> +static void __init kinetis_clockevent_init(struct device_node *np)
> +{
[..]
> irq;
> +	}
> +
> +	chan = of_alias_get_id(np, "pit");
> +	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {

Unnecessary parentheses, please remove them.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-23 22:24     ` Stephen Boyd
  0 siblings, 0 replies; 86+ messages in thread
From: Stephen Boyd @ 2015-06-23 22:24 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On 06/23/2015 02:19 PM, Paul Osmialowski wrote:
>
> diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
> new file mode 100644
> index 0000000..dea1054
> --- /dev/null
> +++ b/drivers/clk/clk-kinetis.c
> @@ -0,0 +1,226 @@
> +/*
> + * clk-kinetis.c - Clock driver for Kinetis K70 MCG
> + *
> + * Based on legacy pre-OF code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>

Is this using the consumer API? Please remove this include.

> +#include <linux/io.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/err.h>
> +#include <mach/kinetis.h>
> +#include <mach/power.h>

It would be nice if we didn't need these mach includes so that this
driver can be easily build tested.

> +
> +#include <dt-bindings/clock/kinetis-mcg.h>
[..]
> +}
> +
> +CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);

A clocksource isn't the same as a clk provider. Please split this patch
into two, one for the clk provider (drivers/clk) and one for the
clocksource driver (drivers/clocksource).

> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 0f1c77e..1d2ecde 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -106,6 +106,11 @@ config CLKSRC_EFM32
>  	  Support to use the timers of EFM32 SoCs as clock source and clock
>  	  event device.
>  
> +config CLKSRC_KINETIS
> +	bool "Clocksource for Kinetis SoCs"
> +	depends on OF && ARM && ARCH_KINETIS

Doesn't ARCH_KINETIS imply ARM? Seems that we can drop the ARM
dependency here.

> +	select CLKSRC_OF
>
>
> diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
> new file mode 100644
> index 0000000..634f365
> --- /dev/null
> +++ b/drivers/clocksource/timer-kinetis.c
[..]
> +
> +/*
> + * Clock event device set mode function
> + */
> +static void kinetis_clockevent_tmr_set_mode(
> +	enum clock_event_mode mode, struct clock_event_device *clk)

s/clk/evt/ ?

> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		kinetis_pit_enable(pit->base, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		kinetis_pit_enable(pit->base, 0);
> +	}
> +}
> +
> +/*
> + * Configure the timer to generate an interrupt in the specified amount of ticks
> + */
> +static int kinetis_clockevent_tmr_set_next_event(
> +	unsigned long delta, struct clock_event_device *c)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
> +	unsigned long flags;
> +
> +	raw_local_irq_save(flags);

What is this protecting against?

> +	kinetis_pit_init(pit->base, delta);
> +	kinetis_pit_enable(pit->base, 1);
> +	raw_local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_mode	= kinetis_clockevent_tmr_set_mode,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer1",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer2",
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "fsl,kinetis-pit-timer3",
> +		},
> +	},
> +};
> +
> +/*
> + * Timer IRQ handler
> + */
> +static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
> +{
> +	struct kinetis_clock_event_ddata *tmr = dev_id;
> +
> +	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
> +
> +	tmr->evtdev.event_handler(&(tmr->evtdev));

Unnecessary parentheses, please remove them.

> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * System timer IRQ action
> + */
> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.name = "Kinetis Kernel Time Tick (pit0)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[0],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit1)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[1],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit2)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[2],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit3)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[3],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	},
> +};

Any reason we can't just use request_irq() instead of having a set of
static irq actions?

> +
> +static void __init kinetis_clockevent_init(struct device_node *np)
> +{
[..]
> irq;
> +	}
> +
> +	chan = of_alias_get_id(np, "pit");
> +	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {

Unnecessary parentheses, please remove them.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

--
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] 86+ messages in thread

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
  2015-06-23 21:19   ` Paul Osmialowski
@ 2015-06-23 22:25     ` Arnd Bergmann
  -1 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 22:25 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime

On Tuesday 23 June 2015 23:19:44 Paul Osmialowski wrote:
> +#define KINETIS_CG_UART0       KINETIS_MKCG(3, 10)     /* SIM_SCGC4[10] */
> +#define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> +#define KINETIS_CG_UART2       KINETIS_MKCG(3, 12)     /* SIM_SCGC4[12] */
> +#define KINETIS_CG_UART3       KINETIS_MKCG(3, 13)     /* SIM_SCGC4[13] */
> +#define KINETIS_CG_UART4       KINETIS_MKCG(0, 10)     /* SIM_SCGC1[10] */
> +#define KINETIS_CG_UART5       KINETIS_MKCG(0, 11)     /* SIM_SCGC1[11] */
> +/* Ports */
> +#define KINETIS_CG_PORTA       KINETIS_MKCG(4, 9)      /* SIM_SCGC5[9] */
> +#define KINETIS_CG_PORTB       KINETIS_MKCG(4, 10)     /* SIM_SCGC5[10] */
> +#define KINETIS_CG_PORTC       KINETIS_MKCG(4, 11)     /* SIM_SCGC5[11] */
> +#define KINETIS_CG_PORTD       KINETIS_MKCG(4, 12)     /* SIM_SCGC5[12] */
> +#define KINETIS_CG_PORTE       KINETIS_MKCG(4, 13)     /* SIM_SCGC5[13] */
> +#define KINETIS_CG_PORTF       KINETIS_MKCG(4, 14)     /* SIM_SCGC5[14] */
> 

Instead of using a triple indirection here, just put the tuples
in the DT directly using #clock-cells=<2>, and get rid of both this
header file and the dt-bindings/clock/kinetis-mcg.h file.

	Arnd

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-23 22:25     ` Arnd Bergmann
  0 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-23 22:25 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Bhupesh Sharma,
	Daniel Lezcano, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart,
	Linus Walleij, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Rob Herring, Russell King, Sergey Senozhatsky,
	Shawn Guo, Simon Horman, Stefan Agner, Stephen Boyd,
	Thomas Gleixner, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, Pawel Moll, linux-kernel, linux-arm-kernel,
	linux-clk, linux-gpio, linux-serial, devicetree, dmaengine,
	Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov,
	Alexander Potashev

On Tuesday 23 June 2015 23:19:44 Paul Osmialowski wrote:
> +#define KINETIS_CG_UART0       KINETIS_MKCG(3, 10)     /* SIM_SCGC4[10] */
> +#define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> +#define KINETIS_CG_UART2       KINETIS_MKCG(3, 12)     /* SIM_SCGC4[12] */
> +#define KINETIS_CG_UART3       KINETIS_MKCG(3, 13)     /* SIM_SCGC4[13] */
> +#define KINETIS_CG_UART4       KINETIS_MKCG(0, 10)     /* SIM_SCGC1[10] */
> +#define KINETIS_CG_UART5       KINETIS_MKCG(0, 11)     /* SIM_SCGC1[11] */
> +/* Ports */
> +#define KINETIS_CG_PORTA       KINETIS_MKCG(4, 9)      /* SIM_SCGC5[9] */
> +#define KINETIS_CG_PORTB       KINETIS_MKCG(4, 10)     /* SIM_SCGC5[10] */
> +#define KINETIS_CG_PORTC       KINETIS_MKCG(4, 11)     /* SIM_SCGC5[11] */
> +#define KINETIS_CG_PORTD       KINETIS_MKCG(4, 12)     /* SIM_SCGC5[12] */
> +#define KINETIS_CG_PORTE       KINETIS_MKCG(4, 13)     /* SIM_SCGC5[13] */
> +#define KINETIS_CG_PORTF       KINETIS_MKCG(4, 14)     /* SIM_SCGC5[14] */
> 

Instead of using a triple indirection here, just put the tuples
in the DT directly using #clock-cells=<2>, and get rid of both this
header file and the dt-bindings/clock/kinetis-mcg.h file.

	Arnd

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  2015-06-23 22:05     ` Arnd Bergmann
@ 2015-06-23 22:33       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 22:33 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nic

On Wed, Jun 24, 2015 at 12:05:40AM +0200, Arnd Bergmann wrote:
> On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
> > @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
> >  config FORCE_MAX_ZONEORDER
> >  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
> >  	range 11 64 if ARCH_SHMOBILE_LEGACY
> > -	default "12" if SOC_AM33XX
> > +	default "12" if SOC_AM33XX || ARCH_KINETIS
> >  	default "9" if SA1111 || ARCH_EFM32
> >  	default "11"
> >  	help
> 
> Put it in the defconfig?

That doesn't work - defconfigs only provide the answers to _visible_
options.  This option won't be visible.

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

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
@ 2015-06-23 22:33       ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-23 22:33 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Sergey Senozhatsky, Shawn Guo, Simon Horman, Stefan Agner,
	Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Wed, Jun 24, 2015 at 12:05:40AM +0200, Arnd Bergmann wrote:
> On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
> > @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
> >  config FORCE_MAX_ZONEORDER
> >  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
> >  	range 11 64 if ARCH_SHMOBILE_LEGACY
> > -	default "12" if SOC_AM33XX
> > +	default "12" if SOC_AM33XX || ARCH_KINETIS
> >  	default "9" if SA1111 || ARCH_EFM32
> >  	default "11"
> >  	help
> 
> Put it in the defconfig?

That doesn't work - defconfigs only provide the answers to _visible_
options.  This option won't be visible.

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

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

* Re: [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
  2015-06-23 21:48     ` Russell King - ARM Linux
@ 2015-06-24  4:22       ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  4:22 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Paul Osmialowski, Arnd Bergmann, Olof Johansson,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	Pawel Moll, linux-kernel, linux-arm-kernel, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2211 bytes --]

Hi Russell,

Thanks for the input. Seems like I trusted get_maintainer.pl blindly and 
wasn't selective - it resulted in recipient list much too long.

As for this patch, I think I went too far with adding it. The board boots 
without it properly, and since it covers more general Cortex-M related 
problems I guess it should be excluded from next iteration of the whole 
patchset.

The problems it adresses may still required further discussion, but I 
think it should not block the whole thing.

On Tue, 23 Jun 2015, Russell King - ARM Linux wrote:

> On Tue, Jun 23, 2015 at 11:19:39PM +0200, Paul Osmialowski wrote:
>> This one is inspired by two commits published on Emcraft git repo:
>>
>> https://github.com/EmcraftSystems/linux-emcraft.git
>>
>> 1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
>>  RT #62654. Fixed kernel crashes while running httpd by enabling
>>  "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
>>  generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
>>  Cortex-M3 Errata it may result in incorrect base register when interrupted
>>  or faulted.
>>
>> by: Yuri Tikhonov <yur@emcraft.com>
>>
>> 2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
>>  RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
>>  sure only the correct instructions will be generated.
>>
>> by: Sergei Poselenov <sposelenov@emcraft.com>
>>
>> I reworked these patches to make them less intrusive.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>
> NAK.
>
> The EFM32 code already added core support for Cortex-M3 cores, under
> the symbol CPU_V7M.  Rather than implementing a whole new set of
> Cortex-M3 support alongside the existing code, please work with the
> EFM32 maintainer (Uwe Kleine-König) to come up with a common set of
> core changes that you can all agree on for Cortex-M3.
>
> Please also try to be a little smarter with whom you're sending your
> patches to, the Cc list looks to be excessively long - having soo many
> recipients on your message is a good way to get your message rejected
> by mailing lists as spam.
>
> -- 
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.
>

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

* [PATCH 1/9] arm: select different compiler flags for ARM CortexM3
@ 2015-06-24  4:22       ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  4:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

Thanks for the input. Seems like I trusted get_maintainer.pl blindly and 
wasn't selective - it resulted in recipient list much too long.

As for this patch, I think I went too far with adding it. The board boots 
without it properly, and since it covers more general Cortex-M related 
problems I guess it should be excluded from next iteration of the whole 
patchset.

The problems it adresses may still required further discussion, but I 
think it should not block the whole thing.

On Tue, 23 Jun 2015, Russell King - ARM Linux wrote:

> On Tue, Jun 23, 2015 at 11:19:39PM +0200, Paul Osmialowski wrote:
>> This one is inspired by two commits published on Emcraft git repo:
>>
>> https://github.com/EmcraftSystems/linux-emcraft.git
>>
>> 1) 6302b692f570ff9d5645a6e72c11f87b0c1aa409
>>  RT #62654. Fixed kernel crashes while running httpd by enabling
>>  "-mfix-cortex-m3-ldrd" compiler option, which prevents compiler from
>>  generating code like 'ldrd Ra, Rb, [Ra, #Imm]' - according to the 602117
>>  Cortex-M3 Errata it may result in incorrect base register when interrupted
>>  or faulted.
>>
>> by: Yuri Tikhonov <yur@emcraft.com>
>>
>> 2) 359d3cda84c01c0f3fae1a519b97a31f318f57ab
>>  RT #62654. Removed "--march=..." leaving only "-mcpu=cortex-m3" to make
>>  sure only the correct instructions will be generated.
>>
>> by: Sergei Poselenov <sposelenov@emcraft.com>
>>
>> I reworked these patches to make them less intrusive.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>
> NAK.
>
> The EFM32 code already added core support for Cortex-M3 cores, under
> the symbol CPU_V7M.  Rather than implementing a whole new set of
> Cortex-M3 support alongside the existing code, please work with the
> EFM32 maintainer (Uwe Kleine-K?nig) to come up with a common set of
> core changes that you can all agree on for Cortex-M3.
>
> Please also try to be a little smarter with whom you're sending your
> patches to, the Cc list looks to be excessively long - having soo many
> recipients on your message is a good way to get your message rejected
> by mailing lists as spam.
>
> -- 
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.
>

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  2015-06-23 22:05     ` Arnd Bergmann
@ 2015-06-24  4:42       ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  4:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nic

Hi Arnd,

Thanks for all of your input. Your comments will all be considered during 
my works on the second iteration of this patchset.

On Wed, 24 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
>> @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
>>  config FORCE_MAX_ZONEORDER
>>  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
>>  	range 11 64 if ARCH_SHMOBILE_LEGACY
>> -	default "12" if SOC_AM33XX
>> +	default "12" if SOC_AM33XX || ARCH_KINETIS
>>  	default "9" if SA1111 || ARCH_EFM32
>>  	default "11"
>>  	help
>
> Put it in the defconfig?
>
>> +#
>> +
>> +obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o
>
> just use
>
> obj-y	+= kinetis.o
>
>> diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
>> new file mode 100644
>> index 0000000..0aafefd
>> --- /dev/null
>> +++ b/arch/arm/mach-kinetis/include/mach/idle.h
>
> No mach/*.h files please.
>
>> +/*
>> + * This Kinetis port assumes that the CPU works in little-endian mode.
>> + * Switching to big-endian will require different bit offsets in peripheral
>> + * devices' registers. Also, some bit groups may lay on byte edges, so issue
>> + * with big-endian cannot be fixed only by defining bit offsets differently
>> + * for the big-endian mode.
>> + */
>> +#ifndef __LITTLE_ENDIAN
>> +#error This Kinetis port assumes that the CPU works in little-endian mode
>> +#endif
>
> Fix the drivers instead?
>
>> +/*
>> + * Peripheral memory map
>> + */
>> +#define KINETIS_AIPS0PERIPH_BASE	0x40000000
>> +#define KINETIS_AIPS1PERIPH_BASE	0x40080000
>
> Move it into DT
>
>> +/*
>> + * System Integration Module (SIM) register map
>> + *
>> + * This map actually covers two hardware modules:
>> + *     1. SIM low-power logic, at 0x40047000
>> + *     2. System integration module (SIM), at 0x40048000
>> + */
>> +struct kinetis_sim_regs {
>> +	u32 sopt1;	/* System Options Register 1 */
>> +	u32 rsv0[1024];
>> +	u32 sopt2;	/* System Options Register 2 */
>> +	u32 rsv1;
>> +	u32 sopt4;	/* System Options Register 4 */
>> +	u32 sopt5;	/* System Options Register 5 */
>> +	u32 sopt6;	/* System Options Register 6 */
>> +	u32 sopt7;	/* System Options Register 7 */
>> +	u32 rsv2[2];
>> +	u32 sdid;	/* System Device Identification Register */
>> +	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
>> +	u32 clkdiv1;	/* System Clock Divider Register 1 */
>> +	u32 clkdiv2;	/* System Clock Divider Register 2 */
>> +	u32 fcfg1;	/* Flash Configuration Register 1 */
>> +	u32 fcfg2;	/* Flash Configuration Register 2 */
>> +	u32 uidh;	/* Unique Identification Register High */
>> +	u32 uidmh;	/* Unique Identification Register Mid-High */
>> +	u32 uidml;	/* Unique Identification Register Mid Low */
>> +	u32 uidl;	/* Unique Identification Register Low */
>> +	u32 clkdiv3;	/* System Clock Divider Register 3 */
>> +	u32 clkdiv4;	/* System Clock Divider Register 4 */
>> +	u32 mcr;	/* Misc Control Register */
>> +};
>
> Move it into the driver that uses these.
>
>> +/*
>> + * SIM registers base
>> + */
>> +#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
>> +#define KINETIS_SIM_PTR(reg) \
>> +	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
>> +#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
>> +#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
>> +#define KINETIS_SIM_SET(reg, mask) \
>> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
>> +#define KINETIS_SIM_RESET(reg, mask) \
>> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
>> +#define KINETIS_SIM_ISSET(reg, mask) \
>> +	(KINETIS_SIM_RD(reg) & (mask))
>> +
>> +/*
>> + * SIM registers
>> + */
>> +/*
>> + * System Options Register 2
>> + */
>> +/* USB HS clock source select */
>> +#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
>> +#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +
>> +/* USB FS clock source select */
>> +#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
>> +#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
>> +
>
> remove all these here.
>
>> +/*
>> + * Map required regions.
>> + * This being the no-MMU Linux, I am not mapping anything
>> + * since all I/O registers are available at their physical addresses.
>> + */
>> +static void __init kinetis_map_io(void)
>> +{
>> +}
>
> Not needed, remove.
>
>> +/*
>> + * Freescale Kinetis platform initialization
>> + */
>> +static void __init kinetis_init(void)
>> +{
>> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>> +}
>
> same here.
>
>> diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
>> index 2ed1b8a..1d05516 100644
>> --- a/arch/arm/tools/mach-types
>> +++ b/arch/arm/tools/mach-types
>> @@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
>>  marzen			MACH_MARZEN		MARZEN			3790
>>  krome			MACH_KROME		KROME			3797
>>  armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
>> +kinetis			MACH_KINETIS		KINETIS			3896
>>  mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
>>  mt4			MACH_MT4		MT4			3981
>>  u8520			MACH_U8520		U8520			3990
>
> Unused, please remove.
>
> 	Arnd
>

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

* Re: [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
@ 2015-06-24  4:42       ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  4:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

Hi Arnd,

Thanks for all of your input. Your comments will all be considered during 
my works on the second iteration of this patchset.

On Wed, 24 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 23 June 2015 23:19:43 Paul Osmialowski wrote:
>> @@ -1740,7 +1752,7 @@ source "mm/Kconfig"
>>  config FORCE_MAX_ZONEORDER
>>  	int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
>>  	range 11 64 if ARCH_SHMOBILE_LEGACY
>> -	default "12" if SOC_AM33XX
>> +	default "12" if SOC_AM33XX || ARCH_KINETIS
>>  	default "9" if SA1111 || ARCH_EFM32
>>  	default "11"
>>  	help
>
> Put it in the defconfig?
>
>> +#
>> +
>> +obj-$(CONFIG_MACH_KINETIS)	+= kinetis_platform.o
>
> just use
>
> obj-y	+= kinetis.o
>
>> diff --git a/arch/arm/mach-kinetis/include/mach/idle.h b/arch/arm/mach-kinetis/include/mach/idle.h
>> new file mode 100644
>> index 0000000..0aafefd
>> --- /dev/null
>> +++ b/arch/arm/mach-kinetis/include/mach/idle.h
>
> No mach/*.h files please.
>
>> +/*
>> + * This Kinetis port assumes that the CPU works in little-endian mode.
>> + * Switching to big-endian will require different bit offsets in peripheral
>> + * devices' registers. Also, some bit groups may lay on byte edges, so issue
>> + * with big-endian cannot be fixed only by defining bit offsets differently
>> + * for the big-endian mode.
>> + */
>> +#ifndef __LITTLE_ENDIAN
>> +#error This Kinetis port assumes that the CPU works in little-endian mode
>> +#endif
>
> Fix the drivers instead?
>
>> +/*
>> + * Peripheral memory map
>> + */
>> +#define KINETIS_AIPS0PERIPH_BASE	0x40000000
>> +#define KINETIS_AIPS1PERIPH_BASE	0x40080000
>
> Move it into DT
>
>> +/*
>> + * System Integration Module (SIM) register map
>> + *
>> + * This map actually covers two hardware modules:
>> + *     1. SIM low-power logic, at 0x40047000
>> + *     2. System integration module (SIM), at 0x40048000
>> + */
>> +struct kinetis_sim_regs {
>> +	u32 sopt1;	/* System Options Register 1 */
>> +	u32 rsv0[1024];
>> +	u32 sopt2;	/* System Options Register 2 */
>> +	u32 rsv1;
>> +	u32 sopt4;	/* System Options Register 4 */
>> +	u32 sopt5;	/* System Options Register 5 */
>> +	u32 sopt6;	/* System Options Register 6 */
>> +	u32 sopt7;	/* System Options Register 7 */
>> +	u32 rsv2[2];
>> +	u32 sdid;	/* System Device Identification Register */
>> +	u32 scgc[KINETIS_SIM_CG_NUMREGS];	/* Clock Gating Regs 1...7 */
>> +	u32 clkdiv1;	/* System Clock Divider Register 1 */
>> +	u32 clkdiv2;	/* System Clock Divider Register 2 */
>> +	u32 fcfg1;	/* Flash Configuration Register 1 */
>> +	u32 fcfg2;	/* Flash Configuration Register 2 */
>> +	u32 uidh;	/* Unique Identification Register High */
>> +	u32 uidmh;	/* Unique Identification Register Mid-High */
>> +	u32 uidml;	/* Unique Identification Register Mid Low */
>> +	u32 uidl;	/* Unique Identification Register Low */
>> +	u32 clkdiv3;	/* System Clock Divider Register 3 */
>> +	u32 clkdiv4;	/* System Clock Divider Register 4 */
>> +	u32 mcr;	/* Misc Control Register */
>> +};
>
> Move it into the driver that uses these.
>
>> +/*
>> + * SIM registers base
>> + */
>> +#define KINETIS_SIM_BASE		(KINETIS_AIPS0PERIPH_BASE + 0x00047000)
>> +#define KINETIS_SIM_PTR(reg) \
>> +	(&(((struct kinetis_sim_regs *)(KINETIS_SIM_BASE))->reg))
>> +#define KINETIS_SIM_RD(reg) readl_relaxed(KINETIS_SIM_PTR(reg))
>> +#define KINETIS_SIM_WR(reg, val) writel_relaxed((val), KINETIS_SIM_PTR(reg))
>> +#define KINETIS_SIM_SET(reg, mask) \
>> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) | (mask))
>> +#define KINETIS_SIM_RESET(reg, mask) \
>> +	KINETIS_SIM_WR(reg, (KINETIS_SIM_RD(reg)) & (~(mask)))
>> +#define KINETIS_SIM_ISSET(reg, mask) \
>> +	(KINETIS_SIM_RD(reg) & (mask))
>> +
>> +/*
>> + * SIM registers
>> + */
>> +/*
>> + * System Options Register 2
>> + */
>> +/* USB HS clock source select */
>> +#define KINETIS_SIM_SOPT2_USBHSRC_BITS	2
>> +#define KINETIS_SIM_SOPT2_USBHSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBHSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBHSRC_BITS)
>> +
>> +/* USB FS clock source select */
>> +#define KINETIS_SIM_SOPT2_USBFSRC_BITS	22
>> +#define KINETIS_SIM_SOPT2_USBFSRC_MSK	(3 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL0	(1 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBFSRC_PLL1	(2 << KINETIS_SIM_SOPT2_USBFSRC_BITS)
>> +#define KINETIS_SIM_SOPT2_USBF_CLKSEL	(1 << 18)
>> +
>
> remove all these here.
>
>> +/*
>> + * Map required regions.
>> + * This being the no-MMU Linux, I am not mapping anything
>> + * since all I/O registers are available at their physical addresses.
>> + */
>> +static void __init kinetis_map_io(void)
>> +{
>> +}
>
> Not needed, remove.
>
>> +/*
>> + * Freescale Kinetis platform initialization
>> + */
>> +static void __init kinetis_init(void)
>> +{
>> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>> +}
>
> same here.
>
>> diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
>> index 2ed1b8a..1d05516 100644
>> --- a/arch/arm/tools/mach-types
>> +++ b/arch/arm/tools/mach-types
>> @@ -554,6 +554,7 @@ smdk4412		MACH_SMDK4412		SMDK4412		3765
>>  marzen			MACH_MARZEN		MARZEN			3790
>>  krome			MACH_KROME		KROME			3797
>>  armadillo800eva		MACH_ARMADILLO800EVA	ARMADILLO800EVA		3863
>> +kinetis			MACH_KINETIS		KINETIS			3896
>>  mx53_umobo		MACH_MX53_UMOBO		MX53_UMOBO		3927
>>  mt4			MACH_MT4		MT4			3981
>>  u8520			MACH_U8520		U8520			3990
>
> Unused, please remove.
>
> 	Arnd
>

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
  2015-06-23 22:24     ` Stephen Boyd
@ 2015-06-24  5:09       ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  5:09 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan

Hi Stephen,

Thanks for the valuable input - all of those points are now on my 
checklist for the work on the second iteration of this patchset.

On Tue, 23 Jun 2015, Stephen Boyd wrote:

> On 06/23/2015 02:19 PM, Paul Osmialowski wrote:
>>
>> diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
>> new file mode 100644
>> index 0000000..dea1054
>> --- /dev/null
>> +++ b/drivers/clk/clk-kinetis.c
>> @@ -0,0 +1,226 @@
>> +/*
>> + * clk-kinetis.c - Clock driver for Kinetis K70 MCG
>> + *
>> + * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
>> + *
>> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it under
>> + * the terms of the GNU General Public License version 2 as published by the
>> + * Free Software Foundation.
>> + */
>> +
>> +#include <linux/clk.h>
>
> Is this using the consumer API? Please remove this include.
>
>> +#include <linux/io.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/err.h>
>> +#include <mach/kinetis.h>
>> +#include <mach/power.h>
>
> It would be nice if we didn't need these mach includes so that this
> driver can be easily build tested.
>
>> +
>> +#include <dt-bindings/clock/kinetis-mcg.h>
> [..]
>> +}
>> +
>> +CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
>
> A clocksource isn't the same as a clk provider. Please split this patch
> into two, one for the clk provider (drivers/clk) and one for the
> clocksource driver (drivers/clocksource).
>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 0f1c77e..1d2ecde 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -106,6 +106,11 @@ config CLKSRC_EFM32
>>  	  Support to use the timers of EFM32 SoCs as clock source and clock
>>  	  event device.
>>
>> +config CLKSRC_KINETIS
>> +	bool "Clocksource for Kinetis SoCs"
>> +	depends on OF && ARM && ARCH_KINETIS
>
> Doesn't ARCH_KINETIS imply ARM? Seems that we can drop the ARM
> dependency here.
>
>> +	select CLKSRC_OF
>>
>>
>> diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
>> new file mode 100644
>> index 0000000..634f365
>> --- /dev/null
>> +++ b/drivers/clocksource/timer-kinetis.c
> [..]
>> +
>> +/*
>> + * Clock event device set mode function
>> + */
>> +static void kinetis_clockevent_tmr_set_mode(
>> +	enum clock_event_mode mode, struct clock_event_device *clk)
>
> s/clk/evt/ ?
>
>> +{
>> +	struct kinetis_clock_event_ddata *pit =
>> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
>> +
>> +	switch (mode) {
>> +	case CLOCK_EVT_MODE_PERIODIC:
>> +		kinetis_pit_enable(pit->base, 1);
>> +		break;
>> +	case CLOCK_EVT_MODE_ONESHOT:
>> +	case CLOCK_EVT_MODE_UNUSED:
>> +	case CLOCK_EVT_MODE_SHUTDOWN:
>> +	default:
>> +		kinetis_pit_enable(pit->base, 0);
>> +	}
>> +}
>> +
>> +/*
>> + * Configure the timer to generate an interrupt in the specified amount of ticks
>> + */
>> +static int kinetis_clockevent_tmr_set_next_event(
>> +	unsigned long delta, struct clock_event_device *c)
>> +{
>> +	struct kinetis_clock_event_ddata *pit =
>> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
>> +	unsigned long flags;
>> +
>> +	raw_local_irq_save(flags);
>
> What is this protecting against?
>
>> +	kinetis_pit_init(pit->base, delta);
>> +	kinetis_pit_enable(pit->base, 1);
>> +	raw_local_irq_restore(flags);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct kinetis_clock_event_ddata
>> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer0",
>> +			.rating		= 200,
>> +			.features	=
>> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
>> +			.set_mode	= kinetis_clockevent_tmr_set_mode,
>> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer1",
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer2",
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer3",
>> +		},
>> +	},
>> +};
>> +
>> +/*
>> + * Timer IRQ handler
>> + */
>> +static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct kinetis_clock_event_ddata *tmr = dev_id;
>> +
>> +	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
>> +
>> +	tmr->evtdev.event_handler(&(tmr->evtdev));
>
> Unnecessary parentheses, please remove them.
>
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +/*
>> + * System timer IRQ action
>> + */
>> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
>> +	{
>> +		.name = "Kinetis Kernel Time Tick (pit0)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[0],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit1)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[1],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit2)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[2],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit3)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[3],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	},
>> +};
>
> Any reason we can't just use request_irq() instead of having a set of
> static irq actions?
>
>> +
>> +static void __init kinetis_clockevent_init(struct device_node *np)
>> +{
> [..]
>> irq;
>> +	}
>> +
>> +	chan = of_alias_get_id(np, "pit");
>> +	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
>
> Unnecessary parentheses, please remove them.
>
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-24  5:09       ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  5:09 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

Hi Stephen,

Thanks for the valuable input - all of those points are now on my 
checklist for the work on the second iteration of this patchset.

On Tue, 23 Jun 2015, Stephen Boyd wrote:

> On 06/23/2015 02:19 PM, Paul Osmialowski wrote:
>>
>> diff --git a/drivers/clk/clk-kinetis.c b/drivers/clk/clk-kinetis.c
>> new file mode 100644
>> index 0000000..dea1054
>> --- /dev/null
>> +++ b/drivers/clk/clk-kinetis.c
>> @@ -0,0 +1,226 @@
>> +/*
>> + * clk-kinetis.c - Clock driver for Kinetis K70 MCG
>> + *
>> + * Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>
>> + *
>> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it under
>> + * the terms of the GNU General Public License version 2 as published by the
>> + * Free Software Foundation.
>> + */
>> +
>> +#include <linux/clk.h>
>
> Is this using the consumer API? Please remove this include.
>
>> +#include <linux/io.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/err.h>
>> +#include <mach/kinetis.h>
>> +#include <mach/power.h>
>
> It would be nice if we didn't need these mach includes so that this
> driver can be easily build tested.
>
>> +
>> +#include <dt-bindings/clock/kinetis-mcg.h>
> [..]
>> +}
>> +
>> +CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
>
> A clocksource isn't the same as a clk provider. Please split this patch
> into two, one for the clk provider (drivers/clk) and one for the
> clocksource driver (drivers/clocksource).
>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 0f1c77e..1d2ecde 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -106,6 +106,11 @@ config CLKSRC_EFM32
>>  	  Support to use the timers of EFM32 SoCs as clock source and clock
>>  	  event device.
>>
>> +config CLKSRC_KINETIS
>> +	bool "Clocksource for Kinetis SoCs"
>> +	depends on OF && ARM && ARCH_KINETIS
>
> Doesn't ARCH_KINETIS imply ARM? Seems that we can drop the ARM
> dependency here.
>
>> +	select CLKSRC_OF
>>
>>
>> diff --git a/drivers/clocksource/timer-kinetis.c b/drivers/clocksource/timer-kinetis.c
>> new file mode 100644
>> index 0000000..634f365
>> --- /dev/null
>> +++ b/drivers/clocksource/timer-kinetis.c
> [..]
>> +
>> +/*
>> + * Clock event device set mode function
>> + */
>> +static void kinetis_clockevent_tmr_set_mode(
>> +	enum clock_event_mode mode, struct clock_event_device *clk)
>
> s/clk/evt/ ?
>
>> +{
>> +	struct kinetis_clock_event_ddata *pit =
>> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
>> +
>> +	switch (mode) {
>> +	case CLOCK_EVT_MODE_PERIODIC:
>> +		kinetis_pit_enable(pit->base, 1);
>> +		break;
>> +	case CLOCK_EVT_MODE_ONESHOT:
>> +	case CLOCK_EVT_MODE_UNUSED:
>> +	case CLOCK_EVT_MODE_SHUTDOWN:
>> +	default:
>> +		kinetis_pit_enable(pit->base, 0);
>> +	}
>> +}
>> +
>> +/*
>> + * Configure the timer to generate an interrupt in the specified amount of ticks
>> + */
>> +static int kinetis_clockevent_tmr_set_next_event(
>> +	unsigned long delta, struct clock_event_device *c)
>> +{
>> +	struct kinetis_clock_event_ddata *pit =
>> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
>> +	unsigned long flags;
>> +
>> +	raw_local_irq_save(flags);
>
> What is this protecting against?
>
>> +	kinetis_pit_init(pit->base, delta);
>> +	kinetis_pit_enable(pit->base, 1);
>> +	raw_local_irq_restore(flags);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct kinetis_clock_event_ddata
>> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer0",
>> +			.rating		= 200,
>> +			.features	=
>> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
>> +			.set_mode	= kinetis_clockevent_tmr_set_mode,
>> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer1",
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer2",
>> +		},
>> +	},
>> +	{
>> +		.evtdev = {
>> +			.name		= "fsl,kinetis-pit-timer3",
>> +		},
>> +	},
>> +};
>> +
>> +/*
>> + * Timer IRQ handler
>> + */
>> +static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct kinetis_clock_event_ddata *tmr = dev_id;
>> +
>> +	KINETIS_PIT_WR(tmr->base, tflg, KINETIS_PIT_TFLG_TIF_MSK);
>> +
>> +	tmr->evtdev.event_handler(&(tmr->evtdev));
>
> Unnecessary parentheses, please remove them.
>
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +/*
>> + * System timer IRQ action
>> + */
>> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
>> +	{
>> +		.name = "Kinetis Kernel Time Tick (pit0)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[0],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit1)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[1],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit2)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[2],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	}, {
>> +		.name = "Kinetis Kernel Time Tick (pit3)",
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +		.dev_id = &kinetis_clockevent_tmrs[3],
>> +		.handler = kinetis_clockevent_tmr_irq_handler,
>> +	},
>> +};
>
> Any reason we can't just use request_irq() instead of having a set of
> static irq actions?
>
>> +
>> +static void __init kinetis_clockevent_init(struct device_node *np)
>> +{
> [..]
>> irq;
>> +	}
>> +
>> +	chan = of_alias_get_id(np, "pit");
>> +	if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
>
> Unnecessary parentheses, please remove them.
>
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

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

* Re: [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small
  2015-06-23 21:19   ` Paul Osmialowski
  (?)
@ 2015-06-24  7:10   ` Geert Uytterhoeven
  2015-06-24  7:17     ` Paul Osmialowski
  -1 siblings, 1 reply; 86+ messages in thread
From: Geert Uytterhoeven @ 2015-06-24  7:10 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> Since stack on Cortex-M3 is too small, we need configuration option
> to avoid using it for huge encoder tables of zlib.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

> --- a/lib/zlib_inflate/inflate.c
> +++ b/lib/zlib_inflate/inflate.c
> @@ -75,9 +75,14 @@ int zlib_inflateInit2(z_streamp strm, int windowBits)
>     Return state with length and distance decoding tables and index sizes set to
>     fixed code decoding.  This returns fixed tables from inffixed.h.
>   */
> +#ifdef CONFIG_ZLIB_INFLATE_STACK_SAVING
> +#   include "inffixed.h"
> +#endif
>  static void zlib_fixedtables(struct inflate_state *state)
>  {
> +#ifndef CONFIG_ZLIB_INFLATE_STACK_SAVING
>  #   include "inffixed.h"

All variables in inffixed.h are "static const", so they are not on the stack
anyway, and this patch shouldn't make a difference.

> +#endif

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small
  2015-06-24  7:10   ` Geert Uytterhoeven
@ 2015-06-24  7:17     ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24  7:17 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Stephen Boyd, Thomas Gleixner,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	Pawel Moll, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

Hi Geert,

You're right. To be removed. Thanks for spotting this.

On Wed, 24 Jun 2015, Geert Uytterhoeven wrote:

> On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
>> Since stack on Cortex-M3 is too small, we need configuration option
>> to avoid using it for huge encoder tables of zlib.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>
>> --- a/lib/zlib_inflate/inflate.c
>> +++ b/lib/zlib_inflate/inflate.c
>> @@ -75,9 +75,14 @@ int zlib_inflateInit2(z_streamp strm, int windowBits)
>>     Return state with length and distance decoding tables and index sizes set to
>>     fixed code decoding.  This returns fixed tables from inffixed.h.
>>   */
>> +#ifdef CONFIG_ZLIB_INFLATE_STACK_SAVING
>> +#   include "inffixed.h"
>> +#endif
>>  static void zlib_fixedtables(struct inflate_state *state)
>>  {
>> +#ifndef CONFIG_ZLIB_INFLATE_STACK_SAVING
>>  #   include "inffixed.h"
>
> All variables in inffixed.h are "static const", so they are not on the stack
> anyway, and this patch shouldn't make a difference.
>
>> +#endif
>
> Gr{oetje,eeting}s,
>
>                        Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                -- Linus Torvalds
>

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
  2015-06-23 21:19   ` Paul Osmialowski
@ 2015-06-24  7:53     ` Thomas Gleixner
  -1 siblings, 0 replies; 86+ messages in thread
From: Thomas Gleixner @ 2015-06-24  7:53 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas

On Tue, 23 Jun 2015, Paul Osmialowski wrote:
> +/*
> + * Clock event device set mode function
> + */
> +static void kinetis_clockevent_tmr_set_mode(
> +	enum clock_event_mode mode, struct clock_event_device *clk)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		kinetis_pit_enable(pit->base, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		kinetis_pit_enable(pit->base, 0);
> +	}
> +}

Please move to the new set_state_* interfaces. set_mode() is deprecated.

> +static int kinetis_clockevent_tmr_set_next_event(
> +	unsigned long delta, struct clock_event_device *c)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
> +	unsigned long flags;
> +
> +	raw_local_irq_save(flags);

Pointless exercise. This is called with interrupts disabled.

> +	kinetis_pit_init(pit->base, delta);
> +	kinetis_pit_enable(pit->base, 1);
> +	raw_local_irq_restore(flags);


> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.name = "Kinetis Kernel Time Tick (pit0)",

Please use oneword descriptive names not half sentences.

> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[0],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit1)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[1],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit2)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[2],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit3)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[3],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	},

Aside of that. Please use standard request_irq() there is no reason to
use setup_irq here.

> +
> +	setup_irq(irq, &(kinetis_clockevent_irqaction[chan]));

  request_irq(irq, handler, flags, "name", &kinetis_clockevent_tmrs[chan]);

....

Thanks,

	tglx

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

* Re: [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC
@ 2015-06-24  7:53     ` Thomas Gleixner
  0 siblings, 0 replies; 86+ messages in thread
From: Thomas Gleixner @ 2015-06-24  7:53 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Uwe Kleine-Koenig, Catalin Marinas,
	Dave Martin, Mark Rutland, Pawel Moll, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Yuri Tikhonov, Sergei Poselenov,
	Dmitry Cherkassov, Alexander Potashev

On Tue, 23 Jun 2015, Paul Osmialowski wrote:
> +/*
> + * Clock event device set mode function
> + */
> +static void kinetis_clockevent_tmr_set_mode(
> +	enum clock_event_mode mode, struct clock_event_device *clk)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(clk, struct kinetis_clock_event_ddata, evtdev);
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		kinetis_pit_enable(pit->base, 1);
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +	default:
> +		kinetis_pit_enable(pit->base, 0);
> +	}
> +}

Please move to the new set_state_* interfaces. set_mode() is deprecated.

> +static int kinetis_clockevent_tmr_set_next_event(
> +	unsigned long delta, struct clock_event_device *c)
> +{
> +	struct kinetis_clock_event_ddata *pit =
> +		container_of(c, struct kinetis_clock_event_ddata, evtdev);
> +	unsigned long flags;
> +
> +	raw_local_irq_save(flags);

Pointless exercise. This is called with interrupts disabled.

> +	kinetis_pit_init(pit->base, delta);
> +	kinetis_pit_enable(pit->base, 1);
> +	raw_local_irq_restore(flags);


> +static struct irqaction kinetis_clockevent_irqaction[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.name = "Kinetis Kernel Time Tick (pit0)",

Please use oneword descriptive names not half sentences.

> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[0],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit1)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[1],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit2)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[2],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	}, {
> +		.name = "Kinetis Kernel Time Tick (pit3)",
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +		.dev_id = &kinetis_clockevent_tmrs[3],
> +		.handler = kinetis_clockevent_tmr_irq_handler,
> +	},

Aside of that. Please use standard request_irq() there is no reason to
use setup_irq here.

> +
> +	setup_irq(irq, &(kinetis_clockevent_irqaction[chan]));

  request_irq(irq, handler, flags, "name", &kinetis_clockevent_tmrs[chan]);

....

Thanks,

	tglx

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
  2015-06-24 10:21     ` Paul Bolle
@ 2015-06-24 10:21     ` Paul Bolle
  1 sibling, 0 replies; 86+ messages in thread
From: Paul Bolle @ 2015-06-24 10:21 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
 
> +config PINCTRL_KINETIS
> +	bool "Kinetis pinctrl driver"
> +	depends on OF
> +	depends on SOC_K70
> +	select PINMUX
> +	help
> +	  Say Y here to enable the Kinetis pinctrl driver

> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile

> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o

> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c

> +#include <linux/module.h>

> +static struct pinctrl_desc kinetis_pinctrl_desc = {
> +	[...]
> +	.owner = THIS_MODULE,
> +};

> +static void __exit kinetis_pinctrl_exit(void)
> +{
> +	platform_driver_unregister(&kinetis_pinctrl_driver);
> +}
> +module_exit(kinetis_pinctrl_exit);
> +
> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
> +MODULE_LICENSE("GPL v2");

pinctrl-kinetis.o can only be built-in, right? But the code uses a few
module specific constructs. Did you mean to make PINCTRL_KINETIS
tristate instead?

Thanks,


Paul Bolle

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-06-24 10:21     ` Paul Bolle
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Bolle @ 2015-06-24 10:21 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
 
> +config PINCTRL_KINETIS
> +	bool "Kinetis pinctrl driver"
> +	depends on OF
> +	depends on SOC_K70
> +	select PINMUX
> +	help
> +	  Say Y here to enable the Kinetis pinctrl driver

> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile

> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o

> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c

> +#include <linux/module.h>

> +static struct pinctrl_desc kinetis_pinctrl_desc = {
> +	[...]
> +	.owner = THIS_MODULE,
> +};

> +static void __exit kinetis_pinctrl_exit(void)
> +{
> +	platform_driver_unregister(&kinetis_pinctrl_driver);
> +}
> +module_exit(kinetis_pinctrl_exit);
> +
> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
> +MODULE_LICENSE("GPL v2");

pinctrl-kinetis.o can only be built-in, right? But the code uses a few
module specific constructs. Did you mean to make PINCTRL_KINETIS
tristate instead?

Thanks,


Paul Bolle

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
       [not found]   ` <1435094387-20146-8-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-06-24 10:21     ` Paul Bolle
  2015-07-14  8:53       ` Linus Walleij
  1 sibling, 0 replies; 86+ messages in thread
From: Paul Bolle @ 2015-06-24 10:21 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
 
> +config PINCTRL_KINETIS
> +	bool "Kinetis pinctrl driver"
> +	depends on OF
> +	depends on SOC_K70
> +	select PINMUX
> +	help
> +	  Say Y here to enable the Kinetis pinctrl driver

> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile

> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o

> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c

> +#include <linux/module.h>

> +static struct pinctrl_desc kinetis_pinctrl_desc = {
> +	[...]
> +	.owner = THIS_MODULE,
> +};

> +static void __exit kinetis_pinctrl_exit(void)
> +{
> +	platform_driver_unregister(&kinetis_pinctrl_driver);
> +}
> +module_exit(kinetis_pinctrl_exit);
> +
> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
> +MODULE_LICENSE("GPL v2");

pinctrl-kinetis.o can only be built-in, right? But the code uses a few
module specific constructs. Did you mean to make PINCTRL_KINETIS
tristate instead?

Thanks,


Paul Bolle
--
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] 86+ messages in thread

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-06-24 10:21     ` Paul Bolle
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Bolle @ 2015-06-24 10:21 UTC (permalink / raw)
  To: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
 
> +config PINCTRL_KINETIS
> +	bool "Kinetis pinctrl driver"
> +	depends on OF
> +	depends on SOC_K70
> +	select PINMUX
> +	help
> +	  Say Y here to enable the Kinetis pinctrl driver

> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile

> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o

> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c

> +#include <linux/module.h>

> +static struct pinctrl_desc kinetis_pinctrl_desc = {
> +	[...]
> +	.owner = THIS_MODULE,
> +};

> +static void __exit kinetis_pinctrl_exit(void)
> +{
> +	platform_driver_unregister(&kinetis_pinctrl_driver);
> +}
> +module_exit(kinetis_pinctrl_exit);
> +
> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
> +MODULE_LICENSE("GPL v2");

pinctrl-kinetis.o can only be built-in, right? But the code uses a few
module specific constructs. Did you mean to make PINCTRL_KINETIS
tristate instead?

Thanks,


Paul Bolle

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

* Re: [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
  2015-06-23 21:19   ` Paul Osmialowski
@ 2015-06-24 16:14       ` Vinod Koul
  -1 siblings, 0 replies; 86+ messages in thread
From: Vinod Koul @ 2015-06-24 16:14 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas

On Tue, Jun 23, 2015 at 11:19:46PM +0200, Paul Osmialowski wrote:
> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
> 
> Note that <mach/memory.h> is needed (which is denoted by
> CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
> operation of DMA allocation functions.
> 
> Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
>  arch/arm/Kconfig                                   |  4 ++
>  arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
>  arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
>  drivers/clk/clk-kinetis.c                          | 15 ++++
>  drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
>  include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
having so many change into one patch is not a great idea, please breka them
up. I am looking for single/multiple patches which only touch dmaengine
files


> +#ifdef CONFIG_ARCH_KINETIS
> +static const char * const txirq_names[] = {
> +	"edma-tx-0,16",
> +	"edma-tx-1,17",
> +	"edma-tx-2,18",
> +	"edma-tx-3,19",
> +	"edma-tx-4,20",
> +	"edma-tx-5,21",
> +	"edma-tx-6,22",
> +	"edma-tx-7,23",
> +	"edma-tx-8,24",
> +	"edma-tx-9,25",
> +	"edma-tx-10,26",
> +	"edma-tx-11,27",
> +	"edma-tx-12,28",
> +	"edma-tx-13,29",
> +	"edma-tx-14,30",
> +	"edma-tx-15,31",
> +};
why do we need this array, these seem to come from DT, right?
> +#endif
> +
>  struct fsl_edma_engine {
>  	struct dma_device	dma_dev;
>  	void __iomem		*membase;
> +#ifdef CONFIG_ARCH_KINETIS
> +	struct clk		*clk;
> +#endif
>  	void __iomem		*muxbase[DMAMUX_NR];
>  	struct clk		*muxclk[DMAMUX_NR];
>  	struct mutex		fsl_edma_mutex;
>  	u32			n_chans;
> +#ifdef CONFIG_ARCH_KINETIS
> +	int			txirq[ARRAY_SIZE(txirq_names)];
> +#else
>  	int			txirq;
> +#endif
>  	int			errirq;
>  	bool			big_endian;
>  	struct fsl_edma_chan	chans[];
we can define these bits and only be used on kinetis machines?

> @@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +#ifndef CONFIG_ARCH_KINETIS
>  static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>  {
>  	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
> @@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>  
>  	return fsl_edma_err_handler(irq, dev_id);
>  }
> +#endif
>  
>  static void fsl_edma_issue_pending(struct dma_chan *chan)
>  {
> @@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
>  }
>  
>  static int
> -fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
> +fsl_edma_irq_init(struct platform_device *pdev,
> +		  struct fsl_edma_engine *fsl_edma)
>  {
>  	int ret;
> +#ifdef CONFIG_ARCH_KINETIS
> +	int i;
>  
> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
> +		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
> +					txirq_names[i]);
> +		if (fsl_edma->txirq[i] < 0) {
> +			dev_err(&pdev->dev, "Can't get %s irq.\n",
> +						txirq_names[i]);
> +			return fsl_edma->txirq[i];
> +		}
> +	}
> +#else
>  	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
>  	if (fsl_edma->txirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>  		return fsl_edma->txirq;
>  	}
> +#endif
can you have two routines and with one of them onvoked based on machine type
which should be configured based on DT data rather

>  
>  	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>  	if (fsl_edma->errirq < 0) {
> @@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>  		return fsl_edma->errirq;
>  	}
>  
> +#ifdef CONFIG_ARCH_KINETIS
> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
> +		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
> +			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
> +		if (ret) {
> +			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> +			return  ret;
> +		}
> +	}
> +#else
>  	if (fsl_edma->txirq == fsl_edma->errirq) {
>  		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>  				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> @@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>  			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>  			return  ret;
>  		}
> +#endif
only one of them will be populated so if-else should work too

please get rid of these ifdef stuff and make it based on DT data based flags

-- 
~Vinod
--
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] 86+ messages in thread

* Re: [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
@ 2015-06-24 16:14       ` Vinod Koul
  0 siblings, 0 replies; 86+ messages in thread
From: Vinod Koul @ 2015-06-24 16:14 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Andrew Morton, Anson Huang, Ard Biesheuvel, Arnd Bergmann,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Nicolas Pitre, Maxime Coquelin stm32,
	Olof Johansson, Paul Bolle, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Tue, Jun 23, 2015 at 11:19:46PM +0200, Paul Osmialowski wrote:
> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
> 
> Note that <mach/memory.h> is needed (which is denoted by
> CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
> operation of DMA allocation functions.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
>  arch/arm/Kconfig                                   |  4 ++
>  arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
>  arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
>  drivers/clk/clk-kinetis.c                          | 15 ++++
>  drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
>  include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
having so many change into one patch is not a great idea, please breka them
up. I am looking for single/multiple patches which only touch dmaengine
files


> +#ifdef CONFIG_ARCH_KINETIS
> +static const char * const txirq_names[] = {
> +	"edma-tx-0,16",
> +	"edma-tx-1,17",
> +	"edma-tx-2,18",
> +	"edma-tx-3,19",
> +	"edma-tx-4,20",
> +	"edma-tx-5,21",
> +	"edma-tx-6,22",
> +	"edma-tx-7,23",
> +	"edma-tx-8,24",
> +	"edma-tx-9,25",
> +	"edma-tx-10,26",
> +	"edma-tx-11,27",
> +	"edma-tx-12,28",
> +	"edma-tx-13,29",
> +	"edma-tx-14,30",
> +	"edma-tx-15,31",
> +};
why do we need this array, these seem to come from DT, right?
> +#endif
> +
>  struct fsl_edma_engine {
>  	struct dma_device	dma_dev;
>  	void __iomem		*membase;
> +#ifdef CONFIG_ARCH_KINETIS
> +	struct clk		*clk;
> +#endif
>  	void __iomem		*muxbase[DMAMUX_NR];
>  	struct clk		*muxclk[DMAMUX_NR];
>  	struct mutex		fsl_edma_mutex;
>  	u32			n_chans;
> +#ifdef CONFIG_ARCH_KINETIS
> +	int			txirq[ARRAY_SIZE(txirq_names)];
> +#else
>  	int			txirq;
> +#endif
>  	int			errirq;
>  	bool			big_endian;
>  	struct fsl_edma_chan	chans[];
we can define these bits and only be used on kinetis machines?

> @@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +#ifndef CONFIG_ARCH_KINETIS
>  static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>  {
>  	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
> @@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>  
>  	return fsl_edma_err_handler(irq, dev_id);
>  }
> +#endif
>  
>  static void fsl_edma_issue_pending(struct dma_chan *chan)
>  {
> @@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
>  }
>  
>  static int
> -fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
> +fsl_edma_irq_init(struct platform_device *pdev,
> +		  struct fsl_edma_engine *fsl_edma)
>  {
>  	int ret;
> +#ifdef CONFIG_ARCH_KINETIS
> +	int i;
>  
> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
> +		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
> +					txirq_names[i]);
> +		if (fsl_edma->txirq[i] < 0) {
> +			dev_err(&pdev->dev, "Can't get %s irq.\n",
> +						txirq_names[i]);
> +			return fsl_edma->txirq[i];
> +		}
> +	}
> +#else
>  	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
>  	if (fsl_edma->txirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>  		return fsl_edma->txirq;
>  	}
> +#endif
can you have two routines and with one of them onvoked based on machine type
which should be configured based on DT data rather

>  
>  	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>  	if (fsl_edma->errirq < 0) {
> @@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>  		return fsl_edma->errirq;
>  	}
>  
> +#ifdef CONFIG_ARCH_KINETIS
> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
> +		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
> +			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
> +		if (ret) {
> +			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> +			return  ret;
> +		}
> +	}
> +#else
>  	if (fsl_edma->txirq == fsl_edma->errirq) {
>  		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>  				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> @@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>  			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>  			return  ret;
>  		}
> +#endif
only one of them will be populated so if-else should work too

please get rid of these ifdef stuff and make it based on DT data based flags

-- 
~Vinod

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

* Re: [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
  2015-06-24 16:14       ` Vinod Koul
@ 2015-06-24 17:43         ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24 17:43 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan


Hi Vinod,

Tanks for your comments. Actually, fsl-lpuart driver is done the way you 
propose to rework this one. I'll consider this during my work on the 
second iteration.

On Wed, 24 Jun 2015, Vinod Koul wrote:

> On Tue, Jun 23, 2015 at 11:19:46PM +0200, Paul Osmialowski wrote:
>> Surprisingly small amount of work was required in order to extend already
>> existing eDMA driver with the support for Kinetis SoC architecture.
>>
>> Note that <mach/memory.h> is needed (which is denoted by
>> CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
>> operation of DMA allocation functions.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
>>  arch/arm/Kconfig                                   |  4 ++
>>  arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
>>  arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
>>  drivers/clk/clk-kinetis.c                          | 15 ++++
>>  drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
>>  include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
> having so many change into one patch is not a great idea, please breka them
> up. I am looking for single/multiple patches which only touch dmaengine
> files
>
>
>> +#ifdef CONFIG_ARCH_KINETIS
>> +static const char * const txirq_names[] = {
>> +	"edma-tx-0,16",
>> +	"edma-tx-1,17",
>> +	"edma-tx-2,18",
>> +	"edma-tx-3,19",
>> +	"edma-tx-4,20",
>> +	"edma-tx-5,21",
>> +	"edma-tx-6,22",
>> +	"edma-tx-7,23",
>> +	"edma-tx-8,24",
>> +	"edma-tx-9,25",
>> +	"edma-tx-10,26",
>> +	"edma-tx-11,27",
>> +	"edma-tx-12,28",
>> +	"edma-tx-13,29",
>> +	"edma-tx-14,30",
>> +	"edma-tx-15,31",
>> +};
> why do we need this array, these seem to come from DT, right?
>> +#endif
>> +
>>  struct fsl_edma_engine {
>>  	struct dma_device	dma_dev;
>>  	void __iomem		*membase;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	struct clk		*clk;
>> +#endif
>>  	void __iomem		*muxbase[DMAMUX_NR];
>>  	struct clk		*muxclk[DMAMUX_NR];
>>  	struct mutex		fsl_edma_mutex;
>>  	u32			n_chans;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	int			txirq[ARRAY_SIZE(txirq_names)];
>> +#else
>>  	int			txirq;
>> +#endif
>>  	int			errirq;
>>  	bool			big_endian;
>>  	struct fsl_edma_chan	chans[];
> we can define these bits and only be used on kinetis machines?
>
>> @@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
>>  	return IRQ_HANDLED;
>>  }
>>
>> +#ifndef CONFIG_ARCH_KINETIS
>>  static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>>  {
>>  	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
>> @@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>>
>>  	return fsl_edma_err_handler(irq, dev_id);
>>  }
>> +#endif
>>
>>  static void fsl_edma_issue_pending(struct dma_chan *chan)
>>  {
>> @@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
>>  }
>>
>>  static int
>> -fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
>> +fsl_edma_irq_init(struct platform_device *pdev,
>> +		  struct fsl_edma_engine *fsl_edma)
>>  {
>>  	int ret;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	int i;
>>
>> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
>> +		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
>> +					txirq_names[i]);
>> +		if (fsl_edma->txirq[i] < 0) {
>> +			dev_err(&pdev->dev, "Can't get %s irq.\n",
>> +						txirq_names[i]);
>> +			return fsl_edma->txirq[i];
>> +		}
>> +	}
>> +#else
>>  	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
>>  	if (fsl_edma->txirq < 0) {
>>  		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>>  		return fsl_edma->txirq;
>>  	}
>> +#endif
> can you have two routines and with one of them onvoked based on machine type
> which should be configured based on DT data rather
>
>>
>>  	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>>  	if (fsl_edma->errirq < 0) {
>> @@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>>  		return fsl_edma->errirq;
>>  	}
>>
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
>> +		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
>> +			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
>> +		if (ret) {
>> +			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>> +			return  ret;
>> +		}
>> +	}
>> +#else
>>  	if (fsl_edma->txirq == fsl_edma->errirq) {
>>  		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>>  				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> @@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>>  			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>>  			return  ret;
>>  		}
>> +#endif
> only one of them will be populated so if-else should work too
>
> please get rid of these ifdef stuff and make it based on DT data based flags
>
> -- 
> ~Vinod
>

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

* Re: [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support Kinetis SoC
@ 2015-06-24 17:43         ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24 17:43 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Stephen Boyd, Thomas Gleixner,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	Pawel Moll, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev


Hi Vinod,

Tanks for your comments. Actually, fsl-lpuart driver is done the way you 
propose to rework this one. I'll consider this during my work on the 
second iteration.

On Wed, 24 Jun 2015, Vinod Koul wrote:

> On Tue, Jun 23, 2015 at 11:19:46PM +0200, Paul Osmialowski wrote:
>> Surprisingly small amount of work was required in order to extend already
>> existing eDMA driver with the support for Kinetis SoC architecture.
>>
>> Note that <mach/memory.h> is needed (which is denoted by
>> CONFIG_NEED_MACH_MEMORY_H) as it provides macros required for proper
>> operation of DMA allocation functions.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  Documentation/devicetree/bindings/dma/fsl-edma.txt | 38 +++++++++-
>>  arch/arm/Kconfig                                   |  4 ++
>>  arch/arm/boot/dts/kinetis.dtsi                     | 34 +++++++++
>>  arch/arm/mach-kinetis/include/mach/memory.h        | 61 ++++++++++++++++
>>  drivers/clk/clk-kinetis.c                          | 15 ++++
>>  drivers/dma/fsl-edma.c                             | 81 +++++++++++++++++++++-
>>  include/dt-bindings/clock/kinetis-mcg.h            |  5 +-
> having so many change into one patch is not a great idea, please breka them
> up. I am looking for single/multiple patches which only touch dmaengine
> files
>
>
>> +#ifdef CONFIG_ARCH_KINETIS
>> +static const char * const txirq_names[] = {
>> +	"edma-tx-0,16",
>> +	"edma-tx-1,17",
>> +	"edma-tx-2,18",
>> +	"edma-tx-3,19",
>> +	"edma-tx-4,20",
>> +	"edma-tx-5,21",
>> +	"edma-tx-6,22",
>> +	"edma-tx-7,23",
>> +	"edma-tx-8,24",
>> +	"edma-tx-9,25",
>> +	"edma-tx-10,26",
>> +	"edma-tx-11,27",
>> +	"edma-tx-12,28",
>> +	"edma-tx-13,29",
>> +	"edma-tx-14,30",
>> +	"edma-tx-15,31",
>> +};
> why do we need this array, these seem to come from DT, right?
>> +#endif
>> +
>>  struct fsl_edma_engine {
>>  	struct dma_device	dma_dev;
>>  	void __iomem		*membase;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	struct clk		*clk;
>> +#endif
>>  	void __iomem		*muxbase[DMAMUX_NR];
>>  	struct clk		*muxclk[DMAMUX_NR];
>>  	struct mutex		fsl_edma_mutex;
>>  	u32			n_chans;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	int			txirq[ARRAY_SIZE(txirq_names)];
>> +#else
>>  	int			txirq;
>> +#endif
>>  	int			errirq;
>>  	bool			big_endian;
>>  	struct fsl_edma_chan	chans[];
> we can define these bits and only be used on kinetis machines?
>
>> @@ -709,6 +737,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
>>  	return IRQ_HANDLED;
>>  }
>>
>> +#ifndef CONFIG_ARCH_KINETIS
>>  static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>>  {
>>  	if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
>> @@ -716,6 +745,7 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
>>
>>  	return fsl_edma_err_handler(irq, dev_id);
>>  }
>> +#endif
>>
>>  static void fsl_edma_issue_pending(struct dma_chan *chan)
>>  {
>> @@ -788,15 +818,29 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
>>  }
>>
>>  static int
>> -fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
>> +fsl_edma_irq_init(struct platform_device *pdev,
>> +		  struct fsl_edma_engine *fsl_edma)
>>  {
>>  	int ret;
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	int i;
>>
>> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
>> +		fsl_edma->txirq[i] = platform_get_irq_byname(pdev,
>> +					txirq_names[i]);
>> +		if (fsl_edma->txirq[i] < 0) {
>> +			dev_err(&pdev->dev, "Can't get %s irq.\n",
>> +						txirq_names[i]);
>> +			return fsl_edma->txirq[i];
>> +		}
>> +	}
>> +#else
>>  	fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
>>  	if (fsl_edma->txirq < 0) {
>>  		dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>>  		return fsl_edma->txirq;
>>  	}
>> +#endif
> can you have two routines and with one of them onvoked based on machine type
> which should be configured based on DT data rather
>
>>
>>  	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>>  	if (fsl_edma->errirq < 0) {
>> @@ -804,6 +848,16 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>>  		return fsl_edma->errirq;
>>  	}
>>
>> +#ifdef CONFIG_ARCH_KINETIS
>> +	for (i = 0; i < ARRAY_SIZE(txirq_names); i++) {
>> +		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq[i],
>> +			fsl_edma_tx_handler, 0, txirq_names[i], fsl_edma);
>> +		if (ret) {
>> +			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>> +			return  ret;
>> +		}
>> +	}
>> +#else
>>  	if (fsl_edma->txirq == fsl_edma->errirq) {
>>  		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>>  				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> @@ -818,6 +872,7 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
>>  			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>>  			return  ret;
>>  		}
>> +#endif
> only one of them will be populated so if-else should work too
>
> please get rid of these ifdef stuff and make it based on DT data based flags
>
> -- 
> ~Vinod
>

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-24 10:21     ` Paul Bolle
@ 2015-06-24 17:44       ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24 17:44 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan

Hi Paul,

Thanks for your comments. I'll make it tristate.

On Wed, 24 Jun 2015, Paul Bolle wrote:

> On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
>> --- a/drivers/pinctrl/freescale/Kconfig
>> +++ b/drivers/pinctrl/freescale/Kconfig
>
>> +config PINCTRL_KINETIS
>> +	bool "Kinetis pinctrl driver"
>> +	depends on OF
>> +	depends on SOC_K70
>> +	select PINMUX
>> +	help
>> +	  Say Y here to enable the Kinetis pinctrl driver
>
>> --- a/drivers/pinctrl/freescale/Makefile
>> +++ b/drivers/pinctrl/freescale/Makefile
>
>> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o
>
>> --- /dev/null
>> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
>
>> +#include <linux/module.h>
>
>> +static struct pinctrl_desc kinetis_pinctrl_desc = {
>> +	[...]
>> +	.owner = THIS_MODULE,
>> +};
>
>> +static void __exit kinetis_pinctrl_exit(void)
>> +{
>> +	platform_driver_unregister(&kinetis_pinctrl_driver);
>> +}
>> +module_exit(kinetis_pinctrl_exit);
>> +
>> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
>> +MODULE_LICENSE("GPL v2");
>
> pinctrl-kinetis.o can only be built-in, right? But the code uses a few
> module specific constructs. Did you mean to make PINCTRL_KINETIS
> tristate instead?
>
> Thanks,
>
>
> Paul Bolle
>

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-06-24 17:44       ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-24 17:44 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Arnd Bergmann, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Rob Herring, Rob Herring,
	Russell King, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

Hi Paul,

Thanks for your comments. I'll make it tristate.

On Wed, 24 Jun 2015, Paul Bolle wrote:

> On Tue, 2015-06-23 at 23:19 +0200, Paul Osmialowski wrote:
>> --- a/drivers/pinctrl/freescale/Kconfig
>> +++ b/drivers/pinctrl/freescale/Kconfig
>
>> +config PINCTRL_KINETIS
>> +	bool "Kinetis pinctrl driver"
>> +	depends on OF
>> +	depends on SOC_K70
>> +	select PINMUX
>> +	help
>> +	  Say Y here to enable the Kinetis pinctrl driver
>
>> --- a/drivers/pinctrl/freescale/Makefile
>> +++ b/drivers/pinctrl/freescale/Makefile
>
>> +obj-$(CONFIG_PINCTRL_KINETIS)	+= pinctrl-kinetis.o
>
>> --- /dev/null
>> +++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
>
>> +#include <linux/module.h>
>
>> +static struct pinctrl_desc kinetis_pinctrl_desc = {
>> +	[...]
>> +	.owner = THIS_MODULE,
>> +};
>
>> +static void __exit kinetis_pinctrl_exit(void)
>> +{
>> +	platform_driver_unregister(&kinetis_pinctrl_driver);
>> +}
>> +module_exit(kinetis_pinctrl_exit);
>> +
>> +MODULE_DESCRIPTION("Freescale Kinetis pinctrl driver");
>> +MODULE_LICENSE("GPL v2");
>
> pinctrl-kinetis.o can only be built-in, right? But the code uses a few
> module specific constructs. Did you mean to make PINCTRL_KINETIS
> tristate instead?
>
> Thanks,
>
>
> Paul Bolle
>

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-23 21:59     ` Arnd Bergmann
@ 2015-06-25 16:42       ` Nicolas Pitre
  -1 siblings, 0 replies; 86+ messages in thread
From: Nicolas Pitre @ 2015-06-25 16:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Max

On Tue, 23 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> > Some SoCs need additional actions to be performed after arch idle,
> > e.g. Kinetis requires invalidation of the I/D bus cache.
> > 
> > Such handler could be held in provided <mach/idle.h> header file.
> > 
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > ---
> >  arch/arm/Kconfig          | 7 +++++++
> >  arch/arm/kernel/process.c | 7 +++++++
> >  2 files changed, 14 insertions(+)
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 8e3a833..8ef8f8f 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
> >  config NEED_SG_DMA_LENGTH
> >  	bool
> >  
> > +config NEED_MACH_IDLE_H
> > +	bool
> > +
> > +config ARM_CPU_IDLE_QUIRKS
> > +	bool
> > +	select NEED_MACH_IDLE_H
> > +
> 
> We're not adding header files like this, please come up
> with another solution. How about a cpuidle driver, or
> possibly just overriding arm_pm_idle()?

If the WFI instruction always requires I and D flushing, then it might 
be a better idea to provide a replacement for the corresponding 
cpu_*_do_idle function.  Plenty of examples exist for other cpu_* 
functions.


Nicolas

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-25 16:42       ` Nicolas Pitre
  0 siblings, 0 replies; 86+ messages in thread
From: Nicolas Pitre @ 2015-06-25 16:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Rob Herring, Russell King, Sergey Senozhatsky,
	Shawn Guo, Simon Horman, Stefan Agner, Stephen Boyd,
	Thomas Gleixner, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, Pawel Moll, linux-kernel, linux-arm-kernel,
	linux-clk, linux-gpio, linux-serial, devicetree, dmaengine,
	Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov,
	Alexander Potashev

On Tue, 23 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
> > Some SoCs need additional actions to be performed after arch idle,
> > e.g. Kinetis requires invalidation of the I/D bus cache.
> > 
> > Such handler could be held in provided <mach/idle.h> header file.
> > 
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > ---
> >  arch/arm/Kconfig          | 7 +++++++
> >  arch/arm/kernel/process.c | 7 +++++++
> >  2 files changed, 14 insertions(+)
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 8e3a833..8ef8f8f 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
> >  config NEED_SG_DMA_LENGTH
> >  	bool
> >  
> > +config NEED_MACH_IDLE_H
> > +	bool
> > +
> > +config ARM_CPU_IDLE_QUIRKS
> > +	bool
> > +	select NEED_MACH_IDLE_H
> > +
> 
> We're not adding header files like this, please come up
> with another solution. How about a cpuidle driver, or
> possibly just overriding arm_pm_idle()?

If the WFI instruction always requires I and D flushing, then it might 
be a better idea to provide a replacement for the corresponding 
cpu_*_do_idle function.  Plenty of examples exist for other cpu_* 
functions.


Nicolas

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-25 16:42       ` Nicolas Pitre
@ 2015-06-26  5:30           ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-26  5:30 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Arnd Bergmann, Paul Osmialowski, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan

Hi Nicolas,

Thanks for your proposal, however, I have some trouble with it.

That would look lovely:

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
  *      cpu_kinetis_do_idle()
  *
  *      Idle the processor (wait for interrupt).
  *
  *      IRQs are already disabled.
  */
ENTRY(cpu_kinetis_do_idle)
         wfi
         movw    r3, #:lower16:0xe0082000
         movt    r3, #:upper16:0xe0082000
         ldr     r0, [r3, #0]
         orr     r2, r0, #0x85000000
         str     r2, [r3, #0]
         ret     lr
ENDPROC(cpu_kinetis_do_idle)

But... what about the rest of this hypothetical proc_kinetis.S file?

It would be a lot of code duplication with proc-v7m.S I think.

I could define CPU_KINETIS as such:

config CPU_KINETIS
 	bool
 	select CPU_V7M

But there's no such thing like customize_processor_functions that would be 
called after proc-v7m.S define_processor_functions specified things like 
idle routine.

Finally, while I was searching for suitable arm_pm_idle-based solution, I 
found idle.c in mach-gemini that encouraged me to write my own idle.c for 
Kinetis:

/*
  * arch/arm/mach-kinetis/idle.c
  */

#include <linux/init.h>
#include <linux/io.h>
#include <asm/system_misc.h>
#include <asm/proc-fns.h>

static void kinetis_idle(void)
{
         asm volatile ("wfi");

         /*
          * This is a dirty hack that invalidates the I/D bus cache
          * on Kinetis K70. This must be done after idle.
          */
         writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
}

static int __init kinetis_idle_init(void)
{
         arm_pm_idle = kinetis_idle;
         return 0;
}

arch_initcall(kinetis_idle_init);

Et voila:

(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
18		writel(readl(IOMEM(0xe0082000)) | 0x85000000, 
IOMEM(0xe0082000));
(gdb) bt
#0  kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
#1  0x0800a91e in arch_cpu_idle () at ../arch/arm/kernel/process.c:70
#2  0x08025402 in cpuidle_idle_call (state=<value optimized out>)
     at ../kernel/sched/idle.c:157
#3  cpu_idle_loop (state=<value optimized out>) at 
../kernel/sched/idle.c:253
#4  cpu_startup_entry (state=<value optimized out>) at 
../kernel/sched/idle.c:301
#5  0x081bf816 in start_kernel () at ../init/main.c:683
#6  0x08008024 in stext () at ../arch/arm/kernel/head-nommu.S:85
(gdb)

On Thu, 25 Jun 2015, Nicolas Pitre wrote:

> On Tue, 23 Jun 2015, Arnd Bergmann wrote:
>
>> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
>>> Some SoCs need additional actions to be performed after arch idle,
>>> e.g. Kinetis requires invalidation of the I/D bus cache.
>>>
>>> Such handler could be held in provided <mach/idle.h> header file.
>>>
>>> Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
>>> ---
>>>  arch/arm/Kconfig          | 7 +++++++
>>>  arch/arm/kernel/process.c | 7 +++++++
>>>  2 files changed, 14 insertions(+)
>>>
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index 8e3a833..8ef8f8f 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>>>  config NEED_SG_DMA_LENGTH
>>>  	bool
>>>
>>> +config NEED_MACH_IDLE_H
>>> +	bool
>>> +
>>> +config ARM_CPU_IDLE_QUIRKS
>>> +	bool
>>> +	select NEED_MACH_IDLE_H
>>> +
>>
>> We're not adding header files like this, please come up
>> with another solution. How about a cpuidle driver, or
>> possibly just overriding arm_pm_idle()?
>
> If the WFI instruction always requires I and D flushing, then it might
> be a better idea to provide a replacement for the corresponding
> cpu_*_do_idle function.  Plenty of examples exist for other cpu_*
> functions.
>
>
> Nicolas
>
--
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] 86+ messages in thread

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-26  5:30           ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-26  5:30 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Arnd Bergmann, Paul Osmialowski, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Stephen Boyd, Thomas Gleixner,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	Pawel Moll, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

Hi Nicolas,

Thanks for your proposal, however, I have some trouble with it.

That would look lovely:

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
  *      cpu_kinetis_do_idle()
  *
  *      Idle the processor (wait for interrupt).
  *
  *      IRQs are already disabled.
  */
ENTRY(cpu_kinetis_do_idle)
         wfi
         movw    r3, #:lower16:0xe0082000
         movt    r3, #:upper16:0xe0082000
         ldr     r0, [r3, #0]
         orr     r2, r0, #0x85000000
         str     r2, [r3, #0]
         ret     lr
ENDPROC(cpu_kinetis_do_idle)

But... what about the rest of this hypothetical proc_kinetis.S file?

It would be a lot of code duplication with proc-v7m.S I think.

I could define CPU_KINETIS as such:

config CPU_KINETIS
 	bool
 	select CPU_V7M

But there's no such thing like customize_processor_functions that would be 
called after proc-v7m.S define_processor_functions specified things like 
idle routine.

Finally, while I was searching for suitable arm_pm_idle-based solution, I 
found idle.c in mach-gemini that encouraged me to write my own idle.c for 
Kinetis:

/*
  * arch/arm/mach-kinetis/idle.c
  */

#include <linux/init.h>
#include <linux/io.h>
#include <asm/system_misc.h>
#include <asm/proc-fns.h>

static void kinetis_idle(void)
{
         asm volatile ("wfi");

         /*
          * This is a dirty hack that invalidates the I/D bus cache
          * on Kinetis K70. This must be done after idle.
          */
         writel(readl(IOMEM(0xe0082000)) | 0x85000000, IOMEM(0xe0082000));
}

static int __init kinetis_idle_init(void)
{
         arm_pm_idle = kinetis_idle;
         return 0;
}

arch_initcall(kinetis_idle_init);

Et voila:

(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
18		writel(readl(IOMEM(0xe0082000)) | 0x85000000, 
IOMEM(0xe0082000));
(gdb) bt
#0  kinetis_idle () at ../arch/arm/mach-kinetis/idle.c:18
#1  0x0800a91e in arch_cpu_idle () at ../arch/arm/kernel/process.c:70
#2  0x08025402 in cpuidle_idle_call (state=<value optimized out>)
     at ../kernel/sched/idle.c:157
#3  cpu_idle_loop (state=<value optimized out>) at 
../kernel/sched/idle.c:253
#4  cpu_startup_entry (state=<value optimized out>) at 
../kernel/sched/idle.c:301
#5  0x081bf816 in start_kernel () at ../init/main.c:683
#6  0x08008024 in stext () at ../arch/arm/kernel/head-nommu.S:85
(gdb)

On Thu, 25 Jun 2015, Nicolas Pitre wrote:

> On Tue, 23 Jun 2015, Arnd Bergmann wrote:
>
>> On Tuesday 23 June 2015 23:19:41 Paul Osmialowski wrote:
>>> Some SoCs need additional actions to be performed after arch idle,
>>> e.g. Kinetis requires invalidation of the I/D bus cache.
>>>
>>> Such handler could be held in provided <mach/idle.h> header file.
>>>
>>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>>> ---
>>>  arch/arm/Kconfig          | 7 +++++++
>>>  arch/arm/kernel/process.c | 7 +++++++
>>>  2 files changed, 14 insertions(+)
>>>
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index 8e3a833..8ef8f8f 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -98,6 +98,13 @@ config ARM_HAS_SG_CHAIN
>>>  config NEED_SG_DMA_LENGTH
>>>  	bool
>>>
>>> +config NEED_MACH_IDLE_H
>>> +	bool
>>> +
>>> +config ARM_CPU_IDLE_QUIRKS
>>> +	bool
>>> +	select NEED_MACH_IDLE_H
>>> +
>>
>> We're not adding header files like this, please come up
>> with another solution. How about a cpuidle driver, or
>> possibly just overriding arm_pm_idle()?
>
> If the WFI instruction always requires I and D flushing, then it might
> be a better idea to provide a replacement for the corresponding
> cpu_*_do_idle function.  Plenty of examples exist for other cpu_*
> functions.
>
>
> Nicolas
>

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-26  5:30           ` Paul Osmialowski
@ 2015-06-26  7:40             ` Arnd Bergmann
  -1 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-26  7:40 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Nicolas Pitre, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch

On Friday 26 June 2015 07:30:49 Paul Osmialowski wrote:
> ENDPROC(cpu_kinetis_do_idle)
> 
> But... what about the rest of this hypothetical proc_kinetis.S file?
> 
> It would be a lot of code duplication with proc-v7m.S I think.
> 

I doubt that the Kinetis has a custom version of the CPU core. Are you
sure that not all Cortex-M4 need this?

As long as the idle implementation depends only on the CPU core type,
it's easy to just define multiple .proc.info.init entries in the
same file, like we do in proc-v7.S.

	Arnd

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-26  7:40             ` Arnd Bergmann
  0 siblings, 0 replies; 86+ messages in thread
From: Arnd Bergmann @ 2015-06-26  7:40 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Nicolas Pitre, Andrew Morton, Anson Huang, Ard Biesheuvel,
	Bhupesh Sharma, Daniel Lezcano, Frank Li, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Linus Walleij, Magnus Damm, Michael Turquette,
	Nathan Lynch, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Rob Herring, Russell King, Sergey Senozhatsky,
	Shawn Guo, Simon Horman, Stefan Agner, Stephen Boyd,
	Thomas Gleixner, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, Pawel Moll, linux-kernel, linux-arm-kernel,
	linux-clk, linux-gpio, linux-serial, devicetree, dmaengine,
	Yuri Tikhonov, Sergei Poselenov, Dmitry Cherkassov,
	Alexander Potashev

On Friday 26 June 2015 07:30:49 Paul Osmialowski wrote:
> ENDPROC(cpu_kinetis_do_idle)
> 
> But... what about the rest of this hypothetical proc_kinetis.S file?
> 
> It would be a lot of code duplication with proc-v7m.S I think.
> 

I doubt that the Kinetis has a custom version of the CPU core. Are you
sure that not all Cortex-M4 need this?

As long as the idle implementation depends only on the CPU core type,
it's easy to just define multiple .proc.info.init entries in the
same file, like we do in proc-v7.S.

	Arnd

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-26  7:40             ` Arnd Bergmann
@ 2015-06-26 21:52               ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-26 21:52 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Nicolas Pitre, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette



On Fri, 26 Jun 2015, Arnd Bergmann wrote:

> I doubt that the Kinetis has a custom version of the CPU core. Are you
> sure that not all Cortex-M4 need this?

I'm not sure and I don't have any other Cortex-M SoC to verify that...
Without this hack, I'm experiencing following exception:

init started: BusyBox v1.17.0 (2015-03-27 08:16:34 CET)
~ # [    1.910000]
[    1.910000] Unhandled exception: IPSR = 00000006 LR = fffffff1
[    1.910000] CPU: 0 PID: 0 Comm: swapper Not tainted 
4.1.0-next-20150623-00007-gf22ea1d-dirty #1
[    1.910000] Hardware name: Freescale Kinetis
[    1.910000] task: 082666f8 ti: 08264000 task.ti: 08264000
[    1.910000] PC is at arch_cpu_idle+0x14/0x1c
[    1.910000] LR is at arch_cpu_idle+0x13/0x1c
[    1.910000] pc : [<0800a928>]    lr : [<0800a927>]    psr: 6100000b
[    1.910000] sp : 08265f98  ip : 08264020  fp : 00000001
[    1.910000] r10: 0827433d  r9 : 00000000  r8 : 08266070
[    1.910000] r7 : 08272a88  r6 : 08266068  r5 : 00000000  r4 : 08266068
[    1.910000] r3 : 00000000  r2 : 08265fa0  r1 : 08264020  r0 : 08264000
[    1.910000] xPSR: 6100000b
[    1.910000] CPU: 0 PID: 0 Comm: swapper Not tainted 
4.1.0-next-20150623-00007-gf22ea1d-dirty #1
[    1.910000] Hardware name: Freescale Kinetis
[    1.910000] [<0800c5cd>] (unwind_backtrace) from [<0800b8b3>] 
(show_stack+0xb/0xc)
[    1.910000] [<0800b8b3>] (show_stack) from [<0800bd8b>] 
(__invalid_entry+0x4b/0x4c)
[    1.910000] [<0800bd8b>] (__invalid_entry) from [<ffffffff>] 
(0xffffffff)

Funny, it does not occur when JTAG is connected.

>
> As long as the idle implementation depends only on the CPU core type,
> it's easy to just define multiple .proc.info.init entries in the
> same file, like we do in proc-v7.S.
>

I tried it and it works. This approach does not cause code duplication, 
but (comparing to arm_pm_idle-based approach) its long. Would something 
like this be accepted ever?

Note that contrary to proc-v7, there's no __v7m_proc macro, I had to 
define it in order to avoid another code duplication:

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8ccffee..da35b0b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -967,6 +967,7 @@ config ARCH_EFM32
  config ARCH_KINETIS
  	bool "Freescale Kinetis MCU"
  	depends on ARM_SINGLE_ARMV7M
+	select CPU_KINETIS
  	select ARMV7M_SYSTICK
  	select CLKSRC_KINETIS
  	select PINCTRL
diff --git a/arch/arm/include/asm/cputype.h 
b/arch/arm/include/asm/cputype.h
index 85e374f..79792e9 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -234,6 +234,12 @@ static inline int cpu_is_xsc3(void)
  #define	cpu_is_xscale()	1
  #endif

+#if !defined(CONFIG_CPU_KINETIS)
+#define	cpu_is_kinetis()	0
+#else
+#define	cpu_is_kinetis()	1
+#endif
+
  /*
   * Marvell's PJ4 and PJ4B cores are based on V7 version,
   * but require a specical sequence for enabling coprocessors.
diff --git a/arch/arm/include/asm/glue-proc.h 
b/arch/arm/include/asm/glue-proc.h
index 74be7c2..08583bb 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -230,6 +230,15 @@
  # endif
  #endif

+#ifdef CONFIG_CPU_KINETIS
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_kinetis
+# endif
+#endif
+
  #ifdef CONFIG_CPU_PJ4B
  # ifdef CPU_NAME
  #  undef  MULTI_CPU
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 121b580..ef59407 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -356,6 +356,11 @@ config CPU_PJ4B
  	bool
  	select CPU_V7

+# Freescale Kinetis
+config CPU_KINETIS
+	bool
+	select CPU_V7M
+
  # ARMv6
  config CPU_V6
  	bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || 
ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || 
MACH_REALVIEW_PBX)
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index ded9504..671374f 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -73,6 +73,30 @@ ENTRY(cpu_v7m_do_resume)
  ENDPROC(cpu_v7m_do_resume)
  #endif

+#ifdef CONFIG_CPU_KINETIS
+	globl_equ	cpu_kinetis_switch_mm,	cpu_v7m_switch_mm
+	globl_equ	cpu_kinetis_proc_init,	cpu_v7m_proc_init
+	globl_equ	cpu_kinetis_proc_fin, 	cpu_v7m_proc_fin
+	globl_equ	cpu_kinetis_reset,	cpu_v7m_reset
+ENTRY(cpu_kinetis_do_idle)
+	dsb
+	wfi
+	movw	r3, #:lower16:0xe0082000
+	movt	r3, #:upper16:0xe0082000
+	ldr	r0, [r3, #0]
+	orr	r2, r0, #0x85000000
+	str	r2, [r3, #0]
+	ret	lr
+ENDPROC(cpu_kinetis_do_idle)
+	globl_equ	cpu_kinetis_dcache_clean_area, 
cpu_v7m_dcache_clean_area
+#ifdef CONFIG_ARM_CPU_SUSPEND
+	globl_equ	cpu_kinetis_do_suspend,	cpu_v7m_do_suspend
+	globl_equ	cpu_kinedis_do_resume,	cpu_v7m_do_resume
+#endif
+.globl	cpu_kinetis_suspend_size
+.equ	cpu_kinetis_suspend_size, cpu_v7m_suspend_size
+#endif
+
  	.section ".text.init", #alloc, #execinstr

  /*
@@ -140,6 +164,9 @@ __v7m_setup_stack:
  __v7m_setup_stack_top:

  	define_processor_functions v7m, dabort=nommu_early_abort, 
pabort=legacy_pabort, nommu=1
+#ifdef CONFIG_CPU_KINETIS
+	define_processor_functions kinetis, dabort=nommu_early_abort, 
pabort=legacy_pabort, nommu=1
+#endif

  	.section ".rodata"
  	string cpu_arch_name, "armv7m"
@@ -148,23 +175,35 @@ __v7m_setup_stack_top:

  	.section ".proc.info.init", #alloc

-	/*
-	 * Match any ARMv7-M processor core.
-	 */
-	.type	__v7m_proc_info, #object
-__v7m_proc_info:
-	.long	0x000f0000		@ Required ID value
-	.long	0x000f0000		@ Mask for ID
+.macro __v7m_proc name, initfunc, proc_fns = v7m_processor_functions
  	.long   0			@ 
proc_info_list.__cpu_mm_mmu_flags
  	.long   0			@ 
proc_info_list.__cpu_io_mmu_flags
-	initfn	__v7m_setup, __v7m_proc_info	@ 
proc_info_list.__cpu_flush
+	initfn	\initfunc, \name	@ proc_info_list.__cpu_flush
  	.long	cpu_arch_name
  	.long	cpu_elf_name
  	.long	HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT
  	.long	cpu_v7m_name
-	.long	v7m_processor_functions	@ proc_info_list.proc
+	.long	\proc_fns		@ proc_info_list.proc
  	.long	0			@ proc_info_list.tlb
  	.long	0			@ proc_info_list.user
  	.long	nop_cache_fns		@ proc_info_list.cache
-	.size	__v7m_proc_info, . - __v7m_proc_info
+.endm
+
+#ifdef CONFIG_CPU_KINETIS
+	.type   __v7m_kinetis_proc_info, #object
+__v7m_kinetis_proc_info:
+	.long	0x410fc240
+	.long	0xff0ffff0
+	__v7m_proc __v7m_kinetis_proc_info, __v7m_setup, proc_fns = 
kinetis_processor_functions
+	.size	__v7m_kinetis_proc_info, . - __v7m_kinetis_proc_info
+#endif

+	/*
+	 * Match any ARMv7-M processor core.
+	 */
+	.type	__v7m_proc_info, #object
+__v7m_proc_info:
+	.long	0x000f0000		@ Required ID value
+	.long	0x000f0000		@ Mask for ID
+	__v7m_proc __v7m_proc_info, __v7m_setup
+	.size	__v7m_proc_info, . - __v7m_proc_info


Works with and without JTAG connected.

(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
cpu_kinetis_do_idle () at ../arch/arm/mm/proc-v7m.S:84
84		movw	r3, #:lower16:0xe0082000
(gdb) bt
#0  cpu_kinetis_do_idle () at ../arch/arm/mm/proc-v7m.S:84
#1  0x0800a4b0 in arch_cpu_idle () at ../arch/arm/kernel/process.c:72
#2  0x0802542a in cpuidle_idle_call (state=<value optimized out>)
     at ../kernel/sched/idle.c:157
#3  cpu_idle_loop (state=<value optimized out>) at 
../kernel/sched/idle.c:253
#4  cpu_startup_entry (state=<value optimized out>) at 
../kernel/sched/idle.c:301
#5  0x081bf816 in start_kernel () at ../init/main.c:683
#6  0x08008024 in stext () at ../arch/arm/kernel/head-nommu.S:85
(gdb)

Note dsb before wfi - I'm experiencing another (different) exception 
without it.
--
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] 86+ messages in thread

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-26 21:52               ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-06-26 21:52 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, Nicolas Pitre, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Russell King, Sergey Senozhatsky, Shawn Guo,
	Simon Horman, Stefan Agner, Stephen Boyd, Thomas Gleixner,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	Pawel Moll, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev



On Fri, 26 Jun 2015, Arnd Bergmann wrote:

> I doubt that the Kinetis has a custom version of the CPU core. Are you
> sure that not all Cortex-M4 need this?

I'm not sure and I don't have any other Cortex-M SoC to verify that...
Without this hack, I'm experiencing following exception:

init started: BusyBox v1.17.0 (2015-03-27 08:16:34 CET)
~ # [    1.910000]
[    1.910000] Unhandled exception: IPSR = 00000006 LR = fffffff1
[    1.910000] CPU: 0 PID: 0 Comm: swapper Not tainted 
4.1.0-next-20150623-00007-gf22ea1d-dirty #1
[    1.910000] Hardware name: Freescale Kinetis
[    1.910000] task: 082666f8 ti: 08264000 task.ti: 08264000
[    1.910000] PC is at arch_cpu_idle+0x14/0x1c
[    1.910000] LR is at arch_cpu_idle+0x13/0x1c
[    1.910000] pc : [<0800a928>]    lr : [<0800a927>]    psr: 6100000b
[    1.910000] sp : 08265f98  ip : 08264020  fp : 00000001
[    1.910000] r10: 0827433d  r9 : 00000000  r8 : 08266070
[    1.910000] r7 : 08272a88  r6 : 08266068  r5 : 00000000  r4 : 08266068
[    1.910000] r3 : 00000000  r2 : 08265fa0  r1 : 08264020  r0 : 08264000
[    1.910000] xPSR: 6100000b
[    1.910000] CPU: 0 PID: 0 Comm: swapper Not tainted 
4.1.0-next-20150623-00007-gf22ea1d-dirty #1
[    1.910000] Hardware name: Freescale Kinetis
[    1.910000] [<0800c5cd>] (unwind_backtrace) from [<0800b8b3>] 
(show_stack+0xb/0xc)
[    1.910000] [<0800b8b3>] (show_stack) from [<0800bd8b>] 
(__invalid_entry+0x4b/0x4c)
[    1.910000] [<0800bd8b>] (__invalid_entry) from [<ffffffff>] 
(0xffffffff)

Funny, it does not occur when JTAG is connected.

>
> As long as the idle implementation depends only on the CPU core type,
> it's easy to just define multiple .proc.info.init entries in the
> same file, like we do in proc-v7.S.
>

I tried it and it works. This approach does not cause code duplication, 
but (comparing to arm_pm_idle-based approach) its long. Would something 
like this be accepted ever?

Note that contrary to proc-v7, there's no __v7m_proc macro, I had to 
define it in order to avoid another code duplication:

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8ccffee..da35b0b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -967,6 +967,7 @@ config ARCH_EFM32
  config ARCH_KINETIS
  	bool "Freescale Kinetis MCU"
  	depends on ARM_SINGLE_ARMV7M
+	select CPU_KINETIS
  	select ARMV7M_SYSTICK
  	select CLKSRC_KINETIS
  	select PINCTRL
diff --git a/arch/arm/include/asm/cputype.h 
b/arch/arm/include/asm/cputype.h
index 85e374f..79792e9 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -234,6 +234,12 @@ static inline int cpu_is_xsc3(void)
  #define	cpu_is_xscale()	1
  #endif

+#if !defined(CONFIG_CPU_KINETIS)
+#define	cpu_is_kinetis()	0
+#else
+#define	cpu_is_kinetis()	1
+#endif
+
  /*
   * Marvell's PJ4 and PJ4B cores are based on V7 version,
   * but require a specical sequence for enabling coprocessors.
diff --git a/arch/arm/include/asm/glue-proc.h 
b/arch/arm/include/asm/glue-proc.h
index 74be7c2..08583bb 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -230,6 +230,15 @@
  # endif
  #endif

+#ifdef CONFIG_CPU_KINETIS
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_kinetis
+# endif
+#endif
+
  #ifdef CONFIG_CPU_PJ4B
  # ifdef CPU_NAME
  #  undef  MULTI_CPU
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 121b580..ef59407 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -356,6 +356,11 @@ config CPU_PJ4B
  	bool
  	select CPU_V7

+# Freescale Kinetis
+config CPU_KINETIS
+	bool
+	select CPU_V7M
+
  # ARMv6
  config CPU_V6
  	bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || 
ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || 
MACH_REALVIEW_PBX)
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index ded9504..671374f 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -73,6 +73,30 @@ ENTRY(cpu_v7m_do_resume)
  ENDPROC(cpu_v7m_do_resume)
  #endif

+#ifdef CONFIG_CPU_KINETIS
+	globl_equ	cpu_kinetis_switch_mm,	cpu_v7m_switch_mm
+	globl_equ	cpu_kinetis_proc_init,	cpu_v7m_proc_init
+	globl_equ	cpu_kinetis_proc_fin, 	cpu_v7m_proc_fin
+	globl_equ	cpu_kinetis_reset,	cpu_v7m_reset
+ENTRY(cpu_kinetis_do_idle)
+	dsb
+	wfi
+	movw	r3, #:lower16:0xe0082000
+	movt	r3, #:upper16:0xe0082000
+	ldr	r0, [r3, #0]
+	orr	r2, r0, #0x85000000
+	str	r2, [r3, #0]
+	ret	lr
+ENDPROC(cpu_kinetis_do_idle)
+	globl_equ	cpu_kinetis_dcache_clean_area, 
cpu_v7m_dcache_clean_area
+#ifdef CONFIG_ARM_CPU_SUSPEND
+	globl_equ	cpu_kinetis_do_suspend,	cpu_v7m_do_suspend
+	globl_equ	cpu_kinedis_do_resume,	cpu_v7m_do_resume
+#endif
+.globl	cpu_kinetis_suspend_size
+.equ	cpu_kinetis_suspend_size, cpu_v7m_suspend_size
+#endif
+
  	.section ".text.init", #alloc, #execinstr

  /*
@@ -140,6 +164,9 @@ __v7m_setup_stack:
  __v7m_setup_stack_top:

  	define_processor_functions v7m, dabort=nommu_early_abort, 
pabort=legacy_pabort, nommu=1
+#ifdef CONFIG_CPU_KINETIS
+	define_processor_functions kinetis, dabort=nommu_early_abort, 
pabort=legacy_pabort, nommu=1
+#endif

  	.section ".rodata"
  	string cpu_arch_name, "armv7m"
@@ -148,23 +175,35 @@ __v7m_setup_stack_top:

  	.section ".proc.info.init", #alloc

-	/*
-	 * Match any ARMv7-M processor core.
-	 */
-	.type	__v7m_proc_info, #object
-__v7m_proc_info:
-	.long	0x000f0000		@ Required ID value
-	.long	0x000f0000		@ Mask for ID
+.macro __v7m_proc name, initfunc, proc_fns = v7m_processor_functions
  	.long   0			@ 
proc_info_list.__cpu_mm_mmu_flags
  	.long   0			@ 
proc_info_list.__cpu_io_mmu_flags
-	initfn	__v7m_setup, __v7m_proc_info	@ 
proc_info_list.__cpu_flush
+	initfn	\initfunc, \name	@ proc_info_list.__cpu_flush
  	.long	cpu_arch_name
  	.long	cpu_elf_name
  	.long	HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT
  	.long	cpu_v7m_name
-	.long	v7m_processor_functions	@ proc_info_list.proc
+	.long	\proc_fns		@ proc_info_list.proc
  	.long	0			@ proc_info_list.tlb
  	.long	0			@ proc_info_list.user
  	.long	nop_cache_fns		@ proc_info_list.cache
-	.size	__v7m_proc_info, . - __v7m_proc_info
+.endm
+
+#ifdef CONFIG_CPU_KINETIS
+	.type   __v7m_kinetis_proc_info, #object
+__v7m_kinetis_proc_info:
+	.long	0x410fc240
+	.long	0xff0ffff0
+	__v7m_proc __v7m_kinetis_proc_info, __v7m_setup, proc_fns = 
kinetis_processor_functions
+	.size	__v7m_kinetis_proc_info, . - __v7m_kinetis_proc_info
+#endif

+	/*
+	 * Match any ARMv7-M processor core.
+	 */
+	.type	__v7m_proc_info, #object
+__v7m_proc_info:
+	.long	0x000f0000		@ Required ID value
+	.long	0x000f0000		@ Mask for ID
+	__v7m_proc __v7m_proc_info, __v7m_setup
+	.size	__v7m_proc_info, . - __v7m_proc_info


Works with and without JTAG connected.

(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
cpu_kinetis_do_idle () at ../arch/arm/mm/proc-v7m.S:84
84		movw	r3, #:lower16:0xe0082000
(gdb) bt
#0  cpu_kinetis_do_idle () at ../arch/arm/mm/proc-v7m.S:84
#1  0x0800a4b0 in arch_cpu_idle () at ../arch/arm/kernel/process.c:72
#2  0x0802542a in cpuidle_idle_call (state=<value optimized out>)
     at ../kernel/sched/idle.c:157
#3  cpu_idle_loop (state=<value optimized out>) at 
../kernel/sched/idle.c:253
#4  cpu_startup_entry (state=<value optimized out>) at 
../kernel/sched/idle.c:301
#5  0x081bf816 in start_kernel () at ../init/main.c:683
#6  0x08008024 in stext () at ../arch/arm/kernel/head-nommu.S:85
(gdb)

Note dsb before wfi - I'm experiencing another (different) exception 
without it.

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

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
  2015-06-26 21:52               ` Paul Osmialowski
@ 2015-06-26 22:27                   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-26 22:27 UTC (permalink / raw)
  To: Paul Osmialowski, Uwe Kleine-König
  Cc: Arnd Bergmann, Nicolas Pitre, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan

On Fri, Jun 26, 2015 at 11:52:23PM +0200, Paul Osmialowski wrote:
> I tried it and it works. This approach does not cause code duplication, but
> (comparing to arm_pm_idle-based approach) its long. Would something like
> this be accepted ever?
> 
> Note that contrary to proc-v7, there's no __v7m_proc macro, I had to define
> it in order to avoid another code duplication:

And I don't like it - until we have word from Uwe, I'd like to keep this
simple and restricted just to the affected SoC.  Until we have it proven
that this is a generic problem, we shouldn't go treating it as such.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
--
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] 86+ messages in thread

* Re: [PATCH 3/9] arm: add call to CPU idle quirks handler
@ 2015-06-26 22:27                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2015-06-26 22:27 UTC (permalink / raw)
  To: Paul Osmialowski, Uwe Kleine-König
  Cc: Arnd Bergmann, Nicolas Pitre, Andrew Morton, Anson Huang,
	Ard Biesheuvel, Bhupesh Sharma, Daniel Lezcano, Frank Li,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Linus Walleij,
	Magnus Damm, Michael Turquette, Nathan Lynch,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Rob Herring, Sergey Senozhatsky, Shawn Guo, Simon Horman,
	Stefan Agner, Stephen Boyd, Thomas Gleixner, Uwe Kleine-Koenig,
	Catalin Marinas, Dave Martin, Mark Rutland, Pawel Moll,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Yuri Tikhonov,
	Sergei Poselenov, Dmitry Cherkassov, Alexander Potashev

On Fri, Jun 26, 2015 at 11:52:23PM +0200, Paul Osmialowski wrote:
> I tried it and it works. This approach does not cause code duplication, but
> (comparing to arm_pm_idle-based approach) its long. Would something like
> this be accepted ever?
> 
> Note that contrary to proc-v7, there's no __v7m_proc macro, I had to define
> it in order to avoid another code duplication:

And I don't like it - until we have word from Uwe, I'd like to keep this
simple and restricted just to the affected SoC.  Until we have it proven
that this is a generic problem, we shouldn't go treating it as such.

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

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-23 21:19 ` Paul Osmialowski
  2015-06-24 10:21     ` Paul Bolle
       [not found]   ` <1435094387-20146-8-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
@ 2015-07-14  8:53       ` Linus Walleij
  1 sibling, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-07-14  8:53 UTC (permalink / raw)
  To: Paul Osmialowski, Sascha Hauer, Shawn Guo
  Cc: Arnd Bergmann, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart, Magnus Damm,
	Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Russell King, Simon Horman, Stefan Agner

On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org> wrote:
> This is very cheap and simple implementation of pinctrl driver
> for Kinetis SoC - its primary role is to provide means for enabling UART
> fuctionality on I/O PORT_E which will be utilized by the commits
> yet to come.
>
> Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>

OK...

I want Shawn and Sascha to look at this as they worked with
other Freescale pin controllers. Especially I want to know if this
is a sibling to the other Freescale controllers or a separate hardware.

If it is *not* a sibling I will *insist* that it use more generic pin
control bindings and move away from the older Freescale-specific
stuff.

>  arch/arm/Kconfig                                   |   1 +
>  arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
>  arch/arm/mach-kinetis/Kconfig                      |   6 +
>  drivers/clk/clk-kinetis.c                          |  28 ++

>  include/dt-bindings/clock/kinetis-mcg.h            |   8 +-

I see that you are trying to hold together "pin control support" in a
patch hitting all over the world. I don't think this is good, I think it is
better if you make a separate patch for bindings, clock, DTS and
mach-kinetis.

I think the clock support could go into the one big clock support
patch in the series simply, but its a question for the clk maintainer.

I only want the below change for the pin control subsystem and I
want to merge that into my tree. I will also merge the device tree
bindings for it. The rest goes to the clock tree and ARM SoC.
You can merge the Kconfig selects
of the symbols orthogonally so you need not keep it together,
and DTS changes are by definition orthogonal.

>  .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++

>  drivers/pinctrl/freescale/Kconfig                  |   8 +
>  drivers/pinctrl/freescale/Makefile                 |   1 +
>  drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
>  9 files changed, 659 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
>  create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

So I will take these things once we are done with review etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> new file mode 100644
> index 0000000..04798c4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> @@ -0,0 +1,31 @@
> +Freescale Kinetis IOMUX Controller
> +
> +This controller is largely based on i.MX IOMUX Controller. Please refer to
> +fsl,imx-pinctrl.txt in this directory for more detailed description.
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-iomuxc".
> +- reg: Should contain the physical address and length of the gpio/pinmux
> +  register range.
> +- clocks: Clock that drives this I/O port.
> +- fsl,pins: Two integers array, represents a group of pins mux and config
> +  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
> +  a pin working on a specific function, CONFIG is the pad setting value
> +  such as pull enable, pull select, drive strength enable. Please refer to
> +  Kinetis datasheet for the valid pad config settings.

There exist generic pin config bindings, see
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

I suggest to to function+group paring and then use generic pin config
with this driver unless it is a very close sibling to the existing Freescale
pin controllers.

Hint: if it is a sibling, it should share code with them.

There are several drivers doing generic pin control/pin config in the kernel
tree.

> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index 12ef544..2d0dfa9 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -94,6 +94,14 @@ config PINCTRL_IMX7D
>         help
>           Say Y here to enable the imx7d pinctrl driver
>
> +config PINCTRL_KINETIS
> +       bool "Kinetis pinctrl driver"
> +       depends on OF
> +       depends on SOC_K70

I don't know if that cryptic symbol is very good. FREESCALE_SOC_K70
makes more sense.

> @@ -0,0 +1,529 @@
> +/*
> + * pinctrl-kinetis.c - iomux for Kinetis MCUs
> + *
> + * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pinctrl/machine.h>

Why are you including this? It seems wrong. Machine
definitions should not be in the driver, in your case it should
probably be in the device tree.

> +/*
> + * PORTx register map
> + */
> +struct kinetis_port_regs {
> +       u32 pcr[32];    /* Pin Control Registers */
> +       u32 gpclr;      /* Global Pin Control Low Register */
> +       u32 gpchr;      /* Global Pin Control High Register */
> +       u32 rsv0[6];
> +       u32 isfr;       /* Interrupt Status Flag Register */
> +       u32 rsv1[7];
> +       u32 dfer;       /* Digital Filter Enable Register */
> +       u32 dfcr;       /* Digital Filter Clock Register */
> +       u32 dfwr;       /* Digital Filter Width Register */
> +};

Why do you need this ... I don't get it.
Please elaborate on why you are keeping a struct model of
the register map around.

> +/*
> + * PORTx registers base
> + */
> +#define KINETIS_PORT_PTR(base, reg) \
> +       (&(((struct kinetis_port_regs *)(base))->reg))
> +#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_WR(base, reg, val) \
> +               writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_SET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
> +#define KINETIS_PORT_RESET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))

Convert these to static inline functions instead. It is way easier to read
than this compact and terse defines.

> +static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
> +                       struct device_node *np,
> +                       struct pinctrl_map **map, unsigned *num_maps)
> +{
> +       struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
> +       const struct kinetis_pin_group *grp;
> +       struct pinctrl_map *new_map;
> +       struct device_node *parent;
> +
> +       /*
> +        * first find the group of this node and check if we need create
> +        * config maps for pins
> +        */
> +       grp = kinetis_pinctrl_find_group_by_name(info, np->name);
> +       if (!grp) {
> +               dev_err(info->dev, "unable to find group for node %s\n",
> +                       np->name);
> +               return -EINVAL;
> +       }
> +
> +       new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;


Use pinctrl_utils_reserve_map() from pinctrl-utils.h

> +static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
> +                               struct pinctrl_map *map, unsigned num_maps)
> +{
> +       kfree(map);
> +}

Use pinctrl_utils_dt_free_map().

> +static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
> +                               struct kinetis_pinctrl_soc_info *info)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct device_node *child;
> +       u32 nfuncs = 0;
> +       u32 i = 0;
> +       bool flat_funcs;
> +
> +       if (!np)
> +               return -ENODEV;
> +
> +       flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);

Why is there an _is_ in that function name? Totally unintuitive
to me.

I think I will have more comments on v2, this is just a first rough look.

Yours,
Linus Walleij
--
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] 86+ messages in thread

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-07-14  8:53       ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-07-14  8:53 UTC (permalink / raw)
  To: Paul Osmialowski, Sascha Hauer, Shawn Guo
  Cc: Arnd Bergmann, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart, Magnus Damm,
	Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Russell King, Simon Horman, Stefan Agner, Stephen Boyd,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	devicetree

On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> This is very cheap and simple implementation of pinctrl driver
> for Kinetis SoC - its primary role is to provide means for enabling UART
> fuctionality on I/O PORT_E which will be utilized by the commits
> yet to come.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

OK...

I want Shawn and Sascha to look at this as they worked with
other Freescale pin controllers. Especially I want to know if this
is a sibling to the other Freescale controllers or a separate hardware.

If it is *not* a sibling I will *insist* that it use more generic pin
control bindings and move away from the older Freescale-specific
stuff.

>  arch/arm/Kconfig                                   |   1 +
>  arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
>  arch/arm/mach-kinetis/Kconfig                      |   6 +
>  drivers/clk/clk-kinetis.c                          |  28 ++

>  include/dt-bindings/clock/kinetis-mcg.h            |   8 +-

I see that you are trying to hold together "pin control support" in a
patch hitting all over the world. I don't think this is good, I think it is
better if you make a separate patch for bindings, clock, DTS and
mach-kinetis.

I think the clock support could go into the one big clock support
patch in the series simply, but its a question for the clk maintainer.

I only want the below change for the pin control subsystem and I
want to merge that into my tree. I will also merge the device tree
bindings for it. The rest goes to the clock tree and ARM SoC.
You can merge the Kconfig selects
of the symbols orthogonally so you need not keep it together,
and DTS changes are by definition orthogonal.

>  .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++

>  drivers/pinctrl/freescale/Kconfig                  |   8 +
>  drivers/pinctrl/freescale/Makefile                 |   1 +
>  drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
>  9 files changed, 659 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
>  create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

So I will take these things once we are done with review etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> new file mode 100644
> index 0000000..04798c4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> @@ -0,0 +1,31 @@
> +Freescale Kinetis IOMUX Controller
> +
> +This controller is largely based on i.MX IOMUX Controller. Please refer to
> +fsl,imx-pinctrl.txt in this directory for more detailed description.
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-iomuxc".
> +- reg: Should contain the physical address and length of the gpio/pinmux
> +  register range.
> +- clocks: Clock that drives this I/O port.
> +- fsl,pins: Two integers array, represents a group of pins mux and config
> +  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
> +  a pin working on a specific function, CONFIG is the pad setting value
> +  such as pull enable, pull select, drive strength enable. Please refer to
> +  Kinetis datasheet for the valid pad config settings.

There exist generic pin config bindings, see
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

I suggest to to function+group paring and then use generic pin config
with this driver unless it is a very close sibling to the existing Freescale
pin controllers.

Hint: if it is a sibling, it should share code with them.

There are several drivers doing generic pin control/pin config in the kernel
tree.

> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index 12ef544..2d0dfa9 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -94,6 +94,14 @@ config PINCTRL_IMX7D
>         help
>           Say Y here to enable the imx7d pinctrl driver
>
> +config PINCTRL_KINETIS
> +       bool "Kinetis pinctrl driver"
> +       depends on OF
> +       depends on SOC_K70

I don't know if that cryptic symbol is very good. FREESCALE_SOC_K70
makes more sense.

> @@ -0,0 +1,529 @@
> +/*
> + * pinctrl-kinetis.c - iomux for Kinetis MCUs
> + *
> + * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng@linaro.org>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pinctrl/machine.h>

Why are you including this? It seems wrong. Machine
definitions should not be in the driver, in your case it should
probably be in the device tree.

> +/*
> + * PORTx register map
> + */
> +struct kinetis_port_regs {
> +       u32 pcr[32];    /* Pin Control Registers */
> +       u32 gpclr;      /* Global Pin Control Low Register */
> +       u32 gpchr;      /* Global Pin Control High Register */
> +       u32 rsv0[6];
> +       u32 isfr;       /* Interrupt Status Flag Register */
> +       u32 rsv1[7];
> +       u32 dfer;       /* Digital Filter Enable Register */
> +       u32 dfcr;       /* Digital Filter Clock Register */
> +       u32 dfwr;       /* Digital Filter Width Register */
> +};

Why do you need this ... I don't get it.
Please elaborate on why you are keeping a struct model of
the register map around.

> +/*
> + * PORTx registers base
> + */
> +#define KINETIS_PORT_PTR(base, reg) \
> +       (&(((struct kinetis_port_regs *)(base))->reg))
> +#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_WR(base, reg, val) \
> +               writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_SET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
> +#define KINETIS_PORT_RESET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))

Convert these to static inline functions instead. It is way easier to read
than this compact and terse defines.

> +static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
> +                       struct device_node *np,
> +                       struct pinctrl_map **map, unsigned *num_maps)
> +{
> +       struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
> +       const struct kinetis_pin_group *grp;
> +       struct pinctrl_map *new_map;
> +       struct device_node *parent;
> +
> +       /*
> +        * first find the group of this node and check if we need create
> +        * config maps for pins
> +        */
> +       grp = kinetis_pinctrl_find_group_by_name(info, np->name);
> +       if (!grp) {
> +               dev_err(info->dev, "unable to find group for node %s\n",
> +                       np->name);
> +               return -EINVAL;
> +       }
> +
> +       new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;


Use pinctrl_utils_reserve_map() from pinctrl-utils.h

> +static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
> +                               struct pinctrl_map *map, unsigned num_maps)
> +{
> +       kfree(map);
> +}

Use pinctrl_utils_dt_free_map().

> +static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
> +                               struct kinetis_pinctrl_soc_info *info)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct device_node *child;
> +       u32 nfuncs = 0;
> +       u32 i = 0;
> +       bool flat_funcs;
> +
> +       if (!np)
> +               return -ENODEV;
> +
> +       flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);

Why is there an _is_ in that function name? Totally unintuitive
to me.

I think I will have more comments on v2, this is just a first rough look.

Yours,
Linus Walleij

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-07-14  8:53       ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-07-14  8:53 UTC (permalink / raw)
  To: Paul Osmialowski, Sascha Hauer, Shawn Guo
  Cc: Arnd Bergmann, Geert Uytterhoeven, Greg Kroah-Hartman,
	Guenter Roeck, Haojian Zhuang, Ian Campbell, Jingchang Lu,
	Jiri Slaby, Kees Cook, Kumar Gala, Laurent Pinchart, Magnus Damm,
	Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Russell King, Simon Horman, Stefan Agner, Stephen Boyd,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	devicetree

On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> This is very cheap and simple implementation of pinctrl driver
> for Kinetis SoC - its primary role is to provide means for enabling UART
> fuctionality on I/O PORT_E which will be utilized by the commits
> yet to come.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

OK...

I want Shawn and Sascha to look at this as they worked with
other Freescale pin controllers. Especially I want to know if this
is a sibling to the other Freescale controllers or a separate hardware.

If it is *not* a sibling I will *insist* that it use more generic pin
control bindings and move away from the older Freescale-specific
stuff.

>  arch/arm/Kconfig                                   |   1 +
>  arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
>  arch/arm/mach-kinetis/Kconfig                      |   6 +
>  drivers/clk/clk-kinetis.c                          |  28 ++

>  include/dt-bindings/clock/kinetis-mcg.h            |   8 +-

I see that you are trying to hold together "pin control support" in a
patch hitting all over the world. I don't think this is good, I think it is
better if you make a separate patch for bindings, clock, DTS and
mach-kinetis.

I think the clock support could go into the one big clock support
patch in the series simply, but its a question for the clk maintainer.

I only want the below change for the pin control subsystem and I
want to merge that into my tree. I will also merge the device tree
bindings for it. The rest goes to the clock tree and ARM SoC.
You can merge the Kconfig selects
of the symbols orthogonally so you need not keep it together,
and DTS changes are by definition orthogonal.

>  .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++

>  drivers/pinctrl/freescale/Kconfig                  |   8 +
>  drivers/pinctrl/freescale/Makefile                 |   1 +
>  drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
>  9 files changed, 659 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
>  create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

So I will take these things once we are done with review etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> new file mode 100644
> index 0000000..04798c4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> @@ -0,0 +1,31 @@
> +Freescale Kinetis IOMUX Controller
> +
> +This controller is largely based on i.MX IOMUX Controller. Please refer to
> +fsl,imx-pinctrl.txt in this directory for more detailed description.
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-iomuxc".
> +- reg: Should contain the physical address and length of the gpio/pinmux
> +  register range.
> +- clocks: Clock that drives this I/O port.
> +- fsl,pins: Two integers array, represents a group of pins mux and config
> +  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
> +  a pin working on a specific function, CONFIG is the pad setting value
> +  such as pull enable, pull select, drive strength enable. Please refer to
> +  Kinetis datasheet for the valid pad config settings.

There exist generic pin config bindings, see
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

I suggest to to function+group paring and then use generic pin config
with this driver unless it is a very close sibling to the existing Freescale
pin controllers.

Hint: if it is a sibling, it should share code with them.

There are several drivers doing generic pin control/pin config in the kernel
tree.

> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index 12ef544..2d0dfa9 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -94,6 +94,14 @@ config PINCTRL_IMX7D
>         help
>           Say Y here to enable the imx7d pinctrl driver
>
> +config PINCTRL_KINETIS
> +       bool "Kinetis pinctrl driver"
> +       depends on OF
> +       depends on SOC_K70

I don't know if that cryptic symbol is very good. FREESCALE_SOC_K70
makes more sense.

> @@ -0,0 +1,529 @@
> +/*
> + * pinctrl-kinetis.c - iomux for Kinetis MCUs
> + *
> + * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng@linaro.org>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pinctrl/machine.h>

Why are you including this? It seems wrong. Machine
definitions should not be in the driver, in your case it should
probably be in the device tree.

> +/*
> + * PORTx register map
> + */
> +struct kinetis_port_regs {
> +       u32 pcr[32];    /* Pin Control Registers */
> +       u32 gpclr;      /* Global Pin Control Low Register */
> +       u32 gpchr;      /* Global Pin Control High Register */
> +       u32 rsv0[6];
> +       u32 isfr;       /* Interrupt Status Flag Register */
> +       u32 rsv1[7];
> +       u32 dfer;       /* Digital Filter Enable Register */
> +       u32 dfcr;       /* Digital Filter Clock Register */
> +       u32 dfwr;       /* Digital Filter Width Register */
> +};

Why do you need this ... I don't get it.
Please elaborate on why you are keeping a struct model of
the register map around.

> +/*
> + * PORTx registers base
> + */
> +#define KINETIS_PORT_PTR(base, reg) \
> +       (&(((struct kinetis_port_regs *)(base))->reg))
> +#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_WR(base, reg, val) \
> +               writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_SET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
> +#define KINETIS_PORT_RESET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))

Convert these to static inline functions instead. It is way easier to read
than this compact and terse defines.

> +static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
> +                       struct device_node *np,
> +                       struct pinctrl_map **map, unsigned *num_maps)
> +{
> +       struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
> +       const struct kinetis_pin_group *grp;
> +       struct pinctrl_map *new_map;
> +       struct device_node *parent;
> +
> +       /*
> +        * first find the group of this node and check if we need create
> +        * config maps for pins
> +        */
> +       grp = kinetis_pinctrl_find_group_by_name(info, np->name);
> +       if (!grp) {
> +               dev_err(info->dev, "unable to find group for node %s\n",
> +                       np->name);
> +               return -EINVAL;
> +       }
> +
> +       new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;


Use pinctrl_utils_reserve_map() from pinctrl-utils.h

> +static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
> +                               struct pinctrl_map *map, unsigned num_maps)
> +{
> +       kfree(map);
> +}

Use pinctrl_utils_dt_free_map().

> +static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
> +                               struct kinetis_pinctrl_soc_info *info)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct device_node *child;
> +       u32 nfuncs = 0;
> +       u32 i = 0;
> +       bool flat_funcs;
> +
> +       if (!np)
> +               return -ENODEV;
> +
> +       flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);

Why is there an _is_ in that function name? Totally unintuitive
to me.

I think I will have more comments on v2, this is just a first rough look.

Yours,
Linus Walleij

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

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-07-14  8:53       ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-07-14  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 23, 2015 at 11:19 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> This is very cheap and simple implementation of pinctrl driver
> for Kinetis SoC - its primary role is to provide means for enabling UART
> fuctionality on I/O PORT_E which will be utilized by the commits
> yet to come.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>

OK...

I want Shawn and Sascha to look at this as they worked with
other Freescale pin controllers. Especially I want to know if this
is a sibling to the other Freescale controllers or a separate hardware.

If it is *not* a sibling I will *insist* that it use more generic pin
control bindings and move away from the older Freescale-specific
stuff.

>  arch/arm/Kconfig                                   |   1 +
>  arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
>  arch/arm/mach-kinetis/Kconfig                      |   6 +
>  drivers/clk/clk-kinetis.c                          |  28 ++

>  include/dt-bindings/clock/kinetis-mcg.h            |   8 +-

I see that you are trying to hold together "pin control support" in a
patch hitting all over the world. I don't think this is good, I think it is
better if you make a separate patch for bindings, clock, DTS and
mach-kinetis.

I think the clock support could go into the one big clock support
patch in the series simply, but its a question for the clk maintainer.

I only want the below change for the pin control subsystem and I
want to merge that into my tree. I will also merge the device tree
bindings for it. The rest goes to the clock tree and ARM SoC.
You can merge the Kconfig selects
of the symbols orthogonally so you need not keep it together,
and DTS changes are by definition orthogonal.

>  .../bindings/pinctrl/fsl,kinetis-pinctrl.txt       |  31 ++

>  drivers/pinctrl/freescale/Kconfig                  |   8 +
>  drivers/pinctrl/freescale/Makefile                 |   1 +
>  drivers/pinctrl/freescale/pinctrl-kinetis.c        | 529 +++++++++++++++++++++
>  9 files changed, 659 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
>  create mode 100644 drivers/pinctrl/freescale/pinctrl-kinetis.c

So I will take these things once we are done with review etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> new file mode 100644
> index 0000000..04798c4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/fsl,kinetis-pinctrl.txt
> @@ -0,0 +1,31 @@
> +Freescale Kinetis IOMUX Controller
> +
> +This controller is largely based on i.MX IOMUX Controller. Please refer to
> +fsl,imx-pinctrl.txt in this directory for more detailed description.
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-iomuxc".
> +- reg: Should contain the physical address and length of the gpio/pinmux
> +  register range.
> +- clocks: Clock that drives this I/O port.
> +- fsl,pins: Two integers array, represents a group of pins mux and config
> +  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
> +  a pin working on a specific function, CONFIG is the pad setting value
> +  such as pull enable, pull select, drive strength enable. Please refer to
> +  Kinetis datasheet for the valid pad config settings.

There exist generic pin config bindings, see
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

I suggest to to function+group paring and then use generic pin config
with this driver unless it is a very close sibling to the existing Freescale
pin controllers.

Hint: if it is a sibling, it should share code with them.

There are several drivers doing generic pin control/pin config in the kernel
tree.

> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index 12ef544..2d0dfa9 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -94,6 +94,14 @@ config PINCTRL_IMX7D
>         help
>           Say Y here to enable the imx7d pinctrl driver
>
> +config PINCTRL_KINETIS
> +       bool "Kinetis pinctrl driver"
> +       depends on OF
> +       depends on SOC_K70

I don't know if that cryptic symbol is very good. FREESCALE_SOC_K70
makes more sense.

> @@ -0,0 +1,529 @@
> +/*
> + * pinctrl-kinetis.c - iomux for Kinetis MCUs
> + *
> + * Based on pinctrl-imx.c by Dong Aisheng <dong.aisheng@linaro.org>
> + *
> + * Copyright (C) 2015 Paul Osmialowski <pawelo@king.net.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pinctrl/machine.h>

Why are you including this? It seems wrong. Machine
definitions should not be in the driver, in your case it should
probably be in the device tree.

> +/*
> + * PORTx register map
> + */
> +struct kinetis_port_regs {
> +       u32 pcr[32];    /* Pin Control Registers */
> +       u32 gpclr;      /* Global Pin Control Low Register */
> +       u32 gpchr;      /* Global Pin Control High Register */
> +       u32 rsv0[6];
> +       u32 isfr;       /* Interrupt Status Flag Register */
> +       u32 rsv1[7];
> +       u32 dfer;       /* Digital Filter Enable Register */
> +       u32 dfcr;       /* Digital Filter Clock Register */
> +       u32 dfwr;       /* Digital Filter Width Register */
> +};

Why do you need this ... I don't get it.
Please elaborate on why you are keeping a struct model of
the register map around.

> +/*
> + * PORTx registers base
> + */
> +#define KINETIS_PORT_PTR(base, reg) \
> +       (&(((struct kinetis_port_regs *)(base))->reg))
> +#define KINETIS_PORT_RD(base, reg) readl_relaxed(KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_WR(base, reg, val) \
> +               writel_relaxed((val), KINETIS_PORT_PTR(base, reg))
> +#define KINETIS_PORT_SET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) | (mask))
> +#define KINETIS_PORT_RESET(base, reg, mask) \
> +       KINETIS_PORT_WR(base, reg, (KINETIS_PORT_RD(base, reg)) & (~(mask)))

Convert these to static inline functions instead. It is way easier to read
than this compact and terse defines.

> +static int kinetis_dt_node_to_map(struct pinctrl_dev *pctldev,
> +                       struct device_node *np,
> +                       struct pinctrl_map **map, unsigned *num_maps)
> +{
> +       struct kinetis_pinctrl *kpctl = pinctrl_dev_get_drvdata(pctldev);
> +       const struct kinetis_pinctrl_soc_info *info = &kpctl->info;
> +       const struct kinetis_pin_group *grp;
> +       struct pinctrl_map *new_map;
> +       struct device_node *parent;
> +
> +       /*
> +        * first find the group of this node and check if we need create
> +        * config maps for pins
> +        */
> +       grp = kinetis_pinctrl_find_group_by_name(info, np->name);
> +       if (!grp) {
> +               dev_err(info->dev, "unable to find group for node %s\n",
> +                       np->name);
> +               return -EINVAL;
> +       }
> +
> +       new_map = kmalloc(sizeof(struct pinctrl_map), GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;


Use pinctrl_utils_reserve_map() from pinctrl-utils.h

> +static void kinetis_dt_free_map(struct pinctrl_dev *pctldev,
> +                               struct pinctrl_map *map, unsigned num_maps)
> +{
> +       kfree(map);
> +}

Use pinctrl_utils_dt_free_map().

> +static int kinetis_pinctrl_probe_dt(struct platform_device *pdev,
> +                               struct kinetis_pinctrl_soc_info *info)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct device_node *child;
> +       u32 nfuncs = 0;
> +       u32 i = 0;
> +       bool flat_funcs;
> +
> +       if (!np)
> +               return -ENODEV;
> +
> +       flat_funcs = kinetis_pinctrl_dt_is_flat_functions(np);

Why is there an _is_ in that function name? Totally unintuitive
to me.

I think I will have more comments on v2, this is just a first rough look.

Yours,
Linus Walleij

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-07-14  8:53       ` Linus Walleij
  (?)
  (?)
@ 2015-09-08  8:04         ` Paul Osmialowski
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-09-08  8:04 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Mark Rutland, Catalin Marinas, Geert Uytterhoeven, Stephen Boyd,
	Michael Turquette, Stefan Agner, Laurent Pinchart, Jiri Slaby,
	linux-clk, Kees Cook, Russell King, Nicolas Pitre, Magnus Damm,
	Uwe Kleine-Koenig, Dave Martin, Guenter Roeck, devicetree,
	Paul Osmialowski, Sascha Hauer, Arnd Bergmann, Ian Campbell,
	Jingchang Lu, Hao

Hi Linus,

On Tue, 14 Jul 2015, Linus Walleij wrote:

> OK...
> 
> I want Shawn and Sascha to look at this as they worked with
> other Freescale pin controllers. Especially I want to know if this
> is a sibling to the other Freescale controllers or a separate hardware.
> 
> If it is *not* a sibling I will *insist* that it use more generic pin
> control bindings and move away from the older Freescale-specific
> stuff.

No one answered me about that. However, I looked at other Freescale 
pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is 
similar to what I need to do for Kinetis, also positions of configuration 
bits differ significantly.

> 
> There exist generic pin config bindings, see
> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
> 
> I suggest to to function+group paring and then use generic pin config
> with this driver unless it is a very close sibling to the existing Freescale
> pin controllers.
> 
> Hint: if it is a sibling, it should share code with them.
> 
> There are several drivers doing generic pin control/pin config in the kernel
> tree.
> 

I tried to analyze few of the drivers (e.g. zynq family) and can't find 
how can I assing clock gate (clock device) to each port (PORTA, PORTB, 
PORTC,...) which is required for Kinetis. Is generic pin control capable 
to express that requirement or is it a time to desing my own pinctrl 
driver (maybe somewhat improved than the one I presented so far)?

This pinctrl component is somwehat critical part of BSP. Until it is not 
sorted, I don't see a point in releasing what was developed so far.

Best regards,
Paul

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08  8:04         ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-09-08  8:04 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Sascha Hauer, Shawn Guo, Arnd Bergmann,
	Geert Uytterhoeven, Greg Kroah-Hartman, Guenter Roeck,
	Haojian Zhuang, Ian Campbell, Jingchang Lu, Jiri Slaby,
	Kees Cook, Kumar Gala, Laurent Pinchart, Magnus Damm,
	Michael Turquette, Nathan Lynch, Nicolas Pitre,
	Maxime Coquelin stm32, Olof Johansson, Paul Bolle, Rob Herring,
	Russell King, Simon Horman, Stefan Agner, Stephen Boyd,
	Uwe Kleine-Koenig, Catalin Marinas, Dave Martin, Mark Rutland,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	devicetree

Hi Linus,

On Tue, 14 Jul 2015, Linus Walleij wrote:

> OK...
> 
> I want Shawn and Sascha to look at this as they worked with
> other Freescale pin controllers. Especially I want to know if this
> is a sibling to the other Freescale controllers or a separate hardware.
> 
> If it is *not* a sibling I will *insist* that it use more generic pin
> control bindings and move away from the older Freescale-specific
> stuff.

No one answered me about that. However, I looked at other Freescale 
pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is 
similar to what I need to do for Kinetis, also positions of configuration 
bits differ significantly.

> 
> There exist generic pin config bindings, see
> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
> 
> I suggest to to function+group paring and then use generic pin config
> with this driver unless it is a very close sibling to the existing Freescale
> pin controllers.
> 
> Hint: if it is a sibling, it should share code with them.
> 
> There are several drivers doing generic pin control/pin config in the kernel
> tree.
> 

I tried to analyze few of the drivers (e.g. zynq family) and can't find 
how can I assing clock gate (clock device) to each port (PORTA, PORTB, 
PORTC,...) which is required for Kinetis. Is generic pin control capable 
to express that requirement or is it a time to desing my own pinctrl 
driver (maybe somewhat improved than the one I presented so far)?

This pinctrl component is somwehat critical part of BSP. Until it is not 
sorted, I don't see a point in releasing what was developed so far.

Best regards,
Paul

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08  8:04         ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-09-08  8:04 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Mark Rutland, Catalin Marinas, Geert Uytterhoeven, Stephen Boyd,
	Michael Turquette, Stefan Agner, Laurent Pinchart, Jiri Slaby,
	linux-clk, Kees Cook, Russell King, Nicolas Pitre, Magnus Damm,
	Uwe Kleine-Koenig, Dave Martin, Guenter Roeck, devicetree,
	Paul Osmialowski, Sascha Hauer, Arnd Bergmann, Ian Campbell,
	Jingchang Lu, Haojian Zhuang, linux-gpio, Rob Herring,
	Simon Horman, linux-arm-kernel, Paul Bolle, Greg Kroah-Hartman,
	Nathan Lynch, linux-kernel, Maxime Coquelin stm32, Kumar Gala,
	Olof Johansson, Shawn Guo

Hi Linus,

On Tue, 14 Jul 2015, Linus Walleij wrote:

> OK...
> 
> I want Shawn and Sascha to look at this as they worked with
> other Freescale pin controllers. Especially I want to know if this
> is a sibling to the other Freescale controllers or a separate hardware.
> 
> If it is *not* a sibling I will *insist* that it use more generic pin
> control bindings and move away from the older Freescale-specific
> stuff.

No one answered me about that. However, I looked at other Freescale 
pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is 
similar to what I need to do for Kinetis, also positions of configuration 
bits differ significantly.

> 
> There exist generic pin config bindings, see
> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
> 
> I suggest to to function+group paring and then use generic pin config
> with this driver unless it is a very close sibling to the existing Freescale
> pin controllers.
> 
> Hint: if it is a sibling, it should share code with them.
> 
> There are several drivers doing generic pin control/pin config in the kernel
> tree.
> 

I tried to analyze few of the drivers (e.g. zynq family) and can't find 
how can I assing clock gate (clock device) to each port (PORTA, PORTB, 
PORTC,...) which is required for Kinetis. Is generic pin control capable 
to express that requirement or is it a time to desing my own pinctrl 
driver (maybe somewhat improved than the one I presented so far)?

This pinctrl component is somwehat critical part of BSP. Until it is not 
sorted, I don't see a point in releasing what was developed so far.

Best regards,
Paul

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

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

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08  8:04         ` Paul Osmialowski
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Osmialowski @ 2015-09-08  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Linus,

On Tue, 14 Jul 2015, Linus Walleij wrote:

> OK...
> 
> I want Shawn and Sascha to look at this as they worked with
> other Freescale pin controllers. Especially I want to know if this
> is a sibling to the other Freescale controllers or a separate hardware.
> 
> If it is *not* a sibling I will *insist* that it use more generic pin
> control bindings and move away from the older Freescale-specific
> stuff.

No one answered me about that. However, I looked at other Freescale 
pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is 
similar to what I need to do for Kinetis, also positions of configuration 
bits differ significantly.

> 
> There exist generic pin config bindings, see
> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
> 
> I suggest to to function+group paring and then use generic pin config
> with this driver unless it is a very close sibling to the existing Freescale
> pin controllers.
> 
> Hint: if it is a sibling, it should share code with them.
> 
> There are several drivers doing generic pin control/pin config in the kernel
> tree.
> 

I tried to analyze few of the drivers (e.g. zynq family) and can't find 
how can I assing clock gate (clock device) to each port (PORTA, PORTB, 
PORTC,...) which is required for Kinetis. Is generic pin control capable 
to express that requirement or is it a time to desing my own pinctrl 
driver (maybe somewhat improved than the one I presented so far)?

This pinctrl component is somwehat critical part of BSP. Until it is not 
sorted, I don't see a point in releasing what was developed so far.

Best regards,
Paul

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-09-08  8:04         ` Paul Osmialowski
  (?)
  (?)
@ 2015-09-08 14:28           ` Linus Walleij
  -1 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-09-08 14:28 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Sascha Hauer, Shawn Guo, Arnd Bergmann, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Russell King, Simon

On Tue, Sep 8, 2015 at 10:04 AM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> On Tue, 14 Jul 2015, Linus Walleij wrote:
>
>> I want Shawn and Sascha to look at this as they worked with
>> other Freescale pin controllers. Especially I want to know if this
>> is a sibling to the other Freescale controllers or a separate hardware.
>>
>> If it is *not* a sibling I will *insist* that it use more generic pin
>> control bindings and move away from the older Freescale-specific
>> stuff.
>
> No one answered me about that. However, I looked at other Freescale
> pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is
> similar to what I need to do for Kinetis, also positions of configuration
> bits differ significantly.

OK I insist on using the generic bindings then.

>> There exist generic pin config bindings, see
>> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
>>
>> I suggest to to function+group paring and then use generic pin config
>> with this driver unless it is a very close sibling to the existing Freescale
>> pin controllers.
>>
>> Hint: if it is a sibling, it should share code with them.
>>
>> There are several drivers doing generic pin control/pin config in the kernel
>> tree.
>
> I tried to analyze few of the drivers (e.g. zynq family) and can't find
> how can I assing clock gate (clock device) to each port (PORTA, PORTB,
> PORTC,...) which is required for Kinetis. Is generic pin control capable
> to express that requirement or is it a time to desing my own pinctrl
> driver (maybe somewhat improved than the one I presented so far)?

That has nothing to do with whether you use generic pinconf or not.
I imagine if a pinctrl unit contains several blocks with individual
clocks you can either:

- Let each block/bank be a device node (this is common) and assign
  each a clocks = <&clock>;

- Keep one node and assign an array of clocks, affected block indicated
  by the index.
  clocks = <&clk1>, <&clk2>, <&clk3>, ... <clkN>;
  This property is in pluralis for this reason I guess.

> This pinctrl component is somwehat critical part of BSP. Until it is not
> sorted, I don't see a point in releasing what was developed so far.

True that, you need infrastructure first. The more important that it is
as good as possible.

Yours,
Linus Walleij

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08 14:28           ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-09-08 14:28 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Sascha Hauer, Shawn Guo, Arnd Bergmann, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Russell King, Simon Horman, Stefan Agner,
	Stephen Boyd, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, devicetree

On Tue, Sep 8, 2015 at 10:04 AM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> On Tue, 14 Jul 2015, Linus Walleij wrote:
>
>> I want Shawn and Sascha to look at this as they worked with
>> other Freescale pin controllers. Especially I want to know if this
>> is a sibling to the other Freescale controllers or a separate hardware.
>>
>> If it is *not* a sibling I will *insist* that it use more generic pin
>> control bindings and move away from the older Freescale-specific
>> stuff.
>
> No one answered me about that. However, I looked at other Freescale
> pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is
> similar to what I need to do for Kinetis, also positions of configuration
> bits differ significantly.

OK I insist on using the generic bindings then.

>> There exist generic pin config bindings, see
>> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
>>
>> I suggest to to function+group paring and then use generic pin config
>> with this driver unless it is a very close sibling to the existing Freescale
>> pin controllers.
>>
>> Hint: if it is a sibling, it should share code with them.
>>
>> There are several drivers doing generic pin control/pin config in the kernel
>> tree.
>
> I tried to analyze few of the drivers (e.g. zynq family) and can't find
> how can I assing clock gate (clock device) to each port (PORTA, PORTB,
> PORTC,...) which is required for Kinetis. Is generic pin control capable
> to express that requirement or is it a time to desing my own pinctrl
> driver (maybe somewhat improved than the one I presented so far)?

That has nothing to do with whether you use generic pinconf or not.
I imagine if a pinctrl unit contains several blocks with individual
clocks you can either:

- Let each block/bank be a device node (this is common) and assign
  each a clocks = <&clock>;

- Keep one node and assign an array of clocks, affected block indicated
  by the index.
  clocks = <&clk1>, <&clk2>, <&clk3>, ... <clkN>;
  This property is in pluralis for this reason I guess.

> This pinctrl component is somwehat critical part of BSP. Until it is not
> sorted, I don't see a point in releasing what was developed so far.

True that, you need infrastructure first. The more important that it is
as good as possible.

Yours,
Linus Walleij

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

* Re: [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08 14:28           ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-09-08 14:28 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Sascha Hauer, Shawn Guo, Arnd Bergmann, Geert Uytterhoeven,
	Greg Kroah-Hartman, Guenter Roeck, Haojian Zhuang, Ian Campbell,
	Jingchang Lu, Jiri Slaby, Kees Cook, Kumar Gala,
	Laurent Pinchart, Magnus Damm, Michael Turquette, Nathan Lynch,
	Nicolas Pitre, Maxime Coquelin stm32, Olof Johansson, Paul Bolle,
	Rob Herring, Russell King, Simon Horman, Stefan Agner,
	Stephen Boyd, Uwe Kleine-Koenig, Catalin Marinas, Dave Martin,
	Mark Rutland, linux-kernel, linux-arm-kernel, linux-clk,
	linux-gpio, devicetree

On Tue, Sep 8, 2015 at 10:04 AM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> On Tue, 14 Jul 2015, Linus Walleij wrote:
>
>> I want Shawn and Sascha to look at this as they worked with
>> other Freescale pin controllers. Especially I want to know if this
>> is a sibling to the other Freescale controllers or a separate hardware.
>>
>> If it is *not* a sibling I will *insist* that it use more generic pin
>> control bindings and move away from the older Freescale-specific
>> stuff.
>
> No one answered me about that. However, I looked at other Freescale
> pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is
> similar to what I need to do for Kinetis, also positions of configuration
> bits differ significantly.

OK I insist on using the generic bindings then.

>> There exist generic pin config bindings, see
>> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
>>
>> I suggest to to function+group paring and then use generic pin config
>> with this driver unless it is a very close sibling to the existing Freescale
>> pin controllers.
>>
>> Hint: if it is a sibling, it should share code with them.
>>
>> There are several drivers doing generic pin control/pin config in the kernel
>> tree.
>
> I tried to analyze few of the drivers (e.g. zynq family) and can't find
> how can I assing clock gate (clock device) to each port (PORTA, PORTB,
> PORTC,...) which is required for Kinetis. Is generic pin control capable
> to express that requirement or is it a time to desing my own pinctrl
> driver (maybe somewhat improved than the one I presented so far)?

That has nothing to do with whether you use generic pinconf or not.
I imagine if a pinctrl unit contains several blocks with individual
clocks you can either:

- Let each block/bank be a device node (this is common) and assign
  each a clocks = <&clock>;

- Keep one node and assign an array of clocks, affected block indicated
  by the index.
  clocks = <&clk1>, <&clk2>, <&clk3>, ... <clkN>;
  This property is in pluralis for this reason I guess.

> This pinctrl component is somwehat critical part of BSP. Until it is not
> sorted, I don't see a point in releasing what was developed so far.

True that, you need infrastructure first. The more important that it is
as good as possible.

Yours,
Linus Walleij

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

* [PATCH 7/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-09-08 14:28           ` Linus Walleij
  0 siblings, 0 replies; 86+ messages in thread
From: Linus Walleij @ 2015-09-08 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 8, 2015 at 10:04 AM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> On Tue, 14 Jul 2015, Linus Walleij wrote:
>
>> I want Shawn and Sascha to look at this as they worked with
>> other Freescale pin controllers. Especially I want to know if this
>> is a sibling to the other Freescale controllers or a separate hardware.
>>
>> If it is *not* a sibling I will *insist* that it use more generic pin
>> control bindings and move away from the older Freescale-specific
>> stuff.
>
> No one answered me about that. However, I looked at other Freescale
> pinctrl drivers and realised that no one of them (IMX, IMX1, MXS) is
> similar to what I need to do for Kinetis, also positions of configuration
> bits differ significantly.

OK I insist on using the generic bindings then.

>> There exist generic pin config bindings, see
>> Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
>>
>> I suggest to to function+group paring and then use generic pin config
>> with this driver unless it is a very close sibling to the existing Freescale
>> pin controllers.
>>
>> Hint: if it is a sibling, it should share code with them.
>>
>> There are several drivers doing generic pin control/pin config in the kernel
>> tree.
>
> I tried to analyze few of the drivers (e.g. zynq family) and can't find
> how can I assing clock gate (clock device) to each port (PORTA, PORTB,
> PORTC,...) which is required for Kinetis. Is generic pin control capable
> to express that requirement or is it a time to desing my own pinctrl
> driver (maybe somewhat improved than the one I presented so far)?

That has nothing to do with whether you use generic pinconf or not.
I imagine if a pinctrl unit contains several blocks with individual
clocks you can either:

- Let each block/bank be a device node (this is common) and assign
  each a clocks = <&clock>;

- Keep one node and assign an array of clocks, affected block indicated
  by the index.
  clocks = <&clk1>, <&clk2>, <&clk3>, ... <clkN>;
  This property is in pluralis for this reason I guess.

> This pinctrl component is somwehat critical part of BSP. Until it is not
> sorted, I don't see a point in releasing what was developed so far.

True that, you need infrastructure first. The more important that it is
as good as possible.

Yours,
Linus Walleij

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

end of thread, other threads:[~2015-09-08 14:29 UTC | newest]

Thread overview: 86+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-23 21:19 [PATCH 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 1/9] arm: select different compiler flags for ARM CortexM3 Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
2015-06-23 21:48   ` Russell King - ARM Linux
2015-06-23 21:48     ` Russell King - ARM Linux
2015-06-24  4:22     ` Paul Osmialowski
2015-06-24  4:22       ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
2015-06-24  7:10   ` Geert Uytterhoeven
2015-06-24  7:17     ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 3/9] arm: add call to CPU idle quirks handler Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:51   ` Russell King - ARM Linux
2015-06-23 21:51     ` Russell King - ARM Linux
2015-06-23 21:59   ` Arnd Bergmann
2015-06-23 21:59     ` Arnd Bergmann
2015-06-25 16:42     ` Nicolas Pitre
2015-06-25 16:42       ` Nicolas Pitre
     [not found]       ` <alpine.LFD.2.11.1506251237000.2617-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2015-06-26  5:30         ` Paul Osmialowski
2015-06-26  5:30           ` Paul Osmialowski
2015-06-26  7:40           ` Arnd Bergmann
2015-06-26  7:40             ` Arnd Bergmann
2015-06-26 21:52             ` Paul Osmialowski
2015-06-26 21:52               ` Paul Osmialowski
     [not found]               ` <alpine.LNX.2.00.1506262324230.5744-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2015-06-26 22:27                 ` Russell King - ARM Linux
2015-06-26 22:27                   ` Russell King - ARM Linux
2015-06-23 21:19 ` [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 5/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
2015-06-23 22:05   ` Arnd Bergmann
2015-06-23 22:05     ` Arnd Bergmann
2015-06-23 22:33     ` Russell King - ARM Linux
2015-06-23 22:33       ` Russell King - ARM Linux
2015-06-24  4:42     ` Paul Osmialowski
2015-06-24  4:42       ` Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
2015-06-23 22:24   ` Stephen Boyd
2015-06-23 22:24     ` Stephen Boyd
2015-06-24  5:09     ` Paul Osmialowski
2015-06-24  5:09       ` Paul Osmialowski
2015-06-23 22:24   ` Stephen Boyd
2015-06-23 22:25   ` Arnd Bergmann
2015-06-23 22:25     ` Arnd Bergmann
2015-06-24  7:53   ` Thomas Gleixner
2015-06-24  7:53     ` Thomas Gleixner
     [not found] ` <1435094387-20146-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
2015-06-23 21:19   ` [PATCH 1/9] arm: select different compiler flags for ARM CortexM3 Paul Osmialowski
2015-06-23 21:19   ` [PATCH 2/9] arm: do not place huge encoder tables on stack when it is too small Paul Osmialowski
2015-06-23 21:19   ` [PATCH 3/9] arm: add call to CPU idle quirks handler Paul Osmialowski
2015-06-23 21:19   ` [PATCH 4/9] arm: allow copying of vector table to internal SRAM memory Paul Osmialowski
2015-06-23 21:19   ` [PATCH 6/9] arm: twr-k70f120m: clock source drivers for Kinetis SoC Paul Osmialowski
2015-06-23 21:19   ` [PATCH 7/9] arm: twr-k70f120m: IOMUX driver " Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-24 10:21   ` Paul Bolle
2015-06-24 10:21     ` Paul Bolle
2015-06-24 10:21     ` Paul Bolle
2015-06-24 17:44     ` Paul Osmialowski
2015-06-24 17:44       ` Paul Osmialowski
     [not found]   ` <1435094387-20146-8-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
2015-06-24 10:21     ` Paul Bolle
2015-07-14  8:53     ` Linus Walleij
2015-07-14  8:53       ` Linus Walleij
2015-07-14  8:53       ` Linus Walleij
2015-07-14  8:53       ` Linus Walleij
2015-09-08  8:04       ` Paul Osmialowski
2015-09-08  8:04         ` Paul Osmialowski
2015-09-08  8:04         ` Paul Osmialowski
2015-09-08  8:04         ` Paul Osmialowski
2015-09-08 14:28         ` Linus Walleij
2015-09-08 14:28           ` Linus Walleij
2015-09-08 14:28           ` Linus Walleij
2015-09-08 14:28           ` Linus Walleij
2015-06-23 21:19 ` [PATCH 8/9] arm: twr-k70f120m: extend Freescale eDMA driver with ability to support " Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski
     [not found]   ` <1435094387-20146-9-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
2015-06-24 16:14     ` Vinod Koul
2015-06-24 16:14       ` Vinod Koul
2015-06-24 17:43       ` Paul Osmialowski
2015-06-24 17:43         ` Paul Osmialowski
2015-06-23 21:19 ` [PATCH 9/9] arm: twr-k70f120m: extend Freescale lpuart " Paul Osmialowski
2015-06-23 21:19 ` Paul Osmialowski
2015-06-23 21:19   ` Paul Osmialowski

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.