All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit
@ 2015-06-30 12:27 ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Nicolas Pitre, Sergei Poselenov, Paul Bolle, Paul Osmialowski,
	Arnd Bergmann, Jingchang Lu, Yuri Tikhonov, Rob Herring,
	Geert Uytterhoeven, Uwe Kleine-Koenig, Alexander Potashev,
	Frank Li, Thomas Gleixner, Anson Huang

This is the second iteration of the patchset that adds a basic initial
support to TWR-K70F120M development kit which is based on ARM Cortex-M4
Freescale Kinetis K70 SoC.

Previous iteration met with a broad response for which I would like
to thank everyone involved.

Following is the change list:

1. First three ('controversial') patches are removed.

   As long as it doesn't hit platform stability, I don't use these Cortex-M
   compiler flags, it should not stop the whole of the patchset.

   The idle quirks issue is now addressed by adding idle.c which provides
   callback for arm_pm_idle.

   The infamous zlib patch was not needed at all - I didn't really check
   what it was protecting against.

2. include/mach/idle.h file removed.

3. kinetis_platform.c renamed to kinetis.c, obj-$(CONFIG_MACH_KINETIS)
   changed to obj-y, CONFIG_MACH_KINETIS not needed anymore, removed with
   the whole of the Kconfig file in mach-kinetis directory.

4. Assuming that fsl-edma and fsl-lpuart drivers handle big-endian properly,
   pinctrl, clk and timer drivers now support big-endian the same way
   ("big-endian" option in .dts).

5. All addresses based on KINETIS_AIPS0PERIPH_BASE and
   KINETIS_AIPS1PERIPH_BASE are moved to DT. The struct kinetis_sim_regs
   is moved to clk-kinetis.c. As a result whole include/mach/kinetis.h is
   now removed.

6. Removed kinetis_map_io() from kinetis.c (formerly kinetis_platform.c).

7. Removed kinetis_init() function along with a call to
   of_platform_populate().

8. Removed MACH_KINETIS from arch/arm/tools/mach-types, removed inclusion
   of asm/mach-types.h in kinetis.c (formerly kinetis_platform.c).

9. Removed inclusion of linux/clk.h from clk-kinetis.c.

10. Clock and timer drivers are in separate patches now.

11. '&& ARM' removed from drivers/clocksource/Kconfig.

12. s/clk/evt/ in timer-kinetis.c (actually, the affected *_set_mode()
    function is replaced by a set of *_set_state_*() functions).

13. Removed pointless raw_local_irq_save/restore() from timer-kinetis.c.

14. Removed overhead () from each of the &(.....) from timer-kinetis.c.

15. Removed unused KINETIS_PITn_IRQ definitions from timer-kinetis.c.

16. Replaced use of IRQ actions with request_irq() in timer-kinetis.c.

17. Removed all uses of KINETIS_MKCG() macro and whole include/mach/power.h
    - now all clock gate details are specified directly in the DT.
    For each clock gate #clock-cells = <2> where the first part of the gate
    address is zero-based gate register number, the second part is the bit
    index.

18. Shortened long timer names in timer-kinetis.c.

19. Ensured module friendliness of pinctrl driver (tristate
    CONFIG_PINCTRL_KINETIS)

20. Removed txirq_names[] array from fsl-edma.c - sprinft()-generated
    strings used instead.

21. fsl-lpuart and fsl-edma related patches are both split into two:
    1) changes in the driver and 2) use in platform.

22. Removed all occurences of CONFIG_ARCH_KINETIS from fsl-edma.c - now it
    looks more like fsl-lpuart driver (boolean 'kinetis' field in the main
    driver structure).

Paul Osmialowski (9):
  arm: allow copying of vector table to internal SRAM memory
  arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  arm: twr-k70f120m: clock driver for Kinetis SoC
  arm: twr-k70f120m: timer driver for Kinetis SoC
  arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  arm: twr-k70f120m: extend Freescale eDMA driver with the ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  arm: twr-k70f120m: extend Freescale lpuart driver with ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 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       |  50 ++
 arch/arm/Kconfig                                   |  16 +-
 arch/arm/Kconfig-nommu                             |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |  43 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 241 +++++++++
 arch/arm/kernel/entry-v7m.S                        |   3 +
 arch/arm/mach-kinetis/Makefile                     |   5 +
 arch/arm/mach-kinetis/Makefile.boot                |   3 +
 arch/arm/mach-kinetis/idle.c                       |  27 +
 arch/arm/mach-kinetis/include/mach/memory.h        |  61 +++
 arch/arm/mach-kinetis/kinetis.c                    |  34 ++
 arch/arm/mm/Kconfig                                |   1 +
 arch/arm/mm/proc-v7m.S                             |  11 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 ++++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 ++++++++++++
 drivers/dma/fsl-edma.c                             | 114 ++++-
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 drivers/tty/serial/fsl_lpuart.c                    |  90 +++-
 29 files changed, 2153 insertions(+), 44 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/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/idle.c
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
 create mode 100644 arch/arm/mach-kinetis/kinetis.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

-- 
2.3.6

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

* [PATCH v2 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit
@ 2015-06-30 12:27 ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

This is the second iteration of the patchset that adds a basic initial
support to TWR-K70F120M development kit which is based on ARM Cortex-M4
Freescale Kinetis K70 SoC.

Previous iteration met with a broad response for which I would like
to thank everyone involved.

Following is the change list:

1. First three ('controversial') patches are removed.

   As long as it doesn't hit platform stability, I don't use these Cortex-M
   compiler flags, it should not stop the whole of the patchset.

   The idle quirks issue is now addressed by adding idle.c which provides
   callback for arm_pm_idle.

   The infamous zlib patch was not needed at all - I didn't really check
   what it was protecting against.

2. include/mach/idle.h file removed.

3. kinetis_platform.c renamed to kinetis.c, obj-$(CONFIG_MACH_KINETIS)
   changed to obj-y, CONFIG_MACH_KINETIS not needed anymore, removed with
   the whole of the Kconfig file in mach-kinetis directory.

4. Assuming that fsl-edma and fsl-lpuart drivers handle big-endian properly,
   pinctrl, clk and timer drivers now support big-endian the same way
   ("big-endian" option in .dts).

5. All addresses based on KINETIS_AIPS0PERIPH_BASE and
   KINETIS_AIPS1PERIPH_BASE are moved to DT. The struct kinetis_sim_regs
   is moved to clk-kinetis.c. As a result whole include/mach/kinetis.h is
   now removed.

6. Removed kinetis_map_io() from kinetis.c (formerly kinetis_platform.c).

7. Removed kinetis_init() function along with a call to
   of_platform_populate().

8. Removed MACH_KINETIS from arch/arm/tools/mach-types, removed inclusion
   of asm/mach-types.h in kinetis.c (formerly kinetis_platform.c).

9. Removed inclusion of linux/clk.h from clk-kinetis.c.

10. Clock and timer drivers are in separate patches now.

11. '&& ARM' removed from drivers/clocksource/Kconfig.

12. s/clk/evt/ in timer-kinetis.c (actually, the affected *_set_mode()
    function is replaced by a set of *_set_state_*() functions).

13. Removed pointless raw_local_irq_save/restore() from timer-kinetis.c.

14. Removed overhead () from each of the &(.....) from timer-kinetis.c.

15. Removed unused KINETIS_PITn_IRQ definitions from timer-kinetis.c.

16. Replaced use of IRQ actions with request_irq() in timer-kinetis.c.

17. Removed all uses of KINETIS_MKCG() macro and whole include/mach/power.h
    - now all clock gate details are specified directly in the DT.
    For each clock gate #clock-cells = <2> where the first part of the gate
    address is zero-based gate register number, the second part is the bit
    index.

18. Shortened long timer names in timer-kinetis.c.

19. Ensured module friendliness of pinctrl driver (tristate
    CONFIG_PINCTRL_KINETIS)

20. Removed txirq_names[] array from fsl-edma.c - sprinft()-generated
    strings used instead.

21. fsl-lpuart and fsl-edma related patches are both split into two:
    1) changes in the driver and 2) use in platform.

22. Removed all occurences of CONFIG_ARCH_KINETIS from fsl-edma.c - now it
    looks more like fsl-lpuart driver (boolean 'kinetis' field in the main
    driver structure).

Paul Osmialowski (9):
  arm: allow copying of vector table to internal SRAM memory
  arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  arm: twr-k70f120m: clock driver for Kinetis SoC
  arm: twr-k70f120m: timer driver for Kinetis SoC
  arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  arm: twr-k70f120m: extend Freescale eDMA driver with the ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  arm: twr-k70f120m: extend Freescale lpuart driver with ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 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       |  50 ++
 arch/arm/Kconfig                                   |  16 +-
 arch/arm/Kconfig-nommu                             |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |  43 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 241 +++++++++
 arch/arm/kernel/entry-v7m.S                        |   3 +
 arch/arm/mach-kinetis/Makefile                     |   5 +
 arch/arm/mach-kinetis/Makefile.boot                |   3 +
 arch/arm/mach-kinetis/idle.c                       |  27 +
 arch/arm/mach-kinetis/include/mach/memory.h        |  61 +++
 arch/arm/mach-kinetis/kinetis.c                    |  34 ++
 arch/arm/mm/Kconfig                                |   1 +
 arch/arm/mm/proc-v7m.S                             |  11 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 ++++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 ++++++++++++
 drivers/dma/fsl-edma.c                             | 114 ++++-
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 drivers/tty/serial/fsl_lpuart.c                    |  90 +++-
 29 files changed, 2153 insertions(+), 44 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/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/idle.c
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
 create mode 100644 arch/arm/mach-kinetis/kinetis.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

-- 
2.3.6


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

* [PATCH v2 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit
@ 2015-06-30 12:27 ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

This is the second iteration of the patchset that adds a basic initial
support to TWR-K70F120M development kit which is based on ARM Cortex-M4
Freescale Kinetis K70 SoC.

Previous iteration met with a broad response for which I would like
to thank everyone involved.

Following is the change list:

1. First three ('controversial') patches are removed.

   As long as it doesn't hit platform stability, I don't use these Cortex-M
   compiler flags, it should not stop the whole of the patchset.

   The idle quirks issue is now addressed by adding idle.c which provides
   callback for arm_pm_idle.

   The infamous zlib patch was not needed at all - I didn't really check
   what it was protecting against.

2. include/mach/idle.h file removed.

3. kinetis_platform.c renamed to kinetis.c, obj-$(CONFIG_MACH_KINETIS)
   changed to obj-y, CONFIG_MACH_KINETIS not needed anymore, removed with
   the whole of the Kconfig file in mach-kinetis directory.

4. Assuming that fsl-edma and fsl-lpuart drivers handle big-endian properly,
   pinctrl, clk and timer drivers now support big-endian the same way
   ("big-endian" option in .dts).

5. All addresses based on KINETIS_AIPS0PERIPH_BASE and
   KINETIS_AIPS1PERIPH_BASE are moved to DT. The struct kinetis_sim_regs
   is moved to clk-kinetis.c. As a result whole include/mach/kinetis.h is
   now removed.

6. Removed kinetis_map_io() from kinetis.c (formerly kinetis_platform.c).

7. Removed kinetis_init() function along with a call to
   of_platform_populate().

8. Removed MACH_KINETIS from arch/arm/tools/mach-types, removed inclusion
   of asm/mach-types.h in kinetis.c (formerly kinetis_platform.c).

9. Removed inclusion of linux/clk.h from clk-kinetis.c.

10. Clock and timer drivers are in separate patches now.

11. '&& ARM' removed from drivers/clocksource/Kconfig.

12. s/clk/evt/ in timer-kinetis.c (actually, the affected *_set_mode()
    function is replaced by a set of *_set_state_*() functions).

13. Removed pointless raw_local_irq_save/restore() from timer-kinetis.c.

14. Removed overhead () from each of the &(.....) from timer-kinetis.c.

15. Removed unused KINETIS_PITn_IRQ definitions from timer-kinetis.c.

16. Replaced use of IRQ actions with request_irq() in timer-kinetis.c.

17. Removed all uses of KINETIS_MKCG() macro and whole include/mach/power.h
    - now all clock gate details are specified directly in the DT.
    For each clock gate #clock-cells = <2> where the first part of the gate
    address is zero-based gate register number, the second part is the bit
    index.

18. Shortened long timer names in timer-kinetis.c.

19. Ensured module friendliness of pinctrl driver (tristate
    CONFIG_PINCTRL_KINETIS)

20. Removed txirq_names[] array from fsl-edma.c - sprinft()-generated
    strings used instead.

21. fsl-lpuart and fsl-edma related patches are both split into two:
    1) changes in the driver and 2) use in platform.

22. Removed all occurences of CONFIG_ARCH_KINETIS from fsl-edma.c - now it
    looks more like fsl-lpuart driver (boolean 'kinetis' field in the main
    driver structure).

Paul Osmialowski (9):
  arm: allow copying of vector table to internal SRAM memory
  arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  arm: twr-k70f120m: clock driver for Kinetis SoC
  arm: twr-k70f120m: timer driver for Kinetis SoC
  arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  arm: twr-k70f120m: extend Freescale eDMA driver with the ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  arm: twr-k70f120m: extend Freescale lpuart driver with ability to
    support Kinetis SoC
  arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 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       |  50 ++
 arch/arm/Kconfig                                   |  16 +-
 arch/arm/Kconfig-nommu                             |  12 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |  43 ++
 arch/arm/boot/dts/kinetis.dtsi                     | 241 +++++++++
 arch/arm/kernel/entry-v7m.S                        |   3 +
 arch/arm/mach-kinetis/Makefile                     |   5 +
 arch/arm/mach-kinetis/Makefile.boot                |   3 +
 arch/arm/mach-kinetis/idle.c                       |  27 +
 arch/arm/mach-kinetis/include/mach/memory.h        |  61 +++
 arch/arm/mach-kinetis/kinetis.c                    |  34 ++
 arch/arm/mm/Kconfig                                |   1 +
 arch/arm/mm/proc-v7m.S                             |  11 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 ++++++++++++++++++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 ++++++++++++
 drivers/dma/fsl-edma.c                             | 114 ++++-
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 drivers/tty/serial/fsl_lpuart.c                    |  90 +++-
 29 files changed, 2153 insertions(+), 44 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/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/idle.c
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
 create mode 100644 arch/arm/mach-kinetis/kinetis.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

-- 
2.3.6

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

* [PATCH v2 1/9] arm: allow copying of vector table to internal SRAM memory
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27     ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, 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 aed66d5..d081fcb 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,14 @@ 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 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] 140+ messages in thread

* [PATCH v2 1/9] arm: allow copying of vector table to internal SRAM memory
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, 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 aed66d5..d081fcb 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,14 @@ 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 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] 140+ messages in thread

* [PATCH v2 1/9] arm: allow copying of vector table to internal SRAM memory
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

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 aed66d5..d081fcb 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -62,3 +62,14 @@ 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 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] 140+ messages in thread

* [PATCH v2 2/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
  2015-06-30 12:27 ` Paul Osmialowski
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

This one was inspired by a serie of 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                              |  9 ++++++-
 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/Makefile                |  5 ++++
 arch/arm/mach-kinetis/Makefile.boot           |  3 +++
 arch/arm/mach-kinetis/idle.c                  | 27 +++++++++++++++++++++
 arch/arm/mach-kinetis/kinetis.c               | 34 +++++++++++++++++++++++++++
 arch/arm/mm/Kconfig                           |  1 +
 11 files changed, 107 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/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/idle.c
 create mode 100644 arch/arm/mach-kinetis/kinetis.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 a750c14..9c89bdc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -964,6 +964,13 @@ 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 ARMV7M_SYSTICK
+	help
+	  This enables support for the Freescale Kinetis MCUs
+
 config ARCH_LPC18XX
 	bool "NXP LPC18xx/LPC43xx"
 	depends on ARM_SINGLE_ARMV7M
@@ -1733,7 +1740,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 d081fcb..4b9aab3 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -65,6 +65,7 @@ config ARM_MPU
 
 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 07ab3d2..e71fc01 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -170,6 +170,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/Makefile b/arch/arm/mach-kinetis/Makefile
new file mode 100644
index 0000000..e759d9e
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Freescale Kinetis platform files
+#
+
+obj-y += kinetis.o idle.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/idle.c b/arch/arm/mach-kinetis/idle.c
new file mode 100644
index 0000000..79d2e1c
--- /dev/null
+++ b/arch/arm/mach-kinetis/idle.c
@@ -0,0 +1,27 @@
+/*
+ * 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);
diff --git a/arch/arm/mach-kinetis/kinetis.c b/arch/arm/mach-kinetis/kinetis.c
new file mode 100644
index 0000000..45e15c6
--- /dev/null
+++ b/arch/arm/mach-kinetis/kinetis.c
@@ -0,0 +1,34 @@
+/*
+ * kinetis.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/arch.h>
+
+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,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c6b976..121b580 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -609,6 +609,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
-- 
2.3.6

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

* [PATCH v2 2/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

This one was inspired by a serie of 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                              |  9 ++++++-
 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/Makefile                |  5 ++++
 arch/arm/mach-kinetis/Makefile.boot           |  3 +++
 arch/arm/mach-kinetis/idle.c                  | 27 +++++++++++++++++++++
 arch/arm/mach-kinetis/kinetis.c               | 34 +++++++++++++++++++++++++++
 arch/arm/mm/Kconfig                           |  1 +
 11 files changed, 107 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/Makefile
 create mode 100644 arch/arm/mach-kinetis/Makefile.boot
 create mode 100644 arch/arm/mach-kinetis/idle.c
 create mode 100644 arch/arm/mach-kinetis/kinetis.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 a750c14..9c89bdc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -964,6 +964,13 @@ 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 ARMV7M_SYSTICK
+	help
+	  This enables support for the Freescale Kinetis MCUs
+
 config ARCH_LPC18XX
 	bool "NXP LPC18xx/LPC43xx"
 	depends on ARM_SINGLE_ARMV7M
@@ -1733,7 +1740,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 d081fcb..4b9aab3 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -65,6 +65,7 @@ config ARM_MPU
 
 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 07ab3d2..e71fc01 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -170,6 +170,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/Makefile b/arch/arm/mach-kinetis/Makefile
new file mode 100644
index 0000000..e759d9e
--- /dev/null
+++ b/arch/arm/mach-kinetis/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Freescale Kinetis platform files
+#
+
+obj-y += kinetis.o idle.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/idle.c b/arch/arm/mach-kinetis/idle.c
new file mode 100644
index 0000000..79d2e1c
--- /dev/null
+++ b/arch/arm/mach-kinetis/idle.c
@@ -0,0 +1,27 @@
+/*
+ * 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);
diff --git a/arch/arm/mach-kinetis/kinetis.c b/arch/arm/mach-kinetis/kinetis.c
new file mode 100644
index 0000000..45e15c6
--- /dev/null
+++ b/arch/arm/mach-kinetis/kinetis.c
@@ -0,0 +1,34 @@
+/*
+ * kinetis.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/arch.h>
+
+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,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c6b976..121b580 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -609,6 +609,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
-- 
2.3.6

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Nicolas Pitre, Sergei Poselenov, Paul Bolle, Paul Osmialowski,
	Arnd Bergmann, Jingchang Lu, Yuri Tikhonov, Rob Herring,
	Geert Uytterhoeven, Uwe Kleine-Koenig, Alexander Potashev,
	Frank Li, Thomas Gleixner, Anson Huang

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
 4 files changed, 563 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..63af6a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,63 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Clock Genetator register set,
+	one for System Integration Module register set.
+- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
+
+For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-root@mcgout {
+		device_type = "mcgout";
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate@cclk {
+		device_type = "cclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_pclk: fixed-rate@pclk {
+		device_type = "pclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_cclk_gate: clock-gate@cclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_cclk>;
+	};
+
+	mcg_pclk_gate: clock-gate@pclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_pclk>;
+	};
+};
+
+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_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..ae0cf00 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,39 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-root@mcgout {
+				device_type = "mcgout";
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate@cclk {
+				device_type = "cclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_pclk: fixed-rate@pclk {
+				device_type = "pclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_cclk_gate: clock-gate@cclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_cclk>;
+			};
+
+			mcg_pclk_gate: clock-gate@pclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_pclk>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..611e2e9
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,463 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+#define KINETIS_SIM_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_SIM_PTR(base, reg)) \
+		      : ioread32(KINETIS_SIM_PTR(base, reg)))
+#define KINETIS_SIM_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_SIM_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_SIM_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_SIM_SET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) | (mask))
+#define KINETIS_SIM_RESET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) & (~(mask)))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return ERR_PTR(ret);
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	u32 clock_val;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct clk *clk;
+	const char *clk_parent_name;
+	struct kinetis_clk_gate_data *clk_gate;
+	struct device_node *child;
+	bool big_endian;
+	int ret;
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		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_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		clock_val = 0;
+		if (child->type) {
+			if (!of_node_cmp(child->type, "mcgout"))
+				clock_val = clock_val_mcgout;
+			else if (!of_node_cmp(child->type, "cclk"))
+				clock_val = clock_val_cclk;
+			else if (!of_node_cmp(child->type, "pclk"))
+				clock_val = clock_val_pclk;
+		}
+
+		if (!of_node_cmp(child->name, "fixed-rate-root")) {
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						NULL, CLK_IS_ROOT, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "fixed-rate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						clk_parent_name, 0, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "clock-gate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data),
+								    GFP_KERNEL);
+			if (!clk_gate)
+				continue;
+
+			clk_gate->clk_parent_name = clk_parent_name;
+			clk_gate->sim = sim;
+			INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+			ret = of_clk_add_provider(child, kinetis_clk_gate_get,
+							clk_gate);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else {
+			pr_err("Unknown clock name\n");
+			continue;
+		}
+	}
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
 4 files changed, 563 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..63af6a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,63 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Clock Genetator register set,
+	one for System Integration Module register set.
+- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
+
+For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-root@mcgout {
+		device_type = "mcgout";
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate@cclk {
+		device_type = "cclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_pclk: fixed-rate@pclk {
+		device_type = "pclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_cclk_gate: clock-gate@cclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_cclk>;
+	};
+
+	mcg_pclk_gate: clock-gate@pclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_pclk>;
+	};
+};
+
+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_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..ae0cf00 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,39 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-root@mcgout {
+				device_type = "mcgout";
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate@cclk {
+				device_type = "cclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_pclk: fixed-rate@pclk {
+				device_type = "pclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_cclk_gate: clock-gate@cclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_cclk>;
+			};
+
+			mcg_pclk_gate: clock-gate@pclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_pclk>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..611e2e9
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,463 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+#define KINETIS_SIM_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_SIM_PTR(base, reg)) \
+		      : ioread32(KINETIS_SIM_PTR(base, reg)))
+#define KINETIS_SIM_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_SIM_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_SIM_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_SIM_SET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) | (mask))
+#define KINETIS_SIM_RESET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) & (~(mask)))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return ERR_PTR(ret);
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	u32 clock_val;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct clk *clk;
+	const char *clk_parent_name;
+	struct kinetis_clk_gate_data *clk_gate;
+	struct device_node *child;
+	bool big_endian;
+	int ret;
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		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_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		clock_val = 0;
+		if (child->type) {
+			if (!of_node_cmp(child->type, "mcgout"))
+				clock_val = clock_val_mcgout;
+			else if (!of_node_cmp(child->type, "cclk"))
+				clock_val = clock_val_cclk;
+			else if (!of_node_cmp(child->type, "pclk"))
+				clock_val = clock_val_pclk;
+		}
+
+		if (!of_node_cmp(child->name, "fixed-rate-root")) {
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						NULL, CLK_IS_ROOT, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "fixed-rate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						clk_parent_name, 0, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "clock-gate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data),
+								    GFP_KERNEL);
+			if (!clk_gate)
+				continue;
+
+			clk_gate->clk_parent_name = clk_parent_name;
+			clk_gate->sim = sim;
+			INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+			ret = of_clk_add_provider(child, kinetis_clk_gate_get,
+							clk_gate);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else {
+			pr_err("Unknown clock name\n");
+			continue;
+		}
+	}
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
 4 files changed, 563 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..63af6a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,63 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Clock Genetator register set,
+	one for System Integration Module register set.
+- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
+
+For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu at 40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-root at mcgout {
+		device_type = "mcgout";
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate at cclk {
+		device_type = "cclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_pclk: fixed-rate at pclk {
+		device_type = "pclk";
+		#clock-cells = <0>;
+		clocks = <&mcg_outclk>;
+	};
+
+	mcg_cclk_gate: clock-gate at cclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_cclk>;
+	};
+
+	mcg_pclk_gate: clock-gate at pclk {
+		#clock-cells = <2>;
+		clocks = <&mcg_pclk>;
+	};
+};
+
+mcg: cmu at 40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>;
+	#clock-cells = <1>;
+};
+
+uart1: serial at 4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..ae0cf00 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,39 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu at 40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-root at mcgout {
+				device_type = "mcgout";
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate at cclk {
+				device_type = "cclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_pclk: fixed-rate at pclk {
+				device_type = "pclk";
+				#clock-cells = <0>;
+				clocks = <&mcg_outclk>;
+			};
+
+			mcg_cclk_gate: clock-gate at cclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_cclk>;
+			};
+
+			mcg_pclk_gate: clock-gate at pclk {
+				#clock-cells = <2>;
+				clocks = <&mcg_pclk>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..611e2e9
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,463 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+#define KINETIS_SIM_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_SIM_PTR(base, reg)) \
+		      : ioread32(KINETIS_SIM_PTR(base, reg)))
+#define KINETIS_SIM_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_SIM_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_SIM_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_SIM_SET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) | (mask))
+#define KINETIS_SIM_RESET(be, base, reg, mask) \
+		KINETIS_SIM_WR(be, base, reg, \
+			KINETIS_SIM_RD(be, base, reg) & (~(mask)))
+
+/*
+ * 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)
+
+/*
+ * 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 at 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return ERR_PTR(ret);
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	u32 clock_val;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct clk *clk;
+	const char *clk_parent_name;
+	struct kinetis_clk_gate_data *clk_gate;
+	struct device_node *child;
+	bool big_endian;
+	int ret;
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		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_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((KINETIS_SIM_RD(big_endian, sim, clkdiv1) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		clock_val = 0;
+		if (child->type) {
+			if (!of_node_cmp(child->type, "mcgout"))
+				clock_val = clock_val_mcgout;
+			else if (!of_node_cmp(child->type, "cclk"))
+				clock_val = clock_val_cclk;
+			else if (!of_node_cmp(child->type, "pclk"))
+				clock_val = clock_val_pclk;
+		}
+
+		if (!of_node_cmp(child->name, "fixed-rate-root")) {
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						NULL, CLK_IS_ROOT, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "fixed-rate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk = clk_register_fixed_rate(NULL, child->full_name,
+						clk_parent_name, 0, clock_val);
+			if (IS_ERR(clk)) {
+				pr_err("Could not register clock %s\n",
+							child->full_name);
+				continue;
+			}
+
+			ret = of_clk_add_provider(child, of_clk_src_simple_get,
+							clk);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else if (!of_node_cmp(child->name, "clock-gate")) {
+			clk_parent_name = kinetis_of_clk_get_name(child);
+			if (IS_ERR(clk_parent_name)) {
+				pr_err("Could not get parent clk name for %s\n",
+							child->full_name);
+			}
+
+			clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data),
+								    GFP_KERNEL);
+			if (!clk_gate)
+				continue;
+
+			clk_gate->clk_parent_name = clk_parent_name;
+			clk_gate->sim = sim;
+			INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+			ret = of_clk_add_provider(child, kinetis_clk_gate_get,
+							clk_gate);
+			if (ret < 0) {
+				pr_err("Could not add clock provider %s\n",
+							child->full_name);
+				continue;
+			}
+		} else {
+			pr_err("Unknown clock name\n");
+			continue;
+		}
+	}
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6

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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27     ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

Based on legacy pre-OF code by Alexander Potashev <aspotashev-qv+LCo8X3VpBDgjK7y7TUQ@public.gmane.org>

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  50 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  40 +++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 +++++++++++++++++++++
 7 files changed, 422 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 drivers/clocksource/timer-kinetis.c

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..4017230
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,50 @@
+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 set for the
+  Periodic Interrupt Timer.
+- clocks: The clock provided by the SoC to drive the timer.
+- Set of timer devices: following properties are required for each:
+	- reg: Specifies base physical address and size of the register set
+		for given timer device.
+	- interrupts: Should be the clock event device interrupt.
+
+Example:
+
+aliases {
+	pit0 = &pit0;
+	pit1 = &pit1;
+	pit2 = &pit2;
+	pit3 = &pit3;
+};
+
+pit@40037000 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037000 0x100>;
+	clocks = <&mcg_pclk_gate 5 23>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	pit0: timer@40037100 {
+		reg = <0x40037100 0x10>;
+		interrupts = <68>;
+	};
+
+	pit1: timer@40037110 {
+		reg = <0x40037110 0x10>;
+		interrupts = <69>;
+	};
+
+	pit2: timer@40037120 {
+		reg = <0x40037120 0x10>;
+		interrupts = <70>;
+	};
+
+	pit3: timer@40037130 {
+		reg = <0x40037130 0x10>;
+		interrupts = <71>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c89bdc..96ddaae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,7 @@ config ARCH_KINETIS
 	bool "Freescale Kinetis MCU"
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	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 ae0cf00..0c572a5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -5,7 +5,47 @@
 #include "armv7-m.dtsi"
 
 / {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
 	soc {
+		pit@40037000 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037000 0x100>;
+			clocks = <&mcg_pclk_gate 5 23>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			pit0: timer@40037100 {
+				reg = <0x40037100 0x10>;
+				interrupts = <68>;
+				status = "disabled";
+			};
+
+			pit1: timer@40037110 {
+				reg = <0x40037110 0x10>;
+				interrupts = <69>;
+				status = "disabled";
+			};
+
+			pit2: timer@40037120 {
+				reg = <0x40037120 0x10>;
+				interrupts = <70>;
+				status = "disabled";
+			};
+
+			pit3: timer@40037130 {
+				reg = <0x40037130 0x10>;
+				interrupts = <71>;
+				status = "disabled";
+			};
+		};
+
 		cmu@40064000 {
 			compatible = "fsl,kinetis-cmu";
 			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 4e57730..a12e5af 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 && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f228354..5807429 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..a2a8880
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,321 @@
+/*
+ * 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>
+
+#define KINETIS_PIT_CHANNELS 4
+
+/*
+ * 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)
+
+struct kinetis_pit_mcr_regs {
+	u32 mcr;
+};
+
+#define KINETIS_PITMCR_PTR(base, reg) \
+	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
+#define KINETIS_PITMCR_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
+		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
+#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
+	} while (0)
+
+/*
+ * 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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PIT_PTR(base, reg)))
+#define KINETIS_PIT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PIT_SET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) | (mask))
+#define KINETIS_PIT_RESET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+	void __iomem *mcr;
+	bool big_endian;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(struct kinetis_clock_event_ddata *tmr,
+							    int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(struct kinetis_clock_event_ddata *tmr, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	KINETIS_PITMCR_WR(tmr->big_endian, tmr->mcr, mcr, 0);
+
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tflg,
+					KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, ldval, ticks);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, cval, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+static int kinetis_clockevent_tmr_set_state_periodic(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static int kinetis_clockevent_tmr_set_state_oneshot(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 0);
+
+	return 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);
+
+	kinetis_pit_init(pit, delta);
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+			.set_state_periodic =
+				kinetis_clockevent_tmr_set_state_periodic,
+			.set_state_oneshot =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_oneshot_stopped =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_shutdown =
+				kinetis_clockevent_tmr_set_state_oneshot,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent3",
+		},
+	},
+};
+
+/*
+ * 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->big_endian, tmr->base, tflg,
+				KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&tmr->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct device_node *child;
+	struct clk *clk;
+	void __iomem *base;
+	void __iomem *mcr;
+	unsigned long rate;
+	int irq, chan;
+	bool big_endian;
+
+	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;
+	}
+
+	mcr = of_iomap(np, 0);
+	if (!mcr) {
+		pr_err("failed to get mcr for clockevent\n");
+		goto err_iomap_mcr;
+	}
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		chan = of_alias_get_id(child, "pit");
+		if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+			pr_err("failed to calculate channel number for pit\n");
+			continue;
+		}
+
+		base = of_iomap(child, 0);
+		if (!base) {
+			pr_err("failed to get registers for pit%d\n", chan);
+			continue;
+		}
+
+		irq = irq_of_parse_and_map(child, 0);
+		if (irq <= 0) {
+			pr_err("failed to get irq for pit%d\n", chan);
+			iounmap(base);
+			continue;
+		}
+
+		kinetis_clockevent_tmrs[chan].big_endian = big_endian;
+		kinetis_clockevent_tmrs[chan].base = base;
+		kinetis_clockevent_tmrs[chan].mcr = mcr;
+
+		/*
+		 * 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(&kinetis_clockevent_tmrs[chan],
+						(rate / HZ) - 1);
+		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
+
+		if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
+					IRQF_TIMER | IRQF_IRQPOLL,
+					"kinetis-timer",
+					&kinetis_clockevent_tmrs[chan])) {
+			pr_err("failed to request irq for pit%d\n", chan);
+			kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 0);
+			continue;
+		}
+
+		pr_info("prepared pit%d at MMIO %#x\n", chan, (unsigned)base);
+	}
+
+	return;
+
+err_iomap_mcr:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
-- 
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] 140+ messages in thread

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  50 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  40 +++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 +++++++++++++++++++++
 7 files changed, 422 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 drivers/clocksource/timer-kinetis.c

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..4017230
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,50 @@
+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 set for the
+  Periodic Interrupt Timer.
+- clocks: The clock provided by the SoC to drive the timer.
+- Set of timer devices: following properties are required for each:
+	- reg: Specifies base physical address and size of the register set
+		for given timer device.
+	- interrupts: Should be the clock event device interrupt.
+
+Example:
+
+aliases {
+	pit0 = &pit0;
+	pit1 = &pit1;
+	pit2 = &pit2;
+	pit3 = &pit3;
+};
+
+pit@40037000 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037000 0x100>;
+	clocks = <&mcg_pclk_gate 5 23>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	pit0: timer@40037100 {
+		reg = <0x40037100 0x10>;
+		interrupts = <68>;
+	};
+
+	pit1: timer@40037110 {
+		reg = <0x40037110 0x10>;
+		interrupts = <69>;
+	};
+
+	pit2: timer@40037120 {
+		reg = <0x40037120 0x10>;
+		interrupts = <70>;
+	};
+
+	pit3: timer@40037130 {
+		reg = <0x40037130 0x10>;
+		interrupts = <71>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c89bdc..96ddaae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,7 @@ config ARCH_KINETIS
 	bool "Freescale Kinetis MCU"
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	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 ae0cf00..0c572a5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -5,7 +5,47 @@
 #include "armv7-m.dtsi"
 
 / {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
 	soc {
+		pit@40037000 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037000 0x100>;
+			clocks = <&mcg_pclk_gate 5 23>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			pit0: timer@40037100 {
+				reg = <0x40037100 0x10>;
+				interrupts = <68>;
+				status = "disabled";
+			};
+
+			pit1: timer@40037110 {
+				reg = <0x40037110 0x10>;
+				interrupts = <69>;
+				status = "disabled";
+			};
+
+			pit2: timer@40037120 {
+				reg = <0x40037120 0x10>;
+				interrupts = <70>;
+				status = "disabled";
+			};
+
+			pit3: timer@40037130 {
+				reg = <0x40037130 0x10>;
+				interrupts = <71>;
+				status = "disabled";
+			};
+		};
+
 		cmu@40064000 {
 			compatible = "fsl,kinetis-cmu";
 			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 4e57730..a12e5af 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 && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f228354..5807429 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..a2a8880
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,321 @@
+/*
+ * 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>
+
+#define KINETIS_PIT_CHANNELS 4
+
+/*
+ * 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)
+
+struct kinetis_pit_mcr_regs {
+	u32 mcr;
+};
+
+#define KINETIS_PITMCR_PTR(base, reg) \
+	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
+#define KINETIS_PITMCR_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
+		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
+#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
+	} while (0)
+
+/*
+ * 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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PIT_PTR(base, reg)))
+#define KINETIS_PIT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PIT_SET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) | (mask))
+#define KINETIS_PIT_RESET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+	void __iomem *mcr;
+	bool big_endian;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(struct kinetis_clock_event_ddata *tmr,
+							    int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(struct kinetis_clock_event_ddata *tmr, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	KINETIS_PITMCR_WR(tmr->big_endian, tmr->mcr, mcr, 0);
+
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tflg,
+					KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, ldval, ticks);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, cval, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+static int kinetis_clockevent_tmr_set_state_periodic(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static int kinetis_clockevent_tmr_set_state_oneshot(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 0);
+
+	return 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);
+
+	kinetis_pit_init(pit, delta);
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+			.set_state_periodic =
+				kinetis_clockevent_tmr_set_state_periodic,
+			.set_state_oneshot =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_oneshot_stopped =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_shutdown =
+				kinetis_clockevent_tmr_set_state_oneshot,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent3",
+		},
+	},
+};
+
+/*
+ * 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->big_endian, tmr->base, tflg,
+				KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&tmr->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct device_node *child;
+	struct clk *clk;
+	void __iomem *base;
+	void __iomem *mcr;
+	unsigned long rate;
+	int irq, chan;
+	bool big_endian;
+
+	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;
+	}
+
+	mcr = of_iomap(np, 0);
+	if (!mcr) {
+		pr_err("failed to get mcr for clockevent\n");
+		goto err_iomap_mcr;
+	}
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		chan = of_alias_get_id(child, "pit");
+		if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+			pr_err("failed to calculate channel number for pit\n");
+			continue;
+		}
+
+		base = of_iomap(child, 0);
+		if (!base) {
+			pr_err("failed to get registers for pit%d\n", chan);
+			continue;
+		}
+
+		irq = irq_of_parse_and_map(child, 0);
+		if (irq <= 0) {
+			pr_err("failed to get irq for pit%d\n", chan);
+			iounmap(base);
+			continue;
+		}
+
+		kinetis_clockevent_tmrs[chan].big_endian = big_endian;
+		kinetis_clockevent_tmrs[chan].base = base;
+		kinetis_clockevent_tmrs[chan].mcr = mcr;
+
+		/*
+		 * 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(&kinetis_clockevent_tmrs[chan],
+						(rate / HZ) - 1);
+		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
+
+		if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
+					IRQF_TIMER | IRQF_IRQPOLL,
+					"kinetis-timer",
+					&kinetis_clockevent_tmrs[chan])) {
+			pr_err("failed to request irq for pit%d\n", chan);
+			kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 0);
+			continue;
+		}
+
+		pr_info("prepared pit%d at MMIO %#x\n", chan, (unsigned)base);
+	}
+
+	return;
+
+err_iomap_mcr:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
-- 
2.3.6


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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  50 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  40 +++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 321 +++++++++++++++++++++
 7 files changed, 422 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 drivers/clocksource/timer-kinetis.c

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..4017230
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,50 @@
+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 set for the
+  Periodic Interrupt Timer.
+- clocks: The clock provided by the SoC to drive the timer.
+- Set of timer devices: following properties are required for each:
+	- reg: Specifies base physical address and size of the register set
+		for given timer device.
+	- interrupts: Should be the clock event device interrupt.
+
+Example:
+
+aliases {
+	pit0 = &pit0;
+	pit1 = &pit1;
+	pit2 = &pit2;
+	pit3 = &pit3;
+};
+
+pit at 40037000 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037000 0x100>;
+	clocks = <&mcg_pclk_gate 5 23>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	pit0: timer at 40037100 {
+		reg = <0x40037100 0x10>;
+		interrupts = <68>;
+	};
+
+	pit1: timer at 40037110 {
+		reg = <0x40037110 0x10>;
+		interrupts = <69>;
+	};
+
+	pit2: timer at 40037120 {
+		reg = <0x40037120 0x10>;
+		interrupts = <70>;
+	};
+
+	pit3: timer at 40037130 {
+		reg = <0x40037130 0x10>;
+		interrupts = <71>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c89bdc..96ddaae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,7 @@ config ARCH_KINETIS
 	bool "Freescale Kinetis MCU"
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	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 ae0cf00..0c572a5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -5,7 +5,47 @@
 #include "armv7-m.dtsi"
 
 / {
+	aliases {
+		pit0 = &pit0;
+		pit1 = &pit1;
+		pit2 = &pit2;
+		pit3 = &pit3;
+	};
+
 	soc {
+		pit at 40037000 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037000 0x100>;
+			clocks = <&mcg_pclk_gate 5 23>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			pit0: timer at 40037100 {
+				reg = <0x40037100 0x10>;
+				interrupts = <68>;
+				status = "disabled";
+			};
+
+			pit1: timer at 40037110 {
+				reg = <0x40037110 0x10>;
+				interrupts = <69>;
+				status = "disabled";
+			};
+
+			pit2: timer at 40037120 {
+				reg = <0x40037120 0x10>;
+				interrupts = <70>;
+				status = "disabled";
+			};
+
+			pit3: timer at 40037130 {
+				reg = <0x40037130 0x10>;
+				interrupts = <71>;
+				status = "disabled";
+			};
+		};
+
 		cmu at 40064000 {
 			compatible = "fsl,kinetis-cmu";
 			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 4e57730..a12e5af 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 && ARCH_KINETIS
+	select CLKSRC_OF
+
 config CLKSRC_LPC32XX
 	bool
 	select CLKSRC_MMIO
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f228354..5807429 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..a2a8880
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,321 @@
+/*
+ * 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>
+
+#define KINETIS_PIT_CHANNELS 4
+
+/*
+ * 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)
+
+struct kinetis_pit_mcr_regs {
+	u32 mcr;
+};
+
+#define KINETIS_PITMCR_PTR(base, reg) \
+	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
+#define KINETIS_PITMCR_RD(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
+		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
+#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
+	} while (0)
+
+/*
+ * 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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PIT_PTR(base, reg)))
+#define KINETIS_PIT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PIT_SET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) | (mask))
+#define KINETIS_PIT_RESET(be, base, reg, mask) \
+		KINETIS_PIT_WR(be, base, reg, \
+			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+	void __iomem *mcr;
+	bool big_endian;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(struct kinetis_clock_event_ddata *tmr,
+							    int enable)
+{
+	if (enable)
+		KINETIS_PIT_SET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+	else
+		KINETIS_PIT_RESET(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TEN_MSK);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(struct kinetis_clock_event_ddata *tmr, u32 ticks)
+{
+	/*
+	 * Enable the PIT module clock
+	 */
+	KINETIS_PITMCR_WR(tmr->big_endian, tmr->mcr, mcr, 0);
+
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tflg,
+					KINETIS_PIT_TFLG_TIF_MSK);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, ldval, ticks);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, cval, 0);
+	KINETIS_PIT_WR(tmr->big_endian, tmr->base, tctrl,
+					KINETIS_PIT_TCTRL_TIE_MSK);
+}
+
+static int kinetis_clockevent_tmr_set_state_periodic(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static int kinetis_clockevent_tmr_set_state_oneshot(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 0);
+
+	return 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);
+
+	kinetis_pit_init(pit, delta);
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static struct kinetis_clock_event_ddata
+		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent0",
+			.rating		= 200,
+			.features	=
+			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
+			.set_state_periodic =
+				kinetis_clockevent_tmr_set_state_periodic,
+			.set_state_oneshot =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_oneshot_stopped =
+				kinetis_clockevent_tmr_set_state_oneshot,
+			.set_state_shutdown =
+				kinetis_clockevent_tmr_set_state_oneshot,
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent1",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent2",
+		},
+	},
+	{
+		.evtdev = {
+			.name		= "kinetis-clockevent3",
+		},
+	},
+};
+
+/*
+ * 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->big_endian, tmr->base, tflg,
+				KINETIS_PIT_TFLG_TIF_MSK);
+
+	tmr->evtdev.event_handler(&tmr->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct device_node *child;
+	struct clk *clk;
+	void __iomem *base;
+	void __iomem *mcr;
+	unsigned long rate;
+	int irq, chan;
+	bool big_endian;
+
+	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;
+	}
+
+	mcr = of_iomap(np, 0);
+	if (!mcr) {
+		pr_err("failed to get mcr for clockevent\n");
+		goto err_iomap_mcr;
+	}
+
+	big_endian = of_property_read_bool(np, "big-endian");
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		chan = of_alias_get_id(child, "pit");
+		if ((chan < 0) || (chan >= KINETIS_PIT_CHANNELS)) {
+			pr_err("failed to calculate channel number for pit\n");
+			continue;
+		}
+
+		base = of_iomap(child, 0);
+		if (!base) {
+			pr_err("failed to get registers for pit%d\n", chan);
+			continue;
+		}
+
+		irq = irq_of_parse_and_map(child, 0);
+		if (irq <= 0) {
+			pr_err("failed to get irq for pit%d\n", chan);
+			iounmap(base);
+			continue;
+		}
+
+		kinetis_clockevent_tmrs[chan].big_endian = big_endian;
+		kinetis_clockevent_tmrs[chan].base = base;
+		kinetis_clockevent_tmrs[chan].mcr = mcr;
+
+		/*
+		 * 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(&kinetis_clockevent_tmrs[chan],
+						(rate / HZ) - 1);
+		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
+
+		if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
+					IRQF_TIMER | IRQF_IRQPOLL,
+					"kinetis-timer",
+					&kinetis_clockevent_tmrs[chan])) {
+			pr_err("failed to request irq for pit%d\n", chan);
+			kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 0);
+			continue;
+		}
+
+		pr_info("prepared pit%d@MMIO %#x\n", chan, (unsigned)base);
+	}
+
+	return;
+
+err_iomap_mcr:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
-- 
2.3.6

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

* [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Nicolas Pitre, Sergei Poselenov, Paul Bolle, Paul Osmialowski,
	Arnd Bergmann, Jingchang Lu, Yuri Tikhonov, Rob Herring,
	Geert Uytterhoeven, Uwe Kleine-Koenig, Alexander Potashev,
	Frank Li, Thomas Gleixner, Anson Huang

This is a 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                                   |   2 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 6 files changed, 631 insertions(+)
 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..a351ce4
--- /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_pclk_gate 4 13>;
+	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 96ddaae..b21592b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -969,6 +969,8 @@ config ARCH_KINETIS
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
+	select PINCTRL_KINETIS
 	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 0c572a5..5ff1d3b 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -10,9 +10,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_pclk_gate 4 9>;
+			status = "disabled";
+		};
+
+		portB: pinmux@4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 10>;
+			status = "disabled";
+		};
+
+		portC: pinmux@4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 11>;
+			status = "disabled";
+		};
+
+		portD: pinmux@4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 12>;
+			status = "disabled";
+		};
+
+		portE: pinmux@4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 13>;
+			status = "disabled";
+		};
+
+		portF: pinmux@4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 14>;
+			status = "disabled";
+		};
+
 		pit@40037000 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037000 0x100>;
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..c547aa9 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
+	tristate "Kinetis pinctrl driver"
+	depends on OF
+	depends on ARCH_KINETIS
+	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..4f0f36f
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,541 @@
+/*
+ * 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;
+	bool				big_endian;
+};
+
+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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PORT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PORT_PTR(base, reg)))
+#define KINETIS_PORT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PORT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PORT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PORT_SET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, base, reg) | (mask))
+#define KINETIS_PORT_RESET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, 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->big_endian, 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;
+
+	kpctl->big_endian = of_property_read_bool(np, "big-endian");
+
+	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);
+}
+module_init(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");
-- 
2.3.6

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

* [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

This is a 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                                   |   2 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 6 files changed, 631 insertions(+)
 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..a351ce4
--- /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_pclk_gate 4 13>;
+	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 96ddaae..b21592b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -969,6 +969,8 @@ config ARCH_KINETIS
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
+	select PINCTRL_KINETIS
 	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 0c572a5..5ff1d3b 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -10,9 +10,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_pclk_gate 4 9>;
+			status = "disabled";
+		};
+
+		portB: pinmux@4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 10>;
+			status = "disabled";
+		};
+
+		portC: pinmux@4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 11>;
+			status = "disabled";
+		};
+
+		portD: pinmux@4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 12>;
+			status = "disabled";
+		};
+
+		portE: pinmux@4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 13>;
+			status = "disabled";
+		};
+
+		portF: pinmux@4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 14>;
+			status = "disabled";
+		};
+
 		pit@40037000 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037000 0x100>;
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..c547aa9 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
+	tristate "Kinetis pinctrl driver"
+	depends on OF
+	depends on ARCH_KINETIS
+	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..4f0f36f
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,541 @@
+/*
+ * 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;
+	bool				big_endian;
+};
+
+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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PORT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PORT_PTR(base, reg)))
+#define KINETIS_PORT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PORT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PORT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PORT_SET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, base, reg) | (mask))
+#define KINETIS_PORT_RESET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, 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->big_endian, 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;
+
+	kpctl->big_endian = of_property_read_bool(np, "big-endian");
+
+	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);
+}
+module_init(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");
-- 
2.3.6


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

* [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

This is a 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                                   |   2 +
 arch/arm/boot/dts/kinetis.dtsi                     |  48 ++
 drivers/pinctrl/freescale/Kconfig                  |   8 +
 drivers/pinctrl/freescale/Makefile                 |   1 +
 drivers/pinctrl/freescale/pinctrl-kinetis.c        | 541 +++++++++++++++++++++
 6 files changed, 631 insertions(+)
 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..a351ce4
--- /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 at 4004d000 {
+	compatible = "fsl,kinetis-padconf";
+	reg = <0x4004d000 0x1000>;
+	clocks = <&mcg_pclk_gate 4 13>;
+	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 96ddaae..b21592b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -969,6 +969,8 @@ config ARCH_KINETIS
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
 	select CLKSRC_KINETIS
+	select PINCTRL
+	select PINCTRL_KINETIS
 	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 0c572a5..5ff1d3b 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -10,9 +10,57 @@
 		pit1 = &pit1;
 		pit2 = &pit2;
 		pit3 = &pit3;
+		pmx0 = &portA;
+		pmx1 = &portB;
+		pmx2 = &portC;
+		pmx3 = &portD;
+		pmx4 = &portE;
+		pmx5 = &portF;
 	};
 
 	soc {
+		portA: pinmux at 40049000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x40049000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 9>;
+			status = "disabled";
+		};
+
+		portB: pinmux at 4004a000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004a000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 10>;
+			status = "disabled";
+		};
+
+		portC: pinmux at 4004b000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004b000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 11>;
+			status = "disabled";
+		};
+
+		portD: pinmux at 4004c000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004c000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 12>;
+			status = "disabled";
+		};
+
+		portE: pinmux at 4004d000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004d000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 13>;
+			status = "disabled";
+		};
+
+		portF: pinmux at 4004e000 {
+			compatible = "fsl,kinetis-padconf";
+			reg = <0x4004e000 0x1000>;
+			clocks = <&mcg_pclk_gate 4 14>;
+			status = "disabled";
+		};
+
 		pit at 40037000 {
 			compatible = "fsl,kinetis-pit-timer";
 			reg = <0x40037000 0x100>;
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 12ef544..c547aa9 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
+	tristate "Kinetis pinctrl driver"
+	depends on OF
+	depends on ARCH_KINETIS
+	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..4f0f36f
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-kinetis.c
@@ -0,0 +1,541 @@
+/*
+ * 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;
+	bool				big_endian;
+};
+
+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(be, base, reg) \
+		((be) ? ioread32be(KINETIS_PORT_PTR(base, reg)) \
+		      : ioread32(KINETIS_PORT_PTR(base, reg)))
+#define KINETIS_PORT_WR(be, base, reg, val) do { \
+		if (be) \
+			iowrite32be((val), KINETIS_PORT_PTR(base, reg)); \
+		else \
+			iowrite32((val), KINETIS_PORT_PTR(base, reg)); \
+	} while (0)
+#define KINETIS_PORT_SET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, base, reg) | (mask))
+#define KINETIS_PORT_RESET(be, base, reg, mask) \
+		KINETIS_PORT_WR(be, base, reg, \
+			KINETIS_PORT_RD(be, 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->big_endian, 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;
+
+	kpctl->big_endian = of_property_read_bool(np, "big-endian");
+
+	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);
+}
+module_init(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");
-- 
2.3.6

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

* [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Nicolas Pitre, Sergei Poselenov, Paul Bolle, Paul Osmialowski,
	Arnd Bergmann, Jingchang Lu, Yuri Tikhonov, Rob Herring,
	Geert Uytterhoeven, Uwe Kleine-Koenig, Alexander Potashev,
	Frank Li, Thomas Gleixner, Anson Huang

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

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt |  38 ++++++-
 drivers/dma/fsl-edma.c                             | 114 ++++++++++++++++-----
 2 files changed, 125 insertions(+), 27 deletions(-)

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..88c3e20 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_cclk_gate 6 1>,
+		 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..e41a3b9 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -164,13 +164,13 @@ struct fsl_edma_desc {
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+	struct clk		*clk;
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
-	int			txirq;
-	int			errirq;
 	bool			big_endian;
+	bool			kinetis;
 	struct fsl_edma_chan	chans[];
 };
 
@@ -788,42 +788,85 @@ 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)
 {
+	struct device_node *np = pdev->dev.of_node;
+	int irq, errirq;
 	int ret;
 
-	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;
-	}
-
-	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
-	if (fsl_edma->errirq < 0) {
+	errirq = platform_get_irq_byname(pdev, "edma-err");
+	if (errirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
-		return fsl_edma->errirq;
+		return irq;
 	}
 
-	if (fsl_edma->txirq == fsl_edma->errirq) {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
-				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
-			 return  ret;
+	if (fsl_edma->kinetis) {
+		int i;
+		int irqs = of_irq_count(np);
+
+		if (irqs <= 1) {
+			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
+			return -EINVAL;
 		}
-	} else {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+
+		for (i = 0; i < (irqs - 1); i++) {
+			char irq_name[32];
+
+			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
+			irq = platform_get_irq_byname(pdev, irq_name);
+			if (irq < 0) {
+				dev_err(&pdev->dev, "Can't get %s irq.\n",
+							irq_name);
+				return irq;
+			}
+
+			ret = devm_request_irq(&pdev->dev, irq,
 				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
-			return  ret;
+			if (ret) {
+				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
+							irq_name);
+				return  ret;
+			}
 		}
 
-		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
-				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+		ret = devm_request_irq(&pdev->dev, errirq,
+			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
 		if (ret) {
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
-			return  ret;
+		return  ret;
+		}
+	} else {
+		irq = platform_get_irq_byname(pdev, "edma-tx");
+		if (irq < 0) {
+			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
+			return irq;
+		}
+
+		if (irq == errirq) {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+						"Can't register eDMA IRQ.\n");
+				return  ret;
+			}
+		} else {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA tx IRQ.\n");
+				return  ret;
+			}
+
+			ret = devm_request_irq(&pdev->dev, errirq,
+				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA err IRQ.\n");
+				return  ret;
+			}
 		}
 	}
 
@@ -851,6 +894,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	fsl_edma->n_chans = chans;
+	fsl_edma->kinetis = of_device_is_compatible(np, "fsl,kinetis-edma");
 	mutex_init(&fsl_edma->fsl_edma_mutex);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -858,6 +902,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+	if (fsl_edma->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;
+		}
+	}
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,10 +1014,14 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+	if (fsl_edma->kinetis)
+		clk_disable_unprepare(fsl_edma->clk);
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+	{ .compatible = "fsl,kinetis-edma", },
 	{ .compatible = "fsl,vf610-edma", },
 	{ /* sentinel */ }
 };
-- 
2.3.6

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

* [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

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

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt |  38 ++++++-
 drivers/dma/fsl-edma.c                             | 114 ++++++++++++++++-----
 2 files changed, 125 insertions(+), 27 deletions(-)

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..88c3e20 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_cclk_gate 6 1>,
+		 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..e41a3b9 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -164,13 +164,13 @@ struct fsl_edma_desc {
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+	struct clk		*clk;
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
-	int			txirq;
-	int			errirq;
 	bool			big_endian;
+	bool			kinetis;
 	struct fsl_edma_chan	chans[];
 };
 
@@ -788,42 +788,85 @@ 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)
 {
+	struct device_node *np = pdev->dev.of_node;
+	int irq, errirq;
 	int ret;
 
-	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;
-	}
-
-	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
-	if (fsl_edma->errirq < 0) {
+	errirq = platform_get_irq_byname(pdev, "edma-err");
+	if (errirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
-		return fsl_edma->errirq;
+		return irq;
 	}
 
-	if (fsl_edma->txirq == fsl_edma->errirq) {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
-				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
-			 return  ret;
+	if (fsl_edma->kinetis) {
+		int i;
+		int irqs = of_irq_count(np);
+
+		if (irqs <= 1) {
+			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
+			return -EINVAL;
 		}
-	} else {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+
+		for (i = 0; i < (irqs - 1); i++) {
+			char irq_name[32];
+
+			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
+			irq = platform_get_irq_byname(pdev, irq_name);
+			if (irq < 0) {
+				dev_err(&pdev->dev, "Can't get %s irq.\n",
+							irq_name);
+				return irq;
+			}
+
+			ret = devm_request_irq(&pdev->dev, irq,
 				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
-			return  ret;
+			if (ret) {
+				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
+							irq_name);
+				return  ret;
+			}
 		}
 
-		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
-				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+		ret = devm_request_irq(&pdev->dev, errirq,
+			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
 		if (ret) {
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
-			return  ret;
+		return  ret;
+		}
+	} else {
+		irq = platform_get_irq_byname(pdev, "edma-tx");
+		if (irq < 0) {
+			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
+			return irq;
+		}
+
+		if (irq == errirq) {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+						"Can't register eDMA IRQ.\n");
+				return  ret;
+			}
+		} else {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA tx IRQ.\n");
+				return  ret;
+			}
+
+			ret = devm_request_irq(&pdev->dev, errirq,
+				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA err IRQ.\n");
+				return  ret;
+			}
 		}
 	}
 
@@ -851,6 +894,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	fsl_edma->n_chans = chans;
+	fsl_edma->kinetis = of_device_is_compatible(np, "fsl,kinetis-edma");
 	mutex_init(&fsl_edma->fsl_edma_mutex);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -858,6 +902,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+	if (fsl_edma->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;
+		}
+	}
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,10 +1014,14 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+	if (fsl_edma->kinetis)
+		clk_disable_unprepare(fsl_edma->clk);
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+	{ .compatible = "fsl,kinetis-edma", },
 	{ .compatible = "fsl,vf610-edma", },
 	{ /* sentinel */ }
 };
-- 
2.3.6


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

* [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 Documentation/devicetree/bindings/dma/fsl-edma.txt |  38 ++++++-
 drivers/dma/fsl-edma.c                             | 114 ++++++++++++++++-----
 2 files changed, 125 insertions(+), 27 deletions(-)

diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
index 191d7bd..88c3e20 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 at 40018000 {
 		<&clks VF610_CLK_DMAMUX1>;
 };
 
+edma: dma-controller at 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_cclk_gate 6 1>,
+		 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+	clock-names = "edma", "dmamux0", "dmamux1";
+};
 
 * DMA clients
 DMA client drivers that uses the DMA function must use the format described
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 915eec3..e41a3b9 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -164,13 +164,13 @@ struct fsl_edma_desc {
 struct fsl_edma_engine {
 	struct dma_device	dma_dev;
 	void __iomem		*membase;
+	struct clk		*clk;
 	void __iomem		*muxbase[DMAMUX_NR];
 	struct clk		*muxclk[DMAMUX_NR];
 	struct mutex		fsl_edma_mutex;
 	u32			n_chans;
-	int			txirq;
-	int			errirq;
 	bool			big_endian;
+	bool			kinetis;
 	struct fsl_edma_chan	chans[];
 };
 
@@ -788,42 +788,85 @@ 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)
 {
+	struct device_node *np = pdev->dev.of_node;
+	int irq, errirq;
 	int ret;
 
-	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;
-	}
-
-	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
-	if (fsl_edma->errirq < 0) {
+	errirq = platform_get_irq_byname(pdev, "edma-err");
+	if (errirq < 0) {
 		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
-		return fsl_edma->errirq;
+		return irq;
 	}
 
-	if (fsl_edma->txirq == fsl_edma->errirq) {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
-				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
-			 return  ret;
+	if (fsl_edma->kinetis) {
+		int i;
+		int irqs = of_irq_count(np);
+
+		if (irqs <= 1) {
+			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
+			return -EINVAL;
 		}
-	} else {
-		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+
+		for (i = 0; i < (irqs - 1); i++) {
+			char irq_name[32];
+
+			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
+			irq = platform_get_irq_byname(pdev, irq_name);
+			if (irq < 0) {
+				dev_err(&pdev->dev, "Can't get %s irq.\n",
+							irq_name);
+				return irq;
+			}
+
+			ret = devm_request_irq(&pdev->dev, irq,
 				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
-		if (ret) {
-			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
-			return  ret;
+			if (ret) {
+				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
+							irq_name);
+				return  ret;
+			}
 		}
 
-		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
-				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+		ret = devm_request_irq(&pdev->dev, errirq,
+			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
 		if (ret) {
 			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
-			return  ret;
+		return  ret;
+		}
+	} else {
+		irq = platform_get_irq_byname(pdev, "edma-tx");
+		if (irq < 0) {
+			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
+			return irq;
+		}
+
+		if (irq == errirq) {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+						"Can't register eDMA IRQ.\n");
+				return  ret;
+			}
+		} else {
+			ret = devm_request_irq(&pdev->dev, irq,
+				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA tx IRQ.\n");
+				return  ret;
+			}
+
+			ret = devm_request_irq(&pdev->dev, errirq,
+				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+			if (ret) {
+				dev_err(&pdev->dev,
+					    "Can't register eDMA err IRQ.\n");
+				return  ret;
+			}
 		}
 	}
 
@@ -851,6 +894,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	fsl_edma->n_chans = chans;
+	fsl_edma->kinetis = of_device_is_compatible(np, "fsl,kinetis-edma");
 	mutex_init(&fsl_edma->fsl_edma_mutex);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -858,6 +902,20 @@ static int fsl_edma_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_edma->membase))
 		return PTR_ERR(fsl_edma->membase);
 
+	if (fsl_edma->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;
+		}
+	}
+
 	for (i = 0; i < DMAMUX_NR; i++) {
 		char clkname[32];
 
@@ -956,10 +1014,14 @@ static int fsl_edma_remove(struct platform_device *pdev)
 	for (i = 0; i < DMAMUX_NR; i++)
 		clk_disable_unprepare(fsl_edma->muxclk[i]);
 
+	if (fsl_edma->kinetis)
+		clk_disable_unprepare(fsl_edma->clk);
+
 	return 0;
 }
 
 static const struct of_device_id fsl_edma_dt_ids[] = {
+	{ .compatible = "fsl,kinetis-edma", },
 	{ .compatible = "fsl,vf610-edma", },
 	{ /* sentinel */ }
 };
-- 
2.3.6

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

* [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

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>
---
 arch/arm/Kconfig                            |  4 ++
 arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
 arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b21592b..8ccffee 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -971,6 +971,10 @@ config ARCH_KINETIS
 	select CLKSRC_KINETIS
 	select PINCTRL
 	select PINCTRL_KINETIS
+	select DMADEVICES
+	select FSL_EDMA
+	select DMA_OF
+	select NEED_MACH_MEMORY_H
 	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 5ff1d3b..c2861f5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -19,6 +19,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_cclk_gate 6 1>,
+				 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+			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 */
-- 
2.3.6


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

* [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 arch/arm/Kconfig                            |  4 ++
 arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
 arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)
 create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b21592b..8ccffee 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -971,6 +971,10 @@ config ARCH_KINETIS
 	select CLKSRC_KINETIS
 	select PINCTRL
 	select PINCTRL_KINETIS
+	select DMADEVICES
+	select FSL_EDMA
+	select DMA_OF
+	select NEED_MACH_MEMORY_H
 	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 5ff1d3b..c2861f5 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -19,6 +19,40 @@
 	};
 
 	soc {
+		edma: dma-controller at 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_cclk_gate 6 1>,
+				 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux at 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 */
-- 
2.3.6

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

* [PATCH v2 8/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
@ 2015-06-30 12:27   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, 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>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  6 +-
 drivers/tty/serial/fsl_lpuart.c                    | 90 ++++++++++++++++++----
 2 files changed, 80 insertions(+), 16 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/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");
 
-- 
2.3.6


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

* [PATCH v2 8/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support Kinetis SoC
@ 2015-06-30 12:27   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

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>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  6 +-
 drivers/tty/serial/fsl_lpuart.c                    | 90 ++++++++++++++++++----
 2 files changed, 80 insertions(+), 16 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/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");
 
-- 
2.3.6

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

* [PATCH v2 9/9] arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC
  2015-06-30 12:27 ` Paul Osmialowski
  (?)
@ 2015-06-30 12:27     ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

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 from Emcraft did not
implement tx DMA at all.

Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
---
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts | 23 +++++++++
 arch/arm/boot/dts/kinetis.dtsi             | 78 ++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

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 c2861f5..fedafe3 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -16,9 +16,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_cclk_gate 3 10>;
+			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_cclk_gate 3 11>;
+			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_pclk_gate 3 12>;
+			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_pclk_gate 3 13>;
+			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_pclk_gate 0 10>;
+			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_pclk_gate 0 11>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller@40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
-- 
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] 140+ messages in thread

* [PATCH v2 9/9] arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine
  Cc: Arnd Bergmann, Geert Uytterhoeven, Nicolas Pitre, Paul Bolle,
	Thomas Gleixner, Uwe Kleine-Koenig, Paul Osmialowski,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

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 from Emcraft did not
implement tx DMA at all.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts | 23 +++++++++
 arch/arm/boot/dts/kinetis.dtsi             | 78 ++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

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 c2861f5..fedafe3 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -16,9 +16,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_cclk_gate 3 10>;
+			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_cclk_gate 3 11>;
+			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_pclk_gate 3 12>;
+			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_pclk_gate 3 13>;
+			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_pclk_gate 0 10>;
+			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_pclk_gate 0 11>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller@40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
-- 
2.3.6


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

* [PATCH v2 9/9] arm: twr-k70f120m: use Freescale lpuart driver with Kinetis SoC
@ 2015-06-30 12:27     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-06-30 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

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 from Emcraft did not
implement tx DMA at all.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts | 23 +++++++++
 arch/arm/boot/dts/kinetis.dtsi             | 78 ++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

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 c2861f5..fedafe3 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -16,9 +16,87 @@
 		pmx3 = &portD;
 		pmx4 = &portE;
 		pmx5 = &portF;
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+		serial5 = &uart5;
 	};
 
 	soc {
+		uart0: serial at 4006a000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006a000 0x1000>;
+			interrupts = <45>, <46>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_cclk_gate 3 10>;
+			clock-names = "ipg";
+			dmas = <&edma 0 2>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart1: serial at 4006b000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006b000 0x1000>;
+			interrupts = <47>, <48>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_cclk_gate 3 11>;
+			clock-names = "ipg";
+			dmas = <&edma 0 4>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart2: serial at 4006c000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006c000 0x1000>;
+			interrupts = <49>, <50>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_pclk_gate 3 12>;
+			clock-names = "ipg";
+			dmas = <&edma 0 6>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart3: serial at 4006d000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x4006d000 0x1000>;
+			interrupts = <51>, <52>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_pclk_gate 3 13>;
+			clock-names = "ipg";
+			dmas = <&edma 0 8>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart4: serial at 400ea000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400ea000 0x1000>;
+			interrupts = <53>, <54>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_pclk_gate 0 10>;
+			clock-names = "ipg";
+			dmas = <&edma 0 10>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
+		uart5: serial at 400eb000 {
+			compatible = "fsl,kinetis-lpuart";
+			reg = <0x400eb000 0x1000>;
+			interrupts = <55>, <56>;
+			interrupt-names = "uart-stat", "uart-err";
+			clocks = <&mcg_pclk_gate 0 11>;
+			clock-names = "ipg";
+			dmas = <&edma 0 12>;
+			dma-names = "rx";
+			status = "disabled";
+		};
+
 		edma: dma-controller at 40008000 {
 			compatible = "fsl,kinetis-edma";
 			reg = <0x40008000 0x2000>, /* DMAC */
-- 
2.3.6

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-06-30 12:27   ` Paul Osmialowski
  (?)
@ 2015-06-30 20:36     ` Arnd Bergmann
  -1 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:36 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov

On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>  4 files changed, 563 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>  create mode 100644 drivers/clk/clk-kinetis.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> new file mode 100644
> index 0000000..63af6a5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> @@ -0,0 +1,63 @@
> +* Clock bindings for Freescale Kinetis SoC
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-cmu".
> +- reg: Two address ranges, one for the Clock Genetator register set,
> +	one for System Integration Module register set.
> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
> +
> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
> +index.

Please document the sub-nodes that are allowed, and the format
of the clock specifiers.

> +
> +Example:
> +
> +cmu@40064000 {
> +	compatible = "fsl,kinetis-cmu";
> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
> +
> +	mcg_outclk: fixed-rate-root@mcgout {
> +		device_type = "mcgout";
> +		#clock-cells = <0>;
> +	};
> +
> +	mcg_cclk: fixed-rate@cclk {

'@' is a reserved character here that is used before the address
of the device, so this has to be a hexadecimal number without leading
'0x', and it should match the 'reg' property of the device.

> +		device_type = "cclk";
> +		#clock-cells = <0>;
> +		clocks = <&mcg_outclk>;
> +	};

The device_type property here is not a standard identifier,
and you don't list it as an optional or mandatory property.

Please remove it and instead use the compatible property, the
name or the address.

	Arnd

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-06-30 20:36     ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:36 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov, Rob Herring, Geert Uytterhoeven,
	Uwe Kleine-Koenig, Alexander Potashev, Frank Li, Thomas Gleixner,
	Anson Huang

On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>  4 files changed, 563 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>  create mode 100644 drivers/clk/clk-kinetis.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> new file mode 100644
> index 0000000..63af6a5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> @@ -0,0 +1,63 @@
> +* Clock bindings for Freescale Kinetis SoC
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-cmu".
> +- reg: Two address ranges, one for the Clock Genetator register set,
> +	one for System Integration Module register set.
> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
> +
> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
> +index.

Please document the sub-nodes that are allowed, and the format
of the clock specifiers.

> +
> +Example:
> +
> +cmu@40064000 {
> +	compatible = "fsl,kinetis-cmu";
> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
> +
> +	mcg_outclk: fixed-rate-root@mcgout {
> +		device_type = "mcgout";
> +		#clock-cells = <0>;
> +	};
> +
> +	mcg_cclk: fixed-rate@cclk {

'@' is a reserved character here that is used before the address
of the device, so this has to be a hexadecimal number without leading
'0x', and it should match the 'reg' property of the device.

> +		device_type = "cclk";
> +		#clock-cells = <0>;
> +		clocks = <&mcg_outclk>;
> +	};

The device_type property here is not a standard identifier,
and you don't list it as an optional or mandatory property.

Please remove it and instead use the compatible property, the
name or the address.

	Arnd


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-06-30 20:36     ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> 
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>  4 files changed, 563 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>  create mode 100644 drivers/clk/clk-kinetis.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> new file mode 100644
> index 0000000..63af6a5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
> @@ -0,0 +1,63 @@
> +* Clock bindings for Freescale Kinetis SoC
> +
> +Required properties:
> +- compatible: Should be "fsl,kinetis-cmu".
> +- reg: Two address ranges, one for the Clock Genetator register set,
> +	one for System Integration Module register set.
> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
> +
> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
> +index.

Please document the sub-nodes that are allowed, and the format
of the clock specifiers.

> +
> +Example:
> +
> +cmu at 40064000 {
> +	compatible = "fsl,kinetis-cmu";
> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
> +
> +	mcg_outclk: fixed-rate-root at mcgout {
> +		device_type = "mcgout";
> +		#clock-cells = <0>;
> +	};
> +
> +	mcg_cclk: fixed-rate at cclk {

'@' is a reserved character here that is used before the address
of the device, so this has to be a hexadecimal number without leading
'0x', and it should match the 'reg' property of the device.

> +		device_type = "cclk";
> +		#clock-cells = <0>;
> +		clocks = <&mcg_outclk>;
> +	};

The device_type property here is not a standard identifier,
and you don't list it as an optional or mandatory property.

Please remove it and instead use the compatible property, the
name or the address.

	Arnd

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-06-30 12:27     ` Paul Osmialowski
  (?)
@ 2015-06-30 20:43         ` Arnd Bergmann
  -1 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:43 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov

On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:

> +Example:
> +
> +aliases {
> +	pit0 = &pit0;
> +	pit1 = &pit1;
> +	pit2 = &pit2;
> +	pit3 = &pit3;
> +};
> +
> +pit@40037000 {
> +	compatible = "fsl,kinetis-pit-timer";
> +	reg = <0x40037000 0x100>;
> +	clocks = <&mcg_pclk_gate 5 23>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	ranges;

All the subnodes seem to fall inside of the device's own register
area, so I think it would be nicer to use a specific 'ranges'
property that only translates the registers in question.

>  / {
> +	aliases {
> +		pit0 = &pit0;
> +		pit1 = &pit1;
> +		pit2 = &pit2;
> +		pit3 = &pit3;
> +	};
> +
>  	soc {
> +		pit@40037000 {
> +			compatible = "fsl,kinetis-pit-timer";
> +			reg = <0x40037000 0x100>;
> +			clocks = <&mcg_pclk_gate 5 23>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges;
> +
> +			pit0: timer@40037100 {
> +				reg = <0x40037100 0x10>;
> +				interrupts = <68>;
> +				status = "disabled";
> +			};

I don't think it's necessary to have both an alias
and a label here. What do you use the alias for?

> +
> +#define KINETIS_PITMCR_PTR(base, reg) \
> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
> +#define KINETIS_PITMCR_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
> +	} while (0)

These should really be written as inline functions. Can you
explain why you need to deal with a big-endian version of this
hardware? Can you configure the endianess of this register block
and just set it to one of the two at boot time?

> +#define KINETIS_PIT_PTR(base, reg) \
> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
> +#define KINETIS_PIT_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
> +	} while (0)
> +#define KINETIS_PIT_SET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) | (mask))
> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))


Functions again. Also, just pass a pointer to your own data structure
into the function, instead of the 'be' and 'base' values.

The 'set' and 'reset' functions look like they need a spinlock
to avoid races.

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-06-30 20:43         ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:43 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov, Rob Herring, Geert Uytterhoeven,
	Uwe Kleine-Koenig, Alexander Potashev, Frank Li, Thomas Gleixner,
	Anson Huang

On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:

> +Example:
> +
> +aliases {
> +	pit0 = &pit0;
> +	pit1 = &pit1;
> +	pit2 = &pit2;
> +	pit3 = &pit3;
> +};
> +
> +pit@40037000 {
> +	compatible = "fsl,kinetis-pit-timer";
> +	reg = <0x40037000 0x100>;
> +	clocks = <&mcg_pclk_gate 5 23>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	ranges;

All the subnodes seem to fall inside of the device's own register
area, so I think it would be nicer to use a specific 'ranges'
property that only translates the registers in question.

>  / {
> +	aliases {
> +		pit0 = &pit0;
> +		pit1 = &pit1;
> +		pit2 = &pit2;
> +		pit3 = &pit3;
> +	};
> +
>  	soc {
> +		pit@40037000 {
> +			compatible = "fsl,kinetis-pit-timer";
> +			reg = <0x40037000 0x100>;
> +			clocks = <&mcg_pclk_gate 5 23>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges;
> +
> +			pit0: timer@40037100 {
> +				reg = <0x40037100 0x10>;
> +				interrupts = <68>;
> +				status = "disabled";
> +			};

I don't think it's necessary to have both an alias
and a label here. What do you use the alias for?

> +
> +#define KINETIS_PITMCR_PTR(base, reg) \
> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
> +#define KINETIS_PITMCR_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
> +	} while (0)

These should really be written as inline functions. Can you
explain why you need to deal with a big-endian version of this
hardware? Can you configure the endianess of this register block
and just set it to one of the two at boot time?

> +#define KINETIS_PIT_PTR(base, reg) \
> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
> +#define KINETIS_PIT_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
> +	} while (0)
> +#define KINETIS_PIT_SET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) | (mask))
> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))


Functions again. Also, just pass a pointer to your own data structure
into the function, instead of the 'be' and 'base' values.

The 'set' and 'reset' functions look like they need a spinlock
to avoid races.

	Arnd

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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-06-30 20:43         ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:

> +Example:
> +
> +aliases {
> +	pit0 = &pit0;
> +	pit1 = &pit1;
> +	pit2 = &pit2;
> +	pit3 = &pit3;
> +};
> +
> +pit at 40037000 {
> +	compatible = "fsl,kinetis-pit-timer";
> +	reg = <0x40037000 0x100>;
> +	clocks = <&mcg_pclk_gate 5 23>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	ranges;

All the subnodes seem to fall inside of the device's own register
area, so I think it would be nicer to use a specific 'ranges'
property that only translates the registers in question.

>  / {
> +	aliases {
> +		pit0 = &pit0;
> +		pit1 = &pit1;
> +		pit2 = &pit2;
> +		pit3 = &pit3;
> +	};
> +
>  	soc {
> +		pit at 40037000 {
> +			compatible = "fsl,kinetis-pit-timer";
> +			reg = <0x40037000 0x100>;
> +			clocks = <&mcg_pclk_gate 5 23>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges;
> +
> +			pit0: timer at 40037100 {
> +				reg = <0x40037100 0x10>;
> +				interrupts = <68>;
> +				status = "disabled";
> +			};

I don't think it's necessary to have both an alias
and a label here. What do you use the alias for?

> +
> +#define KINETIS_PITMCR_PTR(base, reg) \
> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
> +#define KINETIS_PITMCR_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
> +	} while (0)

These should really be written as inline functions. Can you
explain why you need to deal with a big-endian version of this
hardware? Can you configure the endianess of this register block
and just set it to one of the two at boot time?

> +#define KINETIS_PIT_PTR(base, reg) \
> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
> +#define KINETIS_PIT_RD(be, base, reg) \
> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
> +		if (be) \
> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
> +		else \
> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
> +	} while (0)
> +#define KINETIS_PIT_SET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) | (mask))
> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
> +		KINETIS_PIT_WR(be, base, reg, \
> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))


Functions again. Also, just pass a pointer to your own data structure
into the function, instead of the 'be' and 'base' values.

The 'set' and 'reset' functions look like they need a spinlock
to avoid races.

	Arnd

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

* Re: [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  2015-06-30 12:27   ` Paul Osmialowski
  (?)
@ 2015-06-30 20:49     ` Arnd Bergmann
  -1 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov

On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
> 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.

You can't do this, it breaks compilation when multiple platforms
are enabled.

> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig                            |  4 ++
>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>  3 files changed, 99 insertions(+)
>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index b21592b..8ccffee 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>  	select CLKSRC_KINETIS
>  	select PINCTRL
>  	select PINCTRL_KINETIS
> +	select DMADEVICES
> +	select FSL_EDMA
> +	select DMA_OF
> +	select NEED_MACH_MEMORY_H

I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF

> +
> +#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 should be expressed using the 'dma-ranges' properties in the
bus nodes above any DMA master, the normal DMA mapping code will
then do the right thing.

	Arnd

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

* Re: [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
@ 2015-06-30 20:49     ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:49 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov, Rob Herring, Geert Uytterhoeven,
	Uwe Kleine-Koenig, Alexander Potashev, Frank Li, Thomas Gleixner,
	Anson Huang

On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
> 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.

You can't do this, it breaks compilation when multiple platforms
are enabled.

> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig                            |  4 ++
>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>  3 files changed, 99 insertions(+)
>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index b21592b..8ccffee 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>  	select CLKSRC_KINETIS
>  	select PINCTRL
>  	select PINCTRL_KINETIS
> +	select DMADEVICES
> +	select FSL_EDMA
> +	select DMA_OF
> +	select NEED_MACH_MEMORY_H

I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF

> +
> +#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 should be expressed using the 'dma-ranges' properties in the
bus nodes above any DMA master, the normal DMA mapping code will
then do the right thing.

	Arnd

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

* [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
@ 2015-06-30 20:49     ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-06-30 20:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
> 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.

You can't do this, it breaks compilation when multiple platforms
are enabled.

> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> ---
>  arch/arm/Kconfig                            |  4 ++
>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>  3 files changed, 99 insertions(+)
>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index b21592b..8ccffee 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>  	select CLKSRC_KINETIS
>  	select PINCTRL
>  	select PINCTRL_KINETIS
> +	select DMADEVICES
> +	select FSL_EDMA
> +	select DMA_OF
> +	select NEED_MACH_MEMORY_H

I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF

> +
> +#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 should be expressed using the 'dma-ranges' properties in the
bus nodes above any DMA master, the normal DMA mapping code will
then do the right thing.

	Arnd

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

* Re: [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
  2015-06-30 20:49     ` Arnd Bergmann
  (?)
@ 2015-07-01  6:54       ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  6:54 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri

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

Hi Arnd,

Thanks for pointing this - dma-ranges seem to work properly. This makes 
the patch much simpler. To be included to the next iteration.

I also removed DMA_OF from Kconfig and CONFIG_DMA_OF from my defconfig and 
it was automatically added during preparation of .cofing for build.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
>> 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.
>
> You can't do this, it breaks compilation when multiple platforms
> are enabled.
>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  arch/arm/Kconfig                            |  4 ++
>>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>>  3 files changed, 99 insertions(+)
>>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index b21592b..8ccffee 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>>  	select CLKSRC_KINETIS
>>  	select PINCTRL
>>  	select PINCTRL_KINETIS
>> +	select DMADEVICES
>> +	select FSL_EDMA
>> +	select DMA_OF
>> +	select NEED_MACH_MEMORY_H
>
> I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF
>
>> +
>> +#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 should be expressed using the 'dma-ranges' properties in the
> bus nodes above any DMA master, the normal DMA mapping code will
> then do the right thing.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0007-arm-twr-k70f120m-use-Freescale-eDMA-driver-with-Kine.patch, Size: 2182 bytes --]

From e0b549151b3ee8d4419344a2b5ef461bad19b2af Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 23:37:20 +0200
Subject: [PATCH 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis
 SoC

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig               |  2 ++
 arch/arm/boot/dts/kinetis.dtsi | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b21592b..81a6328 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -971,6 +971,8 @@ config ARCH_KINETIS
 	select CLKSRC_KINETIS
 	select PINCTRL
 	select PINCTRL_KINETIS
+	select DMADEVICES
+	select FSL_EDMA
 	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 5ff1d3b..75fc6d4 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -19,6 +19,42 @@
 	};
 
 	soc {
+		dma-ranges = <0x80000000 0x00000000 0x08000000>;
+
+		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_cclk_gate 6 1>,
+				 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux@40049000 {
 			compatible = "fsl,kinetis-padconf";
 			reg = <0x40049000 0x1000>;
-- 
2.3.6


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

* Re: [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
@ 2015-07-01  6:54       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  6:54 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

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

Hi Arnd,

Thanks for pointing this - dma-ranges seem to work properly. This makes 
the patch much simpler. To be included to the next iteration.

I also removed DMA_OF from Kconfig and CONFIG_DMA_OF from my defconfig and 
it was automatically added during preparation of .cofing for build.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
>> 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.
>
> You can't do this, it breaks compilation when multiple platforms
> are enabled.
>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  arch/arm/Kconfig                            |  4 ++
>>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>>  3 files changed, 99 insertions(+)
>>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index b21592b..8ccffee 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>>  	select CLKSRC_KINETIS
>>  	select PINCTRL
>>  	select PINCTRL_KINETIS
>> +	select DMADEVICES
>> +	select FSL_EDMA
>> +	select DMA_OF
>> +	select NEED_MACH_MEMORY_H
>
> I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF
>
>> +
>> +#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 should be expressed using the 'dma-ranges' properties in the
> bus nodes above any DMA master, the normal DMA mapping code will
> then do the right thing.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0007-arm-twr-k70f120m-use-Freescale-eDMA-driver-with-Kine.patch, Size: 2182 bytes --]

From e0b549151b3ee8d4419344a2b5ef461bad19b2af Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 23:37:20 +0200
Subject: [PATCH 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis
 SoC

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 arch/arm/Kconfig               |  2 ++
 arch/arm/boot/dts/kinetis.dtsi | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b21592b..81a6328 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -971,6 +971,8 @@ config ARCH_KINETIS
 	select CLKSRC_KINETIS
 	select PINCTRL
 	select PINCTRL_KINETIS
+	select DMADEVICES
+	select FSL_EDMA
 	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 5ff1d3b..75fc6d4 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -19,6 +19,42 @@
 	};
 
 	soc {
+		dma-ranges = <0x80000000 0x00000000 0x08000000>;
+
+		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_cclk_gate 6 1>,
+				 <&mcg_pclk_gate 5 1>, <&mcg_pclk_gate 5 2>;
+			clock-names = "edma", "dmamux0", "dmamux1";
+		};
+
 		portA: pinmux@40049000 {
 			compatible = "fsl,kinetis-padconf";
 			reg = <0x40049000 0x1000>;
-- 
2.3.6


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

* [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with Kinetis SoC
@ 2015-07-01  6:54       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  6:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

Thanks for pointing this - dma-ranges seem to work properly. This makes 
the patch much simpler. To be included to the next iteration.

I also removed DMA_OF from Kconfig and CONFIG_DMA_OF from my defconfig and 
it was automatically added during preparation of .cofing for build.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:28 Paul Osmialowski wrote:
>> 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.
>
> You can't do this, it breaks compilation when multiple platforms
> are enabled.
>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  arch/arm/Kconfig                            |  4 ++
>>  arch/arm/boot/dts/kinetis.dtsi              | 34 ++++++++++++++++
>>  arch/arm/mach-kinetis/include/mach/memory.h | 61 +++++++++++++++++++++++++++++
>>  3 files changed, 99 insertions(+)
>>  create mode 100644 arch/arm/mach-kinetis/include/mach/memory.h
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index b21592b..8ccffee 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -971,6 +971,10 @@ config ARCH_KINETIS
>>  	select CLKSRC_KINETIS
>>  	select PINCTRL
>>  	select PINCTRL_KINETIS
>> +	select DMADEVICES
>> +	select FSL_EDMA
>> +	select DMA_OF
>> +	select NEED_MACH_MEMORY_H
>
> I think DMA_OF is implied by dmaengine support in combination with CONFIG_OF
>
>> +
>> +#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 should be expressed using the 'dma-ranges' properties in the
> bus nodes above any DMA master, the normal DMA mapping code will
> then do the right thing.
>
> 	Arnd
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0007-arm-twr-k70f120m-use-Freescale-eDMA-driver-with-Kine.patch
Type: text/x-diff
Size: 2182 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150701/b3e0ff39/attachment.bin>

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-06-30 12:27     ` Paul Osmialowski
  (?)
@ 2015-07-01  7:51       ` Thomas Gleixner
  -1 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01  7:51 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson

On Tue, 30 Jun 2015, Paul Osmialowski wrote:
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +			.set_state_periodic =
> +				kinetis_clockevent_tmr_set_state_periodic,
> +			.set_state_oneshot =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_oneshot_stopped =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_shutdown =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent1",
> +		},

So how is that supposed to work if timer 1,2 or 3 is selected from
device tree? The function pointers are not initialized.

You really do not need that array at all. You can simply set the name
at init time.

> +		clockevents_register_device(
> +				&kinetis_clockevent_tmrs[chan].evtdev);
> +
> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> +						(rate / HZ) - 1);
> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);

No point doing this. The core code has invoked the set_periodic call
back via clockevents_register_device() already.

Thanks,

	tglx

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01  7:51       ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01  7:51 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, 30 Jun 2015, Paul Osmialowski wrote:
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +			.set_state_periodic =
> +				kinetis_clockevent_tmr_set_state_periodic,
> +			.set_state_oneshot =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_oneshot_stopped =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_shutdown =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent1",
> +		},

So how is that supposed to work if timer 1,2 or 3 is selected from
device tree? The function pointers are not initialized.

You really do not need that array at all. You can simply set the name
at init time.

> +		clockevents_register_device(
> +				&kinetis_clockevent_tmrs[chan].evtdev);
> +
> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> +						(rate / HZ) - 1);
> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);

No point doing this. The core code has invoked the set_periodic call
back via clockevents_register_device() already.

Thanks,

	tglx

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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01  7:51       ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01  7:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 30 Jun 2015, Paul Osmialowski wrote:
> +static struct kinetis_clock_event_ddata
> +		kinetis_clockevent_tmrs[KINETIS_PIT_CHANNELS] = {
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent0",
> +			.rating		= 200,
> +			.features	=
> +			    CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +			.set_next_event	= kinetis_clockevent_tmr_set_next_event,
> +			.set_state_periodic =
> +				kinetis_clockevent_tmr_set_state_periodic,
> +			.set_state_oneshot =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_oneshot_stopped =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +			.set_state_shutdown =
> +				kinetis_clockevent_tmr_set_state_oneshot,
> +		},
> +	},
> +	{
> +		.evtdev = {
> +			.name		= "kinetis-clockevent1",
> +		},

So how is that supposed to work if timer 1,2 or 3 is selected from
device tree? The function pointers are not initialized.

You really do not need that array at all. You can simply set the name
at init time.

> +		clockevents_register_device(
> +				&kinetis_clockevent_tmrs[chan].evtdev);
> +
> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> +						(rate / HZ) - 1);
> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);

No point doing this. The core code has invoked the set_periodic call
back via clockevents_register_device() already.

Thanks,

	tglx

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-07-01  7:51       ` Thomas Gleixner
  (?)
@ 2015-07-01  8:42         ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  8:42 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle

Hi Thomas,

On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>> +		clockevents_register_device(
>> +				&kinetis_clockevent_tmrs[chan].evtdev);
>> +
>> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
>> +						(rate / HZ) - 1);
>> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
>
> No point doing this. The core code has invoked the set_periodic call
> back via clockevents_register_device() already.
>

As I removed this kinetis_pit_enable() line, the timer did not start, 
therefore the system became unusable. What could be possible reason for 
that?
--
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] 140+ messages in thread

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01  8:42         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  8:42 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

Hi Thomas,

On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>> +		clockevents_register_device(
>> +				&kinetis_clockevent_tmrs[chan].evtdev);
>> +
>> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
>> +						(rate / HZ) - 1);
>> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
>
> No point doing this. The core code has invoked the set_periodic call
> back via clockevents_register_device() already.
>

As I removed this kinetis_pit_enable() line, the timer did not start, 
therefore the system became unusable. What could be possible reason for 
that?

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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01  8:42         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01  8:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>> +		clockevents_register_device(
>> +				&kinetis_clockevent_tmrs[chan].evtdev);
>> +
>> +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
>> +						(rate / HZ) - 1);
>> +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
>
> No point doing this. The core code has invoked the set_periodic call
> back via clockevents_register_device() already.
>

As I removed this kinetis_pit_enable() line, the timer did not start, 
therefore the system became unusable. What could be possible reason for 
that?

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-06-30 20:43         ` Arnd Bergmann
  (?)
@ 2015-07-01 11:44           ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 11:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri

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

Hi Arnd,

Again, thanks for your remarks. I'm attaching timer patch candidate for 
the third iteration.

Following your advices, I've changed following things:

- not abusing aliases (same goes to pinctrl driver)
- ranges for addressing particular timers (no change in code though, it's
   just up to the .dts implementor)
- *_RD and *_WR macros removed; whole this big-endian issue was a mistake,
   I guess I overdid it a bit trying to make my drivers as universal as
   fsl-edma driver...
- *_SET and *_RESET macros removed - they were giving false sense of
   security hiding potential race.

Any comments are welcome.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>
>> +Example:
>> +
>> +aliases {
>> +	pit0 = &pit0;
>> +	pit1 = &pit1;
>> +	pit2 = &pit2;
>> +	pit3 = &pit3;
>> +};
>> +
>> +pit@40037000 {
>> +	compatible = "fsl,kinetis-pit-timer";
>> +	reg = <0x40037000 0x100>;
>> +	clocks = <&mcg_pclk_gate 5 23>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	ranges;
>
> All the subnodes seem to fall inside of the device's own register
> area, so I think it would be nicer to use a specific 'ranges'
> property that only translates the registers in question.
>
>>  / {
>> +	aliases {
>> +		pit0 = &pit0;
>> +		pit1 = &pit1;
>> +		pit2 = &pit2;
>> +		pit3 = &pit3;
>> +	};
>> +
>>  	soc {
>> +		pit@40037000 {
>> +			compatible = "fsl,kinetis-pit-timer";
>> +			reg = <0x40037000 0x100>;
>> +			clocks = <&mcg_pclk_gate 5 23>;
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +			ranges;
>> +
>> +			pit0: timer@40037100 {
>> +				reg = <0x40037100 0x10>;
>> +				interrupts = <68>;
>> +				status = "disabled";
>> +			};
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?
>
>> +
>> +#define KINETIS_PITMCR_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
>> +#define KINETIS_PITMCR_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
>> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +	} while (0)
>
> These should really be written as inline functions. Can you
> explain why you need to deal with a big-endian version of this
> hardware? Can you configure the endianess of this register block
> and just set it to one of the two at boot time?
>
>> +#define KINETIS_PIT_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
>> +#define KINETIS_PIT_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
>> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
>> +	} while (0)
>> +#define KINETIS_PIT_SET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) | (mask))
>> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
>
>
> Functions again. Also, just pass a pointer to your own data structure
> into the function, instead of the 'be' and 'base' values.
>
> The 'set' and 'reset' functions look like they need a spinlock
> to avoid races.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0004-arm-twr-k70f120m-timer-driver-for-Kinetis-SoC.patch, Size: 12866 bytes --]

From 562decc41dc7302c378bf6e4509a22561ff5a85e Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 21:32:41 +0200
Subject: [PATCH 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC

Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  43 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  33 +++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 280 +++++++++++++++++++++
 7 files changed, 367 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 drivers/clocksource/timer-kinetis.c

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..f2930af
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,43 @@
+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 set for the
+  Periodic Interrupt Timer.
+- clocks: The clock provided by the SoC to drive the timer.
+- Set of timer devices: following properties are required for each:
+	- reg: Specifies base physical address and size of the register set
+		for given timer device.
+	- interrupts: Should be the clock event device interrupt.
+
+Example:
+
+pit@40037000 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037000 0x200>;
+	clocks = <&mcg_pclk_gate 5 23>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0x0 0x40037100 0x100>;
+
+	pit0: timer@00 {
+		reg = <0x00 0x10>;
+		interrupts = <68>;
+	};
+
+	pit1: timer@10 {
+		reg = <0x10 0x10>;
+		interrupts = <69>;
+	};
+
+	pit2: timer@20 {
+		reg = <0x20 0x10>;
+		interrupts = <70>;
+	};
+
+	pit3: timer@30 {
+		reg = <0x30 0x10>;
+		interrupts = <71>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c89bdc..96ddaae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,7 @@ config ARCH_KINETIS
 	bool "Freescale Kinetis MCU"
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	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 ae0cf00..74b58cb 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -6,6 +6,39 @@
 
 / {
 	soc {
+		pit@40037000 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037000 0x200>;
+			clocks = <&mcg_pclk_gate 5 23>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x40037100 0x100>;
+
+			pit0: timer@00 {
+				reg = <0x00 0x10>;
+				interrupts = <68>;
+				status = "disabled";
+			};
+
+			pit1: timer@10 {
+				reg = <0x10 0x10>;
+				interrupts = <69>;
+				status = "disabled";
+			};
+
+			pit2: timer@20 {
+				reg = <0x20 0x10>;
+				interrupts = <70>;
+				status = "disabled";
+			};
+
+			pit3: timer@30 {
+				reg = <0x30 0x10>;
+				interrupts = <71>;
+				status = "disabled";
+			};
+		};
+
 		cmu@40064000 {
 			compatible = "fsl,kinetis-cmu";
 			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f1c77e..d377395 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 && 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..1424308
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,280 @@
+/*
+ * 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 <linux/slab.h>
+
+/*
+ * 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)
+
+struct kinetis_pit_mcr_regs {
+	u32 mcr;
+};
+#define KINETIS_PITMCR_PTR(base, reg) \
+	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
+
+/*
+ * 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))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+	void __iomem *mcr;
+	spinlock_t lock;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(struct kinetis_clock_event_ddata *tmr,
+							    int enable)
+{
+	u32 tctrl_val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tmr->lock, flags);
+
+	tctrl_val = ioread32(KINETIS_PIT_PTR(tmr->base, tctrl));
+	if (enable)
+		iowrite32(tctrl_val | KINETIS_PIT_TCTRL_TEN_MSK,
+				KINETIS_PIT_PTR(tmr->base, tctrl));
+	else
+		iowrite32(tctrl_val & ~KINETIS_PIT_TCTRL_TEN_MSK,
+				KINETIS_PIT_PTR(tmr->base, tctrl));
+
+	spin_unlock_irqrestore(&tmr->lock, flags);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(struct kinetis_clock_event_ddata *tmr, u32 ticks)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tmr->lock, flags);
+
+	/*
+	 * Enable the PIT module clock
+	 */
+	iowrite32(0, KINETIS_PITMCR_PTR(tmr->mcr, mcr));
+
+	iowrite32(0, KINETIS_PIT_PTR(tmr->base, tctrl));
+	iowrite32(KINETIS_PIT_TFLG_TIF_MSK, KINETIS_PIT_PTR(tmr->base, tflg));
+	iowrite32(ticks, KINETIS_PIT_PTR(tmr->base, ldval));
+	iowrite32(0, KINETIS_PIT_PTR(tmr->base, cval));
+	iowrite32(KINETIS_PIT_TCTRL_TIE_MSK, KINETIS_PIT_PTR(tmr->base, tctrl));
+
+	spin_unlock_irqrestore(&tmr->lock, flags);
+}
+
+static int kinetis_clockevent_tmr_set_state_periodic(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static int kinetis_clockevent_tmr_set_state_oneshot(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 0);
+
+	return 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);
+
+	kinetis_pit_init(pit, delta);
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+/*
+ * Timer IRQ handler
+ */
+static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
+{
+	struct kinetis_clock_event_ddata *tmr = dev_id;
+
+	iowrite32(KINETIS_PIT_TFLG_TIF_MSK, KINETIS_PIT_PTR(tmr->base, tflg));
+
+	tmr->evtdev.event_handler(&tmr->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct kinetis_clock_event_ddata *kinetis_tmr;
+	struct device_node *child;
+	struct clk *clk;
+	void __iomem *base;
+	void __iomem *mcr;
+	unsigned long rate;
+	int irq;
+
+	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_get_rate;
+	}
+
+	mcr = of_iomap(np, 0);
+	if (!mcr) {
+		pr_err("failed to get mcr for clockevent\n");
+		goto err_iomap_mcr;
+	}
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		kinetis_tmr = kzalloc(sizeof(struct kinetis_clock_event_ddata),
+					GFP_KERNEL);
+		if (!kinetis_tmr)
+			continue;
+
+
+		base = of_iomap(child, 0);
+		if (!base) {
+			pr_err("failed to get registers for pit channel\n");
+			kfree(kinetis_tmr);
+			continue;
+		}
+
+		irq = irq_of_parse_and_map(child, 0);
+		if (irq <= 0) {
+			pr_err("failed to get irq for pit channel\n");
+			iounmap(base);
+			kfree(kinetis_tmr);
+			continue;
+		}
+
+		kinetis_tmr->evtdev.name = child->full_name;
+		kinetis_tmr->evtdev.rating = 200;
+		kinetis_tmr->evtdev.features = CLOCK_EVT_FEAT_PERIODIC |
+						CLOCK_EVT_FEAT_ONESHOT;
+		kinetis_tmr->evtdev.set_next_event =
+				kinetis_clockevent_tmr_set_next_event;
+		kinetis_tmr->evtdev.set_state_periodic =
+				kinetis_clockevent_tmr_set_state_periodic;
+		kinetis_tmr->evtdev.set_state_oneshot =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->evtdev.set_state_oneshot_stopped =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->evtdev.set_state_shutdown =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->base = base;
+		kinetis_tmr->mcr = mcr;
+		spin_lock_init(&kinetis_tmr->lock);
+
+		/*
+		 * Set the fields required for the set_next_event method
+		 * (tickless kernel support)
+		 */
+		clockevents_calc_mult_shift(&kinetis_tmr->evtdev, rate,
+							max_delay_in_sec);
+		kinetis_tmr->evtdev.max_delta_ns =
+					max_delay_in_sec * NSEC_PER_SEC;
+		kinetis_tmr->evtdev.min_delta_ns = clockevent_delta2ns(0xf,
+							&kinetis_tmr->evtdev);
+
+		clockevents_register_device(&kinetis_tmr->evtdev);
+
+		kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);
+		kinetis_pit_enable(kinetis_tmr, 1);
+
+		if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
+					IRQF_TIMER | IRQF_IRQPOLL,
+					"kinetis-timer",
+					kinetis_tmr)) {
+			pr_err("failed to request irq for pit channel\n");
+			kinetis_pit_enable(kinetis_tmr, 0);
+			continue;
+		}
+
+		pr_info("prepared pit channel at MMIO %#x\n", (unsigned)base);
+	}
+
+	return;
+
+err_iomap_mcr:
+err_get_rate:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
-- 
2.3.6


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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 11:44           ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 11:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

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

Hi Arnd,

Again, thanks for your remarks. I'm attaching timer patch candidate for 
the third iteration.

Following your advices, I've changed following things:

- not abusing aliases (same goes to pinctrl driver)
- ranges for addressing particular timers (no change in code though, it's
   just up to the .dts implementor)
- *_RD and *_WR macros removed; whole this big-endian issue was a mistake,
   I guess I overdid it a bit trying to make my drivers as universal as
   fsl-edma driver...
- *_SET and *_RESET macros removed - they were giving false sense of
   security hiding potential race.

Any comments are welcome.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>
>> +Example:
>> +
>> +aliases {
>> +	pit0 = &pit0;
>> +	pit1 = &pit1;
>> +	pit2 = &pit2;
>> +	pit3 = &pit3;
>> +};
>> +
>> +pit@40037000 {
>> +	compatible = "fsl,kinetis-pit-timer";
>> +	reg = <0x40037000 0x100>;
>> +	clocks = <&mcg_pclk_gate 5 23>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	ranges;
>
> All the subnodes seem to fall inside of the device's own register
> area, so I think it would be nicer to use a specific 'ranges'
> property that only translates the registers in question.
>
>>  / {
>> +	aliases {
>> +		pit0 = &pit0;
>> +		pit1 = &pit1;
>> +		pit2 = &pit2;
>> +		pit3 = &pit3;
>> +	};
>> +
>>  	soc {
>> +		pit@40037000 {
>> +			compatible = "fsl,kinetis-pit-timer";
>> +			reg = <0x40037000 0x100>;
>> +			clocks = <&mcg_pclk_gate 5 23>;
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +			ranges;
>> +
>> +			pit0: timer@40037100 {
>> +				reg = <0x40037100 0x10>;
>> +				interrupts = <68>;
>> +				status = "disabled";
>> +			};
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?
>
>> +
>> +#define KINETIS_PITMCR_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
>> +#define KINETIS_PITMCR_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
>> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +	} while (0)
>
> These should really be written as inline functions. Can you
> explain why you need to deal with a big-endian version of this
> hardware? Can you configure the endianess of this register block
> and just set it to one of the two at boot time?
>
>> +#define KINETIS_PIT_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
>> +#define KINETIS_PIT_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
>> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
>> +	} while (0)
>> +#define KINETIS_PIT_SET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) | (mask))
>> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
>
>
> Functions again. Also, just pass a pointer to your own data structure
> into the function, instead of the 'be' and 'base' values.
>
> The 'set' and 'reset' functions look like they need a spinlock
> to avoid races.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0004-arm-twr-k70f120m-timer-driver-for-Kinetis-SoC.patch, Size: 12866 bytes --]

From 562decc41dc7302c378bf6e4509a22561ff5a85e Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 21:32:41 +0200
Subject: [PATCH 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC

Based on legacy pre-OF code by Alexander Potashev <aspotashev@emcraft.com>

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../bindings/timer/fsl,kinetis-pit-timer.txt       |  43 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/kinetis-twr-k70f120m.dts         |   4 +
 arch/arm/boot/dts/kinetis.dtsi                     |  33 +++
 drivers/clocksource/Kconfig                        |   5 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-kinetis.c                | 280 +++++++++++++++++++++
 7 files changed, 367 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
 create mode 100644 drivers/clocksource/timer-kinetis.c

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..f2930af
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,kinetis-pit-timer.txt
@@ -0,0 +1,43 @@
+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 set for the
+  Periodic Interrupt Timer.
+- clocks: The clock provided by the SoC to drive the timer.
+- Set of timer devices: following properties are required for each:
+	- reg: Specifies base physical address and size of the register set
+		for given timer device.
+	- interrupts: Should be the clock event device interrupt.
+
+Example:
+
+pit@40037000 {
+	compatible = "fsl,kinetis-pit-timer";
+	reg = <0x40037000 0x200>;
+	clocks = <&mcg_pclk_gate 5 23>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0x0 0x40037100 0x100>;
+
+	pit0: timer@00 {
+		reg = <0x00 0x10>;
+		interrupts = <68>;
+	};
+
+	pit1: timer@10 {
+		reg = <0x10 0x10>;
+		interrupts = <69>;
+	};
+
+	pit2: timer@20 {
+		reg = <0x20 0x10>;
+		interrupts = <70>;
+	};
+
+	pit3: timer@30 {
+		reg = <0x30 0x10>;
+		interrupts = <71>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c89bdc..96ddaae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,7 @@ config ARCH_KINETIS
 	bool "Freescale Kinetis MCU"
 	depends on ARM_SINGLE_ARMV7M
 	select ARMV7M_SYSTICK
+	select CLKSRC_KINETIS
 	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 ae0cf00..74b58cb 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -6,6 +6,39 @@
 
 / {
 	soc {
+		pit@40037000 {
+			compatible = "fsl,kinetis-pit-timer";
+			reg = <0x40037000 0x200>;
+			clocks = <&mcg_pclk_gate 5 23>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x40037100 0x100>;
+
+			pit0: timer@00 {
+				reg = <0x00 0x10>;
+				interrupts = <68>;
+				status = "disabled";
+			};
+
+			pit1: timer@10 {
+				reg = <0x10 0x10>;
+				interrupts = <69>;
+				status = "disabled";
+			};
+
+			pit2: timer@20 {
+				reg = <0x20 0x10>;
+				interrupts = <70>;
+				status = "disabled";
+			};
+
+			pit3: timer@30 {
+				reg = <0x30 0x10>;
+				interrupts = <71>;
+				status = "disabled";
+			};
+		};
+
 		cmu@40064000 {
 			compatible = "fsl,kinetis-cmu";
 			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 0f1c77e..d377395 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 && 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..1424308
--- /dev/null
+++ b/drivers/clocksource/timer-kinetis.c
@@ -0,0 +1,280 @@
+/*
+ * 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 <linux/slab.h>
+
+/*
+ * 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)
+
+struct kinetis_pit_mcr_regs {
+	u32 mcr;
+};
+#define KINETIS_PITMCR_PTR(base, reg) \
+	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
+
+/*
+ * 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))
+
+struct kinetis_clock_event_ddata {
+	struct clock_event_device evtdev;
+	void __iomem *base;
+	void __iomem *mcr;
+	spinlock_t lock;
+};
+
+/*
+ * Enable or disable a PIT channel
+ */
+static void kinetis_pit_enable(struct kinetis_clock_event_ddata *tmr,
+							    int enable)
+{
+	u32 tctrl_val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tmr->lock, flags);
+
+	tctrl_val = ioread32(KINETIS_PIT_PTR(tmr->base, tctrl));
+	if (enable)
+		iowrite32(tctrl_val | KINETIS_PIT_TCTRL_TEN_MSK,
+				KINETIS_PIT_PTR(tmr->base, tctrl));
+	else
+		iowrite32(tctrl_val & ~KINETIS_PIT_TCTRL_TEN_MSK,
+				KINETIS_PIT_PTR(tmr->base, tctrl));
+
+	spin_unlock_irqrestore(&tmr->lock, flags);
+}
+
+/*
+ * Initialize a PIT channel, but do not enable it
+ */
+static void kinetis_pit_init(struct kinetis_clock_event_ddata *tmr, u32 ticks)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tmr->lock, flags);
+
+	/*
+	 * Enable the PIT module clock
+	 */
+	iowrite32(0, KINETIS_PITMCR_PTR(tmr->mcr, mcr));
+
+	iowrite32(0, KINETIS_PIT_PTR(tmr->base, tctrl));
+	iowrite32(KINETIS_PIT_TFLG_TIF_MSK, KINETIS_PIT_PTR(tmr->base, tflg));
+	iowrite32(ticks, KINETIS_PIT_PTR(tmr->base, ldval));
+	iowrite32(0, KINETIS_PIT_PTR(tmr->base, cval));
+	iowrite32(KINETIS_PIT_TCTRL_TIE_MSK, KINETIS_PIT_PTR(tmr->base, tctrl));
+
+	spin_unlock_irqrestore(&tmr->lock, flags);
+}
+
+static int kinetis_clockevent_tmr_set_state_periodic(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+static int kinetis_clockevent_tmr_set_state_oneshot(
+	struct clock_event_device *evt)
+{
+	struct kinetis_clock_event_ddata *pit =
+		container_of(evt, struct kinetis_clock_event_ddata, evtdev);
+
+	kinetis_pit_enable(pit, 0);
+
+	return 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);
+
+	kinetis_pit_init(pit, delta);
+	kinetis_pit_enable(pit, 1);
+
+	return 0;
+}
+
+/*
+ * Timer IRQ handler
+ */
+static irqreturn_t kinetis_clockevent_tmr_irq_handler(int irq, void *dev_id)
+{
+	struct kinetis_clock_event_ddata *tmr = dev_id;
+
+	iowrite32(KINETIS_PIT_TFLG_TIF_MSK, KINETIS_PIT_PTR(tmr->base, tflg));
+
+	tmr->evtdev.event_handler(&tmr->evtdev);
+
+	return IRQ_HANDLED;
+}
+
+static void __init kinetis_clockevent_init(struct device_node *np)
+{
+	const u64 max_delay_in_sec = 5;
+	struct kinetis_clock_event_ddata *kinetis_tmr;
+	struct device_node *child;
+	struct clk *clk;
+	void __iomem *base;
+	void __iomem *mcr;
+	unsigned long rate;
+	int irq;
+
+	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_get_rate;
+	}
+
+	mcr = of_iomap(np, 0);
+	if (!mcr) {
+		pr_err("failed to get mcr for clockevent\n");
+		goto err_iomap_mcr;
+	}
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		kinetis_tmr = kzalloc(sizeof(struct kinetis_clock_event_ddata),
+					GFP_KERNEL);
+		if (!kinetis_tmr)
+			continue;
+
+
+		base = of_iomap(child, 0);
+		if (!base) {
+			pr_err("failed to get registers for pit channel\n");
+			kfree(kinetis_tmr);
+			continue;
+		}
+
+		irq = irq_of_parse_and_map(child, 0);
+		if (irq <= 0) {
+			pr_err("failed to get irq for pit channel\n");
+			iounmap(base);
+			kfree(kinetis_tmr);
+			continue;
+		}
+
+		kinetis_tmr->evtdev.name = child->full_name;
+		kinetis_tmr->evtdev.rating = 200;
+		kinetis_tmr->evtdev.features = CLOCK_EVT_FEAT_PERIODIC |
+						CLOCK_EVT_FEAT_ONESHOT;
+		kinetis_tmr->evtdev.set_next_event =
+				kinetis_clockevent_tmr_set_next_event;
+		kinetis_tmr->evtdev.set_state_periodic =
+				kinetis_clockevent_tmr_set_state_periodic;
+		kinetis_tmr->evtdev.set_state_oneshot =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->evtdev.set_state_oneshot_stopped =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->evtdev.set_state_shutdown =
+				kinetis_clockevent_tmr_set_state_oneshot;
+		kinetis_tmr->base = base;
+		kinetis_tmr->mcr = mcr;
+		spin_lock_init(&kinetis_tmr->lock);
+
+		/*
+		 * Set the fields required for the set_next_event method
+		 * (tickless kernel support)
+		 */
+		clockevents_calc_mult_shift(&kinetis_tmr->evtdev, rate,
+							max_delay_in_sec);
+		kinetis_tmr->evtdev.max_delta_ns =
+					max_delay_in_sec * NSEC_PER_SEC;
+		kinetis_tmr->evtdev.min_delta_ns = clockevent_delta2ns(0xf,
+							&kinetis_tmr->evtdev);
+
+		clockevents_register_device(&kinetis_tmr->evtdev);
+
+		kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);
+		kinetis_pit_enable(kinetis_tmr, 1);
+
+		if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
+					IRQF_TIMER | IRQF_IRQPOLL,
+					"kinetis-timer",
+					kinetis_tmr)) {
+			pr_err("failed to request irq for pit channel\n");
+			kinetis_pit_enable(kinetis_tmr, 0);
+			continue;
+		}
+
+		pr_info("prepared pit channel at MMIO %#x\n", (unsigned)base);
+	}
+
+	return;
+
+err_iomap_mcr:
+err_get_rate:
+
+	clk_disable_unprepare(clk);
+err_clk_enable:
+
+	clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(kinetis_pit_timer, "fsl,kinetis-pit-timer",
+		       kinetis_clockevent_init);
-- 
2.3.6


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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 11:44           ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

Again, thanks for your remarks. I'm attaching timer patch candidate for 
the third iteration.

Following your advices, I've changed following things:

- not abusing aliases (same goes to pinctrl driver)
- ranges for addressing particular timers (no change in code though, it's
   just up to the .dts implementor)
- *_RD and *_WR macros removed; whole this big-endian issue was a mistake,
   I guess I overdid it a bit trying to make my drivers as universal as
   fsl-edma driver...
- *_SET and *_RESET macros removed - they were giving false sense of
   security hiding potential race.

Any comments are welcome.

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>
>> +Example:
>> +
>> +aliases {
>> +	pit0 = &pit0;
>> +	pit1 = &pit1;
>> +	pit2 = &pit2;
>> +	pit3 = &pit3;
>> +};
>> +
>> +pit at 40037000 {
>> +	compatible = "fsl,kinetis-pit-timer";
>> +	reg = <0x40037000 0x100>;
>> +	clocks = <&mcg_pclk_gate 5 23>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	ranges;
>
> All the subnodes seem to fall inside of the device's own register
> area, so I think it would be nicer to use a specific 'ranges'
> property that only translates the registers in question.
>
>>  / {
>> +	aliases {
>> +		pit0 = &pit0;
>> +		pit1 = &pit1;
>> +		pit2 = &pit2;
>> +		pit3 = &pit3;
>> +	};
>> +
>>  	soc {
>> +		pit at 40037000 {
>> +			compatible = "fsl,kinetis-pit-timer";
>> +			reg = <0x40037000 0x100>;
>> +			clocks = <&mcg_pclk_gate 5 23>;
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +			ranges;
>> +
>> +			pit0: timer at 40037100 {
>> +				reg = <0x40037100 0x10>;
>> +				interrupts = <68>;
>> +				status = "disabled";
>> +			};
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?
>
>> +
>> +#define KINETIS_PITMCR_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_mcr_regs *)(base))->reg))
>> +#define KINETIS_PITMCR_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PITMCR_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PITMCR_PTR(base, reg)))
>> +#define KINETIS_PITMCR_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PITMCR_PTR(base, reg)); \
>> +	} while (0)
>
> These should really be written as inline functions. Can you
> explain why you need to deal with a big-endian version of this
> hardware? Can you configure the endianess of this register block
> and just set it to one of the two at boot time?
>
>> +#define KINETIS_PIT_PTR(base, reg) \
>> +	(&(((struct kinetis_pit_channel_regs *)(base))->reg))
>> +#define KINETIS_PIT_RD(be, base, reg) \
>> +		((be) ? ioread32be(KINETIS_PIT_PTR(base, reg)) \
>> +		      : ioread32(KINETIS_PIT_PTR(base, reg)))
>> +#define KINETIS_PIT_WR(be, base, reg, val) do { \
>> +		if (be) \
>> +			iowrite32be((val), KINETIS_PIT_PTR(base, reg)); \
>> +		else \
>> +			iowrite32((val), KINETIS_PIT_PTR(base, reg)); \
>> +	} while (0)
>> +#define KINETIS_PIT_SET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) | (mask))
>> +#define KINETIS_PIT_RESET(be, base, reg, mask) \
>> +		KINETIS_PIT_WR(be, base, reg, \
>> +			KINETIS_PIT_RD(be, base, reg) & (~(mask)))
>
>
> Functions again. Also, just pass a pointer to your own data structure
> into the function, instead of the 'be' and 'base' values.
>
> The 'set' and 'reset' functions look like they need a spinlock
> to avoid races.
>
> 	Arnd
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0004-arm-twr-k70f120m-timer-driver-for-Kinetis-SoC.patch
Type: text/x-diff
Size: 12866 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150701/0a4754cf/attachment-0001.bin>

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-07-01  8:42         ` Paul Osmialowski
  (?)
@ 2015-07-01 13:28           ` Thomas Gleixner
  -1 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01 13:28 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Thomas,
> 
> On Wed, 1 Jul 2015, Thomas Gleixner wrote:
> 
> > > +		clockevents_register_device(
> > > +				&kinetis_clockevent_tmrs[chan].evtdev);
> > > +
> > > +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> > > +						(rate / HZ) - 1);
> > > +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
> > 
> > No point doing this. The core code has invoked the set_periodic call
> > back via clockevents_register_device() already.
> > 
> 
> As I removed this kinetis_pit_enable() line, the timer did not start,
> therefore the system became unusable. What could be possible reason for that?

Well, you need to move both, the init and the enable into
set_periodic().

Thanks,

	tglx


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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 13:28           ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01 13:28 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Thomas,
> 
> On Wed, 1 Jul 2015, Thomas Gleixner wrote:
> 
> > > +		clockevents_register_device(
> > > +				&kinetis_clockevent_tmrs[chan].evtdev);
> > > +
> > > +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> > > +						(rate / HZ) - 1);
> > > +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
> > 
> > No point doing this. The core code has invoked the set_periodic call
> > back via clockevents_register_device() already.
> > 
> 
> As I removed this kinetis_pit_enable() line, the timer did not start,
> therefore the system became unusable. What could be possible reason for that?

Well, you need to move both, the init and the enable into
set_periodic().

Thanks,

	tglx


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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 13:28           ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-01 13:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Thomas,
> 
> On Wed, 1 Jul 2015, Thomas Gleixner wrote:
> 
> > > +		clockevents_register_device(
> > > +				&kinetis_clockevent_tmrs[chan].evtdev);
> > > +
> > > +		kinetis_pit_init(&kinetis_clockevent_tmrs[chan],
> > > +						(rate / HZ) - 1);
> > > +		kinetis_pit_enable(&kinetis_clockevent_tmrs[chan], 1);
> > 
> > No point doing this. The core code has invoked the set_periodic call
> > back via clockevents_register_device() already.
> > 
> 
> As I removed this kinetis_pit_enable() line, the timer did not start,
> therefore the system became unusable. What could be possible reason for that?

Well, you need to move both, the init and the enable into
set_periodic().

Thanks,

	tglx

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-07-01 13:28           ` Thomas Gleixner
  (?)
@ 2015-07-01 14:20             ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 14:20 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle



On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>>
>> As I removed this kinetis_pit_enable() line, the timer did not start,
>> therefore the system became unusable. What could be possible reason for that?
>
> Well, you need to move both, the init and the enable into
> set_periodic().
>

Indeed, something like this worked:

diff --git a/drivers/clocksource/timer-kinetis.c 
b/drivers/clocksource/timer-kinetis.c
index 1424308..41ef94f 100644
--- a/drivers/clocksource/timer-kinetis.c
+++ b/drivers/clocksource/timer-kinetis.c
@@ -61,6 +61,7 @@ struct kinetis_clock_event_ddata {
         struct clock_event_device evtdev;
         void __iomem *base;
         void __iomem *mcr;
+       unsigned long rate;
         spinlock_t lock;
  };

@@ -115,6 +116,7 @@ static int kinetis_clockevent_tmr_set_state_periodic(
         struct kinetis_clock_event_ddata *pit =
                 container_of(evt, struct kinetis_clock_event_ddata, 
evtdev);

+       kinetis_pit_init(pit, (pit->rate / HZ) - 1);
         kinetis_pit_enable(pit, 1);

         return 0;
@@ -235,6 +237,7 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)
                                 kinetis_clockevent_tmr_set_state_oneshot;
                 kinetis_tmr->base = base;
                 kinetis_tmr->mcr = mcr;
+               kinetis_tmr->rate = rate;
                 spin_lock_init(&kinetis_tmr->lock);

                 /*
@@ -250,9 +253,6 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)

                 clockevents_register_device(&kinetis_tmr->evtdev);

-               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);
-               kinetis_pit_enable(kinetis_tmr, 1);
-
                 if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
                                         IRQF_TIMER | IRQF_IRQPOLL,
                                         "kinetis-timer",


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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 14:20             ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 14:20 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev



On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>>
>> As I removed this kinetis_pit_enable() line, the timer did not start,
>> therefore the system became unusable. What could be possible reason for that?
>
> Well, you need to move both, the init and the enable into
> set_periodic().
>

Indeed, something like this worked:

diff --git a/drivers/clocksource/timer-kinetis.c 
b/drivers/clocksource/timer-kinetis.c
index 1424308..41ef94f 100644
--- a/drivers/clocksource/timer-kinetis.c
+++ b/drivers/clocksource/timer-kinetis.c
@@ -61,6 +61,7 @@ struct kinetis_clock_event_ddata {
         struct clock_event_device evtdev;
         void __iomem *base;
         void __iomem *mcr;
+       unsigned long rate;
         spinlock_t lock;
  };

@@ -115,6 +116,7 @@ static int kinetis_clockevent_tmr_set_state_periodic(
         struct kinetis_clock_event_ddata *pit =
                 container_of(evt, struct kinetis_clock_event_ddata, 
evtdev);

+       kinetis_pit_init(pit, (pit->rate / HZ) - 1);
         kinetis_pit_enable(pit, 1);

         return 0;
@@ -235,6 +237,7 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)
                                 kinetis_clockevent_tmr_set_state_oneshot;
                 kinetis_tmr->base = base;
                 kinetis_tmr->mcr = mcr;
+               kinetis_tmr->rate = rate;
                 spin_lock_init(&kinetis_tmr->lock);

                 /*
@@ -250,9 +253,6 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)

                 clockevents_register_device(&kinetis_tmr->evtdev);

-               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);
-               kinetis_pit_enable(kinetis_tmr, 1);
-
                 if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
                                         IRQF_TIMER | IRQF_IRQPOLL,
                                         "kinetis-timer",


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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-01 14:20             ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 14:20 UTC (permalink / raw)
  To: linux-arm-kernel



On Wed, 1 Jul 2015, Thomas Gleixner wrote:

>>
>> As I removed this kinetis_pit_enable() line, the timer did not start,
>> therefore the system became unusable. What could be possible reason for that?
>
> Well, you need to move both, the init and the enable into
> set_periodic().
>

Indeed, something like this worked:

diff --git a/drivers/clocksource/timer-kinetis.c 
b/drivers/clocksource/timer-kinetis.c
index 1424308..41ef94f 100644
--- a/drivers/clocksource/timer-kinetis.c
+++ b/drivers/clocksource/timer-kinetis.c
@@ -61,6 +61,7 @@ struct kinetis_clock_event_ddata {
         struct clock_event_device evtdev;
         void __iomem *base;
         void __iomem *mcr;
+       unsigned long rate;
         spinlock_t lock;
  };

@@ -115,6 +116,7 @@ static int kinetis_clockevent_tmr_set_state_periodic(
         struct kinetis_clock_event_ddata *pit =
                 container_of(evt, struct kinetis_clock_event_ddata, 
evtdev);

+       kinetis_pit_init(pit, (pit->rate / HZ) - 1);
         kinetis_pit_enable(pit, 1);

         return 0;
@@ -235,6 +237,7 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)
                                 kinetis_clockevent_tmr_set_state_oneshot;
                 kinetis_tmr->base = base;
                 kinetis_tmr->mcr = mcr;
+               kinetis_tmr->rate = rate;
                 spin_lock_init(&kinetis_tmr->lock);

                 /*
@@ -250,9 +253,6 @@ static void __init kinetis_clockevent_init(struct 
device_node *np)

                 clockevents_register_device(&kinetis_tmr->evtdev);

-               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);
-               kinetis_pit_enable(kinetis_tmr, 1);
-
                 if (request_irq(irq, kinetis_clockevent_tmr_irq_handler,
                                         IRQF_TIMER | IRQF_IRQPOLL,
                                         "kinetis-timer",

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-06-30 20:36     ` Arnd Bergmann
  (?)
@ 2015-07-01 15:57       ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 15:57 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri

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

Hi Arnd,

Can you look at attached candidate for the third iteration? Is it any 
better now?

Thanks,
Paul

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>>  4 files changed, 563 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>>  create mode 100644 drivers/clk/clk-kinetis.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> new file mode 100644
>> index 0000000..63af6a5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> @@ -0,0 +1,63 @@
>> +* Clock bindings for Freescale Kinetis SoC
>> +
>> +Required properties:
>> +- compatible: Should be "fsl,kinetis-cmu".
>> +- reg: Two address ranges, one for the Clock Genetator register set,
>> +	one for System Integration Module register set.
>> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
>> +
>> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
>> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
>> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
>> +index.
>
> Please document the sub-nodes that are allowed, and the format
> of the clock specifiers.
>
>> +
>> +Example:
>> +
>> +cmu@40064000 {
>> +	compatible = "fsl,kinetis-cmu";
>> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> +
>> +	mcg_outclk: fixed-rate-root@mcgout {
>> +		device_type = "mcgout";
>> +		#clock-cells = <0>;
>> +	};
>> +
>> +	mcg_cclk: fixed-rate@cclk {
>
> '@' is a reserved character here that is used before the address
> of the device, so this has to be a hexadecimal number without leading
> '0x', and it should match the 'reg' property of the device.
>
>> +		device_type = "cclk";
>> +		#clock-cells = <0>;
>> +		clocks = <&mcg_outclk>;
>> +	};
>
> The device_type property here is not a standard identifier,
> and you don't list it as an optional or mandatory property.
>
> Please remove it and instead use the compatible property, the
> name or the address.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 18309 bytes --]

From 22e89bdbea639d8d4daba548927c661f39ff4551 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  65 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  29 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 486 +++++++++++++++++++++
 4 files changed, 581 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..e6c1cfa
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,65 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Multipurpose Clock Genetator (MCG)
+	register set, one for System Integration Module (SIM) register set.
+- Set of clock devices (obligatory):
+	- fixed-rate-mcgout
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-cclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-pclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- cclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+	- pclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..42a11c7 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,32 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
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..d8b5e7d
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,486 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_CCLK_GATE,
+	KINETIS_CLK_PCLK_GATE,
+	KINETIS_CLK_NUM
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static int kinetis_of_register_fixed_rate_root(struct device_node *np,
+							u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name, NULL, CLK_IS_ROOT,
+								    clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_fixed_rate(struct device_node *np,
+					struct device_node *parent_clk,
+					u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					parent_clk->full_name, 0, clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_clk_gate(struct device_node *np,
+					struct device_node *parent_clk,
+					void __iomem *sim)
+{
+	struct kinetis_clk_gate_data *clk_gate;
+	int ret;
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate)
+		return -ENOMEM;
+
+	clk_gate->clk_parent_name = parent_clk->full_name;
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct device_node *child;
+	struct device_node *clk_nodes[KINETIS_CLK_NUM];
+	int i;
+	bool ok;
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++)
+		clk_nodes[i] = NULL;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		ok = true;
+
+		if (!of_node_cmp(child->name, "fixed-rate-mcgout")) {
+			if (clk_nodes[KINETIS_CLK_MCGOUT])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_MCGOUT] = child;
+		} else if (!of_node_cmp(child->name, "fixed-rate-cclk")) {
+			if (clk_nodes[KINETIS_CLK_CCLK])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_CCLK] = child;
+		} else if (!of_node_cmp(child->name, "fixed-rate-pclk")) {
+			if (clk_nodes[KINETIS_CLK_PCLK])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_PCLK] = child;
+		} else if (!of_node_cmp(child->name, "cclk-gate")) {
+			if (clk_nodes[KINETIS_CLK_CCLK_GATE])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_CCLK_GATE] = child;
+		} else if (!of_node_cmp(child->name, "pclk-gate")) {
+			if (clk_nodes[KINETIS_CLK_PCLK_GATE])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_PCLK_GATE] = child;
+		} else {
+			pr_err("unknown clock %s specified\n", child->name);
+			return;
+		}
+
+		if (!ok) {
+			pr_err("more than one %s specified\n", child->name);
+			return;
+		}
+	}
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++) {
+		if (!(clk_nodes[i])) {
+			pr_err("One of: fixed-rate-mcgout, fixed-rate-cclk, "
+				"fixed-rate-pclk, cclk-gate, pclk-gate "
+				"NOT specified\n");
+			return;
+		}
+	}
+
+	if (kinetis_of_register_fixed_rate_root(clk_nodes[KINETIS_CLK_MCGOUT],
+						clock_val_mcgout))
+		return;
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_CCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_cclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_CCLK_GATE],
+				clk_nodes[KINETIS_CLK_CCLK], sim);
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_PCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_pclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_PCLK_GATE],
+				clk_nodes[KINETIS_CLK_PCLK], sim);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-01 15:57       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 15:57 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

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

Hi Arnd,

Can you look at attached candidate for the third iteration? Is it any 
better now?

Thanks,
Paul

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>>  4 files changed, 563 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>>  create mode 100644 drivers/clk/clk-kinetis.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> new file mode 100644
>> index 0000000..63af6a5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> @@ -0,0 +1,63 @@
>> +* Clock bindings for Freescale Kinetis SoC
>> +
>> +Required properties:
>> +- compatible: Should be "fsl,kinetis-cmu".
>> +- reg: Two address ranges, one for the Clock Genetator register set,
>> +	one for System Integration Module register set.
>> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
>> +
>> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
>> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
>> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
>> +index.
>
> Please document the sub-nodes that are allowed, and the format
> of the clock specifiers.
>
>> +
>> +Example:
>> +
>> +cmu@40064000 {
>> +	compatible = "fsl,kinetis-cmu";
>> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> +
>> +	mcg_outclk: fixed-rate-root@mcgout {
>> +		device_type = "mcgout";
>> +		#clock-cells = <0>;
>> +	};
>> +
>> +	mcg_cclk: fixed-rate@cclk {
>
> '@' is a reserved character here that is used before the address
> of the device, so this has to be a hexadecimal number without leading
> '0x', and it should match the 'reg' property of the device.
>
>> +		device_type = "cclk";
>> +		#clock-cells = <0>;
>> +		clocks = <&mcg_outclk>;
>> +	};
>
> The device_type property here is not a standard identifier,
> and you don't list it as an optional or mandatory property.
>
> Please remove it and instead use the compatible property, the
> name or the address.
>
> 	Arnd
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 18309 bytes --]

From 22e89bdbea639d8d4daba548927c661f39ff4551 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  65 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  29 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 486 +++++++++++++++++++++
 4 files changed, 581 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..e6c1cfa
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,65 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Multipurpose Clock Genetator (MCG)
+	register set, one for System Integration Module (SIM) register set.
+- Set of clock devices (obligatory):
+	- fixed-rate-mcgout
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-cclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-pclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- cclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+	- pclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..42a11c7 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,32 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
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..d8b5e7d
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,486 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_CCLK_GATE,
+	KINETIS_CLK_PCLK_GATE,
+	KINETIS_CLK_NUM
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static int kinetis_of_register_fixed_rate_root(struct device_node *np,
+							u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name, NULL, CLK_IS_ROOT,
+								    clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_fixed_rate(struct device_node *np,
+					struct device_node *parent_clk,
+					u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					parent_clk->full_name, 0, clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_clk_gate(struct device_node *np,
+					struct device_node *parent_clk,
+					void __iomem *sim)
+{
+	struct kinetis_clk_gate_data *clk_gate;
+	int ret;
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate)
+		return -ENOMEM;
+
+	clk_gate->clk_parent_name = parent_clk->full_name;
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct device_node *child;
+	struct device_node *clk_nodes[KINETIS_CLK_NUM];
+	int i;
+	bool ok;
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++)
+		clk_nodes[i] = NULL;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		ok = true;
+
+		if (!of_node_cmp(child->name, "fixed-rate-mcgout")) {
+			if (clk_nodes[KINETIS_CLK_MCGOUT])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_MCGOUT] = child;
+		} else if (!of_node_cmp(child->name, "fixed-rate-cclk")) {
+			if (clk_nodes[KINETIS_CLK_CCLK])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_CCLK] = child;
+		} else if (!of_node_cmp(child->name, "fixed-rate-pclk")) {
+			if (clk_nodes[KINETIS_CLK_PCLK])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_PCLK] = child;
+		} else if (!of_node_cmp(child->name, "cclk-gate")) {
+			if (clk_nodes[KINETIS_CLK_CCLK_GATE])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_CCLK_GATE] = child;
+		} else if (!of_node_cmp(child->name, "pclk-gate")) {
+			if (clk_nodes[KINETIS_CLK_PCLK_GATE])
+				ok = false;
+			else
+				clk_nodes[KINETIS_CLK_PCLK_GATE] = child;
+		} else {
+			pr_err("unknown clock %s specified\n", child->name);
+			return;
+		}
+
+		if (!ok) {
+			pr_err("more than one %s specified\n", child->name);
+			return;
+		}
+	}
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++) {
+		if (!(clk_nodes[i])) {
+			pr_err("One of: fixed-rate-mcgout, fixed-rate-cclk, "
+				"fixed-rate-pclk, cclk-gate, pclk-gate "
+				"NOT specified\n");
+			return;
+		}
+	}
+
+	if (kinetis_of_register_fixed_rate_root(clk_nodes[KINETIS_CLK_MCGOUT],
+						clock_val_mcgout))
+		return;
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_CCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_cclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_CCLK_GATE],
+				clk_nodes[KINETIS_CLK_CCLK], sim);
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_PCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_pclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_PCLK_GATE],
+				clk_nodes[KINETIS_CLK_PCLK], sim);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-01 15:57       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-01 15:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

Can you look at attached candidate for the third iteration? Is it any 
better now?

Thanks,
Paul

On Tue, 30 Jun 2015, Arnd Bergmann wrote:

> On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>>
>> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> ---
>>  .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>>  arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/clk-kinetis.c                          | 463 +++++++++++++++++++++
>>  4 files changed, 563 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
>>  create mode 100644 drivers/clk/clk-kinetis.c
>>
>> diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> new file mode 100644
>> index 0000000..63af6a5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> @@ -0,0 +1,63 @@
>> +* Clock bindings for Freescale Kinetis SoC
>> +
>> +Required properties:
>> +- compatible: Should be "fsl,kinetis-cmu".
>> +- reg: Two address ranges, one for the Clock Genetator register set,
>> +	one for System Integration Module register set.
>> +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and clock-gates.
>> +
>> +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
>> +and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
>> +SIM_SCGC2 has address 1 and so on. The second address component is the bit
>> +index.
>
> Please document the sub-nodes that are allowed, and the format
> of the clock specifiers.
>
>> +
>> +Example:
>> +
>> +cmu at 40064000 {
>> +	compatible = "fsl,kinetis-cmu";
>> +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> +
>> +	mcg_outclk: fixed-rate-root at mcgout {
>> +		device_type = "mcgout";
>> +		#clock-cells = <0>;
>> +	};
>> +
>> +	mcg_cclk: fixed-rate at cclk {
>
> '@' is a reserved character here that is used before the address
> of the device, so this has to be a hexadecimal number without leading
> '0x', and it should match the 'reg' property of the device.
>
>> +		device_type = "cclk";
>> +		#clock-cells = <0>;
>> +		clocks = <&mcg_outclk>;
>> +	};
>
> The device_type property here is not a standard identifier,
> and you don't list it as an optional or mandatory property.
>
> Please remove it and instead use the compatible property, the
> name or the address.
>
> 	Arnd
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch
Type: text/x-diff
Size: 18309 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150701/66ed6f68/attachment-0001.bin>

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-01 15:57       ` Paul Osmialowski
  (?)
@ 2015-07-02 10:08           ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 10:08 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri

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

Nah, I've found this code hard to maintain. I'm attaching simplified 
version.

Thanks,
Paul

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> Can you look at attached candidate for the third iteration? Is it any better 
> now?
>
> Thanks,
> Paul
>
> On Tue, 30 Jun 2015, Arnd Bergmann wrote:
>
>>  On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> >  Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>> > 
>> >  Signed-off-by: Paul Osmialowski <pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
>> >  ---
>> >   .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>> >   arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>> >   drivers/clk/Makefile                               |   1 +
>> >   drivers/clk/clk-kinetis.c                          | 463 
>> >   +++++++++++++++++++++
>> >   4 files changed, 563 insertions(+)
>> >   create mode 100644 
>> >   Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >   create mode 100644 drivers/clk/clk-kinetis.c
>> > 
>> >  diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt 
>> >  b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  new file mode 100644
>> >  index 0000000..63af6a5
>> >  --- /dev/null
>> >  +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  @@ -0,0 +1,63 @@
>> >  +* Clock bindings for Freescale Kinetis SoC
>> >  +
>> >  +Required properties:
>> >  +- compatible: Should be "fsl,kinetis-cmu".
>> >  +- reg: Two address ranges, one for the Clock Genetator register set,
>> >  +	one for System Integration Module register set.
>> >  +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and 
>> >  clock-gates.
>> >  +
>> >  +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 
>> >  pg. 341
>> >  +and later. Notice that addresses are zero-based, so SIM_SCGC1 has 
>> >  address 0,
>> >  +SIM_SCGC2 has address 1 and so on. The second address component is the 
>> >  bit
>> >  +index.
>>
>>  Please document the sub-nodes that are allowed, and the format
>>  of the clock specifiers.
>> 
>> >  +
>> >  +Example:
>> >  +
>> >  +cmu@40064000 {
>> >  +	compatible = "fsl,kinetis-cmu";
>> >  +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> >  +
>> >  +	mcg_outclk: fixed-rate-root@mcgout {
>> >  +		device_type = "mcgout";
>> >  +		#clock-cells = <0>;
>> >  +	};
>> >  +
>> >  +	mcg_cclk: fixed-rate@cclk {
>>
>>  '@' is a reserved character here that is used before the address
>>  of the device, so this has to be a hexadecimal number without leading
>>  '0x', and it should match the 'reg' property of the device.
>> 
>> >  +		device_type = "cclk";
>> >  +		#clock-cells = <0>;
>> >  +		clocks = <&mcg_outclk>;
>> >  +	};
>>
>>  The device_type property here is not a standard identifier,
>>  and you don't list it as an optional or mandatory property.
>>
>>  Please remove it and instead use the compatible property, the
>>  name or the address.
>>
>>   Arnd
>> 
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 17977 bytes --]

From ae43dcd17eec3eb2c3ad4d7cd514295d935655fe Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  65 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  29 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 475 +++++++++++++++++++++
 4 files changed, 570 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..e6c1cfa
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,65 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Multipurpose Clock Genetator (MCG)
+	register set, one for System Integration Module (SIM) register set.
+- Set of clock devices (obligatory):
+	- fixed-rate-mcgout
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-cclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-pclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- cclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+	- pclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..42a11c7 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,32 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..a6e8a28
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,475 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_CCLK_GATE,
+	KINETIS_CLK_PCLK_GATE,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids id;
+	const char *name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT, .name = "fixed-rate-mcgout", },
+	{ .id = KINETIS_CLK_CCLK, .name = "fixed-rate-cclk", },
+	{ .id = KINETIS_CLK_PCLK, .name = "fixed-rate-pclk", },
+	{ .id = KINETIS_CLK_CCLK_GATE, .name = "cclk-gate", },
+	{ .id = KINETIS_CLK_PCLK_GATE, .name = "pclk-gate", },
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static int kinetis_of_register_fixed_rate_root(struct device_node *np,
+							u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name, NULL, CLK_IS_ROOT,
+								    clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_fixed_rate(struct device_node *np,
+					struct device_node *parent_clk,
+					u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					parent_clk->full_name, 0, clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_clk_gate(struct device_node *np,
+					struct device_node *parent_clk,
+					void __iomem *sim)
+{
+	struct kinetis_clk_gate_data *clk_gate;
+	int ret;
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate)
+		return -ENOMEM;
+
+	clk_gate->clk_parent_name = parent_clk->full_name;
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct device_node *child;
+	struct device_node *clk_nodes[KINETIS_CLK_NUM];
+	int i;
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++)
+		clk_nodes[i] = NULL;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		for (i = 0; i < KINETIS_CLK_NUM; i++) {
+			if (!of_node_cmp(child->name, kinetis_clks[i].name)) {
+				if (clk_nodes[kinetis_clks[i].id]) {
+					pr_err("more than one %s specified\n",
+								child->name);
+					goto fail;
+				} else
+					clk_nodes[kinetis_clks[i].id] = child;
+			}
+		}
+	}
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++) {
+		if (!(clk_nodes[kinetis_clks[i].id])) {
+			pr_err("One of obligatory clocks NOT specified\n");
+			goto fail;
+		}
+	}
+
+	if (kinetis_of_register_fixed_rate_root(clk_nodes[KINETIS_CLK_MCGOUT],
+						clock_val_mcgout))
+		goto fail;
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_CCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_cclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_CCLK_GATE],
+				clk_nodes[KINETIS_CLK_CCLK], sim);
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_PCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_pclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_PCLK_GATE],
+				clk_nodes[KINETIS_CLK_PCLK], sim);
+
+	return;
+
+fail:
+
+	iounmap(sim);
+	iounmap(base);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 10:08           ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 10:08 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, linux-arm-kernel, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

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

Nah, I've found this code hard to maintain. I'm attaching simplified 
version.

Thanks,
Paul

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> Can you look at attached candidate for the third iteration? Is it any better 
> now?
>
> Thanks,
> Paul
>
> On Tue, 30 Jun 2015, Arnd Bergmann wrote:
>
>>  On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> >  Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>> > 
>> >  Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> >  ---
>> >   .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>> >   arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>> >   drivers/clk/Makefile                               |   1 +
>> >   drivers/clk/clk-kinetis.c                          | 463 
>> >   +++++++++++++++++++++
>> >   4 files changed, 563 insertions(+)
>> >   create mode 100644 
>> >   Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >   create mode 100644 drivers/clk/clk-kinetis.c
>> > 
>> >  diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt 
>> >  b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  new file mode 100644
>> >  index 0000000..63af6a5
>> >  --- /dev/null
>> >  +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  @@ -0,0 +1,63 @@
>> >  +* Clock bindings for Freescale Kinetis SoC
>> >  +
>> >  +Required properties:
>> >  +- compatible: Should be "fsl,kinetis-cmu".
>> >  +- reg: Two address ranges, one for the Clock Genetator register set,
>> >  +	one for System Integration Module register set.
>> >  +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and 
>> >  clock-gates.
>> >  +
>> >  +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 
>> >  pg. 341
>> >  +and later. Notice that addresses are zero-based, so SIM_SCGC1 has 
>> >  address 0,
>> >  +SIM_SCGC2 has address 1 and so on. The second address component is the 
>> >  bit
>> >  +index.
>>
>>  Please document the sub-nodes that are allowed, and the format
>>  of the clock specifiers.
>> 
>> >  +
>> >  +Example:
>> >  +
>> >  +cmu@40064000 {
>> >  +	compatible = "fsl,kinetis-cmu";
>> >  +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> >  +
>> >  +	mcg_outclk: fixed-rate-root@mcgout {
>> >  +		device_type = "mcgout";
>> >  +		#clock-cells = <0>;
>> >  +	};
>> >  +
>> >  +	mcg_cclk: fixed-rate@cclk {
>>
>>  '@' is a reserved character here that is used before the address
>>  of the device, so this has to be a hexadecimal number without leading
>>  '0x', and it should match the 'reg' property of the device.
>> 
>> >  +		device_type = "cclk";
>> >  +		#clock-cells = <0>;
>> >  +		clocks = <&mcg_outclk>;
>> >  +	};
>>
>>  The device_type property here is not a standard identifier,
>>  and you don't list it as an optional or mandatory property.
>>
>>  Please remove it and instead use the compatible property, the
>>  name or the address.
>>
>>   Arnd
>> 
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 17977 bytes --]

From ae43dcd17eec3eb2c3ad4d7cd514295d935655fe Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  65 +++
 arch/arm/boot/dts/kinetis.dtsi                     |  29 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 475 +++++++++++++++++++++
 4 files changed, 570 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..e6c1cfa
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,65 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges, one for the Multipurpose Clock Genetator (MCG)
+	register set, one for System Integration Module (SIM) register set.
+- Set of clock devices (obligatory):
+	- fixed-rate-mcgout
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-cclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- fixed-rate-pclk
+		Required properties:
+		- #clock-cells: must be <0>.
+	- cclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+	- pclk-gate
+		Required properties:
+		- #clock-cells: must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..42a11c7 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,32 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..a6e8a28
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,475 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_CCLK_GATE,
+	KINETIS_CLK_PCLK_GATE,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids id;
+	const char *name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT, .name = "fixed-rate-mcgout", },
+	{ .id = KINETIS_CLK_CCLK, .name = "fixed-rate-cclk", },
+	{ .id = KINETIS_CLK_PCLK, .name = "fixed-rate-pclk", },
+	{ .id = KINETIS_CLK_CCLK_GATE, .name = "cclk-gate", },
+	{ .id = KINETIS_CLK_PCLK_GATE, .name = "pclk-gate", },
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	const char *clk_parent_name;
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name,
+				clk_gate_data->clk_parent_name, 0,
+				KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]),
+				idx, 0, NULL);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n",
+				clk_gate_data->clk_parent_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static int kinetis_of_register_fixed_rate_root(struct device_node *np,
+							u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name, NULL, CLK_IS_ROOT,
+								    clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_fixed_rate(struct device_node *np,
+					struct device_node *parent_clk,
+					u32 clock_val)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					parent_clk->full_name, 0, clock_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return PTR_ERR(clk);
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int kinetis_of_register_clk_gate(struct device_node *np,
+					struct device_node *parent_clk,
+					void __iomem *sim)
+{
+	struct kinetis_clk_gate_data *clk_gate;
+	int ret;
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate)
+		return -ENOMEM;
+
+	clk_gate->clk_parent_name = parent_clk->full_name;
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val_mcgout;
+	u32 clock_val_cclk;
+	u32 clock_val_pclk;
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	struct device_node *child;
+	struct device_node *clk_nodes[KINETIS_CLK_NUM];
+	int i;
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++)
+		clk_nodes[i] = NULL;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("Failed to map address range for kinetis,mcg node\n");
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("Failed to map address range for kinetis SIM module\n");
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val_mcgout = mcgout;
+
+	clock_val_cclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val_pclk = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		for (i = 0; i < KINETIS_CLK_NUM; i++) {
+			if (!of_node_cmp(child->name, kinetis_clks[i].name)) {
+				if (clk_nodes[kinetis_clks[i].id]) {
+					pr_err("more than one %s specified\n",
+								child->name);
+					goto fail;
+				} else
+					clk_nodes[kinetis_clks[i].id] = child;
+			}
+		}
+	}
+
+	for (i = 0; i < KINETIS_CLK_NUM; i++) {
+		if (!(clk_nodes[kinetis_clks[i].id])) {
+			pr_err("One of obligatory clocks NOT specified\n");
+			goto fail;
+		}
+	}
+
+	if (kinetis_of_register_fixed_rate_root(clk_nodes[KINETIS_CLK_MCGOUT],
+						clock_val_mcgout))
+		goto fail;
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_CCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_cclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_CCLK_GATE],
+				clk_nodes[KINETIS_CLK_CCLK], sim);
+
+	if (!(kinetis_of_register_fixed_rate(clk_nodes[KINETIS_CLK_PCLK],
+				clk_nodes[KINETIS_CLK_MCGOUT], clock_val_pclk)))
+		kinetis_of_register_clk_gate(clk_nodes[KINETIS_CLK_PCLK_GATE],
+				clk_nodes[KINETIS_CLK_PCLK], sim);
+
+	return;
+
+fail:
+
+	iounmap(sim);
+	iounmap(base);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 10:08           ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

Nah, I've found this code hard to maintain. I'm attaching simplified 
version.

Thanks,
Paul

On Wed, 1 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> Can you look at attached candidate for the third iteration? Is it any better 
> now?
>
> Thanks,
> Paul
>
> On Tue, 30 Jun 2015, Arnd Bergmann wrote:
>
>>  On Tuesday 30 June 2015 14:27:24 Paul Osmialowski wrote:
>> >  Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>> > 
>> >  Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
>> >  ---
>> >   .../devicetree/bindings/clock/kinetis-clock.txt    |  63 +++
>> >   arch/arm/boot/dts/kinetis.dtsi                     |  36 ++
>> >   drivers/clk/Makefile                               |   1 +
>> >   drivers/clk/clk-kinetis.c                          | 463 
>> >   +++++++++++++++++++++
>> >   4 files changed, 563 insertions(+)
>> >   create mode 100644 
>> >   Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >   create mode 100644 drivers/clk/clk-kinetis.c
>> > 
>> >  diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt 
>> >  b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  new file mode 100644
>> >  index 0000000..63af6a5
>> >  --- /dev/null
>> >  +++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
>> >  @@ -0,0 +1,63 @@
>> >  +* Clock bindings for Freescale Kinetis SoC
>> >  +
>> >  +Required properties:
>> >  +- compatible: Should be "fsl,kinetis-cmu".
>> >  +- reg: Two address ranges, one for the Clock Genetator register set,
>> >  +	one for System Integration Module register set.
>> >  +- Set of clock devices: one fixed-rate-root, fixed-rate clocks and 
>> >  clock-gates.
>> >  +
>> >  +For clock-gate addresses see K70 Sub-Family Reference Manual, Rev. 3 
>> >  pg. 341
>> >  +and later. Notice that addresses are zero-based, so SIM_SCGC1 has 
>> >  address 0,
>> >  +SIM_SCGC2 has address 1 and so on. The second address component is the 
>> >  bit
>> >  +index.
>>
>>  Please document the sub-nodes that are allowed, and the format
>>  of the clock specifiers.
>> 
>> >  +
>> >  +Example:
>> >  +
>> >  +cmu at 40064000 {
>> >  +	compatible = "fsl,kinetis-cmu";
>> >  +	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
>> >  +
>> >  +	mcg_outclk: fixed-rate-root at mcgout {
>> >  +		device_type = "mcgout";
>> >  +		#clock-cells = <0>;
>> >  +	};
>> >  +
>> >  +	mcg_cclk: fixed-rate at cclk {
>>
>>  '@' is a reserved character here that is used before the address
>>  of the device, so this has to be a hexadecimal number without leading
>>  '0x', and it should match the 'reg' property of the device.
>> 
>> >  +		device_type = "cclk";
>> >  +		#clock-cells = <0>;
>> >  +		clocks = <&mcg_outclk>;
>> >  +	};
>>
>>  The device_type property here is not a standard identifier,
>>  and you don't list it as an optional or mandatory property.
>>
>>  Please remove it and instead use the compatible property, the
>>  name or the address.
>>
>>   Arnd
>> 
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch
Type: text/x-diff
Size: 17977 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150702/d7ac194b/attachment-0001.bin>

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-02 10:08           ` Paul Osmialowski
  (?)
@ 2015-07-02 12:40             ` Arnd Bergmann
  -1 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-02 12:40 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: linux-arm-kernel, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov

On Thursday 02 July 2015 12:08:39 Paul Osmialowski wrote:
> Nah, I've found this code hard to maintain. I'm attaching simplified 
> version.
> 

Looks better to me, but of course needs full review from the clock
maintainers.

I wonder if you could move out the fixed rate clocks into their own
nodes. Are they actually controlled by the same block? If they are
just fixed, you can use the normal binding for fixed rate clocks
and only describe the clocks that are related to the driver.

	Arnd

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 12:40             ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-02 12:40 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: linux-arm-kernel, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov, Rob Herring, Geert Uytterhoeven,
	Uwe Kleine-Koenig, Alexander Potashev, Frank Li, Thomas Gleixner,
	Anson Huang

On Thursday 02 July 2015 12:08:39 Paul Osmialowski wrote:
> Nah, I've found this code hard to maintain. I'm attaching simplified 
> version.
> 

Looks better to me, but of course needs full review from the clock
maintainers.

I wonder if you could move out the fixed rate clocks into their own
nodes. Are they actually controlled by the same block? If they are
just fixed, you can use the normal binding for fixed rate clocks
and only describe the clocks that are related to the driver.

	Arnd

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 12:40             ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-02 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 02 July 2015 12:08:39 Paul Osmialowski wrote:
> Nah, I've found this code hard to maintain. I'm attaching simplified 
> version.
> 

Looks better to me, but of course needs full review from the clock
maintainers.

I wonder if you could move out the fixed rate clocks into their own
nodes. Are they actually controlled by the same block? If they are
just fixed, you can use the normal binding for fixed rate clocks
and only describe the clocks that are related to the driver.

	Arnd

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-02 12:40             ` Arnd Bergmann
  (?)
@ 2015-07-02 21:42               ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 21:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri

Hi Arnd,

On Thu, 2 Jul 2015, Arnd Bergmann wrote:

> I wonder if you could move out the fixed rate clocks into their own
> nodes. Are they actually controlled by the same block? If they are
> just fixed, you can use the normal binding for fixed rate clocks
> and only describe the clocks that are related to the driver.
>
> 	Arnd
>

In my view having these clocks grouped together looks more convincing. 
After all, they all share the same I/O regs in order to read 
configuration.

Thanks,
Paul
--
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] 140+ messages in thread

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 21:42               ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 21:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Paul Osmialowski, linux-arm-kernel, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

Hi Arnd,

On Thu, 2 Jul 2015, Arnd Bergmann wrote:

> I wonder if you could move out the fixed rate clocks into their own
> nodes. Are they actually controlled by the same block? If they are
> just fixed, you can use the normal binding for fixed rate clocks
> and only describe the clocks that are related to the driver.
>
> 	Arnd
>

In my view having these clocks grouped together looks more convincing. 
After all, they all share the same I/O regs in order to read 
configuration.

Thanks,
Paul

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 21:42               ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-02 21:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

On Thu, 2 Jul 2015, Arnd Bergmann wrote:

> I wonder if you could move out the fixed rate clocks into their own
> nodes. Are they actually controlled by the same block? If they are
> just fixed, you can use the normal binding for fixed rate clocks
> and only describe the clocks that are related to the driver.
>
> 	Arnd
>

In my view having these clocks grouped together looks more convincing. 
After all, they all share the same I/O regs in order to read 
configuration.

Thanks,
Paul

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-02 21:42               ` Paul Osmialowski
  (?)
@ 2015-07-02 22:08                 ` Thomas Gleixner
  -1 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-02 22:08 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Jiri Slaby, linux-clk, Russell King,
	Arnd Bergmann, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, Michael Turquette, devicetree,
	Frank Li, Pawel Moll, Ian Campbell, Jingchang Lu, Yuri Tikhonov,
	linux-gpio, Rob Herring, linux-arm-kernel

On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> 
> > I wonder if you could move out the fixed rate clocks into their own
> > nodes. Are they actually controlled by the same block? If they are
> > just fixed, you can use the normal binding for fixed rate clocks
> > and only describe the clocks that are related to the driver.
> 
> In my view having these clocks grouped together looks more convincing. After
> all, they all share the same I/O regs in order to read configuration.

The fact that they share a register is not making them a group. That's
just a HW design decision and you need to deal with that by protecting
the register access, but not by trying to group them artificially at
the functional level.

Thanks,

	tglx

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 22:08                 ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-02 22:08 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Arnd Bergmann, linux-arm-kernel, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Anson Huang

On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> 
> > I wonder if you could move out the fixed rate clocks into their own
> > nodes. Are they actually controlled by the same block? If they are
> > just fixed, you can use the normal binding for fixed rate clocks
> > and only describe the clocks that are related to the driver.
> 
> In my view having these clocks grouped together looks more convincing. After
> all, they all share the same I/O regs in order to read configuration.

The fact that they share a register is not making them a group. That's
just a HW design decision and you need to deal with that by protecting
the register access, but not by trying to group them artificially at
the functional level.

Thanks,

	tglx

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-02 22:08                 ` Thomas Gleixner
  0 siblings, 0 replies; 140+ messages in thread
From: Thomas Gleixner @ 2015-07-02 22:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> 
> > I wonder if you could move out the fixed rate clocks into their own
> > nodes. Are they actually controlled by the same block? If they are
> > just fixed, you can use the normal binding for fixed rate clocks
> > and only describe the clocks that are related to the driver.
> 
> In my view having these clocks grouped together looks more convincing. After
> all, they all share the same I/O regs in order to read configuration.

The fact that they share a register is not making them a group. That's
just a HW design decision and you need to deal with that by protecting
the register access, but not by trying to group them artificially at
the functional level.

Thanks,

	tglx

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-02 22:08                 ` Thomas Gleixner
  (?)
@ 2015-07-03 17:40                   ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-03 17:40 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Arnd Bergmann, linux-arm-kernel,
	Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu

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

Arnd, Thomas,

Thanks for your valuable input and for your patience.

I'm attaching yet another proposal for this clock driver. I've 
flattened the .dts and ensured register access protection. I've also added 
one more clock source (osc0er) and clock gate to it.

Can you comment this one too?

On Fri, 3 Jul 2015, Thomas Gleixner wrote:

> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>
>>> I wonder if you could move out the fixed rate clocks into their own
>>> nodes. Are they actually controlled by the same block? If they are
>>> just fixed, you can use the normal binding for fixed rate clocks
>>> and only describe the clocks that are related to the driver.
>>
>> In my view having these clocks grouped together looks more convincing. After
>> all, they all share the same I/O regs in order to read configuration.
>
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.
>
> Thanks,
>
> 	tglx
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 19961 bytes --]

From e05dcb772d47e4473914ac1e7703b361eb54db14 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  86 ++++
 arch/arm/boot/dts/kinetis.dtsi                     |  51 +++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 502 +++++++++++++++++++++
 4 files changed, 640 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..507f91b
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,86 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: For fixed rate clocks, two address ranges:
+	- one for the Multipurpose Clock Genetator (MCG)
+	- one for System Integration Module (SIM) register set.
+	For clock gates, one address range for System Integration Module (SIM)
+	register set.
+- clocks: single element list of parent clocks (only for non-root clocks).
+- #clock-cells: For fixed rate clocks must be <0>,
+	for clock gates must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Notice that (non-gate) clock device names must be known to Kinetis CMU drivers.
+
+Currently these are:
+
+o fixed-rate-mcgout (root)
+o fixed-rate-osc0er (root)
+o fixed-rate-cclk (fixed-rate-mcgout child)
+o fixed-rate-pclk (fixed-rate-mcgout child)
+
+Example:
+
+mcg_outclk: fixed-rate-mcgout@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	#clock-cells = <0>;
+};
+
+mcg_cclk: fixed-rate-cclk@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	clocks = <&mcg_outclk>;
+	#clock-cells = <0>;
+};
+
+mcg_pclk: fixed-rate-pclk@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	clocks = <&mcg_outclk>;
+	#clock-cells = <0>;
+};
+
+mcg_cclk_gate: cclk-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&mcg_cclk>;
+	#clock-cells = <2>;
+};
+
+mcg_pclk_gate: pclk-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&mcg_pclk>;
+	#clock-cells = <2>;
+};
+
+osc0_erclk: fixed-rate-osc0er@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	#clock-cells = <0>;
+};
+
+osc0_erclk_gate: osc0-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&osc0_erclk>;
+	#clock-cells = <2>;
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..72eb941 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,54 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		mcg_outclk: fixed-rate-mcgout@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			#clock-cells = <0>;
+		};
+
+		mcg_cclk: fixed-rate-cclk@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			clocks = <&mcg_outclk>;
+			#clock-cells = <0>;
+		};
+
+		mcg_pclk: fixed-rate-pclk@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			clocks = <&mcg_outclk>;
+			#clock-cells = <0>;
+		};
+
+		mcg_cclk_gate: cclk-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&mcg_cclk>;
+			#clock-cells = <2>;
+		};
+
+		mcg_pclk_gate: pclk-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&mcg_pclk>;
+			#clock-cells = <2>;
+		};
+
+		osc0_erclk: fixed-rate-osc0er@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			#clock-cells = <0>;
+		};
+
+		osc0_erclk_gate: osc0-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&osc0_erclk>;
+			#clock-cells = <2>;
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..8e0a0d7
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,502 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_OSC0ER,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids	id;
+	const char		*name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT,	.name = "fixed-rate-mcgout",	},
+	{ .id = KINETIS_CLK_OSC0ER,	.name = "fixed-rate-osc0er",	},
+	{ .id = KINETIS_CLK_CCLK,	.name = "fixed-rate-cclk",	},
+	{ .id = KINETIS_CLK_PCLK,	.name = "fixed-rate-pclk",	},
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+struct kinetis_scgc {
+	unsigned long paddr;
+	spinlock_t lock;
+	struct list_head scgc_list;
+};
+
+static struct list_head kinetis_scgc_list = LIST_HEAD_INIT(kinetis_scgc_list);
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return NULL;
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct kinetis_scgc *kinetis_find_scgc(unsigned long paddr)
+{
+	struct kinetis_scgc *scgc;
+
+	list_for_each_entry(scgc, &kinetis_scgc_list, scgc_list)
+		if (scgc->paddr == paddr)
+			return scgc;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	const char *clk_name;
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+	struct kinetis_scgc *scgc;
+	void __iomem *addr = KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]);
+	unsigned long paddr = virt_to_phys(addr);
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	clk_name = kinetis_of_clk_get_name(clkspec->np);
+	BUG_ON(!clk_name);
+
+	scgc = kinetis_find_scgc(paddr);
+	if (!scgc) {
+		scgc = kzalloc(sizeof(struct kinetis_scgc), GFP_KERNEL);
+		if (!scgc)
+			return ERR_PTR(-ENOMEM);
+		scgc->paddr = paddr;
+		spin_lock_init(&scgc->lock);
+
+		list_add(&scgc->scgc_list, &kinetis_scgc_list);
+	}
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+	if (!gate->clk_gate_name) {
+		kfree(gate);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name, clk_name, 0, addr,
+							idx, 0, &scgc->lock);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n", clk_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static void kinetis_of_register_clk_gate(struct device_node *np)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct kinetis_clk_gate_data *clk_gate;
+	void __iomem *sim;
+	int ret;
+
+	if (!clk_parent_name) {
+		pr_err("no clock specified for gate %s\n", np->full_name);
+		return;
+	}
+
+	sim = of_iomap(np, 0);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+							np->full_name);
+		return;
+	}
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate) {
+		iounmap(sim);
+		return;
+	}
+
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		iounmap(sim);
+		return;
+	}
+}
+
+static void kinetis_of_register_fixed_rate(struct device_node *np, u32 clk_val)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					clk_parent_name,
+					clk_parent_name ? 0 : CLK_IS_ROOT,
+					clk_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return;
+	}
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[] = { [0 ... KINETIS_CLK_NUM] = 0 };
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	enum kinetis_clk_ids clk_id;
+	u32 clock_cells;
+
+	if (of_property_read_u32_index(np, "#clock-cells", 0, &clock_cells)) {
+		pr_err("no #clock-cells set for %s\n", np->full_name);
+		return;
+	}
+
+	/*
+	 * Handle clock gates (recognized by two clock cells)
+	 */
+	if (2 == clock_cells) {
+		kinetis_of_register_clk_gate(np);
+		return;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to map MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[KINETIS_CLK_MCGOUT] = mcgout;
+	clock_val[KINETIS_CLK_OSC0ER] = KINETIS_OSC0_RATE;
+
+	clock_val[KINETIS_CLK_CCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[KINETIS_CLK_PCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	iounmap(sim);
+	iounmap(base);
+
+	for (clk_id = 0; clk_id < KINETIS_CLK_NUM; clk_id++)
+		if (!of_node_cmp(np->name, kinetis_clks[clk_id].name))
+			break;
+
+	if (KINETIS_CLK_NUM == clk_id) {
+		pr_err("unknown clock %s specified\n", np->name);
+		return;
+	}
+
+	if (!clock_val[clk_id]) {
+		pr_err("no clock rate for %s\n", np->name);
+		return;
+	}
+
+	kinetis_of_register_fixed_rate(np, clock_val[clk_id]);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-03 17:40                   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-03 17:40 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Paul Osmialowski, Arnd Bergmann, linux-arm-kernel,
	Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-clk, linux-gpio, linux-serial, devicetree,
	dmaengine, Nicolas Pitre, Sergei Poselenov, Paul Bolle,
	Jingchang Lu, Yuri Tikhonov, Rob Herring, Geert Uytterhoeven,
	Uwe Kleine-Koenig, Alexander Potashev, Frank Li, Anson Huang

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

Arnd, Thomas,

Thanks for your valuable input and for your patience.

I'm attaching yet another proposal for this clock driver. I've 
flattened the .dts and ensured register access protection. I've also added 
one more clock source (osc0er) and clock gate to it.

Can you comment this one too?

On Fri, 3 Jul 2015, Thomas Gleixner wrote:

> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>
>>> I wonder if you could move out the fixed rate clocks into their own
>>> nodes. Are they actually controlled by the same block? If they are
>>> just fixed, you can use the normal binding for fixed rate clocks
>>> and only describe the clocks that are related to the driver.
>>
>> In my view having these clocks grouped together looks more convincing. After
>> all, they all share the same I/O regs in order to read configuration.
>
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.
>
> Thanks,
>
> 	tglx
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 19961 bytes --]

From e05dcb772d47e4473914ac1e7703b361eb54db14 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  86 ++++
 arch/arm/boot/dts/kinetis.dtsi                     |  51 +++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 502 +++++++++++++++++++++
 4 files changed, 640 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..507f91b
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,86 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: For fixed rate clocks, two address ranges:
+	- one for the Multipurpose Clock Genetator (MCG)
+	- one for System Integration Module (SIM) register set.
+	For clock gates, one address range for System Integration Module (SIM)
+	register set.
+- clocks: single element list of parent clocks (only for non-root clocks).
+- #clock-cells: For fixed rate clocks must be <0>,
+	for clock gates must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Notice that (non-gate) clock device names must be known to Kinetis CMU drivers.
+
+Currently these are:
+
+o fixed-rate-mcgout (root)
+o fixed-rate-osc0er (root)
+o fixed-rate-cclk (fixed-rate-mcgout child)
+o fixed-rate-pclk (fixed-rate-mcgout child)
+
+Example:
+
+mcg_outclk: fixed-rate-mcgout@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	#clock-cells = <0>;
+};
+
+mcg_cclk: fixed-rate-cclk@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	clocks = <&mcg_outclk>;
+	#clock-cells = <0>;
+};
+
+mcg_pclk: fixed-rate-pclk@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	clocks = <&mcg_outclk>;
+	#clock-cells = <0>;
+};
+
+mcg_cclk_gate: cclk-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&mcg_cclk>;
+	#clock-cells = <2>;
+};
+
+mcg_pclk_gate: pclk-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&mcg_pclk>;
+	#clock-cells = <2>;
+};
+
+osc0_erclk: fixed-rate-osc0er@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	#clock-cells = <0>;
+};
+
+osc0_erclk_gate: osc0-gate@40047000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40047000 0x1100>;
+	clocks = <&osc0_erclk>;
+	#clock-cells = <2>;
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..72eb941 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,54 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		mcg_outclk: fixed-rate-mcgout@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			#clock-cells = <0>;
+		};
+
+		mcg_cclk: fixed-rate-cclk@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			clocks = <&mcg_outclk>;
+			#clock-cells = <0>;
+		};
+
+		mcg_pclk: fixed-rate-pclk@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			clocks = <&mcg_outclk>;
+			#clock-cells = <0>;
+		};
+
+		mcg_cclk_gate: cclk-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&mcg_cclk>;
+			#clock-cells = <2>;
+		};
+
+		mcg_pclk_gate: pclk-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&mcg_pclk>;
+			#clock-cells = <2>;
+		};
+
+		osc0_erclk: fixed-rate-osc0er@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			#clock-cells = <0>;
+		};
+
+		osc0_erclk_gate: osc0-gate@40047000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40047000 0x1100>;
+			clocks = <&osc0_erclk>;
+			#clock-cells = <2>;
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 63418cf..412d76b 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..8e0a0d7
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,502 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_OSC0ER,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids	id;
+	const char		*name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT,	.name = "fixed-rate-mcgout",	},
+	{ .id = KINETIS_CLK_OSC0ER,	.name = "fixed-rate-osc0er",	},
+	{ .id = KINETIS_CLK_CCLK,	.name = "fixed-rate-cclk",	},
+	{ .id = KINETIS_CLK_PCLK,	.name = "fixed-rate-pclk",	},
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+struct kinetis_scgc {
+	unsigned long paddr;
+	spinlock_t lock;
+	struct list_head scgc_list;
+};
+
+static struct list_head kinetis_scgc_list = LIST_HEAD_INIT(kinetis_scgc_list);
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return NULL;
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct kinetis_scgc *kinetis_find_scgc(unsigned long paddr)
+{
+	struct kinetis_scgc *scgc;
+
+	list_for_each_entry(scgc, &kinetis_scgc_list, scgc_list)
+		if (scgc->paddr == paddr)
+			return scgc;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	const char *clk_name;
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+	struct kinetis_scgc *scgc;
+	void __iomem *addr = KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]);
+	unsigned long paddr = virt_to_phys(addr);
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	clk_name = kinetis_of_clk_get_name(clkspec->np);
+	BUG_ON(!clk_name);
+
+	scgc = kinetis_find_scgc(paddr);
+	if (!scgc) {
+		scgc = kzalloc(sizeof(struct kinetis_scgc), GFP_KERNEL);
+		if (!scgc)
+			return ERR_PTR(-ENOMEM);
+		scgc->paddr = paddr;
+		spin_lock_init(&scgc->lock);
+
+		list_add(&scgc->scgc_list, &kinetis_scgc_list);
+	}
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+	if (!gate->clk_gate_name) {
+		kfree(gate);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name, clk_name, 0, addr,
+							idx, 0, &scgc->lock);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n", clk_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static void kinetis_of_register_clk_gate(struct device_node *np)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct kinetis_clk_gate_data *clk_gate;
+	void __iomem *sim;
+	int ret;
+
+	if (!clk_parent_name) {
+		pr_err("no clock specified for gate %s\n", np->full_name);
+		return;
+	}
+
+	sim = of_iomap(np, 0);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+							np->full_name);
+		return;
+	}
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate) {
+		iounmap(sim);
+		return;
+	}
+
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		iounmap(sim);
+		return;
+	}
+}
+
+static void kinetis_of_register_fixed_rate(struct device_node *np, u32 clk_val)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					clk_parent_name,
+					clk_parent_name ? 0 : CLK_IS_ROOT,
+					clk_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return;
+	}
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[] = { [0 ... KINETIS_CLK_NUM] = 0 };
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	unsigned long mcgout;
+	enum kinetis_clk_ids clk_id;
+	u32 clock_cells;
+
+	if (of_property_read_u32_index(np, "#clock-cells", 0, &clock_cells)) {
+		pr_err("no #clock-cells set for %s\n", np->full_name);
+		return;
+	}
+
+	/*
+	 * Handle clock gates (recognized by two clock cells)
+	 */
+	if (2 == clock_cells) {
+		kinetis_of_register_clk_gate(np);
+		return;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to map MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+
+	sim = of_iomap(np, 1);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[KINETIS_CLK_MCGOUT] = mcgout;
+	clock_val[KINETIS_CLK_OSC0ER] = KINETIS_OSC0_RATE;
+
+	clock_val[KINETIS_CLK_CCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[KINETIS_CLK_PCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	iounmap(sim);
+	iounmap(base);
+
+	for (clk_id = 0; clk_id < KINETIS_CLK_NUM; clk_id++)
+		if (!of_node_cmp(np->name, kinetis_clks[clk_id].name))
+			break;
+
+	if (KINETIS_CLK_NUM == clk_id) {
+		pr_err("unknown clock %s specified\n", np->name);
+		return;
+	}
+
+	if (!clock_val[clk_id]) {
+		pr_err("no clock rate for %s\n", np->name);
+		return;
+	}
+
+	kinetis_of_register_fixed_rate(np, clock_val[clk_id]);
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-03 17:40                   ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-03 17:40 UTC (permalink / raw)
  To: linux-arm-kernel

Arnd, Thomas,

Thanks for your valuable input and for your patience.

I'm attaching yet another proposal for this clock driver. I've 
flattened the .dts and ensured register access protection. I've also added 
one more clock source (osc0er) and clock gate to it.

Can you comment this one too?

On Fri, 3 Jul 2015, Thomas Gleixner wrote:

> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>
>>> I wonder if you could move out the fixed rate clocks into their own
>>> nodes. Are they actually controlled by the same block? If they are
>>> just fixed, you can use the normal binding for fixed rate clocks
>>> and only describe the clocks that are related to the driver.
>>
>> In my view having these clocks grouped together looks more convincing. After
>> all, they all share the same I/O regs in order to read configuration.
>
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.
>
> Thanks,
>
> 	tglx
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch
Type: text/x-diff
Size: 19961 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150703/1ae55ef7/attachment-0001.bin>

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-02 22:08                 ` Thomas Gleixner
  (?)
@ 2015-07-04 19:54                   ` Arnd Bergmann
  -1 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-04 19:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, Michael Turquette, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Kumar Gala,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > 
> > > I wonder if you could move out the fixed rate clocks into their own
> > > nodes. Are they actually controlled by the same block? If they are
> > > just fixed, you can use the normal binding for fixed rate clocks
> > > and only describe the clocks that are related to the driver.
> > 
> > In my view having these clocks grouped together looks more convincing. After
> > all, they all share the same I/O regs in order to read configuration.
> 
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.

I'd disagree with that: The clock controller is the device that owns the
registers and that should be one node in DT, as Paul's first version does.

The part I'm still struggling with is understanding how the fixed-rate
clocks are controlled through those registers. If they are indeed configured
through the registers, the name is probably wrong and should be changed
to whatever kind of non-fixed clock this is.

	Arnd

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-04 19:54                   ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-04 19:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Thomas Gleixner, Paul Osmialowski, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Jiri Slaby,
	linux-clk, Russell King, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, Michael Turquette,
	devicetree, Frank Li, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Sergei Poselenov,
	Paul Bolle, Greg Kroah-Hartman, Stephen Boyd, linux-kernel,
	Kumar Gala, dmaengine

On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > 
> > > I wonder if you could move out the fixed rate clocks into their own
> > > nodes. Are they actually controlled by the same block? If they are
> > > just fixed, you can use the normal binding for fixed rate clocks
> > > and only describe the clocks that are related to the driver.
> > 
> > In my view having these clocks grouped together looks more convincing. After
> > all, they all share the same I/O regs in order to read configuration.
> 
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.

I'd disagree with that: The clock controller is the device that owns the
registers and that should be one node in DT, as Paul's first version does.

The part I'm still struggling with is understanding how the fixed-rate
clocks are controlled through those registers. If they are indeed configured
through the registers, the name is probably wrong and should be changed
to whatever kind of non-fixed clock this is.

	Arnd

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-04 19:54                   ` Arnd Bergmann
  0 siblings, 0 replies; 140+ messages in thread
From: Arnd Bergmann @ 2015-07-04 19:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > 
> > > I wonder if you could move out the fixed rate clocks into their own
> > > nodes. Are they actually controlled by the same block? If they are
> > > just fixed, you can use the normal binding for fixed rate clocks
> > > and only describe the clocks that are related to the driver.
> > 
> > In my view having these clocks grouped together looks more convincing. After
> > all, they all share the same I/O regs in order to read configuration.
> 
> The fact that they share a register is not making them a group. That's
> just a HW design decision and you need to deal with that by protecting
> the register access, but not by trying to group them artificially at
> the functional level.

I'd disagree with that: The clock controller is the device that owns the
registers and that should be one node in DT, as Paul's first version does.

The part I'm still struggling with is understanding how the fixed-rate
clocks are controlled through those registers. If they are indeed configured
through the registers, the name is probably wrong and should be changed
to whatever kind of non-fixed clock this is.

	Arnd

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-04 19:54                   ` Arnd Bergmann
  (?)
@ 2015-07-04 21:50                     ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-04 21:50 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, Michael Turquette, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Kumar Gala,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

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

Hi Arnd,

I'm attaching excerpt from Kinetis reference manual that may make 
situation clearer.

These MCG and SIM registers are used only to determine configuration 
(clock fixed rates and clock signal origins) at run time.

Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
reading MCG registers, let me quote commit message from Emcraft git repo:

      * Determine in run-time what oscillator module (OSC0 or OSC1) is used
     as clock source for the main PLL.
      * When OSC1 is selected, assume its frequency to be 12 MHz on all
     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
     TWR-K70F120M boards).

In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
U-boot. But that's too demanding for any potential users of this BSP. So 
let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
PCLK.

In my most recent version I added OSC0ERCLK explicitly as one more root 
clock, since it is also used directly (through CG reg. 1 bit 0) by 
Freescale fec network device whose in-tree driver I'm trying to make 
usable for Kinetis.

On Sat, 4 Jul 2015, Arnd Bergmann wrote:

> On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>>
>>>> I wonder if you could move out the fixed rate clocks into their own
>>>> nodes. Are they actually controlled by the same block? If they are
>>>> just fixed, you can use the normal binding for fixed rate clocks
>>>> and only describe the clocks that are related to the driver.
>>>
>>> In my view having these clocks grouped together looks more convincing. After
>>> all, they all share the same I/O regs in order to read configuration.
>>
>> The fact that they share a register is not making them a group. That's
>> just a HW design decision and you need to deal with that by protecting
>> the register access, but not by trying to group them artificially at
>> the functional level.
>
> I'd disagree with that: The clock controller is the device that owns the
> registers and that should be one node in DT, as Paul's first version does.
>
> The part I'm still struggling with is understanding how the fixed-rate
> clocks are controlled through those registers. If they are indeed configured
> through the registers, the name is probably wrong and should be changed
> to whatever kind of non-fixed clock this is.
>
> 	Arnd
>

[-- Attachment #2: Type: IMAGE/gif, Size: 57514 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-04 21:50                     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-04 21:50 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, Michael Turquette, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Kumar Gala,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner,
	linux-arm-kernel, Sergei Poselenov, Paul Bolle,
	Greg Kroah-Hartman, Stephen Boyd, linux-kernel, Jingchang Lu,
	dmaengine

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

Hi Arnd,

I'm attaching excerpt from Kinetis reference manual that may make 
situation clearer.

These MCG and SIM registers are used only to determine configuration 
(clock fixed rates and clock signal origins) at run time.

Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
reading MCG registers, let me quote commit message from Emcraft git repo:

      * Determine in run-time what oscillator module (OSC0 or OSC1) is used
     as clock source for the main PLL.
      * When OSC1 is selected, assume its frequency to be 12 MHz on all
     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
     TWR-K70F120M boards).

In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
U-boot. But that's too demanding for any potential users of this BSP. So 
let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
PCLK.

In my most recent version I added OSC0ERCLK explicitly as one more root 
clock, since it is also used directly (through CG reg. 1 bit 0) by 
Freescale fec network device whose in-tree driver I'm trying to make 
usable for Kinetis.

On Sat, 4 Jul 2015, Arnd Bergmann wrote:

> On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>>
>>>> I wonder if you could move out the fixed rate clocks into their own
>>>> nodes. Are they actually controlled by the same block? If they are
>>>> just fixed, you can use the normal binding for fixed rate clocks
>>>> and only describe the clocks that are related to the driver.
>>>
>>> In my view having these clocks grouped together looks more convincing. After
>>> all, they all share the same I/O regs in order to read configuration.
>>
>> The fact that they share a register is not making them a group. That's
>> just a HW design decision and you need to deal with that by protecting
>> the register access, but not by trying to group them artificially at
>> the functional level.
>
> I'd disagree with that: The clock controller is the device that owns the
> registers and that should be one node in DT, as Paul's first version does.
>
> The part I'm still struggling with is understanding how the fixed-rate
> clocks are controlled through those registers. If they are indeed configured
> through the registers, the name is probably wrong and should be changed
> to whatever kind of non-fixed clock this is.
>
> 	Arnd
>

[-- Attachment #2: Type: IMAGE/gif, Size: 57514 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-04 21:50                     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-04 21:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

I'm attaching excerpt from Kinetis reference manual that may make 
situation clearer.

These MCG and SIM registers are used only to determine configuration 
(clock fixed rates and clock signal origins) at run time.

Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
reading MCG registers, let me quote commit message from Emcraft git repo:

      * Determine in run-time what oscillator module (OSC0 or OSC1) is used
     as clock source for the main PLL.
      * When OSC1 is selected, assume its frequency to be 12 MHz on all
     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
     TWR-K70F120M boards).

In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
U-boot. But that's too demanding for any potential users of this BSP. So 
let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
PCLK.

In my most recent version I added OSC0ERCLK explicitly as one more root 
clock, since it is also used directly (through CG reg. 1 bit 0) by 
Freescale fec network device whose in-tree driver I'm trying to make 
usable for Kinetis.

On Sat, 4 Jul 2015, Arnd Bergmann wrote:

> On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>>>
>>>> I wonder if you could move out the fixed rate clocks into their own
>>>> nodes. Are they actually controlled by the same block? If they are
>>>> just fixed, you can use the normal binding for fixed rate clocks
>>>> and only describe the clocks that are related to the driver.
>>>
>>> In my view having these clocks grouped together looks more convincing. After
>>> all, they all share the same I/O regs in order to read configuration.
>>
>> The fact that they share a register is not making them a group. That's
>> just a HW design decision and you need to deal with that by protecting
>> the register access, but not by trying to group them artificially at
>> the functional level.
>
> I'd disagree with that: The clock controller is the device that owns the
> registers and that should be one node in DT, as Paul's first version does.
>
> The part I'm still struggling with is understanding how the fixed-rate
> clocks are controlled through those registers. If they are indeed configured
> through the registers, the name is probably wrong and should be changed
> to whatever kind of non-fixed clock this is.
>
> 	Arnd
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: kinetis-clkgen.gif
Type: image/gif
Size: 57514 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150704/ab0f010e/attachment-0001.gif>

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

* Re: [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
  2015-06-30 12:27   ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-05  6:45     ` Vinod Koul
  -1 siblings, 0 replies; 140+ messages in thread
From: Vinod Koul @ 2015-07-05  6:45 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Jiri Slaby, linux-clk, Russell King,
	Pawel Moll, Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig,
	Anson Huang, Michael Turquette, devicetree, Frank Li,
	Arnd Bergmann, Ian Campbell, Jingchang Lu, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel

On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
The patch title is not per subsystem semantics, pls fix that

> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
And this doesn't tell me the stuff you added/removed/fixed in current driver
to extend to Kinetis. Our changelog should tell what changed and why

Btw is this patch dependent upon the rest of the series?

>  
>  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)
please keep style changes in a separate patch

>  {
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, errirq;
>  	int ret;
>  
> -	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;
> -	}
> -
> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
> -	if (fsl_edma->errirq < 0) {
> +	errirq = platform_get_irq_byname(pdev, "edma-err");
> +	if (errirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
> -		return fsl_edma->errirq;
> +		return irq;
shouldn't this be errirq

>  	}
>  
> -	if (fsl_edma->txirq == fsl_edma->errirq) {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
> -			 return  ret;
> +	if (fsl_edma->kinetis) {
> +		int i;
> +		int irqs = of_irq_count(np);
> +
> +		if (irqs <= 1) {
> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
> +			return -EINVAL;
why not return irqs?

>  		}
> -	} else {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> +
> +		for (i = 0; i < (irqs - 1); i++) {
> +			char irq_name[32];
> +
> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
> +			irq = platform_get_irq_byname(pdev, irq_name);
> +			if (irq < 0) {
> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
> +							irq_name);
> +				return irq;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, irq,
>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> -			return  ret;
> +			if (ret) {
> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
> +							irq_name);
> +				return  ret;
> +			}
>  		}
>  
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +		ret = devm_request_irq(&pdev->dev, errirq,
> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>  		if (ret) {
>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
> -			return  ret;
> +		return  ret;
> +		}
> +	} else {
> +		irq = platform_get_irq_byname(pdev, "edma-tx");
> +		if (irq < 0) {
> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
> +			return irq;
> +		}
> +
> +		if (irq == errirq) {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +						"Can't register eDMA IRQ.\n");
> +				return  ret;
> +			}
> +		} else {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA tx IRQ.\n");
> +				return  ret;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, errirq,
> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA err IRQ.\n");
> +				return  ret;
> +			}
>  		}
>  	}
Okay here we have a bunch of changes without explanation on why these are
required and what are they supposed to do. So it is kind of very difficult to
review!

So please split these up in sequence of patches where each patch does only
ONE thing with right changelog messages

Thanks

-- 
~Vinod

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

* Re: [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-07-05  6:45     ` Vinod Koul
  0 siblings, 0 replies; 140+ messages in thread
From: Vinod Koul @ 2015-07-05  6:45 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Linus Walleij, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas Pitre, Paul Bolle, Thomas Gleixner, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
The patch title is not per subsystem semantics, pls fix that

> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
And this doesn't tell me the stuff you added/removed/fixed in current driver
to extend to Kinetis. Our changelog should tell what changed and why

Btw is this patch dependent upon the rest of the series?

>  
>  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)
please keep style changes in a separate patch

>  {
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, errirq;
>  	int ret;
>  
> -	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;
> -	}
> -
> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
> -	if (fsl_edma->errirq < 0) {
> +	errirq = platform_get_irq_byname(pdev, "edma-err");
> +	if (errirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
> -		return fsl_edma->errirq;
> +		return irq;
shouldn't this be errirq

>  	}
>  
> -	if (fsl_edma->txirq == fsl_edma->errirq) {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
> -			 return  ret;
> +	if (fsl_edma->kinetis) {
> +		int i;
> +		int irqs = of_irq_count(np);
> +
> +		if (irqs <= 1) {
> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
> +			return -EINVAL;
why not return irqs?

>  		}
> -	} else {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> +
> +		for (i = 0; i < (irqs - 1); i++) {
> +			char irq_name[32];
> +
> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
> +			irq = platform_get_irq_byname(pdev, irq_name);
> +			if (irq < 0) {
> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
> +							irq_name);
> +				return irq;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, irq,
>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> -			return  ret;
> +			if (ret) {
> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
> +							irq_name);
> +				return  ret;
> +			}
>  		}
>  
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +		ret = devm_request_irq(&pdev->dev, errirq,
> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>  		if (ret) {
>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
> -			return  ret;
> +		return  ret;
> +		}
> +	} else {
> +		irq = platform_get_irq_byname(pdev, "edma-tx");
> +		if (irq < 0) {
> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
> +			return irq;
> +		}
> +
> +		if (irq == errirq) {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +						"Can't register eDMA IRQ.\n");
> +				return  ret;
> +			}
> +		} else {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA tx IRQ.\n");
> +				return  ret;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, errirq,
> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA err IRQ.\n");
> +				return  ret;
> +			}
>  		}
>  	}
Okay here we have a bunch of changes without explanation on why these are
required and what are they supposed to do. So it is kind of very difficult to
review!

So please split these up in sequence of patches where each patch does only
ONE thing with right changelog messages

Thanks

-- 
~Vinod

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

* Re: [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-07-05  6:45     ` Vinod Koul
  0 siblings, 0 replies; 140+ messages in thread
From: Vinod Koul @ 2015-07-05  6:45 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Jiri Slaby, linux-clk, Russell King,
	Pawel Moll, Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig,
	Anson Huang, Michael Turquette, devicetree, Frank Li,
	Arnd Bergmann, Ian Campbell, Jingchang Lu, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Kumar Gala, dmaengine

On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
The patch title is not per subsystem semantics, pls fix that

> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
And this doesn't tell me the stuff you added/removed/fixed in current driver
to extend to Kinetis. Our changelog should tell what changed and why

Btw is this patch dependent upon the rest of the series?

>  
>  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)
please keep style changes in a separate patch

>  {
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, errirq;
>  	int ret;
>  
> -	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;
> -	}
> -
> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
> -	if (fsl_edma->errirq < 0) {
> +	errirq = platform_get_irq_byname(pdev, "edma-err");
> +	if (errirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
> -		return fsl_edma->errirq;
> +		return irq;
shouldn't this be errirq

>  	}
>  
> -	if (fsl_edma->txirq == fsl_edma->errirq) {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
> -			 return  ret;
> +	if (fsl_edma->kinetis) {
> +		int i;
> +		int irqs = of_irq_count(np);
> +
> +		if (irqs <= 1) {
> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
> +			return -EINVAL;
why not return irqs?

>  		}
> -	} else {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> +
> +		for (i = 0; i < (irqs - 1); i++) {
> +			char irq_name[32];
> +
> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
> +			irq = platform_get_irq_byname(pdev, irq_name);
> +			if (irq < 0) {
> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
> +							irq_name);
> +				return irq;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, irq,
>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> -			return  ret;
> +			if (ret) {
> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
> +							irq_name);
> +				return  ret;
> +			}
>  		}
>  
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +		ret = devm_request_irq(&pdev->dev, errirq,
> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>  		if (ret) {
>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
> -			return  ret;
> +		return  ret;
> +		}
> +	} else {
> +		irq = platform_get_irq_byname(pdev, "edma-tx");
> +		if (irq < 0) {
> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
> +			return irq;
> +		}
> +
> +		if (irq == errirq) {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +						"Can't register eDMA IRQ.\n");
> +				return  ret;
> +			}
> +		} else {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA tx IRQ.\n");
> +				return  ret;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, errirq,
> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA err IRQ.\n");
> +				return  ret;
> +			}
>  		}
>  	}
Okay here we have a bunch of changes without explanation on why these are
required and what are they supposed to do. So it is kind of very difficult to
review!

So please split these up in sequence of patches where each patch does only
ONE thing with right changelog messages

Thanks

-- 
~Vinod

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

* [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-07-05  6:45     ` Vinod Koul
  0 siblings, 0 replies; 140+ messages in thread
From: Vinod Koul @ 2015-07-05  6:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
The patch title is not per subsystem semantics, pls fix that

> Surprisingly small amount of work was required in order to extend already
> existing eDMA driver with the support for Kinetis SoC architecture.
And this doesn't tell me the stuff you added/removed/fixed in current driver
to extend to Kinetis. Our changelog should tell what changed and why

Btw is this patch dependent upon the rest of the series?

>  
>  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)
please keep style changes in a separate patch

>  {
> +	struct device_node *np = pdev->dev.of_node;
> +	int irq, errirq;
>  	int ret;
>  
> -	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;
> -	}
> -
> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
> -	if (fsl_edma->errirq < 0) {
> +	errirq = platform_get_irq_byname(pdev, "edma-err");
> +	if (errirq < 0) {
>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
> -		return fsl_edma->errirq;
> +		return irq;
shouldn't this be errirq

>  	}
>  
> -	if (fsl_edma->txirq == fsl_edma->errirq) {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
> -			 return  ret;
> +	if (fsl_edma->kinetis) {
> +		int i;
> +		int irqs = of_irq_count(np);
> +
> +		if (irqs <= 1) {
> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
> +			return -EINVAL;
why not return irqs?

>  		}
> -	} else {
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
> +
> +		for (i = 0; i < (irqs - 1); i++) {
> +			char irq_name[32];
> +
> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
> +			irq = platform_get_irq_byname(pdev, irq_name);
> +			if (irq < 0) {
> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
> +							irq_name);
> +				return irq;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, irq,
>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> -		if (ret) {
> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
> -			return  ret;
> +			if (ret) {
> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
> +							irq_name);
> +				return  ret;
> +			}
>  		}
>  
> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +		ret = devm_request_irq(&pdev->dev, errirq,
> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>  		if (ret) {
>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
> -			return  ret;
> +		return  ret;
> +		}
> +	} else {
> +		irq = platform_get_irq_byname(pdev, "edma-tx");
> +		if (irq < 0) {
> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
> +			return irq;
> +		}
> +
> +		if (irq == errirq) {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +						"Can't register eDMA IRQ.\n");
> +				return  ret;
> +			}
> +		} else {
> +			ret = devm_request_irq(&pdev->dev, irq,
> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA tx IRQ.\n");
> +				return  ret;
> +			}
> +
> +			ret = devm_request_irq(&pdev->dev, errirq,
> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					    "Can't register eDMA err IRQ.\n");
> +				return  ret;
> +			}
>  		}
>  	}
Okay here we have a bunch of changes without explanation on why these are
required and what are they supposed to do. So it is kind of very difficult to
review!

So please split these up in sequence of patches where each patch does only
ONE thing with right changelog messages

Thanks

-- 
~Vinod

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

* Re: [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
  2015-07-05  6:45     ` Vinod Koul
  (?)
@ 2015-07-05  9:45       ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-05  9:45 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe

Hi Vinod,

You're right, this should be separate patchset. Having patchset too big
leads to huge list of maintainers and lack of focusing on details 
(on-error return values are total mess now!).

I plan to split it into three: 1) initial support (so the proof that 
platform is living could be read only on JTAG), 2) DMA support and 3) UART 
support.

Also in my view extending this DMA driver requires acceptance of initial
platform support first - there's no point in extending this driver without
having support for a platform for which we are extending it.

Thanks,
Paul

On Sun, 5 Jul 2015, Vinod Koul wrote:

> On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
> The patch title is not per subsystem semantics, pls fix that
>
>> Surprisingly small amount of work was required in order to extend already
>> existing eDMA driver with the support for Kinetis SoC architecture.
> And this doesn't tell me the stuff you added/removed/fixed in current driver
> to extend to Kinetis. Our changelog should tell what changed and why
>
> Btw is this patch dependent upon the rest of the series?
>
>>
>>  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)
> please keep style changes in a separate patch
>
>>  {
>> +	struct device_node *np = pdev->dev.of_node;
>> +	int irq, errirq;
>>  	int ret;
>>
>> -	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;
>> -	}
>> -
>> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>> -	if (fsl_edma->errirq < 0) {
>> +	errirq = platform_get_irq_byname(pdev, "edma-err");
>> +	if (errirq < 0) {
>>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
>> -		return fsl_edma->errirq;
>> +		return irq;
> shouldn't this be errirq
>
>>  	}
>>
>> -	if (fsl_edma->txirq == fsl_edma->errirq) {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
>> -			 return  ret;
>> +	if (fsl_edma->kinetis) {
>> +		int i;
>> +		int irqs = of_irq_count(np);
>> +
>> +		if (irqs <= 1) {
>> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
>> +			return -EINVAL;
> why not return irqs?
>
>>  		}
>> -	} else {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> +
>> +		for (i = 0; i < (irqs - 1); i++) {
>> +			char irq_name[32];
>> +
>> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
>> +			irq = platform_get_irq_byname(pdev, irq_name);
>> +			if (irq < 0) {
>> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
>> +							irq_name);
>> +				return irq;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, irq,
>>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>> -			return  ret;
>> +			if (ret) {
>> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
>> +							irq_name);
>> +				return  ret;
>> +			}
>>  		}
>>
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
>> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +		ret = devm_request_irq(&pdev->dev, errirq,
>> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>>  		if (ret) {
>>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
>> -			return  ret;
>> +		return  ret;
>> +		}
>> +	} else {
>> +		irq = platform_get_irq_byname(pdev, "edma-tx");
>> +		if (irq < 0) {
>> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>> +			return irq;
>> +		}
>> +
>> +		if (irq == errirq) {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +						"Can't register eDMA IRQ.\n");
>> +				return  ret;
>> +			}
>> +		} else {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA tx IRQ.\n");
>> +				return  ret;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, errirq,
>> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA err IRQ.\n");
>> +				return  ret;
>> +			}
>>  		}
>>  	}
> Okay here we have a bunch of changes without explanation on why these are
> required and what are they supposed to do. So it is kind of very difficult to
> review!
>
> So please split these up in sequence of patches where each patch does only
> ONE thing with right changelog messages
>
> Thanks
>
> -- 
> ~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] 140+ messages in thread

* Re: [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-07-05  9:45       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-05  9:45 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe Kleine-Koenig, Anson Huang, Frank Li, Jingchang Lu,
	Rob Herring, Yuri Tikhonov, Sergei Poselenov, Alexander Potashev

Hi Vinod,

You're right, this should be separate patchset. Having patchset too big
leads to huge list of maintainers and lack of focusing on details 
(on-error return values are total mess now!).

I plan to split it into three: 1) initial support (so the proof that 
platform is living could be read only on JTAG), 2) DMA support and 3) UART 
support.

Also in my view extending this DMA driver requires acceptance of initial
platform support first - there's no point in extending this driver without
having support for a platform for which we are extending it.

Thanks,
Paul

On Sun, 5 Jul 2015, Vinod Koul wrote:

> On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
> The patch title is not per subsystem semantics, pls fix that
>
>> Surprisingly small amount of work was required in order to extend already
>> existing eDMA driver with the support for Kinetis SoC architecture.
> And this doesn't tell me the stuff you added/removed/fixed in current driver
> to extend to Kinetis. Our changelog should tell what changed and why
>
> Btw is this patch dependent upon the rest of the series?
>
>>
>>  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)
> please keep style changes in a separate patch
>
>>  {
>> +	struct device_node *np = pdev->dev.of_node;
>> +	int irq, errirq;
>>  	int ret;
>>
>> -	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;
>> -	}
>> -
>> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>> -	if (fsl_edma->errirq < 0) {
>> +	errirq = platform_get_irq_byname(pdev, "edma-err");
>> +	if (errirq < 0) {
>>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
>> -		return fsl_edma->errirq;
>> +		return irq;
> shouldn't this be errirq
>
>>  	}
>>
>> -	if (fsl_edma->txirq == fsl_edma->errirq) {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
>> -			 return  ret;
>> +	if (fsl_edma->kinetis) {
>> +		int i;
>> +		int irqs = of_irq_count(np);
>> +
>> +		if (irqs <= 1) {
>> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
>> +			return -EINVAL;
> why not return irqs?
>
>>  		}
>> -	} else {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> +
>> +		for (i = 0; i < (irqs - 1); i++) {
>> +			char irq_name[32];
>> +
>> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
>> +			irq = platform_get_irq_byname(pdev, irq_name);
>> +			if (irq < 0) {
>> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
>> +							irq_name);
>> +				return irq;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, irq,
>>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>> -			return  ret;
>> +			if (ret) {
>> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
>> +							irq_name);
>> +				return  ret;
>> +			}
>>  		}
>>
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
>> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +		ret = devm_request_irq(&pdev->dev, errirq,
>> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>>  		if (ret) {
>>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
>> -			return  ret;
>> +		return  ret;
>> +		}
>> +	} else {
>> +		irq = platform_get_irq_byname(pdev, "edma-tx");
>> +		if (irq < 0) {
>> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>> +			return irq;
>> +		}
>> +
>> +		if (irq == errirq) {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +						"Can't register eDMA IRQ.\n");
>> +				return  ret;
>> +			}
>> +		} else {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA tx IRQ.\n");
>> +				return  ret;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, errirq,
>> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA err IRQ.\n");
>> +				return  ret;
>> +			}
>>  		}
>>  	}
> Okay here we have a bunch of changes without explanation on why these are
> required and what are they supposed to do. So it is kind of very difficult to
> review!
>
> So please split these up in sequence of patches where each patch does only
> ONE thing with right changelog messages
>
> Thanks
>
> -- 
> ~Vinod
>

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

* [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support Kinetis SoC
@ 2015-07-05  9:45       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-05  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vinod,

You're right, this should be separate patchset. Having patchset too big
leads to huge list of maintainers and lack of focusing on details 
(on-error return values are total mess now!).

I plan to split it into three: 1) initial support (so the proof that 
platform is living could be read only on JTAG), 2) DMA support and 3) UART 
support.

Also in my view extending this DMA driver requires acceptance of initial
platform support first - there's no point in extending this driver without
having support for a platform for which we are extending it.

Thanks,
Paul

On Sun, 5 Jul 2015, Vinod Koul wrote:

> On Tue, Jun 30, 2015 at 02:27:27PM +0200, Paul Osmialowski wrote:
> The patch title is not per subsystem semantics, pls fix that
>
>> Surprisingly small amount of work was required in order to extend already
>> existing eDMA driver with the support for Kinetis SoC architecture.
> And this doesn't tell me the stuff you added/removed/fixed in current driver
> to extend to Kinetis. Our changelog should tell what changed and why
>
> Btw is this patch dependent upon the rest of the series?
>
>>
>>  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)
> please keep style changes in a separate patch
>
>>  {
>> +	struct device_node *np = pdev->dev.of_node;
>> +	int irq, errirq;
>>  	int ret;
>>
>> -	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;
>> -	}
>> -
>> -	fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
>> -	if (fsl_edma->errirq < 0) {
>> +	errirq = platform_get_irq_byname(pdev, "edma-err");
>> +	if (errirq < 0) {
>>  		dev_err(&pdev->dev, "Can't get edma-err irq.\n");
>> -		return fsl_edma->errirq;
>> +		return irq;
> shouldn't this be errirq
>
>>  	}
>>
>> -	if (fsl_edma->txirq == fsl_edma->errirq) {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> -				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
>> -			 return  ret;
>> +	if (fsl_edma->kinetis) {
>> +		int i;
>> +		int irqs = of_irq_count(np);
>> +
>> +		if (irqs <= 1) {
>> +			dev_err(&pdev->dev, "Wrong eDMA irq count %d\n", irqs);
>> +			return -EINVAL;
> why not return irqs?
>
>>  		}
>> -	} else {
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
>> +
>> +		for (i = 0; i < (irqs - 1); i++) {
>> +			char irq_name[32];
>> +
>> +			sprintf(irq_name, "edma-tx-%d,%d", i, 16 + i);
>> +			irq = platform_get_irq_byname(pdev, irq_name);
>> +			if (irq < 0) {
>> +				dev_err(&pdev->dev, "Can't get %s irq.\n",
>> +							irq_name);
>> +				return irq;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, irq,
>>  				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> -		if (ret) {
>> -			dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
>> -			return  ret;
>> +			if (ret) {
>> +				dev_err(&pdev->dev, "Can't register %s IRQ.\n",
>> +							irq_name);
>> +				return  ret;
>> +			}
>>  		}
>>
>> -		ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
>> -				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +		ret = devm_request_irq(&pdev->dev, errirq,
>> +			fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>>  		if (ret) {
>>  			dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
>> -			return  ret;
>> +		return  ret;
>> +		}
>> +	} else {
>> +		irq = platform_get_irq_byname(pdev, "edma-tx");
>> +		if (irq < 0) {
>> +			dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
>> +			return irq;
>> +		}
>> +
>> +		if (irq == errirq) {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +						"Can't register eDMA IRQ.\n");
>> +				return  ret;
>> +			}
>> +		} else {
>> +			ret = devm_request_irq(&pdev->dev, irq,
>> +				fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA tx IRQ.\n");
>> +				return  ret;
>> +			}
>> +
>> +			ret = devm_request_irq(&pdev->dev, errirq,
>> +				fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
>> +			if (ret) {
>> +				dev_err(&pdev->dev,
>> +					    "Can't register eDMA err IRQ.\n");
>> +				return  ret;
>> +			}
>>  		}
>>  	}
> Okay here we have a bunch of changes without explanation on why these are
> required and what are they supposed to do. So it is kind of very difficult to
> review!
>
> So please split these up in sequence of patches where each patch does only
> ONE thing with right changelog messages
>
> Thanks
>
> -- 
> ~Vinod
>

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-06-30 20:43         ` Arnd Bergmann
  (?)
  (?)
@ 2015-07-05 14:39           ` Rob Herring
  -1 siblings, 0 replies; 140+ messages in thread
From: Rob Herring @ 2015-07-05 14:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Linus Walleij, Mark Rutland, Michael Turquette,
	Pawel Moll, Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmaengine-u79uwXL29TY76Z2rM5mHXA

On Tue, Jun 30, 2015 at 3:43 PM, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>

>>  / {
>> +     aliases {
>> +             pit0 = &pit0;
>> +             pit1 = &pit1;
>> +             pit2 = &pit2;
>> +             pit3 = &pit3;
>> +     };
>> +
>>       soc {
>> +             pit@40037000 {
>> +                     compatible = "fsl,kinetis-pit-timer";
>> +                     reg = <0x40037000 0x100>;
>> +                     clocks = <&mcg_pclk_gate 5 23>;
>> +                     #address-cells = <1>;
>> +                     #size-cells = <1>;
>> +                     ranges;
>> +
>> +                     pit0: timer@40037100 {
>> +                             reg = <0x40037100 0x10>;
>> +                             interrupts = <68>;
>> +                             status = "disabled";
>> +                     };
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?

Yes, don't use aliases. If you really need a specific timer to be used
then there must be some feature it has or doesn't have (e.g. always
on, output compare pin, specific clock, etc.) Put those those
properties in DT if that is the case. See OMAP timers for a complex
example of this.

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-05 14:39           ` Rob Herring
  0 siblings, 0 replies; 140+ messages in thread
From: Rob Herring @ 2015-07-05 14:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

On Tue, Jun 30, 2015 at 3:43 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>

>>  / {
>> +     aliases {
>> +             pit0 = &pit0;
>> +             pit1 = &pit1;
>> +             pit2 = &pit2;
>> +             pit3 = &pit3;
>> +     };
>> +
>>       soc {
>> +             pit@40037000 {
>> +                     compatible = "fsl,kinetis-pit-timer";
>> +                     reg = <0x40037000 0x100>;
>> +                     clocks = <&mcg_pclk_gate 5 23>;
>> +                     #address-cells = <1>;
>> +                     #size-cells = <1>;
>> +                     ranges;
>> +
>> +                     pit0: timer@40037100 {
>> +                             reg = <0x40037100 0x10>;
>> +                             interrupts = <68>;
>> +                             status = "disabled";
>> +                     };
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?

Yes, don't use aliases. If you really need a specific timer to be used
then there must be some feature it has or doesn't have (e.g. always
on, output compare pin, specific clock, etc.) Put those those
properties in DT if that is the case. See OMAP timers for a complex
example of this.

Rob

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-05 14:39           ` Rob Herring
  0 siblings, 0 replies; 140+ messages in thread
From: Rob Herring @ 2015-07-05 14:39 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Paul Osmialowski, Greg Kroah-Hartman,
	Ian Campbell, Jiri Slaby, Kumar Gala, Linus Walleij,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel, linux-clk,
	linux-gpio, linux-serial, devicetree, dmaengine, Nicolas Pitre,
	Sergei Poselenov, Paul Bolle, Jingchang Lu, Yuri Tikhonov,
	Rob Herring, Geert Uytterhoeven, Uwe Kleine-Koenig,
	Alexander Potashev, Frank Li, Thomas Gleixner, Anson Huang

On Tue, Jun 30, 2015 at 3:43 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>

>>  / {
>> +     aliases {
>> +             pit0 = &pit0;
>> +             pit1 = &pit1;
>> +             pit2 = &pit2;
>> +             pit3 = &pit3;
>> +     };
>> +
>>       soc {
>> +             pit@40037000 {
>> +                     compatible = "fsl,kinetis-pit-timer";
>> +                     reg = <0x40037000 0x100>;
>> +                     clocks = <&mcg_pclk_gate 5 23>;
>> +                     #address-cells = <1>;
>> +                     #size-cells = <1>;
>> +                     ranges;
>> +
>> +                     pit0: timer@40037100 {
>> +                             reg = <0x40037100 0x10>;
>> +                             interrupts = <68>;
>> +                             status = "disabled";
>> +                     };
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?

Yes, don't use aliases. If you really need a specific timer to be used
then there must be some feature it has or doesn't have (e.g. always
on, output compare pin, specific clock, etc.) Put those those
properties in DT if that is the case. See OMAP timers for a complex
example of this.

Rob

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

* [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-05 14:39           ` Rob Herring
  0 siblings, 0 replies; 140+ messages in thread
From: Rob Herring @ 2015-07-05 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 30, 2015 at 3:43 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 30 June 2015 14:27:25 Paul Osmialowski wrote:
>

>>  / {
>> +     aliases {
>> +             pit0 = &pit0;
>> +             pit1 = &pit1;
>> +             pit2 = &pit2;
>> +             pit3 = &pit3;
>> +     };
>> +
>>       soc {
>> +             pit at 40037000 {
>> +                     compatible = "fsl,kinetis-pit-timer";
>> +                     reg = <0x40037000 0x100>;
>> +                     clocks = <&mcg_pclk_gate 5 23>;
>> +                     #address-cells = <1>;
>> +                     #size-cells = <1>;
>> +                     ranges;
>> +
>> +                     pit0: timer at 40037100 {
>> +                             reg = <0x40037100 0x10>;
>> +                             interrupts = <68>;
>> +                             status = "disabled";
>> +                     };
>
> I don't think it's necessary to have both an alias
> and a label here. What do you use the alias for?

Yes, don't use aliases. If you really need a specific timer to be used
then there must be some feature it has or doesn't have (e.g. always
on, output compare pin, specific clock, etc.) Put those those
properties in DT if that is the case. See OMAP timers for a complex
example of this.

Rob

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-04 21:50                     ` Paul Osmialowski
  (?)
@ 2015-07-06 20:57                       ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-06 20:57 UTC (permalink / raw)
  To: Arnd Bergmann, Thomas Gleixner
  Cc: Paul Osmialowski, linux-arm-kernel, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Jiri Slaby,
	linux-clk, Russell King, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, Michael Turquette,
	devicetree, Frank Li, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio

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

Hi Guys,

Let me share with you one more approach. I moved clocks back to 
sub-devices, so sharing the same resources (registers) is more obvious 
again. I like it better than previous approach. Can you look at this, 
please?

On Sat, 4 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> I'm attaching excerpt from Kinetis reference manual that may make situation 
> clearer.
>
> These MCG and SIM registers are used only to determine configuration (clock 
> fixed rates and clock signal origins) at run time.
>
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
>
>     * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>     as clock source for the main PLL.
>     * When OSC1 is selected, assume its frequency to be 12 MHz on all
>     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>     TWR-K70F120M boards).
>
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and PCLK.
>
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by Freescale 
> fec network device whose in-tree driver I'm trying to make usable for 
> Kinetis.
>
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
>
>>  On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> >  On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> > >  On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>> > > 
>> > > >  I wonder if you could move out the fixed rate clocks into their own
>> > > >  nodes. Are they actually controlled by the same block? If they are
>> > > >  just fixed, you can use the normal binding for fixed rate clocks
>> > > >  and only describe the clocks that are related to the driver.
>> > > 
>> > >  In my view having these clocks grouped together looks more convincing. 
>> > >  After
>> > >  all, they all share the same I/O regs in order to read configuration.
>> > 
>> >  The fact that they share a register is not making them a group. That's
>> >  just a HW design decision and you need to deal with that by protecting
>> >  the register access, but not by trying to group them artificially at
>> >  the functional level.
>>
>>  I'd disagree with that: The clock controller is the device that owns the
>>  registers and that should be one node in DT, as Paul's first version does.
>>
>>  The part I'm still struggling with is understanding how the fixed-rate
>>  clocks are controlled through those registers. If they are indeed
>>  configured
>>  through the registers, the name is probably wrong and should be changed
>>  to whatever kind of non-fixed clock this is.
>>
>>   Arnd
>> 
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 20061 bytes --]

From 273fdc022a44e2c4ac94a8bc070dd42a8f299215 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  82 ++++
 arch/arm/boot/dts/kinetis.dtsi                     |  43 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 532 +++++++++++++++++++++
 4 files changed, 658 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..d7c4ebf
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,82 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges:
+	- "mcg" for the Multipurpose Clock Genetator (MCG) register set.
+	- "sim" for System Integration Module (SIM) register set.
+- reg-names: Should name the address ranges ("mcg" and "sim" respectively).
+
+A set of clock sub-devices should be also provided. Each sub-device should be
+a fixed-rate clock or a clock gate.
+
+Required properties for sub-devices:
+- clocks: single element list of parent clocks (only for non-root clocks).
+- #clock-cells: For fixed rate clocks must be <0>,
+		for clock gates must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Notice that (non-gate) clock device names must be known to Kinetis CMU drivers.
+
+Currently known names are:
+
+o fixed-rate-mcgout (root)
+o fixed-rate-osc0er (root)
+o fixed-rate-cclk (fixed-rate-mcgout child)
+o fixed-rate-pclk (fixed-rate-mcgout child)
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	reg-names = "mcg", "sim";
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		clocks = <&mcg_outclk>;
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		clocks = <&mcg_outclk>;
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		clocks = <&mcg_cclk>;
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		clocks = <&mcg_pclk>;
+		#clock-cells = <2>;
+	};
+
+	osc0_erclk: fixed-rate-osc0er {
+		#clock-cells = <0>;
+	};
+
+	osc0_erclk_gate: osc0-gate {
+		clocks = <&osc0_erclk>;
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..ad58168 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,46 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			reg-names = "mcg", "sim";
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				clocks = <&mcg_outclk>;
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				clocks = <&mcg_outclk>;
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				clocks = <&mcg_cclk>;
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				clocks = <&mcg_pclk>;
+				#clock-cells = <2>;
+			};
+
+			osc0_erclk: fixed-rate-osc0er {
+				#clock-cells = <0>;
+			};
+
+			osc0_erclk_gate: osc0-gate {
+				clocks = <&osc0_erclk>;
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c4cf075..0d48167 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..d23153d
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,532 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_OSC0ER,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids	id;
+	const char		*name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT,	.name = "fixed-rate-mcgout",	},
+	{ .id = KINETIS_CLK_OSC0ER,	.name = "fixed-rate-osc0er",	},
+	{ .id = KINETIS_CLK_CCLK,	.name = "fixed-rate-cclk",	},
+	{ .id = KINETIS_CLK_PCLK,	.name = "fixed-rate-pclk",	},
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+struct kinetis_scgc {
+	unsigned long paddr;
+	spinlock_t lock;
+	struct list_head scgc_list;
+};
+
+static struct list_head kinetis_scgc_list = LIST_HEAD_INIT(kinetis_scgc_list);
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return NULL;
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct kinetis_scgc *kinetis_find_scgc(unsigned long paddr)
+{
+	struct kinetis_scgc *scgc;
+
+	list_for_each_entry(scgc, &kinetis_scgc_list, scgc_list)
+		if (scgc->paddr == paddr)
+			return scgc;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	const char *clk_name;
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+	struct kinetis_scgc *scgc;
+	void __iomem *addr = KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]);
+	unsigned long paddr = virt_to_phys(addr);
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	clk_name = kinetis_of_clk_get_name(clkspec->np);
+	BUG_ON(!clk_name);
+
+	scgc = kinetis_find_scgc(paddr);
+	if (!scgc) {
+		scgc = kzalloc(sizeof(struct kinetis_scgc), GFP_KERNEL);
+		if (!scgc)
+			return ERR_PTR(-ENOMEM);
+		scgc->paddr = paddr;
+		spin_lock_init(&scgc->lock);
+
+		list_add(&scgc->scgc_list, &kinetis_scgc_list);
+	}
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+	if (!gate->clk_gate_name) {
+		kfree(gate);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name, clk_name, 0, addr,
+							idx, 0, &scgc->lock);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n", clk_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static void kinetis_of_register_clk_gate(struct device_node *np)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct kinetis_clk_gate_data *clk_gate;
+	void __iomem *sim;
+	int ret;
+
+	if (!clk_parent_name) {
+		pr_err("no clock specified for gate %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_property_match_string(np->parent, "reg-names", "sim");
+	if (ret < 0) {
+		pr_err("failed to get SIM address range for %s\n",
+							np->parent->full_name);
+		return;
+	}
+	sim = of_iomap(np->parent, ret);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+							np->parent->full_name);
+		return;
+	}
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate) {
+		iounmap(sim);
+		return;
+	}
+
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		iounmap(sim);
+		return;
+	}
+}
+
+static void kinetis_of_register_fixed_rate(struct device_node *np, u32 clk_val)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					clk_parent_name,
+					clk_parent_name ? 0 : CLK_IS_ROOT,
+					clk_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return;
+	}
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[] = { [0 ... KINETIS_CLK_NUM] = 0 };
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	int ret;
+	unsigned long mcgout;
+	enum kinetis_clk_ids clk_id;
+	u32 clock_cells;
+	struct device_node *child;
+
+	ret = of_property_match_string(np, "reg-names", "mcg");
+	if (ret < 0) {
+		pr_err("failed to get MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+	base = of_iomap(np, ret);
+	if (!base) {
+		pr_err("failed to map MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+
+	ret = of_property_match_string(np, "reg-names", "sim");
+	if (ret < 0) {
+		pr_err("failed to get SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+	sim = of_iomap(np, ret);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[KINETIS_CLK_MCGOUT] = mcgout;
+	clock_val[KINETIS_CLK_OSC0ER] = KINETIS_OSC0_RATE;
+
+	clock_val[KINETIS_CLK_CCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[KINETIS_CLK_PCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	iounmap(sim);
+	iounmap(base);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		clock_cells = 0;
+		if (of_property_read_u32_index(child, "#clock-cells", 0,
+							&clock_cells)) {
+			pr_err("no #clock-cells set for %s\n",
+							child->full_name);
+			continue;
+		}
+
+		/*
+		 * Handle clock gates (recognized by two clock cells)
+		 */
+		if (2 == clock_cells) {
+			kinetis_of_register_clk_gate(child);
+			continue;
+		}
+
+		for (clk_id = 0; clk_id < KINETIS_CLK_NUM; clk_id++)
+			if (!of_node_cmp(child->name,
+					    kinetis_clks[clk_id].name))
+				break;
+
+		if (KINETIS_CLK_NUM == clk_id) {
+			pr_err("unknown clock %s specified\n", child->name);
+			continue;
+		}
+
+		if (!clock_val[clk_id]) {
+			pr_err("no clock rate for %s\n", child->name);
+			continue;
+		}
+
+		kinetis_of_register_fixed_rate(child, clock_val[clk_id]);
+	}
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-06 20:57                       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-06 20:57 UTC (permalink / raw)
  To: Arnd Bergmann, Thomas Gleixner
  Cc: Paul Osmialowski, linux-arm-kernel, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Jiri Slaby,
	linux-clk, Russell King, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, Michael Turquette,
	devicetree, Frank Li, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Sergei Poselenov,
	Paul Bolle, Greg Kroah-Hartman, Stephen Boyd, linux-kernel,
	Kumar Gala, dmaengine

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

Hi Guys,

Let me share with you one more approach. I moved clocks back to 
sub-devices, so sharing the same resources (registers) is more obvious 
again. I like it better than previous approach. Can you look at this, 
please?

On Sat, 4 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> I'm attaching excerpt from Kinetis reference manual that may make situation 
> clearer.
>
> These MCG and SIM registers are used only to determine configuration (clock 
> fixed rates and clock signal origins) at run time.
>
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
>
>     * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>     as clock source for the main PLL.
>     * When OSC1 is selected, assume its frequency to be 12 MHz on all
>     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>     TWR-K70F120M boards).
>
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and PCLK.
>
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by Freescale 
> fec network device whose in-tree driver I'm trying to make usable for 
> Kinetis.
>
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
>
>>  On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> >  On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> > >  On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>> > > 
>> > > >  I wonder if you could move out the fixed rate clocks into their own
>> > > >  nodes. Are they actually controlled by the same block? If they are
>> > > >  just fixed, you can use the normal binding for fixed rate clocks
>> > > >  and only describe the clocks that are related to the driver.
>> > > 
>> > >  In my view having these clocks grouped together looks more convincing. 
>> > >  After
>> > >  all, they all share the same I/O regs in order to read configuration.
>> > 
>> >  The fact that they share a register is not making them a group. That's
>> >  just a HW design decision and you need to deal with that by protecting
>> >  the register access, but not by trying to group them artificially at
>> >  the functional level.
>>
>>  I'd disagree with that: The clock controller is the device that owns the
>>  registers and that should be one node in DT, as Paul's first version does.
>>
>>  The part I'm still struggling with is understanding how the fixed-rate
>>  clocks are controlled through those registers. If they are indeed
>>  configured
>>  through the registers, the name is probably wrong and should be changed
>>  to whatever kind of non-fixed clock this is.
>>
>>   Arnd
>> 
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/x-diff; name=0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch, Size: 20061 bytes --]

From 273fdc022a44e2c4ac94a8bc070dd42a8f299215 Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawelo@king.net.pl>
Date: Mon, 29 Jun 2015 20:58:55 +0200
Subject: [PATCH 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC

Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.

Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
---
 .../devicetree/bindings/clock/kinetis-clock.txt    |  82 ++++
 arch/arm/boot/dts/kinetis.dtsi                     |  43 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-kinetis.c                          | 532 +++++++++++++++++++++
 4 files changed, 658 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/kinetis-clock.txt
 create mode 100644 drivers/clk/clk-kinetis.c

diff --git a/Documentation/devicetree/bindings/clock/kinetis-clock.txt b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
new file mode 100644
index 0000000..d7c4ebf
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/kinetis-clock.txt
@@ -0,0 +1,82 @@
+* Clock bindings for Freescale Kinetis SoC
+
+Required properties:
+- compatible: Should be "fsl,kinetis-cmu".
+- reg: Two address ranges:
+	- "mcg" for the Multipurpose Clock Genetator (MCG) register set.
+	- "sim" for System Integration Module (SIM) register set.
+- reg-names: Should name the address ranges ("mcg" and "sim" respectively).
+
+A set of clock sub-devices should be also provided. Each sub-device should be
+a fixed-rate clock or a clock gate.
+
+Required properties for sub-devices:
+- clocks: single element list of parent clocks (only for non-root clocks).
+- #clock-cells: For fixed rate clocks must be <0>,
+		for clock gates must be <2> (see below).
+
+For clock gate addresses see K70 Sub-Family Reference Manual, Rev. 3 pg. 341
+and later. Notice that addresses are zero-based, so SIM_SCGC1 has address 0,
+SIM_SCGC2 has address 1 and so on. The second address component is the bit
+index.
+
+Notice that (non-gate) clock device names must be known to Kinetis CMU drivers.
+
+Currently known names are:
+
+o fixed-rate-mcgout (root)
+o fixed-rate-osc0er (root)
+o fixed-rate-cclk (fixed-rate-mcgout child)
+o fixed-rate-pclk (fixed-rate-mcgout child)
+
+Example:
+
+cmu@40064000 {
+	compatible = "fsl,kinetis-cmu";
+	reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+	reg-names = "mcg", "sim";
+
+	mcg_outclk: fixed-rate-mcgout {
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk: fixed-rate-cclk {
+		clocks = <&mcg_outclk>;
+		#clock-cells = <0>;
+	};
+
+	mcg_pclk: fixed-rate-pclk {
+		clocks = <&mcg_outclk>;
+		#clock-cells = <0>;
+	};
+
+	mcg_cclk_gate: cclk-gate {
+		clocks = <&mcg_cclk>;
+		#clock-cells = <2>;
+	};
+
+	mcg_pclk_gate: pclk-gate {
+		clocks = <&mcg_pclk>;
+		#clock-cells = <2>;
+	};
+
+	osc0_erclk: fixed-rate-osc0er {
+		#clock-cells = <0>;
+	};
+
+	osc0_erclk_gate: osc0-gate {
+		clocks = <&osc0_erclk>;
+		#clock-cells = <2>;
+	};
+};
+
+uart1: serial@4006b000 {
+	compatible = "fsl,kinetis-lpuart";
+	reg = <0x4006b000 0x1000>;
+	interrupts = <47>, <48>;
+	interrupt-names = "uart-stat", "uart-err";
+	clocks = <&mcg_cclk_gate 3 11>;
+	clock-names = "ipg";
+	dmas = <&edma 0 4>;
+	dma-names = "rx";
+};
diff --git a/arch/arm/boot/dts/kinetis.dtsi b/arch/arm/boot/dts/kinetis.dtsi
index 93d2a8a..ad58168 100644
--- a/arch/arm/boot/dts/kinetis.dtsi
+++ b/arch/arm/boot/dts/kinetis.dtsi
@@ -3,3 +3,46 @@
  *
  */
 #include "armv7-m.dtsi"
+
+/ {
+	soc {
+		cmu@40064000 {
+			compatible = "fsl,kinetis-cmu";
+			reg = <0x40064000 0x14>, <0x40047000 0x1100>;
+			reg-names = "mcg", "sim";
+
+			mcg_outclk: fixed-rate-mcgout {
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk: fixed-rate-cclk {
+				clocks = <&mcg_outclk>;
+				#clock-cells = <0>;
+			};
+
+			mcg_pclk: fixed-rate-pclk {
+				clocks = <&mcg_outclk>;
+				#clock-cells = <0>;
+			};
+
+			mcg_cclk_gate: cclk-gate {
+				clocks = <&mcg_cclk>;
+				#clock-cells = <2>;
+			};
+
+			mcg_pclk_gate: pclk-gate {
+				clocks = <&mcg_pclk>;
+				#clock-cells = <2>;
+			};
+
+			osc0_erclk: fixed-rate-osc0er {
+				#clock-cells = <0>;
+			};
+
+			osc0_erclk_gate: osc0-gate {
+				clocks = <&osc0_erclk>;
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c4cf075..0d48167 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..d23153d
--- /dev/null
+++ b/drivers/clk/clk-kinetis.c
@@ -0,0 +1,532 @@
+/*
+ * 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/io.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+enum kinetis_clk_ids {
+	KINETIS_CLK_MCGOUT = 0,
+	KINETIS_CLK_OSC0ER,
+	KINETIS_CLK_CCLK,
+	KINETIS_CLK_PCLK,
+	KINETIS_CLK_NUM
+};
+
+static const struct {
+	enum kinetis_clk_ids	id;
+	const char		*name;
+} kinetis_clks[KINETIS_CLK_NUM] = {
+	{ .id = KINETIS_CLK_MCGOUT,	.name = "fixed-rate-mcgout",	},
+	{ .id = KINETIS_CLK_OSC0ER,	.name = "fixed-rate-osc0er",	},
+	{ .id = KINETIS_CLK_CCLK,	.name = "fixed-rate-cclk",	},
+	{ .id = KINETIS_CLK_PCLK,	.name = "fixed-rate-pclk",	},
+};
+
+/*
+ * 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 */
+
+#define KINETIS_SIM_CG_NUMREGS	7
+
+/*
+ * 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 */
+};
+#define KINETIS_SIM_PTR(base, reg) \
+	(&(((struct kinetis_sim_regs *)(base))->reg))
+
+/*
+ * 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)
+
+/*
+ * 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))
+
+struct kinetis_clk_gate {
+	const char *clk_gate_name;
+	struct clk *clk;
+	u32 reg;
+	u32 idx;
+	struct list_head clk_list;
+};
+
+struct kinetis_clk_gate_data {
+	void __iomem *sim;
+	struct list_head clk_gate_list;
+};
+
+struct kinetis_scgc {
+	unsigned long paddr;
+	spinlock_t lock;
+	struct list_head scgc_list;
+};
+
+static struct list_head kinetis_scgc_list = LIST_HEAD_INIT(kinetis_scgc_list);
+
+static const char *kinetis_of_clk_get_name(struct device_node *np)
+{
+	struct of_phandle_args clkspec;
+	int ret;
+	const char *retval;
+
+	ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+					&clkspec);
+	if (ret)
+		return NULL;
+
+	retval = clkspec.np->full_name;
+
+	of_node_put(clkspec.np);
+
+	return retval;
+}
+
+static struct clk *kinetis_find_clk_gate(
+		struct kinetis_clk_gate_data *clk_gate_data, u32 reg, u32 idx)
+{
+	struct kinetis_clk_gate *gate;
+
+	list_for_each_entry(gate, &clk_gate_data->clk_gate_list, clk_list)
+		if ((gate->reg == reg) && (gate->idx == idx))
+			return gate->clk;
+
+	return NULL;
+}
+
+static struct kinetis_scgc *kinetis_find_scgc(unsigned long paddr)
+{
+	struct kinetis_scgc *scgc;
+
+	list_for_each_entry(scgc, &kinetis_scgc_list, scgc_list)
+		if (scgc->paddr == paddr)
+			return scgc;
+
+	return NULL;
+}
+
+static struct clk *kinetis_clk_gate_get(struct of_phandle_args *clkspec,
+					void *data)
+{
+	const char *clk_name;
+	struct kinetis_clk_gate_data *clk_gate_data = data;
+	struct kinetis_clk_gate *gate;
+	u32 reg = clkspec->args[0];
+	u32 idx = clkspec->args[1];
+	struct clk *clk;
+	struct kinetis_scgc *scgc;
+	void __iomem *addr = KINETIS_SIM_PTR(clk_gate_data->sim, scgc[reg]);
+	unsigned long paddr = virt_to_phys(addr);
+
+	clk = kinetis_find_clk_gate(clk_gate_data, reg, idx);
+	if (clk)
+		return clk;
+
+	clk_name = kinetis_of_clk_get_name(clkspec->np);
+	BUG_ON(!clk_name);
+
+	scgc = kinetis_find_scgc(paddr);
+	if (!scgc) {
+		scgc = kzalloc(sizeof(struct kinetis_scgc), GFP_KERNEL);
+		if (!scgc)
+			return ERR_PTR(-ENOMEM);
+		scgc->paddr = paddr;
+		spin_lock_init(&scgc->lock);
+
+		list_add(&scgc->scgc_list, &kinetis_scgc_list);
+	}
+
+	gate = kzalloc(sizeof(struct kinetis_clk_gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->clk_gate_name = kasprintf(GFP_KERNEL, "%s:%u:%u",
+				clkspec->np->full_name, reg, idx);
+	if (!gate->clk_gate_name) {
+		kfree(gate);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	clk = clk_register_gate(NULL, gate->clk_gate_name, clk_name, 0, addr,
+							idx, 0, &scgc->lock);
+	if (IS_ERR(clk)) {
+		pr_err("Cannot register gate to clock %s\n", clk_name);
+		kfree_const(gate->clk_gate_name);
+		kfree(gate);
+		return clk;
+	}
+
+	gate->clk = clk;
+	gate->reg = reg;
+	gate->idx = idx;
+
+	list_add(&gate->clk_list, &clk_gate_data->clk_gate_list);
+
+	return clk;
+}
+
+static void kinetis_of_register_clk_gate(struct device_node *np)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct kinetis_clk_gate_data *clk_gate;
+	void __iomem *sim;
+	int ret;
+
+	if (!clk_parent_name) {
+		pr_err("no clock specified for gate %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_property_match_string(np->parent, "reg-names", "sim");
+	if (ret < 0) {
+		pr_err("failed to get SIM address range for %s\n",
+							np->parent->full_name);
+		return;
+	}
+	sim = of_iomap(np->parent, ret);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+							np->parent->full_name);
+		return;
+	}
+
+	clk_gate = kzalloc(sizeof(struct kinetis_clk_gate_data), GFP_KERNEL);
+	if (!clk_gate) {
+		iounmap(sim);
+		return;
+	}
+
+	clk_gate->sim = sim;
+	INIT_LIST_HEAD(&clk_gate->clk_gate_list);
+
+	ret = of_clk_add_provider(np, kinetis_clk_gate_get, clk_gate);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		kfree(clk_gate);
+		iounmap(sim);
+		return;
+	}
+}
+
+static void kinetis_of_register_fixed_rate(struct device_node *np, u32 clk_val)
+{
+	const char *clk_parent_name = kinetis_of_clk_get_name(np);
+	struct clk *clk;
+	int ret;
+
+	clk = clk_register_fixed_rate(NULL, np->full_name,
+					clk_parent_name,
+					clk_parent_name ? 0 : CLK_IS_ROOT,
+					clk_val);
+	if (IS_ERR(clk)) {
+		pr_err("Could not register clock %s\n", np->full_name);
+		return;
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		pr_err("Could not add clock provider %s\n", np->full_name);
+		clk_unregister(clk);
+		return;
+	}
+}
+
+static void __init kinetis_mcg_init(struct device_node *np)
+{
+	const int vco_div = 2;
+	const int vdiv_min = 16;
+	u32 clock_val[] = { [0 ... KINETIS_CLK_NUM] = 0 };
+	void __iomem *base;
+	void __iomem *sim;
+	int pll_sel;
+	int osc_sel;
+	int ret;
+	unsigned long mcgout;
+	enum kinetis_clk_ids clk_id;
+	u32 clock_cells;
+	struct device_node *child;
+
+	ret = of_property_match_string(np, "reg-names", "mcg");
+	if (ret < 0) {
+		pr_err("failed to get MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+	base = of_iomap(np, ret);
+	if (!base) {
+		pr_err("failed to map MCG address range for %s\n",
+								np->full_name);
+		return;
+	}
+
+	ret = of_property_match_string(np, "reg-names", "sim");
+	if (ret < 0) {
+		pr_err("failed to get SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+	sim = of_iomap(np, ret);
+	if (!sim) {
+		pr_err("failed to map SIM address range for %s\n",
+								np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	/*
+	 * Check whether PLL0 or PLL1 is used for MCGOUTCLK
+	 */
+	pll_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLCS_MSK);
+
+	/*
+	 * Check whether OSC0 or OSC1 is used to source the main PLL
+	 */
+	if (pll_sel)
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(base, c11)) &
+				KINETIS_MCG_C11_PLLREFSEL1_MSK);
+	else
+		osc_sel = !!(ioread8(KINETIS_MCG_PTR(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 /= ((ioread8(KINETIS_MCG_PTR(base, c11)) &
+		  KINETIS_MCG_C11_PRDIV_MSK) >> KINETIS_MCG_C11_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL1 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c12)) &
+		  KINETIS_MCG_C12_VDIV1_MSK) >> KINETIS_MCG_C12_VDIV1_BITS) +
+								    vdiv_min;
+	} else {
+		/*
+		 * PLL0 internal divider (PRDIV)
+		 */
+		mcgout /= ((ioread8(KINETIS_MCG_PTR(base, c5)) &
+			KINETIS_MCG_C5_PRDIV_MSK) >>
+			KINETIS_MCG_C5_PRDIV_BITS) + 1;
+
+		/*
+		 * PLL0 multiplication factor (VDIV)
+		 */
+		mcgout *= ((ioread8(KINETIS_MCG_PTR(base, c6)) &
+			KINETIS_MCG_C6_VDIV_MSK) >>
+			KINETIS_MCG_C6_VDIV_BITS) + vdiv_min;
+	}
+
+	/*
+	 * Apply the PLL output divider
+	 */
+	mcgout /= vco_div;
+
+	clock_val[KINETIS_CLK_MCGOUT] = mcgout;
+	clock_val[KINETIS_CLK_OSC0ER] = KINETIS_OSC0_RATE;
+
+	clock_val[KINETIS_CLK_CCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV1_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV1_BITS) + 1);
+
+	/*
+	 * Peripheral (bus) clock
+	 */
+	clock_val[KINETIS_CLK_PCLK] = mcgout /
+		(((ioread32(KINETIS_SIM_PTR(sim, clkdiv1)) &
+			KINETIS_SIM_CLKDIV1_OUTDIV2_MSK) >>
+				KINETIS_SIM_CLKDIV1_OUTDIV2_BITS) + 1);
+
+	iounmap(sim);
+	iounmap(base);
+
+	for_each_child_of_node(np, child) {
+		if (!of_device_is_available(child))
+			continue;
+
+		clock_cells = 0;
+		if (of_property_read_u32_index(child, "#clock-cells", 0,
+							&clock_cells)) {
+			pr_err("no #clock-cells set for %s\n",
+							child->full_name);
+			continue;
+		}
+
+		/*
+		 * Handle clock gates (recognized by two clock cells)
+		 */
+		if (2 == clock_cells) {
+			kinetis_of_register_clk_gate(child);
+			continue;
+		}
+
+		for (clk_id = 0; clk_id < KINETIS_CLK_NUM; clk_id++)
+			if (!of_node_cmp(child->name,
+					    kinetis_clks[clk_id].name))
+				break;
+
+		if (KINETIS_CLK_NUM == clk_id) {
+			pr_err("unknown clock %s specified\n", child->name);
+			continue;
+		}
+
+		if (!clock_val[clk_id]) {
+			pr_err("no clock rate for %s\n", child->name);
+			continue;
+		}
+
+		kinetis_of_register_fixed_rate(child, clock_val[clk_id]);
+	}
+}
+
+CLK_OF_DECLARE(kinetis_mcg, "fsl,kinetis-cmu", kinetis_mcg_init);
-- 
2.3.6


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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-06 20:57                       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-06 20:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Guys,

Let me share with you one more approach. I moved clocks back to 
sub-devices, so sharing the same resources (registers) is more obvious 
again. I like it better than previous approach. Can you look at this, 
please?

On Sat, 4 Jul 2015, Paul Osmialowski wrote:

> Hi Arnd,
>
> I'm attaching excerpt from Kinetis reference manual that may make situation 
> clearer.
>
> These MCG and SIM registers are used only to determine configuration (clock 
> fixed rates and clock signal origins) at run time.
>
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
>
>     * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>     as clock source for the main PLL.
>     * When OSC1 is selected, assume its frequency to be 12 MHz on all
>     boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>     TWR-K70F120M boards).
>
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and PCLK.
>
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by Freescale 
> fec network device whose in-tree driver I'm trying to make usable for 
> Kinetis.
>
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
>
>>  On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
>> >  On Thu, 2 Jul 2015, Paul Osmialowski wrote:
>> > >  On Thu, 2 Jul 2015, Arnd Bergmann wrote:
>> > > 
>> > > >  I wonder if you could move out the fixed rate clocks into their own
>> > > >  nodes. Are they actually controlled by the same block? If they are
>> > > >  just fixed, you can use the normal binding for fixed rate clocks
>> > > >  and only describe the clocks that are related to the driver.
>> > > 
>> > >  In my view having these clocks grouped together looks more convincing. 
>> > >  After
>> > >  all, they all share the same I/O regs in order to read configuration.
>> > 
>> >  The fact that they share a register is not making them a group. That's
>> >  just a HW design decision and you need to deal with that by protecting
>> >  the register access, but not by trying to group them artificially at
>> >  the functional level.
>>
>>  I'd disagree with that: The clock controller is the device that owns the
>>  registers and that should be one node in DT, as Paul's first version does.
>>
>>  The part I'm still struggling with is understanding how the fixed-rate
>>  clocks are controlled through those registers. If they are indeed
>>  configured
>>  through the registers, the name is probably wrong and should be changed
>>  to whatever kind of non-fixed clock this is.
>>
>>   Arnd
>> 
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-arm-twr-k70f120m-clock-driver-for-Kinetis-SoC.patch
Type: text/x-diff
Size: 20061 bytes
Desc: 
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150706/1653224d/attachment-0001.bin>

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

* Re: [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
  2015-06-30 12:27   ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-14  8:55     ` Linus Walleij
  -1 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:55 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> This is a 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>

Same comments as for v1. Sorry for taking time to review,
was in the merge window and some vacation.

Yours,
Linus Walleij

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

* Re: [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-07-14  8:55     ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:55 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas Pitre, Paul Bolle, Thomas Gleixner, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> This is a 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>

Same comments as for v1. Sorry for taking time to review,
was in the merge window and some vacation.

Yours,
Linus Walleij

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

* Re: [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for Kinetis SoC
@ 2015-07-14  8:55     ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:55 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas Pitre, Paul Bolle, Thomas Gleixner, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> This is a 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>

Same comments as for v1. Sorry for taking time to review,
was in the merge window and some vacation.

Yours,
Linus Walleij

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

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

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> This is a 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>

Same comments as for v1. Sorry for taking time to review,
was in the merge window and some vacation.

Yours,
Linus Walleij

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
  2015-07-01 14:20             ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-14  8:59               ` Linus Walleij
  -1 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:59 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Thomas Gleixner, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann, Geert

On Wed, Jul 1, 2015 at 4:20 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> -               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);

Do you want to do DIV_ROUND_UP() or why is this -1 here?

Yours,
Linus Walleij

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-14  8:59               ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:59 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Thomas Gleixner, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Wed, Jul 1, 2015 at 4:20 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> -               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);

Do you want to do DIV_ROUND_UP() or why is this -1 here?

Yours,
Linus Walleij

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

* Re: [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC
@ 2015-07-14  8:59               ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  8:59 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Thomas Gleixner, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Wed, Jul 1, 2015 at 4:20 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> -               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);

Do you want to do DIV_ROUND_UP() or why is this -1 here?

Yours,
Linus Walleij

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

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

On Wed, Jul 1, 2015 at 4:20 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> -               kinetis_pit_init(kinetis_tmr, (rate / HZ) - 1);

Do you want to do DIV_ROUND_UP() or why is this -1 here?

Yours,
Linus Walleij

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-06-30 12:27   ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-14  9:03     ` Linus Walleij
  -1 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  9:03 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
(...)
> +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 */
> +};

Now there is this design pattern where you copy the datasheet
register map to a struct again.

This is not good if there is a second revision of the hardware and some
registers are shuffled around. IMO it is better to just use #defines
for register
offsets, so you can do exceptions later. Else a new hardware revision
leads to a new struct with new accessor functions etc etc.

Yours,
Linus Walleij

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-14  9:03     ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  9:03 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas Pitre, Paul Bolle, Thomas Gleixner, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
(...)
> +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 */
> +};

Now there is this design pattern where you copy the datasheet
register map to a struct again.

This is not good if there is a second revision of the hardware and some
registers are shuffled around. IMO it is better to just use #defines
for register
offsets, so you can do exceptions later. Else a new hardware revision
leads to a new struct with new accessor functions etc etc.

Yours,
Linus Walleij

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-14  9:03     ` Linus Walleij
  0 siblings, 0 replies; 140+ messages in thread
From: Linus Walleij @ 2015-07-14  9:03 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Greg Kroah-Hartman, Ian Campbell, Jiri Slaby, Kumar Gala,
	Mark Rutland, Michael Turquette, Pawel Moll, Rob Herring,
	Russell King, Stephen Boyd, Vinod Koul, linux-kernel,
	linux-arm-kernel, linux-clk, linux-gpio, linux-serial,
	devicetree, dmaengine, Arnd Bergmann, Geert Uytterhoeven,
	Nicolas Pitre, Paul Bolle, Thomas Gleixner, Uwe Kleine-Koenig,
	Anson Huang, Frank Li, Jingchang Lu, Rob Herring, Yuri Tikhonov,
	Sergei Poselenov, Alexander Potashev

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
(...)
> +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 */
> +};

Now there is this design pattern where you copy the datasheet
register map to a struct again.

This is not good if there is a second revision of the hardware and some
registers are shuffled around. IMO it is better to just use #defines
for register
offsets, so you can do exceptions later. Else a new hardware revision
leads to a new struct with new accessor functions etc etc.

Yours,
Linus Walleij

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

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

On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:

> Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
>
> Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
(...)
> +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 */
> +};

Now there is this design pattern where you copy the datasheet
register map to a struct again.

This is not good if there is a second revision of the hardware and some
registers are shuffled around. IMO it is better to just use #defines
for register
offsets, so you can do exceptions later. Else a new hardware revision
leads to a new struct with new accessor functions etc etc.

Yours,
Linus Walleij

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-14  9:03     ` Linus Walleij
  (?)
  (?)
@ 2015-07-15  7:31       ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15  7:31 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann, Geert

Hi Linus,

Thanks for all of your comments, I'll consider them during my works on the 
next iteration. However, I have doubts about this one:

On Tue, 14 Jul 2015, Linus Walleij wrote:

> On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> 
> > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> >
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> (...)
> > +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 */
> > +};
> 
> Now there is this design pattern where you copy the datasheet
> register map to a struct again.
> 
> This is not good if there is a second revision of the hardware and some
> registers are shuffled around. IMO it is better to just use #defines
> for register
> offsets, so you can do exceptions later. Else a new hardware revision
> leads to a new struct with new accessor functions etc etc.
> 

I don't see how replacing this structure with bunch of defines could make 
anyones life easier. As registers are shuffled around due to updated 
hardware revision they could be shuffled in this structure too. Doing 
this with buch of defines would require eager and careful adaptation of 
all the defines. I don't see how this could be easier.

Note that I'm not making any instances of the structure (it is used only 
for casting), so shuffling its fields around should not affect the code 
that follows.

After recent purge it is only used within this macro:

#define KINETIS_SIM_PTR(base, reg) \
        (&(((struct kinetis_sim_regs *)(base))->reg))

...and used like this:

        ioread32(KINETIS_SIM_PTR(sim, clkdiv1));

IMHO changing the struct internals does not require subsequent changes in 
any of those.

Thanks,
Paul

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15  7:31       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15  7:31 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe Kleine-Koenig, Anson Huang, Frank Li, Jingchang Lu,
	Rob Herring, Yuri Tikhonov, Sergei Poselenov, Alexander Potashev

Hi Linus,

Thanks for all of your comments, I'll consider them during my works on the 
next iteration. However, I have doubts about this one:

On Tue, 14 Jul 2015, Linus Walleij wrote:

> On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> 
> > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> >
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> (...)
> > +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 */
> > +};
> 
> Now there is this design pattern where you copy the datasheet
> register map to a struct again.
> 
> This is not good if there is a second revision of the hardware and some
> registers are shuffled around. IMO it is better to just use #defines
> for register
> offsets, so you can do exceptions later. Else a new hardware revision
> leads to a new struct with new accessor functions etc etc.
> 

I don't see how replacing this structure with bunch of defines could make 
anyones life easier. As registers are shuffled around due to updated 
hardware revision they could be shuffled in this structure too. Doing 
this with buch of defines would require eager and careful adaptation of 
all the defines. I don't see how this could be easier.

Note that I'm not making any instances of the structure (it is used only 
for casting), so shuffling its fields around should not affect the code 
that follows.

After recent purge it is only used within this macro:

#define KINETIS_SIM_PTR(base, reg) \
        (&(((struct kinetis_sim_regs *)(base))->reg))

...and used like this:

        ioread32(KINETIS_SIM_PTR(sim, clkdiv1));

IMHO changing the struct internals does not require subsequent changes in 
any of those.

Thanks,
Paul

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15  7:31       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15  7:31 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe Kleine-Koenig, Anson Huang, Frank Li, Jingchang Lu,
	Rob Herring, Yuri Tikhonov, Sergei Poselenov, Alexander Potashev

Hi Linus,

Thanks for all of your comments, I'll consider them during my works on the 
next iteration. However, I have doubts about this one:

On Tue, 14 Jul 2015, Linus Walleij wrote:

> On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> 
> > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> >
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> (...)
> > +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 */
> > +};
> 
> Now there is this design pattern where you copy the datasheet
> register map to a struct again.
> 
> This is not good if there is a second revision of the hardware and some
> registers are shuffled around. IMO it is better to just use #defines
> for register
> offsets, so you can do exceptions later. Else a new hardware revision
> leads to a new struct with new accessor functions etc etc.
> 

I don't see how replacing this structure with bunch of defines could make 
anyones life easier. As registers are shuffled around due to updated 
hardware revision they could be shuffled in this structure too. Doing 
this with buch of defines would require eager and careful adaptation of 
all the defines. I don't see how this could be easier.

Note that I'm not making any instances of the structure (it is used only 
for casting), so shuffling its fields around should not affect the code 
that follows.

After recent purge it is only used within this macro:

#define KINETIS_SIM_PTR(base, reg) \
        (&(((struct kinetis_sim_regs *)(base))->reg))

...and used like this:

        ioread32(KINETIS_SIM_PTR(sim, clkdiv1));

IMHO changing the struct internals does not require subsequent changes in 
any of those.

Thanks,
Paul

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15  7:31       ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15  7:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Linus,

Thanks for all of your comments, I'll consider them during my works on the 
next iteration. However, I have doubts about this one:

On Tue, 14 Jul 2015, Linus Walleij wrote:

> On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> 
> > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> >
> > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> (...)
> > +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 */
> > +};
> 
> Now there is this design pattern where you copy the datasheet
> register map to a struct again.
> 
> This is not good if there is a second revision of the hardware and some
> registers are shuffled around. IMO it is better to just use #defines
> for register
> offsets, so you can do exceptions later. Else a new hardware revision
> leads to a new struct with new accessor functions etc etc.
> 

I don't see how replacing this structure with bunch of defines could make 
anyones life easier. As registers are shuffled around due to updated 
hardware revision they could be shuffled in this structure too. Doing 
this with buch of defines would require eager and careful adaptation of 
all the defines. I don't see how this could be easier.

Note that I'm not making any instances of the structure (it is used only 
for casting), so shuffling its fields around should not affect the code 
that follows.

After recent purge it is only used within this macro:

#define KINETIS_SIM_PTR(base, reg) \
        (&(((struct kinetis_sim_regs *)(base))->reg))

...and used like this:

        ioread32(KINETIS_SIM_PTR(sim, clkdiv1));

IMHO changing the struct internals does not require subsequent changes in 
any of those.

Thanks,
Paul

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-15  7:31       ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-15 17:34         ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15 17:34 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann, Geert

Hi Linus,

I had some discussion with an expert here and now I see drawbacks of using 
struct for regs, I'll turn it into defines as you suggested.

On Wed, 15 Jul 2015, Paul Osmialowski wrote:

> Hi Linus,
> 
> Thanks for all of your comments, I'll consider them during my works on the 
> next iteration. However, I have doubts about this one:
> 
> On Tue, 14 Jul 2015, Linus Walleij wrote:
> 
> > On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> > 
> > > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> > >
> > > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > (...)
> > > +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 */
> > > +};
> > 
> > Now there is this design pattern where you copy the datasheet
> > register map to a struct again.
> > 
> > This is not good if there is a second revision of the hardware and some
> > registers are shuffled around. IMO it is better to just use #defines
> > for register
> > offsets, so you can do exceptions later. Else a new hardware revision
> > leads to a new struct with new accessor functions etc etc.
> > 
> 
> I don't see how replacing this structure with bunch of defines could make 
> anyones life easier. As registers are shuffled around due to updated 
> hardware revision they could be shuffled in this structure too. Doing 
> this with buch of defines would require eager and careful adaptation of 
> all the defines. I don't see how this could be easier.
> 
> Note that I'm not making any instances of the structure (it is used only 
> for casting), so shuffling its fields around should not affect the code 
> that follows.
> 
> After recent purge it is only used within this macro:
> 
> #define KINETIS_SIM_PTR(base, reg) \
>         (&(((struct kinetis_sim_regs *)(base))->reg))
> 
> ...and used like this:
> 
>         ioread32(KINETIS_SIM_PTR(sim, clkdiv1));
> 
> IMHO changing the struct internals does not require subsequent changes in 
> any of those.
> 
> Thanks,
> Paul
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15 17:34         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15 17:34 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe Kleine-Koenig, Anson Huang, Frank Li, Jingchang Lu,
	Rob Herring, Yuri Tikhonov, Sergei Poselenov, Alexander Potashev

Hi Linus,

I had some discussion with an expert here and now I see drawbacks of using 
struct for regs, I'll turn it into defines as you suggested.

On Wed, 15 Jul 2015, Paul Osmialowski wrote:

> Hi Linus,
> 
> Thanks for all of your comments, I'll consider them during my works on the 
> next iteration. However, I have doubts about this one:
> 
> On Tue, 14 Jul 2015, Linus Walleij wrote:
> 
> > On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> > 
> > > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> > >
> > > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > (...)
> > > +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 */
> > > +};
> > 
> > Now there is this design pattern where you copy the datasheet
> > register map to a struct again.
> > 
> > This is not good if there is a second revision of the hardware and some
> > registers are shuffled around. IMO it is better to just use #defines
> > for register
> > offsets, so you can do exceptions later. Else a new hardware revision
> > leads to a new struct with new accessor functions etc etc.
> > 
> 
> I don't see how replacing this structure with bunch of defines could make 
> anyones life easier. As registers are shuffled around due to updated 
> hardware revision they could be shuffled in this structure too. Doing 
> this with buch of defines would require eager and careful adaptation of 
> all the defines. I don't see how this could be easier.
> 
> Note that I'm not making any instances of the structure (it is used only 
> for casting), so shuffling its fields around should not affect the code 
> that follows.
> 
> After recent purge it is only used within this macro:
> 
> #define KINETIS_SIM_PTR(base, reg) \
>         (&(((struct kinetis_sim_regs *)(base))->reg))
> 
> ...and used like this:
> 
>         ioread32(KINETIS_SIM_PTR(sim, clkdiv1));
> 
> IMHO changing the struct internals does not require subsequent changes in 
> any of those.
> 
> Thanks,
> Paul
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15 17:34         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15 17:34 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Osmialowski, Greg Kroah-Hartman, Ian Campbell, Jiri Slaby,
	Kumar Gala, Mark Rutland, Michael Turquette, Pawel Moll,
	Rob Herring, Russell King, Stephen Boyd, Vinod Koul,
	linux-kernel, linux-arm-kernel, linux-clk, linux-gpio,
	linux-serial, devicetree, dmaengine, Arnd Bergmann,
	Geert Uytterhoeven, Nicolas Pitre, Paul Bolle, Thomas Gleixner,
	Uwe Kleine-Koenig, Anson Huang, Frank Li, Jingchang Lu,
	Rob Herring, Yuri Tikhonov, Sergei Poselenov, Alexander Potashev

Hi Linus,

I had some discussion with an expert here and now I see drawbacks of using 
struct for regs, I'll turn it into defines as you suggested.

On Wed, 15 Jul 2015, Paul Osmialowski wrote:

> Hi Linus,
> 
> Thanks for all of your comments, I'll consider them during my works on the 
> next iteration. However, I have doubts about this one:
> 
> On Tue, 14 Jul 2015, Linus Walleij wrote:
> 
> > On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> > 
> > > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> > >
> > > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > (...)
> > > +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 */
> > > +};
> > 
> > Now there is this design pattern where you copy the datasheet
> > register map to a struct again.
> > 
> > This is not good if there is a second revision of the hardware and some
> > registers are shuffled around. IMO it is better to just use #defines
> > for register
> > offsets, so you can do exceptions later. Else a new hardware revision
> > leads to a new struct with new accessor functions etc etc.
> > 
> 
> I don't see how replacing this structure with bunch of defines could make 
> anyones life easier. As registers are shuffled around due to updated 
> hardware revision they could be shuffled in this structure too. Doing 
> this with buch of defines would require eager and careful adaptation of 
> all the defines. I don't see how this could be easier.
> 
> Note that I'm not making any instances of the structure (it is used only 
> for casting), so shuffling its fields around should not affect the code 
> that follows.
> 
> After recent purge it is only used within this macro:
> 
> #define KINETIS_SIM_PTR(base, reg) \
>         (&(((struct kinetis_sim_regs *)(base))->reg))
> 
> ...and used like this:
> 
>         ioread32(KINETIS_SIM_PTR(sim, clkdiv1));
> 
> IMHO changing the struct internals does not require subsequent changes in 
> any of those.
> 
> Thanks,
> Paul
> 

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-15 17:34         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-15 17:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Linus,

I had some discussion with an expert here and now I see drawbacks of using 
struct for regs, I'll turn it into defines as you suggested.

On Wed, 15 Jul 2015, Paul Osmialowski wrote:

> Hi Linus,
> 
> Thanks for all of your comments, I'll consider them during my works on the 
> next iteration. However, I have doubts about this one:
> 
> On Tue, 14 Jul 2015, Linus Walleij wrote:
> 
> > On Tue, Jun 30, 2015 at 2:27 PM, Paul Osmialowski <pawelo@king.net.pl> wrote:
> > 
> > > Based on K70P256M150SF3RM.pdf K70 Sub-Family Reference Manual, Rev. 3.
> > >
> > > Signed-off-by: Paul Osmialowski <pawelo@king.net.pl>
> > (...)
> > > +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 */
> > > +};
> > 
> > Now there is this design pattern where you copy the datasheet
> > register map to a struct again.
> > 
> > This is not good if there is a second revision of the hardware and some
> > registers are shuffled around. IMO it is better to just use #defines
> > for register
> > offsets, so you can do exceptions later. Else a new hardware revision
> > leads to a new struct with new accessor functions etc etc.
> > 
> 
> I don't see how replacing this structure with bunch of defines could make 
> anyones life easier. As registers are shuffled around due to updated 
> hardware revision they could be shuffled in this structure too. Doing 
> this with buch of defines would require eager and careful adaptation of 
> all the defines. I don't see how this could be easier.
> 
> Note that I'm not making any instances of the structure (it is used only 
> for casting), so shuffling its fields around should not affect the code 
> that follows.
> 
> After recent purge it is only used within this macro:
> 
> #define KINETIS_SIM_PTR(base, reg) \
>         (&(((struct kinetis_sim_regs *)(base))->reg))
> 
> ...and used like this:
> 
>         ioread32(KINETIS_SIM_PTR(sim, clkdiv1));
> 
> IMHO changing the struct internals does not require subsequent changes in 
> any of those.
> 
> Thanks,
> Paul
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-04 21:50                     ` Paul Osmialowski
  (?)
  (?)
@ 2015-07-24  3:42                       ` Michael Turquette
  -1 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-24  3:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, devicetree, Paul Osmialowski,
	Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov, linux-gpio,
	Rob Herring, Thomas Gleixner

Quoting Paul Osmialowski (2015-07-04 14:50:03)
> Hi Arnd,
> 
> I'm attaching excerpt from Kinetis reference manual that may make 
> situation clearer.

Hi Paul,

Can you please post the patch in the body of the email instead of an
attachment? It makes it easier to review. Another small nitpick is that
the $SUBJECT for this patch might be better off as something like:

clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC

At least it helps me find the patch I care about when skimming the
series ;-)

> 
> These MCG and SIM registers are used only to determine configuration 
> (clock fixed rates and clock signal origins) at run time.
> 
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
> 
>       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>      as clock source for the main PLL.

According to [0] there are three options: a 32k RTC osc clock and osc0
both feed into a mux. You should model this 32k clock with the
fixed-rate binding.

>       * When OSC1 is selected, assume its frequency to be 12 MHz on all
>      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>      TWR-K70F120M boards).
> 
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> PCLK.

I'm confused. The point of device tree is to solve problems like this;
i.e. board-specific differences such as different oscillator
frequencies.

OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
can probably go in your chip-specific .dtsi as a fixed-rate clock since
it appears to mandated in the reference manual[0].

These three fixed-rate clocks are your root clock nodes. Customers only
need to worry about this if they spin a board, and then they will need
to populate the frequencies of OSC0 and OSC1 in their board-specific
.dts.

Please break clk-kinetis.c into two files:
drivers/clk/kinetis/clk-mcg.c
drivers/clk/kinetis/clk-sim.c

Below is what your binding/dts should look like:

{
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	soc: soc {
		mcg: clock-controller@40064000 {
			compatible = "fsl,kinetis-mcg";
			clock-cells = <1>;
			reg = <0x40064000 0x14>;
			clocks = <&osc0>, <&osc1>, <&rtc>;
			clock-names = "osc0", "osc1", "rtc";
		};

		sim: clock-controller@40047000 {
			compatible = "fsl,kinetis-sim";
			clock-cells = <1>;
			reg = <0x40047000 0x1100>;
			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
			clock-names = "core", "bus", "flexbus", "flash";
		};
	};

	uart0: serial@4006a000 {
		compatible = "fsl,kinetis-lpuart";
		reg = <0x4006a000 0x1000>;
		clocks = <&sim SIM_SCGC4_UART1_CLK>;
		clock-names = "gate";
	};

I removed the interrupts and dma stuff from the uart0 node for clarity.
The above is the only style of binding that I have been accepting for
some time; first declare the clock controller and establish its register
space, and then consumers can consume clocks by providing the phandle to
the controller plus an offset corresponding to a unique clock. The
clock-names property makes it really easy to use with the clkdev stuff
(e.g. clk_get()).

I've covered this before on the mailing list so here is a link
describing how the qcom bindings do it in detail:

http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>

Technically you could encode the same bits as sub-nodes of the mcg and
sim nodes, but the shared header is how the magic happens with the
driver so it's best to keep the clock controller binding small and
light.

I think this means you can also get rid of kinetis_of_clk_get_name and
kinetis_clk_gate_get but my brain is tired so I'll leave that as an
exercise to the reader.

[0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf

Regards,
Mike

> 
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by 
> Freescale fec network device whose in-tree driver I'm trying to make 
> usable for Kinetis.
> 
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> 
> > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> >>>
> >>>> I wonder if you could move out the fixed rate clocks into their own
> >>>> nodes. Are they actually controlled by the same block? If they are
> >>>> just fixed, you can use the normal binding for fixed rate clocks
> >>>> and only describe the clocks that are related to the driver.
> >>>
> >>> In my view having these clocks grouped together looks more convincing. After
> >>> all, they all share the same I/O regs in order to read configuration.
> >>
> >> The fact that they share a register is not making them a group. That's
> >> just a HW design decision and you need to deal with that by protecting
> >> the register access, but not by trying to group them artificially at
> >> the functional level.
> >
> > I'd disagree with that: The clock controller is the device that owns the
> > registers and that should be one node in DT, as Paul's first version does.
> >
> > The part I'm still struggling with is understanding how the fixed-rate
> > clocks are controlled through those registers. If they are indeed configured
> > through the registers, the name is probably wrong and should be changed
> > to whatever kind of non-fixed clock this is.
> >
> >       Arnd
> >
> 
> _______________________________________________
> 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] 140+ messages in thread

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-24  3:42                       ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-24  3:42 UTC (permalink / raw)
  To: Paul Osmialowski, Arnd Bergmann
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, devicetree, Paul Osmialowski,
	Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov, linux-gpio,
	Rob Herring, Thomas Gleixner, linux-arm-kernel, Sergei Poselenov,
	Paul Bolle, Greg Kroah-Hartman, Stephen Boyd, linux-kernel,
	Jingchang Lu, dmaengine

Quoting Paul Osmialowski (2015-07-04 14:50:03)
> Hi Arnd,
> 
> I'm attaching excerpt from Kinetis reference manual that may make 
> situation clearer.

Hi Paul,

Can you please post the patch in the body of the email instead of an
attachment? It makes it easier to review. Another small nitpick is that
the $SUBJECT for this patch might be better off as something like:

clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC

At least it helps me find the patch I care about when skimming the
series ;-)

> 
> These MCG and SIM registers are used only to determine configuration 
> (clock fixed rates and clock signal origins) at run time.
> 
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
> 
>       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>      as clock source for the main PLL.

According to [0] there are three options: a 32k RTC osc clock and osc0
both feed into a mux. You should model this 32k clock with the
fixed-rate binding.

>       * When OSC1 is selected, assume its frequency to be 12 MHz on all
>      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>      TWR-K70F120M boards).
> 
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> PCLK.

I'm confused. The point of device tree is to solve problems like this;
i.e. board-specific differences such as different oscillator
frequencies.

OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
can probably go in your chip-specific .dtsi as a fixed-rate clock since
it appears to mandated in the reference manual[0].

These three fixed-rate clocks are your root clock nodes. Customers only
need to worry about this if they spin a board, and then they will need
to populate the frequencies of OSC0 and OSC1 in their board-specific
.dts.

Please break clk-kinetis.c into two files:
drivers/clk/kinetis/clk-mcg.c
drivers/clk/kinetis/clk-sim.c

Below is what your binding/dts should look like:

{
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	soc: soc {
		mcg: clock-controller@40064000 {
			compatible = "fsl,kinetis-mcg";
			clock-cells = <1>;
			reg = <0x40064000 0x14>;
			clocks = <&osc0>, <&osc1>, <&rtc>;
			clock-names = "osc0", "osc1", "rtc";
		};

		sim: clock-controller@40047000 {
			compatible = "fsl,kinetis-sim";
			clock-cells = <1>;
			reg = <0x40047000 0x1100>;
			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
			clock-names = "core", "bus", "flexbus", "flash";
		};
	};

	uart0: serial@4006a000 {
		compatible = "fsl,kinetis-lpuart";
		reg = <0x4006a000 0x1000>;
		clocks = <&sim SIM_SCGC4_UART1_CLK>;
		clock-names = "gate";
	};

I removed the interrupts and dma stuff from the uart0 node for clarity.
The above is the only style of binding that I have been accepting for
some time; first declare the clock controller and establish its register
space, and then consumers can consume clocks by providing the phandle to
the controller plus an offset corresponding to a unique clock. The
clock-names property makes it really easy to use with the clkdev stuff
(e.g. clk_get()).

I've covered this before on the mailing list so here is a link
describing how the qcom bindings do it in detail:

http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>

Technically you could encode the same bits as sub-nodes of the mcg and
sim nodes, but the shared header is how the magic happens with the
driver so it's best to keep the clock controller binding small and
light.

I think this means you can also get rid of kinetis_of_clk_get_name and
kinetis_clk_gate_get but my brain is tired so I'll leave that as an
exercise to the reader.

[0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf

Regards,
Mike

> 
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by 
> Freescale fec network device whose in-tree driver I'm trying to make 
> usable for Kinetis.
> 
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> 
> > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> >>>
> >>>> I wonder if you could move out the fixed rate clocks into their own
> >>>> nodes. Are they actually controlled by the same block? If they are
> >>>> just fixed, you can use the normal binding for fixed rate clocks
> >>>> and only describe the clocks that are related to the driver.
> >>>
> >>> In my view having these clocks grouped together looks more convincing. After
> >>> all, they all share the same I/O regs in order to read configuration.
> >>
> >> The fact that they share a register is not making them a group. That's
> >> just a HW design decision and you need to deal with that by protecting
> >> the register access, but not by trying to group them artificially at
> >> the functional level.
> >
> > I'd disagree with that: The clock controller is the device that owns the
> > registers and that should be one node in DT, as Paul's first version does.
> >
> > The part I'm still struggling with is understanding how the fixed-rate
> > clocks are controlled through those registers. If they are indeed configured
> > through the registers, the name is probably wrong and should be changed
> > to whatever kind of non-fixed clock this is.
> >
> >       Arnd
> >
> 
> _______________________________________________
> 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] 140+ messages in thread

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-24  3:42                       ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-24  3:42 UTC (permalink / raw)
  To: Paul Osmialowski, Arnd Bergmann
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Vinod Koul, Geert Uytterhoeven, linux-serial,
	Uwe Kleine-Koenig, Anson Huang, devicetree, Paul Osmialowski,
	Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov, linux-gpio,
	Rob Herring, Thomas Gleixner, linux-arm-kernel, Sergei Poselenov,
	Paul Bolle, Greg Kroah-Hartman, Stephen Boyd, linux-kernel,
	Jingchang Lu, dmaengine

Quoting Paul Osmialowski (2015-07-04 14:50:03)
> Hi Arnd,
> =

> I'm attaching excerpt from Kinetis reference manual that may make =

> situation clearer.

Hi Paul,

Can you please post the patch in the body of the email instead of an
attachment? It makes it easier to review. Another small nitpick is that
the $SUBJECT for this patch might be better off as something like:

clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC

At least it helps me find the patch I care about when skimming the
series ;-)

> =

> These MCG and SIM registers are used only to determine configuration =

> (clock fixed rates and clock signal origins) at run time.
> =

> Namely, the real MCGOUTCLK source (in the middle) which is the parent for =

> core clock (CCLK) and peripheral clock (PCLK) is determined at run time b=
y =

> reading MCG registers, let me quote commit message from Emcraft git repo:
> =

>       * Determine in run-time what oscillator module (OSC0 or OSC1) is us=
ed
>      as clock source for the main PLL.

According to [0] there are three options: a 32k RTC osc clock and osc0
both feed into a mux. You should model this 32k clock with the
fixed-rate binding.

>       * When OSC1 is selected, assume its frequency to be 12 MHz on all
>      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>      TWR-K70F120M boards).
> =

> In my .dts I'm trying to possibly follow real clock hierarchy, but to go =

> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by =

> U-boot. But that's too demanding for any potential users of this BSP. So =

> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and =

> PCLK.

I'm confused. The point of device tree is to solve problems like this;
i.e. board-specific differences such as different oscillator
frequencies.

OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
can probably go in your chip-specific .dtsi as a fixed-rate clock since
it appears to mandated in the reference manual[0].

These three fixed-rate clocks are your root clock nodes. Customers only
need to worry about this if they spin a board, and then they will need
to populate the frequencies of OSC0 and OSC1 in their board-specific
.dts.

Please break clk-kinetis.c into two files:
drivers/clk/kinetis/clk-mcg.c
drivers/clk/kinetis/clk-sim.c

Below is what your binding/dts should look like:

{
	osc0: clock {
		compatible =3D "fixed-clock";
		#clock-cells =3D <0>;
		clock-frequency =3D <50000000>;
	};

	osc1: clock {
		compatible =3D "fixed-clock";
		#clock-cells =3D <0>;
		clock-frequency =3D <12000000>;
	};

	rtc: clock {
		compatible =3D "fixed-clock";
		#clock-cells =3D <0>;
		clock-frequency =3D <32768>;
	};

	soc: soc {
		mcg: clock-controller@40064000 {
			compatible =3D "fsl,kinetis-mcg";
			clock-cells =3D <1>;
			reg =3D <0x40064000 0x14>;
			clocks =3D <&osc0>, <&osc1>, <&rtc>;
			clock-names =3D "osc0", "osc1", "rtc";
		};

		sim: clock-controller@40047000 {
			compatible =3D "fsl,kinetis-sim";
			clock-cells =3D <1>;
			reg =3D <0x40047000 0x1100>;
			clocks =3D <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg M=
CG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
			clock-names =3D "core", "bus", "flexbus", "flash";
		};
	};

	uart0: serial@4006a000 {
		compatible =3D "fsl,kinetis-lpuart";
		reg =3D <0x4006a000 0x1000>;
		clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
		clock-names =3D "gate";
	};

I removed the interrupts and dma stuff from the uart0 node for clarity.
The above is the only style of binding that I have been accepting for
some time; first declare the clock controller and establish its register
space, and then consumers can consume clocks by providing the phandle to
the controller plus an offset corresponding to a unique clock. The
clock-names property makes it really easy to use with the clkdev stuff
(e.g. clk_get()).

I've covered this before on the mailing list so here is a link
describing how the qcom bindings do it in detail:

http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>

Technically you could encode the same bits as sub-nodes of the mcg and
sim nodes, but the shared header is how the magic happens with the
driver so it's best to keep the clock controller binding small and
light.

I think this means you can also get rid of kinetis_of_clk_get_name and
kinetis_clk_gate_get but my brain is tired so I'll leave that as an
exercise to the reader.

[0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P25=
6M150SF3RM.pdf

Regards,
Mike

> =

> In my most recent version I added OSC0ERCLK explicitly as one more root =

> clock, since it is also used directly (through CG reg. 1 bit 0) by =

> Freescale fec network device whose in-tree driver I'm trying to make =

> usable for Kinetis.
> =

> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> =

> > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> >>>
> >>>> I wonder if you could move out the fixed rate clocks into their own
> >>>> nodes. Are they actually controlled by the same block? If they are
> >>>> just fixed, you can use the normal binding for fixed rate clocks
> >>>> and only describe the clocks that are related to the driver.
> >>>
> >>> In my view having these clocks grouped together looks more convincing=
. After
> >>> all, they all share the same I/O regs in order to read configuration.
> >>
> >> The fact that they share a register is not making them a group. That's
> >> just a HW design decision and you need to deal with that by protecting
> >> the register access, but not by trying to group them artificially at
> >> the functional level.
> >
> > I'd disagree with that: The clock controller is the device that owns the
> > registers and that should be one node in DT, as Paul's first version do=
es.
> >
> > The part I'm still struggling with is understanding how the fixed-rate
> > clocks are controlled through those registers. If they are indeed confi=
gured
> > through the registers, the name is probably wrong and should be changed
> > to whatever kind of non-fixed clock this is.
> >
> >       Arnd
> >
> =

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-24  3:42                       ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-24  3:42 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Paul Osmialowski (2015-07-04 14:50:03)
> Hi Arnd,
> 
> I'm attaching excerpt from Kinetis reference manual that may make 
> situation clearer.

Hi Paul,

Can you please post the patch in the body of the email instead of an
attachment? It makes it easier to review. Another small nitpick is that
the $SUBJECT for this patch might be better off as something like:

clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC

At least it helps me find the patch I care about when skimming the
series ;-)

> 
> These MCG and SIM registers are used only to determine configuration 
> (clock fixed rates and clock signal origins) at run time.
> 
> Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> reading MCG registers, let me quote commit message from Emcraft git repo:
> 
>       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
>      as clock source for the main PLL.

According to [0] there are three options: a 32k RTC osc clock and osc0
both feed into a mux. You should model this 32k clock with the
fixed-rate binding.

>       * When OSC1 is selected, assume its frequency to be 12 MHz on all
>      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
>      TWR-K70F120M boards).
> 
> In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> U-boot. But that's too demanding for any potential users of this BSP. So 
> let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> PCLK.

I'm confused. The point of device tree is to solve problems like this;
i.e. board-specific differences such as different oscillator
frequencies.

OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
can probably go in your chip-specific .dtsi as a fixed-rate clock since
it appears to mandated in the reference manual[0].

These three fixed-rate clocks are your root clock nodes. Customers only
need to worry about this if they spin a board, and then they will need
to populate the frequencies of OSC0 and OSC1 in their board-specific
.dts.

Please break clk-kinetis.c into two files:
drivers/clk/kinetis/clk-mcg.c
drivers/clk/kinetis/clk-sim.c

Below is what your binding/dts should look like:

{
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	soc: soc {
		mcg: clock-controller at 40064000 {
			compatible = "fsl,kinetis-mcg";
			clock-cells = <1>;
			reg = <0x40064000 0x14>;
			clocks = <&osc0>, <&osc1>, <&rtc>;
			clock-names = "osc0", "osc1", "rtc";
		};

		sim: clock-controller at 40047000 {
			compatible = "fsl,kinetis-sim";
			clock-cells = <1>;
			reg = <0x40047000 0x1100>;
			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
			clock-names = "core", "bus", "flexbus", "flash";
		};
	};

	uart0: serial at 4006a000 {
		compatible = "fsl,kinetis-lpuart";
		reg = <0x4006a000 0x1000>;
		clocks = <&sim SIM_SCGC4_UART1_CLK>;
		clock-names = "gate";
	};

I removed the interrupts and dma stuff from the uart0 node for clarity.
The above is the only style of binding that I have been accepting for
some time; first declare the clock controller and establish its register
space, and then consumers can consume clocks by providing the phandle to
the controller plus an offset corresponding to a unique clock. The
clock-names property makes it really easy to use with the clkdev stuff
(e.g. clk_get()).

I've covered this before on the mailing list so here is a link
describing how the qcom bindings do it in detail:

http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>

Technically you could encode the same bits as sub-nodes of the mcg and
sim nodes, but the shared header is how the magic happens with the
driver so it's best to keep the clock controller binding small and
light.

I think this means you can also get rid of kinetis_of_clk_get_name and
kinetis_clk_gate_get but my brain is tired so I'll leave that as an
exercise to the reader.

[0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf

Regards,
Mike

> 
> In my most recent version I added OSC0ERCLK explicitly as one more root 
> clock, since it is also used directly (through CG reg. 1 bit 0) by 
> Freescale fec network device whose in-tree driver I'm trying to make 
> usable for Kinetis.
> 
> On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> 
> > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> >>>
> >>>> I wonder if you could move out the fixed rate clocks into their own
> >>>> nodes. Are they actually controlled by the same block? If they are
> >>>> just fixed, you can use the normal binding for fixed rate clocks
> >>>> and only describe the clocks that are related to the driver.
> >>>
> >>> In my view having these clocks grouped together looks more convincing. After
> >>> all, they all share the same I/O regs in order to read configuration.
> >>
> >> The fact that they share a register is not making them a group. That's
> >> just a HW design decision and you need to deal with that by protecting
> >> the register access, but not by trying to group them artificially at
> >> the functional level.
> >
> > I'd disagree with that: The clock controller is the device that owns the
> > registers and that should be one node in DT, as Paul's first version does.
> >
> > The part I'm still struggling with is understanding how the fixed-rate
> > clocks are controlled through those registers. If they are indeed configured
> > through the registers, the name is probably wrong and should be changed
> > to whatever kind of non-fixed clock this is.
> >
> >       Arnd
> >
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-24  3:42                       ` Michael Turquette
  (?)
@ 2015-07-26 20:24                         ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-26 20:24 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner

Hi Mike,

Thank you for spending time on this and pointing me into the right 
direction. I'm wondering about going even further with it. Assuming that I 
know everything about my board, I can skip run-time discovery phase (note 
that the original driver was designed for other Kinetis-based boards too) 
and move everything into DTS, somewhat like this:

/ {
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	mcgout: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&osc0>;
		clock-mult = <12>;
		clock-div = <5>;
	};

	core: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <1>;
	};

	bus: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <2>;
	};

	soc {
		cmu@0x40047000 {
			compatible = "fsl,kinetis-gate-clock";
			reg = <0x40047000 0x1100>;

			mcg_core_gate: clock-gate {
				clocks = <&core>;
				#clock-cells = <2>;
			};

			mcg_bus_gate: clock-gate {
				clocks = <&bus>;
				#clock-cells = <2>;
			};

			osc0_erclk_gate: clock-gate {
				clocks = <&osc0>;
				#clock-cells = <2>;
			};
		};

		uart0: serial@4006a000 {
			compatible = "fsl,kinetis-lpuart";
			reg = <0x4006a000 0x1000>;
			interrupts = <45>, <46>;
			interrupt-names = "uart-stat", "uart-err";
			clocks = <&mcg_core_gate 3 10>;
			clock-names = "ipg";
			dmas = <&edma 0 2>;
			dma-names = "rx";
			status = "disabled";
		};
	};
};

As you can see, mcg part is not required anymore.

I guess that the approach above would require split into soc-specific and 
board-specific part (as I said, dividers arrangement is something board 
specific), but I wonder what you thing about this proposal.

Thanks,
Paul

On Thu, 23 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > Hi Arnd,
> > 
> > I'm attaching excerpt from Kinetis reference manual that may make 
> > situation clearer.
> 
> Hi Paul,
> 
> Can you please post the patch in the body of the email instead of an
> attachment? It makes it easier to review. Another small nitpick is that
> the $SUBJECT for this patch might be better off as something like:
> 
> clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> 
> At least it helps me find the patch I care about when skimming the
> series ;-)
> 
> > 
> > These MCG and SIM registers are used only to determine configuration 
> > (clock fixed rates and clock signal origins) at run time.
> > 
> > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > reading MCG registers, let me quote commit message from Emcraft git repo:
> > 
> >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> >      as clock source for the main PLL.
> 
> According to [0] there are three options: a 32k RTC osc clock and osc0
> both feed into a mux. You should model this 32k clock with the
> fixed-rate binding.
> 
> >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> >      TWR-K70F120M boards).
> > 
> > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > U-boot. But that's too demanding for any potential users of this BSP. So 
> > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > PCLK.
> 
> I'm confused. The point of device tree is to solve problems like this;
> i.e. board-specific differences such as different oscillator
> frequencies.
> 
> OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> can probably go in your chip-specific .dtsi as a fixed-rate clock since
> it appears to mandated in the reference manual[0].
> 
> These three fixed-rate clocks are your root clock nodes. Customers only
> need to worry about this if they spin a board, and then they will need
> to populate the frequencies of OSC0 and OSC1 in their board-specific
> .dts.
> 
> Please break clk-kinetis.c into two files:
> drivers/clk/kinetis/clk-mcg.c
> drivers/clk/kinetis/clk-sim.c
> 
> Below is what your binding/dts should look like:
> 
> {
> 	osc0: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <50000000>;
> 	};
> 
> 	osc1: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <12000000>;
> 	};
> 
> 	rtc: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <32768>;
> 	};
> 
> 	soc: soc {
> 		mcg: clock-controller@40064000 {
> 			compatible = "fsl,kinetis-mcg";
> 			clock-cells = <1>;
> 			reg = <0x40064000 0x14>;
> 			clocks = <&osc0>, <&osc1>, <&rtc>;
> 			clock-names = "osc0", "osc1", "rtc";
> 		};
> 
> 		sim: clock-controller@40047000 {
> 			compatible = "fsl,kinetis-sim";
> 			clock-cells = <1>;
> 			reg = <0x40047000 0x1100>;
> 			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> 			clock-names = "core", "bus", "flexbus", "flash";
> 		};
> 	};
> 
> 	uart0: serial@4006a000 {
> 		compatible = "fsl,kinetis-lpuart";
> 		reg = <0x4006a000 0x1000>;
> 		clocks = <&sim SIM_SCGC4_UART1_CLK>;
> 		clock-names = "gate";
> 	};
> 
> I removed the interrupts and dma stuff from the uart0 node for clarity.
> The above is the only style of binding that I have been accepting for
> some time; first declare the clock controller and establish its register
> space, and then consumers can consume clocks by providing the phandle to
> the controller plus an offset corresponding to a unique clock. The
> clock-names property makes it really easy to use with the clkdev stuff
> (e.g. clk_get()).
> 
> I've covered this before on the mailing list so here is a link
> describing how the qcom bindings do it in detail:
> 
> http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> 
> Technically you could encode the same bits as sub-nodes of the mcg and
> sim nodes, but the shared header is how the magic happens with the
> driver so it's best to keep the clock controller binding small and
> light.
> 
> I think this means you can also get rid of kinetis_of_clk_get_name and
> kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> exercise to the reader.
> 
> [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> 
> Regards,
> Mike
> 
> > 
> > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > Freescale fec network device whose in-tree driver I'm trying to make 
> > usable for Kinetis.
> > 
> > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > 
> > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > >>>
> > >>>> I wonder if you could move out the fixed rate clocks into their own
> > >>>> nodes. Are they actually controlled by the same block? If they are
> > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > >>>> and only describe the clocks that are related to the driver.
> > >>>
> > >>> In my view having these clocks grouped together looks more convincing. After
> > >>> all, they all share the same I/O regs in order to read configuration.
> > >>
> > >> The fact that they share a register is not making them a group. That's
> > >> just a HW design decision and you need to deal with that by protecting
> > >> the register access, but not by trying to group them artificially at
> > >> the functional level.
> > >
> > > I'd disagree with that: The clock controller is the device that owns the
> > > registers and that should be one node in DT, as Paul's first version does.
> > >
> > > The part I'm still struggling with is understanding how the fixed-rate
> > > clocks are controlled through those registers. If they are indeed configured
> > > through the registers, the name is probably wrong and should be changed
> > > to whatever kind of non-fixed clock this is.
> > >
> > >       Arnd
> > >
> > 
> > _______________________________________________
> > 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] 140+ messages in thread

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-26 20:24                         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-26 20:24 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Hi Mike,

Thank you for spending time on this and pointing me into the right 
direction. I'm wondering about going even further with it. Assuming that I 
know everything about my board, I can skip run-time discovery phase (note 
that the original driver was designed for other Kinetis-based boards too) 
and move everything into DTS, somewhat like this:

/ {
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	mcgout: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&osc0>;
		clock-mult = <12>;
		clock-div = <5>;
	};

	core: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <1>;
	};

	bus: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <2>;
	};

	soc {
		cmu@0x40047000 {
			compatible = "fsl,kinetis-gate-clock";
			reg = <0x40047000 0x1100>;

			mcg_core_gate: clock-gate {
				clocks = <&core>;
				#clock-cells = <2>;
			};

			mcg_bus_gate: clock-gate {
				clocks = <&bus>;
				#clock-cells = <2>;
			};

			osc0_erclk_gate: clock-gate {
				clocks = <&osc0>;
				#clock-cells = <2>;
			};
		};

		uart0: serial@4006a000 {
			compatible = "fsl,kinetis-lpuart";
			reg = <0x4006a000 0x1000>;
			interrupts = <45>, <46>;
			interrupt-names = "uart-stat", "uart-err";
			clocks = <&mcg_core_gate 3 10>;
			clock-names = "ipg";
			dmas = <&edma 0 2>;
			dma-names = "rx";
			status = "disabled";
		};
	};
};

As you can see, mcg part is not required anymore.

I guess that the approach above would require split into soc-specific and 
board-specific part (as I said, dividers arrangement is something board 
specific), but I wonder what you thing about this proposal.

Thanks,
Paul

On Thu, 23 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > Hi Arnd,
> > 
> > I'm attaching excerpt from Kinetis reference manual that may make 
> > situation clearer.
> 
> Hi Paul,
> 
> Can you please post the patch in the body of the email instead of an
> attachment? It makes it easier to review. Another small nitpick is that
> the $SUBJECT for this patch might be better off as something like:
> 
> clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> 
> At least it helps me find the patch I care about when skimming the
> series ;-)
> 
> > 
> > These MCG and SIM registers are used only to determine configuration 
> > (clock fixed rates and clock signal origins) at run time.
> > 
> > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > reading MCG registers, let me quote commit message from Emcraft git repo:
> > 
> >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> >      as clock source for the main PLL.
> 
> According to [0] there are three options: a 32k RTC osc clock and osc0
> both feed into a mux. You should model this 32k clock with the
> fixed-rate binding.
> 
> >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> >      TWR-K70F120M boards).
> > 
> > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > U-boot. But that's too demanding for any potential users of this BSP. So 
> > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > PCLK.
> 
> I'm confused. The point of device tree is to solve problems like this;
> i.e. board-specific differences such as different oscillator
> frequencies.
> 
> OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> can probably go in your chip-specific .dtsi as a fixed-rate clock since
> it appears to mandated in the reference manual[0].
> 
> These three fixed-rate clocks are your root clock nodes. Customers only
> need to worry about this if they spin a board, and then they will need
> to populate the frequencies of OSC0 and OSC1 in their board-specific
> .dts.
> 
> Please break clk-kinetis.c into two files:
> drivers/clk/kinetis/clk-mcg.c
> drivers/clk/kinetis/clk-sim.c
> 
> Below is what your binding/dts should look like:
> 
> {
> 	osc0: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <50000000>;
> 	};
> 
> 	osc1: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <12000000>;
> 	};
> 
> 	rtc: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <32768>;
> 	};
> 
> 	soc: soc {
> 		mcg: clock-controller@40064000 {
> 			compatible = "fsl,kinetis-mcg";
> 			clock-cells = <1>;
> 			reg = <0x40064000 0x14>;
> 			clocks = <&osc0>, <&osc1>, <&rtc>;
> 			clock-names = "osc0", "osc1", "rtc";
> 		};
> 
> 		sim: clock-controller@40047000 {
> 			compatible = "fsl,kinetis-sim";
> 			clock-cells = <1>;
> 			reg = <0x40047000 0x1100>;
> 			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> 			clock-names = "core", "bus", "flexbus", "flash";
> 		};
> 	};
> 
> 	uart0: serial@4006a000 {
> 		compatible = "fsl,kinetis-lpuart";
> 		reg = <0x4006a000 0x1000>;
> 		clocks = <&sim SIM_SCGC4_UART1_CLK>;
> 		clock-names = "gate";
> 	};
> 
> I removed the interrupts and dma stuff from the uart0 node for clarity.
> The above is the only style of binding that I have been accepting for
> some time; first declare the clock controller and establish its register
> space, and then consumers can consume clocks by providing the phandle to
> the controller plus an offset corresponding to a unique clock. The
> clock-names property makes it really easy to use with the clkdev stuff
> (e.g. clk_get()).
> 
> I've covered this before on the mailing list so here is a link
> describing how the qcom bindings do it in detail:
> 
> http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> 
> Technically you could encode the same bits as sub-nodes of the mcg and
> sim nodes, but the shared header is how the magic happens with the
> driver so it's best to keep the clock controller binding small and
> light.
> 
> I think this means you can also get rid of kinetis_of_clk_get_name and
> kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> exercise to the reader.
> 
> [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> 
> Regards,
> Mike
> 
> > 
> > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > Freescale fec network device whose in-tree driver I'm trying to make 
> > usable for Kinetis.
> > 
> > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > 
> > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > >>>
> > >>>> I wonder if you could move out the fixed rate clocks into their own
> > >>>> nodes. Are they actually controlled by the same block? If they are
> > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > >>>> and only describe the clocks that are related to the driver.
> > >>>
> > >>> In my view having these clocks grouped together looks more convincing. After
> > >>> all, they all share the same I/O regs in order to read configuration.
> > >>
> > >> The fact that they share a register is not making them a group. That's
> > >> just a HW design decision and you need to deal with that by protecting
> > >> the register access, but not by trying to group them artificially at
> > >> the functional level.
> > >
> > > I'd disagree with that: The clock controller is the device that owns the
> > > registers and that should be one node in DT, as Paul's first version does.
> > >
> > > The part I'm still struggling with is understanding how the fixed-rate
> > > clocks are controlled through those registers. If they are indeed configured
> > > through the registers, the name is probably wrong and should be changed
> > > to whatever kind of non-fixed clock this is.
> > >
> > >       Arnd
> > >
> > 
> > _______________________________________________
> > 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] 140+ messages in thread

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-26 20:24                         ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-26 20:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

Thank you for spending time on this and pointing me into the right 
direction. I'm wondering about going even further with it. Assuming that I 
know everything about my board, I can skip run-time discovery phase (note 
that the original driver was designed for other Kinetis-based boards too) 
and move everything into DTS, somewhat like this:

/ {
	osc0: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <50000000>;
	};

	osc1: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <12000000>;
	};

	rtc: clock {
		compatible = "fixed-clock";
		#clock-cells = <0>;
		clock-frequency = <32768>;
	};

	mcgout: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&osc0>;
		clock-mult = <12>;
		clock-div = <5>;
	};

	core: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <1>;
	};

	bus: clock {
		compatible = "fixed-factor-clock";
		#clock-cells = <0>;
		clocks = <&mcgout>;
		clock-mult = <1>;
		clock-div = <2>;
	};

	soc {
		cmu at 0x40047000 {
			compatible = "fsl,kinetis-gate-clock";
			reg = <0x40047000 0x1100>;

			mcg_core_gate: clock-gate {
				clocks = <&core>;
				#clock-cells = <2>;
			};

			mcg_bus_gate: clock-gate {
				clocks = <&bus>;
				#clock-cells = <2>;
			};

			osc0_erclk_gate: clock-gate {
				clocks = <&osc0>;
				#clock-cells = <2>;
			};
		};

		uart0: serial at 4006a000 {
			compatible = "fsl,kinetis-lpuart";
			reg = <0x4006a000 0x1000>;
			interrupts = <45>, <46>;
			interrupt-names = "uart-stat", "uart-err";
			clocks = <&mcg_core_gate 3 10>;
			clock-names = "ipg";
			dmas = <&edma 0 2>;
			dma-names = "rx";
			status = "disabled";
		};
	};
};

As you can see, mcg part is not required anymore.

I guess that the approach above would require split into soc-specific and 
board-specific part (as I said, dividers arrangement is something board 
specific), but I wonder what you thing about this proposal.

Thanks,
Paul

On Thu, 23 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > Hi Arnd,
> > 
> > I'm attaching excerpt from Kinetis reference manual that may make 
> > situation clearer.
> 
> Hi Paul,
> 
> Can you please post the patch in the body of the email instead of an
> attachment? It makes it easier to review. Another small nitpick is that
> the $SUBJECT for this patch might be better off as something like:
> 
> clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> 
> At least it helps me find the patch I care about when skimming the
> series ;-)
> 
> > 
> > These MCG and SIM registers are used only to determine configuration 
> > (clock fixed rates and clock signal origins) at run time.
> > 
> > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > reading MCG registers, let me quote commit message from Emcraft git repo:
> > 
> >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> >      as clock source for the main PLL.
> 
> According to [0] there are three options: a 32k RTC osc clock and osc0
> both feed into a mux. You should model this 32k clock with the
> fixed-rate binding.
> 
> >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> >      TWR-K70F120M boards).
> > 
> > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > U-boot. But that's too demanding for any potential users of this BSP. So 
> > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > PCLK.
> 
> I'm confused. The point of device tree is to solve problems like this;
> i.e. board-specific differences such as different oscillator
> frequencies.
> 
> OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> can probably go in your chip-specific .dtsi as a fixed-rate clock since
> it appears to mandated in the reference manual[0].
> 
> These three fixed-rate clocks are your root clock nodes. Customers only
> need to worry about this if they spin a board, and then they will need
> to populate the frequencies of OSC0 and OSC1 in their board-specific
> .dts.
> 
> Please break clk-kinetis.c into two files:
> drivers/clk/kinetis/clk-mcg.c
> drivers/clk/kinetis/clk-sim.c
> 
> Below is what your binding/dts should look like:
> 
> {
> 	osc0: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <50000000>;
> 	};
> 
> 	osc1: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <12000000>;
> 	};
> 
> 	rtc: clock {
> 		compatible = "fixed-clock";
> 		#clock-cells = <0>;
> 		clock-frequency = <32768>;
> 	};
> 
> 	soc: soc {
> 		mcg: clock-controller at 40064000 {
> 			compatible = "fsl,kinetis-mcg";
> 			clock-cells = <1>;
> 			reg = <0x40064000 0x14>;
> 			clocks = <&osc0>, <&osc1>, <&rtc>;
> 			clock-names = "osc0", "osc1", "rtc";
> 		};
> 
> 		sim: clock-controller at 40047000 {
> 			compatible = "fsl,kinetis-sim";
> 			clock-cells = <1>;
> 			reg = <0x40047000 0x1100>;
> 			clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> 			clock-names = "core", "bus", "flexbus", "flash";
> 		};
> 	};
> 
> 	uart0: serial at 4006a000 {
> 		compatible = "fsl,kinetis-lpuart";
> 		reg = <0x4006a000 0x1000>;
> 		clocks = <&sim SIM_SCGC4_UART1_CLK>;
> 		clock-names = "gate";
> 	};
> 
> I removed the interrupts and dma stuff from the uart0 node for clarity.
> The above is the only style of binding that I have been accepting for
> some time; first declare the clock controller and establish its register
> space, and then consumers can consume clocks by providing the phandle to
> the controller plus an offset corresponding to a unique clock. The
> clock-names property makes it really easy to use with the clkdev stuff
> (e.g. clk_get()).
> 
> I've covered this before on the mailing list so here is a link
> describing how the qcom bindings do it in detail:
> 
> http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> 
> Technically you could encode the same bits as sub-nodes of the mcg and
> sim nodes, but the shared header is how the magic happens with the
> driver so it's best to keep the clock controller binding small and
> light.
> 
> I think this means you can also get rid of kinetis_of_clk_get_name and
> kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> exercise to the reader.
> 
> [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> 
> Regards,
> Mike
> 
> > 
> > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > Freescale fec network device whose in-tree driver I'm trying to make 
> > usable for Kinetis.
> > 
> > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > 
> > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > >>>
> > >>>> I wonder if you could move out the fixed rate clocks into their own
> > >>>> nodes. Are they actually controlled by the same block? If they are
> > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > >>>> and only describe the clocks that are related to the driver.
> > >>>
> > >>> In my view having these clocks grouped together looks more convincing. After
> > >>> all, they all share the same I/O regs in order to read configuration.
> > >>
> > >> The fact that they share a register is not making them a group. That's
> > >> just a HW design decision and you need to deal with that by protecting
> > >> the register access, but not by trying to group them artificially at
> > >> the functional level.
> > >
> > > I'd disagree with that: The clock controller is the device that owns the
> > > registers and that should be one node in DT, as Paul's first version does.
> > >
> > > The part I'm still struggling with is understanding how the fixed-rate
> > > clocks are controlled through those registers. If they are indeed configured
> > > through the registers, the name is probably wrong and should be changed
> > > to whatever kind of non-fixed clock this is.
> > >
> > >       Arnd
> > >
> > 
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-26 20:24                         ` Paul Osmialowski
  (?)
@ 2015-07-28 16:03                           ` Michael Turquette
  -1 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-28 16:03 UTC (permalink / raw)
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Arnd Bergmann, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

Quoting Paul Osmialowski (2015-07-26 13:24:08)
> Hi Mike,
> 
> Thank you for spending time on this and pointing me into the right 
> direction. I'm wondering about going even further with it. Assuming that I 

Hi Paul,

No problem! And thanks for the quick turnaround on your patches so far.

> know everything about my board, I can skip run-time discovery phase (note 
> that the original driver was designed for other Kinetis-based boards too) 
> and move everything into DTS, somewhat like this:
> 
> / {
>         osc0: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <50000000>;
>         };
> 
>         osc1: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <12000000>;
>         };
> 
>         rtc: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <32768>;
>         };
> 
>         mcgout: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&osc0>;
>                 clock-mult = <12>;
>                 clock-div = <5>;
>         };

I think this is a step backwards.

Did you look at the qcom clock binding and read the email where I
detailed how that binding works?

The point of that type of binding is to not shove per-clock data into
DT, but instead to declare every clock controller IP block (e.g. the
device) as well as every board-level clock (e.g. as osc that feeds into
your mcu). Once these "clock providers" are enumerated in DT, then we
create linkage between the clock providers and the clock consumers by
using phandles + an index. Linux device drivers tap into this by using
clk_get() and using the "clock-names" property from DT.

Put another way: we mostly use DT to model "devices". That is open to
interpretation for but for clock-related stuff we typically interpret
the clock controller as the device, not the individual clock outputs
coming out of the controller.

Note that a clock controller IP block may be both a provider and a
consumer.  I/O controllers are a very common type of consumer (e.g. USB
host controller, MMC controller, GPU, etc).

Additionally, from my reading of the reference manual, mcgout is defined
as:

"""
MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
MCGPLL1CLK, or MCG's external reference clock that
sources the core, system, bus, FlexBus, and flash clock. It is
also an option for the debug trace clock.
"""

So why is it listed here as a fixed-factor clock? Is it not a
multiplexer? Also, why is it listed here at all? Please take another
look at the qcom binding example I linked to in my previous mail.

> 
>         core: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&mcgout>;
>                 clock-mult = <1>;
>                 clock-div = <1>;
>         };
> 
>         bus: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&mcgout>;
>                 clock-mult = <1>;
>                 clock-div = <2>;

These are actually not fixed dividers but programmable dividers. You can
probably use drivers/clk/clk-divider.c for these. I'm fine with using
fixed-dividers for the initial merge just to get things up and running
if that is your strategy, but you'll need to revisit them later on when
you need more flexible support for other boards.

Again, I'm not sure why these clocks are enumerated in DT. Why not just
enumerate your mcg clock controller and your sim clock controller? If
you want to be a perfectionist then it appears that there is an osc
clock controller upstream from the mcg controller as well ;-)

It occurs to me that maybe you are trying to use fixed-factor clocks so
that you can program a sane default rate? We use the
assigned-clock-rates property for that. Note that this value is a
property of some device which *consumes* the clock, not the clock
controller or the clock output itself.

>         };
> 
>         soc {
>                 cmu@0x40047000 {
>                         compatible = "fsl,kinetis-gate-clock";
>                         reg = <0x40047000 0x1100>;
> 
>                         mcg_core_gate: clock-gate {
>                                 clocks = <&core>;
>                                 #clock-cells = <2>;
>                         };
> 
>                         mcg_bus_gate: clock-gate {
>                                 clocks = <&bus>;
>                                 #clock-cells = <2>;
>                         };
> 
>                         osc0_erclk_gate: clock-gate {
>                                 clocks = <&osc0>;
>                                 #clock-cells = <2>;
>                         };
>                 };
> 
>                 uart0: serial@4006a000 {
>                         compatible = "fsl,kinetis-lpuart";
>                         reg = <0x4006a000 0x1000>;
>                         interrupts = <45>, <46>;
>                         interrupt-names = "uart-stat", "uart-err";
>                         clocks = <&mcg_core_gate 3 10>;

Magic numbers are not good. dtc has been able to use preprocessor macros
for a while now which means we can use constants instead of magic
numbers. Please look at the shared header in the qcom binding for an
example.

>                         clock-names = "ipg";
>                         dmas = <&edma 0 2>;
>                         dma-names = "rx";
>                         status = "disabled";
>                 };
>         };
> };
> 
> As you can see, mcg part is not required anymore.

I think the mcg should be required. The mcg is a real IP block on your
SoC, according to my reading of your technical reference manual. Just
because you can model a few of its output clocks in dts does not mean
that you should.

I did a quick grep and didn't find "cmu" anywhere in the reference
manual.

> 
> I guess that the approach above would require split into soc-specific and 
> board-specific part (as I said, dividers arrangement is something board 
> specific), but I wonder what you thing about this proposal.

Splitting is good. Chip-specific stuff can go into the chip-specific
dtsi file. The board-level (osc) stuff can go into the individual board
files. The ultimate goal is to make it trivial to add new boards.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> On Thu, 23 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > Hi Arnd,
> > > 
> > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > situation clearer.
> > 
> > Hi Paul,
> > 
> > Can you please post the patch in the body of the email instead of an
> > attachment? It makes it easier to review. Another small nitpick is that
> > the $SUBJECT for this patch might be better off as something like:
> > 
> > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > 
> > At least it helps me find the patch I care about when skimming the
> > series ;-)
> > 
> > > 
> > > These MCG and SIM registers are used only to determine configuration 
> > > (clock fixed rates and clock signal origins) at run time.
> > > 
> > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > 
> > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > >      as clock source for the main PLL.
> > 
> > According to [0] there are three options: a 32k RTC osc clock and osc0
> > both feed into a mux. You should model this 32k clock with the
> > fixed-rate binding.
> > 
> > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > >      TWR-K70F120M boards).
> > > 
> > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > PCLK.
> > 
> > I'm confused. The point of device tree is to solve problems like this;
> > i.e. board-specific differences such as different oscillator
> > frequencies.
> > 
> > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > it appears to mandated in the reference manual[0].
> > 
> > These three fixed-rate clocks are your root clock nodes. Customers only
> > need to worry about this if they spin a board, and then they will need
> > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > .dts.
> > 
> > Please break clk-kinetis.c into two files:
> > drivers/clk/kinetis/clk-mcg.c
> > drivers/clk/kinetis/clk-sim.c
> > 
> > Below is what your binding/dts should look like:
> > 
> > {
> >       osc0: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <50000000>;
> >       };
> > 
> >       osc1: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <12000000>;
> >       };
> > 
> >       rtc: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <32768>;
> >       };
> > 
> >       soc: soc {
> >               mcg: clock-controller@40064000 {
> >                       compatible = "fsl,kinetis-mcg";
> >                       clock-cells = <1>;
> >                       reg = <0x40064000 0x14>;
> >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> >                       clock-names = "osc0", "osc1", "rtc";
> >               };
> > 
> >               sim: clock-controller@40047000 {
> >                       compatible = "fsl,kinetis-sim";
> >                       clock-cells = <1>;
> >                       reg = <0x40047000 0x1100>;
> >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> >                       clock-names = "core", "bus", "flexbus", "flash";
> >               };
> >       };
> > 
> >       uart0: serial@4006a000 {
> >               compatible = "fsl,kinetis-lpuart";
> >               reg = <0x4006a000 0x1000>;
> >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> >               clock-names = "gate";
> >       };
> > 
> > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > The above is the only style of binding that I have been accepting for
> > some time; first declare the clock controller and establish its register
> > space, and then consumers can consume clocks by providing the phandle to
> > the controller plus an offset corresponding to a unique clock. The
> > clock-names property makes it really easy to use with the clkdev stuff
> > (e.g. clk_get()).
> > 
> > I've covered this before on the mailing list so here is a link
> > describing how the qcom bindings do it in detail:
> > 
> > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > 
> > Technically you could encode the same bits as sub-nodes of the mcg and
> > sim nodes, but the shared header is how the magic happens with the
> > driver so it's best to keep the clock controller binding small and
> > light.
> > 
> > I think this means you can also get rid of kinetis_of_clk_get_name and
> > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > exercise to the reader.
> > 
> > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > usable for Kinetis.
> > > 
> > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > 
> > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > >>>
> > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > >>>> and only describe the clocks that are related to the driver.
> > > >>>
> > > >>> In my view having these clocks grouped together looks more convincing. After
> > > >>> all, they all share the same I/O regs in order to read configuration.
> > > >>
> > > >> The fact that they share a register is not making them a group. That's
> > > >> just a HW design decision and you need to deal with that by protecting
> > > >> the register access, but not by trying to group them artificially at
> > > >> the functional level.
> > > >
> > > > I'd disagree with that: The clock controller is the device that owns the
> > > > registers and that should be one node in DT, as Paul's first version does.
> > > >
> > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > clocks are controlled through those registers. If they are indeed configured
> > > > through the registers, the name is probably wrong and should be changed
> > > > to whatever kind of non-fixed clock this is.
> > > >
> > > >       Arnd
> > > >
> > > 
> > > _______________________________________________
> > > linux-arm-kernel mailing list
> > > linux-arm-kernel@lists.infradead.org
> > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-28 16:03                           ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-28 16:03 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Quoting Paul Osmialowski (2015-07-26 13:24:08)
> Hi Mike,
> =

> Thank you for spending time on this and pointing me into the right =

> direction. I'm wondering about going even further with it. Assuming that =
I =


Hi Paul,

No problem! And thanks for the quick turnaround on your patches so far.

> know everything about my board, I can skip run-time discovery phase (note =

> that the original driver was designed for other Kinetis-based boards too) =

> and move everything into DTS, somewhat like this:
> =

> / {
>         osc0: clock {
>                 compatible =3D "fixed-clock";
>                 #clock-cells =3D <0>;
>                 clock-frequency =3D <50000000>;
>         };
> =

>         osc1: clock {
>                 compatible =3D "fixed-clock";
>                 #clock-cells =3D <0>;
>                 clock-frequency =3D <12000000>;
>         };
> =

>         rtc: clock {
>                 compatible =3D "fixed-clock";
>                 #clock-cells =3D <0>;
>                 clock-frequency =3D <32768>;
>         };
> =

>         mcgout: clock {
>                 compatible =3D "fixed-factor-clock";
>                 #clock-cells =3D <0>;
>                 clocks =3D <&osc0>;
>                 clock-mult =3D <12>;
>                 clock-div =3D <5>;
>         };

I think this is a step backwards.

Did you look at the qcom clock binding and read the email where I
detailed how that binding works?

The point of that type of binding is to not shove per-clock data into
DT, but instead to declare every clock controller IP block (e.g. the
device) as well as every board-level clock (e.g. as osc that feeds into
your mcu). Once these "clock providers" are enumerated in DT, then we
create linkage between the clock providers and the clock consumers by
using phandles + an index. Linux device drivers tap into this by using
clk_get() and using the "clock-names" property from DT.

Put another way: we mostly use DT to model "devices". That is open to
interpretation for but for clock-related stuff we typically interpret
the clock controller as the device, not the individual clock outputs
coming out of the controller.

Note that a clock controller IP block may be both a provider and a
consumer.  I/O controllers are a very common type of consumer (e.g. USB
host controller, MMC controller, GPU, etc).

Additionally, from my reading of the reference manual, mcgout is defined
as:

"""
MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
MCGPLL1CLK, or MCG's external reference clock that
sources the core, system, bus, FlexBus, and flash clock. It is
also an option for the debug trace clock.
"""

So why is it listed here as a fixed-factor clock? Is it not a
multiplexer? Also, why is it listed here at all? Please take another
look at the qcom binding example I linked to in my previous mail.

> =

>         core: clock {
>                 compatible =3D "fixed-factor-clock";
>                 #clock-cells =3D <0>;
>                 clocks =3D <&mcgout>;
>                 clock-mult =3D <1>;
>                 clock-div =3D <1>;
>         };
> =

>         bus: clock {
>                 compatible =3D "fixed-factor-clock";
>                 #clock-cells =3D <0>;
>                 clocks =3D <&mcgout>;
>                 clock-mult =3D <1>;
>                 clock-div =3D <2>;

These are actually not fixed dividers but programmable dividers. You can
probably use drivers/clk/clk-divider.c for these. I'm fine with using
fixed-dividers for the initial merge just to get things up and running
if that is your strategy, but you'll need to revisit them later on when
you need more flexible support for other boards.

Again, I'm not sure why these clocks are enumerated in DT. Why not just
enumerate your mcg clock controller and your sim clock controller? If
you want to be a perfectionist then it appears that there is an osc
clock controller upstream from the mcg controller as well ;-)

It occurs to me that maybe you are trying to use fixed-factor clocks so
that you can program a sane default rate? We use the
assigned-clock-rates property for that. Note that this value is a
property of some device which *consumes* the clock, not the clock
controller or the clock output itself.

>         };
> =

>         soc {
>                 cmu@0x40047000 {
>                         compatible =3D "fsl,kinetis-gate-clock";
>                         reg =3D <0x40047000 0x1100>;
> =

>                         mcg_core_gate: clock-gate {
>                                 clocks =3D <&core>;
>                                 #clock-cells =3D <2>;
>                         };
> =

>                         mcg_bus_gate: clock-gate {
>                                 clocks =3D <&bus>;
>                                 #clock-cells =3D <2>;
>                         };
> =

>                         osc0_erclk_gate: clock-gate {
>                                 clocks =3D <&osc0>;
>                                 #clock-cells =3D <2>;
>                         };
>                 };
> =

>                 uart0: serial@4006a000 {
>                         compatible =3D "fsl,kinetis-lpuart";
>                         reg =3D <0x4006a000 0x1000>;
>                         interrupts =3D <45>, <46>;
>                         interrupt-names =3D "uart-stat", "uart-err";
>                         clocks =3D <&mcg_core_gate 3 10>;

Magic numbers are not good. dtc has been able to use preprocessor macros
for a while now which means we can use constants instead of magic
numbers. Please look at the shared header in the qcom binding for an
example.

>                         clock-names =3D "ipg";
>                         dmas =3D <&edma 0 2>;
>                         dma-names =3D "rx";
>                         status =3D "disabled";
>                 };
>         };
> };
> =

> As you can see, mcg part is not required anymore.

I think the mcg should be required. The mcg is a real IP block on your
SoC, according to my reading of your technical reference manual. Just
because you can model a few of its output clocks in dts does not mean
that you should.

I did a quick grep and didn't find "cmu" anywhere in the reference
manual.

> =

> I guess that the approach above would require split into soc-specific and =

> board-specific part (as I said, dividers arrangement is something board =

> specific), but I wonder what you thing about this proposal.

Splitting is good. Chip-specific stuff can go into the chip-specific
dtsi file. The board-level (osc) stuff can go into the individual board
files. The ultimate goal is to make it trivial to add new boards.

Regards,
Mike

> =

> Thanks,
> Paul
> =

> On Thu, 23 Jul 2015, Michael Turquette wrote:
> =

> > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > Hi Arnd,
> > > =

> > > I'm attaching excerpt from Kinetis reference manual that may make =

> > > situation clearer.
> > =

> > Hi Paul,
> > =

> > Can you please post the patch in the body of the email instead of an
> > attachment? It makes it easier to review. Another small nitpick is that
> > the $SUBJECT for this patch might be better off as something like:
> > =

> > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > =

> > At least it helps me find the patch I care about when skimming the
> > series ;-)
> > =

> > > =

> > > These MCG and SIM registers are used only to determine configuration =

> > > (clock fixed rates and clock signal origins) at run time.
> > > =

> > > Namely, the real MCGOUTCLK source (in the middle) which is the parent=
 for =

> > > core clock (CCLK) and peripheral clock (PCLK) is determined at run ti=
me by =

> > > reading MCG registers, let me quote commit message from Emcraft git r=
epo:
> > > =

> > >       * Determine in run-time what oscillator module (OSC0 or OSC1) i=
s used
> > >      as clock source for the main PLL.
> > =

> > According to [0] there are three options: a 32k RTC osc clock and osc0
> > both feed into a mux. You should model this 32k clock with the
> > fixed-rate binding.
> > =

> > >       * When OSC1 is selected, assume its frequency to be 12 MHz on a=
ll
> > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM =
and
> > >      TWR-K70F120M boards).
> > > =

> > > In my .dts I'm trying to possibly follow real clock hierarchy, but to=
 go =

> > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. =
by =

> > > U-boot. But that's too demanding for any potential users of this BSP.=
 So =

> > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK an=
d =

> > > PCLK.
> > =

> > I'm confused. The point of device tree is to solve problems like this;
> > i.e. board-specific differences such as different oscillator
> > frequencies.
> > =

> > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > it appears to mandated in the reference manual[0].
> > =

> > These three fixed-rate clocks are your root clock nodes. Customers only
> > need to worry about this if they spin a board, and then they will need
> > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > .dts.
> > =

> > Please break clk-kinetis.c into two files:
> > drivers/clk/kinetis/clk-mcg.c
> > drivers/clk/kinetis/clk-sim.c
> > =

> > Below is what your binding/dts should look like:
> > =

> > {
> >       osc0: clock {
> >               compatible =3D "fixed-clock";
> >               #clock-cells =3D <0>;
> >               clock-frequency =3D <50000000>;
> >       };
> > =

> >       osc1: clock {
> >               compatible =3D "fixed-clock";
> >               #clock-cells =3D <0>;
> >               clock-frequency =3D <12000000>;
> >       };
> > =

> >       rtc: clock {
> >               compatible =3D "fixed-clock";
> >               #clock-cells =3D <0>;
> >               clock-frequency =3D <32768>;
> >       };
> > =

> >       soc: soc {
> >               mcg: clock-controller@40064000 {
> >                       compatible =3D "fsl,kinetis-mcg";
> >                       clock-cells =3D <1>;
> >                       reg =3D <0x40064000 0x14>;
> >                       clocks =3D <&osc0>, <&osc1>, <&rtc>;
> >                       clock-names =3D "osc0", "osc1", "rtc";
> >               };
> > =

> >               sim: clock-controller@40047000 {
> >                       compatible =3D "fsl,kinetis-sim";
> >                       clock-cells =3D <1>;
> >                       reg =3D <0x40047000 0x1100>;
> >                       clocks =3D <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_M=
CGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> >                       clock-names =3D "core", "bus", "flexbus", "flash";
> >               };
> >       };
> > =

> >       uart0: serial@4006a000 {
> >               compatible =3D "fsl,kinetis-lpuart";
> >               reg =3D <0x4006a000 0x1000>;
> >               clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
> >               clock-names =3D "gate";
> >       };
> > =

> > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > The above is the only style of binding that I have been accepting for
> > some time; first declare the clock controller and establish its register
> > space, and then consumers can consume clocks by providing the phandle to
> > the controller plus an offset corresponding to a unique clock. The
> > clock-names property makes it really easy to use with the clkdev stuff
> > (e.g. clk_get()).
> > =

> > I've covered this before on the mailing list so here is a link
> > describing how the qcom bindings do it in detail:
> > =

> > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > =

> > Technically you could encode the same bits as sub-nodes of the mcg and
> > sim nodes, but the shared header is how the magic happens with the
> > driver so it's best to keep the clock controller binding small and
> > light.
> > =

> > I think this means you can also get rid of kinetis_of_clk_get_name and
> > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > exercise to the reader.
> > =

> > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K7=
0P256M150SF3RM.pdf
> > =

> > Regards,
> > Mike
> > =

> > > =

> > > In my most recent version I added OSC0ERCLK explicitly as one more ro=
ot =

> > > clock, since it is also used directly (through CG reg. 1 bit 0) by =

> > > Freescale fec network device whose in-tree driver I'm trying to make =

> > > usable for Kinetis.
> > > =

> > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > =

> > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > >>>
> > > >>>> I wonder if you could move out the fixed rate clocks into their =
own
> > > >>>> nodes. Are they actually controlled by the same block? If they a=
re
> > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > >>>> and only describe the clocks that are related to the driver.
> > > >>>
> > > >>> In my view having these clocks grouped together looks more convin=
cing. After
> > > >>> all, they all share the same I/O regs in order to read configurat=
ion.
> > > >>
> > > >> The fact that they share a register is not making them a group. Th=
at's
> > > >> just a HW design decision and you need to deal with that by protec=
ting
> > > >> the register access, but not by trying to group them artificially =
at
> > > >> the functional level.
> > > >
> > > > I'd disagree with that: The clock controller is the device that own=
s the
> > > > registers and that should be one node in DT, as Paul's first versio=
n does.
> > > >
> > > > The part I'm still struggling with is understanding how the fixed-r=
ate
> > > > clocks are controlled through those registers. If they are indeed c=
onfigured
> > > > through the registers, the name is probably wrong and should be cha=
nged
> > > > to whatever kind of non-fixed clock this is.
> > > >
> > > >       Arnd
> > > >
> > > =

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

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-28 16:03                           ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-28 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Paul Osmialowski (2015-07-26 13:24:08)
> Hi Mike,
> 
> Thank you for spending time on this and pointing me into the right 
> direction. I'm wondering about going even further with it. Assuming that I 

Hi Paul,

No problem! And thanks for the quick turnaround on your patches so far.

> know everything about my board, I can skip run-time discovery phase (note 
> that the original driver was designed for other Kinetis-based boards too) 
> and move everything into DTS, somewhat like this:
> 
> / {
>         osc0: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <50000000>;
>         };
> 
>         osc1: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <12000000>;
>         };
> 
>         rtc: clock {
>                 compatible = "fixed-clock";
>                 #clock-cells = <0>;
>                 clock-frequency = <32768>;
>         };
> 
>         mcgout: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&osc0>;
>                 clock-mult = <12>;
>                 clock-div = <5>;
>         };

I think this is a step backwards.

Did you look at the qcom clock binding and read the email where I
detailed how that binding works?

The point of that type of binding is to not shove per-clock data into
DT, but instead to declare every clock controller IP block (e.g. the
device) as well as every board-level clock (e.g. as osc that feeds into
your mcu). Once these "clock providers" are enumerated in DT, then we
create linkage between the clock providers and the clock consumers by
using phandles + an index. Linux device drivers tap into this by using
clk_get() and using the "clock-names" property from DT.

Put another way: we mostly use DT to model "devices". That is open to
interpretation for but for clock-related stuff we typically interpret
the clock controller as the device, not the individual clock outputs
coming out of the controller.

Note that a clock controller IP block may be both a provider and a
consumer.  I/O controllers are a very common type of consumer (e.g. USB
host controller, MMC controller, GPU, etc).

Additionally, from my reading of the reference manual, mcgout is defined
as:

"""
MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
MCGPLL1CLK, or MCG's external reference clock that
sources the core, system, bus, FlexBus, and flash clock. It is
also an option for the debug trace clock.
"""

So why is it listed here as a fixed-factor clock? Is it not a
multiplexer? Also, why is it listed here at all? Please take another
look at the qcom binding example I linked to in my previous mail.

> 
>         core: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&mcgout>;
>                 clock-mult = <1>;
>                 clock-div = <1>;
>         };
> 
>         bus: clock {
>                 compatible = "fixed-factor-clock";
>                 #clock-cells = <0>;
>                 clocks = <&mcgout>;
>                 clock-mult = <1>;
>                 clock-div = <2>;

These are actually not fixed dividers but programmable dividers. You can
probably use drivers/clk/clk-divider.c for these. I'm fine with using
fixed-dividers for the initial merge just to get things up and running
if that is your strategy, but you'll need to revisit them later on when
you need more flexible support for other boards.

Again, I'm not sure why these clocks are enumerated in DT. Why not just
enumerate your mcg clock controller and your sim clock controller? If
you want to be a perfectionist then it appears that there is an osc
clock controller upstream from the mcg controller as well ;-)

It occurs to me that maybe you are trying to use fixed-factor clocks so
that you can program a sane default rate? We use the
assigned-clock-rates property for that. Note that this value is a
property of some device which *consumes* the clock, not the clock
controller or the clock output itself.

>         };
> 
>         soc {
>                 cmu at 0x40047000 {
>                         compatible = "fsl,kinetis-gate-clock";
>                         reg = <0x40047000 0x1100>;
> 
>                         mcg_core_gate: clock-gate {
>                                 clocks = <&core>;
>                                 #clock-cells = <2>;
>                         };
> 
>                         mcg_bus_gate: clock-gate {
>                                 clocks = <&bus>;
>                                 #clock-cells = <2>;
>                         };
> 
>                         osc0_erclk_gate: clock-gate {
>                                 clocks = <&osc0>;
>                                 #clock-cells = <2>;
>                         };
>                 };
> 
>                 uart0: serial at 4006a000 {
>                         compatible = "fsl,kinetis-lpuart";
>                         reg = <0x4006a000 0x1000>;
>                         interrupts = <45>, <46>;
>                         interrupt-names = "uart-stat", "uart-err";
>                         clocks = <&mcg_core_gate 3 10>;

Magic numbers are not good. dtc has been able to use preprocessor macros
for a while now which means we can use constants instead of magic
numbers. Please look at the shared header in the qcom binding for an
example.

>                         clock-names = "ipg";
>                         dmas = <&edma 0 2>;
>                         dma-names = "rx";
>                         status = "disabled";
>                 };
>         };
> };
> 
> As you can see, mcg part is not required anymore.

I think the mcg should be required. The mcg is a real IP block on your
SoC, according to my reading of your technical reference manual. Just
because you can model a few of its output clocks in dts does not mean
that you should.

I did a quick grep and didn't find "cmu" anywhere in the reference
manual.

> 
> I guess that the approach above would require split into soc-specific and 
> board-specific part (as I said, dividers arrangement is something board 
> specific), but I wonder what you thing about this proposal.

Splitting is good. Chip-specific stuff can go into the chip-specific
dtsi file. The board-level (osc) stuff can go into the individual board
files. The ultimate goal is to make it trivial to add new boards.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> On Thu, 23 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > Hi Arnd,
> > > 
> > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > situation clearer.
> > 
> > Hi Paul,
> > 
> > Can you please post the patch in the body of the email instead of an
> > attachment? It makes it easier to review. Another small nitpick is that
> > the $SUBJECT for this patch might be better off as something like:
> > 
> > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > 
> > At least it helps me find the patch I care about when skimming the
> > series ;-)
> > 
> > > 
> > > These MCG and SIM registers are used only to determine configuration 
> > > (clock fixed rates and clock signal origins) at run time.
> > > 
> > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > 
> > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > >      as clock source for the main PLL.
> > 
> > According to [0] there are three options: a 32k RTC osc clock and osc0
> > both feed into a mux. You should model this 32k clock with the
> > fixed-rate binding.
> > 
> > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > >      TWR-K70F120M boards).
> > > 
> > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > PCLK.
> > 
> > I'm confused. The point of device tree is to solve problems like this;
> > i.e. board-specific differences such as different oscillator
> > frequencies.
> > 
> > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > it appears to mandated in the reference manual[0].
> > 
> > These three fixed-rate clocks are your root clock nodes. Customers only
> > need to worry about this if they spin a board, and then they will need
> > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > .dts.
> > 
> > Please break clk-kinetis.c into two files:
> > drivers/clk/kinetis/clk-mcg.c
> > drivers/clk/kinetis/clk-sim.c
> > 
> > Below is what your binding/dts should look like:
> > 
> > {
> >       osc0: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <50000000>;
> >       };
> > 
> >       osc1: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <12000000>;
> >       };
> > 
> >       rtc: clock {
> >               compatible = "fixed-clock";
> >               #clock-cells = <0>;
> >               clock-frequency = <32768>;
> >       };
> > 
> >       soc: soc {
> >               mcg: clock-controller at 40064000 {
> >                       compatible = "fsl,kinetis-mcg";
> >                       clock-cells = <1>;
> >                       reg = <0x40064000 0x14>;
> >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> >                       clock-names = "osc0", "osc1", "rtc";
> >               };
> > 
> >               sim: clock-controller at 40047000 {
> >                       compatible = "fsl,kinetis-sim";
> >                       clock-cells = <1>;
> >                       reg = <0x40047000 0x1100>;
> >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> >                       clock-names = "core", "bus", "flexbus", "flash";
> >               };
> >       };
> > 
> >       uart0: serial at 4006a000 {
> >               compatible = "fsl,kinetis-lpuart";
> >               reg = <0x4006a000 0x1000>;
> >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> >               clock-names = "gate";
> >       };
> > 
> > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > The above is the only style of binding that I have been accepting for
> > some time; first declare the clock controller and establish its register
> > space, and then consumers can consume clocks by providing the phandle to
> > the controller plus an offset corresponding to a unique clock. The
> > clock-names property makes it really easy to use with the clkdev stuff
> > (e.g. clk_get()).
> > 
> > I've covered this before on the mailing list so here is a link
> > describing how the qcom bindings do it in detail:
> > 
> > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > 
> > Technically you could encode the same bits as sub-nodes of the mcg and
> > sim nodes, but the shared header is how the magic happens with the
> > driver so it's best to keep the clock controller binding small and
> > light.
> > 
> > I think this means you can also get rid of kinetis_of_clk_get_name and
> > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > exercise to the reader.
> > 
> > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > usable for Kinetis.
> > > 
> > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > 
> > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > >>>
> > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > >>>> and only describe the clocks that are related to the driver.
> > > >>>
> > > >>> In my view having these clocks grouped together looks more convincing. After
> > > >>> all, they all share the same I/O regs in order to read configuration.
> > > >>
> > > >> The fact that they share a register is not making them a group. That's
> > > >> just a HW design decision and you need to deal with that by protecting
> > > >> the register access, but not by trying to group them artificially at
> > > >> the functional level.
> > > >
> > > > I'd disagree with that: The clock controller is the device that owns the
> > > > registers and that should be one node in DT, as Paul's first version does.
> > > >
> > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > clocks are controlled through those registers. If they are indeed configured
> > > > through the registers, the name is probably wrong and should be changed
> > > > to whatever kind of non-fixed clock this is.
> > > >
> > > >       Arnd
> > > >
> > > 
> > > _______________________________________________
> > > linux-arm-kernel mailing list
> > > linux-arm-kernel at lists.infradead.org
> > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-28 16:03                           ` Michael Turquette
  (?)
@ 2015-07-28 20:30                             ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-28 20:30 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner

Hi Mike,

My trouble is that now I'm dealing with two conradictory opinions on how 
this driver should be written. The one you presented in your previous post 
assumes that there will be a header file with defines shared between the 
clock driver and DTS, also with clock gating details hidden behind some 
additional level of indirection, e.g.:

clocks = <&sim SIM_SCGC4_UART1_CLK>;

Note that I've been through this at the very beginning, though the names 
I used have been bit different, e.g.:

#define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */

This was rejected with a comment by Arnd:

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.

So I dropped all of these includes and started to use magic numbers (as 
you put it). Now I need to go one way or another or even go the third way: 
extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
scgc_register_number bit_index_number>.

Reading your previous post I'm starting to feel that it would bring me 
closer to final acceptance if I stick to what you proposed in that post 
(I'm really grateful to you for writting so huge chunk of DTS for me!), so 
I'll probably adopt that.

You're right about my "get things up and running" attitude - currently I 
want to develop things extensively (cover as much subsystems as 
possible) and then at some stage switch to intensive approach. This board 
is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
of coding opportunity in this field in the future.

Thanks,
Paul

On Tue, 28 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > Hi Mike,
> > 
> > Thank you for spending time on this and pointing me into the right 
> > direction. I'm wondering about going even further with it. Assuming that I 
> 
> Hi Paul,
> 
> No problem! And thanks for the quick turnaround on your patches so far.
> 
> > know everything about my board, I can skip run-time discovery phase (note 
> > that the original driver was designed for other Kinetis-based boards too) 
> > and move everything into DTS, somewhat like this:
> > 
> > / {
> >         osc0: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <50000000>;
> >         };
> > 
> >         osc1: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <12000000>;
> >         };
> > 
> >         rtc: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <32768>;
> >         };
> > 
> >         mcgout: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&osc0>;
> >                 clock-mult = <12>;
> >                 clock-div = <5>;
> >         };
> 
> I think this is a step backwards.
> 
> Did you look at the qcom clock binding and read the email where I
> detailed how that binding works?
> 
> The point of that type of binding is to not shove per-clock data into
> DT, but instead to declare every clock controller IP block (e.g. the
> device) as well as every board-level clock (e.g. as osc that feeds into
> your mcu). Once these "clock providers" are enumerated in DT, then we
> create linkage between the clock providers and the clock consumers by
> using phandles + an index. Linux device drivers tap into this by using
> clk_get() and using the "clock-names" property from DT.
> 
> Put another way: we mostly use DT to model "devices". That is open to
> interpretation for but for clock-related stuff we typically interpret
> the clock controller as the device, not the individual clock outputs
> coming out of the controller.
> 
> Note that a clock controller IP block may be both a provider and a
> consumer.  I/O controllers are a very common type of consumer (e.g. USB
> host controller, MMC controller, GPU, etc).
> 
> Additionally, from my reading of the reference manual, mcgout is defined
> as:
> 
> """
> MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> MCGPLL1CLK, or MCG's external reference clock that
> sources the core, system, bus, FlexBus, and flash clock. It is
> also an option for the debug trace clock.
> """
> 
> So why is it listed here as a fixed-factor clock? Is it not a
> multiplexer? Also, why is it listed here at all? Please take another
> look at the qcom binding example I linked to in my previous mail.
> 
> > 
> >         core: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <1>;
> >         };
> > 
> >         bus: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <2>;
> 
> These are actually not fixed dividers but programmable dividers. You can
> probably use drivers/clk/clk-divider.c for these. I'm fine with using
> fixed-dividers for the initial merge just to get things up and running
> if that is your strategy, but you'll need to revisit them later on when
> you need more flexible support for other boards.
> 
> Again, I'm not sure why these clocks are enumerated in DT. Why not just
> enumerate your mcg clock controller and your sim clock controller? If
> you want to be a perfectionist then it appears that there is an osc
> clock controller upstream from the mcg controller as well ;-)
> 
> It occurs to me that maybe you are trying to use fixed-factor clocks so
> that you can program a sane default rate? We use the
> assigned-clock-rates property for that. Note that this value is a
> property of some device which *consumes* the clock, not the clock
> controller or the clock output itself.
> 
> >         };
> > 
> >         soc {
> >                 cmu@0x40047000 {
> >                         compatible = "fsl,kinetis-gate-clock";
> >                         reg = <0x40047000 0x1100>;
> > 
> >                         mcg_core_gate: clock-gate {
> >                                 clocks = <&core>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         mcg_bus_gate: clock-gate {
> >                                 clocks = <&bus>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         osc0_erclk_gate: clock-gate {
> >                                 clocks = <&osc0>;
> >                                 #clock-cells = <2>;
> >                         };
> >                 };
> > 
> >                 uart0: serial@4006a000 {
> >                         compatible = "fsl,kinetis-lpuart";
> >                         reg = <0x4006a000 0x1000>;
> >                         interrupts = <45>, <46>;
> >                         interrupt-names = "uart-stat", "uart-err";
> >                         clocks = <&mcg_core_gate 3 10>;
> 
> Magic numbers are not good. dtc has been able to use preprocessor macros
> for a while now which means we can use constants instead of magic
> numbers. Please look at the shared header in the qcom binding for an
> example.
> 
> >                         clock-names = "ipg";
> >                         dmas = <&edma 0 2>;
> >                         dma-names = "rx";
> >                         status = "disabled";
> >                 };
> >         };
> > };
> > 
> > As you can see, mcg part is not required anymore.
> 
> I think the mcg should be required. The mcg is a real IP block on your
> SoC, according to my reading of your technical reference manual. Just
> because you can model a few of its output clocks in dts does not mean
> that you should.
> 
> I did a quick grep and didn't find "cmu" anywhere in the reference
> manual.
> 
> > 
> > I guess that the approach above would require split into soc-specific and 
> > board-specific part (as I said, dividers arrangement is something board 
> > specific), but I wonder what you thing about this proposal.
> 
> Splitting is good. Chip-specific stuff can go into the chip-specific
> dtsi file. The board-level (osc) stuff can go into the individual board
> files. The ultimate goal is to make it trivial to add new boards.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > Hi Arnd,
> > > > 
> > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > situation clearer.
> > > 
> > > Hi Paul,
> > > 
> > > Can you please post the patch in the body of the email instead of an
> > > attachment? It makes it easier to review. Another small nitpick is that
> > > the $SUBJECT for this patch might be better off as something like:
> > > 
> > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > 
> > > At least it helps me find the patch I care about when skimming the
> > > series ;-)
> > > 
> > > > 
> > > > These MCG and SIM registers are used only to determine configuration 
> > > > (clock fixed rates and clock signal origins) at run time.
> > > > 
> > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > 
> > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > >      as clock source for the main PLL.
> > > 
> > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > both feed into a mux. You should model this 32k clock with the
> > > fixed-rate binding.
> > > 
> > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > >      TWR-K70F120M boards).
> > > > 
> > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > PCLK.
> > > 
> > > I'm confused. The point of device tree is to solve problems like this;
> > > i.e. board-specific differences such as different oscillator
> > > frequencies.
> > > 
> > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > it appears to mandated in the reference manual[0].
> > > 
> > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > need to worry about this if they spin a board, and then they will need
> > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > .dts.
> > > 
> > > Please break clk-kinetis.c into two files:
> > > drivers/clk/kinetis/clk-mcg.c
> > > drivers/clk/kinetis/clk-sim.c
> > > 
> > > Below is what your binding/dts should look like:
> > > 
> > > {
> > >       osc0: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <50000000>;
> > >       };
> > > 
> > >       osc1: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <12000000>;
> > >       };
> > > 
> > >       rtc: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <32768>;
> > >       };
> > > 
> > >       soc: soc {
> > >               mcg: clock-controller@40064000 {
> > >                       compatible = "fsl,kinetis-mcg";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40064000 0x14>;
> > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > >                       clock-names = "osc0", "osc1", "rtc";
> > >               };
> > > 
> > >               sim: clock-controller@40047000 {
> > >                       compatible = "fsl,kinetis-sim";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40047000 0x1100>;
> > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > >                       clock-names = "core", "bus", "flexbus", "flash";
> > >               };
> > >       };
> > > 
> > >       uart0: serial@4006a000 {
> > >               compatible = "fsl,kinetis-lpuart";
> > >               reg = <0x4006a000 0x1000>;
> > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > >               clock-names = "gate";
> > >       };
> > > 
> > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > The above is the only style of binding that I have been accepting for
> > > some time; first declare the clock controller and establish its register
> > > space, and then consumers can consume clocks by providing the phandle to
> > > the controller plus an offset corresponding to a unique clock. The
> > > clock-names property makes it really easy to use with the clkdev stuff
> > > (e.g. clk_get()).
> > > 
> > > I've covered this before on the mailing list so here is a link
> > > describing how the qcom bindings do it in detail:
> > > 
> > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > 
> > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > sim nodes, but the shared header is how the magic happens with the
> > > driver so it's best to keep the clock controller binding small and
> > > light.
> > > 
> > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > exercise to the reader.
> > > 
> > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > usable for Kinetis.
> > > > 
> > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > 
> > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > >>>
> > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > >>>> and only describe the clocks that are related to the driver.
> > > > >>>
> > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > >>
> > > > >> The fact that they share a register is not making them a group. That's
> > > > >> just a HW design decision and you need to deal with that by protecting
> > > > >> the register access, but not by trying to group them artificially at
> > > > >> the functional level.
> > > > >
> > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > >
> > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > through the registers, the name is probably wrong and should be changed
> > > > > to whatever kind of non-fixed clock this is.
> > > > >
> > > > >       Arnd
> > > > >
> > > > 
> > > > _______________________________________________
> > > > linux-arm-kernel mailing list
> > > > linux-arm-kernel@lists.infradead.org
> > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-28 20:30                             ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-28 20:30 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Hi Mike,

My trouble is that now I'm dealing with two conradictory opinions on how 
this driver should be written. The one you presented in your previous post 
assumes that there will be a header file with defines shared between the 
clock driver and DTS, also with clock gating details hidden behind some 
additional level of indirection, e.g.:

clocks = <&sim SIM_SCGC4_UART1_CLK>;

Note that I've been through this at the very beginning, though the names 
I used have been bit different, e.g.:

#define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */

This was rejected with a comment by Arnd:

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.

So I dropped all of these includes and started to use magic numbers (as 
you put it). Now I need to go one way or another or even go the third way: 
extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
scgc_register_number bit_index_number>.

Reading your previous post I'm starting to feel that it would bring me 
closer to final acceptance if I stick to what you proposed in that post 
(I'm really grateful to you for writting so huge chunk of DTS for me!), so 
I'll probably adopt that.

You're right about my "get things up and running" attitude - currently I 
want to develop things extensively (cover as much subsystems as 
possible) and then at some stage switch to intensive approach. This board 
is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
of coding opportunity in this field in the future.

Thanks,
Paul

On Tue, 28 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > Hi Mike,
> > 
> > Thank you for spending time on this and pointing me into the right 
> > direction. I'm wondering about going even further with it. Assuming that I 
> 
> Hi Paul,
> 
> No problem! And thanks for the quick turnaround on your patches so far.
> 
> > know everything about my board, I can skip run-time discovery phase (note 
> > that the original driver was designed for other Kinetis-based boards too) 
> > and move everything into DTS, somewhat like this:
> > 
> > / {
> >         osc0: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <50000000>;
> >         };
> > 
> >         osc1: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <12000000>;
> >         };
> > 
> >         rtc: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <32768>;
> >         };
> > 
> >         mcgout: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&osc0>;
> >                 clock-mult = <12>;
> >                 clock-div = <5>;
> >         };
> 
> I think this is a step backwards.
> 
> Did you look at the qcom clock binding and read the email where I
> detailed how that binding works?
> 
> The point of that type of binding is to not shove per-clock data into
> DT, but instead to declare every clock controller IP block (e.g. the
> device) as well as every board-level clock (e.g. as osc that feeds into
> your mcu). Once these "clock providers" are enumerated in DT, then we
> create linkage between the clock providers and the clock consumers by
> using phandles + an index. Linux device drivers tap into this by using
> clk_get() and using the "clock-names" property from DT.
> 
> Put another way: we mostly use DT to model "devices". That is open to
> interpretation for but for clock-related stuff we typically interpret
> the clock controller as the device, not the individual clock outputs
> coming out of the controller.
> 
> Note that a clock controller IP block may be both a provider and a
> consumer.  I/O controllers are a very common type of consumer (e.g. USB
> host controller, MMC controller, GPU, etc).
> 
> Additionally, from my reading of the reference manual, mcgout is defined
> as:
> 
> """
> MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> MCGPLL1CLK, or MCG's external reference clock that
> sources the core, system, bus, FlexBus, and flash clock. It is
> also an option for the debug trace clock.
> """
> 
> So why is it listed here as a fixed-factor clock? Is it not a
> multiplexer? Also, why is it listed here at all? Please take another
> look at the qcom binding example I linked to in my previous mail.
> 
> > 
> >         core: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <1>;
> >         };
> > 
> >         bus: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <2>;
> 
> These are actually not fixed dividers but programmable dividers. You can
> probably use drivers/clk/clk-divider.c for these. I'm fine with using
> fixed-dividers for the initial merge just to get things up and running
> if that is your strategy, but you'll need to revisit them later on when
> you need more flexible support for other boards.
> 
> Again, I'm not sure why these clocks are enumerated in DT. Why not just
> enumerate your mcg clock controller and your sim clock controller? If
> you want to be a perfectionist then it appears that there is an osc
> clock controller upstream from the mcg controller as well ;-)
> 
> It occurs to me that maybe you are trying to use fixed-factor clocks so
> that you can program a sane default rate? We use the
> assigned-clock-rates property for that. Note that this value is a
> property of some device which *consumes* the clock, not the clock
> controller or the clock output itself.
> 
> >         };
> > 
> >         soc {
> >                 cmu@0x40047000 {
> >                         compatible = "fsl,kinetis-gate-clock";
> >                         reg = <0x40047000 0x1100>;
> > 
> >                         mcg_core_gate: clock-gate {
> >                                 clocks = <&core>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         mcg_bus_gate: clock-gate {
> >                                 clocks = <&bus>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         osc0_erclk_gate: clock-gate {
> >                                 clocks = <&osc0>;
> >                                 #clock-cells = <2>;
> >                         };
> >                 };
> > 
> >                 uart0: serial@4006a000 {
> >                         compatible = "fsl,kinetis-lpuart";
> >                         reg = <0x4006a000 0x1000>;
> >                         interrupts = <45>, <46>;
> >                         interrupt-names = "uart-stat", "uart-err";
> >                         clocks = <&mcg_core_gate 3 10>;
> 
> Magic numbers are not good. dtc has been able to use preprocessor macros
> for a while now which means we can use constants instead of magic
> numbers. Please look at the shared header in the qcom binding for an
> example.
> 
> >                         clock-names = "ipg";
> >                         dmas = <&edma 0 2>;
> >                         dma-names = "rx";
> >                         status = "disabled";
> >                 };
> >         };
> > };
> > 
> > As you can see, mcg part is not required anymore.
> 
> I think the mcg should be required. The mcg is a real IP block on your
> SoC, according to my reading of your technical reference manual. Just
> because you can model a few of its output clocks in dts does not mean
> that you should.
> 
> I did a quick grep and didn't find "cmu" anywhere in the reference
> manual.
> 
> > 
> > I guess that the approach above would require split into soc-specific and 
> > board-specific part (as I said, dividers arrangement is something board 
> > specific), but I wonder what you thing about this proposal.
> 
> Splitting is good. Chip-specific stuff can go into the chip-specific
> dtsi file. The board-level (osc) stuff can go into the individual board
> files. The ultimate goal is to make it trivial to add new boards.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > Hi Arnd,
> > > > 
> > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > situation clearer.
> > > 
> > > Hi Paul,
> > > 
> > > Can you please post the patch in the body of the email instead of an
> > > attachment? It makes it easier to review. Another small nitpick is that
> > > the $SUBJECT for this patch might be better off as something like:
> > > 
> > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > 
> > > At least it helps me find the patch I care about when skimming the
> > > series ;-)
> > > 
> > > > 
> > > > These MCG and SIM registers are used only to determine configuration 
> > > > (clock fixed rates and clock signal origins) at run time.
> > > > 
> > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > 
> > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > >      as clock source for the main PLL.
> > > 
> > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > both feed into a mux. You should model this 32k clock with the
> > > fixed-rate binding.
> > > 
> > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > >      TWR-K70F120M boards).
> > > > 
> > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > PCLK.
> > > 
> > > I'm confused. The point of device tree is to solve problems like this;
> > > i.e. board-specific differences such as different oscillator
> > > frequencies.
> > > 
> > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > it appears to mandated in the reference manual[0].
> > > 
> > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > need to worry about this if they spin a board, and then they will need
> > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > .dts.
> > > 
> > > Please break clk-kinetis.c into two files:
> > > drivers/clk/kinetis/clk-mcg.c
> > > drivers/clk/kinetis/clk-sim.c
> > > 
> > > Below is what your binding/dts should look like:
> > > 
> > > {
> > >       osc0: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <50000000>;
> > >       };
> > > 
> > >       osc1: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <12000000>;
> > >       };
> > > 
> > >       rtc: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <32768>;
> > >       };
> > > 
> > >       soc: soc {
> > >               mcg: clock-controller@40064000 {
> > >                       compatible = "fsl,kinetis-mcg";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40064000 0x14>;
> > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > >                       clock-names = "osc0", "osc1", "rtc";
> > >               };
> > > 
> > >               sim: clock-controller@40047000 {
> > >                       compatible = "fsl,kinetis-sim";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40047000 0x1100>;
> > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > >                       clock-names = "core", "bus", "flexbus", "flash";
> > >               };
> > >       };
> > > 
> > >       uart0: serial@4006a000 {
> > >               compatible = "fsl,kinetis-lpuart";
> > >               reg = <0x4006a000 0x1000>;
> > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > >               clock-names = "gate";
> > >       };
> > > 
> > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > The above is the only style of binding that I have been accepting for
> > > some time; first declare the clock controller and establish its register
> > > space, and then consumers can consume clocks by providing the phandle to
> > > the controller plus an offset corresponding to a unique clock. The
> > > clock-names property makes it really easy to use with the clkdev stuff
> > > (e.g. clk_get()).
> > > 
> > > I've covered this before on the mailing list so here is a link
> > > describing how the qcom bindings do it in detail:
> > > 
> > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > 
> > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > sim nodes, but the shared header is how the magic happens with the
> > > driver so it's best to keep the clock controller binding small and
> > > light.
> > > 
> > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > exercise to the reader.
> > > 
> > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > usable for Kinetis.
> > > > 
> > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > 
> > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > >>>
> > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > >>>> and only describe the clocks that are related to the driver.
> > > > >>>
> > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > >>
> > > > >> The fact that they share a register is not making them a group. That's
> > > > >> just a HW design decision and you need to deal with that by protecting
> > > > >> the register access, but not by trying to group them artificially at
> > > > >> the functional level.
> > > > >
> > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > >
> > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > through the registers, the name is probably wrong and should be changed
> > > > > to whatever kind of non-fixed clock this is.
> > > > >
> > > > >       Arnd
> > > > >
> > > > 
> > > > _______________________________________________
> > > > linux-arm-kernel mailing list
> > > > linux-arm-kernel@lists.infradead.org
> > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-28 20:30                             ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-28 20:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

My trouble is that now I'm dealing with two conradictory opinions on how 
this driver should be written. The one you presented in your previous post 
assumes that there will be a header file with defines shared between the 
clock driver and DTS, also with clock gating details hidden behind some 
additional level of indirection, e.g.:

clocks = <&sim SIM_SCGC4_UART1_CLK>;

Note that I've been through this at the very beginning, though the names 
I used have been bit different, e.g.:

#define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */

This was rejected with a comment by Arnd:

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.

So I dropped all of these includes and started to use magic numbers (as 
you put it). Now I need to go one way or another or even go the third way: 
extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
scgc_register_number bit_index_number>.

Reading your previous post I'm starting to feel that it would bring me 
closer to final acceptance if I stick to what you proposed in that post 
(I'm really grateful to you for writting so huge chunk of DTS for me!), so 
I'll probably adopt that.

You're right about my "get things up and running" attitude - currently I 
want to develop things extensively (cover as much subsystems as 
possible) and then at some stage switch to intensive approach. This board 
is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
of coding opportunity in this field in the future.

Thanks,
Paul

On Tue, 28 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > Hi Mike,
> > 
> > Thank you for spending time on this and pointing me into the right 
> > direction. I'm wondering about going even further with it. Assuming that I 
> 
> Hi Paul,
> 
> No problem! And thanks for the quick turnaround on your patches so far.
> 
> > know everything about my board, I can skip run-time discovery phase (note 
> > that the original driver was designed for other Kinetis-based boards too) 
> > and move everything into DTS, somewhat like this:
> > 
> > / {
> >         osc0: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <50000000>;
> >         };
> > 
> >         osc1: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <12000000>;
> >         };
> > 
> >         rtc: clock {
> >                 compatible = "fixed-clock";
> >                 #clock-cells = <0>;
> >                 clock-frequency = <32768>;
> >         };
> > 
> >         mcgout: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&osc0>;
> >                 clock-mult = <12>;
> >                 clock-div = <5>;
> >         };
> 
> I think this is a step backwards.
> 
> Did you look at the qcom clock binding and read the email where I
> detailed how that binding works?
> 
> The point of that type of binding is to not shove per-clock data into
> DT, but instead to declare every clock controller IP block (e.g. the
> device) as well as every board-level clock (e.g. as osc that feeds into
> your mcu). Once these "clock providers" are enumerated in DT, then we
> create linkage between the clock providers and the clock consumers by
> using phandles + an index. Linux device drivers tap into this by using
> clk_get() and using the "clock-names" property from DT.
> 
> Put another way: we mostly use DT to model "devices". That is open to
> interpretation for but for clock-related stuff we typically interpret
> the clock controller as the device, not the individual clock outputs
> coming out of the controller.
> 
> Note that a clock controller IP block may be both a provider and a
> consumer.  I/O controllers are a very common type of consumer (e.g. USB
> host controller, MMC controller, GPU, etc).
> 
> Additionally, from my reading of the reference manual, mcgout is defined
> as:
> 
> """
> MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> MCGPLL1CLK, or MCG's external reference clock that
> sources the core, system, bus, FlexBus, and flash clock. It is
> also an option for the debug trace clock.
> """
> 
> So why is it listed here as a fixed-factor clock? Is it not a
> multiplexer? Also, why is it listed here at all? Please take another
> look at the qcom binding example I linked to in my previous mail.
> 
> > 
> >         core: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <1>;
> >         };
> > 
> >         bus: clock {
> >                 compatible = "fixed-factor-clock";
> >                 #clock-cells = <0>;
> >                 clocks = <&mcgout>;
> >                 clock-mult = <1>;
> >                 clock-div = <2>;
> 
> These are actually not fixed dividers but programmable dividers. You can
> probably use drivers/clk/clk-divider.c for these. I'm fine with using
> fixed-dividers for the initial merge just to get things up and running
> if that is your strategy, but you'll need to revisit them later on when
> you need more flexible support for other boards.
> 
> Again, I'm not sure why these clocks are enumerated in DT. Why not just
> enumerate your mcg clock controller and your sim clock controller? If
> you want to be a perfectionist then it appears that there is an osc
> clock controller upstream from the mcg controller as well ;-)
> 
> It occurs to me that maybe you are trying to use fixed-factor clocks so
> that you can program a sane default rate? We use the
> assigned-clock-rates property for that. Note that this value is a
> property of some device which *consumes* the clock, not the clock
> controller or the clock output itself.
> 
> >         };
> > 
> >         soc {
> >                 cmu at 0x40047000 {
> >                         compatible = "fsl,kinetis-gate-clock";
> >                         reg = <0x40047000 0x1100>;
> > 
> >                         mcg_core_gate: clock-gate {
> >                                 clocks = <&core>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         mcg_bus_gate: clock-gate {
> >                                 clocks = <&bus>;
> >                                 #clock-cells = <2>;
> >                         };
> > 
> >                         osc0_erclk_gate: clock-gate {
> >                                 clocks = <&osc0>;
> >                                 #clock-cells = <2>;
> >                         };
> >                 };
> > 
> >                 uart0: serial at 4006a000 {
> >                         compatible = "fsl,kinetis-lpuart";
> >                         reg = <0x4006a000 0x1000>;
> >                         interrupts = <45>, <46>;
> >                         interrupt-names = "uart-stat", "uart-err";
> >                         clocks = <&mcg_core_gate 3 10>;
> 
> Magic numbers are not good. dtc has been able to use preprocessor macros
> for a while now which means we can use constants instead of magic
> numbers. Please look at the shared header in the qcom binding for an
> example.
> 
> >                         clock-names = "ipg";
> >                         dmas = <&edma 0 2>;
> >                         dma-names = "rx";
> >                         status = "disabled";
> >                 };
> >         };
> > };
> > 
> > As you can see, mcg part is not required anymore.
> 
> I think the mcg should be required. The mcg is a real IP block on your
> SoC, according to my reading of your technical reference manual. Just
> because you can model a few of its output clocks in dts does not mean
> that you should.
> 
> I did a quick grep and didn't find "cmu" anywhere in the reference
> manual.
> 
> > 
> > I guess that the approach above would require split into soc-specific and 
> > board-specific part (as I said, dividers arrangement is something board 
> > specific), but I wonder what you thing about this proposal.
> 
> Splitting is good. Chip-specific stuff can go into the chip-specific
> dtsi file. The board-level (osc) stuff can go into the individual board
> files. The ultimate goal is to make it trivial to add new boards.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > Hi Arnd,
> > > > 
> > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > situation clearer.
> > > 
> > > Hi Paul,
> > > 
> > > Can you please post the patch in the body of the email instead of an
> > > attachment? It makes it easier to review. Another small nitpick is that
> > > the $SUBJECT for this patch might be better off as something like:
> > > 
> > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > 
> > > At least it helps me find the patch I care about when skimming the
> > > series ;-)
> > > 
> > > > 
> > > > These MCG and SIM registers are used only to determine configuration 
> > > > (clock fixed rates and clock signal origins) at run time.
> > > > 
> > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > 
> > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > >      as clock source for the main PLL.
> > > 
> > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > both feed into a mux. You should model this 32k clock with the
> > > fixed-rate binding.
> > > 
> > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > >      TWR-K70F120M boards).
> > > > 
> > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > PCLK.
> > > 
> > > I'm confused. The point of device tree is to solve problems like this;
> > > i.e. board-specific differences such as different oscillator
> > > frequencies.
> > > 
> > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > it appears to mandated in the reference manual[0].
> > > 
> > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > need to worry about this if they spin a board, and then they will need
> > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > .dts.
> > > 
> > > Please break clk-kinetis.c into two files:
> > > drivers/clk/kinetis/clk-mcg.c
> > > drivers/clk/kinetis/clk-sim.c
> > > 
> > > Below is what your binding/dts should look like:
> > > 
> > > {
> > >       osc0: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <50000000>;
> > >       };
> > > 
> > >       osc1: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <12000000>;
> > >       };
> > > 
> > >       rtc: clock {
> > >               compatible = "fixed-clock";
> > >               #clock-cells = <0>;
> > >               clock-frequency = <32768>;
> > >       };
> > > 
> > >       soc: soc {
> > >               mcg: clock-controller at 40064000 {
> > >                       compatible = "fsl,kinetis-mcg";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40064000 0x14>;
> > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > >                       clock-names = "osc0", "osc1", "rtc";
> > >               };
> > > 
> > >               sim: clock-controller at 40047000 {
> > >                       compatible = "fsl,kinetis-sim";
> > >                       clock-cells = <1>;
> > >                       reg = <0x40047000 0x1100>;
> > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > >                       clock-names = "core", "bus", "flexbus", "flash";
> > >               };
> > >       };
> > > 
> > >       uart0: serial at 4006a000 {
> > >               compatible = "fsl,kinetis-lpuart";
> > >               reg = <0x4006a000 0x1000>;
> > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > >               clock-names = "gate";
> > >       };
> > > 
> > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > The above is the only style of binding that I have been accepting for
> > > some time; first declare the clock controller and establish its register
> > > space, and then consumers can consume clocks by providing the phandle to
> > > the controller plus an offset corresponding to a unique clock. The
> > > clock-names property makes it really easy to use with the clkdev stuff
> > > (e.g. clk_get()).
> > > 
> > > I've covered this before on the mailing list so here is a link
> > > describing how the qcom bindings do it in detail:
> > > 
> > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > 
> > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > sim nodes, but the shared header is how the magic happens with the
> > > driver so it's best to keep the clock controller binding small and
> > > light.
> > > 
> > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > exercise to the reader.
> > > 
> > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > usable for Kinetis.
> > > > 
> > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > 
> > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > >>>
> > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > >>>> and only describe the clocks that are related to the driver.
> > > > >>>
> > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > >>
> > > > >> The fact that they share a register is not making them a group. That's
> > > > >> just a HW design decision and you need to deal with that by protecting
> > > > >> the register access, but not by trying to group them artificially at
> > > > >> the functional level.
> > > > >
> > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > >
> > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > through the registers, the name is probably wrong and should be changed
> > > > > to whatever kind of non-fixed clock this is.
> > > > >
> > > > >       Arnd
> > > > >
> > > > 
> > > > _______________________________________________
> > > > linux-arm-kernel mailing list
> > > > linux-arm-kernel at lists.infradead.org
> > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-28 20:30                             ` Paul Osmialowski
  (?)
@ 2015-07-29 23:05                               ` Michael Turquette
  -1 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-29 23:05 UTC (permalink / raw)
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Arnd Bergmann, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

Quoting Paul Osmialowski (2015-07-28 13:30:17)
> Hi Mike,
> 
> My trouble is that now I'm dealing with two conradictory opinions on how 
> this driver should be written. The one you presented in your previous post 
> assumes that there will be a header file with defines shared between the 
> clock driver and DTS, also with clock gating details hidden behind some 
> additional level of indirection, e.g.:
> 
> clocks = <&sim SIM_SCGC4_UART1_CLK>;
> 
> Note that I've been through this at the very beginning, though the names 
> I used have been bit different, e.g.:
> 
> #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> 
> This was rejected with a comment by Arnd:
> 
> 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, are you OK with my type of binding description now that I
explained it with some examples?

> 
> So I dropped all of these includes and started to use magic numbers (as 
> you put it). Now I need to go one way or another or even go the third way: 
> extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> scgc_register_number bit_index_number>.

Paul,

>From my understanding the DT folks do not like register-level or
bit-level details going into DT. It is better to handle the clock
signals as abstract resources and link a provider and consumer with a
simple phandle plus an index representing that abstract resource (i.e.
the clock output signal).

> 
> Reading your previous post I'm starting to feel that it would bring me 
> closer to final acceptance if I stick to what you proposed in that post 
> (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> I'll probably adopt that.
> 
> You're right about my "get things up and running" attitude - currently I 
> want to develop things extensively (cover as much subsystems as 
> possible) and then at some stage switch to intensive approach. This board 
> is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> of coding opportunity in this field in the future.

I'm happy to take clock drivers and add my Reviewed-by to .dts files
that make use of fixed-rate and fixed-factor clocks as an interim
solution.  Of course it will be best to get The Real Thing merged
upstream asap, but this is something I've done before to help get new
platform upstream before and I'm fine to do it again.

With that said, Devicetree bindings are allegedly a stable ABI that
cannot be broken. So let's make sure that any Kinetis clock binding
description is in good shape before merging it. The rest can follow on
later if it needs to.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> On Tue, 28 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > Hi Mike,
> > > 
> > > Thank you for spending time on this and pointing me into the right 
> > > direction. I'm wondering about going even further with it. Assuming that I 
> > 
> > Hi Paul,
> > 
> > No problem! And thanks for the quick turnaround on your patches so far.
> > 
> > > know everything about my board, I can skip run-time discovery phase (note 
> > > that the original driver was designed for other Kinetis-based boards too) 
> > > and move everything into DTS, somewhat like this:
> > > 
> > > / {
> > >         osc0: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <50000000>;
> > >         };
> > > 
> > >         osc1: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <12000000>;
> > >         };
> > > 
> > >         rtc: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <32768>;
> > >         };
> > > 
> > >         mcgout: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&osc0>;
> > >                 clock-mult = <12>;
> > >                 clock-div = <5>;
> > >         };
> > 
> > I think this is a step backwards.
> > 
> > Did you look at the qcom clock binding and read the email where I
> > detailed how that binding works?
> > 
> > The point of that type of binding is to not shove per-clock data into
> > DT, but instead to declare every clock controller IP block (e.g. the
> > device) as well as every board-level clock (e.g. as osc that feeds into
> > your mcu). Once these "clock providers" are enumerated in DT, then we
> > create linkage between the clock providers and the clock consumers by
> > using phandles + an index. Linux device drivers tap into this by using
> > clk_get() and using the "clock-names" property from DT.
> > 
> > Put another way: we mostly use DT to model "devices". That is open to
> > interpretation for but for clock-related stuff we typically interpret
> > the clock controller as the device, not the individual clock outputs
> > coming out of the controller.
> > 
> > Note that a clock controller IP block may be both a provider and a
> > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > host controller, MMC controller, GPU, etc).
> > 
> > Additionally, from my reading of the reference manual, mcgout is defined
> > as:
> > 
> > """
> > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > MCGPLL1CLK, or MCG's external reference clock that
> > sources the core, system, bus, FlexBus, and flash clock. It is
> > also an option for the debug trace clock.
> > """
> > 
> > So why is it listed here as a fixed-factor clock? Is it not a
> > multiplexer? Also, why is it listed here at all? Please take another
> > look at the qcom binding example I linked to in my previous mail.
> > 
> > > 
> > >         core: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&mcgout>;
> > >                 clock-mult = <1>;
> > >                 clock-div = <1>;
> > >         };
> > > 
> > >         bus: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&mcgout>;
> > >                 clock-mult = <1>;
> > >                 clock-div = <2>;
> > 
> > These are actually not fixed dividers but programmable dividers. You can
> > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > fixed-dividers for the initial merge just to get things up and running
> > if that is your strategy, but you'll need to revisit them later on when
> > you need more flexible support for other boards.
> > 
> > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > enumerate your mcg clock controller and your sim clock controller? If
> > you want to be a perfectionist then it appears that there is an osc
> > clock controller upstream from the mcg controller as well ;-)
> > 
> > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > that you can program a sane default rate? We use the
> > assigned-clock-rates property for that. Note that this value is a
> > property of some device which *consumes* the clock, not the clock
> > controller or the clock output itself.
> > 
> > >         };
> > > 
> > >         soc {
> > >                 cmu@0x40047000 {
> > >                         compatible = "fsl,kinetis-gate-clock";
> > >                         reg = <0x40047000 0x1100>;
> > > 
> > >                         mcg_core_gate: clock-gate {
> > >                                 clocks = <&core>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > > 
> > >                         mcg_bus_gate: clock-gate {
> > >                                 clocks = <&bus>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > > 
> > >                         osc0_erclk_gate: clock-gate {
> > >                                 clocks = <&osc0>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > >                 };
> > > 
> > >                 uart0: serial@4006a000 {
> > >                         compatible = "fsl,kinetis-lpuart";
> > >                         reg = <0x4006a000 0x1000>;
> > >                         interrupts = <45>, <46>;
> > >                         interrupt-names = "uart-stat", "uart-err";
> > >                         clocks = <&mcg_core_gate 3 10>;
> > 
> > Magic numbers are not good. dtc has been able to use preprocessor macros
> > for a while now which means we can use constants instead of magic
> > numbers. Please look at the shared header in the qcom binding for an
> > example.
> > 
> > >                         clock-names = "ipg";
> > >                         dmas = <&edma 0 2>;
> > >                         dma-names = "rx";
> > >                         status = "disabled";
> > >                 };
> > >         };
> > > };
> > > 
> > > As you can see, mcg part is not required anymore.
> > 
> > I think the mcg should be required. The mcg is a real IP block on your
> > SoC, according to my reading of your technical reference manual. Just
> > because you can model a few of its output clocks in dts does not mean
> > that you should.
> > 
> > I did a quick grep and didn't find "cmu" anywhere in the reference
> > manual.
> > 
> > > 
> > > I guess that the approach above would require split into soc-specific and 
> > > board-specific part (as I said, dividers arrangement is something board 
> > > specific), but I wonder what you thing about this proposal.
> > 
> > Splitting is good. Chip-specific stuff can go into the chip-specific
> > dtsi file. The board-level (osc) stuff can go into the individual board
> > files. The ultimate goal is to make it trivial to add new boards.
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > Thanks,
> > > Paul
> > > 
> > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > Hi Arnd,
> > > > > 
> > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > situation clearer.
> > > > 
> > > > Hi Paul,
> > > > 
> > > > Can you please post the patch in the body of the email instead of an
> > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > the $SUBJECT for this patch might be better off as something like:
> > > > 
> > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > 
> > > > At least it helps me find the patch I care about when skimming the
> > > > series ;-)
> > > > 
> > > > > 
> > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > 
> > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > 
> > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > >      as clock source for the main PLL.
> > > > 
> > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > both feed into a mux. You should model this 32k clock with the
> > > > fixed-rate binding.
> > > > 
> > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > >      TWR-K70F120M boards).
> > > > > 
> > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > PCLK.
> > > > 
> > > > I'm confused. The point of device tree is to solve problems like this;
> > > > i.e. board-specific differences such as different oscillator
> > > > frequencies.
> > > > 
> > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > it appears to mandated in the reference manual[0].
> > > > 
> > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > need to worry about this if they spin a board, and then they will need
> > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > .dts.
> > > > 
> > > > Please break clk-kinetis.c into two files:
> > > > drivers/clk/kinetis/clk-mcg.c
> > > > drivers/clk/kinetis/clk-sim.c
> > > > 
> > > > Below is what your binding/dts should look like:
> > > > 
> > > > {
> > > >       osc0: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <50000000>;
> > > >       };
> > > > 
> > > >       osc1: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <12000000>;
> > > >       };
> > > > 
> > > >       rtc: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <32768>;
> > > >       };
> > > > 
> > > >       soc: soc {
> > > >               mcg: clock-controller@40064000 {
> > > >                       compatible = "fsl,kinetis-mcg";
> > > >                       clock-cells = <1>;
> > > >                       reg = <0x40064000 0x14>;
> > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > >                       clock-names = "osc0", "osc1", "rtc";
> > > >               };
> > > > 
> > > >               sim: clock-controller@40047000 {
> > > >                       compatible = "fsl,kinetis-sim";
> > > >                       clock-cells = <1>;
> > > >                       reg = <0x40047000 0x1100>;
> > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > >               };
> > > >       };
> > > > 
> > > >       uart0: serial@4006a000 {
> > > >               compatible = "fsl,kinetis-lpuart";
> > > >               reg = <0x4006a000 0x1000>;
> > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > >               clock-names = "gate";
> > > >       };
> > > > 
> > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > The above is the only style of binding that I have been accepting for
> > > > some time; first declare the clock controller and establish its register
> > > > space, and then consumers can consume clocks by providing the phandle to
> > > > the controller plus an offset corresponding to a unique clock. The
> > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > (e.g. clk_get()).
> > > > 
> > > > I've covered this before on the mailing list so here is a link
> > > > describing how the qcom bindings do it in detail:
> > > > 
> > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > 
> > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > sim nodes, but the shared header is how the magic happens with the
> > > > driver so it's best to keep the clock controller binding small and
> > > > light.
> > > > 
> > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > exercise to the reader.
> > > > 
> > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > usable for Kinetis.
> > > > > 
> > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > 
> > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > >>>
> > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > >>>
> > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > >>
> > > > > >> The fact that they share a register is not making them a group. That's
> > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > >> the register access, but not by trying to group them artificially at
> > > > > >> the functional level.
> > > > > >
> > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > >
> > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > to whatever kind of non-fixed clock this is.
> > > > > >
> > > > > >       Arnd
> > > > > >
> > > > > 
> > > > > _______________________________________________
> > > > > linux-arm-kernel mailing list
> > > > > linux-arm-kernel@lists.infradead.org
> > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-29 23:05                               ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-29 23:05 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Quoting Paul Osmialowski (2015-07-28 13:30:17)
> Hi Mike,
> =

> My trouble is that now I'm dealing with two conradictory opinions on how =

> this driver should be written. The one you presented in your previous pos=
t =

> assumes that there will be a header file with defines shared between the =

> clock driver and DTS, also with clock gating details hidden behind some =

> additional level of indirection, e.g.:
> =

> clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
> =

> Note that I've been through this at the very beginning, though the names =

> I used have been bit different, e.g.:
> =

> #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> =

> This was rejected with a comment by Arnd:
> =

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

Arnd, are you OK with my type of binding description now that I
explained it with some examples?

> =

> So I dropped all of these includes and started to use magic numbers (as =

> you put it). Now I need to go one way or another or even go the third way=
: =

> extend #clock-cells to <3> and address it like: <&sim parent_clock_id =

> scgc_register_number bit_index_number>.

Paul,

From=20my understanding the DT folks do not like register-level or
bit-level details going into DT. It is better to handle the clock
signals as abstract resources and link a provider and consumer with a
simple phandle plus an index representing that abstract resource (i.e.
the clock output signal).

> =

> Reading your previous post I'm starting to feel that it would bring me =

> closer to final acceptance if I stick to what you proposed in that post =

> (I'm really grateful to you for writting so huge chunk of DTS for me!), s=
o =

> I'll probably adopt that.
> =

> You're right about my "get things up and running" attitude - currently I =

> want to develop things extensively (cover as much subsystems as =

> possible) and then at some stage switch to intensive approach. This board =

> is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot =

> of coding opportunity in this field in the future.

I'm happy to take clock drivers and add my Reviewed-by to .dts files
that make use of fixed-rate and fixed-factor clocks as an interim
solution.  Of course it will be best to get The Real Thing merged
upstream asap, but this is something I've done before to help get new
platform upstream before and I'm fine to do it again.

With that said, Devicetree bindings are allegedly a stable ABI that
cannot be broken. So let's make sure that any Kinetis clock binding
description is in good shape before merging it. The rest can follow on
later if it needs to.

Regards,
Mike

> =

> Thanks,
> Paul
> =

> On Tue, 28 Jul 2015, Michael Turquette wrote:
> =

> > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > Hi Mike,
> > > =

> > > Thank you for spending time on this and pointing me into the right =

> > > direction. I'm wondering about going even further with it. Assuming t=
hat I =

> > =

> > Hi Paul,
> > =

> > No problem! And thanks for the quick turnaround on your patches so far.
> > =

> > > know everything about my board, I can skip run-time discovery phase (=
note =

> > > that the original driver was designed for other Kinetis-based boards =
too) =

> > > and move everything into DTS, somewhat like this:
> > > =

> > > / {
> > >         osc0: clock {
> > >                 compatible =3D "fixed-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clock-frequency =3D <50000000>;
> > >         };
> > > =

> > >         osc1: clock {
> > >                 compatible =3D "fixed-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clock-frequency =3D <12000000>;
> > >         };
> > > =

> > >         rtc: clock {
> > >                 compatible =3D "fixed-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clock-frequency =3D <32768>;
> > >         };
> > > =

> > >         mcgout: clock {
> > >                 compatible =3D "fixed-factor-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clocks =3D <&osc0>;
> > >                 clock-mult =3D <12>;
> > >                 clock-div =3D <5>;
> > >         };
> > =

> > I think this is a step backwards.
> > =

> > Did you look at the qcom clock binding and read the email where I
> > detailed how that binding works?
> > =

> > The point of that type of binding is to not shove per-clock data into
> > DT, but instead to declare every clock controller IP block (e.g. the
> > device) as well as every board-level clock (e.g. as osc that feeds into
> > your mcu). Once these "clock providers" are enumerated in DT, then we
> > create linkage between the clock providers and the clock consumers by
> > using phandles + an index. Linux device drivers tap into this by using
> > clk_get() and using the "clock-names" property from DT.
> > =

> > Put another way: we mostly use DT to model "devices". That is open to
> > interpretation for but for clock-related stuff we typically interpret
> > the clock controller as the device, not the individual clock outputs
> > coming out of the controller.
> > =

> > Note that a clock controller IP block may be both a provider and a
> > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > host controller, MMC controller, GPU, etc).
> > =

> > Additionally, from my reading of the reference manual, mcgout is defined
> > as:
> > =

> > """
> > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > MCGPLL1CLK, or MCG's external reference clock that
> > sources the core, system, bus, FlexBus, and flash clock. It is
> > also an option for the debug trace clock.
> > """
> > =

> > So why is it listed here as a fixed-factor clock? Is it not a
> > multiplexer? Also, why is it listed here at all? Please take another
> > look at the qcom binding example I linked to in my previous mail.
> > =

> > > =

> > >         core: clock {
> > >                 compatible =3D "fixed-factor-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clocks =3D <&mcgout>;
> > >                 clock-mult =3D <1>;
> > >                 clock-div =3D <1>;
> > >         };
> > > =

> > >         bus: clock {
> > >                 compatible =3D "fixed-factor-clock";
> > >                 #clock-cells =3D <0>;
> > >                 clocks =3D <&mcgout>;
> > >                 clock-mult =3D <1>;
> > >                 clock-div =3D <2>;
> > =

> > These are actually not fixed dividers but programmable dividers. You can
> > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > fixed-dividers for the initial merge just to get things up and running
> > if that is your strategy, but you'll need to revisit them later on when
> > you need more flexible support for other boards.
> > =

> > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > enumerate your mcg clock controller and your sim clock controller? If
> > you want to be a perfectionist then it appears that there is an osc
> > clock controller upstream from the mcg controller as well ;-)
> > =

> > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > that you can program a sane default rate? We use the
> > assigned-clock-rates property for that. Note that this value is a
> > property of some device which *consumes* the clock, not the clock
> > controller or the clock output itself.
> > =

> > >         };
> > > =

> > >         soc {
> > >                 cmu@0x40047000 {
> > >                         compatible =3D "fsl,kinetis-gate-clock";
> > >                         reg =3D <0x40047000 0x1100>;
> > > =

> > >                         mcg_core_gate: clock-gate {
> > >                                 clocks =3D <&core>;
> > >                                 #clock-cells =3D <2>;
> > >                         };
> > > =

> > >                         mcg_bus_gate: clock-gate {
> > >                                 clocks =3D <&bus>;
> > >                                 #clock-cells =3D <2>;
> > >                         };
> > > =

> > >                         osc0_erclk_gate: clock-gate {
> > >                                 clocks =3D <&osc0>;
> > >                                 #clock-cells =3D <2>;
> > >                         };
> > >                 };
> > > =

> > >                 uart0: serial@4006a000 {
> > >                         compatible =3D "fsl,kinetis-lpuart";
> > >                         reg =3D <0x4006a000 0x1000>;
> > >                         interrupts =3D <45>, <46>;
> > >                         interrupt-names =3D "uart-stat", "uart-err";
> > >                         clocks =3D <&mcg_core_gate 3 10>;
> > =

> > Magic numbers are not good. dtc has been able to use preprocessor macros
> > for a while now which means we can use constants instead of magic
> > numbers. Please look at the shared header in the qcom binding for an
> > example.
> > =

> > >                         clock-names =3D "ipg";
> > >                         dmas =3D <&edma 0 2>;
> > >                         dma-names =3D "rx";
> > >                         status =3D "disabled";
> > >                 };
> > >         };
> > > };
> > > =

> > > As you can see, mcg part is not required anymore.
> > =

> > I think the mcg should be required. The mcg is a real IP block on your
> > SoC, according to my reading of your technical reference manual. Just
> > because you can model a few of its output clocks in dts does not mean
> > that you should.
> > =

> > I did a quick grep and didn't find "cmu" anywhere in the reference
> > manual.
> > =

> > > =

> > > I guess that the approach above would require split into soc-specific=
 and =

> > > board-specific part (as I said, dividers arrangement is something boa=
rd =

> > > specific), but I wonder what you thing about this proposal.
> > =

> > Splitting is good. Chip-specific stuff can go into the chip-specific
> > dtsi file. The board-level (osc) stuff can go into the individual board
> > files. The ultimate goal is to make it trivial to add new boards.
> > =

> > Regards,
> > Mike
> > =

> > > =

> > > Thanks,
> > > Paul
> > > =

> > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > =

> > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > Hi Arnd,
> > > > > =

> > > > > I'm attaching excerpt from Kinetis reference manual that may make =

> > > > > situation clearer.
> > > > =

> > > > Hi Paul,
> > > > =

> > > > Can you please post the patch in the body of the email instead of an
> > > > attachment? It makes it easier to review. Another small nitpick is =
that
> > > > the $SUBJECT for this patch might be better off as something like:
> > > > =

> > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > =

> > > > At least it helps me find the patch I care about when skimming the
> > > > series ;-)
> > > > =

> > > > > =

> > > > > These MCG and SIM registers are used only to determine configurat=
ion =

> > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > =

> > > > > Namely, the real MCGOUTCLK source (in the middle) which is the pa=
rent for =

> > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at ru=
n time by =

> > > > > reading MCG registers, let me quote commit message from Emcraft g=
it repo:
> > > > > =

> > > > >       * Determine in run-time what oscillator module (OSC0 or OSC=
1) is used
> > > > >      as clock source for the main PLL.
> > > > =

> > > > According to [0] there are three options: a 32k RTC osc clock and o=
sc0
> > > > both feed into a mux. You should model this 32k clock with the
> > > > fixed-rate binding.
> > > > =

> > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz =
on all
> > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-=
SOM and
> > > > >      TWR-K70F120M boards).
> > > > > =

> > > > > In my .dts I'm trying to possibly follow real clock hierarchy, bu=
t to go =

> > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e=
.g. by =

> > > > > U-boot. But that's too demanding for any potential users of this =
BSP. So =

> > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCL=
K and =

> > > > > PCLK.
> > > > =

> > > > I'm confused. The point of device tree is to solve problems like th=
is;
> > > > i.e. board-specific differences such as different oscillator
> > > > frequencies.
> > > > =

> > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-speci=
fic
> > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in =
the
> > > > cmu node, and they should use the "fixed-clock" binding. The 32k RT=
C osc
> > > > can probably go in your chip-specific .dtsi as a fixed-rate clock s=
ince
> > > > it appears to mandated in the reference manual[0].
> > > > =

> > > > These three fixed-rate clocks are your root clock nodes. Customers =
only
> > > > need to worry about this if they spin a board, and then they will n=
eed
> > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > .dts.
> > > > =

> > > > Please break clk-kinetis.c into two files:
> > > > drivers/clk/kinetis/clk-mcg.c
> > > > drivers/clk/kinetis/clk-sim.c
> > > > =

> > > > Below is what your binding/dts should look like:
> > > > =

> > > > {
> > > >       osc0: clock {
> > > >               compatible =3D "fixed-clock";
> > > >               #clock-cells =3D <0>;
> > > >               clock-frequency =3D <50000000>;
> > > >       };
> > > > =

> > > >       osc1: clock {
> > > >               compatible =3D "fixed-clock";
> > > >               #clock-cells =3D <0>;
> > > >               clock-frequency =3D <12000000>;
> > > >       };
> > > > =

> > > >       rtc: clock {
> > > >               compatible =3D "fixed-clock";
> > > >               #clock-cells =3D <0>;
> > > >               clock-frequency =3D <32768>;
> > > >       };
> > > > =

> > > >       soc: soc {
> > > >               mcg: clock-controller@40064000 {
> > > >                       compatible =3D "fsl,kinetis-mcg";
> > > >                       clock-cells =3D <1>;
> > > >                       reg =3D <0x40064000 0x14>;
> > > >                       clocks =3D <&osc0>, <&osc1>, <&rtc>;
> > > >                       clock-names =3D "osc0", "osc1", "rtc";
> > > >               };
> > > > =

> > > >               sim: clock-controller@40047000 {
> > > >                       compatible =3D "fsl,kinetis-sim";
> > > >                       clock-cells =3D <1>;
> > > >                       reg =3D <0x40047000 0x1100>;
> > > >                       clocks =3D <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg M=
CG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > >                       clock-names =3D "core", "bus", "flexbus", "fl=
ash";
> > > >               };
> > > >       };
> > > > =

> > > >       uart0: serial@4006a000 {
> > > >               compatible =3D "fsl,kinetis-lpuart";
> > > >               reg =3D <0x4006a000 0x1000>;
> > > >               clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
> > > >               clock-names =3D "gate";
> > > >       };
> > > > =

> > > > I removed the interrupts and dma stuff from the uart0 node for clar=
ity.
> > > > The above is the only style of binding that I have been accepting f=
or
> > > > some time; first declare the clock controller and establish its reg=
ister
> > > > space, and then consumers can consume clocks by providing the phand=
le to
> > > > the controller plus an offset corresponding to a unique clock. The
> > > > clock-names property makes it really easy to use with the clkdev st=
uff
> > > > (e.g. clk_get()).
> > > > =

> > > > I've covered this before on the mailing list so here is a link
> > > > describing how the qcom bindings do it in detail:
> > > > =

> > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > =

> > > > Technically you could encode the same bits as sub-nodes of the mcg =
and
> > > > sim nodes, but the shared header is how the magic happens with the
> > > > driver so it's best to keep the clock controller binding small and
> > > > light.
> > > > =

> > > > I think this means you can also get rid of kinetis_of_clk_get_name =
and
> > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > exercise to the reader.
> > > > =

> > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manua=
l/K70P256M150SF3RM.pdf
> > > > =

> > > > Regards,
> > > > Mike
> > > > =

> > > > > =

> > > > > In my most recent version I added OSC0ERCLK explicitly as one mor=
e root =

> > > > > clock, since it is also used directly (through CG reg. 1 bit 0) b=
y =

> > > > > Freescale fec network device whose in-tree driver I'm trying to m=
ake =

> > > > > usable for Kinetis.
> > > > > =

> > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > =

> > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > >>>
> > > > > >>>> I wonder if you could move out the fixed rate clocks into th=
eir own
> > > > > >>>> nodes. Are they actually controlled by the same block? If th=
ey are
> > > > > >>>> just fixed, you can use the normal binding for fixed rate cl=
ocks
> > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > >>>
> > > > > >>> In my view having these clocks grouped together looks more co=
nvincing. After
> > > > > >>> all, they all share the same I/O regs in order to read config=
uration.
> > > > > >>
> > > > > >> The fact that they share a register is not making them a group=
. That's
> > > > > >> just a HW design decision and you need to deal with that by pr=
otecting
> > > > > >> the register access, but not by trying to group them artificia=
lly at
> > > > > >> the functional level.
> > > > > >
> > > > > > I'd disagree with that: The clock controller is the device that=
 owns the
> > > > > > registers and that should be one node in DT, as Paul's first ve=
rsion does.
> > > > > >
> > > > > > The part I'm still struggling with is understanding how the fix=
ed-rate
> > > > > > clocks are controlled through those registers. If they are inde=
ed configured
> > > > > > through the registers, the name is probably wrong and should be=
 changed
> > > > > > to whatever kind of non-fixed clock this is.
> > > > > >
> > > > > >       Arnd
> > > > > >
> > > > > =

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

> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kerne=
l" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > =

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-29 23:05                               ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-07-29 23:05 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Paul Osmialowski (2015-07-28 13:30:17)
> Hi Mike,
> 
> My trouble is that now I'm dealing with two conradictory opinions on how 
> this driver should be written. The one you presented in your previous post 
> assumes that there will be a header file with defines shared between the 
> clock driver and DTS, also with clock gating details hidden behind some 
> additional level of indirection, e.g.:
> 
> clocks = <&sim SIM_SCGC4_UART1_CLK>;
> 
> Note that I've been through this at the very beginning, though the names 
> I used have been bit different, e.g.:
> 
> #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> 
> This was rejected with a comment by Arnd:
> 
> 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, are you OK with my type of binding description now that I
explained it with some examples?

> 
> So I dropped all of these includes and started to use magic numbers (as 
> you put it). Now I need to go one way or another or even go the third way: 
> extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> scgc_register_number bit_index_number>.

Paul,

>From my understanding the DT folks do not like register-level or
bit-level details going into DT. It is better to handle the clock
signals as abstract resources and link a provider and consumer with a
simple phandle plus an index representing that abstract resource (i.e.
the clock output signal).

> 
> Reading your previous post I'm starting to feel that it would bring me 
> closer to final acceptance if I stick to what you proposed in that post 
> (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> I'll probably adopt that.
> 
> You're right about my "get things up and running" attitude - currently I 
> want to develop things extensively (cover as much subsystems as 
> possible) and then at some stage switch to intensive approach. This board 
> is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> of coding opportunity in this field in the future.

I'm happy to take clock drivers and add my Reviewed-by to .dts files
that make use of fixed-rate and fixed-factor clocks as an interim
solution.  Of course it will be best to get The Real Thing merged
upstream asap, but this is something I've done before to help get new
platform upstream before and I'm fine to do it again.

With that said, Devicetree bindings are allegedly a stable ABI that
cannot be broken. So let's make sure that any Kinetis clock binding
description is in good shape before merging it. The rest can follow on
later if it needs to.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> On Tue, 28 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > Hi Mike,
> > > 
> > > Thank you for spending time on this and pointing me into the right 
> > > direction. I'm wondering about going even further with it. Assuming that I 
> > 
> > Hi Paul,
> > 
> > No problem! And thanks for the quick turnaround on your patches so far.
> > 
> > > know everything about my board, I can skip run-time discovery phase (note 
> > > that the original driver was designed for other Kinetis-based boards too) 
> > > and move everything into DTS, somewhat like this:
> > > 
> > > / {
> > >         osc0: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <50000000>;
> > >         };
> > > 
> > >         osc1: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <12000000>;
> > >         };
> > > 
> > >         rtc: clock {
> > >                 compatible = "fixed-clock";
> > >                 #clock-cells = <0>;
> > >                 clock-frequency = <32768>;
> > >         };
> > > 
> > >         mcgout: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&osc0>;
> > >                 clock-mult = <12>;
> > >                 clock-div = <5>;
> > >         };
> > 
> > I think this is a step backwards.
> > 
> > Did you look at the qcom clock binding and read the email where I
> > detailed how that binding works?
> > 
> > The point of that type of binding is to not shove per-clock data into
> > DT, but instead to declare every clock controller IP block (e.g. the
> > device) as well as every board-level clock (e.g. as osc that feeds into
> > your mcu). Once these "clock providers" are enumerated in DT, then we
> > create linkage between the clock providers and the clock consumers by
> > using phandles + an index. Linux device drivers tap into this by using
> > clk_get() and using the "clock-names" property from DT.
> > 
> > Put another way: we mostly use DT to model "devices". That is open to
> > interpretation for but for clock-related stuff we typically interpret
> > the clock controller as the device, not the individual clock outputs
> > coming out of the controller.
> > 
> > Note that a clock controller IP block may be both a provider and a
> > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > host controller, MMC controller, GPU, etc).
> > 
> > Additionally, from my reading of the reference manual, mcgout is defined
> > as:
> > 
> > """
> > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > MCGPLL1CLK, or MCG's external reference clock that
> > sources the core, system, bus, FlexBus, and flash clock. It is
> > also an option for the debug trace clock.
> > """
> > 
> > So why is it listed here as a fixed-factor clock? Is it not a
> > multiplexer? Also, why is it listed here at all? Please take another
> > look at the qcom binding example I linked to in my previous mail.
> > 
> > > 
> > >         core: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&mcgout>;
> > >                 clock-mult = <1>;
> > >                 clock-div = <1>;
> > >         };
> > > 
> > >         bus: clock {
> > >                 compatible = "fixed-factor-clock";
> > >                 #clock-cells = <0>;
> > >                 clocks = <&mcgout>;
> > >                 clock-mult = <1>;
> > >                 clock-div = <2>;
> > 
> > These are actually not fixed dividers but programmable dividers. You can
> > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > fixed-dividers for the initial merge just to get things up and running
> > if that is your strategy, but you'll need to revisit them later on when
> > you need more flexible support for other boards.
> > 
> > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > enumerate your mcg clock controller and your sim clock controller? If
> > you want to be a perfectionist then it appears that there is an osc
> > clock controller upstream from the mcg controller as well ;-)
> > 
> > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > that you can program a sane default rate? We use the
> > assigned-clock-rates property for that. Note that this value is a
> > property of some device which *consumes* the clock, not the clock
> > controller or the clock output itself.
> > 
> > >         };
> > > 
> > >         soc {
> > >                 cmu at 0x40047000 {
> > >                         compatible = "fsl,kinetis-gate-clock";
> > >                         reg = <0x40047000 0x1100>;
> > > 
> > >                         mcg_core_gate: clock-gate {
> > >                                 clocks = <&core>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > > 
> > >                         mcg_bus_gate: clock-gate {
> > >                                 clocks = <&bus>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > > 
> > >                         osc0_erclk_gate: clock-gate {
> > >                                 clocks = <&osc0>;
> > >                                 #clock-cells = <2>;
> > >                         };
> > >                 };
> > > 
> > >                 uart0: serial at 4006a000 {
> > >                         compatible = "fsl,kinetis-lpuart";
> > >                         reg = <0x4006a000 0x1000>;
> > >                         interrupts = <45>, <46>;
> > >                         interrupt-names = "uart-stat", "uart-err";
> > >                         clocks = <&mcg_core_gate 3 10>;
> > 
> > Magic numbers are not good. dtc has been able to use preprocessor macros
> > for a while now which means we can use constants instead of magic
> > numbers. Please look at the shared header in the qcom binding for an
> > example.
> > 
> > >                         clock-names = "ipg";
> > >                         dmas = <&edma 0 2>;
> > >                         dma-names = "rx";
> > >                         status = "disabled";
> > >                 };
> > >         };
> > > };
> > > 
> > > As you can see, mcg part is not required anymore.
> > 
> > I think the mcg should be required. The mcg is a real IP block on your
> > SoC, according to my reading of your technical reference manual. Just
> > because you can model a few of its output clocks in dts does not mean
> > that you should.
> > 
> > I did a quick grep and didn't find "cmu" anywhere in the reference
> > manual.
> > 
> > > 
> > > I guess that the approach above would require split into soc-specific and 
> > > board-specific part (as I said, dividers arrangement is something board 
> > > specific), but I wonder what you thing about this proposal.
> > 
> > Splitting is good. Chip-specific stuff can go into the chip-specific
> > dtsi file. The board-level (osc) stuff can go into the individual board
> > files. The ultimate goal is to make it trivial to add new boards.
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > Thanks,
> > > Paul
> > > 
> > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > Hi Arnd,
> > > > > 
> > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > situation clearer.
> > > > 
> > > > Hi Paul,
> > > > 
> > > > Can you please post the patch in the body of the email instead of an
> > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > the $SUBJECT for this patch might be better off as something like:
> > > > 
> > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > 
> > > > At least it helps me find the patch I care about when skimming the
> > > > series ;-)
> > > > 
> > > > > 
> > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > 
> > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > 
> > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > >      as clock source for the main PLL.
> > > > 
> > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > both feed into a mux. You should model this 32k clock with the
> > > > fixed-rate binding.
> > > > 
> > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > >      TWR-K70F120M boards).
> > > > > 
> > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > PCLK.
> > > > 
> > > > I'm confused. The point of device tree is to solve problems like this;
> > > > i.e. board-specific differences such as different oscillator
> > > > frequencies.
> > > > 
> > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > it appears to mandated in the reference manual[0].
> > > > 
> > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > need to worry about this if they spin a board, and then they will need
> > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > .dts.
> > > > 
> > > > Please break clk-kinetis.c into two files:
> > > > drivers/clk/kinetis/clk-mcg.c
> > > > drivers/clk/kinetis/clk-sim.c
> > > > 
> > > > Below is what your binding/dts should look like:
> > > > 
> > > > {
> > > >       osc0: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <50000000>;
> > > >       };
> > > > 
> > > >       osc1: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <12000000>;
> > > >       };
> > > > 
> > > >       rtc: clock {
> > > >               compatible = "fixed-clock";
> > > >               #clock-cells = <0>;
> > > >               clock-frequency = <32768>;
> > > >       };
> > > > 
> > > >       soc: soc {
> > > >               mcg: clock-controller at 40064000 {
> > > >                       compatible = "fsl,kinetis-mcg";
> > > >                       clock-cells = <1>;
> > > >                       reg = <0x40064000 0x14>;
> > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > >                       clock-names = "osc0", "osc1", "rtc";
> > > >               };
> > > > 
> > > >               sim: clock-controller at 40047000 {
> > > >                       compatible = "fsl,kinetis-sim";
> > > >                       clock-cells = <1>;
> > > >                       reg = <0x40047000 0x1100>;
> > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > >               };
> > > >       };
> > > > 
> > > >       uart0: serial at 4006a000 {
> > > >               compatible = "fsl,kinetis-lpuart";
> > > >               reg = <0x4006a000 0x1000>;
> > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > >               clock-names = "gate";
> > > >       };
> > > > 
> > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > The above is the only style of binding that I have been accepting for
> > > > some time; first declare the clock controller and establish its register
> > > > space, and then consumers can consume clocks by providing the phandle to
> > > > the controller plus an offset corresponding to a unique clock. The
> > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > (e.g. clk_get()).
> > > > 
> > > > I've covered this before on the mailing list so here is a link
> > > > describing how the qcom bindings do it in detail:
> > > > 
> > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > 
> > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > sim nodes, but the shared header is how the magic happens with the
> > > > driver so it's best to keep the clock controller binding small and
> > > > light.
> > > > 
> > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > exercise to the reader.
> > > > 
> > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > usable for Kinetis.
> > > > > 
> > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > 
> > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > >>>
> > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > >>>
> > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > >>
> > > > > >> The fact that they share a register is not making them a group. That's
> > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > >> the register access, but not by trying to group them artificially at
> > > > > >> the functional level.
> > > > > >
> > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > >
> > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > to whatever kind of non-fixed clock this is.
> > > > > >
> > > > > >       Arnd
> > > > > >
> > > > > 
> > > > > _______________________________________________
> > > > > linux-arm-kernel mailing list
> > > > > linux-arm-kernel at lists.infradead.org
> > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo at vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-29 23:05                               ` Michael Turquette
  (?)
@ 2015-07-30 21:40                                 ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-30 21:40 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner

Hi Mike,

I encountered some trouble while I tried to implement code fitting to DTS 
that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
Therefore, in MCG device code I won't be able to figure out clock rate 
for outputed clocks unles I try to access SIM registers from MCG driver - 
that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
to expose not core, bus and the others:

        soc {
                mcg: clock-controller@40064000 {
                        compatible = "fsl,kinetis-mcg";
                        clock-cells = <0>;
                        reg = <0x40064000 0x14>;
                        clocks = <&osc0>, <&osc1>, <&rtc>;
                        clock-names = "osc0", "osc1", "rtc";
                };
                sim: clock-controller@40047000 {
                        compatible = "fsl,kinetis-sim";
                        clock-cells = <1>;
                        reg = <0x40047000 0x1100>;
                        clocks = <&mcg>,
                                 <&osc0>;
                        clock-names = "mcgoutclk", "enet";
                };

                uart0: serial@4006a000 {
                        compatible = "fsl,kinetis-lpuart";
                        reg = <0x4006a000 0x1000>;
                        interrupts = <45>, <46>;
                        interrupt-names = "uart-stat", "uart-err";
                        clocks = <&sim SIM_SCGC4_UART0_CLK>;
                        clock-names = "ipg";
                        dmas = <&edma 0 2>;
                        dma-names = "rx";
                        status = "disabled";
                };
        };

Now fsl,kinetis-sim device will be responsible for clock gating and it 
will know about core, bus, flexbus and flash clocks only internally - 
none of them are exposed.

Also note that fec (ethernet device) driver is connected directly to osc0 
(though clock gate, you can see this CG attached to osc0 on the diagram 
too) - to control this gate I need to access SIM device registers, so it 
should be covered by the same fsl,kinetis-sim driver.

On Wed, 29 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > Hi Mike,
> > 
> > My trouble is that now I'm dealing with two conradictory opinions on how 
> > this driver should be written. The one you presented in your previous post 
> > assumes that there will be a header file with defines shared between the 
> > clock driver and DTS, also with clock gating details hidden behind some 
> > additional level of indirection, e.g.:
> > 
> > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > 
> > Note that I've been through this at the very beginning, though the names 
> > I used have been bit different, e.g.:
> > 
> > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > 
> > This was rejected with a comment by Arnd:
> > 
> > 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, are you OK with my type of binding description now that I
> explained it with some examples?
> 
> > 
> > So I dropped all of these includes and started to use magic numbers (as 
> > you put it). Now I need to go one way or another or even go the third way: 
> > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > scgc_register_number bit_index_number>.
> 
> Paul,
> 
> >From my understanding the DT folks do not like register-level or
> bit-level details going into DT. It is better to handle the clock
> signals as abstract resources and link a provider and consumer with a
> simple phandle plus an index representing that abstract resource (i.e.
> the clock output signal).
> 
> > 
> > Reading your previous post I'm starting to feel that it would bring me 
> > closer to final acceptance if I stick to what you proposed in that post 
> > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > I'll probably adopt that.
> > 
> > You're right about my "get things up and running" attitude - currently I 
> > want to develop things extensively (cover as much subsystems as 
> > possible) and then at some stage switch to intensive approach. This board 
> > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > of coding opportunity in this field in the future.
> 
> I'm happy to take clock drivers and add my Reviewed-by to .dts files
> that make use of fixed-rate and fixed-factor clocks as an interim
> solution.  Of course it will be best to get The Real Thing merged
> upstream asap, but this is something I've done before to help get new
> platform upstream before and I'm fine to do it again.
> 
> With that said, Devicetree bindings are allegedly a stable ABI that
> cannot be broken. So let's make sure that any Kinetis clock binding
> description is in good shape before merging it. The rest can follow on
> later if it needs to.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > Hi Mike,
> > > > 
> > > > Thank you for spending time on this and pointing me into the right 
> > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > 
> > > Hi Paul,
> > > 
> > > No problem! And thanks for the quick turnaround on your patches so far.
> > > 
> > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > and move everything into DTS, somewhat like this:
> > > > 
> > > > / {
> > > >         osc0: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <50000000>;
> > > >         };
> > > > 
> > > >         osc1: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <12000000>;
> > > >         };
> > > > 
> > > >         rtc: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <32768>;
> > > >         };
> > > > 
> > > >         mcgout: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&osc0>;
> > > >                 clock-mult = <12>;
> > > >                 clock-div = <5>;
> > > >         };
> > > 
> > > I think this is a step backwards.
> > > 
> > > Did you look at the qcom clock binding and read the email where I
> > > detailed how that binding works?
> > > 
> > > The point of that type of binding is to not shove per-clock data into
> > > DT, but instead to declare every clock controller IP block (e.g. the
> > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > create linkage between the clock providers and the clock consumers by
> > > using phandles + an index. Linux device drivers tap into this by using
> > > clk_get() and using the "clock-names" property from DT.
> > > 
> > > Put another way: we mostly use DT to model "devices". That is open to
> > > interpretation for but for clock-related stuff we typically interpret
> > > the clock controller as the device, not the individual clock outputs
> > > coming out of the controller.
> > > 
> > > Note that a clock controller IP block may be both a provider and a
> > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > host controller, MMC controller, GPU, etc).
> > > 
> > > Additionally, from my reading of the reference manual, mcgout is defined
> > > as:
> > > 
> > > """
> > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > MCGPLL1CLK, or MCG's external reference clock that
> > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > also an option for the debug trace clock.
> > > """
> > > 
> > > So why is it listed here as a fixed-factor clock? Is it not a
> > > multiplexer? Also, why is it listed here at all? Please take another
> > > look at the qcom binding example I linked to in my previous mail.
> > > 
> > > > 
> > > >         core: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <1>;
> > > >         };
> > > > 
> > > >         bus: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <2>;
> > > 
> > > These are actually not fixed dividers but programmable dividers. You can
> > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > fixed-dividers for the initial merge just to get things up and running
> > > if that is your strategy, but you'll need to revisit them later on when
> > > you need more flexible support for other boards.
> > > 
> > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > enumerate your mcg clock controller and your sim clock controller? If
> > > you want to be a perfectionist then it appears that there is an osc
> > > clock controller upstream from the mcg controller as well ;-)
> > > 
> > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > that you can program a sane default rate? We use the
> > > assigned-clock-rates property for that. Note that this value is a
> > > property of some device which *consumes* the clock, not the clock
> > > controller or the clock output itself.
> > > 
> > > >         };
> > > > 
> > > >         soc {
> > > >                 cmu@0x40047000 {
> > > >                         compatible = "fsl,kinetis-gate-clock";
> > > >                         reg = <0x40047000 0x1100>;
> > > > 
> > > >                         mcg_core_gate: clock-gate {
> > > >                                 clocks = <&core>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         mcg_bus_gate: clock-gate {
> > > >                                 clocks = <&bus>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         osc0_erclk_gate: clock-gate {
> > > >                                 clocks = <&osc0>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > >                 };
> > > > 
> > > >                 uart0: serial@4006a000 {
> > > >                         compatible = "fsl,kinetis-lpuart";
> > > >                         reg = <0x4006a000 0x1000>;
> > > >                         interrupts = <45>, <46>;
> > > >                         interrupt-names = "uart-stat", "uart-err";
> > > >                         clocks = <&mcg_core_gate 3 10>;
> > > 
> > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > for a while now which means we can use constants instead of magic
> > > numbers. Please look at the shared header in the qcom binding for an
> > > example.
> > > 
> > > >                         clock-names = "ipg";
> > > >                         dmas = <&edma 0 2>;
> > > >                         dma-names = "rx";
> > > >                         status = "disabled";
> > > >                 };
> > > >         };
> > > > };
> > > > 
> > > > As you can see, mcg part is not required anymore.
> > > 
> > > I think the mcg should be required. The mcg is a real IP block on your
> > > SoC, according to my reading of your technical reference manual. Just
> > > because you can model a few of its output clocks in dts does not mean
> > > that you should.
> > > 
> > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > manual.
> > > 
> > > > 
> > > > I guess that the approach above would require split into soc-specific and 
> > > > board-specific part (as I said, dividers arrangement is something board 
> > > > specific), but I wonder what you thing about this proposal.
> > > 
> > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > files. The ultimate goal is to make it trivial to add new boards.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > Hi Arnd,
> > > > > > 
> > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > situation clearer.
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > Can you please post the patch in the body of the email instead of an
> > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > 
> > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > 
> > > > > At least it helps me find the patch I care about when skimming the
> > > > > series ;-)
> > > > > 
> > > > > > 
> > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > 
> > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > 
> > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > >      as clock source for the main PLL.
> > > > > 
> > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > both feed into a mux. You should model this 32k clock with the
> > > > > fixed-rate binding.
> > > > > 
> > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > >      TWR-K70F120M boards).
> > > > > > 
> > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > PCLK.
> > > > > 
> > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > i.e. board-specific differences such as different oscillator
> > > > > frequencies.
> > > > > 
> > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > it appears to mandated in the reference manual[0].
> > > > > 
> > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > need to worry about this if they spin a board, and then they will need
> > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > .dts.
> > > > > 
> > > > > Please break clk-kinetis.c into two files:
> > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > drivers/clk/kinetis/clk-sim.c
> > > > > 
> > > > > Below is what your binding/dts should look like:
> > > > > 
> > > > > {
> > > > >       osc0: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <50000000>;
> > > > >       };
> > > > > 
> > > > >       osc1: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <12000000>;
> > > > >       };
> > > > > 
> > > > >       rtc: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <32768>;
> > > > >       };
> > > > > 
> > > > >       soc: soc {
> > > > >               mcg: clock-controller@40064000 {
> > > > >                       compatible = "fsl,kinetis-mcg";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40064000 0x14>;
> > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > >               };
> > > > > 
> > > > >               sim: clock-controller@40047000 {
> > > > >                       compatible = "fsl,kinetis-sim";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40047000 0x1100>;
> > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > >               };
> > > > >       };
> > > > > 
> > > > >       uart0: serial@4006a000 {
> > > > >               compatible = "fsl,kinetis-lpuart";
> > > > >               reg = <0x4006a000 0x1000>;
> > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > >               clock-names = "gate";
> > > > >       };
> > > > > 
> > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > The above is the only style of binding that I have been accepting for
> > > > > some time; first declare the clock controller and establish its register
> > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > (e.g. clk_get()).
> > > > > 
> > > > > I've covered this before on the mailing list so here is a link
> > > > > describing how the qcom bindings do it in detail:
> > > > > 
> > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > 
> > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > driver so it's best to keep the clock controller binding small and
> > > > > light.
> > > > > 
> > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > exercise to the reader.
> > > > > 
> > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > usable for Kinetis.
> > > > > > 
> > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > 
> > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > >>>
> > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > >>>
> > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > >>
> > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > >> the functional level.
> > > > > > >
> > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > >
> > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > >
> > > > > > >       Arnd
> > > > > > >
> > > > > > 
> > > > > > _______________________________________________
> > > > > > linux-arm-kernel mailing list
> > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo@vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-30 21:40                                 ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-30 21:40 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Hi Mike,

I encountered some trouble while I tried to implement code fitting to DTS 
that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
Therefore, in MCG device code I won't be able to figure out clock rate 
for outputed clocks unles I try to access SIM registers from MCG driver - 
that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
to expose not core, bus and the others:

        soc {
                mcg: clock-controller@40064000 {
                        compatible = "fsl,kinetis-mcg";
                        clock-cells = <0>;
                        reg = <0x40064000 0x14>;
                        clocks = <&osc0>, <&osc1>, <&rtc>;
                        clock-names = "osc0", "osc1", "rtc";
                };
                sim: clock-controller@40047000 {
                        compatible = "fsl,kinetis-sim";
                        clock-cells = <1>;
                        reg = <0x40047000 0x1100>;
                        clocks = <&mcg>,
                                 <&osc0>;
                        clock-names = "mcgoutclk", "enet";
                };

                uart0: serial@4006a000 {
                        compatible = "fsl,kinetis-lpuart";
                        reg = <0x4006a000 0x1000>;
                        interrupts = <45>, <46>;
                        interrupt-names = "uart-stat", "uart-err";
                        clocks = <&sim SIM_SCGC4_UART0_CLK>;
                        clock-names = "ipg";
                        dmas = <&edma 0 2>;
                        dma-names = "rx";
                        status = "disabled";
                };
        };

Now fsl,kinetis-sim device will be responsible for clock gating and it 
will know about core, bus, flexbus and flash clocks only internally - 
none of them are exposed.

Also note that fec (ethernet device) driver is connected directly to osc0 
(though clock gate, you can see this CG attached to osc0 on the diagram 
too) - to control this gate I need to access SIM device registers, so it 
should be covered by the same fsl,kinetis-sim driver.

On Wed, 29 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > Hi Mike,
> > 
> > My trouble is that now I'm dealing with two conradictory opinions on how 
> > this driver should be written. The one you presented in your previous post 
> > assumes that there will be a header file with defines shared between the 
> > clock driver and DTS, also with clock gating details hidden behind some 
> > additional level of indirection, e.g.:
> > 
> > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > 
> > Note that I've been through this at the very beginning, though the names 
> > I used have been bit different, e.g.:
> > 
> > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > 
> > This was rejected with a comment by Arnd:
> > 
> > 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, are you OK with my type of binding description now that I
> explained it with some examples?
> 
> > 
> > So I dropped all of these includes and started to use magic numbers (as 
> > you put it). Now I need to go one way or another or even go the third way: 
> > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > scgc_register_number bit_index_number>.
> 
> Paul,
> 
> >From my understanding the DT folks do not like register-level or
> bit-level details going into DT. It is better to handle the clock
> signals as abstract resources and link a provider and consumer with a
> simple phandle plus an index representing that abstract resource (i.e.
> the clock output signal).
> 
> > 
> > Reading your previous post I'm starting to feel that it would bring me 
> > closer to final acceptance if I stick to what you proposed in that post 
> > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > I'll probably adopt that.
> > 
> > You're right about my "get things up and running" attitude - currently I 
> > want to develop things extensively (cover as much subsystems as 
> > possible) and then at some stage switch to intensive approach. This board 
> > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > of coding opportunity in this field in the future.
> 
> I'm happy to take clock drivers and add my Reviewed-by to .dts files
> that make use of fixed-rate and fixed-factor clocks as an interim
> solution.  Of course it will be best to get The Real Thing merged
> upstream asap, but this is something I've done before to help get new
> platform upstream before and I'm fine to do it again.
> 
> With that said, Devicetree bindings are allegedly a stable ABI that
> cannot be broken. So let's make sure that any Kinetis clock binding
> description is in good shape before merging it. The rest can follow on
> later if it needs to.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > Hi Mike,
> > > > 
> > > > Thank you for spending time on this and pointing me into the right 
> > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > 
> > > Hi Paul,
> > > 
> > > No problem! And thanks for the quick turnaround on your patches so far.
> > > 
> > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > and move everything into DTS, somewhat like this:
> > > > 
> > > > / {
> > > >         osc0: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <50000000>;
> > > >         };
> > > > 
> > > >         osc1: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <12000000>;
> > > >         };
> > > > 
> > > >         rtc: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <32768>;
> > > >         };
> > > > 
> > > >         mcgout: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&osc0>;
> > > >                 clock-mult = <12>;
> > > >                 clock-div = <5>;
> > > >         };
> > > 
> > > I think this is a step backwards.
> > > 
> > > Did you look at the qcom clock binding and read the email where I
> > > detailed how that binding works?
> > > 
> > > The point of that type of binding is to not shove per-clock data into
> > > DT, but instead to declare every clock controller IP block (e.g. the
> > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > create linkage between the clock providers and the clock consumers by
> > > using phandles + an index. Linux device drivers tap into this by using
> > > clk_get() and using the "clock-names" property from DT.
> > > 
> > > Put another way: we mostly use DT to model "devices". That is open to
> > > interpretation for but for clock-related stuff we typically interpret
> > > the clock controller as the device, not the individual clock outputs
> > > coming out of the controller.
> > > 
> > > Note that a clock controller IP block may be both a provider and a
> > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > host controller, MMC controller, GPU, etc).
> > > 
> > > Additionally, from my reading of the reference manual, mcgout is defined
> > > as:
> > > 
> > > """
> > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > MCGPLL1CLK, or MCG's external reference clock that
> > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > also an option for the debug trace clock.
> > > """
> > > 
> > > So why is it listed here as a fixed-factor clock? Is it not a
> > > multiplexer? Also, why is it listed here at all? Please take another
> > > look at the qcom binding example I linked to in my previous mail.
> > > 
> > > > 
> > > >         core: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <1>;
> > > >         };
> > > > 
> > > >         bus: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <2>;
> > > 
> > > These are actually not fixed dividers but programmable dividers. You can
> > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > fixed-dividers for the initial merge just to get things up and running
> > > if that is your strategy, but you'll need to revisit them later on when
> > > you need more flexible support for other boards.
> > > 
> > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > enumerate your mcg clock controller and your sim clock controller? If
> > > you want to be a perfectionist then it appears that there is an osc
> > > clock controller upstream from the mcg controller as well ;-)
> > > 
> > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > that you can program a sane default rate? We use the
> > > assigned-clock-rates property for that. Note that this value is a
> > > property of some device which *consumes* the clock, not the clock
> > > controller or the clock output itself.
> > > 
> > > >         };
> > > > 
> > > >         soc {
> > > >                 cmu@0x40047000 {
> > > >                         compatible = "fsl,kinetis-gate-clock";
> > > >                         reg = <0x40047000 0x1100>;
> > > > 
> > > >                         mcg_core_gate: clock-gate {
> > > >                                 clocks = <&core>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         mcg_bus_gate: clock-gate {
> > > >                                 clocks = <&bus>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         osc0_erclk_gate: clock-gate {
> > > >                                 clocks = <&osc0>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > >                 };
> > > > 
> > > >                 uart0: serial@4006a000 {
> > > >                         compatible = "fsl,kinetis-lpuart";
> > > >                         reg = <0x4006a000 0x1000>;
> > > >                         interrupts = <45>, <46>;
> > > >                         interrupt-names = "uart-stat", "uart-err";
> > > >                         clocks = <&mcg_core_gate 3 10>;
> > > 
> > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > for a while now which means we can use constants instead of magic
> > > numbers. Please look at the shared header in the qcom binding for an
> > > example.
> > > 
> > > >                         clock-names = "ipg";
> > > >                         dmas = <&edma 0 2>;
> > > >                         dma-names = "rx";
> > > >                         status = "disabled";
> > > >                 };
> > > >         };
> > > > };
> > > > 
> > > > As you can see, mcg part is not required anymore.
> > > 
> > > I think the mcg should be required. The mcg is a real IP block on your
> > > SoC, according to my reading of your technical reference manual. Just
> > > because you can model a few of its output clocks in dts does not mean
> > > that you should.
> > > 
> > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > manual.
> > > 
> > > > 
> > > > I guess that the approach above would require split into soc-specific and 
> > > > board-specific part (as I said, dividers arrangement is something board 
> > > > specific), but I wonder what you thing about this proposal.
> > > 
> > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > files. The ultimate goal is to make it trivial to add new boards.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > Hi Arnd,
> > > > > > 
> > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > situation clearer.
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > Can you please post the patch in the body of the email instead of an
> > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > 
> > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > 
> > > > > At least it helps me find the patch I care about when skimming the
> > > > > series ;-)
> > > > > 
> > > > > > 
> > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > 
> > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > 
> > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > >      as clock source for the main PLL.
> > > > > 
> > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > both feed into a mux. You should model this 32k clock with the
> > > > > fixed-rate binding.
> > > > > 
> > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > >      TWR-K70F120M boards).
> > > > > > 
> > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > PCLK.
> > > > > 
> > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > i.e. board-specific differences such as different oscillator
> > > > > frequencies.
> > > > > 
> > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > it appears to mandated in the reference manual[0].
> > > > > 
> > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > need to worry about this if they spin a board, and then they will need
> > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > .dts.
> > > > > 
> > > > > Please break clk-kinetis.c into two files:
> > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > drivers/clk/kinetis/clk-sim.c
> > > > > 
> > > > > Below is what your binding/dts should look like:
> > > > > 
> > > > > {
> > > > >       osc0: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <50000000>;
> > > > >       };
> > > > > 
> > > > >       osc1: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <12000000>;
> > > > >       };
> > > > > 
> > > > >       rtc: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <32768>;
> > > > >       };
> > > > > 
> > > > >       soc: soc {
> > > > >               mcg: clock-controller@40064000 {
> > > > >                       compatible = "fsl,kinetis-mcg";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40064000 0x14>;
> > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > >               };
> > > > > 
> > > > >               sim: clock-controller@40047000 {
> > > > >                       compatible = "fsl,kinetis-sim";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40047000 0x1100>;
> > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > >               };
> > > > >       };
> > > > > 
> > > > >       uart0: serial@4006a000 {
> > > > >               compatible = "fsl,kinetis-lpuart";
> > > > >               reg = <0x4006a000 0x1000>;
> > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > >               clock-names = "gate";
> > > > >       };
> > > > > 
> > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > The above is the only style of binding that I have been accepting for
> > > > > some time; first declare the clock controller and establish its register
> > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > (e.g. clk_get()).
> > > > > 
> > > > > I've covered this before on the mailing list so here is a link
> > > > > describing how the qcom bindings do it in detail:
> > > > > 
> > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > 
> > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > driver so it's best to keep the clock controller binding small and
> > > > > light.
> > > > > 
> > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > exercise to the reader.
> > > > > 
> > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > usable for Kinetis.
> > > > > > 
> > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > 
> > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > >>>
> > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > >>>
> > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > >>
> > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > >> the functional level.
> > > > > > >
> > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > >
> > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > >
> > > > > > >       Arnd
> > > > > > >
> > > > > > 
> > > > > > _______________________________________________
> > > > > > linux-arm-kernel mailing list
> > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo@vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-07-30 21:40                                 ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-07-30 21:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

I encountered some trouble while I tried to implement code fitting to DTS 
that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
Therefore, in MCG device code I won't be able to figure out clock rate 
for outputed clocks unles I try to access SIM registers from MCG driver - 
that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
to expose not core, bus and the others:

        soc {
                mcg: clock-controller at 40064000 {
                        compatible = "fsl,kinetis-mcg";
                        clock-cells = <0>;
                        reg = <0x40064000 0x14>;
                        clocks = <&osc0>, <&osc1>, <&rtc>;
                        clock-names = "osc0", "osc1", "rtc";
                };
                sim: clock-controller at 40047000 {
                        compatible = "fsl,kinetis-sim";
                        clock-cells = <1>;
                        reg = <0x40047000 0x1100>;
                        clocks = <&mcg>,
                                 <&osc0>;
                        clock-names = "mcgoutclk", "enet";
                };

                uart0: serial at 4006a000 {
                        compatible = "fsl,kinetis-lpuart";
                        reg = <0x4006a000 0x1000>;
                        interrupts = <45>, <46>;
                        interrupt-names = "uart-stat", "uart-err";
                        clocks = <&sim SIM_SCGC4_UART0_CLK>;
                        clock-names = "ipg";
                        dmas = <&edma 0 2>;
                        dma-names = "rx";
                        status = "disabled";
                };
        };

Now fsl,kinetis-sim device will be responsible for clock gating and it 
will know about core, bus, flexbus and flash clocks only internally - 
none of them are exposed.

Also note that fec (ethernet device) driver is connected directly to osc0 
(though clock gate, you can see this CG attached to osc0 on the diagram 
too) - to control this gate I need to access SIM device registers, so it 
should be covered by the same fsl,kinetis-sim driver.

On Wed, 29 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > Hi Mike,
> > 
> > My trouble is that now I'm dealing with two conradictory opinions on how 
> > this driver should be written. The one you presented in your previous post 
> > assumes that there will be a header file with defines shared between the 
> > clock driver and DTS, also with clock gating details hidden behind some 
> > additional level of indirection, e.g.:
> > 
> > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > 
> > Note that I've been through this at the very beginning, though the names 
> > I used have been bit different, e.g.:
> > 
> > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > 
> > This was rejected with a comment by Arnd:
> > 
> > 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, are you OK with my type of binding description now that I
> explained it with some examples?
> 
> > 
> > So I dropped all of these includes and started to use magic numbers (as 
> > you put it). Now I need to go one way or another or even go the third way: 
> > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > scgc_register_number bit_index_number>.
> 
> Paul,
> 
> >From my understanding the DT folks do not like register-level or
> bit-level details going into DT. It is better to handle the clock
> signals as abstract resources and link a provider and consumer with a
> simple phandle plus an index representing that abstract resource (i.e.
> the clock output signal).
> 
> > 
> > Reading your previous post I'm starting to feel that it would bring me 
> > closer to final acceptance if I stick to what you proposed in that post 
> > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > I'll probably adopt that.
> > 
> > You're right about my "get things up and running" attitude - currently I 
> > want to develop things extensively (cover as much subsystems as 
> > possible) and then at some stage switch to intensive approach. This board 
> > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > of coding opportunity in this field in the future.
> 
> I'm happy to take clock drivers and add my Reviewed-by to .dts files
> that make use of fixed-rate and fixed-factor clocks as an interim
> solution.  Of course it will be best to get The Real Thing merged
> upstream asap, but this is something I've done before to help get new
> platform upstream before and I'm fine to do it again.
> 
> With that said, Devicetree bindings are allegedly a stable ABI that
> cannot be broken. So let's make sure that any Kinetis clock binding
> description is in good shape before merging it. The rest can follow on
> later if it needs to.
> 
> Regards,
> Mike
> 
> > 
> > Thanks,
> > Paul
> > 
> > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > Hi Mike,
> > > > 
> > > > Thank you for spending time on this and pointing me into the right 
> > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > 
> > > Hi Paul,
> > > 
> > > No problem! And thanks for the quick turnaround on your patches so far.
> > > 
> > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > and move everything into DTS, somewhat like this:
> > > > 
> > > > / {
> > > >         osc0: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <50000000>;
> > > >         };
> > > > 
> > > >         osc1: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <12000000>;
> > > >         };
> > > > 
> > > >         rtc: clock {
> > > >                 compatible = "fixed-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clock-frequency = <32768>;
> > > >         };
> > > > 
> > > >         mcgout: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&osc0>;
> > > >                 clock-mult = <12>;
> > > >                 clock-div = <5>;
> > > >         };
> > > 
> > > I think this is a step backwards.
> > > 
> > > Did you look at the qcom clock binding and read the email where I
> > > detailed how that binding works?
> > > 
> > > The point of that type of binding is to not shove per-clock data into
> > > DT, but instead to declare every clock controller IP block (e.g. the
> > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > create linkage between the clock providers and the clock consumers by
> > > using phandles + an index. Linux device drivers tap into this by using
> > > clk_get() and using the "clock-names" property from DT.
> > > 
> > > Put another way: we mostly use DT to model "devices". That is open to
> > > interpretation for but for clock-related stuff we typically interpret
> > > the clock controller as the device, not the individual clock outputs
> > > coming out of the controller.
> > > 
> > > Note that a clock controller IP block may be both a provider and a
> > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > host controller, MMC controller, GPU, etc).
> > > 
> > > Additionally, from my reading of the reference manual, mcgout is defined
> > > as:
> > > 
> > > """
> > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > MCGPLL1CLK, or MCG's external reference clock that
> > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > also an option for the debug trace clock.
> > > """
> > > 
> > > So why is it listed here as a fixed-factor clock? Is it not a
> > > multiplexer? Also, why is it listed here at all? Please take another
> > > look at the qcom binding example I linked to in my previous mail.
> > > 
> > > > 
> > > >         core: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <1>;
> > > >         };
> > > > 
> > > >         bus: clock {
> > > >                 compatible = "fixed-factor-clock";
> > > >                 #clock-cells = <0>;
> > > >                 clocks = <&mcgout>;
> > > >                 clock-mult = <1>;
> > > >                 clock-div = <2>;
> > > 
> > > These are actually not fixed dividers but programmable dividers. You can
> > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > fixed-dividers for the initial merge just to get things up and running
> > > if that is your strategy, but you'll need to revisit them later on when
> > > you need more flexible support for other boards.
> > > 
> > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > enumerate your mcg clock controller and your sim clock controller? If
> > > you want to be a perfectionist then it appears that there is an osc
> > > clock controller upstream from the mcg controller as well ;-)
> > > 
> > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > that you can program a sane default rate? We use the
> > > assigned-clock-rates property for that. Note that this value is a
> > > property of some device which *consumes* the clock, not the clock
> > > controller or the clock output itself.
> > > 
> > > >         };
> > > > 
> > > >         soc {
> > > >                 cmu at 0x40047000 {
> > > >                         compatible = "fsl,kinetis-gate-clock";
> > > >                         reg = <0x40047000 0x1100>;
> > > > 
> > > >                         mcg_core_gate: clock-gate {
> > > >                                 clocks = <&core>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         mcg_bus_gate: clock-gate {
> > > >                                 clocks = <&bus>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > > 
> > > >                         osc0_erclk_gate: clock-gate {
> > > >                                 clocks = <&osc0>;
> > > >                                 #clock-cells = <2>;
> > > >                         };
> > > >                 };
> > > > 
> > > >                 uart0: serial at 4006a000 {
> > > >                         compatible = "fsl,kinetis-lpuart";
> > > >                         reg = <0x4006a000 0x1000>;
> > > >                         interrupts = <45>, <46>;
> > > >                         interrupt-names = "uart-stat", "uart-err";
> > > >                         clocks = <&mcg_core_gate 3 10>;
> > > 
> > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > for a while now which means we can use constants instead of magic
> > > numbers. Please look at the shared header in the qcom binding for an
> > > example.
> > > 
> > > >                         clock-names = "ipg";
> > > >                         dmas = <&edma 0 2>;
> > > >                         dma-names = "rx";
> > > >                         status = "disabled";
> > > >                 };
> > > >         };
> > > > };
> > > > 
> > > > As you can see, mcg part is not required anymore.
> > > 
> > > I think the mcg should be required. The mcg is a real IP block on your
> > > SoC, according to my reading of your technical reference manual. Just
> > > because you can model a few of its output clocks in dts does not mean
> > > that you should.
> > > 
> > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > manual.
> > > 
> > > > 
> > > > I guess that the approach above would require split into soc-specific and 
> > > > board-specific part (as I said, dividers arrangement is something board 
> > > > specific), but I wonder what you thing about this proposal.
> > > 
> > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > files. The ultimate goal is to make it trivial to add new boards.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > Hi Arnd,
> > > > > > 
> > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > situation clearer.
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > Can you please post the patch in the body of the email instead of an
> > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > 
> > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > 
> > > > > At least it helps me find the patch I care about when skimming the
> > > > > series ;-)
> > > > > 
> > > > > > 
> > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > 
> > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > 
> > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > >      as clock source for the main PLL.
> > > > > 
> > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > both feed into a mux. You should model this 32k clock with the
> > > > > fixed-rate binding.
> > > > > 
> > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > >      TWR-K70F120M boards).
> > > > > > 
> > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > PCLK.
> > > > > 
> > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > i.e. board-specific differences such as different oscillator
> > > > > frequencies.
> > > > > 
> > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > it appears to mandated in the reference manual[0].
> > > > > 
> > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > need to worry about this if they spin a board, and then they will need
> > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > .dts.
> > > > > 
> > > > > Please break clk-kinetis.c into two files:
> > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > drivers/clk/kinetis/clk-sim.c
> > > > > 
> > > > > Below is what your binding/dts should look like:
> > > > > 
> > > > > {
> > > > >       osc0: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <50000000>;
> > > > >       };
> > > > > 
> > > > >       osc1: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <12000000>;
> > > > >       };
> > > > > 
> > > > >       rtc: clock {
> > > > >               compatible = "fixed-clock";
> > > > >               #clock-cells = <0>;
> > > > >               clock-frequency = <32768>;
> > > > >       };
> > > > > 
> > > > >       soc: soc {
> > > > >               mcg: clock-controller at 40064000 {
> > > > >                       compatible = "fsl,kinetis-mcg";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40064000 0x14>;
> > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > >               };
> > > > > 
> > > > >               sim: clock-controller at 40047000 {
> > > > >                       compatible = "fsl,kinetis-sim";
> > > > >                       clock-cells = <1>;
> > > > >                       reg = <0x40047000 0x1100>;
> > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > >               };
> > > > >       };
> > > > > 
> > > > >       uart0: serial at 4006a000 {
> > > > >               compatible = "fsl,kinetis-lpuart";
> > > > >               reg = <0x4006a000 0x1000>;
> > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > >               clock-names = "gate";
> > > > >       };
> > > > > 
> > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > The above is the only style of binding that I have been accepting for
> > > > > some time; first declare the clock controller and establish its register
> > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > (e.g. clk_get()).
> > > > > 
> > > > > I've covered this before on the mailing list so here is a link
> > > > > describing how the qcom bindings do it in detail:
> > > > > 
> > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > 
> > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > driver so it's best to keep the clock controller binding small and
> > > > > light.
> > > > > 
> > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > exercise to the reader.
> > > > > 
> > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > usable for Kinetis.
> > > > > > 
> > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > 
> > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > >>>
> > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > >>>
> > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > >>
> > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > >> the functional level.
> > > > > > >
> > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > >
> > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > >
> > > > > > >       Arnd
> > > > > > >
> > > > > > 
> > > > > > _______________________________________________
> > > > > > linux-arm-kernel mailing list
> > > > > > linux-arm-kernel at lists.infradead.org
> > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo at vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-07-30 21:40                                 ` Paul Osmialowski
  (?)
@ 2015-08-01  0:58                                   ` Michael Turquette
  -1 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-01  0:58 UTC (permalink / raw)
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Arnd Bergmann, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

Quoting Paul Osmialowski (2015-07-30 14:40:48)
> Hi Mike,
> 
> I encountered some trouble while I tried to implement code fitting to DTS 
> that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> Therefore, in MCG device code I won't be able to figure out clock rate 
> for outputed clocks unles I try to access SIM registers from MCG driver - 

Right, the MCG driver will only know the rates of the clocks that it
outputs, namely:

MCGIRCLK
MCGFFCLK
MCGOUTCLK
MCGFLLCLK
MCGPLL0CLK
MCGPLL1CLK

The naming scheme in the TRM is a bit unfortunate; it looks like some of
the clock outputs coming out of SIM also retain the MCG* names.

> that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
> to expose not core, bus and the others:

Right again. SIM is both a clock provider and a consumer. It will
consume MCGOUTCLK (as well as some of the other clocks I mentioned above
I think) and output the OUTDIVn dividers and gates (Core, Bus, FlexBus,
Flash).

> 
>         soc {
>                 mcg: clock-controller@40064000 {
>                         compatible = "fsl,kinetis-mcg";
>                         clock-cells = <0>;

Why is clock-cells zero? I think the MCG block outputs all of the clocks
that I listed above? As such they should be addressable as <&mcg N> by
any downstream users.

>                         reg = <0x40064000 0x14>;
>                         clocks = <&osc0>, <&osc1>, <&rtc>;
>                         clock-names = "osc0", "osc1", "rtc";

Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?

>                 };
>                 sim: clock-controller@40047000 {
>                         compatible = "fsl,kinetis-sim";
>                         clock-cells = <1>;
>                         reg = <0x40047000 0x1100>;
>                         clocks = <&mcg>,
>                                  <&osc0>;

It looks like the SIM block should also consume:

MCGFLLCLK
MCGIRCLK
MCGFFCLK
MCGPLL0CLK
MCGPLL1CLK
OSC0ERCLK
OSC1ERCLK
OSC032KCLK
RTCCLK (I made that name up)

The mcg clocks should come out of the mcg node. It looks like you
already modeled oscN and rtc clocks, which is great. There are some
gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
actually in the osc IP block or if they actually live in SIM. More on
that below...

>                         clock-names = "mcgoutclk", "enet";
>                 };
> 
>                 uart0: serial@4006a000 {
>                         compatible = "fsl,kinetis-lpuart";
>                         reg = <0x4006a000 0x1000>;
>                         interrupts = <45>, <46>;
>                         interrupt-names = "uart-stat", "uart-err";
>                         clocks = <&sim SIM_SCGC4_UART0_CLK>;
>                         clock-names = "ipg";
>                         dmas = <&edma 0 2>;
>                         dma-names = "rx";
>                         status = "disabled";
>                 };
>         };
> 
> Now fsl,kinetis-sim device will be responsible for clock gating and it 
> will know about core, bus, flexbus and flash clocks only internally - 
> none of them are exposed.

Well they certainly can be exposed if you need them to be. If a device
driver wants to get the core clock and set it's rate then it should be
able to with something like <&sim CORE_CLK>.

> 
> Also note that fec (ethernet device) driver is connected directly to osc0 
> (though clock gate, you can see this CG attached to osc0 on the diagram 
> too) - to control this gate I need to access SIM device registers, so it 
> should be covered by the same fsl,kinetis-sim driver.

Do you mean the SIM_SOPT2 register? It looks like the connection is not
"direct", as the osc0 signal feeds into the SIM block and the gate there
controls it.  Perhaps the diagram is incorrect by placing the CG block
inside osc0? It looks like you correctly modeled this relationship in
the sim node.

Besides my annoying questions above this binding is starting to shape up
very well. Thanks for your patience!

Regards,
Mike

> 
> On Wed, 29 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > Hi Mike,
> > > 
> > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > this driver should be written. The one you presented in your previous post 
> > > assumes that there will be a header file with defines shared between the 
> > > clock driver and DTS, also with clock gating details hidden behind some 
> > > additional level of indirection, e.g.:
> > > 
> > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > 
> > > Note that I've been through this at the very beginning, though the names 
> > > I used have been bit different, e.g.:
> > > 
> > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > 
> > > This was rejected with a comment by Arnd:
> > > 
> > > 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, are you OK with my type of binding description now that I
> > explained it with some examples?
> > 
> > > 
> > > So I dropped all of these includes and started to use magic numbers (as 
> > > you put it). Now I need to go one way or another or even go the third way: 
> > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > scgc_register_number bit_index_number>.
> > 
> > Paul,
> > 
> > >From my understanding the DT folks do not like register-level or
> > bit-level details going into DT. It is better to handle the clock
> > signals as abstract resources and link a provider and consumer with a
> > simple phandle plus an index representing that abstract resource (i.e.
> > the clock output signal).
> > 
> > > 
> > > Reading your previous post I'm starting to feel that it would bring me 
> > > closer to final acceptance if I stick to what you proposed in that post 
> > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > I'll probably adopt that.
> > > 
> > > You're right about my "get things up and running" attitude - currently I 
> > > want to develop things extensively (cover as much subsystems as 
> > > possible) and then at some stage switch to intensive approach. This board 
> > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > of coding opportunity in this field in the future.
> > 
> > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > that make use of fixed-rate and fixed-factor clocks as an interim
> > solution.  Of course it will be best to get The Real Thing merged
> > upstream asap, but this is something I've done before to help get new
> > platform upstream before and I'm fine to do it again.
> > 
> > With that said, Devicetree bindings are allegedly a stable ABI that
> > cannot be broken. So let's make sure that any Kinetis clock binding
> > description is in good shape before merging it. The rest can follow on
> > later if it needs to.
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > Thanks,
> > > Paul
> > > 
> > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > Hi Mike,
> > > > > 
> > > > > Thank you for spending time on this and pointing me into the right 
> > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > 
> > > > Hi Paul,
> > > > 
> > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > 
> > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > and move everything into DTS, somewhat like this:
> > > > > 
> > > > > / {
> > > > >         osc0: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <50000000>;
> > > > >         };
> > > > > 
> > > > >         osc1: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <12000000>;
> > > > >         };
> > > > > 
> > > > >         rtc: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <32768>;
> > > > >         };
> > > > > 
> > > > >         mcgout: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&osc0>;
> > > > >                 clock-mult = <12>;
> > > > >                 clock-div = <5>;
> > > > >         };
> > > > 
> > > > I think this is a step backwards.
> > > > 
> > > > Did you look at the qcom clock binding and read the email where I
> > > > detailed how that binding works?
> > > > 
> > > > The point of that type of binding is to not shove per-clock data into
> > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > create linkage between the clock providers and the clock consumers by
> > > > using phandles + an index. Linux device drivers tap into this by using
> > > > clk_get() and using the "clock-names" property from DT.
> > > > 
> > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > interpretation for but for clock-related stuff we typically interpret
> > > > the clock controller as the device, not the individual clock outputs
> > > > coming out of the controller.
> > > > 
> > > > Note that a clock controller IP block may be both a provider and a
> > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > host controller, MMC controller, GPU, etc).
> > > > 
> > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > as:
> > > > 
> > > > """
> > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > also an option for the debug trace clock.
> > > > """
> > > > 
> > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > look at the qcom binding example I linked to in my previous mail.
> > > > 
> > > > > 
> > > > >         core: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <1>;
> > > > >         };
> > > > > 
> > > > >         bus: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <2>;
> > > > 
> > > > These are actually not fixed dividers but programmable dividers. You can
> > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > fixed-dividers for the initial merge just to get things up and running
> > > > if that is your strategy, but you'll need to revisit them later on when
> > > > you need more flexible support for other boards.
> > > > 
> > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > you want to be a perfectionist then it appears that there is an osc
> > > > clock controller upstream from the mcg controller as well ;-)
> > > > 
> > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > that you can program a sane default rate? We use the
> > > > assigned-clock-rates property for that. Note that this value is a
> > > > property of some device which *consumes* the clock, not the clock
> > > > controller or the clock output itself.
> > > > 
> > > > >         };
> > > > > 
> > > > >         soc {
> > > > >                 cmu@0x40047000 {
> > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > >                         reg = <0x40047000 0x1100>;
> > > > > 
> > > > >                         mcg_core_gate: clock-gate {
> > > > >                                 clocks = <&core>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         mcg_bus_gate: clock-gate {
> > > > >                                 clocks = <&bus>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         osc0_erclk_gate: clock-gate {
> > > > >                                 clocks = <&osc0>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > >                 };
> > > > > 
> > > > >                 uart0: serial@4006a000 {
> > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > >                         reg = <0x4006a000 0x1000>;
> > > > >                         interrupts = <45>, <46>;
> > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > 
> > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > for a while now which means we can use constants instead of magic
> > > > numbers. Please look at the shared header in the qcom binding for an
> > > > example.
> > > > 
> > > > >                         clock-names = "ipg";
> > > > >                         dmas = <&edma 0 2>;
> > > > >                         dma-names = "rx";
> > > > >                         status = "disabled";
> > > > >                 };
> > > > >         };
> > > > > };
> > > > > 
> > > > > As you can see, mcg part is not required anymore.
> > > > 
> > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > SoC, according to my reading of your technical reference manual. Just
> > > > because you can model a few of its output clocks in dts does not mean
> > > > that you should.
> > > > 
> > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > manual.
> > > > 
> > > > > 
> > > > > I guess that the approach above would require split into soc-specific and 
> > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > specific), but I wonder what you thing about this proposal.
> > > > 
> > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Paul
> > > > > 
> > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > 
> > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > Hi Arnd,
> > > > > > > 
> > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > situation clearer.
> > > > > > 
> > > > > > Hi Paul,
> > > > > > 
> > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > 
> > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > 
> > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > series ;-)
> > > > > > 
> > > > > > > 
> > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > 
> > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > 
> > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > >      as clock source for the main PLL.
> > > > > > 
> > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > fixed-rate binding.
> > > > > > 
> > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > >      TWR-K70F120M boards).
> > > > > > > 
> > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > PCLK.
> > > > > > 
> > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > i.e. board-specific differences such as different oscillator
> > > > > > frequencies.
> > > > > > 
> > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > it appears to mandated in the reference manual[0].
> > > > > > 
> > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > .dts.
> > > > > > 
> > > > > > Please break clk-kinetis.c into two files:
> > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > 
> > > > > > Below is what your binding/dts should look like:
> > > > > > 
> > > > > > {
> > > > > >       osc0: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <50000000>;
> > > > > >       };
> > > > > > 
> > > > > >       osc1: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <12000000>;
> > > > > >       };
> > > > > > 
> > > > > >       rtc: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <32768>;
> > > > > >       };
> > > > > > 
> > > > > >       soc: soc {
> > > > > >               mcg: clock-controller@40064000 {
> > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40064000 0x14>;
> > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > >               };
> > > > > > 
> > > > > >               sim: clock-controller@40047000 {
> > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40047000 0x1100>;
> > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > >               };
> > > > > >       };
> > > > > > 
> > > > > >       uart0: serial@4006a000 {
> > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > >               reg = <0x4006a000 0x1000>;
> > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > >               clock-names = "gate";
> > > > > >       };
> > > > > > 
> > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > The above is the only style of binding that I have been accepting for
> > > > > > some time; first declare the clock controller and establish its register
> > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > (e.g. clk_get()).
> > > > > > 
> > > > > > I've covered this before on the mailing list so here is a link
> > > > > > describing how the qcom bindings do it in detail:
> > > > > > 
> > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > 
> > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > light.
> > > > > > 
> > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > exercise to the reader.
> > > > > > 
> > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > 
> > > > > > Regards,
> > > > > > Mike
> > > > > > 
> > > > > > > 
> > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > usable for Kinetis.
> > > > > > > 
> > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > 
> > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > >>>
> > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > >>>
> > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > >>
> > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > >> the functional level.
> > > > > > > >
> > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > >
> > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > >
> > > > > > > >       Arnd
> > > > > > > >
> > > > > > > 
> > > > > > > _______________________________________________
> > > > > > > linux-arm-kernel mailing list
> > > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > 
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > the body of a message to majordomo@vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-01  0:58                                   ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-01  0:58 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Arnd Bergmann, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner,
	linux-arm-kernel, Sergei Poselenov, Paul Bolle,
	Greg Kroah-Hartman, Stephen Boyd, linux-kernel, Kumar Gala,
	dmaengine

Quoting Paul Osmialowski (2015-07-30 14:40:48)
> Hi Mike,
> 
> I encountered some trouble while I tried to implement code fitting to DTS 
> that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> Therefore, in MCG device code I won't be able to figure out clock rate 
> for outputed clocks unles I try to access SIM registers from MCG driver - 

Right, the MCG driver will only know the rates of the clocks that it
outputs, namely:

MCGIRCLK
MCGFFCLK
MCGOUTCLK
MCGFLLCLK
MCGPLL0CLK
MCGPLL1CLK

The naming scheme in the TRM is a bit unfortunate; it looks like some of
the clock outputs coming out of SIM also retain the MCG* names.

> that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
> to expose not core, bus and the others:

Right again. SIM is both a clock provider and a consumer. It will
consume MCGOUTCLK (as well as some of the other clocks I mentioned above
I think) and output the OUTDIVn dividers and gates (Core, Bus, FlexBus,
Flash).

> 
>         soc {
>                 mcg: clock-controller@40064000 {
>                         compatible = "fsl,kinetis-mcg";
>                         clock-cells = <0>;

Why is clock-cells zero? I think the MCG block outputs all of the clocks
that I listed above? As such they should be addressable as <&mcg N> by
any downstream users.

>                         reg = <0x40064000 0x14>;
>                         clocks = <&osc0>, <&osc1>, <&rtc>;
>                         clock-names = "osc0", "osc1", "rtc";

Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?

>                 };
>                 sim: clock-controller@40047000 {
>                         compatible = "fsl,kinetis-sim";
>                         clock-cells = <1>;
>                         reg = <0x40047000 0x1100>;
>                         clocks = <&mcg>,
>                                  <&osc0>;

It looks like the SIM block should also consume:

MCGFLLCLK
MCGIRCLK
MCGFFCLK
MCGPLL0CLK
MCGPLL1CLK
OSC0ERCLK
OSC1ERCLK
OSC032KCLK
RTCCLK (I made that name up)

The mcg clocks should come out of the mcg node. It looks like you
already modeled oscN and rtc clocks, which is great. There are some
gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
actually in the osc IP block or if they actually live in SIM. More on
that below...

>                         clock-names = "mcgoutclk", "enet";
>                 };
> 
>                 uart0: serial@4006a000 {
>                         compatible = "fsl,kinetis-lpuart";
>                         reg = <0x4006a000 0x1000>;
>                         interrupts = <45>, <46>;
>                         interrupt-names = "uart-stat", "uart-err";
>                         clocks = <&sim SIM_SCGC4_UART0_CLK>;
>                         clock-names = "ipg";
>                         dmas = <&edma 0 2>;
>                         dma-names = "rx";
>                         status = "disabled";
>                 };
>         };
> 
> Now fsl,kinetis-sim device will be responsible for clock gating and it 
> will know about core, bus, flexbus and flash clocks only internally - 
> none of them are exposed.

Well they certainly can be exposed if you need them to be. If a device
driver wants to get the core clock and set it's rate then it should be
able to with something like <&sim CORE_CLK>.

> 
> Also note that fec (ethernet device) driver is connected directly to osc0 
> (though clock gate, you can see this CG attached to osc0 on the diagram 
> too) - to control this gate I need to access SIM device registers, so it 
> should be covered by the same fsl,kinetis-sim driver.

Do you mean the SIM_SOPT2 register? It looks like the connection is not
"direct", as the osc0 signal feeds into the SIM block and the gate there
controls it.  Perhaps the diagram is incorrect by placing the CG block
inside osc0? It looks like you correctly modeled this relationship in
the sim node.

Besides my annoying questions above this binding is starting to shape up
very well. Thanks for your patience!

Regards,
Mike

> 
> On Wed, 29 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > Hi Mike,
> > > 
> > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > this driver should be written. The one you presented in your previous post 
> > > assumes that there will be a header file with defines shared between the 
> > > clock driver and DTS, also with clock gating details hidden behind some 
> > > additional level of indirection, e.g.:
> > > 
> > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > 
> > > Note that I've been through this at the very beginning, though the names 
> > > I used have been bit different, e.g.:
> > > 
> > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > 
> > > This was rejected with a comment by Arnd:
> > > 
> > > 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, are you OK with my type of binding description now that I
> > explained it with some examples?
> > 
> > > 
> > > So I dropped all of these includes and started to use magic numbers (as 
> > > you put it). Now I need to go one way or another or even go the third way: 
> > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > scgc_register_number bit_index_number>.
> > 
> > Paul,
> > 
> > >From my understanding the DT folks do not like register-level or
> > bit-level details going into DT. It is better to handle the clock
> > signals as abstract resources and link a provider and consumer with a
> > simple phandle plus an index representing that abstract resource (i.e.
> > the clock output signal).
> > 
> > > 
> > > Reading your previous post I'm starting to feel that it would bring me 
> > > closer to final acceptance if I stick to what you proposed in that post 
> > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > I'll probably adopt that.
> > > 
> > > You're right about my "get things up and running" attitude - currently I 
> > > want to develop things extensively (cover as much subsystems as 
> > > possible) and then at some stage switch to intensive approach. This board 
> > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > of coding opportunity in this field in the future.
> > 
> > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > that make use of fixed-rate and fixed-factor clocks as an interim
> > solution.  Of course it will be best to get The Real Thing merged
> > upstream asap, but this is something I've done before to help get new
> > platform upstream before and I'm fine to do it again.
> > 
> > With that said, Devicetree bindings are allegedly a stable ABI that
> > cannot be broken. So let's make sure that any Kinetis clock binding
> > description is in good shape before merging it. The rest can follow on
> > later if it needs to.
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > Thanks,
> > > Paul
> > > 
> > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > Hi Mike,
> > > > > 
> > > > > Thank you for spending time on this and pointing me into the right 
> > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > 
> > > > Hi Paul,
> > > > 
> > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > 
> > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > and move everything into DTS, somewhat like this:
> > > > > 
> > > > > / {
> > > > >         osc0: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <50000000>;
> > > > >         };
> > > > > 
> > > > >         osc1: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <12000000>;
> > > > >         };
> > > > > 
> > > > >         rtc: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <32768>;
> > > > >         };
> > > > > 
> > > > >         mcgout: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&osc0>;
> > > > >                 clock-mult = <12>;
> > > > >                 clock-div = <5>;
> > > > >         };
> > > > 
> > > > I think this is a step backwards.
> > > > 
> > > > Did you look at the qcom clock binding and read the email where I
> > > > detailed how that binding works?
> > > > 
> > > > The point of that type of binding is to not shove per-clock data into
> > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > create linkage between the clock providers and the clock consumers by
> > > > using phandles + an index. Linux device drivers tap into this by using
> > > > clk_get() and using the "clock-names" property from DT.
> > > > 
> > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > interpretation for but for clock-related stuff we typically interpret
> > > > the clock controller as the device, not the individual clock outputs
> > > > coming out of the controller.
> > > > 
> > > > Note that a clock controller IP block may be both a provider and a
> > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > host controller, MMC controller, GPU, etc).
> > > > 
> > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > as:
> > > > 
> > > > """
> > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > also an option for the debug trace clock.
> > > > """
> > > > 
> > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > look at the qcom binding example I linked to in my previous mail.
> > > > 
> > > > > 
> > > > >         core: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <1>;
> > > > >         };
> > > > > 
> > > > >         bus: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <2>;
> > > > 
> > > > These are actually not fixed dividers but programmable dividers. You can
> > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > fixed-dividers for the initial merge just to get things up and running
> > > > if that is your strategy, but you'll need to revisit them later on when
> > > > you need more flexible support for other boards.
> > > > 
> > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > you want to be a perfectionist then it appears that there is an osc
> > > > clock controller upstream from the mcg controller as well ;-)
> > > > 
> > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > that you can program a sane default rate? We use the
> > > > assigned-clock-rates property for that. Note that this value is a
> > > > property of some device which *consumes* the clock, not the clock
> > > > controller or the clock output itself.
> > > > 
> > > > >         };
> > > > > 
> > > > >         soc {
> > > > >                 cmu@0x40047000 {
> > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > >                         reg = <0x40047000 0x1100>;
> > > > > 
> > > > >                         mcg_core_gate: clock-gate {
> > > > >                                 clocks = <&core>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         mcg_bus_gate: clock-gate {
> > > > >                                 clocks = <&bus>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         osc0_erclk_gate: clock-gate {
> > > > >                                 clocks = <&osc0>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > >                 };
> > > > > 
> > > > >                 uart0: serial@4006a000 {
> > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > >                         reg = <0x4006a000 0x1000>;
> > > > >                         interrupts = <45>, <46>;
> > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > 
> > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > for a while now which means we can use constants instead of magic
> > > > numbers. Please look at the shared header in the qcom binding for an
> > > > example.
> > > > 
> > > > >                         clock-names = "ipg";
> > > > >                         dmas = <&edma 0 2>;
> > > > >                         dma-names = "rx";
> > > > >                         status = "disabled";
> > > > >                 };
> > > > >         };
> > > > > };
> > > > > 
> > > > > As you can see, mcg part is not required anymore.
> > > > 
> > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > SoC, according to my reading of your technical reference manual. Just
> > > > because you can model a few of its output clocks in dts does not mean
> > > > that you should.
> > > > 
> > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > manual.
> > > > 
> > > > > 
> > > > > I guess that the approach above would require split into soc-specific and 
> > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > specific), but I wonder what you thing about this proposal.
> > > > 
> > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Paul
> > > > > 
> > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > 
> > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > Hi Arnd,
> > > > > > > 
> > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > situation clearer.
> > > > > > 
> > > > > > Hi Paul,
> > > > > > 
> > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > 
> > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > 
> > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > series ;-)
> > > > > > 
> > > > > > > 
> > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > 
> > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > 
> > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > >      as clock source for the main PLL.
> > > > > > 
> > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > fixed-rate binding.
> > > > > > 
> > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > >      TWR-K70F120M boards).
> > > > > > > 
> > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > PCLK.
> > > > > > 
> > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > i.e. board-specific differences such as different oscillator
> > > > > > frequencies.
> > > > > > 
> > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > it appears to mandated in the reference manual[0].
> > > > > > 
> > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > .dts.
> > > > > > 
> > > > > > Please break clk-kinetis.c into two files:
> > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > 
> > > > > > Below is what your binding/dts should look like:
> > > > > > 
> > > > > > {
> > > > > >       osc0: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <50000000>;
> > > > > >       };
> > > > > > 
> > > > > >       osc1: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <12000000>;
> > > > > >       };
> > > > > > 
> > > > > >       rtc: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <32768>;
> > > > > >       };
> > > > > > 
> > > > > >       soc: soc {
> > > > > >               mcg: clock-controller@40064000 {
> > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40064000 0x14>;
> > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > >               };
> > > > > > 
> > > > > >               sim: clock-controller@40047000 {
> > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40047000 0x1100>;
> > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > >               };
> > > > > >       };
> > > > > > 
> > > > > >       uart0: serial@4006a000 {
> > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > >               reg = <0x4006a000 0x1000>;
> > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > >               clock-names = "gate";
> > > > > >       };
> > > > > > 
> > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > The above is the only style of binding that I have been accepting for
> > > > > > some time; first declare the clock controller and establish its register
> > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > (e.g. clk_get()).
> > > > > > 
> > > > > > I've covered this before on the mailing list so here is a link
> > > > > > describing how the qcom bindings do it in detail:
> > > > > > 
> > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > 
> > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > light.
> > > > > > 
> > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > exercise to the reader.
> > > > > > 
> > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > 
> > > > > > Regards,
> > > > > > Mike
> > > > > > 
> > > > > > > 
> > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > usable for Kinetis.
> > > > > > > 
> > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > 
> > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > >>>
> > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > >>>
> > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > >>
> > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > >> the functional level.
> > > > > > > >
> > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > >
> > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > >
> > > > > > > >       Arnd
> > > > > > > >
> > > > > > > 
> > > > > > > _______________________________________________
> > > > > > > linux-arm-kernel mailing list
> > > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > 
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > the body of a message to majordomo@vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-01  0:58                                   ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-01  0:58 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Paul Osmialowski (2015-07-30 14:40:48)
> Hi Mike,
> 
> I encountered some trouble while I tried to implement code fitting to DTS 
> that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> Therefore, in MCG device code I won't be able to figure out clock rate 
> for outputed clocks unles I try to access SIM registers from MCG driver - 

Right, the MCG driver will only know the rates of the clocks that it
outputs, namely:

MCGIRCLK
MCGFFCLK
MCGOUTCLK
MCGFLLCLK
MCGPLL0CLK
MCGPLL1CLK

The naming scheme in the TRM is a bit unfortunate; it looks like some of
the clock outputs coming out of SIM also retain the MCG* names.

> that's what we wanted to avoid. Looks like it's the mcgoutclk that we want 
> to expose not core, bus and the others:

Right again. SIM is both a clock provider and a consumer. It will
consume MCGOUTCLK (as well as some of the other clocks I mentioned above
I think) and output the OUTDIVn dividers and gates (Core, Bus, FlexBus,
Flash).

> 
>         soc {
>                 mcg: clock-controller at 40064000 {
>                         compatible = "fsl,kinetis-mcg";
>                         clock-cells = <0>;

Why is clock-cells zero? I think the MCG block outputs all of the clocks
that I listed above? As such they should be addressable as <&mcg N> by
any downstream users.

>                         reg = <0x40064000 0x14>;
>                         clocks = <&osc0>, <&osc1>, <&rtc>;
>                         clock-names = "osc0", "osc1", "rtc";

Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?

>                 };
>                 sim: clock-controller at 40047000 {
>                         compatible = "fsl,kinetis-sim";
>                         clock-cells = <1>;
>                         reg = <0x40047000 0x1100>;
>                         clocks = <&mcg>,
>                                  <&osc0>;

It looks like the SIM block should also consume:

MCGFLLCLK
MCGIRCLK
MCGFFCLK
MCGPLL0CLK
MCGPLL1CLK
OSC0ERCLK
OSC1ERCLK
OSC032KCLK
RTCCLK (I made that name up)

The mcg clocks should come out of the mcg node. It looks like you
already modeled oscN and rtc clocks, which is great. There are some
gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
actually in the osc IP block or if they actually live in SIM. More on
that below...

>                         clock-names = "mcgoutclk", "enet";
>                 };
> 
>                 uart0: serial at 4006a000 {
>                         compatible = "fsl,kinetis-lpuart";
>                         reg = <0x4006a000 0x1000>;
>                         interrupts = <45>, <46>;
>                         interrupt-names = "uart-stat", "uart-err";
>                         clocks = <&sim SIM_SCGC4_UART0_CLK>;
>                         clock-names = "ipg";
>                         dmas = <&edma 0 2>;
>                         dma-names = "rx";
>                         status = "disabled";
>                 };
>         };
> 
> Now fsl,kinetis-sim device will be responsible for clock gating and it 
> will know about core, bus, flexbus and flash clocks only internally - 
> none of them are exposed.

Well they certainly can be exposed if you need them to be. If a device
driver wants to get the core clock and set it's rate then it should be
able to with something like <&sim CORE_CLK>.

> 
> Also note that fec (ethernet device) driver is connected directly to osc0 
> (though clock gate, you can see this CG attached to osc0 on the diagram 
> too) - to control this gate I need to access SIM device registers, so it 
> should be covered by the same fsl,kinetis-sim driver.

Do you mean the SIM_SOPT2 register? It looks like the connection is not
"direct", as the osc0 signal feeds into the SIM block and the gate there
controls it.  Perhaps the diagram is incorrect by placing the CG block
inside osc0? It looks like you correctly modeled this relationship in
the sim node.

Besides my annoying questions above this binding is starting to shape up
very well. Thanks for your patience!

Regards,
Mike

> 
> On Wed, 29 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > Hi Mike,
> > > 
> > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > this driver should be written. The one you presented in your previous post 
> > > assumes that there will be a header file with defines shared between the 
> > > clock driver and DTS, also with clock gating details hidden behind some 
> > > additional level of indirection, e.g.:
> > > 
> > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > 
> > > Note that I've been through this at the very beginning, though the names 
> > > I used have been bit different, e.g.:
> > > 
> > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > 
> > > This was rejected with a comment by Arnd:
> > > 
> > > 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, are you OK with my type of binding description now that I
> > explained it with some examples?
> > 
> > > 
> > > So I dropped all of these includes and started to use magic numbers (as 
> > > you put it). Now I need to go one way or another or even go the third way: 
> > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > scgc_register_number bit_index_number>.
> > 
> > Paul,
> > 
> > >From my understanding the DT folks do not like register-level or
> > bit-level details going into DT. It is better to handle the clock
> > signals as abstract resources and link a provider and consumer with a
> > simple phandle plus an index representing that abstract resource (i.e.
> > the clock output signal).
> > 
> > > 
> > > Reading your previous post I'm starting to feel that it would bring me 
> > > closer to final acceptance if I stick to what you proposed in that post 
> > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > I'll probably adopt that.
> > > 
> > > You're right about my "get things up and running" attitude - currently I 
> > > want to develop things extensively (cover as much subsystems as 
> > > possible) and then at some stage switch to intensive approach. This board 
> > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > of coding opportunity in this field in the future.
> > 
> > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > that make use of fixed-rate and fixed-factor clocks as an interim
> > solution.  Of course it will be best to get The Real Thing merged
> > upstream asap, but this is something I've done before to help get new
> > platform upstream before and I'm fine to do it again.
> > 
> > With that said, Devicetree bindings are allegedly a stable ABI that
> > cannot be broken. So let's make sure that any Kinetis clock binding
> > description is in good shape before merging it. The rest can follow on
> > later if it needs to.
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > Thanks,
> > > Paul
> > > 
> > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > Hi Mike,
> > > > > 
> > > > > Thank you for spending time on this and pointing me into the right 
> > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > 
> > > > Hi Paul,
> > > > 
> > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > 
> > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > and move everything into DTS, somewhat like this:
> > > > > 
> > > > > / {
> > > > >         osc0: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <50000000>;
> > > > >         };
> > > > > 
> > > > >         osc1: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <12000000>;
> > > > >         };
> > > > > 
> > > > >         rtc: clock {
> > > > >                 compatible = "fixed-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clock-frequency = <32768>;
> > > > >         };
> > > > > 
> > > > >         mcgout: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&osc0>;
> > > > >                 clock-mult = <12>;
> > > > >                 clock-div = <5>;
> > > > >         };
> > > > 
> > > > I think this is a step backwards.
> > > > 
> > > > Did you look at the qcom clock binding and read the email where I
> > > > detailed how that binding works?
> > > > 
> > > > The point of that type of binding is to not shove per-clock data into
> > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > create linkage between the clock providers and the clock consumers by
> > > > using phandles + an index. Linux device drivers tap into this by using
> > > > clk_get() and using the "clock-names" property from DT.
> > > > 
> > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > interpretation for but for clock-related stuff we typically interpret
> > > > the clock controller as the device, not the individual clock outputs
> > > > coming out of the controller.
> > > > 
> > > > Note that a clock controller IP block may be both a provider and a
> > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > host controller, MMC controller, GPU, etc).
> > > > 
> > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > as:
> > > > 
> > > > """
> > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > also an option for the debug trace clock.
> > > > """
> > > > 
> > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > look at the qcom binding example I linked to in my previous mail.
> > > > 
> > > > > 
> > > > >         core: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <1>;
> > > > >         };
> > > > > 
> > > > >         bus: clock {
> > > > >                 compatible = "fixed-factor-clock";
> > > > >                 #clock-cells = <0>;
> > > > >                 clocks = <&mcgout>;
> > > > >                 clock-mult = <1>;
> > > > >                 clock-div = <2>;
> > > > 
> > > > These are actually not fixed dividers but programmable dividers. You can
> > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > fixed-dividers for the initial merge just to get things up and running
> > > > if that is your strategy, but you'll need to revisit them later on when
> > > > you need more flexible support for other boards.
> > > > 
> > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > you want to be a perfectionist then it appears that there is an osc
> > > > clock controller upstream from the mcg controller as well ;-)
> > > > 
> > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > that you can program a sane default rate? We use the
> > > > assigned-clock-rates property for that. Note that this value is a
> > > > property of some device which *consumes* the clock, not the clock
> > > > controller or the clock output itself.
> > > > 
> > > > >         };
> > > > > 
> > > > >         soc {
> > > > >                 cmu at 0x40047000 {
> > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > >                         reg = <0x40047000 0x1100>;
> > > > > 
> > > > >                         mcg_core_gate: clock-gate {
> > > > >                                 clocks = <&core>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         mcg_bus_gate: clock-gate {
> > > > >                                 clocks = <&bus>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > > 
> > > > >                         osc0_erclk_gate: clock-gate {
> > > > >                                 clocks = <&osc0>;
> > > > >                                 #clock-cells = <2>;
> > > > >                         };
> > > > >                 };
> > > > > 
> > > > >                 uart0: serial at 4006a000 {
> > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > >                         reg = <0x4006a000 0x1000>;
> > > > >                         interrupts = <45>, <46>;
> > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > 
> > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > for a while now which means we can use constants instead of magic
> > > > numbers. Please look at the shared header in the qcom binding for an
> > > > example.
> > > > 
> > > > >                         clock-names = "ipg";
> > > > >                         dmas = <&edma 0 2>;
> > > > >                         dma-names = "rx";
> > > > >                         status = "disabled";
> > > > >                 };
> > > > >         };
> > > > > };
> > > > > 
> > > > > As you can see, mcg part is not required anymore.
> > > > 
> > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > SoC, according to my reading of your technical reference manual. Just
> > > > because you can model a few of its output clocks in dts does not mean
> > > > that you should.
> > > > 
> > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > manual.
> > > > 
> > > > > 
> > > > > I guess that the approach above would require split into soc-specific and 
> > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > specific), but I wonder what you thing about this proposal.
> > > > 
> > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Paul
> > > > > 
> > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > 
> > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > Hi Arnd,
> > > > > > > 
> > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > situation clearer.
> > > > > > 
> > > > > > Hi Paul,
> > > > > > 
> > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > 
> > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > 
> > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > series ;-)
> > > > > > 
> > > > > > > 
> > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > 
> > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > 
> > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > >      as clock source for the main PLL.
> > > > > > 
> > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > fixed-rate binding.
> > > > > > 
> > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > >      TWR-K70F120M boards).
> > > > > > > 
> > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > PCLK.
> > > > > > 
> > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > i.e. board-specific differences such as different oscillator
> > > > > > frequencies.
> > > > > > 
> > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > it appears to mandated in the reference manual[0].
> > > > > > 
> > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > .dts.
> > > > > > 
> > > > > > Please break clk-kinetis.c into two files:
> > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > 
> > > > > > Below is what your binding/dts should look like:
> > > > > > 
> > > > > > {
> > > > > >       osc0: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <50000000>;
> > > > > >       };
> > > > > > 
> > > > > >       osc1: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <12000000>;
> > > > > >       };
> > > > > > 
> > > > > >       rtc: clock {
> > > > > >               compatible = "fixed-clock";
> > > > > >               #clock-cells = <0>;
> > > > > >               clock-frequency = <32768>;
> > > > > >       };
> > > > > > 
> > > > > >       soc: soc {
> > > > > >               mcg: clock-controller at 40064000 {
> > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40064000 0x14>;
> > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > >               };
> > > > > > 
> > > > > >               sim: clock-controller at 40047000 {
> > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > >                       clock-cells = <1>;
> > > > > >                       reg = <0x40047000 0x1100>;
> > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > >               };
> > > > > >       };
> > > > > > 
> > > > > >       uart0: serial at 4006a000 {
> > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > >               reg = <0x4006a000 0x1000>;
> > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > >               clock-names = "gate";
> > > > > >       };
> > > > > > 
> > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > The above is the only style of binding that I have been accepting for
> > > > > > some time; first declare the clock controller and establish its register
> > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > (e.g. clk_get()).
> > > > > > 
> > > > > > I've covered this before on the mailing list so here is a link
> > > > > > describing how the qcom bindings do it in detail:
> > > > > > 
> > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > 
> > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > light.
> > > > > > 
> > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > exercise to the reader.
> > > > > > 
> > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > 
> > > > > > Regards,
> > > > > > Mike
> > > > > > 
> > > > > > > 
> > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > usable for Kinetis.
> > > > > > > 
> > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > 
> > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > >>>
> > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > >>>
> > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > >>
> > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > >> the functional level.
> > > > > > > >
> > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > >
> > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > >
> > > > > > > >       Arnd
> > > > > > > >
> > > > > > > 
> > > > > > > _______________________________________________
> > > > > > > linux-arm-kernel mailing list
> > > > > > > linux-arm-kernel at lists.infradead.org
> > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > 
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > the body of a message to majordomo at vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo at vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-08-01  0:58                                   ` Michael Turquette
  (?)
@ 2015-08-01 15:27                                     ` Paul Osmialowski
  -1 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-08-01 15:27 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner


Hi Mike,

On Fri, 31 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > Hi Mike,
> > 
> > I encountered some trouble while I tried to implement code fitting to DTS 
> > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> > Therefore, in MCG device code I won't be able to figure out clock rate 
> > for outputed clocks unles I try to access SIM registers from MCG driver - 
> 
> Right, the MCG driver will only know the rates of the clocks that it
> outputs, namely:
> 
> MCGIRCLK
> MCGFFCLK
> MCGOUTCLK
> MCGFLLCLK
> MCGPLL0CLK
> MCGPLL1CLK
> 
> The naming scheme in the TRM is a bit unfortunate; it looks like some of
> the clock outputs coming out of SIM also retain the MCG* names.

I wonder if I really need to implement support for all of these clocks 
while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK 
(and for this, it never considers FLL as a source). 
I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since 
their rates are computed as a byproduct while determining rate of 
MCGOUTCLK. I may define constants for all of them in related header file, 
but I'm thinking about leaving most of implementations as TBD - otherwise 
I doubt I'll be ever able to test that my driver fully works.

> 
> Why is clock-cells zero? I think the MCG block outputs all of the clocks
> that I listed above? As such they should be addressable as <&mcg N> by
> any downstream users.
> 

Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.


> >                         reg = <0x40064000 0x14>;
> >                         clocks = <&osc0>, <&osc1>, <&rtc>;
> >                         clock-names = "osc0", "osc1", "rtc";
> 
> Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> 

Yes, I skipped the part above soc during copy-paste.

> It looks like the SIM block should also consume:
> 
> MCGFLLCLK
> MCGIRCLK
> MCGFFCLK
> MCGPLL0CLK
> MCGPLL1CLK
> OSC0ERCLK
> OSC1ERCLK
> OSC032KCLK
> RTCCLK (I made that name up)
> 
> The mcg clocks should come out of the mcg node. It looks like you
> already modeled oscN and rtc clocks, which is great. There are some
> gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> actually in the osc IP block or if they actually live in SIM. More on
> that below...
> 
> Well they certainly can be exposed if you need them to be. If a device
> driver wants to get the core clock and set it's rate then it should be
> able to with something like <&sim CORE_CLK>.
> 

Ok, the user of the clock does not relly need to know whether it is clock 
device or a clock gate - fortunately, I already learnt how to implement 
such thing.

> > 
> > Also note that fec (ethernet device) driver is connected directly to osc0 
> > (though clock gate, you can see this CG attached to osc0 on the diagram 
> > too) - to control this gate I need to access SIM device registers, so it 
> > should be covered by the same fsl,kinetis-sim driver.
> 
> Do you mean the SIM_SOPT2 register? It looks like the connection is not
> "direct", as the osc0 signal feeds into the SIM block and the gate there
> controls it.  Perhaps the diagram is incorrect by placing the CG block
> inside osc0? It looks like you correctly modeled this relationship in
> the sim node.

In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMII 
mode to work, and according to what I see on the page 228 of the reference
manual, it is osc0 clock behind this gate.

In the context of network device, I would need to read SIM_SOPT2 to 
determine clock source for IEEE 1588 timestamp while implementing PTP 
support - which currently I don't have in my plans, network device can do 
without it.

Thanks,
Paul

> 
> Besides my annoying questions above this binding is starting to shape up
> very well. Thanks for your patience!
> 
> Regards,
> Mike
> 
> > 
> > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > Hi Mike,
> > > > 
> > > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > > this driver should be written. The one you presented in your previous post 
> > > > assumes that there will be a header file with defines shared between the 
> > > > clock driver and DTS, also with clock gating details hidden behind some 
> > > > additional level of indirection, e.g.:
> > > > 
> > > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > 
> > > > Note that I've been through this at the very beginning, though the names 
> > > > I used have been bit different, e.g.:
> > > > 
> > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > > 
> > > > This was rejected with a comment by Arnd:
> > > > 
> > > > 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, are you OK with my type of binding description now that I
> > > explained it with some examples?
> > > 
> > > > 
> > > > So I dropped all of these includes and started to use magic numbers (as 
> > > > you put it). Now I need to go one way or another or even go the third way: 
> > > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > > scgc_register_number bit_index_number>.
> > > 
> > > Paul,
> > > 
> > > >From my understanding the DT folks do not like register-level or
> > > bit-level details going into DT. It is better to handle the clock
> > > signals as abstract resources and link a provider and consumer with a
> > > simple phandle plus an index representing that abstract resource (i.e.
> > > the clock output signal).
> > > 
> > > > 
> > > > Reading your previous post I'm starting to feel that it would bring me 
> > > > closer to final acceptance if I stick to what you proposed in that post 
> > > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > > I'll probably adopt that.
> > > > 
> > > > You're right about my "get things up and running" attitude - currently I 
> > > > want to develop things extensively (cover as much subsystems as 
> > > > possible) and then at some stage switch to intensive approach. This board 
> > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > > of coding opportunity in this field in the future.
> > > 
> > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > solution.  Of course it will be best to get The Real Thing merged
> > > upstream asap, but this is something I've done before to help get new
> > > platform upstream before and I'm fine to do it again.
> > > 
> > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > description is in good shape before merging it. The rest can follow on
> > > later if it needs to.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > Hi Mike,
> > > > > > 
> > > > > > Thank you for spending time on this and pointing me into the right 
> > > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > > 
> > > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > > and move everything into DTS, somewhat like this:
> > > > > > 
> > > > > > / {
> > > > > >         osc0: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <50000000>;
> > > > > >         };
> > > > > > 
> > > > > >         osc1: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <12000000>;
> > > > > >         };
> > > > > > 
> > > > > >         rtc: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <32768>;
> > > > > >         };
> > > > > > 
> > > > > >         mcgout: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&osc0>;
> > > > > >                 clock-mult = <12>;
> > > > > >                 clock-div = <5>;
> > > > > >         };
> > > > > 
> > > > > I think this is a step backwards.
> > > > > 
> > > > > Did you look at the qcom clock binding and read the email where I
> > > > > detailed how that binding works?
> > > > > 
> > > > > The point of that type of binding is to not shove per-clock data into
> > > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > > create linkage between the clock providers and the clock consumers by
> > > > > using phandles + an index. Linux device drivers tap into this by using
> > > > > clk_get() and using the "clock-names" property from DT.
> > > > > 
> > > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > > interpretation for but for clock-related stuff we typically interpret
> > > > > the clock controller as the device, not the individual clock outputs
> > > > > coming out of the controller.
> > > > > 
> > > > > Note that a clock controller IP block may be both a provider and a
> > > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > > host controller, MMC controller, GPU, etc).
> > > > > 
> > > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > > as:
> > > > > 
> > > > > """
> > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > also an option for the debug trace clock.
> > > > > """
> > > > > 
> > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > > look at the qcom binding example I linked to in my previous mail.
> > > > > 
> > > > > > 
> > > > > >         core: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <1>;
> > > > > >         };
> > > > > > 
> > > > > >         bus: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <2>;
> > > > > 
> > > > > These are actually not fixed dividers but programmable dividers. You can
> > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > > fixed-dividers for the initial merge just to get things up and running
> > > > > if that is your strategy, but you'll need to revisit them later on when
> > > > > you need more flexible support for other boards.
> > > > > 
> > > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > > you want to be a perfectionist then it appears that there is an osc
> > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > 
> > > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > > that you can program a sane default rate? We use the
> > > > > assigned-clock-rates property for that. Note that this value is a
> > > > > property of some device which *consumes* the clock, not the clock
> > > > > controller or the clock output itself.
> > > > > 
> > > > > >         };
> > > > > > 
> > > > > >         soc {
> > > > > >                 cmu@0x40047000 {
> > > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > > >                         reg = <0x40047000 0x1100>;
> > > > > > 
> > > > > >                         mcg_core_gate: clock-gate {
> > > > > >                                 clocks = <&core>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         mcg_bus_gate: clock-gate {
> > > > > >                                 clocks = <&bus>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > >                                 clocks = <&osc0>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > >                 };
> > > > > > 
> > > > > >                 uart0: serial@4006a000 {
> > > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > > >                         reg = <0x4006a000 0x1000>;
> > > > > >                         interrupts = <45>, <46>;
> > > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > > 
> > > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > > for a while now which means we can use constants instead of magic
> > > > > numbers. Please look at the shared header in the qcom binding for an
> > > > > example.
> > > > > 
> > > > > >                         clock-names = "ipg";
> > > > > >                         dmas = <&edma 0 2>;
> > > > > >                         dma-names = "rx";
> > > > > >                         status = "disabled";
> > > > > >                 };
> > > > > >         };
> > > > > > };
> > > > > > 
> > > > > > As you can see, mcg part is not required anymore.
> > > > > 
> > > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > > SoC, according to my reading of your technical reference manual. Just
> > > > > because you can model a few of its output clocks in dts does not mean
> > > > > that you should.
> > > > > 
> > > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > > manual.
> > > > > 
> > > > > > 
> > > > > > I guess that the approach above would require split into soc-specific and 
> > > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > > specific), but I wonder what you thing about this proposal.
> > > > > 
> > > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > Thanks,
> > > > > > Paul
> > > > > > 
> > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > 
> > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > Hi Arnd,
> > > > > > > > 
> > > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > > situation clearer.
> > > > > > > 
> > > > > > > Hi Paul,
> > > > > > > 
> > > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > > 
> > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > 
> > > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > > series ;-)
> > > > > > > 
> > > > > > > > 
> > > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > 
> > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > > 
> > > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > > >      as clock source for the main PLL.
> > > > > > > 
> > > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > > fixed-rate binding.
> > > > > > > 
> > > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > > >      TWR-K70F120M boards).
> > > > > > > > 
> > > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > > PCLK.
> > > > > > > 
> > > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > frequencies.
> > > > > > > 
> > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > 
> > > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > > .dts.
> > > > > > > 
> > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > 
> > > > > > > Below is what your binding/dts should look like:
> > > > > > > 
> > > > > > > {
> > > > > > >       osc0: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <50000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       osc1: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <12000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       rtc: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <32768>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       soc: soc {
> > > > > > >               mcg: clock-controller@40064000 {
> > > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40064000 0x14>;
> > > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > > >               };
> > > > > > > 
> > > > > > >               sim: clock-controller@40047000 {
> > > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40047000 0x1100>;
> > > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > > >               };
> > > > > > >       };
> > > > > > > 
> > > > > > >       uart0: serial@4006a000 {
> > > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > > >               reg = <0x4006a000 0x1000>;
> > > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > >               clock-names = "gate";
> > > > > > >       };
> > > > > > > 
> > > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > > The above is the only style of binding that I have been accepting for
> > > > > > > some time; first declare the clock controller and establish its register
> > > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > > (e.g. clk_get()).
> > > > > > > 
> > > > > > > I've covered this before on the mailing list so here is a link
> > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > 
> > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > 
> > > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > > light.
> > > > > > > 
> > > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > > exercise to the reader.
> > > > > > > 
> > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > > 
> > > > > > > Regards,
> > > > > > > Mike
> > > > > > > 
> > > > > > > > 
> > > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > > usable for Kinetis.
> > > > > > > > 
> > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > 
> > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > >>>
> > > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > > >>>
> > > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > > >>
> > > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > > >> the functional level.
> > > > > > > > >
> > > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > > >
> > > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > >
> > > > > > > > >       Arnd
> > > > > > > > >
> > > > > > > > 
> > > > > > > > _______________________________________________
> > > > > > > > linux-arm-kernel mailing list
> > > > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > > 
> > > > > > --
> > > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > > the body of a message to majordomo@vger.kernel.org
> > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo@vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-01 15:27                                     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-08-01 15:27 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine


Hi Mike,

On Fri, 31 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > Hi Mike,
> > 
> > I encountered some trouble while I tried to implement code fitting to DTS 
> > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> > Therefore, in MCG device code I won't be able to figure out clock rate 
> > for outputed clocks unles I try to access SIM registers from MCG driver - 
> 
> Right, the MCG driver will only know the rates of the clocks that it
> outputs, namely:
> 
> MCGIRCLK
> MCGFFCLK
> MCGOUTCLK
> MCGFLLCLK
> MCGPLL0CLK
> MCGPLL1CLK
> 
> The naming scheme in the TRM is a bit unfortunate; it looks like some of
> the clock outputs coming out of SIM also retain the MCG* names.

I wonder if I really need to implement support for all of these clocks 
while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK 
(and for this, it never considers FLL as a source). 
I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since 
their rates are computed as a byproduct while determining rate of 
MCGOUTCLK. I may define constants for all of them in related header file, 
but I'm thinking about leaving most of implementations as TBD - otherwise 
I doubt I'll be ever able to test that my driver fully works.

> 
> Why is clock-cells zero? I think the MCG block outputs all of the clocks
> that I listed above? As such they should be addressable as <&mcg N> by
> any downstream users.
> 

Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.


> >                         reg = <0x40064000 0x14>;
> >                         clocks = <&osc0>, <&osc1>, <&rtc>;
> >                         clock-names = "osc0", "osc1", "rtc";
> 
> Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> 

Yes, I skipped the part above soc during copy-paste.

> It looks like the SIM block should also consume:
> 
> MCGFLLCLK
> MCGIRCLK
> MCGFFCLK
> MCGPLL0CLK
> MCGPLL1CLK
> OSC0ERCLK
> OSC1ERCLK
> OSC032KCLK
> RTCCLK (I made that name up)
> 
> The mcg clocks should come out of the mcg node. It looks like you
> already modeled oscN and rtc clocks, which is great. There are some
> gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> actually in the osc IP block or if they actually live in SIM. More on
> that below...
> 
> Well they certainly can be exposed if you need them to be. If a device
> driver wants to get the core clock and set it's rate then it should be
> able to with something like <&sim CORE_CLK>.
> 

Ok, the user of the clock does not relly need to know whether it is clock 
device or a clock gate - fortunately, I already learnt how to implement 
such thing.

> > 
> > Also note that fec (ethernet device) driver is connected directly to osc0 
> > (though clock gate, you can see this CG attached to osc0 on the diagram 
> > too) - to control this gate I need to access SIM device registers, so it 
> > should be covered by the same fsl,kinetis-sim driver.
> 
> Do you mean the SIM_SOPT2 register? It looks like the connection is not
> "direct", as the osc0 signal feeds into the SIM block and the gate there
> controls it.  Perhaps the diagram is incorrect by placing the CG block
> inside osc0? It looks like you correctly modeled this relationship in
> the sim node.

In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMII 
mode to work, and according to what I see on the page 228 of the reference
manual, it is osc0 clock behind this gate.

In the context of network device, I would need to read SIM_SOPT2 to 
determine clock source for IEEE 1588 timestamp while implementing PTP 
support - which currently I don't have in my plans, network device can do 
without it.

Thanks,
Paul

> 
> Besides my annoying questions above this binding is starting to shape up
> very well. Thanks for your patience!
> 
> Regards,
> Mike
> 
> > 
> > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > Hi Mike,
> > > > 
> > > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > > this driver should be written. The one you presented in your previous post 
> > > > assumes that there will be a header file with defines shared between the 
> > > > clock driver and DTS, also with clock gating details hidden behind some 
> > > > additional level of indirection, e.g.:
> > > > 
> > > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > 
> > > > Note that I've been through this at the very beginning, though the names 
> > > > I used have been bit different, e.g.:
> > > > 
> > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > > 
> > > > This was rejected with a comment by Arnd:
> > > > 
> > > > 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, are you OK with my type of binding description now that I
> > > explained it with some examples?
> > > 
> > > > 
> > > > So I dropped all of these includes and started to use magic numbers (as 
> > > > you put it). Now I need to go one way or another or even go the third way: 
> > > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > > scgc_register_number bit_index_number>.
> > > 
> > > Paul,
> > > 
> > > >From my understanding the DT folks do not like register-level or
> > > bit-level details going into DT. It is better to handle the clock
> > > signals as abstract resources and link a provider and consumer with a
> > > simple phandle plus an index representing that abstract resource (i.e.
> > > the clock output signal).
> > > 
> > > > 
> > > > Reading your previous post I'm starting to feel that it would bring me 
> > > > closer to final acceptance if I stick to what you proposed in that post 
> > > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > > I'll probably adopt that.
> > > > 
> > > > You're right about my "get things up and running" attitude - currently I 
> > > > want to develop things extensively (cover as much subsystems as 
> > > > possible) and then at some stage switch to intensive approach. This board 
> > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > > of coding opportunity in this field in the future.
> > > 
> > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > solution.  Of course it will be best to get The Real Thing merged
> > > upstream asap, but this is something I've done before to help get new
> > > platform upstream before and I'm fine to do it again.
> > > 
> > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > description is in good shape before merging it. The rest can follow on
> > > later if it needs to.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > Hi Mike,
> > > > > > 
> > > > > > Thank you for spending time on this and pointing me into the right 
> > > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > > 
> > > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > > and move everything into DTS, somewhat like this:
> > > > > > 
> > > > > > / {
> > > > > >         osc0: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <50000000>;
> > > > > >         };
> > > > > > 
> > > > > >         osc1: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <12000000>;
> > > > > >         };
> > > > > > 
> > > > > >         rtc: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <32768>;
> > > > > >         };
> > > > > > 
> > > > > >         mcgout: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&osc0>;
> > > > > >                 clock-mult = <12>;
> > > > > >                 clock-div = <5>;
> > > > > >         };
> > > > > 
> > > > > I think this is a step backwards.
> > > > > 
> > > > > Did you look at the qcom clock binding and read the email where I
> > > > > detailed how that binding works?
> > > > > 
> > > > > The point of that type of binding is to not shove per-clock data into
> > > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > > create linkage between the clock providers and the clock consumers by
> > > > > using phandles + an index. Linux device drivers tap into this by using
> > > > > clk_get() and using the "clock-names" property from DT.
> > > > > 
> > > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > > interpretation for but for clock-related stuff we typically interpret
> > > > > the clock controller as the device, not the individual clock outputs
> > > > > coming out of the controller.
> > > > > 
> > > > > Note that a clock controller IP block may be both a provider and a
> > > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > > host controller, MMC controller, GPU, etc).
> > > > > 
> > > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > > as:
> > > > > 
> > > > > """
> > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > also an option for the debug trace clock.
> > > > > """
> > > > > 
> > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > > look at the qcom binding example I linked to in my previous mail.
> > > > > 
> > > > > > 
> > > > > >         core: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <1>;
> > > > > >         };
> > > > > > 
> > > > > >         bus: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <2>;
> > > > > 
> > > > > These are actually not fixed dividers but programmable dividers. You can
> > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > > fixed-dividers for the initial merge just to get things up and running
> > > > > if that is your strategy, but you'll need to revisit them later on when
> > > > > you need more flexible support for other boards.
> > > > > 
> > > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > > you want to be a perfectionist then it appears that there is an osc
> > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > 
> > > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > > that you can program a sane default rate? We use the
> > > > > assigned-clock-rates property for that. Note that this value is a
> > > > > property of some device which *consumes* the clock, not the clock
> > > > > controller or the clock output itself.
> > > > > 
> > > > > >         };
> > > > > > 
> > > > > >         soc {
> > > > > >                 cmu@0x40047000 {
> > > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > > >                         reg = <0x40047000 0x1100>;
> > > > > > 
> > > > > >                         mcg_core_gate: clock-gate {
> > > > > >                                 clocks = <&core>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         mcg_bus_gate: clock-gate {
> > > > > >                                 clocks = <&bus>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > >                                 clocks = <&osc0>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > >                 };
> > > > > > 
> > > > > >                 uart0: serial@4006a000 {
> > > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > > >                         reg = <0x4006a000 0x1000>;
> > > > > >                         interrupts = <45>, <46>;
> > > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > > 
> > > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > > for a while now which means we can use constants instead of magic
> > > > > numbers. Please look at the shared header in the qcom binding for an
> > > > > example.
> > > > > 
> > > > > >                         clock-names = "ipg";
> > > > > >                         dmas = <&edma 0 2>;
> > > > > >                         dma-names = "rx";
> > > > > >                         status = "disabled";
> > > > > >                 };
> > > > > >         };
> > > > > > };
> > > > > > 
> > > > > > As you can see, mcg part is not required anymore.
> > > > > 
> > > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > > SoC, according to my reading of your technical reference manual. Just
> > > > > because you can model a few of its output clocks in dts does not mean
> > > > > that you should.
> > > > > 
> > > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > > manual.
> > > > > 
> > > > > > 
> > > > > > I guess that the approach above would require split into soc-specific and 
> > > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > > specific), but I wonder what you thing about this proposal.
> > > > > 
> > > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > Thanks,
> > > > > > Paul
> > > > > > 
> > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > 
> > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > Hi Arnd,
> > > > > > > > 
> > > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > > situation clearer.
> > > > > > > 
> > > > > > > Hi Paul,
> > > > > > > 
> > > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > > 
> > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > 
> > > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > > series ;-)
> > > > > > > 
> > > > > > > > 
> > > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > 
> > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > > 
> > > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > > >      as clock source for the main PLL.
> > > > > > > 
> > > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > > fixed-rate binding.
> > > > > > > 
> > > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > > >      TWR-K70F120M boards).
> > > > > > > > 
> > > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > > PCLK.
> > > > > > > 
> > > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > frequencies.
> > > > > > > 
> > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > 
> > > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > > .dts.
> > > > > > > 
> > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > 
> > > > > > > Below is what your binding/dts should look like:
> > > > > > > 
> > > > > > > {
> > > > > > >       osc0: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <50000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       osc1: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <12000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       rtc: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <32768>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       soc: soc {
> > > > > > >               mcg: clock-controller@40064000 {
> > > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40064000 0x14>;
> > > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > > >               };
> > > > > > > 
> > > > > > >               sim: clock-controller@40047000 {
> > > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40047000 0x1100>;
> > > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > > >               };
> > > > > > >       };
> > > > > > > 
> > > > > > >       uart0: serial@4006a000 {
> > > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > > >               reg = <0x4006a000 0x1000>;
> > > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > >               clock-names = "gate";
> > > > > > >       };
> > > > > > > 
> > > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > > The above is the only style of binding that I have been accepting for
> > > > > > > some time; first declare the clock controller and establish its register
> > > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > > (e.g. clk_get()).
> > > > > > > 
> > > > > > > I've covered this before on the mailing list so here is a link
> > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > 
> > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > 
> > > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > > light.
> > > > > > > 
> > > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > > exercise to the reader.
> > > > > > > 
> > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > > 
> > > > > > > Regards,
> > > > > > > Mike
> > > > > > > 
> > > > > > > > 
> > > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > > usable for Kinetis.
> > > > > > > > 
> > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > 
> > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > >>>
> > > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > > >>>
> > > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > > >>
> > > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > > >> the functional level.
> > > > > > > > >
> > > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > > >
> > > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > >
> > > > > > > > >       Arnd
> > > > > > > > >
> > > > > > > > 
> > > > > > > > _______________________________________________
> > > > > > > > linux-arm-kernel mailing list
> > > > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > > 
> > > > > > --
> > > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > > the body of a message to majordomo@vger.kernel.org
> > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo@vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-01 15:27                                     ` Paul Osmialowski
  0 siblings, 0 replies; 140+ messages in thread
From: Paul Osmialowski @ 2015-08-01 15:27 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Mike,

On Fri, 31 Jul 2015, Michael Turquette wrote:

> Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > Hi Mike,
> > 
> > I encountered some trouble while I tried to implement code fitting to DTS 
> > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> > Therefore, in MCG device code I won't be able to figure out clock rate 
> > for outputed clocks unles I try to access SIM registers from MCG driver - 
> 
> Right, the MCG driver will only know the rates of the clocks that it
> outputs, namely:
> 
> MCGIRCLK
> MCGFFCLK
> MCGOUTCLK
> MCGFLLCLK
> MCGPLL0CLK
> MCGPLL1CLK
> 
> The naming scheme in the TRM is a bit unfortunate; it looks like some of
> the clock outputs coming out of SIM also retain the MCG* names.

I wonder if I really need to implement support for all of these clocks 
while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK 
(and for this, it never considers FLL as a source). 
I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since 
their rates are computed as a byproduct while determining rate of 
MCGOUTCLK. I may define constants for all of them in related header file, 
but I'm thinking about leaving most of implementations as TBD - otherwise 
I doubt I'll be ever able to test that my driver fully works.

> 
> Why is clock-cells zero? I think the MCG block outputs all of the clocks
> that I listed above? As such they should be addressable as <&mcg N> by
> any downstream users.
> 

Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.


> >                         reg = <0x40064000 0x14>;
> >                         clocks = <&osc0>, <&osc1>, <&rtc>;
> >                         clock-names = "osc0", "osc1", "rtc";
> 
> Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> 

Yes, I skipped the part above soc during copy-paste.

> It looks like the SIM block should also consume:
> 
> MCGFLLCLK
> MCGIRCLK
> MCGFFCLK
> MCGPLL0CLK
> MCGPLL1CLK
> OSC0ERCLK
> OSC1ERCLK
> OSC032KCLK
> RTCCLK (I made that name up)
> 
> The mcg clocks should come out of the mcg node. It looks like you
> already modeled oscN and rtc clocks, which is great. There are some
> gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> actually in the osc IP block or if they actually live in SIM. More on
> that below...
> 
> Well they certainly can be exposed if you need them to be. If a device
> driver wants to get the core clock and set it's rate then it should be
> able to with something like <&sim CORE_CLK>.
> 

Ok, the user of the clock does not relly need to know whether it is clock 
device or a clock gate - fortunately, I already learnt how to implement 
such thing.

> > 
> > Also note that fec (ethernet device) driver is connected directly to osc0 
> > (though clock gate, you can see this CG attached to osc0 on the diagram 
> > too) - to control this gate I need to access SIM device registers, so it 
> > should be covered by the same fsl,kinetis-sim driver.
> 
> Do you mean the SIM_SOPT2 register? It looks like the connection is not
> "direct", as the osc0 signal feeds into the SIM block and the gate there
> controls it.  Perhaps the diagram is incorrect by placing the CG block
> inside osc0? It looks like you correctly modeled this relationship in
> the sim node.

In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMII 
mode to work, and according to what I see on the page 228 of the reference
manual, it is osc0 clock behind this gate.

In the context of network device, I would need to read SIM_SOPT2 to 
determine clock source for IEEE 1588 timestamp while implementing PTP 
support - which currently I don't have in my plans, network device can do 
without it.

Thanks,
Paul

> 
> Besides my annoying questions above this binding is starting to shape up
> very well. Thanks for your patience!
> 
> Regards,
> Mike
> 
> > 
> > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > 
> > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > Hi Mike,
> > > > 
> > > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > > this driver should be written. The one you presented in your previous post 
> > > > assumes that there will be a header file with defines shared between the 
> > > > clock driver and DTS, also with clock gating details hidden behind some 
> > > > additional level of indirection, e.g.:
> > > > 
> > > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > 
> > > > Note that I've been through this at the very beginning, though the names 
> > > > I used have been bit different, e.g.:
> > > > 
> > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > > 
> > > > This was rejected with a comment by Arnd:
> > > > 
> > > > 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, are you OK with my type of binding description now that I
> > > explained it with some examples?
> > > 
> > > > 
> > > > So I dropped all of these includes and started to use magic numbers (as 
> > > > you put it). Now I need to go one way or another or even go the third way: 
> > > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > > scgc_register_number bit_index_number>.
> > > 
> > > Paul,
> > > 
> > > >From my understanding the DT folks do not like register-level or
> > > bit-level details going into DT. It is better to handle the clock
> > > signals as abstract resources and link a provider and consumer with a
> > > simple phandle plus an index representing that abstract resource (i.e.
> > > the clock output signal).
> > > 
> > > > 
> > > > Reading your previous post I'm starting to feel that it would bring me 
> > > > closer to final acceptance if I stick to what you proposed in that post 
> > > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > > I'll probably adopt that.
> > > > 
> > > > You're right about my "get things up and running" attitude - currently I 
> > > > want to develop things extensively (cover as much subsystems as 
> > > > possible) and then at some stage switch to intensive approach. This board 
> > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > > of coding opportunity in this field in the future.
> > > 
> > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > solution.  Of course it will be best to get The Real Thing merged
> > > upstream asap, but this is something I've done before to help get new
> > > platform upstream before and I'm fine to do it again.
> > > 
> > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > description is in good shape before merging it. The rest can follow on
> > > later if it needs to.
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > 
> > > > Thanks,
> > > > Paul
> > > > 
> > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > 
> > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > Hi Mike,
> > > > > > 
> > > > > > Thank you for spending time on this and pointing me into the right 
> > > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > > 
> > > > > Hi Paul,
> > > > > 
> > > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > > 
> > > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > > and move everything into DTS, somewhat like this:
> > > > > > 
> > > > > > / {
> > > > > >         osc0: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <50000000>;
> > > > > >         };
> > > > > > 
> > > > > >         osc1: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <12000000>;
> > > > > >         };
> > > > > > 
> > > > > >         rtc: clock {
> > > > > >                 compatible = "fixed-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clock-frequency = <32768>;
> > > > > >         };
> > > > > > 
> > > > > >         mcgout: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&osc0>;
> > > > > >                 clock-mult = <12>;
> > > > > >                 clock-div = <5>;
> > > > > >         };
> > > > > 
> > > > > I think this is a step backwards.
> > > > > 
> > > > > Did you look at the qcom clock binding and read the email where I
> > > > > detailed how that binding works?
> > > > > 
> > > > > The point of that type of binding is to not shove per-clock data into
> > > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > > create linkage between the clock providers and the clock consumers by
> > > > > using phandles + an index. Linux device drivers tap into this by using
> > > > > clk_get() and using the "clock-names" property from DT.
> > > > > 
> > > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > > interpretation for but for clock-related stuff we typically interpret
> > > > > the clock controller as the device, not the individual clock outputs
> > > > > coming out of the controller.
> > > > > 
> > > > > Note that a clock controller IP block may be both a provider and a
> > > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > > host controller, MMC controller, GPU, etc).
> > > > > 
> > > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > > as:
> > > > > 
> > > > > """
> > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > also an option for the debug trace clock.
> > > > > """
> > > > > 
> > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > > look at the qcom binding example I linked to in my previous mail.
> > > > > 
> > > > > > 
> > > > > >         core: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <1>;
> > > > > >         };
> > > > > > 
> > > > > >         bus: clock {
> > > > > >                 compatible = "fixed-factor-clock";
> > > > > >                 #clock-cells = <0>;
> > > > > >                 clocks = <&mcgout>;
> > > > > >                 clock-mult = <1>;
> > > > > >                 clock-div = <2>;
> > > > > 
> > > > > These are actually not fixed dividers but programmable dividers. You can
> > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > > fixed-dividers for the initial merge just to get things up and running
> > > > > if that is your strategy, but you'll need to revisit them later on when
> > > > > you need more flexible support for other boards.
> > > > > 
> > > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > > you want to be a perfectionist then it appears that there is an osc
> > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > 
> > > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > > that you can program a sane default rate? We use the
> > > > > assigned-clock-rates property for that. Note that this value is a
> > > > > property of some device which *consumes* the clock, not the clock
> > > > > controller or the clock output itself.
> > > > > 
> > > > > >         };
> > > > > > 
> > > > > >         soc {
> > > > > >                 cmu at 0x40047000 {
> > > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > > >                         reg = <0x40047000 0x1100>;
> > > > > > 
> > > > > >                         mcg_core_gate: clock-gate {
> > > > > >                                 clocks = <&core>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         mcg_bus_gate: clock-gate {
> > > > > >                                 clocks = <&bus>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > > 
> > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > >                                 clocks = <&osc0>;
> > > > > >                                 #clock-cells = <2>;
> > > > > >                         };
> > > > > >                 };
> > > > > > 
> > > > > >                 uart0: serial at 4006a000 {
> > > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > > >                         reg = <0x4006a000 0x1000>;
> > > > > >                         interrupts = <45>, <46>;
> > > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > > 
> > > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > > for a while now which means we can use constants instead of magic
> > > > > numbers. Please look at the shared header in the qcom binding for an
> > > > > example.
> > > > > 
> > > > > >                         clock-names = "ipg";
> > > > > >                         dmas = <&edma 0 2>;
> > > > > >                         dma-names = "rx";
> > > > > >                         status = "disabled";
> > > > > >                 };
> > > > > >         };
> > > > > > };
> > > > > > 
> > > > > > As you can see, mcg part is not required anymore.
> > > > > 
> > > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > > SoC, according to my reading of your technical reference manual. Just
> > > > > because you can model a few of its output clocks in dts does not mean
> > > > > that you should.
> > > > > 
> > > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > > manual.
> > > > > 
> > > > > > 
> > > > > > I guess that the approach above would require split into soc-specific and 
> > > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > > specific), but I wonder what you thing about this proposal.
> > > > > 
> > > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > > 
> > > > > Regards,
> > > > > Mike
> > > > > 
> > > > > > 
> > > > > > Thanks,
> > > > > > Paul
> > > > > > 
> > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > 
> > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > Hi Arnd,
> > > > > > > > 
> > > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > > situation clearer.
> > > > > > > 
> > > > > > > Hi Paul,
> > > > > > > 
> > > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > > 
> > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > 
> > > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > > series ;-)
> > > > > > > 
> > > > > > > > 
> > > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > 
> > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > > 
> > > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > > >      as clock source for the main PLL.
> > > > > > > 
> > > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > > fixed-rate binding.
> > > > > > > 
> > > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > > >      TWR-K70F120M boards).
> > > > > > > > 
> > > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > > PCLK.
> > > > > > > 
> > > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > frequencies.
> > > > > > > 
> > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > 
> > > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > > .dts.
> > > > > > > 
> > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > 
> > > > > > > Below is what your binding/dts should look like:
> > > > > > > 
> > > > > > > {
> > > > > > >       osc0: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <50000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       osc1: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <12000000>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       rtc: clock {
> > > > > > >               compatible = "fixed-clock";
> > > > > > >               #clock-cells = <0>;
> > > > > > >               clock-frequency = <32768>;
> > > > > > >       };
> > > > > > > 
> > > > > > >       soc: soc {
> > > > > > >               mcg: clock-controller at 40064000 {
> > > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40064000 0x14>;
> > > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > > >               };
> > > > > > > 
> > > > > > >               sim: clock-controller at 40047000 {
> > > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > > >                       clock-cells = <1>;
> > > > > > >                       reg = <0x40047000 0x1100>;
> > > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > > >               };
> > > > > > >       };
> > > > > > > 
> > > > > > >       uart0: serial at 4006a000 {
> > > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > > >               reg = <0x4006a000 0x1000>;
> > > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > >               clock-names = "gate";
> > > > > > >       };
> > > > > > > 
> > > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > > The above is the only style of binding that I have been accepting for
> > > > > > > some time; first declare the clock controller and establish its register
> > > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > > (e.g. clk_get()).
> > > > > > > 
> > > > > > > I've covered this before on the mailing list so here is a link
> > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > 
> > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > 
> > > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > > light.
> > > > > > > 
> > > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > > exercise to the reader.
> > > > > > > 
> > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > > 
> > > > > > > Regards,
> > > > > > > Mike
> > > > > > > 
> > > > > > > > 
> > > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > > usable for Kinetis.
> > > > > > > > 
> > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > 
> > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > >>>
> > > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > > >>>
> > > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > > >>
> > > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > > >> the functional level.
> > > > > > > > >
> > > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > > >
> > > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > >
> > > > > > > > >       Arnd
> > > > > > > > >
> > > > > > > > 
> > > > > > > > _______________________________________________
> > > > > > > > linux-arm-kernel mailing list
> > > > > > > > linux-arm-kernel at lists.infradead.org
> > > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > > 
> > > > > > --
> > > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > > the body of a message to majordomo at vger.kernel.org
> > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > 
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > the body of a message to majordomo at vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
  2015-08-01 15:27                                     ` Paul Osmialowski
  (?)
@ 2015-08-05 19:27                                       ` Michael Turquette
  -1 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-05 19:27 UTC (permalink / raw)
  Cc: Mark Rutland, Nicolas Pitre, Linus Walleij, Rob Herring,
	Alexander Potashev, Frank Li, Jiri Slaby, linux-clk,
	Russell King, Arnd Bergmann, Vinod Koul, Geert Uytterhoeven,
	linux-serial, Uwe Kleine-Koenig, Anson Huang, devicetree,
	Paul Osmialowski, Pawel Moll, Ian Campbell, Jingchang Lu,
	Yuri Tikhonov, linux-gpio, Rob Herring, Thomas Gleixner

Quoting Paul Osmialowski (2015-08-01 08:27:30)
> 
> Hi Mike,
> 
> On Fri, 31 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > > Hi Mike,
> > > 
> > > I encountered some trouble while I tried to implement code fitting to DTS 
> > > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> > > Therefore, in MCG device code I won't be able to figure out clock rate 
> > > for outputed clocks unles I try to access SIM registers from MCG driver - 
> > 
> > Right, the MCG driver will only know the rates of the clocks that it
> > outputs, namely:
> > 
> > MCGIRCLK
> > MCGFFCLK
> > MCGOUTCLK
> > MCGFLLCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > 
> > The naming scheme in the TRM is a bit unfortunate; it looks like some of
> > the clock outputs coming out of SIM also retain the MCG* names.
> 
> I wonder if I really need to implement support for all of these clocks 
> while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK 
> (and for this, it never considers FLL as a source). 
> I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since 
> their rates are computed as a byproduct while determining rate of 
> MCGOUTCLK. I may define constants for all of them in related header file, 
> but I'm thinking about leaving most of implementations as TBD - otherwise 
> I doubt I'll be ever able to test that my driver fully works.

You do not need to implement support for everything in your driver if
you don't want to, but DT binding descriptions are supposed to a stable
ABI. Why not make clock-cells == 1 and sleep better at night knowing
that you can grow the number of clocks you expose in the mcg node?

As kernel developers it is our job to write code that allows for restful
sleep.

> 
> > 
> > Why is clock-cells zero? I think the MCG block outputs all of the clocks
> > that I listed above? As such they should be addressable as <&mcg N> by
> > any downstream users.
> > 
> 
> Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.

Great.

> 
> 
> > >                         reg = <0x40064000 0x14>;
> > >                         clocks = <&osc0>, <&osc1>, <&rtc>;
> > >                         clock-names = "osc0", "osc1", "rtc";
> > 
> > Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> > 
> 
> Yes, I skipped the part above soc during copy-paste.
> 
> > It looks like the SIM block should also consume:
> > 
> > MCGFLLCLK
> > MCGIRCLK
> > MCGFFCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > OSC0ERCLK
> > OSC1ERCLK
> > OSC032KCLK
> > RTCCLK (I made that name up)
> > 
> > The mcg clocks should come out of the mcg node. It looks like you
> > already modeled oscN and rtc clocks, which is great. There are some
> > gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> > actually in the osc IP block or if they actually live in SIM. More on
> > that below...
> > 
> > Well they certainly can be exposed if you need them to be. If a device
> > driver wants to get the core clock and set it's rate then it should be
> > able to with something like <&sim CORE_CLK>.
> > 
> 
> Ok, the user of the clock does not relly need to know whether it is clock 
> device or a clock gate - fortunately, I already learnt how to implement 
> such thing.
> 
> > > 
> > > Also note that fec (ethernet device) driver is connected directly to osc0 
> > > (though clock gate, you can see this CG attached to osc0 on the diagram 
> > > too) - to control this gate I need to access SIM device registers, so it 
> > > should be covered by the same fsl,kinetis-sim driver.
> > 
> > Do you mean the SIM_SOPT2 register? It looks like the connection is not
> > "direct", as the osc0 signal feeds into the SIM block and the gate there
> > controls it.  Perhaps the diagram is incorrect by placing the CG block
> > inside osc0? It looks like you correctly modeled this relationship in
> > the sim node.
> 
> In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMII 
> mode to work, and according to what I see on the page 228 of the reference
> manual, it is osc0 clock behind this gate.
> 
> In the context of network device, I would need to read SIM_SOPT2 to 
> determine clock source for IEEE 1588 timestamp while implementing PTP 
> support - which currently I don't have in my plans, network device can do 
> without it.

OK, I'll leave all of that stuff in your hands. The bindings are looking
good and when the day comes for you to add more depth to your clock
driver then it won't require breaking backwards compatibility with
existing/deployed dtb blobs.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> > 
> > Besides my annoying questions above this binding is starting to shape up
> > very well. Thanks for your patience!
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > > Hi Mike,
> > > > > 
> > > > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > > > this driver should be written. The one you presented in your previous post 
> > > > > assumes that there will be a header file with defines shared between the 
> > > > > clock driver and DTS, also with clock gating details hidden behind some 
> > > > > additional level of indirection, e.g.:
> > > > > 
> > > > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > 
> > > > > Note that I've been through this at the very beginning, though the names 
> > > > > I used have been bit different, e.g.:
> > > > > 
> > > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > > > 
> > > > > This was rejected with a comment by Arnd:
> > > > > 
> > > > > 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, are you OK with my type of binding description now that I
> > > > explained it with some examples?
> > > > 
> > > > > 
> > > > > So I dropped all of these includes and started to use magic numbers (as 
> > > > > you put it). Now I need to go one way or another or even go the third way: 
> > > > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > > > scgc_register_number bit_index_number>.
> > > > 
> > > > Paul,
> > > > 
> > > > >From my understanding the DT folks do not like register-level or
> > > > bit-level details going into DT. It is better to handle the clock
> > > > signals as abstract resources and link a provider and consumer with a
> > > > simple phandle plus an index representing that abstract resource (i.e.
> > > > the clock output signal).
> > > > 
> > > > > 
> > > > > Reading your previous post I'm starting to feel that it would bring me 
> > > > > closer to final acceptance if I stick to what you proposed in that post 
> > > > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > > > I'll probably adopt that.
> > > > > 
> > > > > You're right about my "get things up and running" attitude - currently I 
> > > > > want to develop things extensively (cover as much subsystems as 
> > > > > possible) and then at some stage switch to intensive approach. This board 
> > > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > > > of coding opportunity in this field in the future.
> > > > 
> > > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > > solution.  Of course it will be best to get The Real Thing merged
> > > > upstream asap, but this is something I've done before to help get new
> > > > platform upstream before and I'm fine to do it again.
> > > > 
> > > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > > description is in good shape before merging it. The rest can follow on
> > > > later if it needs to.
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Paul
> > > > > 
> > > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > > 
> > > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > > Hi Mike,
> > > > > > > 
> > > > > > > Thank you for spending time on this and pointing me into the right 
> > > > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > > > 
> > > > > > Hi Paul,
> > > > > > 
> > > > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > > > 
> > > > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > > > and move everything into DTS, somewhat like this:
> > > > > > > 
> > > > > > > / {
> > > > > > >         osc0: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <50000000>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         osc1: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <12000000>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         rtc: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <32768>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         mcgout: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&osc0>;
> > > > > > >                 clock-mult = <12>;
> > > > > > >                 clock-div = <5>;
> > > > > > >         };
> > > > > > 
> > > > > > I think this is a step backwards.
> > > > > > 
> > > > > > Did you look at the qcom clock binding and read the email where I
> > > > > > detailed how that binding works?
> > > > > > 
> > > > > > The point of that type of binding is to not shove per-clock data into
> > > > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > > > create linkage between the clock providers and the clock consumers by
> > > > > > using phandles + an index. Linux device drivers tap into this by using
> > > > > > clk_get() and using the "clock-names" property from DT.
> > > > > > 
> > > > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > > > interpretation for but for clock-related stuff we typically interpret
> > > > > > the clock controller as the device, not the individual clock outputs
> > > > > > coming out of the controller.
> > > > > > 
> > > > > > Note that a clock controller IP block may be both a provider and a
> > > > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > > > host controller, MMC controller, GPU, etc).
> > > > > > 
> > > > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > > > as:
> > > > > > 
> > > > > > """
> > > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > > also an option for the debug trace clock.
> > > > > > """
> > > > > > 
> > > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > > > look at the qcom binding example I linked to in my previous mail.
> > > > > > 
> > > > > > > 
> > > > > > >         core: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&mcgout>;
> > > > > > >                 clock-mult = <1>;
> > > > > > >                 clock-div = <1>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         bus: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&mcgout>;
> > > > > > >                 clock-mult = <1>;
> > > > > > >                 clock-div = <2>;
> > > > > > 
> > > > > > These are actually not fixed dividers but programmable dividers. You can
> > > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > > > fixed-dividers for the initial merge just to get things up and running
> > > > > > if that is your strategy, but you'll need to revisit them later on when
> > > > > > you need more flexible support for other boards.
> > > > > > 
> > > > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > > > you want to be a perfectionist then it appears that there is an osc
> > > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > > 
> > > > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > > > that you can program a sane default rate? We use the
> > > > > > assigned-clock-rates property for that. Note that this value is a
> > > > > > property of some device which *consumes* the clock, not the clock
> > > > > > controller or the clock output itself.
> > > > > > 
> > > > > > >         };
> > > > > > > 
> > > > > > >         soc {
> > > > > > >                 cmu@0x40047000 {
> > > > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > > > >                         reg = <0x40047000 0x1100>;
> > > > > > > 
> > > > > > >                         mcg_core_gate: clock-gate {
> > > > > > >                                 clocks = <&core>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > > 
> > > > > > >                         mcg_bus_gate: clock-gate {
> > > > > > >                                 clocks = <&bus>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > > 
> > > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > > >                                 clocks = <&osc0>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > >                 };
> > > > > > > 
> > > > > > >                 uart0: serial@4006a000 {
> > > > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > > > >                         reg = <0x4006a000 0x1000>;
> > > > > > >                         interrupts = <45>, <46>;
> > > > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > > > 
> > > > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > > > for a while now which means we can use constants instead of magic
> > > > > > numbers. Please look at the shared header in the qcom binding for an
> > > > > > example.
> > > > > > 
> > > > > > >                         clock-names = "ipg";
> > > > > > >                         dmas = <&edma 0 2>;
> > > > > > >                         dma-names = "rx";
> > > > > > >                         status = "disabled";
> > > > > > >                 };
> > > > > > >         };
> > > > > > > };
> > > > > > > 
> > > > > > > As you can see, mcg part is not required anymore.
> > > > > > 
> > > > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > > > SoC, according to my reading of your technical reference manual. Just
> > > > > > because you can model a few of its output clocks in dts does not mean
> > > > > > that you should.
> > > > > > 
> > > > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > > > manual.
> > > > > > 
> > > > > > > 
> > > > > > > I guess that the approach above would require split into soc-specific and 
> > > > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > > > specific), but I wonder what you thing about this proposal.
> > > > > > 
> > > > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > > > 
> > > > > > Regards,
> > > > > > Mike
> > > > > > 
> > > > > > > 
> > > > > > > Thanks,
> > > > > > > Paul
> > > > > > > 
> > > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > > 
> > > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > > Hi Arnd,
> > > > > > > > > 
> > > > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > > > situation clearer.
> > > > > > > > 
> > > > > > > > Hi Paul,
> > > > > > > > 
> > > > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > > > 
> > > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > > 
> > > > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > > > series ;-)
> > > > > > > > 
> > > > > > > > > 
> > > > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > > 
> > > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > > > 
> > > > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > > > >      as clock source for the main PLL.
> > > > > > > > 
> > > > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > > > fixed-rate binding.
> > > > > > > > 
> > > > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > > > >      TWR-K70F120M boards).
> > > > > > > > > 
> > > > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > > > PCLK.
> > > > > > > > 
> > > > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > > frequencies.
> > > > > > > > 
> > > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > > 
> > > > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > > > .dts.
> > > > > > > > 
> > > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > > 
> > > > > > > > Below is what your binding/dts should look like:
> > > > > > > > 
> > > > > > > > {
> > > > > > > >       osc0: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <50000000>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       osc1: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <12000000>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       rtc: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <32768>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       soc: soc {
> > > > > > > >               mcg: clock-controller@40064000 {
> > > > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > > > >                       clock-cells = <1>;
> > > > > > > >                       reg = <0x40064000 0x14>;
> > > > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > > > >               };
> > > > > > > > 
> > > > > > > >               sim: clock-controller@40047000 {
> > > > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > > > >                       clock-cells = <1>;
> > > > > > > >                       reg = <0x40047000 0x1100>;
> > > > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > > > >               };
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       uart0: serial@4006a000 {
> > > > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > > > >               reg = <0x4006a000 0x1000>;
> > > > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > > >               clock-names = "gate";
> > > > > > > >       };
> > > > > > > > 
> > > > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > > > The above is the only style of binding that I have been accepting for
> > > > > > > > some time; first declare the clock controller and establish its register
> > > > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > > > (e.g. clk_get()).
> > > > > > > > 
> > > > > > > > I've covered this before on the mailing list so here is a link
> > > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > > 
> > > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > > 
> > > > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > > > light.
> > > > > > > > 
> > > > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > > > exercise to the reader.
> > > > > > > > 
> > > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > > > 
> > > > > > > > Regards,
> > > > > > > > Mike
> > > > > > > > 
> > > > > > > > > 
> > > > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > > > usable for Kinetis.
> > > > > > > > > 
> > > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > 
> > > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > >>>
> > > > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > > > >>>
> > > > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > > > >>
> > > > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > > > >> the functional level.
> > > > > > > > > >
> > > > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > > > >
> > > > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > > >
> > > > > > > > > >       Arnd
> > > > > > > > > >
> > > > > > > > > 
> > > > > > > > > _______________________________________________
> > > > > > > > > linux-arm-kernel mailing list
> > > > > > > > > linux-arm-kernel@lists.infradead.org
> > > > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > > > 
> > > > > > > --
> > > > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > > > the body of a message to majordomo@vger.kernel.org
> > > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > > 
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > the body of a message to majordomo@vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-05 19:27                                       ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-05 19:27 UTC (permalink / raw)
  To: Paul Osmialowski
  Cc: Paul Osmialowski, Arnd Bergmann, Mark Rutland, Nicolas Pitre,
	Linus Walleij, Rob Herring, Alexander Potashev, Frank Li,
	Jiri Slaby, linux-clk, Russell King, Vinod Koul,
	Geert Uytterhoeven, linux-serial, Uwe Kleine-Koenig, Anson Huang,
	devicetree, Pawel Moll, Ian Campbell, Kumar Gala, Yuri Tikhonov,
	linux-gpio, Rob Herring, Thomas Gleixner, linux-arm-kernel,
	Sergei Poselenov, Paul Bolle, Greg Kroah-Hartman, Stephen Boyd,
	linux-kernel, Jingchang Lu, dmaengine

Quoting Paul Osmialowski (2015-08-01 08:27:30)
> =

> Hi Mike,
> =

> On Fri, 31 Jul 2015, Michael Turquette wrote:
> =

> > Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > > Hi Mike,
> > > =

> > > I encountered some trouble while I tried to implement code fitting to=
 DTS =

> > > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. =

> > > Therefore, in MCG device code I won't be able to figure out clock rat=
e =

> > > for outputed clocks unles I try to access SIM registers from MCG driv=
er - =

> > =

> > Right, the MCG driver will only know the rates of the clocks that it
> > outputs, namely:
> > =

> > MCGIRCLK
> > MCGFFCLK
> > MCGOUTCLK
> > MCGFLLCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > =

> > The naming scheme in the TRM is a bit unfortunate; it looks like some of
> > the clock outputs coming out of SIM also retain the MCG* names.
> =

> I wonder if I really need to implement support for all of these clocks =

> while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK =

> (and for this, it never considers FLL as a source). =

> I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since =

> their rates are computed as a byproduct while determining rate of =

> MCGOUTCLK. I may define constants for all of them in related header file, =

> but I'm thinking about leaving most of implementations as TBD - otherwise =

> I doubt I'll be ever able to test that my driver fully works.

You do not need to implement support for everything in your driver if
you don't want to, but DT binding descriptions are supposed to a stable
ABI. Why not make clock-cells =3D=3D 1 and sleep better at night knowing
that you can grow the number of clocks you expose in the mcg node?

As kernel developers it is our job to write code that allows for restful
sleep.

> =

> > =

> > Why is clock-cells zero? I think the MCG block outputs all of the clocks
> > that I listed above? As such they should be addressable as <&mcg N> by
> > any downstream users.
> > =

> =

> Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.

Great.

> =

> =

> > >                         reg =3D <0x40064000 0x14>;
> > >                         clocks =3D <&osc0>, <&osc1>, <&rtc>;
> > >                         clock-names =3D "osc0", "osc1", "rtc";
> > =

> > Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> > =

> =

> Yes, I skipped the part above soc during copy-paste.
> =

> > It looks like the SIM block should also consume:
> > =

> > MCGFLLCLK
> > MCGIRCLK
> > MCGFFCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > OSC0ERCLK
> > OSC1ERCLK
> > OSC032KCLK
> > RTCCLK (I made that name up)
> > =

> > The mcg clocks should come out of the mcg node. It looks like you
> > already modeled oscN and rtc clocks, which is great. There are some
> > gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> > actually in the osc IP block or if they actually live in SIM. More on
> > that below...
> > =

> > Well they certainly can be exposed if you need them to be. If a device
> > driver wants to get the core clock and set it's rate then it should be
> > able to with something like <&sim CORE_CLK>.
> > =

> =

> Ok, the user of the clock does not relly need to know whether it is clock =

> device or a clock gate - fortunately, I already learnt how to implement =

> such thing.
> =

> > > =

> > > Also note that fec (ethernet device) driver is connected directly to =
osc0 =

> > > (though clock gate, you can see this CG attached to osc0 on the diagr=
am =

> > > too) - to control this gate I need to access SIM device registers, so=
 it =

> > > should be covered by the same fsl,kinetis-sim driver.
> > =

> > Do you mean the SIM_SOPT2 register? It looks like the connection is not
> > "direct", as the osc0 signal feeds into the SIM block and the gate there
> > controls it.  Perhaps the diagram is incorrect by placing the CG block
> > inside osc0? It looks like you correctly modeled this relationship in
> > the sim node.
> =

> In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMI=
I =

> mode to work, and according to what I see on the page 228 of the reference
> manual, it is osc0 clock behind this gate.
> =

> In the context of network device, I would need to read SIM_SOPT2 to =

> determine clock source for IEEE 1588 timestamp while implementing PTP =

> support - which currently I don't have in my plans, network device can do =

> without it.

OK, I'll leave all of that stuff in your hands. The bindings are looking
good and when the day comes for you to add more depth to your clock
driver then it won't require breaking backwards compatibility with
existing/deployed dtb blobs.

Regards,
Mike

> =

> Thanks,
> Paul
> =

> > =

> > Besides my annoying questions above this binding is starting to shape up
> > very well. Thanks for your patience!
> > =

> > Regards,
> > Mike
> > =

> > > =

> > > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > > =

> > > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > > Hi Mike,
> > > > > =

> > > > > My trouble is that now I'm dealing with two conradictory opinions=
 on how =

> > > > > this driver should be written. The one you presented in your prev=
ious post =

> > > > > assumes that there will be a header file with defines shared betw=
een the =

> > > > > clock driver and DTS, also with clock gating details hidden behin=
d some =

> > > > > additional level of indirection, e.g.:
> > > > > =

> > > > > clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
> > > > > =

> > > > > Note that I've been through this at the very beginning, though th=
e names =

> > > > > I used have been bit different, e.g.:
> > > > > =

> > > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCG=
C4[11] */
> > > > > =

> > > > > This was rejected with a comment by Arnd:
> > > > > =

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

> > > > Arnd, are you OK with my type of binding description now that I
> > > > explained it with some examples?
> > > > =

> > > > > =

> > > > > So I dropped all of these includes and started to use magic numbe=
rs (as =

> > > > > you put it). Now I need to go one way or another or even go the t=
hird way: =

> > > > > extend #clock-cells to <3> and address it like: <&sim parent_cloc=
k_id =

> > > > > scgc_register_number bit_index_number>.
> > > > =

> > > > Paul,
> > > > =

> > > > >From my understanding the DT folks do not like register-level or
> > > > bit-level details going into DT. It is better to handle the clock
> > > > signals as abstract resources and link a provider and consumer with=
 a
> > > > simple phandle plus an index representing that abstract resource (i=
.e.
> > > > the clock output signal).
> > > > =

> > > > > =

> > > > > Reading your previous post I'm starting to feel that it would bri=
ng me =

> > > > > closer to final acceptance if I stick to what you proposed in tha=
t post =

> > > > > (I'm really grateful to you for writting so huge chunk of DTS for=
 me!), so =

> > > > > I'll probably adopt that.
> > > > > =

> > > > > You're right about my "get things up and running" attitude - curr=
ently I =

> > > > > want to develop things extensively (cover as much subsystems as =

> > > > > possible) and then at some stage switch to intensive approach. Th=
is board =

> > > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will b=
e a lot =

> > > > > of coding opportunity in this field in the future.
> > > > =

> > > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > > solution.  Of course it will be best to get The Real Thing merged
> > > > upstream asap, but this is something I've done before to help get n=
ew
> > > > platform upstream before and I'm fine to do it again.
> > > > =

> > > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > > description is in good shape before merging it. The rest can follow=
 on
> > > > later if it needs to.
> > > > =

> > > > Regards,
> > > > Mike
> > > > =

> > > > > =

> > > > > Thanks,
> > > > > Paul
> > > > > =

> > > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > > =

> > > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > > Hi Mike,
> > > > > > > =

> > > > > > > Thank you for spending time on this and pointing me into the =
right =

> > > > > > > direction. I'm wondering about going even further with it. As=
suming that I =

> > > > > > =

> > > > > > Hi Paul,
> > > > > > =

> > > > > > No problem! And thanks for the quick turnaround on your patches=
 so far.
> > > > > > =

> > > > > > > know everything about my board, I can skip run-time discovery=
 phase (note =

> > > > > > > that the original driver was designed for other Kinetis-based=
 boards too) =

> > > > > > > and move everything into DTS, somewhat like this:
> > > > > > > =

> > > > > > > / {
> > > > > > >         osc0: clock {
> > > > > > >                 compatible =3D "fixed-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clock-frequency =3D <50000000>;
> > > > > > >         };
> > > > > > > =

> > > > > > >         osc1: clock {
> > > > > > >                 compatible =3D "fixed-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clock-frequency =3D <12000000>;
> > > > > > >         };
> > > > > > > =

> > > > > > >         rtc: clock {
> > > > > > >                 compatible =3D "fixed-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clock-frequency =3D <32768>;
> > > > > > >         };
> > > > > > > =

> > > > > > >         mcgout: clock {
> > > > > > >                 compatible =3D "fixed-factor-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clocks =3D <&osc0>;
> > > > > > >                 clock-mult =3D <12>;
> > > > > > >                 clock-div =3D <5>;
> > > > > > >         };
> > > > > > =

> > > > > > I think this is a step backwards.
> > > > > > =

> > > > > > Did you look at the qcom clock binding and read the email where=
 I
> > > > > > detailed how that binding works?
> > > > > > =

> > > > > > The point of that type of binding is to not shove per-clock dat=
a into
> > > > > > DT, but instead to declare every clock controller IP block (e.g=
. the
> > > > > > device) as well as every board-level clock (e.g. as osc that fe=
eds into
> > > > > > your mcu). Once these "clock providers" are enumerated in DT, t=
hen we
> > > > > > create linkage between the clock providers and the clock consum=
ers by
> > > > > > using phandles + an index. Linux device drivers tap into this b=
y using
> > > > > > clk_get() and using the "clock-names" property from DT.
> > > > > > =

> > > > > > Put another way: we mostly use DT to model "devices". That is o=
pen to
> > > > > > interpretation for but for clock-related stuff we typically int=
erpret
> > > > > > the clock controller as the device, not the individual clock ou=
tputs
> > > > > > coming out of the controller.
> > > > > > =

> > > > > > Note that a clock controller IP block may be both a provider an=
d a
> > > > > > consumer.  I/O controllers are a very common type of consumer (=
e.g. USB
> > > > > > host controller, MMC controller, GPU, etc).
> > > > > > =

> > > > > > Additionally, from my reading of the reference manual, mcgout i=
s defined
> > > > > > as:
> > > > > > =

> > > > > > """
> > > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > > also an option for the debug trace clock.
> > > > > > """
> > > > > > =

> > > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > > multiplexer? Also, why is it listed here at all? Please take an=
other
> > > > > > look at the qcom binding example I linked to in my previous mai=
l.
> > > > > > =

> > > > > > > =

> > > > > > >         core: clock {
> > > > > > >                 compatible =3D "fixed-factor-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clocks =3D <&mcgout>;
> > > > > > >                 clock-mult =3D <1>;
> > > > > > >                 clock-div =3D <1>;
> > > > > > >         };
> > > > > > > =

> > > > > > >         bus: clock {
> > > > > > >                 compatible =3D "fixed-factor-clock";
> > > > > > >                 #clock-cells =3D <0>;
> > > > > > >                 clocks =3D <&mcgout>;
> > > > > > >                 clock-mult =3D <1>;
> > > > > > >                 clock-div =3D <2>;
> > > > > > =

> > > > > > These are actually not fixed dividers but programmable dividers=
. You can
> > > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with=
 using
> > > > > > fixed-dividers for the initial merge just to get things up and =
running
> > > > > > if that is your strategy, but you'll need to revisit them later=
 on when
> > > > > > you need more flexible support for other boards.
> > > > > > =

> > > > > > Again, I'm not sure why these clocks are enumerated in DT. Why =
not just
> > > > > > enumerate your mcg clock controller and your sim clock controll=
er? If
> > > > > > you want to be a perfectionist then it appears that there is an=
 osc
> > > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > > =

> > > > > > It occurs to me that maybe you are trying to use fixed-factor c=
locks so
> > > > > > that you can program a sane default rate? We use the
> > > > > > assigned-clock-rates property for that. Note that this value is=
 a
> > > > > > property of some device which *consumes* the clock, not the clo=
ck
> > > > > > controller or the clock output itself.
> > > > > > =

> > > > > > >         };
> > > > > > > =

> > > > > > >         soc {
> > > > > > >                 cmu@0x40047000 {
> > > > > > >                         compatible =3D "fsl,kinetis-gate-cloc=
k";
> > > > > > >                         reg =3D <0x40047000 0x1100>;
> > > > > > > =

> > > > > > >                         mcg_core_gate: clock-gate {
> > > > > > >                                 clocks =3D <&core>;
> > > > > > >                                 #clock-cells =3D <2>;
> > > > > > >                         };
> > > > > > > =

> > > > > > >                         mcg_bus_gate: clock-gate {
> > > > > > >                                 clocks =3D <&bus>;
> > > > > > >                                 #clock-cells =3D <2>;
> > > > > > >                         };
> > > > > > > =

> > > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > > >                                 clocks =3D <&osc0>;
> > > > > > >                                 #clock-cells =3D <2>;
> > > > > > >                         };
> > > > > > >                 };
> > > > > > > =

> > > > > > >                 uart0: serial@4006a000 {
> > > > > > >                         compatible =3D "fsl,kinetis-lpuart";
> > > > > > >                         reg =3D <0x4006a000 0x1000>;
> > > > > > >                         interrupts =3D <45>, <46>;
> > > > > > >                         interrupt-names =3D "uart-stat", "uar=
t-err";
> > > > > > >                         clocks =3D <&mcg_core_gate 3 10>;
> > > > > > =

> > > > > > Magic numbers are not good. dtc has been able to use preprocess=
or macros
> > > > > > for a while now which means we can use constants instead of mag=
ic
> > > > > > numbers. Please look at the shared header in the qcom binding f=
or an
> > > > > > example.
> > > > > > =

> > > > > > >                         clock-names =3D "ipg";
> > > > > > >                         dmas =3D <&edma 0 2>;
> > > > > > >                         dma-names =3D "rx";
> > > > > > >                         status =3D "disabled";
> > > > > > >                 };
> > > > > > >         };
> > > > > > > };
> > > > > > > =

> > > > > > > As you can see, mcg part is not required anymore.
> > > > > > =

> > > > > > I think the mcg should be required. The mcg is a real IP block =
on your
> > > > > > SoC, according to my reading of your technical reference manual=
. Just
> > > > > > because you can model a few of its output clocks in dts does no=
t mean
> > > > > > that you should.
> > > > > > =

> > > > > > I did a quick grep and didn't find "cmu" anywhere in the refere=
nce
> > > > > > manual.
> > > > > > =

> > > > > > > =

> > > > > > > I guess that the approach above would require split into soc-=
specific and =

> > > > > > > board-specific part (as I said, dividers arrangement is somet=
hing board =

> > > > > > > specific), but I wonder what you thing about this proposal.
> > > > > > =

> > > > > > Splitting is good. Chip-specific stuff can go into the chip-spe=
cific
> > > > > > dtsi file. The board-level (osc) stuff can go into the individu=
al board
> > > > > > files. The ultimate goal is to make it trivial to add new board=
s.
> > > > > > =

> > > > > > Regards,
> > > > > > Mike
> > > > > > =

> > > > > > > =

> > > > > > > Thanks,
> > > > > > > Paul
> > > > > > > =

> > > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > > =

> > > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > > Hi Arnd,
> > > > > > > > > =

> > > > > > > > > I'm attaching excerpt from Kinetis reference manual that =
may make =

> > > > > > > > > situation clearer.
> > > > > > > > =

> > > > > > > > Hi Paul,
> > > > > > > > =

> > > > > > > > Can you please post the patch in the body of the email inst=
ead of an
> > > > > > > > attachment? It makes it easier to review. Another small nit=
pick is that
> > > > > > > > the $SUBJECT for this patch might be better off as somethin=
g like:
> > > > > > > > =

> > > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > > =

> > > > > > > > At least it helps me find the patch I care about when skimm=
ing the
> > > > > > > > series ;-)
> > > > > > > > =

> > > > > > > > > =

> > > > > > > > > These MCG and SIM registers are used only to determine co=
nfiguration =

> > > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > > =

> > > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which i=
s the parent for =

> > > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determin=
ed at run time by =

> > > > > > > > > reading MCG registers, let me quote commit message from E=
mcraft git repo:
> > > > > > > > > =

> > > > > > > > >       * Determine in run-time what oscillator module (OSC=
0 or OSC1) is used
> > > > > > > > >      as clock source for the main PLL.
> > > > > > > > =

> > > > > > > > According to [0] there are three options: a 32k RTC osc clo=
ck and osc0
> > > > > > > > both feed into a mux. You should model this 32k clock with =
the
> > > > > > > > fixed-rate binding.
> > > > > > > > =

> > > > > > > > >       * When OSC1 is selected, assume its frequency to be=
 12 MHz on all
> > > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1=
 on K70-SOM and
> > > > > > > > >      TWR-K70F120M boards).
> > > > > > > > > =

> > > > > > > > > In my .dts I'm trying to possibly follow real clock hiera=
rchy, but to go =

> > > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrit=
e .dtb e.g. by =

> > > > > > > > > U-boot. But that's too demanding for any potential users =
of this BSP. So =

> > > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent=
 for CCLK and =

> > > > > > > > > PCLK.
> > > > > > > > =

> > > > > > > > I'm confused. The point of device tree is to solve problems=
 like this;
> > > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > > frequencies.
> > > > > > > > =

> > > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your boa=
rd-specific
> > > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not be=
long in the
> > > > > > > > cmu node, and they should use the "fixed-clock" binding. Th=
e 32k RTC osc
> > > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate=
 clock since
> > > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > > =

> > > > > > > > These three fixed-rate clocks are your root clock nodes. Cu=
stomers only
> > > > > > > > need to worry about this if they spin a board, and then the=
y will need
> > > > > > > > to populate the frequencies of OSC0 and OSC1 in their board=
-specific
> > > > > > > > .dts.
> > > > > > > > =

> > > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > > =

> > > > > > > > Below is what your binding/dts should look like:
> > > > > > > > =

> > > > > > > > {
> > > > > > > >       osc0: clock {
> > > > > > > >               compatible =3D "fixed-clock";
> > > > > > > >               #clock-cells =3D <0>;
> > > > > > > >               clock-frequency =3D <50000000>;
> > > > > > > >       };
> > > > > > > > =

> > > > > > > >       osc1: clock {
> > > > > > > >               compatible =3D "fixed-clock";
> > > > > > > >               #clock-cells =3D <0>;
> > > > > > > >               clock-frequency =3D <12000000>;
> > > > > > > >       };
> > > > > > > > =

> > > > > > > >       rtc: clock {
> > > > > > > >               compatible =3D "fixed-clock";
> > > > > > > >               #clock-cells =3D <0>;
> > > > > > > >               clock-frequency =3D <32768>;
> > > > > > > >       };
> > > > > > > > =

> > > > > > > >       soc: soc {
> > > > > > > >               mcg: clock-controller@40064000 {
> > > > > > > >                       compatible =3D "fsl,kinetis-mcg";
> > > > > > > >                       clock-cells =3D <1>;
> > > > > > > >                       reg =3D <0x40064000 0x14>;
> > > > > > > >                       clocks =3D <&osc0>, <&osc1>, <&rtc>;
> > > > > > > >                       clock-names =3D "osc0", "osc1", "rtc";
> > > > > > > >               };
> > > > > > > > =

> > > > > > > >               sim: clock-controller@40047000 {
> > > > > > > >                       compatible =3D "fsl,kinetis-sim";
> > > > > > > >                       clock-cells =3D <1>;
> > > > > > > >                       reg =3D <0x40047000 0x1100>;
> > > > > > > >                       clocks =3D <&mcg MCG_MCGOUTCLK_DIV1>,=
 <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_D=
IV4>;
> > > > > > > >                       clock-names =3D "core", "bus", "flexb=
us", "flash";
> > > > > > > >               };
> > > > > > > >       };
> > > > > > > > =

> > > > > > > >       uart0: serial@4006a000 {
> > > > > > > >               compatible =3D "fsl,kinetis-lpuart";
> > > > > > > >               reg =3D <0x4006a000 0x1000>;
> > > > > > > >               clocks =3D <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > > >               clock-names =3D "gate";
> > > > > > > >       };
> > > > > > > > =

> > > > > > > > I removed the interrupts and dma stuff from the uart0 node =
for clarity.
> > > > > > > > The above is the only style of binding that I have been acc=
epting for
> > > > > > > > some time; first declare the clock controller and establish=
 its register
> > > > > > > > space, and then consumers can consume clocks by providing t=
he phandle to
> > > > > > > > the controller plus an offset corresponding to a unique clo=
ck. The
> > > > > > > > clock-names property makes it really easy to use with the c=
lkdev stuff
> > > > > > > > (e.g. clk_get()).
> > > > > > > > =

> > > > > > > > I've covered this before on the mailing list so here is a l=
ink
> > > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > > =

> > > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > > =

> > > > > > > > Technically you could encode the same bits as sub-nodes of =
the mcg and
> > > > > > > > sim nodes, but the shared header is how the magic happens w=
ith the
> > > > > > > > driver so it's best to keep the clock controller binding sm=
all and
> > > > > > > > light.
> > > > > > > > =

> > > > > > > > I think this means you can also get rid of kinetis_of_clk_g=
et_name and
> > > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave th=
at as an
> > > > > > > > exercise to the reader.
> > > > > > > > =

> > > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/r=
ef_manual/K70P256M150SF3RM.pdf
> > > > > > > > =

> > > > > > > > Regards,
> > > > > > > > Mike
> > > > > > > > =

> > > > > > > > > =

> > > > > > > > > In my most recent version I added OSC0ERCLK explicitly as=
 one more root =

> > > > > > > > > clock, since it is also used directly (through CG reg. 1 =
bit 0) by =

> > > > > > > > > Freescale fec network device whose in-tree driver I'm try=
ing to make =

> > > > > > > > > usable for Kinetis.
> > > > > > > > > =

> > > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > =

> > > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > >>>
> > > > > > > > > >>>> I wonder if you could move out the fixed rate clocks=
 into their own
> > > > > > > > > >>>> nodes. Are they actually controlled by the same bloc=
k? If they are
> > > > > > > > > >>>> just fixed, you can use the normal binding for fixed=
 rate clocks
> > > > > > > > > >>>> and only describe the clocks that are related to the=
 driver.
> > > > > > > > > >>>
> > > > > > > > > >>> In my view having these clocks grouped together looks=
 more convincing. After
> > > > > > > > > >>> all, they all share the same I/O regs in order to rea=
d configuration.
> > > > > > > > > >>
> > > > > > > > > >> The fact that they share a register is not making them=
 a group. That's
> > > > > > > > > >> just a HW design decision and you need to deal with th=
at by protecting
> > > > > > > > > >> the register access, but not by trying to group them a=
rtificially at
> > > > > > > > > >> the functional level.
> > > > > > > > > >
> > > > > > > > > > I'd disagree with that: The clock controller is the dev=
ice that owns the
> > > > > > > > > > registers and that should be one node in DT, as Paul's =
first version does.
> > > > > > > > > >
> > > > > > > > > > The part I'm still struggling with is understanding how=
 the fixed-rate
> > > > > > > > > > clocks are controlled through those registers. If they =
are indeed configured
> > > > > > > > > > through the registers, the name is probably wrong and s=
hould be changed
> > > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > > >
> > > > > > > > > >       Arnd
> > > > > > > > > >
> > > > > > > > > =

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

> > > > > > > --
> > > > > > > To unsubscribe from this list: send the line "unsubscribe lin=
ux-kernel" in
> > > > > > > the body of a message to majordomo@vger.kernel.org
> > > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info=
.html
> > > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > > =

> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-k=
ernel" in
> > > > > the body of a message to majordomo@vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > =

> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kerne=
l" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > =

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC
@ 2015-08-05 19:27                                       ` Michael Turquette
  0 siblings, 0 replies; 140+ messages in thread
From: Michael Turquette @ 2015-08-05 19:27 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Paul Osmialowski (2015-08-01 08:27:30)
> 
> Hi Mike,
> 
> On Fri, 31 Jul 2015, Michael Turquette wrote:
> 
> > Quoting Paul Osmialowski (2015-07-30 14:40:48)
> > > Hi Mike,
> > > 
> > > I encountered some trouble while I tried to implement code fitting to DTS 
> > > that you proposed. SIM_CLKDIVx are SIM device registers, not MCG. 
> > > Therefore, in MCG device code I won't be able to figure out clock rate 
> > > for outputed clocks unles I try to access SIM registers from MCG driver - 
> > 
> > Right, the MCG driver will only know the rates of the clocks that it
> > outputs, namely:
> > 
> > MCGIRCLK
> > MCGFFCLK
> > MCGOUTCLK
> > MCGFLLCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > 
> > The naming scheme in the TRM is a bit unfortunate; it looks like some of
> > the clock outputs coming out of SIM also retain the MCG* names.
> 
> I wonder if I really need to implement support for all of these clocks 
> while to run Linux on this board reference 2.6 kernel uses only MCGOUTCLK 
> (and for this, it never considers FLL as a source). 
> I can also provide support for MCGPLL0CLK and MCGPLL1CLK as well since 
> their rates are computed as a byproduct while determining rate of 
> MCGOUTCLK. I may define constants for all of them in related header file, 
> but I'm thinking about leaving most of implementations as TBD - otherwise 
> I doubt I'll be ever able to test that my driver fully works.

You do not need to implement support for everything in your driver if
you don't want to, but DT binding descriptions are supposed to a stable
ABI. Why not make clock-cells == 1 and sleep better at night knowing
that you can grow the number of clocks you expose in the mcg node?

As kernel developers it is our job to write code that allows for restful
sleep.

> 
> > 
> > Why is clock-cells zero? I think the MCG block outputs all of the clocks
> > that I listed above? As such they should be addressable as <&mcg N> by
> > any downstream users.
> > 
> 
> Ok, will be 1, to distinguish between MCGOUTCLK, MCGPLL0CLK, MCGPLL1CLK.

Great.

> 
> 
> > >                         reg = <0x40064000 0x14>;
> > >                         clocks = <&osc0>, <&osc1>, <&rtc>;
> > >                         clock-names = "osc0", "osc1", "rtc";
> > 
> > Are the oscN and rtc clocks modeled as fixed-rate clocks in DT?
> > 
> 
> Yes, I skipped the part above soc during copy-paste.
> 
> > It looks like the SIM block should also consume:
> > 
> > MCGFLLCLK
> > MCGIRCLK
> > MCGFFCLK
> > MCGPLL0CLK
> > MCGPLL1CLK
> > OSC0ERCLK
> > OSC1ERCLK
> > OSC032KCLK
> > RTCCLK (I made that name up)
> > 
> > The mcg clocks should come out of the mcg node. It looks like you
> > already modeled oscN and rtc clocks, which is great. There are some
> > gates after these clocks (e.g. OSC0ERCLK). I wonder if those gates are
> > actually in the osc IP block or if they actually live in SIM. More on
> > that below...
> > 
> > Well they certainly can be exposed if you need them to be. If a device
> > driver wants to get the core clock and set it's rate then it should be
> > able to with something like <&sim CORE_CLK>.
> > 
> 
> Ok, the user of the clock does not relly need to know whether it is clock 
> device or a clock gate - fortunately, I already learnt how to implement 
> such thing.
> 
> > > 
> > > Also note that fec (ethernet device) driver is connected directly to osc0 
> > > (though clock gate, you can see this CG attached to osc0 on the diagram 
> > > too) - to control this gate I need to access SIM device registers, so it 
> > > should be covered by the same fsl,kinetis-sim driver.
> > 
> > Do you mean the SIM_SOPT2 register? It looks like the connection is not
> > "direct", as the osc0 signal feeds into the SIM block and the gate there
> > controls it.  Perhaps the diagram is incorrect by placing the CG block
> > inside osc0? It looks like you correctly modeled this relationship in
> > the sim node.
> 
> In order to enable network device, bit 0 of SIM_SCGC2 must be set for RMII 
> mode to work, and according to what I see on the page 228 of the reference
> manual, it is osc0 clock behind this gate.
> 
> In the context of network device, I would need to read SIM_SOPT2 to 
> determine clock source for IEEE 1588 timestamp while implementing PTP 
> support - which currently I don't have in my plans, network device can do 
> without it.

OK, I'll leave all of that stuff in your hands. The bindings are looking
good and when the day comes for you to add more depth to your clock
driver then it won't require breaking backwards compatibility with
existing/deployed dtb blobs.

Regards,
Mike

> 
> Thanks,
> Paul
> 
> > 
> > Besides my annoying questions above this binding is starting to shape up
> > very well. Thanks for your patience!
> > 
> > Regards,
> > Mike
> > 
> > > 
> > > On Wed, 29 Jul 2015, Michael Turquette wrote:
> > > 
> > > > Quoting Paul Osmialowski (2015-07-28 13:30:17)
> > > > > Hi Mike,
> > > > > 
> > > > > My trouble is that now I'm dealing with two conradictory opinions on how 
> > > > > this driver should be written. The one you presented in your previous post 
> > > > > assumes that there will be a header file with defines shared between the 
> > > > > clock driver and DTS, also with clock gating details hidden behind some 
> > > > > additional level of indirection, e.g.:
> > > > > 
> > > > > clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > 
> > > > > Note that I've been through this at the very beginning, though the names 
> > > > > I used have been bit different, e.g.:
> > > > > 
> > > > > #define KINETIS_CG_UART1       KINETIS_MKCG(3, 11)     /* SIM_SCGC4[11] */
> > > > > 
> > > > > This was rejected with a comment by Arnd:
> > > > > 
> > > > > 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, are you OK with my type of binding description now that I
> > > > explained it with some examples?
> > > > 
> > > > > 
> > > > > So I dropped all of these includes and started to use magic numbers (as 
> > > > > you put it). Now I need to go one way or another or even go the third way: 
> > > > > extend #clock-cells to <3> and address it like: <&sim parent_clock_id 
> > > > > scgc_register_number bit_index_number>.
> > > > 
> > > > Paul,
> > > > 
> > > > >From my understanding the DT folks do not like register-level or
> > > > bit-level details going into DT. It is better to handle the clock
> > > > signals as abstract resources and link a provider and consumer with a
> > > > simple phandle plus an index representing that abstract resource (i.e.
> > > > the clock output signal).
> > > > 
> > > > > 
> > > > > Reading your previous post I'm starting to feel that it would bring me 
> > > > > closer to final acceptance if I stick to what you proposed in that post 
> > > > > (I'm really grateful to you for writting so huge chunk of DTS for me!), so 
> > > > > I'll probably adopt that.
> > > > > 
> > > > > You're right about my "get things up and running" attitude - currently I 
> > > > > want to develop things extensively (cover as much subsystems as 
> > > > > possible) and then at some stage switch to intensive approach. This board 
> > > > > is a somewhat huge monster (for a Cortex-M4 SoC) and there will be a lot 
> > > > > of coding opportunity in this field in the future.
> > > > 
> > > > I'm happy to take clock drivers and add my Reviewed-by to .dts files
> > > > that make use of fixed-rate and fixed-factor clocks as an interim
> > > > solution.  Of course it will be best to get The Real Thing merged
> > > > upstream asap, but this is something I've done before to help get new
> > > > platform upstream before and I'm fine to do it again.
> > > > 
> > > > With that said, Devicetree bindings are allegedly a stable ABI that
> > > > cannot be broken. So let's make sure that any Kinetis clock binding
> > > > description is in good shape before merging it. The rest can follow on
> > > > later if it needs to.
> > > > 
> > > > Regards,
> > > > Mike
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Paul
> > > > > 
> > > > > On Tue, 28 Jul 2015, Michael Turquette wrote:
> > > > > 
> > > > > > Quoting Paul Osmialowski (2015-07-26 13:24:08)
> > > > > > > Hi Mike,
> > > > > > > 
> > > > > > > Thank you for spending time on this and pointing me into the right 
> > > > > > > direction. I'm wondering about going even further with it. Assuming that I 
> > > > > > 
> > > > > > Hi Paul,
> > > > > > 
> > > > > > No problem! And thanks for the quick turnaround on your patches so far.
> > > > > > 
> > > > > > > know everything about my board, I can skip run-time discovery phase (note 
> > > > > > > that the original driver was designed for other Kinetis-based boards too) 
> > > > > > > and move everything into DTS, somewhat like this:
> > > > > > > 
> > > > > > > / {
> > > > > > >         osc0: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <50000000>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         osc1: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <12000000>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         rtc: clock {
> > > > > > >                 compatible = "fixed-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clock-frequency = <32768>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         mcgout: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&osc0>;
> > > > > > >                 clock-mult = <12>;
> > > > > > >                 clock-div = <5>;
> > > > > > >         };
> > > > > > 
> > > > > > I think this is a step backwards.
> > > > > > 
> > > > > > Did you look at the qcom clock binding and read the email where I
> > > > > > detailed how that binding works?
> > > > > > 
> > > > > > The point of that type of binding is to not shove per-clock data into
> > > > > > DT, but instead to declare every clock controller IP block (e.g. the
> > > > > > device) as well as every board-level clock (e.g. as osc that feeds into
> > > > > > your mcu). Once these "clock providers" are enumerated in DT, then we
> > > > > > create linkage between the clock providers and the clock consumers by
> > > > > > using phandles + an index. Linux device drivers tap into this by using
> > > > > > clk_get() and using the "clock-names" property from DT.
> > > > > > 
> > > > > > Put another way: we mostly use DT to model "devices". That is open to
> > > > > > interpretation for but for clock-related stuff we typically interpret
> > > > > > the clock controller as the device, not the individual clock outputs
> > > > > > coming out of the controller.
> > > > > > 
> > > > > > Note that a clock controller IP block may be both a provider and a
> > > > > > consumer.  I/O controllers are a very common type of consumer (e.g. USB
> > > > > > host controller, MMC controller, GPU, etc).
> > > > > > 
> > > > > > Additionally, from my reading of the reference manual, mcgout is defined
> > > > > > as:
> > > > > > 
> > > > > > """
> > > > > > MCG output of either IRC, MCGFLLCLK MCGPLL0CLK,
> > > > > > MCGPLL1CLK, or MCG's external reference clock that
> > > > > > sources the core, system, bus, FlexBus, and flash clock. It is
> > > > > > also an option for the debug trace clock.
> > > > > > """
> > > > > > 
> > > > > > So why is it listed here as a fixed-factor clock? Is it not a
> > > > > > multiplexer? Also, why is it listed here at all? Please take another
> > > > > > look at the qcom binding example I linked to in my previous mail.
> > > > > > 
> > > > > > > 
> > > > > > >         core: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&mcgout>;
> > > > > > >                 clock-mult = <1>;
> > > > > > >                 clock-div = <1>;
> > > > > > >         };
> > > > > > > 
> > > > > > >         bus: clock {
> > > > > > >                 compatible = "fixed-factor-clock";
> > > > > > >                 #clock-cells = <0>;
> > > > > > >                 clocks = <&mcgout>;
> > > > > > >                 clock-mult = <1>;
> > > > > > >                 clock-div = <2>;
> > > > > > 
> > > > > > These are actually not fixed dividers but programmable dividers. You can
> > > > > > probably use drivers/clk/clk-divider.c for these. I'm fine with using
> > > > > > fixed-dividers for the initial merge just to get things up and running
> > > > > > if that is your strategy, but you'll need to revisit them later on when
> > > > > > you need more flexible support for other boards.
> > > > > > 
> > > > > > Again, I'm not sure why these clocks are enumerated in DT. Why not just
> > > > > > enumerate your mcg clock controller and your sim clock controller? If
> > > > > > you want to be a perfectionist then it appears that there is an osc
> > > > > > clock controller upstream from the mcg controller as well ;-)
> > > > > > 
> > > > > > It occurs to me that maybe you are trying to use fixed-factor clocks so
> > > > > > that you can program a sane default rate? We use the
> > > > > > assigned-clock-rates property for that. Note that this value is a
> > > > > > property of some device which *consumes* the clock, not the clock
> > > > > > controller or the clock output itself.
> > > > > > 
> > > > > > >         };
> > > > > > > 
> > > > > > >         soc {
> > > > > > >                 cmu at 0x40047000 {
> > > > > > >                         compatible = "fsl,kinetis-gate-clock";
> > > > > > >                         reg = <0x40047000 0x1100>;
> > > > > > > 
> > > > > > >                         mcg_core_gate: clock-gate {
> > > > > > >                                 clocks = <&core>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > > 
> > > > > > >                         mcg_bus_gate: clock-gate {
> > > > > > >                                 clocks = <&bus>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > > 
> > > > > > >                         osc0_erclk_gate: clock-gate {
> > > > > > >                                 clocks = <&osc0>;
> > > > > > >                                 #clock-cells = <2>;
> > > > > > >                         };
> > > > > > >                 };
> > > > > > > 
> > > > > > >                 uart0: serial at 4006a000 {
> > > > > > >                         compatible = "fsl,kinetis-lpuart";
> > > > > > >                         reg = <0x4006a000 0x1000>;
> > > > > > >                         interrupts = <45>, <46>;
> > > > > > >                         interrupt-names = "uart-stat", "uart-err";
> > > > > > >                         clocks = <&mcg_core_gate 3 10>;
> > > > > > 
> > > > > > Magic numbers are not good. dtc has been able to use preprocessor macros
> > > > > > for a while now which means we can use constants instead of magic
> > > > > > numbers. Please look at the shared header in the qcom binding for an
> > > > > > example.
> > > > > > 
> > > > > > >                         clock-names = "ipg";
> > > > > > >                         dmas = <&edma 0 2>;
> > > > > > >                         dma-names = "rx";
> > > > > > >                         status = "disabled";
> > > > > > >                 };
> > > > > > >         };
> > > > > > > };
> > > > > > > 
> > > > > > > As you can see, mcg part is not required anymore.
> > > > > > 
> > > > > > I think the mcg should be required. The mcg is a real IP block on your
> > > > > > SoC, according to my reading of your technical reference manual. Just
> > > > > > because you can model a few of its output clocks in dts does not mean
> > > > > > that you should.
> > > > > > 
> > > > > > I did a quick grep and didn't find "cmu" anywhere in the reference
> > > > > > manual.
> > > > > > 
> > > > > > > 
> > > > > > > I guess that the approach above would require split into soc-specific and 
> > > > > > > board-specific part (as I said, dividers arrangement is something board 
> > > > > > > specific), but I wonder what you thing about this proposal.
> > > > > > 
> > > > > > Splitting is good. Chip-specific stuff can go into the chip-specific
> > > > > > dtsi file. The board-level (osc) stuff can go into the individual board
> > > > > > files. The ultimate goal is to make it trivial to add new boards.
> > > > > > 
> > > > > > Regards,
> > > > > > Mike
> > > > > > 
> > > > > > > 
> > > > > > > Thanks,
> > > > > > > Paul
> > > > > > > 
> > > > > > > On Thu, 23 Jul 2015, Michael Turquette wrote:
> > > > > > > 
> > > > > > > > Quoting Paul Osmialowski (2015-07-04 14:50:03)
> > > > > > > > > Hi Arnd,
> > > > > > > > > 
> > > > > > > > > I'm attaching excerpt from Kinetis reference manual that may make 
> > > > > > > > > situation clearer.
> > > > > > > > 
> > > > > > > > Hi Paul,
> > > > > > > > 
> > > > > > > > Can you please post the patch in the body of the email instead of an
> > > > > > > > attachment? It makes it easier to review. Another small nitpick is that
> > > > > > > > the $SUBJECT for this patch might be better off as something like:
> > > > > > > > 
> > > > > > > > clk: mcg and sim clock drivers for twr-k70f120m Kinetis SoC
> > > > > > > > 
> > > > > > > > At least it helps me find the patch I care about when skimming the
> > > > > > > > series ;-)
> > > > > > > > 
> > > > > > > > > 
> > > > > > > > > These MCG and SIM registers are used only to determine configuration 
> > > > > > > > > (clock fixed rates and clock signal origins) at run time.
> > > > > > > > > 
> > > > > > > > > Namely, the real MCGOUTCLK source (in the middle) which is the parent for 
> > > > > > > > > core clock (CCLK) and peripheral clock (PCLK) is determined at run time by 
> > > > > > > > > reading MCG registers, let me quote commit message from Emcraft git repo:
> > > > > > > > > 
> > > > > > > > >       * Determine in run-time what oscillator module (OSC0 or OSC1) is used
> > > > > > > > >      as clock source for the main PLL.
> > > > > > > > 
> > > > > > > > According to [0] there are three options: a 32k RTC osc clock and osc0
> > > > > > > > both feed into a mux. You should model this 32k clock with the
> > > > > > > > fixed-rate binding.
> > > > > > > > 
> > > > > > > > >       * When OSC1 is selected, assume its frequency to be 12 MHz on all
> > > > > > > > >      boards (there is a 12 MHz oscillator on XTAL1/EXTAL1 on K70-SOM and
> > > > > > > > >      TWR-K70F120M boards).
> > > > > > > > > 
> > > > > > > > > In my .dts I'm trying to possibly follow real clock hierarchy, but to go 
> > > > > > > > > anywhere behind MCGOUTCLK would require ability to rewrite .dtb e.g. by 
> > > > > > > > > U-boot. But that's too demanding for any potential users of this BSP. So 
> > > > > > > > > let's asume that MCGOUTCLK is the root clock and a parent for CCLK and 
> > > > > > > > > PCLK.
> > > > > > > > 
> > > > > > > > I'm confused. The point of device tree is to solve problems like this;
> > > > > > > > i.e. board-specific differences such as different oscillator
> > > > > > > > frequencies.
> > > > > > > > 
> > > > > > > > OSC0 and OSC1 should each be a fixed-rate clock in your board-specific
> > > > > > > > TWR-K70F120M DTS (not a chip-specific file). They do not belong in the
> > > > > > > > cmu node, and they should use the "fixed-clock" binding. The 32k RTC osc
> > > > > > > > can probably go in your chip-specific .dtsi as a fixed-rate clock since
> > > > > > > > it appears to mandated in the reference manual[0].
> > > > > > > > 
> > > > > > > > These three fixed-rate clocks are your root clock nodes. Customers only
> > > > > > > > need to worry about this if they spin a board, and then they will need
> > > > > > > > to populate the frequencies of OSC0 and OSC1 in their board-specific
> > > > > > > > .dts.
> > > > > > > > 
> > > > > > > > Please break clk-kinetis.c into two files:
> > > > > > > > drivers/clk/kinetis/clk-mcg.c
> > > > > > > > drivers/clk/kinetis/clk-sim.c
> > > > > > > > 
> > > > > > > > Below is what your binding/dts should look like:
> > > > > > > > 
> > > > > > > > {
> > > > > > > >       osc0: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <50000000>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       osc1: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <12000000>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       rtc: clock {
> > > > > > > >               compatible = "fixed-clock";
> > > > > > > >               #clock-cells = <0>;
> > > > > > > >               clock-frequency = <32768>;
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       soc: soc {
> > > > > > > >               mcg: clock-controller at 40064000 {
> > > > > > > >                       compatible = "fsl,kinetis-mcg";
> > > > > > > >                       clock-cells = <1>;
> > > > > > > >                       reg = <0x40064000 0x14>;
> > > > > > > >                       clocks = <&osc0>, <&osc1>, <&rtc>;
> > > > > > > >                       clock-names = "osc0", "osc1", "rtc";
> > > > > > > >               };
> > > > > > > > 
> > > > > > > >               sim: clock-controller at 40047000 {
> > > > > > > >                       compatible = "fsl,kinetis-sim";
> > > > > > > >                       clock-cells = <1>;
> > > > > > > >                       reg = <0x40047000 0x1100>;
> > > > > > > >                       clocks = <&mcg MCG_MCGOUTCLK_DIV1>, <&mcg MCG_MCGOUTCLK_DIV2>, <&mcg MCG_MCGOUTCLK_DIV3> <&mcg MCG_MCGOUTCLK_DIV4>;
> > > > > > > >                       clock-names = "core", "bus", "flexbus", "flash";
> > > > > > > >               };
> > > > > > > >       };
> > > > > > > > 
> > > > > > > >       uart0: serial at 4006a000 {
> > > > > > > >               compatible = "fsl,kinetis-lpuart";
> > > > > > > >               reg = <0x4006a000 0x1000>;
> > > > > > > >               clocks = <&sim SIM_SCGC4_UART1_CLK>;
> > > > > > > >               clock-names = "gate";
> > > > > > > >       };
> > > > > > > > 
> > > > > > > > I removed the interrupts and dma stuff from the uart0 node for clarity.
> > > > > > > > The above is the only style of binding that I have been accepting for
> > > > > > > > some time; first declare the clock controller and establish its register
> > > > > > > > space, and then consumers can consume clocks by providing the phandle to
> > > > > > > > the controller plus an offset corresponding to a unique clock. The
> > > > > > > > clock-names property makes it really easy to use with the clkdev stuff
> > > > > > > > (e.g. clk_get()).
> > > > > > > > 
> > > > > > > > I've covered this before on the mailing list so here is a link
> > > > > > > > describing how the qcom bindings do it in detail:
> > > > > > > > 
> > > > > > > > http://lkml.kernel.org/r/<20150416192014.19585.9663@quantum>
> > > > > > > > 
> > > > > > > > Technically you could encode the same bits as sub-nodes of the mcg and
> > > > > > > > sim nodes, but the shared header is how the magic happens with the
> > > > > > > > driver so it's best to keep the clock controller binding small and
> > > > > > > > light.
> > > > > > > > 
> > > > > > > > I think this means you can also get rid of kinetis_of_clk_get_name and
> > > > > > > > kinetis_clk_gate_get but my brain is tired so I'll leave that as an
> > > > > > > > exercise to the reader.
> > > > > > > > 
> > > > > > > > [0] http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K70P256M150SF3RM.pdf
> > > > > > > > 
> > > > > > > > Regards,
> > > > > > > > Mike
> > > > > > > > 
> > > > > > > > > 
> > > > > > > > > In my most recent version I added OSC0ERCLK explicitly as one more root 
> > > > > > > > > clock, since it is also used directly (through CG reg. 1 bit 0) by 
> > > > > > > > > Freescale fec network device whose in-tree driver I'm trying to make 
> > > > > > > > > usable for Kinetis.
> > > > > > > > > 
> > > > > > > > > On Sat, 4 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > 
> > > > > > > > > > On Friday 03 July 2015 00:08:27 Thomas Gleixner wrote:
> > > > > > > > > >> On Thu, 2 Jul 2015, Paul Osmialowski wrote:
> > > > > > > > > >>> On Thu, 2 Jul 2015, Arnd Bergmann wrote:
> > > > > > > > > >>>
> > > > > > > > > >>>> I wonder if you could move out the fixed rate clocks into their own
> > > > > > > > > >>>> nodes. Are they actually controlled by the same block? If they are
> > > > > > > > > >>>> just fixed, you can use the normal binding for fixed rate clocks
> > > > > > > > > >>>> and only describe the clocks that are related to the driver.
> > > > > > > > > >>>
> > > > > > > > > >>> In my view having these clocks grouped together looks more convincing. After
> > > > > > > > > >>> all, they all share the same I/O regs in order to read configuration.
> > > > > > > > > >>
> > > > > > > > > >> The fact that they share a register is not making them a group. That's
> > > > > > > > > >> just a HW design decision and you need to deal with that by protecting
> > > > > > > > > >> the register access, but not by trying to group them artificially at
> > > > > > > > > >> the functional level.
> > > > > > > > > >
> > > > > > > > > > I'd disagree with that: The clock controller is the device that owns the
> > > > > > > > > > registers and that should be one node in DT, as Paul's first version does.
> > > > > > > > > >
> > > > > > > > > > The part I'm still struggling with is understanding how the fixed-rate
> > > > > > > > > > clocks are controlled through those registers. If they are indeed configured
> > > > > > > > > > through the registers, the name is probably wrong and should be changed
> > > > > > > > > > to whatever kind of non-fixed clock this is.
> > > > > > > > > >
> > > > > > > > > >       Arnd
> > > > > > > > > >
> > > > > > > > > 
> > > > > > > > > _______________________________________________
> > > > > > > > > linux-arm-kernel mailing list
> > > > > > > > > linux-arm-kernel at lists.infradead.org
> > > > > > > > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> > > > > > > > 
> > > > > > > --
> > > > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > > > the body of a message to majordomo at vger.kernel.org
> > > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > > > 
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > > > the body of a message to majordomo at vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > Please read the FAQ at  http://www.tux.org/lkml/
> > > > 
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > > the body of a message to majordomo at vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

end of thread, other threads:[~2015-08-05 19:27 UTC | newest]

Thread overview: 140+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-30 12:27 [PATCH v2 0/9] [New BSP] Add initial support for Freescale Kinetis TWR-K70F120M development kit Paul Osmialowski
2015-06-30 12:27 ` Paul Osmialowski
2015-06-30 12:27 ` Paul Osmialowski
2015-06-30 12:27 ` [PATCH v2 2/9] arm: twr-k70f120m: basic support for Kinetis TWR-K70F120M Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 12:27 ` [PATCH v2 3/9] arm: twr-k70f120m: clock driver for Kinetis SoC Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 20:36   ` Arnd Bergmann
2015-06-30 20:36     ` Arnd Bergmann
2015-06-30 20:36     ` Arnd Bergmann
2015-07-01 15:57     ` Paul Osmialowski
2015-07-01 15:57       ` Paul Osmialowski
2015-07-01 15:57       ` Paul Osmialowski
     [not found]       ` <alpine.LNX.2.00.1507011756140.14440-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2015-07-02 10:08         ` Paul Osmialowski
2015-07-02 10:08           ` Paul Osmialowski
2015-07-02 10:08           ` Paul Osmialowski
2015-07-02 12:40           ` Arnd Bergmann
2015-07-02 12:40             ` Arnd Bergmann
2015-07-02 12:40             ` Arnd Bergmann
2015-07-02 21:42             ` Paul Osmialowski
2015-07-02 21:42               ` Paul Osmialowski
2015-07-02 21:42               ` Paul Osmialowski
2015-07-02 22:08               ` Thomas Gleixner
2015-07-02 22:08                 ` Thomas Gleixner
2015-07-02 22:08                 ` Thomas Gleixner
2015-07-03 17:40                 ` Paul Osmialowski
2015-07-03 17:40                   ` Paul Osmialowski
2015-07-03 17:40                   ` Paul Osmialowski
2015-07-04 19:54                 ` Arnd Bergmann
2015-07-04 19:54                   ` Arnd Bergmann
2015-07-04 19:54                   ` Arnd Bergmann
2015-07-04 21:50                   ` Paul Osmialowski
2015-07-04 21:50                     ` Paul Osmialowski
2015-07-04 21:50                     ` Paul Osmialowski
2015-07-06 20:57                     ` Paul Osmialowski
2015-07-06 20:57                       ` Paul Osmialowski
2015-07-06 20:57                       ` Paul Osmialowski
2015-07-24  3:42                     ` Michael Turquette
2015-07-24  3:42                       ` Michael Turquette
2015-07-24  3:42                       ` Michael Turquette
2015-07-24  3:42                       ` Michael Turquette
2015-07-26 20:24                       ` Paul Osmialowski
2015-07-26 20:24                         ` Paul Osmialowski
2015-07-26 20:24                         ` Paul Osmialowski
2015-07-28 16:03                         ` Michael Turquette
2015-07-28 16:03                           ` Michael Turquette
2015-07-28 16:03                           ` Michael Turquette
2015-07-28 20:30                           ` Paul Osmialowski
2015-07-28 20:30                             ` Paul Osmialowski
2015-07-28 20:30                             ` Paul Osmialowski
2015-07-29 23:05                             ` Michael Turquette
2015-07-29 23:05                               ` Michael Turquette
2015-07-29 23:05                               ` Michael Turquette
2015-07-30 21:40                               ` Paul Osmialowski
2015-07-30 21:40                                 ` Paul Osmialowski
2015-07-30 21:40                                 ` Paul Osmialowski
2015-08-01  0:58                                 ` Michael Turquette
2015-08-01  0:58                                   ` Michael Turquette
2015-08-01  0:58                                   ` Michael Turquette
2015-08-01 15:27                                   ` Paul Osmialowski
2015-08-01 15:27                                     ` Paul Osmialowski
2015-08-01 15:27                                     ` Paul Osmialowski
2015-08-05 19:27                                     ` Michael Turquette
2015-08-05 19:27                                       ` Michael Turquette
2015-08-05 19:27                                       ` Michael Turquette
2015-07-14  9:03   ` Linus Walleij
2015-07-14  9:03     ` Linus Walleij
2015-07-14  9:03     ` Linus Walleij
2015-07-14  9:03     ` Linus Walleij
2015-07-15  7:31     ` Paul Osmialowski
2015-07-15  7:31       ` Paul Osmialowski
2015-07-15  7:31       ` Paul Osmialowski
2015-07-15  7:31       ` Paul Osmialowski
2015-07-15 17:34       ` Paul Osmialowski
2015-07-15 17:34         ` Paul Osmialowski
2015-07-15 17:34         ` Paul Osmialowski
2015-07-15 17:34         ` Paul Osmialowski
     [not found] ` <1435667250-28299-1-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
2015-06-30 12:27   ` [PATCH v2 1/9] arm: allow copying of vector table to internal SRAM memory Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
2015-06-30 12:27   ` [PATCH v2 4/9] arm: twr-k70f120m: timer driver for Kinetis SoC Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
     [not found]     ` <1435667250-28299-5-git-send-email-pawelo-rhuoMcPwk82rDJvtcaxF/A@public.gmane.org>
2015-06-30 20:43       ` Arnd Bergmann
2015-06-30 20:43         ` Arnd Bergmann
2015-06-30 20:43         ` Arnd Bergmann
2015-07-01 11:44         ` Paul Osmialowski
2015-07-01 11:44           ` Paul Osmialowski
2015-07-01 11:44           ` Paul Osmialowski
2015-07-05 14:39         ` Rob Herring
2015-07-05 14:39           ` Rob Herring
2015-07-05 14:39           ` Rob Herring
2015-07-05 14:39           ` Rob Herring
2015-07-01  7:51     ` Thomas Gleixner
2015-07-01  7:51       ` Thomas Gleixner
2015-07-01  7:51       ` Thomas Gleixner
2015-07-01  8:42       ` Paul Osmialowski
2015-07-01  8:42         ` Paul Osmialowski
2015-07-01  8:42         ` Paul Osmialowski
2015-07-01 13:28         ` Thomas Gleixner
2015-07-01 13:28           ` Thomas Gleixner
2015-07-01 13:28           ` Thomas Gleixner
2015-07-01 14:20           ` Paul Osmialowski
2015-07-01 14:20             ` Paul Osmialowski
2015-07-01 14:20             ` Paul Osmialowski
2015-07-14  8:59             ` Linus Walleij
2015-07-14  8:59               ` Linus Walleij
2015-07-14  8:59               ` Linus Walleij
2015-07-14  8:59               ` Linus Walleij
2015-06-30 12:27   ` [PATCH v2 9/9] arm: twr-k70f120m: use Freescale lpuart driver with " Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
2015-06-30 12:27     ` Paul Osmialowski
2015-06-30 12:27 ` [PATCH v2 5/9] arm: twr-k70f120m: IOMUX driver for " Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-07-14  8:55   ` Linus Walleij
2015-07-14  8:55     ` Linus Walleij
2015-07-14  8:55     ` Linus Walleij
2015-07-14  8:55     ` Linus Walleij
2015-06-30 12:27 ` [PATCH v2 6/9] arm: twr-k70f120m: extend Freescale eDMA driver with the ability to support " Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-07-05  6:45   ` Vinod Koul
2015-07-05  6:45     ` Vinod Koul
2015-07-05  6:45     ` Vinod Koul
2015-07-05  6:45     ` Vinod Koul
2015-07-05  9:45     ` Paul Osmialowski
2015-07-05  9:45       ` Paul Osmialowski
2015-07-05  9:45       ` Paul Osmialowski
2015-06-30 12:27 ` [PATCH v2 7/9] arm: twr-k70f120m: use Freescale eDMA driver with " Paul Osmialowski
2015-06-30 12:27   ` Paul Osmialowski
2015-06-30 20:49   ` Arnd Bergmann
2015-06-30 20:49     ` Arnd Bergmann
2015-06-30 20:49     ` Arnd Bergmann
2015-07-01  6:54     ` Paul Osmialowski
2015-07-01  6:54       ` Paul Osmialowski
2015-07-01  6:54       ` Paul Osmialowski
2015-06-30 12:27 ` [PATCH v2 8/9] arm: twr-k70f120m: extend Freescale lpuart driver with ability to support " Paul Osmialowski
2015-06-30 12:27   ` 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.